diff options
Diffstat (limited to 'drivers')
395 files changed, 9837 insertions, 4447 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 20eacc2c9e0e..e942ffe8b57e 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -13,6 +13,7 @@ config ACPI depends on IA64 || X86 depends on PCI depends on PM + select PNP default y ---help--- Advanced Configuration and Power Interface (ACPI) support for @@ -132,15 +133,6 @@ config ACPI_VIDEO Note that this is an ref. implementation only. It may or may not work for your integrated video device. -config ACPI_HOTKEY - tristate "Generic Hotkey (EXPERIMENTAL)" - depends on EXPERIMENTAL - depends on X86 - default n - help - Experimental consolidated hotkey driver. - If you are unsure, say N. - config ACPI_FAN tristate "Fan" default y diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 856c32bccacb..5956e9f64a8b 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -46,7 +46,6 @@ obj-$(CONFIG_ACPI_FAN) += fan.o obj-$(CONFIG_ACPI_DOCK) += dock.o obj-$(CONFIG_ACPI_BAY) += bay.o obj-$(CONFIG_ACPI_VIDEO) += video.o -obj-$(CONFIG_ACPI_HOTKEY) += hotkey.o obj-y += pci_root.o pci_link.o pci_irq.o pci_bind.o obj-$(CONFIG_ACPI_POWER) += power.o obj-$(CONFIG_ACPI_PROCESSOR) += processor.o diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c index 6daeace796a8..37c7dc4f9fe5 100644 --- a/drivers/acpi/ac.c +++ b/drivers/acpi/ac.c @@ -35,7 +35,6 @@ #define ACPI_AC_COMPONENT 0x00020000 #define ACPI_AC_CLASS "ac_adapter" #define ACPI_AC_HID "ACPI0003" -#define ACPI_AC_DRIVER_NAME "ACPI AC Adapter Driver" #define ACPI_AC_DEVICE_NAME "AC Adapter" #define ACPI_AC_FILE_STATE "state" #define ACPI_AC_NOTIFY_STATUS 0x80 @@ -44,10 +43,10 @@ #define ACPI_AC_STATUS_UNKNOWN 0xFF #define _COMPONENT ACPI_AC_COMPONENT -ACPI_MODULE_NAME("acpi_ac") +ACPI_MODULE_NAME("ac"); - MODULE_AUTHOR("Paul Diefenbaugh"); -MODULE_DESCRIPTION(ACPI_AC_DRIVER_NAME); +MODULE_AUTHOR("Paul Diefenbaugh"); +MODULE_DESCRIPTION("ACPI AC Adapter Driver"); MODULE_LICENSE("GPL"); extern struct proc_dir_entry *acpi_lock_ac_dir(void); @@ -58,7 +57,7 @@ static int acpi_ac_remove(struct acpi_device *device, int type); static int acpi_ac_open_fs(struct inode *inode, struct file *file); static struct acpi_driver acpi_ac_driver = { - .name = ACPI_AC_DRIVER_NAME, + .name = "ac", .class = ACPI_AC_CLASS, .ids = ACPI_AC_HID, .ops = { diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c index cd946ed192d3..c26172671fd8 100644 --- a/drivers/acpi/acpi_memhotplug.c +++ b/drivers/acpi/acpi_memhotplug.c @@ -35,14 +35,13 @@ #define ACPI_MEMORY_DEVICE_COMPONENT 0x08000000UL #define ACPI_MEMORY_DEVICE_CLASS "memory" #define ACPI_MEMORY_DEVICE_HID "PNP0C80" -#define ACPI_MEMORY_DEVICE_DRIVER_NAME "Hotplug Mem Driver" #define ACPI_MEMORY_DEVICE_NAME "Hotplug Mem Device" #define _COMPONENT ACPI_MEMORY_DEVICE_COMPONENT -ACPI_MODULE_NAME("acpi_memory") - MODULE_AUTHOR("Naveen B S <naveen.b.s@intel.com>"); -MODULE_DESCRIPTION(ACPI_MEMORY_DEVICE_DRIVER_NAME); +ACPI_MODULE_NAME("acpi_memhotplug"); +MODULE_AUTHOR("Naveen B S <naveen.b.s@intel.com>"); +MODULE_DESCRIPTION("Hotplug Mem Driver"); MODULE_LICENSE("GPL"); /* ACPI _STA method values */ @@ -60,7 +59,7 @@ static int acpi_memory_device_remove(struct acpi_device *device, int type); static int acpi_memory_device_start(struct acpi_device *device); static struct acpi_driver acpi_memory_device_driver = { - .name = ACPI_MEMORY_DEVICE_DRIVER_NAME, + .name = "acpi_memhotplug", .class = ACPI_MEMORY_DEVICE_CLASS, .ids = ACPI_MEMORY_DEVICE_HID, .ops = { diff --git a/drivers/acpi/asus_acpi.c b/drivers/acpi/asus_acpi.c index 31ad70a6e22e..772299fb5f9d 100644 --- a/drivers/acpi/asus_acpi.c +++ b/drivers/acpi/asus_acpi.c @@ -141,6 +141,7 @@ struct asus_hotk { W5A, //W5A W3V, //W3030V xxN, //M2400N, M3700N, M5200N, M6800N, S1300N, S5200N + A4S, //Z81sp //(Centrino) END_MODEL } model; //Models currently supported @@ -397,7 +398,16 @@ static struct model_data model_conf[END_MODEL] = { .brightness_set = "SPLV", .brightness_get = "GPLV", .display_set = "SDSP", - .display_get = "\\ADVG"} + .display_get = "\\ADVG"}, + + { + .name = "A4S", + .brightness_set = "SPLV", + .brightness_get = "GPLV", + .mt_bt_switch = "BLED", + .mt_wled = "WLED" + } + }; /* procdir we use */ @@ -421,7 +431,7 @@ static struct asus_hotk *hotk; static int asus_hotk_add(struct acpi_device *device); static int asus_hotk_remove(struct acpi_device *device, int type); static struct acpi_driver asus_hotk_driver = { - .name = ACPI_HOTK_NAME, + .name = "asus_acpi", .class = ACPI_HOTK_CLASS, .ids = ACPI_HOTK_HID, .ops = { @@ -1117,6 +1127,8 @@ static int asus_model_match(char *model) return W3V; else if (strncmp(model, "W5A", 3) == 0) return W5A; + else if (strncmp(model, "A4S", 3) == 0) + return A4S; else return END_MODEL; } @@ -1365,10 +1377,6 @@ static int __init asus_acpi_init(void) if (acpi_disabled) return -ENODEV; - if (!acpi_specific_hotkey_enabled) { - printk(KERN_ERR "Using generic hotkey driver\n"); - return -ENODEV; - } asus_proc_dir = proc_mkdir(PROC_ASUS, acpi_root_dir); if (!asus_proc_dir) { printk(KERN_ERR "Asus ACPI: Unable to create /proc entry\n"); diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 2f4521a48fe7..e64c76c8b726 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -42,7 +42,6 @@ #define ACPI_BATTERY_COMPONENT 0x00040000 #define ACPI_BATTERY_CLASS "battery" #define ACPI_BATTERY_HID "PNP0C0A" -#define ACPI_BATTERY_DRIVER_NAME "ACPI Battery Driver" #define ACPI_BATTERY_DEVICE_NAME "Battery" #define ACPI_BATTERY_FILE_INFO "info" #define ACPI_BATTERY_FILE_STATUS "state" @@ -53,10 +52,10 @@ #define ACPI_BATTERY_UNITS_AMPS "mA" #define _COMPONENT ACPI_BATTERY_COMPONENT -ACPI_MODULE_NAME("acpi_battery") +ACPI_MODULE_NAME("battery"); - MODULE_AUTHOR("Paul Diefenbaugh"); -MODULE_DESCRIPTION(ACPI_BATTERY_DRIVER_NAME); +MODULE_AUTHOR("Paul Diefenbaugh"); +MODULE_DESCRIPTION("ACPI Battery Driver"); MODULE_LICENSE("GPL"); extern struct proc_dir_entry *acpi_lock_battery_dir(void); @@ -67,7 +66,7 @@ static int acpi_battery_remove(struct acpi_device *device, int type); static int acpi_battery_resume(struct acpi_device *device); static struct acpi_driver acpi_battery_driver = { - .name = ACPI_BATTERY_DRIVER_NAME, + .name = "battery", .class = ACPI_BATTERY_CLASS, .ids = ACPI_BATTERY_HID, .ops = { @@ -324,6 +323,13 @@ static int acpi_battery_check(struct acpi_battery *battery) return result; } +static void acpi_battery_check_present(struct acpi_battery *battery) +{ + if (!battery->flags.present) { + acpi_battery_check(battery); + } +} + /* -------------------------------------------------------------------------- FS Interface (/proc) -------------------------------------------------------------------------- */ @@ -340,6 +346,8 @@ static int acpi_battery_read_info(struct seq_file *seq, void *offset) if (!battery) goto end; + acpi_battery_check_present(battery); + if (battery->flags.present) seq_printf(seq, "present: yes\n"); else { @@ -424,6 +432,8 @@ static int acpi_battery_read_state(struct seq_file *seq, void *offset) if (!battery) goto end; + acpi_battery_check_present(battery); + if (battery->flags.present) seq_printf(seq, "present: yes\n"); else { @@ -499,6 +509,8 @@ static int acpi_battery_read_alarm(struct seq_file *seq, void *offset) if (!battery) goto end; + acpi_battery_check_present(battery); + if (!battery->flags.present) { seq_printf(seq, "present: no\n"); goto end; @@ -536,6 +548,8 @@ acpi_battery_write_alarm(struct file *file, if (!battery || (count > sizeof(alarm_string) - 1)) return -EINVAL; + acpi_battery_check_present(battery); + if (!battery->flags.present) return -ENODEV; diff --git a/drivers/acpi/bay.c b/drivers/acpi/bay.c index 91082ce6f5d1..fb3f31b5e69f 100644 --- a/drivers/acpi/bay.c +++ b/drivers/acpi/bay.c @@ -32,11 +32,9 @@ #include <asm/uaccess.h> #include <linux/platform_device.h> -#define ACPI_BAY_DRIVER_NAME "ACPI Removable Drive Bay Driver" - -ACPI_MODULE_NAME("bay") +ACPI_MODULE_NAME("bay"); MODULE_AUTHOR("Kristen Carlson Accardi"); -MODULE_DESCRIPTION(ACPI_BAY_DRIVER_NAME); +MODULE_DESCRIPTION("ACPI Removable Drive Bay Driver"); MODULE_LICENSE("GPL"); #define ACPI_BAY_CLASS "bay" #define ACPI_BAY_COMPONENT 0x10000000 @@ -47,18 +45,6 @@ MODULE_LICENSE("GPL"); acpi_get_name(h, ACPI_FULL_PATHNAME, &buffer);\ printk(KERN_DEBUG PREFIX "%s: %s\n", prefix, s); } static void bay_notify(acpi_handle handle, u32 event, void *data); -static int acpi_bay_add(struct acpi_device *device); -static int acpi_bay_remove(struct acpi_device *device, int type); - -static struct acpi_driver acpi_bay_driver = { - .name = ACPI_BAY_DRIVER_NAME, - .class = ACPI_BAY_CLASS, - .ids = ACPI_BAY_HID, - .ops = { - .add = acpi_bay_add, - .remove = acpi_bay_remove, - }, -}; struct bay { acpi_handle handle; @@ -234,14 +220,6 @@ int eject_removable_drive(struct device *dev) } EXPORT_SYMBOL_GPL(eject_removable_drive); -static int acpi_bay_add(struct acpi_device *device) -{ - bay_dprintk(device->handle, "adding bay device"); - strcpy(acpi_device_name(device), "Dockable Bay"); - strcpy(acpi_device_class(device), "bay"); - return 0; -} - static int acpi_bay_add_fs(struct bay *bay) { int ret; @@ -303,7 +281,7 @@ static int bay_add(acpi_handle handle, int id) /* initialize platform device stuff */ pdev = platform_device_register_simple(ACPI_BAY_CLASS, id, NULL, 0); - if (pdev == NULL) { + if (IS_ERR(pdev)) { printk(KERN_ERR PREFIX "Error registering bay device\n"); goto bay_add_err; } @@ -339,52 +317,6 @@ bay_add_err: return -ENODEV; } -static int acpi_bay_remove(struct acpi_device *device, int type) -{ - /*** FIXME: do something here */ - return 0; -} - -/** - * bay_create_acpi_device - add new devices to acpi - * @handle - handle of the device to add - * - * This function will create a new acpi_device for the given - * handle if one does not exist already. This should cause - * acpi to scan for drivers for the given devices, and call - * matching driver's add routine. - * - * Returns a pointer to the acpi_device corresponding to the handle. - */ -static struct acpi_device * bay_create_acpi_device(acpi_handle handle) -{ - struct acpi_device *device = NULL; - struct acpi_device *parent_device; - acpi_handle parent; - int ret; - - bay_dprintk(handle, "Trying to get device"); - if (acpi_bus_get_device(handle, &device)) { - /* - * no device created for this object, - * so we should create one. - */ - bay_dprintk(handle, "No device for handle"); - acpi_get_parent(handle, &parent); - if (acpi_bus_get_device(parent, &parent_device)) - parent_device = NULL; - - ret = acpi_bus_add(&device, parent_device, handle, - ACPI_BUS_TYPE_DEVICE); - if (ret) { - pr_debug("error adding bus, %x\n", - -ret); - return NULL; - } - } - return device; -} - /** * bay_notify - act upon an acpi bay notification * @handle: the bay handle @@ -394,38 +326,19 @@ static struct acpi_device * bay_create_acpi_device(acpi_handle handle) */ static void bay_notify(acpi_handle handle, u32 event, void *data) { - struct acpi_device *dev; + struct bay *bay_dev = (struct bay *)data; + struct device *dev = &bay_dev->pdev->dev; bay_dprintk(handle, "Bay event"); switch(event) { case ACPI_NOTIFY_BUS_CHECK: - printk("Bus Check\n"); case ACPI_NOTIFY_DEVICE_CHECK: - printk("Device Check\n"); - dev = bay_create_acpi_device(handle); - if (dev) - acpi_bus_generate_event(dev, event, 0); - else - printk("No device for generating event\n"); - /* wouldn't it be a good idea to just rescan SATA - * right here? - */ - break; case ACPI_NOTIFY_EJECT_REQUEST: - printk("Eject request\n"); - dev = bay_create_acpi_device(handle); - if (dev) - acpi_bus_generate_event(dev, event, 0); - else - printk("No device for generating eventn"); - - /* wouldn't it be a good idea to just call the - * eject_device here if we were a SATA device? - */ + kobject_uevent(&dev->kobj, KOBJ_CHANGE); break; default: - printk("unknown event %d\n", event); + printk(KERN_ERR PREFIX "Bay: unknown event %d\n", event); } } @@ -457,10 +370,6 @@ static int __init bay_init(void) acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, find_bay, &bays, NULL); - if (bays) - if ((acpi_bus_register_driver(&acpi_bay_driver) < 0)) - printk(KERN_ERR "Unable to register bay driver\n"); - if (!bays) return -ENODEV; @@ -481,8 +390,6 @@ static void __exit bay_exit(void) kfree(bay->name); kfree(bay); } - - acpi_bus_unregister_driver(&acpi_bay_driver); } postcore_initcall(bay_init); diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index c26468da4295..dd49ea0d0ed3 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -39,7 +39,7 @@ #include <acpi/acpi_drivers.h> #define _COMPONENT ACPI_BUS_COMPONENT -ACPI_MODULE_NAME("acpi_bus") +ACPI_MODULE_NAME("bus"); #ifdef CONFIG_X86 extern void __init acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger); #endif @@ -147,7 +147,7 @@ int acpi_bus_get_power(acpi_handle handle, int *state) *state = ACPI_STATE_D0; } else { /* - * Get the device's power state either directly (via _PSC) or + * Get the device's power state either directly (via _PSC) or * indirectly (via power resources). */ if (device->power.flags.explicit_get) { @@ -199,15 +199,14 @@ int acpi_bus_set_power(acpi_handle handle, int state) * Get device's current power state if it's unknown * This means device power state isn't initialized or previous setting failed */ - if (!device->flags.force_power_state) { - if (device->power.state == ACPI_STATE_UNKNOWN) - acpi_bus_get_power(device->handle, &device->power.state); - if (state == device->power.state) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n", - state)); - return 0; - } + if ((device->power.state == ACPI_STATE_UNKNOWN) || device->flags.force_power_state) + acpi_bus_get_power(device->handle, &device->power.state); + if ((state == device->power.state) && !device->flags.force_power_state) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n", + state)); + return 0; } + if (!device->power.states[state].flags.valid) { printk(KERN_WARNING PREFIX "Device does not support D%d\n", state); return -ENODEV; @@ -462,7 +461,7 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) "Received BUS CHECK notification for device [%s]\n", device->pnp.bus_id)); result = acpi_bus_check_scope(device); - /* + /* * TBD: We'll need to outsource certain events to non-ACPI * drivers via the device manager (device.c). */ @@ -473,7 +472,7 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) "Received DEVICE CHECK notification for device [%s]\n", device->pnp.bus_id)); result = acpi_bus_check_device(device, NULL); - /* + /* * TBD: We'll need to outsource certain events to non-ACPI * drivers via the device manager (device.c). */ @@ -543,7 +542,7 @@ static int __init acpi_bus_init_irq(void) char *message = NULL; - /* + /* * Let the system know what interrupt model we are using by * evaluating the \_PIC object, if exists. */ @@ -684,7 +683,7 @@ static int __init acpi_bus_init(void) * the EC device is found in the namespace (i.e. before acpi_initialize_objects() * is called). * - * This is accomplished by looking for the ECDT table, and getting + * This is accomplished by looking for the ECDT table, and getting * the EC parameters out of that. */ status = acpi_ec_ecdt_probe(); @@ -699,6 +698,9 @@ static int __init acpi_bus_init(void) printk(KERN_INFO PREFIX "Interpreter enabled\n"); + /* Initialize sleep structures */ + acpi_sleep_init(); + /* * Get the system interrupt model and evaluate \_PIC. */ diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index c726612fafb6..cb4110b50cd0 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -34,7 +34,6 @@ #include <acpi/acpi_drivers.h> #define ACPI_BUTTON_COMPONENT 0x00080000 -#define ACPI_BUTTON_DRIVER_NAME "ACPI Button Driver" #define ACPI_BUTTON_CLASS "button" #define ACPI_BUTTON_FILE_INFO "info" #define ACPI_BUTTON_FILE_STATE "state" @@ -61,10 +60,10 @@ #define ACPI_BUTTON_TYPE_LID 0x05 #define _COMPONENT ACPI_BUTTON_COMPONENT -ACPI_MODULE_NAME("acpi_button") +ACPI_MODULE_NAME("button"); MODULE_AUTHOR("Paul Diefenbaugh"); -MODULE_DESCRIPTION(ACPI_BUTTON_DRIVER_NAME); +MODULE_DESCRIPTION("ACPI Button Driver"); MODULE_LICENSE("GPL"); static int acpi_button_add(struct acpi_device *device); @@ -73,7 +72,7 @@ static int acpi_button_info_open_fs(struct inode *inode, struct file *file); static int acpi_button_state_open_fs(struct inode *inode, struct file *file); static struct acpi_driver acpi_button_driver = { - .name = ACPI_BUTTON_DRIVER_NAME, + .name = "button", .class = ACPI_BUTTON_CLASS, .ids = "button_power,button_sleep,PNP0C0D,PNP0C0C,PNP0C0E", .ops = { diff --git a/drivers/acpi/cm_sbs.c b/drivers/acpi/cm_sbs.c index 4a9b7bf6f44e..f9db4f444bd0 100644 --- a/drivers/acpi/cm_sbs.c +++ b/drivers/acpi/cm_sbs.c @@ -31,7 +31,7 @@ #include <acpi/actypes.h> #include <acpi/acutils.h> -ACPI_MODULE_NAME("cm_sbs") +ACPI_MODULE_NAME("cm_sbs"); #define ACPI_AC_CLASS "ac_adapter" #define ACPI_BATTERY_CLASS "battery" #define ACPI_SBS_COMPONENT 0x00080000 diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c index 69a68fd394cf..0930d9413dfa 100644 --- a/drivers/acpi/container.c +++ b/drivers/acpi/container.c @@ -35,7 +35,6 @@ #include <acpi/acpi_drivers.h> #include <acpi/container.h> -#define ACPI_CONTAINER_DRIVER_NAME "ACPI container driver" #define ACPI_CONTAINER_DEVICE_NAME "ACPI container device" #define ACPI_CONTAINER_CLASS "container" @@ -44,10 +43,10 @@ #define ACPI_CONTAINER_COMPONENT 0x01000000 #define _COMPONENT ACPI_CONTAINER_COMPONENT -ACPI_MODULE_NAME("acpi_container") +ACPI_MODULE_NAME("container"); - MODULE_AUTHOR("Anil S Keshavamurthy"); -MODULE_DESCRIPTION(ACPI_CONTAINER_DRIVER_NAME); +MODULE_AUTHOR("Anil S Keshavamurthy"); +MODULE_DESCRIPTION("ACPI container driver"); MODULE_LICENSE("GPL"); #define ACPI_STA_PRESENT (0x00000001) @@ -56,7 +55,7 @@ static int acpi_container_add(struct acpi_device *device); static int acpi_container_remove(struct acpi_device *device, int type); static struct acpi_driver acpi_container_driver = { - .name = ACPI_CONTAINER_DRIVER_NAME, + .name = "container", .class = ACPI_CONTAINER_CLASS, .ids = "ACPI0004,PNP0A05,PNP0A06", .ops = { diff --git a/drivers/acpi/debug.c b/drivers/acpi/debug.c index d48f65a8f658..bf513e07b773 100644 --- a/drivers/acpi/debug.c +++ b/drivers/acpi/debug.c @@ -12,7 +12,7 @@ #include <acpi/acglobal.h> #define _COMPONENT ACPI_SYSTEM_COMPONENT -ACPI_MODULE_NAME("debug") +ACPI_MODULE_NAME("debug"); #ifdef MODULE_PARAM_PREFIX #undef MODULE_PARAM_PREFIX diff --git a/drivers/acpi/dispatcher/dsmethod.c b/drivers/acpi/dispatcher/dsmethod.c index 1cbe61905824..1683e5c5b94c 100644 --- a/drivers/acpi/dispatcher/dsmethod.c +++ b/drivers/acpi/dispatcher/dsmethod.c @@ -231,10 +231,8 @@ acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node, * Obtain the method mutex if necessary. Do not acquire mutex for a * recursive call. */ - if (!walk_state || - !obj_desc->method.mutex->mutex.owner_thread || - (walk_state->thread != - obj_desc->method.mutex->mutex.owner_thread)) { + if (acpi_os_get_thread_id() != + obj_desc->method.mutex->mutex.owner_thread_id) { /* * Acquire the method mutex. This releases the interpreter if we * block (and reacquires it before it returns) @@ -248,14 +246,14 @@ acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node, } /* Update the mutex and walk info and save the original sync_level */ + obj_desc->method.mutex->mutex.owner_thread_id = + acpi_os_get_thread_id(); if (walk_state) { obj_desc->method.mutex->mutex. original_sync_level = walk_state->thread->current_sync_level; - obj_desc->method.mutex->mutex.owner_thread = - walk_state->thread; walk_state->thread->current_sync_level = obj_desc->method.sync_level; } else { @@ -569,7 +567,7 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc, acpi_os_release_mutex(method_desc->method.mutex->mutex. os_mutex); - method_desc->method.mutex->mutex.owner_thread = NULL; + method_desc->method.mutex->mutex.owner_thread_id = ACPI_MUTEX_NOT_ACQUIRED; } } diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 688e83a16906..54a697f9aa18 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -32,11 +32,11 @@ #include <acpi/acpi_bus.h> #include <acpi/acpi_drivers.h> -#define ACPI_DOCK_DRIVER_NAME "ACPI Dock Station Driver" +#define ACPI_DOCK_DRIVER_DESCRIPTION "ACPI Dock Station Driver" -ACPI_MODULE_NAME("dock") +ACPI_MODULE_NAME("dock"); MODULE_AUTHOR("Kristen Carlson Accardi"); -MODULE_DESCRIPTION(ACPI_DOCK_DRIVER_NAME); +MODULE_DESCRIPTION(ACPI_DOCK_DRIVER_DESCRIPTION); MODULE_LICENSE("GPL"); static struct atomic_notifier_head dock_notifier_list; @@ -741,7 +741,7 @@ static int dock_add(acpi_handle handle) goto dock_add_err; } - printk(KERN_INFO PREFIX "%s \n", ACPI_DOCK_DRIVER_NAME); + printk(KERN_INFO PREFIX "%s \n", ACPI_DOCK_DRIVER_DESCRIPTION); return 0; diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 743ce27fa0bb..ab6888373795 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -38,11 +38,10 @@ #include <acpi/actypes.h> #define _COMPONENT ACPI_EC_COMPONENT -ACPI_MODULE_NAME("acpi_ec") +ACPI_MODULE_NAME("ec"); #define ACPI_EC_COMPONENT 0x00100000 #define ACPI_EC_CLASS "embedded_controller" #define ACPI_EC_HID "PNP0C09" -#define ACPI_EC_DRIVER_NAME "ACPI Embedded Controller Driver" #define ACPI_EC_DEVICE_NAME "Embedded Controller" #define ACPI_EC_FILE_INFO "info" #undef PREFIX @@ -80,7 +79,7 @@ static int acpi_ec_stop(struct acpi_device *device, int type); static int acpi_ec_add(struct acpi_device *device); static struct acpi_driver acpi_ec_driver = { - .name = ACPI_EC_DRIVER_NAME, + .name = "ec", .class = ACPI_EC_CLASS, .ids = ACPI_EC_HID, .ops = { @@ -280,8 +279,10 @@ static int acpi_ec_transaction(struct acpi_ec *ec, u8 command, mutex_lock(&ec->lock); if (ec->global_lock) { status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk); - if (ACPI_FAILURE(status)) + if (ACPI_FAILURE(status)) { + mutex_unlock(&ec->lock); return -ENODEV; + } } /* Make sure GPE is enabled before doing transaction */ diff --git a/drivers/acpi/event.c b/drivers/acpi/event.c index 959a893c8d1f..3b23562e6f92 100644 --- a/drivers/acpi/event.c +++ b/drivers/acpi/event.c @@ -13,7 +13,7 @@ #include <acpi/acpi_drivers.h> #define _COMPONENT ACPI_SYSTEM_COMPONENT -ACPI_MODULE_NAME("event") +ACPI_MODULE_NAME("event"); /* Global vars for handling event proc entry */ static DEFINE_SPINLOCK(acpi_system_event_lock); diff --git a/drivers/acpi/events/evgpe.c b/drivers/acpi/events/evgpe.c index dfac3ecc596e..635ba449ebc2 100644 --- a/drivers/acpi/events/evgpe.c +++ b/drivers/acpi/events/evgpe.c @@ -636,17 +636,6 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number) } } - if (!acpi_gbl_system_awake_and_running) { - /* - * We just woke up because of a wake GPE. Disable any further GPEs - * until we are fully up and running (Only wake GPEs should be enabled - * at this time, but we just brute-force disable them all.) - * 1) We must disable this particular wake GPE so it won't fire again - * 2) We want to disable all wake GPEs, since we are now awake - */ - (void)acpi_hw_disable_all_gpes(); - } - /* * Dispatch the GPE to either an installed handler, or the control method * associated with this GPE (_Lxx or _Exx). If a handler exists, we invoke diff --git a/drivers/acpi/events/evmisc.c b/drivers/acpi/events/evmisc.c index 1b784ffe54c3..d572700197f3 100644 --- a/drivers/acpi/events/evmisc.c +++ b/drivers/acpi/events/evmisc.c @@ -196,12 +196,11 @@ acpi_ev_queue_notify_request(struct acpi_namespace_node * node, notify_info->notify.value = (u16) notify_value; notify_info->notify.handler_obj = handler_obj; - status = - acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_ev_notify_dispatch, - notify_info); - if (ACPI_FAILURE(status)) { - acpi_ut_delete_generic_state(notify_info); - } + acpi_ex_relinquish_interpreter(); + + acpi_ev_notify_dispatch(notify_info); + + acpi_ex_reacquire_interpreter(); } if (!handler_obj) { diff --git a/drivers/acpi/executer/exdump.c b/drivers/acpi/executer/exdump.c index 68d283fd60e7..1a73c14df2c5 100644 --- a/drivers/acpi/executer/exdump.c +++ b/drivers/acpi/executer/exdump.c @@ -134,7 +134,7 @@ static struct acpi_exdump_info acpi_ex_dump_method[8] = { static struct acpi_exdump_info acpi_ex_dump_mutex[5] = { {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_mutex), NULL}, {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(mutex.sync_level), "Sync Level"}, - {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(mutex.owner_thread), "Owner Thread"}, + {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(mutex.owner_thread_id), "Owner Thread"}, {ACPI_EXD_UINT16, ACPI_EXD_OFFSET(mutex.acquisition_depth), "Acquire Depth"}, {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(mutex.os_mutex), "OsMutex"} diff --git a/drivers/acpi/executer/exmutex.c b/drivers/acpi/executer/exmutex.c index 5101bad5baf8..4eb883bda6ae 100644 --- a/drivers/acpi/executer/exmutex.c +++ b/drivers/acpi/executer/exmutex.c @@ -66,10 +66,9 @@ acpi_ex_link_mutex(union acpi_operand_object *obj_desc, * ******************************************************************************/ -void acpi_ex_unlink_mutex(union acpi_operand_object *obj_desc) +void acpi_ex_unlink_mutex(union acpi_operand_object *obj_desc, + struct acpi_thread_state *thread) { - struct acpi_thread_state *thread = obj_desc->mutex.owner_thread; - if (!thread) { return; } @@ -174,16 +173,13 @@ acpi_ex_acquire_mutex(union acpi_operand_object *time_desc, /* Support for multiple acquires by the owning thread */ - if (obj_desc->mutex.owner_thread) { - if (obj_desc->mutex.owner_thread->thread_id == - walk_state->thread->thread_id) { - /* - * The mutex is already owned by this thread, just increment the - * acquisition depth - */ - obj_desc->mutex.acquisition_depth++; - return_ACPI_STATUS(AE_OK); - } + if (obj_desc->mutex.owner_thread_id == acpi_os_get_thread_id()) { + /* + * The mutex is already owned by this thread, just increment the + * acquisition depth + */ + obj_desc->mutex.acquisition_depth++; + return_ACPI_STATUS(AE_OK); } /* Acquire the mutex, wait if necessary. Special case for Global Lock */ @@ -206,7 +202,7 @@ acpi_ex_acquire_mutex(union acpi_operand_object *time_desc, /* Have the mutex: update mutex and walk info and save the sync_level */ - obj_desc->mutex.owner_thread = walk_state->thread; + obj_desc->mutex.owner_thread_id = acpi_os_get_thread_id(); obj_desc->mutex.acquisition_depth = 1; obj_desc->mutex.original_sync_level = walk_state->thread->current_sync_level; @@ -246,7 +242,7 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc, /* The mutex must have been previously acquired in order to release it */ - if (!obj_desc->mutex.owner_thread) { + if (!obj_desc->mutex.owner_thread_id) { ACPI_ERROR((AE_INFO, "Cannot release Mutex [%4.4s], not acquired", acpi_ut_get_node_name(obj_desc->mutex.node))); @@ -266,14 +262,14 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc, * The Mutex is owned, but this thread must be the owner. * Special case for Global Lock, any thread can release */ - if ((obj_desc->mutex.owner_thread->thread_id != + if ((obj_desc->mutex.owner_thread_id != walk_state->thread->thread_id) && (obj_desc->mutex.os_mutex != acpi_gbl_global_lock_mutex)) { ACPI_ERROR((AE_INFO, "Thread %lX cannot release Mutex [%4.4s] acquired by thread %lX", (unsigned long)walk_state->thread->thread_id, acpi_ut_get_node_name(obj_desc->mutex.node), - (unsigned long)obj_desc->mutex.owner_thread->thread_id)); + (unsigned long)obj_desc->mutex.owner_thread_id)); return_ACPI_STATUS(AE_AML_NOT_OWNER); } @@ -300,7 +296,7 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc, /* Unlink the mutex from the owner's list */ - acpi_ex_unlink_mutex(obj_desc); + acpi_ex_unlink_mutex(obj_desc, walk_state->thread); /* Release the mutex, special case for Global Lock */ @@ -312,7 +308,7 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc, /* Update the mutex and restore sync_level */ - obj_desc->mutex.owner_thread = NULL; + obj_desc->mutex.owner_thread_id = ACPI_MUTEX_NOT_ACQUIRED; walk_state->thread->current_sync_level = obj_desc->mutex.original_sync_level; @@ -367,7 +363,7 @@ void acpi_ex_release_all_mutexes(struct acpi_thread_state *thread) /* Mark mutex unowned */ - obj_desc->mutex.owner_thread = NULL; + obj_desc->mutex.owner_thread_id = ACPI_MUTEX_NOT_ACQUIRED; /* Update Thread sync_level (Last mutex is the important one) */ diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c index af22fdf73413..ec655c539492 100644 --- a/drivers/acpi/fan.c +++ b/drivers/acpi/fan.c @@ -36,14 +36,13 @@ #define ACPI_FAN_COMPONENT 0x00200000 #define ACPI_FAN_CLASS "fan" -#define ACPI_FAN_DRIVER_NAME "ACPI Fan Driver" #define ACPI_FAN_FILE_STATE "state" #define _COMPONENT ACPI_FAN_COMPONENT -ACPI_MODULE_NAME("acpi_fan") +ACPI_MODULE_NAME("fan"); - MODULE_AUTHOR("Paul Diefenbaugh"); -MODULE_DESCRIPTION(ACPI_FAN_DRIVER_NAME); +MODULE_AUTHOR("Paul Diefenbaugh"); +MODULE_DESCRIPTION("ACPI Fan Driver"); MODULE_LICENSE("GPL"); static int acpi_fan_add(struct acpi_device *device); @@ -52,7 +51,7 @@ static int acpi_fan_suspend(struct acpi_device *device, pm_message_t state); static int acpi_fan_resume(struct acpi_device *device); static struct acpi_driver acpi_fan_driver = { - .name = ACPI_FAN_DRIVER_NAME, + .name = "fan", .class = ACPI_FAN_CLASS, .ids = "PNP0C0B", .ops = { diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 7b6c9ff9bebe..4334c208841a 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -241,3 +241,65 @@ static int __init init_acpi_device_notify(void) } arch_initcall(init_acpi_device_notify); + + +#if defined(CONFIG_RTC_DRV_CMOS) || defined(CONFIG_RTC_DRV_CMOS_MODULE) + +/* Every ACPI platform has a mc146818 compatible "cmos rtc". Here we find + * its device node and pass extra config data. This helps its driver use + * capabilities that the now-obsolete mc146818 didn't have, and informs it + * that this board's RTC is wakeup-capable (per ACPI spec). + */ +#include <linux/mc146818rtc.h> + +static struct cmos_rtc_board_info rtc_info; + + +/* PNP devices are registered in a subsys_initcall(); + * ACPI specifies the PNP IDs to use. + */ +#include <linux/pnp.h> + +static int __init pnp_match(struct device *dev, void *data) +{ + static const char *ids[] = { "PNP0b00", "PNP0b01", "PNP0b02", }; + struct pnp_dev *pnp = to_pnp_dev(dev); + int i; + + for (i = 0; i < ARRAY_SIZE(ids); i++) { + if (compare_pnp_id(pnp->id, ids[i]) != 0) + return 1; + } + return 0; +} + +static struct device *__init get_rtc_dev(void) +{ + return bus_find_device(&pnp_bus_type, NULL, NULL, pnp_match); +} + +static int __init acpi_rtc_init(void) +{ + struct device *dev = get_rtc_dev(); + + if (dev) { + rtc_info.rtc_day_alarm = acpi_gbl_FADT.day_alarm; + rtc_info.rtc_mon_alarm = acpi_gbl_FADT.month_alarm; + rtc_info.rtc_century = acpi_gbl_FADT.century; + + /* NOTE: acpi_gbl_FADT->rtcs4 is NOT currently useful */ + + dev->platform_data = &rtc_info; + + /* RTC always wakes from S1/S2/S3, and often S4/STD */ + device_init_wakeup(dev, 1); + + put_device(dev); + } else + pr_debug("ACPI: RTC unavailable?\n"); + return 0; +} +/* do this between RTC subsys_initcall() and rtc_cmos driver_initcall() */ +fs_initcall(acpi_rtc_init); + +#endif diff --git a/drivers/acpi/hardware/hwsleep.c b/drivers/acpi/hardware/hwsleep.c index 57901ca3ade9..8fa93125fd4c 100644 --- a/drivers/acpi/hardware/hwsleep.c +++ b/drivers/acpi/hardware/hwsleep.c @@ -235,6 +235,14 @@ acpi_status acpi_enter_sleep_state_prep(u8 sleep_state) "While executing method _SST")); } + /* + * 1) Disable/Clear all GPEs + */ + status = acpi_hw_disable_all_gpes(); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + return_ACPI_STATUS(AE_OK); } @@ -290,13 +298,8 @@ acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state) } /* - * 1) Disable/Clear all GPEs * 2) Enable all wakeup GPEs */ - status = acpi_hw_disable_all_gpes(); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } acpi_gbl_system_awake_and_running = FALSE; status = acpi_hw_enable_all_wakeup_gpes(); diff --git a/drivers/acpi/hotkey.c b/drivers/acpi/hotkey.c deleted file mode 100644 index 8edfb92f7ede..000000000000 --- a/drivers/acpi/hotkey.c +++ /dev/null @@ -1,1042 +0,0 @@ -/* - * hotkey.c - ACPI Hotkey Driver ($Revision: 0.2 $) - * - * Copyright (C) 2004 Luming Yu <luming.yu@intel.com> - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/types.h> -#include <linux/proc_fs.h> -#include <linux/sched.h> -#include <linux/kmod.h> -#include <linux/seq_file.h> -#include <acpi/acpi_drivers.h> -#include <acpi/acpi_bus.h> -#include <asm/uaccess.h> - -#define HOTKEY_ACPI_VERSION "0.1" - -#define HOTKEY_PROC "hotkey" -#define HOTKEY_EV_CONFIG "event_config" -#define HOTKEY_PL_CONFIG "poll_config" -#define HOTKEY_ACTION "action" -#define HOTKEY_INFO "info" - -#define ACPI_HOTK_NAME "Generic Hotkey Driver" -#define ACPI_HOTK_CLASS "Hotkey" -#define ACPI_HOTK_DEVICE_NAME "Hotkey" -#define ACPI_HOTK_HID "Unknown?" -#define ACPI_HOTKEY_COMPONENT 0x20000000 - -#define ACPI_HOTKEY_EVENT 0x1 -#define ACPI_HOTKEY_POLLING 0x2 -#define ACPI_UNDEFINED_EVENT 0xf - -#define RESULT_STR_LEN 80 - -#define ACTION_METHOD 0 -#define POLL_METHOD 1 - -#define IS_EVENT(e) ((e) <= 10000 && (e) >0) -#define IS_POLL(e) ((e) > 10000) -#define IS_OTHERS(e) ((e)<=0 || (e)>=20000) -#define _COMPONENT ACPI_HOTKEY_COMPONENT -ACPI_MODULE_NAME("acpi_hotkey") - - MODULE_AUTHOR("luming.yu@intel.com"); -MODULE_DESCRIPTION(ACPI_HOTK_NAME); -MODULE_LICENSE("GPL"); - -/* standardized internal hotkey number/event */ -enum { - /* Video Extension event */ - HK_EVENT_CYCLE_OUTPUT_DEVICE = 0x80, - HK_EVENT_OUTPUT_DEVICE_STATUS_CHANGE, - HK_EVENT_CYCLE_DISPLAY_OUTPUT, - HK_EVENT_NEXT_DISPLAY_OUTPUT, - HK_EVENT_PREVIOUS_DISPLAY_OUTPUT, - HK_EVENT_CYCLE_BRIGHTNESS, - HK_EVENT_INCREASE_BRIGHTNESS, - HK_EVENT_DECREASE_BRIGHTNESS, - HK_EVENT_ZERO_BRIGHTNESS, - HK_EVENT_DISPLAY_DEVICE_OFF, - - /* Snd Card event */ - HK_EVENT_VOLUME_MUTE, - HK_EVENT_VOLUME_INCLREASE, - HK_EVENT_VOLUME_DECREASE, - - /* running state control */ - HK_EVENT_ENTERRING_S3, - HK_EVENT_ENTERRING_S4, - HK_EVENT_ENTERRING_S5, -}; - -enum conf_entry_enum { - bus_handle = 0, - bus_method = 1, - action_handle = 2, - method = 3, - LAST_CONF_ENTRY -}; - -/* procdir we use */ -static struct proc_dir_entry *hotkey_proc_dir; -static struct proc_dir_entry *hotkey_config; -static struct proc_dir_entry *hotkey_poll_config; -static struct proc_dir_entry *hotkey_action; -static struct proc_dir_entry *hotkey_info; - -/* linkage for all type of hotkey */ -struct acpi_hotkey_link { - struct list_head entries; - int hotkey_type; /* event or polling based hotkey */ - int hotkey_standard_num; /* standardized hotkey(event) number */ -}; - -/* event based hotkey */ -struct acpi_event_hotkey { - struct acpi_hotkey_link hotkey_link; - int flag; - acpi_handle bus_handle; /* bus to install notify handler */ - int external_hotkey_num; /* external hotkey/event number */ - acpi_handle action_handle; /* acpi handle attached aml action method */ - char *action_method; /* action method */ -}; - -/* - * There are two ways to poll status - * 1. directy call read_xxx method, without any arguments passed in - * 2. call write_xxx method, with arguments passed in, you need - * the result is saved in acpi_polling_hotkey.poll_result. - * anthoer read command through polling interface. - * - */ - -/* polling based hotkey */ -struct acpi_polling_hotkey { - struct acpi_hotkey_link hotkey_link; - int flag; - acpi_handle poll_handle; /* acpi handle attached polling method */ - char *poll_method; /* poll method */ - acpi_handle action_handle; /* acpi handle attached action method */ - char *action_method; /* action method */ - union acpi_object *poll_result; /* polling_result */ - struct proc_dir_entry *proc; -}; - -/* hotkey object union */ -union acpi_hotkey { - struct list_head entries; - struct acpi_hotkey_link link; - struct acpi_event_hotkey event_hotkey; - struct acpi_polling_hotkey poll_hotkey; -}; - -/* hotkey object list */ -struct acpi_hotkey_list { - struct list_head *entries; - int count; -}; - -static int auto_hotkey_add(struct acpi_device *device); -static int auto_hotkey_remove(struct acpi_device *device, int type); - -static struct acpi_driver hotkey_driver = { - .name = ACPI_HOTK_NAME, - .class = ACPI_HOTK_CLASS, - .ids = ACPI_HOTK_HID, - .ops = { - .add = auto_hotkey_add, - .remove = auto_hotkey_remove, - }, -}; - -static void free_hotkey_device(union acpi_hotkey *key); -static void free_hotkey_buffer(union acpi_hotkey *key); -static void free_poll_hotkey_buffer(union acpi_hotkey *key); -static int hotkey_open_config(struct inode *inode, struct file *file); -static int hotkey_poll_open_config(struct inode *inode, struct file *file); -static ssize_t hotkey_write_config(struct file *file, - const char __user * buffer, - size_t count, loff_t * data); -static int hotkey_info_open_fs(struct inode *inode, struct file *file); -static int hotkey_action_open_fs(struct inode *inode, struct file *file); -static ssize_t hotkey_execute_aml_method(struct file *file, - const char __user * buffer, - size_t count, loff_t * data); -static int hotkey_config_seq_show(struct seq_file *seq, void *offset); -static int hotkey_poll_config_seq_show(struct seq_file *seq, void *offset); -static int hotkey_polling_open_fs(struct inode *inode, struct file *file); -static union acpi_hotkey *get_hotkey_by_event(struct - acpi_hotkey_list - *hotkey_list, int event); - -/* event based config */ -static const struct file_operations hotkey_config_fops = { - .open = hotkey_open_config, - .read = seq_read, - .write = hotkey_write_config, - .llseek = seq_lseek, - .release = single_release, -}; - -/* polling based config */ -static const struct file_operations hotkey_poll_config_fops = { - .open = hotkey_poll_open_config, - .read = seq_read, - .write = hotkey_write_config, - .llseek = seq_lseek, - .release = single_release, -}; - -/* hotkey driver info */ -static const struct file_operations hotkey_info_fops = { - .open = hotkey_info_open_fs, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -/* action */ -static const struct file_operations hotkey_action_fops = { - .open = hotkey_action_open_fs, - .read = seq_read, - .write = hotkey_execute_aml_method, - .llseek = seq_lseek, - .release = single_release, -}; - -/* polling results */ -static const struct file_operations hotkey_polling_fops = { - .open = hotkey_polling_open_fs, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -struct acpi_hotkey_list global_hotkey_list; /* link all ev or pl hotkey */ -struct list_head hotkey_entries; /* head of the list of hotkey_list */ - -static int hotkey_info_seq_show(struct seq_file *seq, void *offset) -{ - - seq_printf(seq, "Hotkey generic driver ver: %s\n", HOTKEY_ACPI_VERSION); - - return 0; -} - -static int hotkey_info_open_fs(struct inode *inode, struct file *file) -{ - return single_open(file, hotkey_info_seq_show, PDE(inode)->data); -} - -static char *format_result(union acpi_object *object) -{ - char *buf; - - buf = kzalloc(RESULT_STR_LEN, GFP_KERNEL); - if (!buf) - return NULL; - /* Now, just support integer type */ - if (object->type == ACPI_TYPE_INTEGER) - sprintf(buf, "%d\n", (u32) object->integer.value); - return buf; -} - -static int hotkey_polling_seq_show(struct seq_file *seq, void *offset) -{ - struct acpi_polling_hotkey *poll_hotkey = seq->private; - char *buf; - - - if (poll_hotkey->poll_result) { - buf = format_result(poll_hotkey->poll_result); - if (buf) - seq_printf(seq, "%s", buf); - kfree(buf); - } - return 0; -} - -static int hotkey_polling_open_fs(struct inode *inode, struct file *file) -{ - return single_open(file, hotkey_polling_seq_show, PDE(inode)->data); -} - -static int hotkey_action_open_fs(struct inode *inode, struct file *file) -{ - return single_open(file, hotkey_info_seq_show, PDE(inode)->data); -} - -/* Mapping external hotkey number to standardized hotkey event num */ -static int hotkey_get_internal_event(int event, struct acpi_hotkey_list *list) -{ - struct list_head *entries; - int val = -1; - - - list_for_each(entries, list->entries) { - union acpi_hotkey *key = - container_of(entries, union acpi_hotkey, entries); - if (key->link.hotkey_type == ACPI_HOTKEY_EVENT - && key->event_hotkey.external_hotkey_num == event) { - val = key->link.hotkey_standard_num; - break; - } - } - - return val; -} - -static void -acpi_hotkey_notify_handler(acpi_handle handle, u32 event, void *data) -{ - struct acpi_device *device = NULL; - u32 internal_event; - - - if (acpi_bus_get_device(handle, &device)) - return; - - internal_event = hotkey_get_internal_event(event, &global_hotkey_list); - acpi_bus_generate_event(device, internal_event, 0); - - return; -} - -/* Need to invent automatically hotkey add method */ -static int auto_hotkey_add(struct acpi_device *device) -{ - /* Implement me */ - return 0; -} - -/* Need to invent automatically hotkey remove method */ -static int auto_hotkey_remove(struct acpi_device *device, int type) -{ - /* Implement me */ - return 0; -} - -/* Create a proc file for each polling method */ -static int create_polling_proc(union acpi_hotkey *device) -{ - struct proc_dir_entry *proc; - char proc_name[80]; - mode_t mode; - - mode = S_IFREG | S_IRUGO | S_IWUGO; - - sprintf(proc_name, "%d", device->link.hotkey_standard_num); - /* - strcat(proc_name, device->poll_hotkey.poll_method); - */ - proc = create_proc_entry(proc_name, mode, hotkey_proc_dir); - - if (!proc) { - return -ENODEV; - } else { - proc->proc_fops = &hotkey_polling_fops; - proc->owner = THIS_MODULE; - proc->data = device; - proc->uid = 0; - proc->gid = 0; - device->poll_hotkey.proc = proc; - } - return 0; -} - -static int hotkey_add(union acpi_hotkey *device) -{ - int status = 0; - struct acpi_device *dev = NULL; - - - if (device->link.hotkey_type == ACPI_HOTKEY_EVENT) { - acpi_bus_get_device(device->event_hotkey.bus_handle, &dev); - status = acpi_install_notify_handler(dev->handle, - ACPI_DEVICE_NOTIFY, - acpi_hotkey_notify_handler, - dev); - } else /* Add polling hotkey */ - create_polling_proc(device); - - global_hotkey_list.count++; - - list_add_tail(&device->link.entries, global_hotkey_list.entries); - - return status; -} - -static int hotkey_remove(union acpi_hotkey *device) -{ - struct list_head *entries, *next; - - - list_for_each_safe(entries, next, global_hotkey_list.entries) { - union acpi_hotkey *key = - container_of(entries, union acpi_hotkey, entries); - if (key->link.hotkey_standard_num == - device->link.hotkey_standard_num) { - list_del(&key->link.entries); - free_hotkey_device(key); - global_hotkey_list.count--; - break; - } - } - kfree(device); - return 0; -} - -static int hotkey_update(union acpi_hotkey *key) -{ - struct list_head *entries; - - - list_for_each(entries, global_hotkey_list.entries) { - union acpi_hotkey *tmp = - container_of(entries, union acpi_hotkey, entries); - if (tmp->link.hotkey_standard_num == - key->link.hotkey_standard_num) { - if (key->link.hotkey_type == ACPI_HOTKEY_EVENT) { - free_hotkey_buffer(tmp); - tmp->event_hotkey.bus_handle = - key->event_hotkey.bus_handle; - tmp->event_hotkey.external_hotkey_num = - key->event_hotkey.external_hotkey_num; - tmp->event_hotkey.action_handle = - key->event_hotkey.action_handle; - tmp->event_hotkey.action_method = - key->event_hotkey.action_method; - kfree(key); - } else { - /* - char proc_name[80]; - - sprintf(proc_name, "%d", tmp->link.hotkey_standard_num); - strcat(proc_name, tmp->poll_hotkey.poll_method); - remove_proc_entry(proc_name,hotkey_proc_dir); - */ - free_poll_hotkey_buffer(tmp); - tmp->poll_hotkey.poll_handle = - key->poll_hotkey.poll_handle; - tmp->poll_hotkey.poll_method = - key->poll_hotkey.poll_method; - tmp->poll_hotkey.action_handle = - key->poll_hotkey.action_handle; - tmp->poll_hotkey.action_method = - key->poll_hotkey.action_method; - tmp->poll_hotkey.poll_result = - key->poll_hotkey.poll_result; - /* - create_polling_proc(tmp); - */ - kfree(key); - } - return 0; - break; - } - } - - return -ENODEV; -} - -static void free_hotkey_device(union acpi_hotkey *key) -{ - struct acpi_device *dev; - - - if (key->link.hotkey_type == ACPI_HOTKEY_EVENT) { - acpi_bus_get_device(key->event_hotkey.bus_handle, &dev); - if (dev->handle) - acpi_remove_notify_handler(dev->handle, - ACPI_DEVICE_NOTIFY, - acpi_hotkey_notify_handler); - free_hotkey_buffer(key); - } else { - char proc_name[80]; - - sprintf(proc_name, "%d", key->link.hotkey_standard_num); - /* - strcat(proc_name, key->poll_hotkey.poll_method); - */ - remove_proc_entry(proc_name, hotkey_proc_dir); - free_poll_hotkey_buffer(key); - } - kfree(key); - return; -} - -static void free_hotkey_buffer(union acpi_hotkey *key) -{ - /* key would never be null, action method could be */ - kfree(key->event_hotkey.action_method); -} - -static void free_poll_hotkey_buffer(union acpi_hotkey *key) -{ - /* key would never be null, others could be*/ - kfree(key->poll_hotkey.action_method); - kfree(key->poll_hotkey.poll_method); - kfree(key->poll_hotkey.poll_result); -} -static int -init_hotkey_device(union acpi_hotkey *key, char **config_entry, - int std_num, int external_num) -{ - acpi_handle tmp_handle; - acpi_status status = AE_OK; - - if (std_num < 0 || IS_POLL(std_num) || !key) - goto do_fail; - - if (!config_entry[bus_handle] || !config_entry[action_handle] - || !config_entry[method]) - goto do_fail; - - key->link.hotkey_type = ACPI_HOTKEY_EVENT; - key->link.hotkey_standard_num = std_num; - key->event_hotkey.flag = 0; - key->event_hotkey.action_method = config_entry[method]; - - status = acpi_get_handle(NULL, config_entry[bus_handle], - &(key->event_hotkey.bus_handle)); - if (ACPI_FAILURE(status)) - goto do_fail_zero; - key->event_hotkey.external_hotkey_num = external_num; - status = acpi_get_handle(NULL, config_entry[action_handle], - &(key->event_hotkey.action_handle)); - if (ACPI_FAILURE(status)) - goto do_fail_zero; - status = acpi_get_handle(key->event_hotkey.action_handle, - config_entry[method], &tmp_handle); - if (ACPI_FAILURE(status)) - goto do_fail_zero; - return AE_OK; -do_fail_zero: - key->event_hotkey.action_method = NULL; -do_fail: - return -ENODEV; -} - -static int -init_poll_hotkey_device(union acpi_hotkey *key, char **config_entry, - int std_num) -{ - acpi_status status = AE_OK; - acpi_handle tmp_handle; - - if (std_num < 0 || IS_EVENT(std_num) || !key) - goto do_fail; - if (!config_entry[bus_handle] ||!config_entry[bus_method] || - !config_entry[action_handle] || !config_entry[method]) - goto do_fail; - - key->link.hotkey_type = ACPI_HOTKEY_POLLING; - key->link.hotkey_standard_num = std_num; - key->poll_hotkey.flag = 0; - key->poll_hotkey.poll_method = config_entry[bus_method]; - key->poll_hotkey.action_method = config_entry[method]; - - status = acpi_get_handle(NULL, config_entry[bus_handle], - &(key->poll_hotkey.poll_handle)); - if (ACPI_FAILURE(status)) - goto do_fail_zero; - status = acpi_get_handle(key->poll_hotkey.poll_handle, - config_entry[bus_method], &tmp_handle); - if (ACPI_FAILURE(status)) - goto do_fail_zero; - status = - acpi_get_handle(NULL, config_entry[action_handle], - &(key->poll_hotkey.action_handle)); - if (ACPI_FAILURE(status)) - goto do_fail_zero; - status = acpi_get_handle(key->poll_hotkey.action_handle, - config_entry[method], &tmp_handle); - if (ACPI_FAILURE(status)) - goto do_fail_zero; - key->poll_hotkey.poll_result = - kmalloc(sizeof(union acpi_object), GFP_KERNEL); - if (!key->poll_hotkey.poll_result) - goto do_fail_zero; - return AE_OK; - -do_fail_zero: - key->poll_hotkey.poll_method = NULL; - key->poll_hotkey.action_method = NULL; -do_fail: - return -ENODEV; -} - -static int hotkey_open_config(struct inode *inode, struct file *file) -{ - return (single_open - (file, hotkey_config_seq_show, PDE(inode)->data)); -} - -static int hotkey_poll_open_config(struct inode *inode, struct file *file) -{ - return (single_open - (file, hotkey_poll_config_seq_show, PDE(inode)->data)); -} - -static int hotkey_config_seq_show(struct seq_file *seq, void *offset) -{ - struct acpi_hotkey_list *hotkey_list = &global_hotkey_list; - struct list_head *entries; - char bus_name[ACPI_PATHNAME_MAX] = { 0 }; - char action_name[ACPI_PATHNAME_MAX] = { 0 }; - struct acpi_buffer bus = { ACPI_PATHNAME_MAX, bus_name }; - struct acpi_buffer act = { ACPI_PATHNAME_MAX, action_name }; - - - list_for_each(entries, hotkey_list->entries) { - union acpi_hotkey *key = - container_of(entries, union acpi_hotkey, entries); - if (key->link.hotkey_type == ACPI_HOTKEY_EVENT) { - acpi_get_name(key->event_hotkey.bus_handle, - ACPI_NAME_TYPE_MAX, &bus); - acpi_get_name(key->event_hotkey.action_handle, - ACPI_NAME_TYPE_MAX, &act); - seq_printf(seq, "%s:%s:%s:%d:%d\n", bus_name, - action_name, - key->event_hotkey.action_method, - key->link.hotkey_standard_num, - key->event_hotkey.external_hotkey_num); - } - } - seq_puts(seq, "\n"); - return 0; -} - -static int hotkey_poll_config_seq_show(struct seq_file *seq, void *offset) -{ - struct acpi_hotkey_list *hotkey_list = &global_hotkey_list; - struct list_head *entries; - char bus_name[ACPI_PATHNAME_MAX] = { 0 }; - char action_name[ACPI_PATHNAME_MAX] = { 0 }; - struct acpi_buffer bus = { ACPI_PATHNAME_MAX, bus_name }; - struct acpi_buffer act = { ACPI_PATHNAME_MAX, action_name }; - - - list_for_each(entries, hotkey_list->entries) { - union acpi_hotkey *key = - container_of(entries, union acpi_hotkey, entries); - if (key->link.hotkey_type == ACPI_HOTKEY_POLLING) { - acpi_get_name(key->poll_hotkey.poll_handle, - ACPI_NAME_TYPE_MAX, &bus); - acpi_get_name(key->poll_hotkey.action_handle, - ACPI_NAME_TYPE_MAX, &act); - seq_printf(seq, "%s:%s:%s:%s:%d\n", bus_name, - key->poll_hotkey.poll_method, - action_name, - key->poll_hotkey.action_method, - key->link.hotkey_standard_num); - } - } - seq_puts(seq, "\n"); - return 0; -} - -static int -get_parms(char *config_record, int *cmd, char **config_entry, - int *internal_event_num, int *external_event_num) -{ -/* the format of *config_record = - * "1:\d+:*" : "cmd:internal_event_num" - * "\d+:\w+:\w+:\w+:\w+:\d+:\d+" : - * "cmd:bus_handle:bus_method:action_handle:method:internal_event_num:external_event_num" - */ - char *tmp, *tmp1, count; - int i; - - sscanf(config_record, "%d", cmd); - if (*cmd == 1) { - if (sscanf(config_record, "%d:%d", cmd, internal_event_num) != - 2) - goto do_fail; - else - return (6); - } - tmp = strchr(config_record, ':'); - if (!tmp) - goto do_fail; - tmp++; - for (i = 0; i < LAST_CONF_ENTRY; i++) { - tmp1 = strchr(tmp, ':'); - if (!tmp1) { - goto do_fail; - } - count = tmp1 - tmp; - config_entry[i] = kzalloc(count + 1, GFP_KERNEL); - if (!config_entry[i]) - goto handle_failure; - strncpy(config_entry[i], tmp, count); - tmp = tmp1 + 1; - } - if (sscanf(tmp, "%d:%d", internal_event_num, external_event_num) <= 0) - goto handle_failure; - if (!IS_OTHERS(*internal_event_num)) { - return 6; - } -handle_failure: - while (i-- > 0) - kfree(config_entry[i]); -do_fail: - return -1; -} - -/* count is length for one input record */ -static ssize_t hotkey_write_config(struct file *file, - const char __user * buffer, - size_t count, loff_t * data) -{ - char *config_record = NULL; - char *config_entry[LAST_CONF_ENTRY]; - int cmd, internal_event_num, external_event_num; - int ret = 0; - union acpi_hotkey *key = kzalloc(sizeof(union acpi_hotkey), GFP_KERNEL); - - if (!key) - return -ENOMEM; - - config_record = kzalloc(count + 1, GFP_KERNEL); - if (!config_record) { - kfree(key); - return -ENOMEM; - } - - if (copy_from_user(config_record, buffer, count)) { - kfree(config_record); - kfree(key); - printk(KERN_ERR PREFIX "Invalid data\n"); - return -EINVAL; - } - ret = get_parms(config_record, &cmd, config_entry, - &internal_event_num, &external_event_num); - kfree(config_record); - if (ret != 6) { - printk(KERN_ERR PREFIX "Invalid data format ret=%d\n", ret); - return -EINVAL; - } - - if (cmd == 1) { - union acpi_hotkey *tmp = NULL; - tmp = get_hotkey_by_event(&global_hotkey_list, - internal_event_num); - if (!tmp) - printk(KERN_ERR PREFIX "Invalid key\n"); - else - memcpy(key, tmp, sizeof(union acpi_hotkey)); - goto cont_cmd; - } - if (IS_EVENT(internal_event_num)) { - if (init_hotkey_device(key, config_entry, - internal_event_num, external_event_num)) - goto init_hotkey_fail; - } else { - if (init_poll_hotkey_device(key, config_entry, - internal_event_num)) - goto init_poll_hotkey_fail; - } -cont_cmd: - switch (cmd) { - case 0: - if (get_hotkey_by_event(&global_hotkey_list, - key->link.hotkey_standard_num)) - goto fail_out; - else - hotkey_add(key); - break; - case 1: - hotkey_remove(key); - break; - case 2: - /* key is kfree()ed if matched*/ - if (hotkey_update(key)) - goto fail_out; - break; - default: - goto fail_out; - break; - } - return count; - -init_poll_hotkey_fail: /* failed init_poll_hotkey_device */ - kfree(config_entry[bus_method]); - config_entry[bus_method] = NULL; -init_hotkey_fail: /* failed init_hotkey_device */ - kfree(config_entry[method]); -fail_out: - kfree(config_entry[bus_handle]); - kfree(config_entry[action_handle]); - /* No double free since elements =NULL for error cases */ - if (IS_EVENT(internal_event_num)) { - if (config_entry[bus_method]) - kfree(config_entry[bus_method]); - free_hotkey_buffer(key); /* frees [method] */ - } else - free_poll_hotkey_buffer(key); /* frees [bus_method]+[method] */ - kfree(key); - printk(KERN_ERR PREFIX "invalid key\n"); - return -EINVAL; -} - -/* - * This function evaluates an ACPI method, given an int as parameter, the - * method is searched within the scope of the handle, can be NULL. The output - * of the method is written is output, which can also be NULL - * - * returns 1 if write is successful, 0 else. - */ -static int write_acpi_int(acpi_handle handle, const char *method, int val, - struct acpi_buffer *output) -{ - struct acpi_object_list params; /* list of input parameters (an int here) */ - union acpi_object in_obj; /* the only param we use */ - acpi_status status; - - params.count = 1; - params.pointer = &in_obj; - in_obj.type = ACPI_TYPE_INTEGER; - in_obj.integer.value = val; - - status = acpi_evaluate_object(handle, (char *)method, ¶ms, output); - - return (status == AE_OK); -} - -static int read_acpi_int(acpi_handle handle, const char *method, - union acpi_object *val) -{ - struct acpi_buffer output; - union acpi_object out_obj; - acpi_status status; - - output.length = sizeof(out_obj); - output.pointer = &out_obj; - - status = acpi_evaluate_object(handle, (char *)method, NULL, &output); - if (val) { - val->integer.value = out_obj.integer.value; - val->type = out_obj.type; - } else - printk(KERN_ERR PREFIX "null val pointer\n"); - return ((status == AE_OK) - && (out_obj.type == ACPI_TYPE_INTEGER)); -} - -static union acpi_hotkey *get_hotkey_by_event(struct - acpi_hotkey_list - *hotkey_list, int event) -{ - struct list_head *entries; - - list_for_each(entries, hotkey_list->entries) { - union acpi_hotkey *key = - container_of(entries, union acpi_hotkey, entries); - if (key->link.hotkey_standard_num == event) { - return (key); - } - } - return (NULL); -} - -/* - * user call AML method interface: - * Call convention: - * echo "event_num: arg type : value" - * example: echo "1:1:30" > /proc/acpi/action - * Just support 1 integer arg passing to AML method - */ - -static ssize_t hotkey_execute_aml_method(struct file *file, - const char __user * buffer, - size_t count, loff_t * data) -{ - struct acpi_hotkey_list *hotkey_list = &global_hotkey_list; - char *arg; - int event, method_type, type, value; - union acpi_hotkey *key; - - - arg = kzalloc(count + 1, GFP_KERNEL); - if (!arg) - return -ENOMEM; - - if (copy_from_user(arg, buffer, count)) { - kfree(arg); - printk(KERN_ERR PREFIX "Invalid argument 2\n"); - return -EINVAL; - } - - if (sscanf(arg, "%d:%d:%d:%d", &event, &method_type, &type, &value) != - 4) { - kfree(arg); - printk(KERN_ERR PREFIX "Invalid argument 3\n"); - return -EINVAL; - } - kfree(arg); - if (type == ACPI_TYPE_INTEGER) { - key = get_hotkey_by_event(hotkey_list, event); - if (!key) - goto do_fail; - if (IS_EVENT(event)) - write_acpi_int(key->event_hotkey.action_handle, - key->event_hotkey.action_method, value, - NULL); - else if (IS_POLL(event)) { - if (method_type == POLL_METHOD) - read_acpi_int(key->poll_hotkey.poll_handle, - key->poll_hotkey.poll_method, - key->poll_hotkey.poll_result); - else if (method_type == ACTION_METHOD) - write_acpi_int(key->poll_hotkey.action_handle, - key->poll_hotkey.action_method, - value, NULL); - else - goto do_fail; - - } - } else { - printk(KERN_WARNING "Not supported\n"); - return -EINVAL; - } - return count; - do_fail: - return -EINVAL; - -} - -static int __init hotkey_init(void) -{ - int result; - mode_t mode = S_IFREG | S_IRUGO | S_IWUGO; - - - if (acpi_disabled) - return -ENODEV; - - if (acpi_specific_hotkey_enabled) { - printk("Using specific hotkey driver\n"); - return -ENODEV; - } - - hotkey_proc_dir = proc_mkdir(HOTKEY_PROC, acpi_root_dir); - if (!hotkey_proc_dir) { - return (-ENODEV); - } - hotkey_proc_dir->owner = THIS_MODULE; - - hotkey_config = - create_proc_entry(HOTKEY_EV_CONFIG, mode, hotkey_proc_dir); - if (!hotkey_config) { - goto do_fail1; - } else { - hotkey_config->proc_fops = &hotkey_config_fops; - hotkey_config->data = &global_hotkey_list; - hotkey_config->owner = THIS_MODULE; - hotkey_config->uid = 0; - hotkey_config->gid = 0; - } - - hotkey_poll_config = - create_proc_entry(HOTKEY_PL_CONFIG, mode, hotkey_proc_dir); - if (!hotkey_poll_config) { - goto do_fail2; - } else { - hotkey_poll_config->proc_fops = &hotkey_poll_config_fops; - hotkey_poll_config->data = &global_hotkey_list; - hotkey_poll_config->owner = THIS_MODULE; - hotkey_poll_config->uid = 0; - hotkey_poll_config->gid = 0; - } - - hotkey_action = create_proc_entry(HOTKEY_ACTION, mode, hotkey_proc_dir); - if (!hotkey_action) { - goto do_fail3; - } else { - hotkey_action->proc_fops = &hotkey_action_fops; - hotkey_action->owner = THIS_MODULE; - hotkey_action->uid = 0; - hotkey_action->gid = 0; - } - - hotkey_info = create_proc_entry(HOTKEY_INFO, mode, hotkey_proc_dir); - if (!hotkey_info) { - goto do_fail4; - } else { - hotkey_info->proc_fops = &hotkey_info_fops; - hotkey_info->owner = THIS_MODULE; - hotkey_info->uid = 0; - hotkey_info->gid = 0; - } - - result = acpi_bus_register_driver(&hotkey_driver); - if (result < 0) - goto do_fail5; - global_hotkey_list.count = 0; - global_hotkey_list.entries = &hotkey_entries; - - INIT_LIST_HEAD(&hotkey_entries); - - return (0); - - do_fail5: - remove_proc_entry(HOTKEY_INFO, hotkey_proc_dir); - do_fail4: - remove_proc_entry(HOTKEY_ACTION, hotkey_proc_dir); - do_fail3: - remove_proc_entry(HOTKEY_PL_CONFIG, hotkey_proc_dir); - do_fail2: - remove_proc_entry(HOTKEY_EV_CONFIG, hotkey_proc_dir); - do_fail1: - remove_proc_entry(HOTKEY_PROC, acpi_root_dir); - return (-ENODEV); -} - -static void __exit hotkey_exit(void) -{ - struct list_head *entries, *next; - - - list_for_each_safe(entries, next, global_hotkey_list.entries) { - union acpi_hotkey *key = - container_of(entries, union acpi_hotkey, entries); - - acpi_os_wait_events_complete(NULL); - list_del(&key->link.entries); - global_hotkey_list.count--; - free_hotkey_device(key); - } - acpi_bus_unregister_driver(&hotkey_driver); - remove_proc_entry(HOTKEY_EV_CONFIG, hotkey_proc_dir); - remove_proc_entry(HOTKEY_PL_CONFIG, hotkey_proc_dir); - remove_proc_entry(HOTKEY_ACTION, hotkey_proc_dir); - remove_proc_entry(HOTKEY_INFO, hotkey_proc_dir); - remove_proc_entry(HOTKEY_PROC, acpi_root_dir); - return; -} - -module_init(hotkey_init); -module_exit(hotkey_exit); diff --git a/drivers/acpi/i2c_ec.c b/drivers/acpi/i2c_ec.c index 76ec8b63e69f..acab4a481897 100644 --- a/drivers/acpi/i2c_ec.c +++ b/drivers/acpi/i2c_ec.c @@ -27,18 +27,17 @@ #define ACPI_EC_HC_COMPONENT 0x00080000 #define ACPI_EC_HC_CLASS "ec_hc_smbus" #define ACPI_EC_HC_HID "ACPI0001" -#define ACPI_EC_HC_DRIVER_NAME "ACPI EC HC smbus driver" #define ACPI_EC_HC_DEVICE_NAME "EC HC smbus" #define _COMPONENT ACPI_EC_HC_COMPONENT -ACPI_MODULE_NAME("acpi_smbus") +ACPI_MODULE_NAME("i2c_ec"); static int acpi_ec_hc_add(struct acpi_device *device); static int acpi_ec_hc_remove(struct acpi_device *device, int type); static struct acpi_driver acpi_ec_hc_driver = { - .name = ACPI_EC_HC_DRIVER_NAME, + .name = "i2c_ec", .class = ACPI_EC_HC_CLASS, .ids = ACPI_EC_HC_HID, .ops = { diff --git a/drivers/acpi/ibm_acpi.c b/drivers/acpi/ibm_acpi.c index c6144ca66638..1a0ed3dc409c 100644 --- a/drivers/acpi/ibm_acpi.c +++ b/drivers/acpi/ibm_acpi.c @@ -496,6 +496,10 @@ 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); + if (ibm_thinkpad_ec_found) + printk(IBM_INFO "ThinkPad EC firmware %s\n", + ibm_thinkpad_ec_found); + return 0; } @@ -2617,7 +2621,7 @@ static void __init ibm_handle_init(char *name, ibm_handle_init(#object, &object##_handle, *object##_parent, \ object##_paths, ARRAY_SIZE(object##_paths), &object##_path) -static int set_ibm_param(const char *val, struct kernel_param *kp) +static int __init set_ibm_param(const char *val, struct kernel_param *kp) { unsigned int i; @@ -2659,7 +2663,8 @@ static void acpi_ibm_exit(void) for (i = ARRAY_SIZE(ibms) - 1; i >= 0; i--) ibm_exit(&ibms[i]); - remove_proc_entry(IBM_DIR, acpi_root_dir); + if (proc_dir) + remove_proc_entry(IBM_DIR, acpi_root_dir); if (ibm_thinkpad_ec_found) kfree(ibm_thinkpad_ec_found); @@ -2696,11 +2701,6 @@ static int __init acpi_ibm_init(void) if (acpi_disabled) return -ENODEV; - if (!acpi_specific_hotkey_enabled) { - printk(IBM_ERR "using generic hotkey driver\n"); - return -ENODEV; - } - /* ec is required because many other handles are relative to it */ IBM_HANDLE_INIT(ec); if (!ec_handle) { @@ -2710,9 +2710,6 @@ static int __init acpi_ibm_init(void) /* 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); @@ -2742,6 +2739,7 @@ static int __init acpi_ibm_init(void) proc_dir = proc_mkdir(IBM_DIR, acpi_root_dir); if (!proc_dir) { printk(IBM_ERR "unable to create proc dir %s", IBM_DIR); + acpi_ibm_exit(); return -ENODEV; } proc_dir->owner = THIS_MODULE; diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c index 4a9faff4c01d..8fcd6a15517f 100644 --- a/drivers/acpi/numa.c +++ b/drivers/acpi/numa.c @@ -33,7 +33,7 @@ #define ACPI_NUMA 0x80000000 #define _COMPONENT ACPI_NUMA -ACPI_MODULE_NAME("numa") +ACPI_MODULE_NAME("numa"); static nodemask_t nodes_found_map = NODE_MASK_NONE; #define PXM_INVAL -1 @@ -45,12 +45,6 @@ int __cpuinitdata pxm_to_node_map[MAX_PXM_DOMAINS] int __cpuinitdata node_to_pxm_map[MAX_NUMNODES] = { [0 ... MAX_NUMNODES - 1] = PXM_INVAL }; -extern int __init acpi_table_parse_madt_family(char *id, - unsigned long madt_size, - int entry_id, - acpi_madt_entry_handler handler, - unsigned int max_entries); - int __cpuinit pxm_to_node(int pxm) { if (pxm < 0) @@ -208,9 +202,9 @@ static int __init acpi_parse_srat(struct acpi_table_header *table) int __init acpi_table_parse_srat(enum acpi_srat_type id, - acpi_madt_entry_handler handler, unsigned int max_entries) + acpi_table_entry_handler handler, unsigned int max_entries) { - return acpi_table_parse_madt_family(ACPI_SIG_SRAT, + return acpi_table_parse_entries(ACPI_SIG_SRAT, sizeof(struct acpi_table_srat), id, handler, max_entries); } @@ -220,9 +214,7 @@ int __init acpi_numa_init(void) int result; /* SRAT: Static Resource Affinity Table */ - result = acpi_table_parse(ACPI_SIG_SRAT, acpi_parse_srat); - - if (result > 0) { + if (!acpi_table_parse(ACPI_SIG_SRAT, acpi_parse_srat)) { result = acpi_table_parse_srat(ACPI_SRAT_TYPE_CPU_AFFINITY, acpi_parse_processor_affinity, NR_CPUS); @@ -230,7 +222,7 @@ int __init acpi_numa_init(void) } /* SLIT: System Locality Information Table */ - result = acpi_table_parse(ACPI_SIG_SLIT, acpi_parse_slit); + acpi_table_parse(ACPI_SIG_SLIT, acpi_parse_slit); acpi_numa_arch_fixup(); return 0; diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 0f6f3bcbc8eb..971eca4864fa 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -46,7 +46,7 @@ #include <linux/efi.h> #define _COMPONENT ACPI_OS_SERVICES -ACPI_MODULE_NAME("osl") +ACPI_MODULE_NAME("osl"); #define PREFIX "ACPI: " struct acpi_os_dpc { acpi_osd_exec_callback function; @@ -68,9 +68,6 @@ EXPORT_SYMBOL(acpi_in_debugger); extern char line_buf[80]; #endif /*ENABLE_DEBUGGER */ -int acpi_specific_hotkey_enabled = TRUE; -EXPORT_SYMBOL(acpi_specific_hotkey_enabled); - static unsigned int acpi_irq_irq; static acpi_osd_handler acpi_irq_handler; static void *acpi_irq_context; @@ -205,7 +202,7 @@ void __iomem *acpi_os_map_memory(acpi_physical_address phys, acpi_size size) { if (phys > ULONG_MAX) { printk(KERN_ERR PREFIX "Cannot map memory that high\n"); - return 0; + return NULL; } if (acpi_gbl_permanent_mmap) /* @@ -890,26 +887,6 @@ u32 acpi_os_get_line(char *buffer) } #endif /* ACPI_FUTURE_USAGE */ -/* Assumes no unreadable holes inbetween */ -u8 acpi_os_readable(void *ptr, acpi_size len) -{ -#if defined(__i386__) || defined(__x86_64__) - char tmp; - return !__get_user(tmp, (char __user *)ptr) - && !__get_user(tmp, (char __user *)ptr + len - 1); -#endif - return 1; -} - -#ifdef ACPI_FUTURE_USAGE -u8 acpi_os_writable(void *ptr, acpi_size len) -{ - /* could do dummy write (racy) or a kernel page table lookup. - The later may be difficult at early boot when kmap doesn't work yet. */ - return 1; -} -#endif - acpi_status acpi_os_signal(u32 function, void *info) { switch (function) { @@ -1012,14 +989,6 @@ static int __init acpi_wake_gpes_always_on_setup(char *str) __setup("acpi_wake_gpes_always_on", acpi_wake_gpes_always_on_setup); -static int __init acpi_hotkey_setup(char *str) -{ - acpi_specific_hotkey_enabled = FALSE; - return 1; -} - -__setup("acpi_generic_hotkey", acpi_hotkey_setup); - /* * max_cstate is defined in the base kernel so modules can * change it w/o depending on the state of the processor module. diff --git a/drivers/acpi/pci_bind.c b/drivers/acpi/pci_bind.c index 55f57a61c55e..028969370bbf 100644 --- a/drivers/acpi/pci_bind.c +++ b/drivers/acpi/pci_bind.c @@ -36,7 +36,7 @@ #include <acpi/acpi_drivers.h> #define _COMPONENT ACPI_PCI_COMPONENT -ACPI_MODULE_NAME("pci_bind") +ACPI_MODULE_NAME("pci_bind"); struct acpi_pci_data { struct acpi_pci_id id; diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c index fe7d007833ad..dd3186abe07a 100644 --- a/drivers/acpi/pci_irq.c +++ b/drivers/acpi/pci_irq.c @@ -38,7 +38,7 @@ #include <acpi/acpi_drivers.h> #define _COMPONENT ACPI_PCI_COMPONENT -ACPI_MODULE_NAME("pci_irq") +ACPI_MODULE_NAME("pci_irq"); static struct acpi_prt_list acpi_prt; static DEFINE_SPINLOCK(acpi_prt_lock); diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c index 0f683c8c6fbc..acc594771379 100644 --- a/drivers/acpi/pci_link.c +++ b/drivers/acpi/pci_link.c @@ -44,10 +44,9 @@ #include <acpi/acpi_drivers.h> #define _COMPONENT ACPI_PCI_COMPONENT -ACPI_MODULE_NAME("pci_link") +ACPI_MODULE_NAME("pci_link"); #define ACPI_PCI_LINK_CLASS "pci_irq_routing" #define ACPI_PCI_LINK_HID "PNP0C0F" -#define ACPI_PCI_LINK_DRIVER_NAME "ACPI PCI Interrupt Link Driver" #define ACPI_PCI_LINK_DEVICE_NAME "PCI Interrupt Link" #define ACPI_PCI_LINK_FILE_INFO "info" #define ACPI_PCI_LINK_FILE_STATUS "state" @@ -56,7 +55,7 @@ static int acpi_pci_link_add(struct acpi_device *device); static int acpi_pci_link_remove(struct acpi_device *device, int type); static struct acpi_driver acpi_pci_link_driver = { - .name = ACPI_PCI_LINK_DRIVER_NAME, + .name = "pci_link", .class = ACPI_PCI_LINK_CLASS, .ids = ACPI_PCI_LINK_HID, .ops = { diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 4ecf701687e8..ad4145a37786 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -36,17 +36,16 @@ #include <acpi/acpi_drivers.h> #define _COMPONENT ACPI_PCI_COMPONENT -ACPI_MODULE_NAME("pci_root") +ACPI_MODULE_NAME("pci_root"); #define ACPI_PCI_ROOT_CLASS "pci_bridge" #define ACPI_PCI_ROOT_HID "PNP0A03" -#define ACPI_PCI_ROOT_DRIVER_NAME "ACPI PCI Root Bridge Driver" #define ACPI_PCI_ROOT_DEVICE_NAME "PCI Root Bridge" static int acpi_pci_root_add(struct acpi_device *device); static int acpi_pci_root_remove(struct acpi_device *device, int type); static int acpi_pci_root_start(struct acpi_device *device); static struct acpi_driver acpi_pci_root_driver = { - .name = ACPI_PCI_ROOT_DRIVER_NAME, + .name = "pci_root", .class = ACPI_PCI_ROOT_CLASS, .ids = ACPI_PCI_ROOT_HID, .ops = { diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index 0ba7dfbbb2ee..1ef338545dfe 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -45,10 +45,9 @@ #include <acpi/acpi_drivers.h> #define _COMPONENT ACPI_POWER_COMPONENT -ACPI_MODULE_NAME("acpi_power") +ACPI_MODULE_NAME("power"); #define ACPI_POWER_COMPONENT 0x00800000 #define ACPI_POWER_CLASS "power_resource" -#define ACPI_POWER_DRIVER_NAME "ACPI Power Resource Driver" #define ACPI_POWER_DEVICE_NAME "Power Resource" #define ACPI_POWER_FILE_INFO "info" #define ACPI_POWER_FILE_STATUS "state" @@ -57,25 +56,33 @@ ACPI_MODULE_NAME("acpi_power") #define ACPI_POWER_RESOURCE_STATE_UNKNOWN 0xFF static int acpi_power_add(struct acpi_device *device); static int acpi_power_remove(struct acpi_device *device, int type); +static int acpi_power_resume(struct acpi_device *device); static int acpi_power_open_fs(struct inode *inode, struct file *file); static struct acpi_driver acpi_power_driver = { - .name = ACPI_POWER_DRIVER_NAME, + .name = "power", .class = ACPI_POWER_CLASS, .ids = ACPI_POWER_HID, .ops = { .add = acpi_power_add, .remove = acpi_power_remove, + .resume = acpi_power_resume, }, }; +struct acpi_power_reference { + struct list_head node; + struct acpi_device *device; +}; + struct acpi_power_resource { struct acpi_device * device; acpi_bus_id name; u32 system_level; u32 order; int state; - int references; + struct mutex resource_lock; + struct list_head reference; }; static struct list_head acpi_power_resource_list; @@ -171,22 +178,47 @@ static int acpi_power_get_list_state(struct acpi_handle_list *list, int *state) return result; } -static int acpi_power_on(acpi_handle handle) +static int acpi_power_on(acpi_handle handle, struct acpi_device *dev) { int result = 0; + int found = 0; acpi_status status = AE_OK; - struct acpi_device *device = NULL; struct acpi_power_resource *resource = NULL; + struct list_head *node, *next; + struct acpi_power_reference *ref; result = acpi_power_get_context(handle, &resource); if (result) return result; - resource->references++; + mutex_lock(&resource->resource_lock); + list_for_each_safe(node, next, &resource->reference) { + ref = container_of(node, struct acpi_power_reference, node); + if (dev->handle == ref->device->handle) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] already referenced by resource [%s]\n", + dev->pnp.bus_id, resource->name)); + found = 1; + break; + } + } + + if (!found) { + ref = kmalloc(sizeof (struct acpi_power_reference), + irqs_disabled() ? GFP_ATOMIC : GFP_KERNEL); + if (!ref) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "kmalloc() failed\n")); + mutex_unlock(&resource->resource_lock); + return -ENOMEM; + } + list_add_tail(&ref->node, &resource->reference); + ref->device = dev; + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] added to resource [%s] references\n", + dev->pnp.bus_id, resource->name)); + } + mutex_unlock(&resource->resource_lock); - if ((resource->references > 1) - || (resource->state == ACPI_POWER_RESOURCE_STATE_ON)) { + if (resource->state == ACPI_POWER_RESOURCE_STATE_ON) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] already on\n", resource->name)); return 0; @@ -203,38 +235,49 @@ static int acpi_power_on(acpi_handle handle) return -ENOEXEC; /* Update the power resource's _device_ power state */ - device = resource->device; resource->device->power.state = ACPI_STATE_D0; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] turned on\n", resource->name)); - return 0; } -static int acpi_power_off_device(acpi_handle handle) +static int acpi_power_off_device(acpi_handle handle, struct acpi_device *dev) { int result = 0; acpi_status status = AE_OK; struct acpi_power_resource *resource = NULL; + struct list_head *node, *next; + struct acpi_power_reference *ref; + result = acpi_power_get_context(handle, &resource); if (result) return result; - if (resource->references) - resource->references--; + mutex_lock(&resource->resource_lock); + list_for_each_safe(node, next, &resource->reference) { + ref = container_of(node, struct acpi_power_reference, node); + if (dev->handle == ref->device->handle) { + list_del(&ref->node); + kfree(ref); + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] removed from resource [%s] references\n", + dev->pnp.bus_id, resource->name)); + break; + } + } - if (resource->references) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Resource [%s] is still in use, dereferencing\n", - resource->device->pnp.bus_id)); + if (!list_empty(&resource->reference)) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Cannot turn resource [%s] off - resource is in use\n", + resource->name)); + mutex_unlock(&resource->resource_lock); return 0; } + mutex_unlock(&resource->resource_lock); if (resource->state == ACPI_POWER_RESOURCE_STATE_OFF) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] already off\n", - resource->device->pnp.bus_id)); + resource->name)); return 0; } @@ -276,7 +319,7 @@ int acpi_enable_wakeup_device_power(struct acpi_device *dev) arg.integer.value = 1; /* Open power resource */ for (i = 0; i < dev->wakeup.resources.count; i++) { - ret = acpi_power_on(dev->wakeup.resources.handles[i]); + ret = acpi_power_on(dev->wakeup.resources.handles[i], dev); if (ret) { printk(KERN_ERR PREFIX "Transition power state\n"); dev->wakeup.flags.valid = 0; @@ -323,7 +366,7 @@ int acpi_disable_wakeup_device_power(struct acpi_device *dev) /* Close power resource */ for (i = 0; i < dev->wakeup.resources.count; i++) { - ret = acpi_power_off_device(dev->wakeup.resources.handles[i]); + ret = acpi_power_off_device(dev->wakeup.resources.handles[i], dev); if (ret) { printk(KERN_ERR PREFIX "Transition power state\n"); dev->wakeup.flags.valid = 0; @@ -407,16 +450,20 @@ int acpi_power_transition(struct acpi_device *device, int state) * (e.g. so the device doesn't lose power while transitioning). */ for (i = 0; i < tl->count; i++) { - result = acpi_power_on(tl->handles[i]); + result = acpi_power_on(tl->handles[i], device); if (result) goto end; } + if (device->power.state == state) { + goto end; + } + /* * Then we dereference all power resources used in the current list. */ for (i = 0; i < cl->count; i++) { - result = acpi_power_off_device(cl->handles[i]); + result = acpi_power_off_device(cl->handles[i], device); if (result) goto end; } @@ -439,7 +486,11 @@ static struct proc_dir_entry *acpi_power_dir; static int acpi_power_seq_show(struct seq_file *seq, void *offset) { + int count = 0; + int result = 0; struct acpi_power_resource *resource = NULL; + struct list_head *node, *next; + struct acpi_power_reference *ref; resource = seq->private; @@ -447,6 +498,10 @@ static int acpi_power_seq_show(struct seq_file *seq, void *offset) if (!resource) goto end; + result = acpi_power_get_state(resource); + if (result) + goto end; + seq_puts(seq, "state: "); switch (resource->state) { case ACPI_POWER_RESOURCE_STATE_ON: @@ -460,11 +515,18 @@ static int acpi_power_seq_show(struct seq_file *seq, void *offset) break; } + mutex_lock(&resource->resource_lock); + list_for_each_safe(node, next, &resource->reference) { + ref = container_of(node, struct acpi_power_reference, node); + count++; + } + mutex_unlock(&resource->resource_lock); + seq_printf(seq, "system level: S%d\n" "order: %d\n" "reference count: %d\n", resource->system_level, - resource->order, resource->references); + resource->order, count); end: return 0; @@ -537,6 +599,8 @@ static int acpi_power_add(struct acpi_device *device) return -ENOMEM; resource->device = device; + mutex_init(&resource->resource_lock); + INIT_LIST_HEAD(&resource->reference); strcpy(resource->name, device->pnp.bus_id); strcpy(acpi_device_name(device), ACPI_POWER_DEVICE_NAME); strcpy(acpi_device_class(device), ACPI_POWER_CLASS); @@ -584,6 +648,7 @@ static int acpi_power_add(struct acpi_device *device) static int acpi_power_remove(struct acpi_device *device, int type) { struct acpi_power_resource *resource = NULL; + struct list_head *node, *next; if (!device || !acpi_driver_data(device)) @@ -593,11 +658,54 @@ static int acpi_power_remove(struct acpi_device *device, int type) acpi_power_remove_fs(device); + mutex_lock(&resource->resource_lock); + list_for_each_safe(node, next, &resource->reference) { + struct acpi_power_reference *ref = container_of(node, struct acpi_power_reference, node); + list_del(&ref->node); + kfree(ref); + } + mutex_unlock(&resource->resource_lock); + kfree(resource); return 0; } +static int acpi_power_resume(struct acpi_device *device) +{ + int result = 0; + struct acpi_power_resource *resource = NULL; + struct acpi_power_reference *ref; + + if (!device || !acpi_driver_data(device)) + return -EINVAL; + + resource = (struct acpi_power_resource *)acpi_driver_data(device); + + result = acpi_power_get_state(resource); + if (result) + return result; + + mutex_lock(&resource->resource_lock); + if ((resource->state == ACPI_POWER_RESOURCE_STATE_ON) && + list_empty(&resource->reference)) { + mutex_unlock(&resource->resource_lock); + result = acpi_power_off_device(device->handle, NULL); + return result; + } + + if ((resource->state == ACPI_POWER_RESOURCE_STATE_OFF) && + !list_empty(&resource->reference)) { + ref = container_of(resource->reference.next, struct acpi_power_reference, node); + mutex_unlock(&resource->resource_lock); + result = acpi_power_on(device->handle, ref->device); + return result; + } + + mutex_unlock(&resource->resource_lock); + return 0; +} + static int __init acpi_power_init(void) { int result = 0; diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index 0079bc51082c..99d1516d1e70 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -60,7 +60,6 @@ #define ACPI_PROCESSOR_COMPONENT 0x01000000 #define ACPI_PROCESSOR_CLASS "processor" -#define ACPI_PROCESSOR_DRIVER_NAME "ACPI Processor Driver" #define ACPI_PROCESSOR_DEVICE_NAME "Processor" #define ACPI_PROCESSOR_FILE_INFO "info" #define ACPI_PROCESSOR_FILE_THROTTLING "throttling" @@ -74,10 +73,10 @@ #define ACPI_STA_PRESENT 0x00000001 #define _COMPONENT ACPI_PROCESSOR_COMPONENT -ACPI_MODULE_NAME("acpi_processor") +ACPI_MODULE_NAME("processor_core"); - MODULE_AUTHOR("Paul Diefenbaugh"); -MODULE_DESCRIPTION(ACPI_PROCESSOR_DRIVER_NAME); +MODULE_AUTHOR("Paul Diefenbaugh"); +MODULE_DESCRIPTION("ACPI Processor Driver"); MODULE_LICENSE("GPL"); static int acpi_processor_add(struct acpi_device *device); @@ -89,7 +88,7 @@ static acpi_status acpi_processor_hotadd_init(acpi_handle handle, int *p_cpu); static int acpi_processor_handle_eject(struct acpi_processor *pr); static struct acpi_driver acpi_processor_driver = { - .name = ACPI_PROCESSOR_DRIVER_NAME, + .name = "processor", .class = ACPI_PROCESSOR_CLASS, .ids = ACPI_PROCESSOR_HID, .ops = { @@ -404,7 +403,7 @@ static int map_lsapic_id(struct acpi_subtable_header *entry, if (lsapic->lapic_flags & ACPI_MADT_ENABLED) { /* First check against id */ if (lsapic->processor_id == acpi_id) { - *apic_id = lsapic->id; + *apic_id = (lsapic->id << 8) | lsapic->eid; return 1; /* Check against optional uid */ } else if (entry->length >= 16 && @@ -1005,7 +1004,7 @@ static int __init acpi_processor_init(void) #ifdef CONFIG_SMP if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_MADT, 0, (struct acpi_table_header **)&madt))) - madt = 0; + madt = NULL; #endif acpi_processor_dir = proc_mkdir(ACPI_PROCESSOR_CLASS, acpi_root_dir); diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 8206fc1ecc58..60773005b8af 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -51,6 +51,14 @@ #include <asm/apic.h> #endif +/* + * Include the apic definitions for x86 to have the APIC timer related defines + * available also for UP (on SMP it gets magically included via linux/smp.h). + */ +#ifdef CONFIG_X86 +#include <asm/apic.h> +#endif + #include <asm/io.h> #include <asm/uaccess.h> @@ -59,9 +67,8 @@ #define ACPI_PROCESSOR_COMPONENT 0x01000000 #define ACPI_PROCESSOR_CLASS "processor" -#define ACPI_PROCESSOR_DRIVER_NAME "ACPI Processor Driver" #define _COMPONENT ACPI_PROCESSOR_COMPONENT -ACPI_MODULE_NAME("acpi_processor") +ACPI_MODULE_NAME("processor_idle"); #define ACPI_PROCESSOR_FILE_POWER "power" #define US_TO_PM_TIMER_TICKS(t) ((t * (PM_TIMER_FREQUENCY/1000)) / 1000) #define C2_OVERHEAD 4 /* 1us (3.579 ticks per us) */ diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c index 058f13cf3b79..2f2e7964226d 100644 --- a/drivers/acpi/processor_perflib.c +++ b/drivers/acpi/processor_perflib.c @@ -44,10 +44,9 @@ #define ACPI_PROCESSOR_COMPONENT 0x01000000 #define ACPI_PROCESSOR_CLASS "processor" -#define ACPI_PROCESSOR_DRIVER_NAME "ACPI Processor Driver" #define ACPI_PROCESSOR_FILE_PERFORMANCE "performance" #define _COMPONENT ACPI_PROCESSOR_COMPONENT -ACPI_MODULE_NAME("acpi_processor") +ACPI_MODULE_NAME("processor_perflib"); static DEFINE_MUTEX(performance_mutex); diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c index 40fecd67ad83..06e6f3fb8825 100644 --- a/drivers/acpi/processor_thermal.c +++ b/drivers/acpi/processor_thermal.c @@ -41,9 +41,8 @@ #define ACPI_PROCESSOR_COMPONENT 0x01000000 #define ACPI_PROCESSOR_CLASS "processor" -#define ACPI_PROCESSOR_DRIVER_NAME "ACPI Processor Driver" #define _COMPONENT ACPI_PROCESSOR_COMPONENT -ACPI_MODULE_NAME("acpi_processor") +ACPI_MODULE_NAME("processor_thermal"); /* -------------------------------------------------------------------------- Limit Interface diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c index 89dff3639abe..b33486009f41 100644 --- a/drivers/acpi/processor_throttling.c +++ b/drivers/acpi/processor_throttling.c @@ -41,9 +41,8 @@ #define ACPI_PROCESSOR_COMPONENT 0x01000000 #define ACPI_PROCESSOR_CLASS "processor" -#define ACPI_PROCESSOR_DRIVER_NAME "ACPI Processor Driver" #define _COMPONENT ACPI_PROCESSOR_COMPONENT -ACPI_MODULE_NAME("acpi_processor") +ACPI_MODULE_NAME("processor_throttling"); /* -------------------------------------------------------------------------- Throttling Control diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c index f58fc7447ab4..59640d9a0acc 100644 --- a/drivers/acpi/sbs.c +++ b/drivers/acpi/sbs.c @@ -59,7 +59,6 @@ extern void acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir); #define ACPI_AC_CLASS "ac_adapter" #define ACPI_BATTERY_CLASS "battery" #define ACPI_SBS_HID "ACPI0002" -#define ACPI_SBS_DRIVER_NAME "ACPI Smart Battery System Driver" #define ACPI_SBS_DEVICE_NAME "Smart Battery System" #define ACPI_SBS_FILE_INFO "info" #define ACPI_SBS_FILE_STATE "state" @@ -78,7 +77,7 @@ extern void acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir); #define MAX_SBS_BAT 4 #define MAX_SMBUS_ERR 1 -ACPI_MODULE_NAME("acpi_sbs"); +ACPI_MODULE_NAME("sbs"); MODULE_AUTHOR("Rich Townsend"); MODULE_DESCRIPTION("Smart Battery System ACPI interface driver"); @@ -110,7 +109,7 @@ static void acpi_battery_smbus_err_handler(struct acpi_ec_smbus *smbus); static void acpi_sbs_update_queue(void *data); static struct acpi_driver acpi_sbs_driver = { - .name = ACPI_SBS_DRIVER_NAME, + .name = "sbs", .class = ACPI_SBS_CLASS, .ids = ACPI_SBS_HID, .ops = { @@ -1034,21 +1033,19 @@ static int acpi_battery_read_state(struct seq_file *seq, void *offset) } else { seq_printf(seq, "capacity state: ok\n"); } + + foo = (s16) battery->state.amperage * battery->info.ipscale; + if (battery->info.capacity_mode) { + foo = foo * battery->info.design_voltage / 1000; + } if (battery->state.amperage < 0) { seq_printf(seq, "charging state: discharging\n"); - foo = battery->state.remaining_capacity * cscale * 60 / - (battery->state.average_time_to_empty == 0 ? 1 : - battery->state.average_time_to_empty); - seq_printf(seq, "present rate: %i%s\n", - foo, battery->info.capacity_mode ? "0 mW" : " mA"); + seq_printf(seq, "present rate: %d %s\n", + -foo, battery->info.capacity_mode ? "mW" : "mA"); } else if (battery->state.amperage > 0) { seq_printf(seq, "charging state: charging\n"); - foo = (battery->info.full_charge_capacity - - battery->state.remaining_capacity) * cscale * 60 / - (battery->state.average_time_to_full == 0 ? 1 : - battery->state.average_time_to_full); - seq_printf(seq, "present rate: %i%s\n", - foo, battery->info.capacity_mode ? "0 mW" : " mA"); + seq_printf(seq, "present rate: %d %s\n", + foo, battery->info.capacity_mode ? "mW" : "mA"); } else { seq_printf(seq, "charging state: charged\n"); seq_printf(seq, "present rate: 0 %s\n", diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 64f26db10c8e..bb0e0da39fb1 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -11,13 +11,12 @@ #include <acpi/acinterp.h> /* for acpi_ex_eisa_id_to_string() */ #define _COMPONENT ACPI_BUS_COMPONENT -ACPI_MODULE_NAME("scan") +ACPI_MODULE_NAME("scan"); #define STRUCT_TO_INT(s) (*((int*)&s)) extern struct acpi_device *acpi_root; #define ACPI_BUS_CLASS "system_bus" #define ACPI_BUS_HID "ACPI_BUS" -#define ACPI_BUS_DRIVER_NAME "ACPI Bus Driver" #define ACPI_BUS_DEVICE_NAME "System Bus" static LIST_HEAD(acpi_device_list); diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c index 62ce87d71651..37a0930fc0a6 100644 --- a/drivers/acpi/sleep/main.c +++ b/drivers/acpi/sleep/main.c @@ -200,7 +200,7 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = { {}, }; -static int __init acpi_sleep_init(void) +int __init acpi_sleep_init(void) { int i = 0; @@ -229,4 +229,3 @@ static int __init acpi_sleep_init(void) return 0; } -late_initcall(acpi_sleep_init); diff --git a/drivers/acpi/system.c b/drivers/acpi/system.c index 7147b0bdab0a..83a8d3097904 100644 --- a/drivers/acpi/system.c +++ b/drivers/acpi/system.c @@ -31,14 +31,13 @@ #include <acpi/acpi_drivers.h> #define _COMPONENT ACPI_SYSTEM_COMPONENT -ACPI_MODULE_NAME("acpi_system") +ACPI_MODULE_NAME("system"); #ifdef MODULE_PARAM_PREFIX #undef MODULE_PARAM_PREFIX #endif #define MODULE_PARAM_PREFIX "acpi." #define ACPI_SYSTEM_CLASS "system" -#define ACPI_SYSTEM_DRIVER_NAME "ACPI System Driver" #define ACPI_SYSTEM_DEVICE_NAME "System" #define ACPI_SYSTEM_FILE_INFO "info" #define ACPI_SYSTEM_FILE_EVENT "event" diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c index 45bd17313c4a..849e2c361804 100644 --- a/drivers/acpi/tables.c +++ b/drivers/acpi/tables.c @@ -169,40 +169,40 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header * header) int __init -acpi_table_parse_madt_family(char *id, - unsigned long madt_size, +acpi_table_parse_entries(char *id, + unsigned long table_size, int entry_id, - acpi_madt_entry_handler handler, + acpi_table_entry_handler handler, unsigned int max_entries) { - struct acpi_table_header *madt = NULL; + struct acpi_table_header *table_header = NULL; struct acpi_subtable_header *entry; unsigned int count = 0; - unsigned long madt_end; + unsigned long table_end; if (!handler) return -EINVAL; - /* Locate the MADT (if exists). There should only be one. */ - acpi_get_table(id, 0, &madt); + /* Locate the table (if exists). There should only be one. */ + acpi_get_table(id, 0, &table_header); - if (!madt) { + if (!table_header) { printk(KERN_WARNING PREFIX "%4.4s not present\n", id); return -ENODEV; } - madt_end = (unsigned long)madt + madt->length; + table_end = (unsigned long)table_header + table_header->length; /* Parse all entries looking for a match. */ entry = (struct acpi_subtable_header *) - ((unsigned long)madt + madt_size); + ((unsigned long)table_header + table_size); while (((unsigned long)entry) + sizeof(struct acpi_subtable_header) < - madt_end) { + table_end) { if (entry->type == entry_id && (!max_entries || count++ < max_entries)) - if (handler(entry, madt_end)) + if (handler(entry, table_end)) return -EINVAL; entry = (struct acpi_subtable_header *) @@ -218,13 +218,22 @@ acpi_table_parse_madt_family(char *id, int __init acpi_table_parse_madt(enum acpi_madt_type id, - acpi_madt_entry_handler handler, unsigned int max_entries) + acpi_table_entry_handler handler, unsigned int max_entries) { - return acpi_table_parse_madt_family(ACPI_SIG_MADT, + return acpi_table_parse_entries(ACPI_SIG_MADT, sizeof(struct acpi_table_madt), id, handler, max_entries); } +/** + * acpi_table_parse - find table with @id, run @handler on it + * + * @id: table id to find + * @handler: handler to run + * + * Scan the ACPI System Descriptor Table (STD) for a table matching @id, + * run @handler on it. Return 0 if table found, return on if not. + */ int __init acpi_table_parse(char *id, acpi_table_handler handler) { struct acpi_table_header *table = NULL; @@ -234,9 +243,9 @@ int __init acpi_table_parse(char *id, acpi_table_handler handler) acpi_get_table(id, 0, &table); if (table) { handler(table); - return 1; - } else return 0; + } else + return 1; } /* diff --git a/drivers/acpi/tables/tbxface.c b/drivers/acpi/tables/tbxface.c index 807978d5381a..417ef5fa7666 100644 --- a/drivers/acpi/tables/tbxface.c +++ b/drivers/acpi/tables/tbxface.c @@ -338,9 +338,9 @@ acpi_status acpi_unload_table_id(acpi_owner_id id) int i; acpi_status status = AE_NOT_EXIST; - ACPI_FUNCTION_TRACE(acpi_unload_table); + ACPI_FUNCTION_TRACE(acpi_unload_table_id); - /* Find table from the requested type list */ + /* Find table in the global table list */ for (i = 0; i < acpi_gbl_root_table_list.count; ++i) { if (id != acpi_gbl_root_table_list.tables[i].owner_id) { continue; @@ -352,8 +352,9 @@ acpi_status acpi_unload_table_id(acpi_owner_id id) * simply a position within the hierarchy */ acpi_tb_delete_namespace_by_owner(i); - acpi_tb_release_owner_id(i); + status = acpi_tb_release_owner_id(i); acpi_tb_set_table_loaded_flag(i, FALSE); + break; } return_ACPI_STATUS(status); } @@ -408,7 +409,7 @@ acpi_get_table(char *signature, } if (!acpi_gbl_permanent_mmap) { - acpi_gbl_root_table_list.tables[i].pointer = 0; + acpi_gbl_root_table_list.tables[i].pointer = NULL; } return (status); diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 986afd470a14..0ae8b9310cbf 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -47,7 +47,6 @@ #define ACPI_THERMAL_COMPONENT 0x04000000 #define ACPI_THERMAL_CLASS "thermal_zone" -#define ACPI_THERMAL_DRIVER_NAME "ACPI Thermal Zone Driver" #define ACPI_THERMAL_DEVICE_NAME "Thermal Zone" #define ACPI_THERMAL_FILE_STATE "state" #define ACPI_THERMAL_FILE_TEMPERATURE "temperature" @@ -71,10 +70,10 @@ #define CELSIUS_TO_KELVIN(t) ((t+273)*10) #define _COMPONENT ACPI_THERMAL_COMPONENT -ACPI_MODULE_NAME("acpi_thermal") +ACPI_MODULE_NAME("thermal"); MODULE_AUTHOR("Paul Diefenbaugh"); -MODULE_DESCRIPTION(ACPI_THERMAL_DRIVER_NAME); +MODULE_DESCRIPTION("ACPI Thermal Zone Driver"); MODULE_LICENSE("GPL"); static int tzp; @@ -99,7 +98,7 @@ static ssize_t acpi_thermal_write_polling(struct file *, const char __user *, size_t, loff_t *); static struct acpi_driver acpi_thermal_driver = { - .name = ACPI_THERMAL_DRIVER_NAME, + .name = "thermal", .class = ACPI_THERMAL_CLASS, .ids = ACPI_THERMAL_HID, .ops = { @@ -270,7 +269,7 @@ static int acpi_thermal_set_polling(struct acpi_thermal *tz, int seconds) ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Polling frequency set to %lu seconds\n", - tz->polling_frequency)); + tz->polling_frequency/10)); return 0; } @@ -1357,28 +1356,32 @@ static int acpi_thermal_remove(struct acpi_device *device, int type) static int acpi_thermal_resume(struct acpi_device *device) { struct acpi_thermal *tz = NULL; - int i; + int i, j, power_state, result; + if (!device || !acpi_driver_data(device)) return -EINVAL; tz = acpi_driver_data(device); - acpi_thermal_get_temperature(tz); - for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) { - if (tz->trips.active[i].flags.valid) { - tz->temperature = tz->trips.active[i].temperature; - tz->trips.active[i].flags.enabled = 0; - - acpi_thermal_active(tz); - - tz->state.active |= tz->trips.active[i].flags.enabled; - tz->state.active_index = i; + if (!(&tz->trips.active[i])) + break; + if (!tz->trips.active[i].flags.valid) + break; + tz->trips.active[i].flags.enabled = 1; + for (j = 0; j < tz->trips.active[i].devices.count; j++) { + result = acpi_bus_get_power(tz->trips.active[i].devices. + handles[j], &power_state); + if (result || (power_state != ACPI_STATE_D0)) { + tz->trips.active[i].flags.enabled = 0; + break; + } } + tz->state.active |= tz->trips.active[i].flags.enabled; } - acpi_thermal_check(tz); + acpi_thermal_check(tz); return AE_OK; } diff --git a/drivers/acpi/toshiba_acpi.c b/drivers/acpi/toshiba_acpi.c index d9b651ffcdc0..faf8a5232d8e 100644 --- a/drivers/acpi/toshiba_acpi.c +++ b/drivers/acpi/toshiba_acpi.c @@ -125,7 +125,7 @@ static int write_acpi_int(const char *methodName, int val) union acpi_object in_objs[1]; acpi_status status; - params.count = sizeof(in_objs) / sizeof(in_objs[0]); + params.count = ARRAY_SIZE(in_objs); params.pointer = in_objs; in_objs[0].type = ACPI_TYPE_INTEGER; in_objs[0].integer.value = val; @@ -561,10 +561,6 @@ static int __init toshiba_acpi_init(void) if (acpi_disabled) return -ENODEV; - if (!acpi_specific_hotkey_enabled) { - printk(MY_INFO "Using generic hotkey driver\n"); - return -ENODEV; - } /* simple device detection: look for HCI method */ if (is_valid_acpi_path(METHOD_HCI_1)) method_hci = METHOD_HCI_1; diff --git a/drivers/acpi/utilities/utdelete.c b/drivers/acpi/utilities/utdelete.c index f777cebdc46d..673a0caa4073 100644 --- a/drivers/acpi/utilities/utdelete.c +++ b/drivers/acpi/utilities/utdelete.c @@ -170,7 +170,6 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object) acpi_os_delete_mutex(object->mutex.os_mutex); acpi_gbl_global_lock_mutex = NULL; } else { - acpi_ex_unlink_mutex(object); acpi_os_delete_mutex(object->mutex.os_mutex); } break; diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index 68a809fa7b19..34f157571080 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -31,7 +31,7 @@ #include <acpi/acpi_drivers.h> #define _COMPONENT ACPI_BUS_COMPONENT -ACPI_MODULE_NAME("acpi_utils") +ACPI_MODULE_NAME("utils"); /* -------------------------------------------------------------------------- Object Evaluation Helpers diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index e0b97add8c63..bf525cca3b63 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -40,7 +40,6 @@ #define ACPI_VIDEO_COMPONENT 0x08000000 #define ACPI_VIDEO_CLASS "video" -#define ACPI_VIDEO_DRIVER_NAME "ACPI Video Driver" #define ACPI_VIDEO_BUS_NAME "Video Bus" #define ACPI_VIDEO_DEVICE_NAME "Video Device" #define ACPI_VIDEO_NOTIFY_SWITCH 0x80 @@ -65,17 +64,17 @@ #define ACPI_VIDEO_DISPLAY_LCD 4 #define _COMPONENT ACPI_VIDEO_COMPONENT -ACPI_MODULE_NAME("acpi_video") +ACPI_MODULE_NAME("video"); - MODULE_AUTHOR("Bruno Ducrot"); -MODULE_DESCRIPTION(ACPI_VIDEO_DRIVER_NAME); +MODULE_AUTHOR("Bruno Ducrot"); +MODULE_DESCRIPTION("ACPI Video Driver"); MODULE_LICENSE("GPL"); static int acpi_video_bus_add(struct acpi_device *device); static int acpi_video_bus_remove(struct acpi_device *device, int type); static struct acpi_driver acpi_video_bus = { - .name = ACPI_VIDEO_DRIVER_NAME, + .name = "video", .class = ACPI_VIDEO_CLASS, .ids = ACPI_VIDEO_HID, .ops = { diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 3747457fee7a..4af0a4bb5780 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -161,6 +161,19 @@ config SATA_INTEL_COMBINED depends on IDE=y && !BLK_DEV_IDE_SATA && (SATA_AHCI || ATA_PIIX) default y +config SATA_ACPI + bool + depends on ACPI && PCI + default y + help + This option adds support for SATA-related ACPI objects. + These ACPI objects add the ability to retrieve taskfiles + from the ACPI BIOS and write them to the disk controller. + These objects may be related to performance, security, + power management, or other areas. + You can disable this at kernel boot time by using the + option libata.noacpi=1 + config PATA_ALI tristate "ALi PATA support (Experimental)" depends on PCI && EXPERIMENTAL diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index cd096f0c78a1..74298afbbaa7 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -66,4 +66,4 @@ obj-$(CONFIG_ATA_GENERIC) += ata_generic.o obj-$(CONFIG_PATA_LEGACY) += pata_legacy.o libata-objs := libata-core.o libata-scsi.o libata-sff.o libata-eh.o - +libata-$(CONFIG_SATA_ACPI) += libata-acpi.o diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c new file mode 100644 index 000000000000..b4e8be5d292c --- /dev/null +++ b/drivers/ata/libata-acpi.c @@ -0,0 +1,698 @@ +/* + * libata-acpi.c + * Provides ACPI support for PATA/SATA. + * + * Copyright (C) 2006 Intel Corp. + * Copyright (C) 2006 Randy Dunlap + */ + +#include <linux/ata.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/acpi.h> +#include <linux/libata.h> +#include <linux/pci.h> +#include "libata.h" + +#include <acpi/acpi_bus.h> +#include <acpi/acnames.h> +#include <acpi/acnamesp.h> +#include <acpi/acparser.h> +#include <acpi/acexcep.h> +#include <acpi/acmacros.h> +#include <acpi/actypes.h> + +#define SATA_ROOT_PORT(x) (((x) >> 16) & 0xffff) +#define SATA_PORT_NUMBER(x) ((x) & 0xffff) /* or NO_PORT_MULT */ +#define NO_PORT_MULT 0xffff +#define SATA_ADR_RSVD 0xffffffff + +#define REGS_PER_GTF 7 +struct taskfile_array { + u8 tfa[REGS_PER_GTF]; /* regs. 0x1f1 - 0x1f7 */ +}; + + +/** + * sata_get_dev_handle - finds acpi_handle and PCI device.function + * @dev: device to locate + * @handle: returned acpi_handle for @dev + * @pcidevfn: return PCI device.func for @dev + * + * This function is somewhat SATA-specific. Or at least the + * PATA & SATA versions of this function are different, + * so it's not entirely generic code. + * + * Returns 0 on success, <0 on error. + */ +static int sata_get_dev_handle(struct device *dev, acpi_handle *handle, + acpi_integer *pcidevfn) +{ + struct pci_dev *pci_dev; + acpi_integer addr; + + pci_dev = to_pci_dev(dev); /* NOTE: PCI-specific */ + /* Please refer to the ACPI spec for the syntax of _ADR. */ + addr = (PCI_SLOT(pci_dev->devfn) << 16) | PCI_FUNC(pci_dev->devfn); + *pcidevfn = addr; + *handle = acpi_get_child(DEVICE_ACPI_HANDLE(dev->parent), addr); + if (!*handle) + return -ENODEV; + return 0; +} + +/** + * pata_get_dev_handle - finds acpi_handle and PCI device.function + * @dev: device to locate + * @handle: returned acpi_handle for @dev + * @pcidevfn: return PCI device.func for @dev + * + * The PATA and SATA versions of this function are different. + * + * Returns 0 on success, <0 on error. + */ +static int pata_get_dev_handle(struct device *dev, acpi_handle *handle, + acpi_integer *pcidevfn) +{ + unsigned int bus, devnum, func; + acpi_integer addr; + acpi_handle dev_handle, parent_handle; + struct acpi_buffer buffer = {.length = ACPI_ALLOCATE_BUFFER, + .pointer = NULL}; + acpi_status status; + struct acpi_device_info *dinfo = NULL; + int ret = -ENODEV; + struct pci_dev *pdev = to_pci_dev(dev); + + bus = pdev->bus->number; + devnum = PCI_SLOT(pdev->devfn); + func = PCI_FUNC(pdev->devfn); + + dev_handle = DEVICE_ACPI_HANDLE(dev); + parent_handle = DEVICE_ACPI_HANDLE(dev->parent); + + status = acpi_get_object_info(parent_handle, &buffer); + if (ACPI_FAILURE(status)) + goto err; + + dinfo = buffer.pointer; + if (dinfo && (dinfo->valid & ACPI_VALID_ADR) && + dinfo->address == bus) { + /* ACPI spec for _ADR for PCI bus: */ + addr = (acpi_integer)(devnum << 16 | func); + *pcidevfn = addr; + *handle = dev_handle; + } else { + goto err; + } + + if (!*handle) + goto err; + ret = 0; +err: + kfree(dinfo); + return ret; +} + +struct walk_info { /* can be trimmed some */ + struct device *dev; + struct acpi_device *adev; + acpi_handle handle; + acpi_integer pcidevfn; + unsigned int drivenum; + acpi_handle obj_handle; + struct ata_port *ataport; + struct ata_device *atadev; + u32 sata_adr; + int status; + char basepath[ACPI_PATHNAME_MAX]; + int basepath_len; +}; + +static acpi_status get_devices(acpi_handle handle, + u32 level, void *context, void **return_value) +{ + acpi_status status; + struct walk_info *winfo = context; + struct acpi_buffer namebuf = {ACPI_ALLOCATE_BUFFER, NULL}; + char *pathname; + struct acpi_buffer buffer; + struct acpi_device_info *dinfo; + + status = acpi_get_name(handle, ACPI_FULL_PATHNAME, &namebuf); + if (status) + goto ret; + pathname = namebuf.pointer; + + buffer.length = ACPI_ALLOCATE_BUFFER; + buffer.pointer = NULL; + status = acpi_get_object_info(handle, &buffer); + if (ACPI_FAILURE(status)) + goto out2; + + dinfo = buffer.pointer; + + /* find full device path name for pcidevfn */ + if (dinfo && (dinfo->valid & ACPI_VALID_ADR) && + dinfo->address == winfo->pcidevfn) { + if (ata_msg_probe(winfo->ataport)) + ata_dev_printk(winfo->atadev, KERN_DEBUG, + ":%s: matches pcidevfn (0x%llx)\n", + pathname, winfo->pcidevfn); + strlcpy(winfo->basepath, pathname, + sizeof(winfo->basepath)); + winfo->basepath_len = strlen(pathname); + goto out; + } + + /* if basepath is not yet known, ignore this object */ + if (!winfo->basepath_len) + goto out; + + /* if this object is in scope of basepath, maybe use it */ + if (strncmp(pathname, winfo->basepath, + winfo->basepath_len) == 0) { + if (!(dinfo->valid & ACPI_VALID_ADR)) + goto out; + if (ata_msg_probe(winfo->ataport)) + ata_dev_printk(winfo->atadev, KERN_DEBUG, + "GOT ONE: (%s) root_port = 0x%llx," + " port_num = 0x%llx\n", pathname, + SATA_ROOT_PORT(dinfo->address), + SATA_PORT_NUMBER(dinfo->address)); + /* heuristics: */ + if (SATA_PORT_NUMBER(dinfo->address) != NO_PORT_MULT) + if (ata_msg_probe(winfo->ataport)) + ata_dev_printk(winfo->atadev, + KERN_DEBUG, "warning: don't" + " know how to handle SATA port" + " multiplier\n"); + if (SATA_ROOT_PORT(dinfo->address) == + winfo->ataport->port_no && + SATA_PORT_NUMBER(dinfo->address) == NO_PORT_MULT) { + if (ata_msg_probe(winfo->ataport)) + ata_dev_printk(winfo->atadev, + KERN_DEBUG, + "THIS ^^^^^ is the requested" + " SATA drive (handle = 0x%p)\n", + handle); + winfo->sata_adr = dinfo->address; + winfo->obj_handle = handle; + } + } +out: + kfree(dinfo); +out2: + kfree(pathname); + +ret: + return status; +} + +/* Get the SATA drive _ADR object. */ +static int get_sata_adr(struct device *dev, acpi_handle handle, + acpi_integer pcidevfn, unsigned int drive, + struct ata_port *ap, + struct ata_device *atadev, u32 *dev_adr) +{ + acpi_status status; + struct walk_info *winfo; + int err = -ENOMEM; + + winfo = kzalloc(sizeof(struct walk_info), GFP_KERNEL); + if (!winfo) + goto out; + + winfo->dev = dev; + winfo->atadev = atadev; + winfo->ataport = ap; + if (acpi_bus_get_device(handle, &winfo->adev) < 0) + if (ata_msg_probe(ap)) + ata_dev_printk(winfo->atadev, KERN_DEBUG, + "acpi_bus_get_device failed\n"); + winfo->handle = handle; + winfo->pcidevfn = pcidevfn; + winfo->drivenum = drive; + + status = acpi_get_devices(NULL, get_devices, winfo, NULL); + if (ACPI_FAILURE(status)) { + if (ata_msg_probe(ap)) + ata_dev_printk(winfo->atadev, KERN_DEBUG, + "%s: acpi_get_devices failed\n", + __FUNCTION__); + err = -ENODEV; + } else { + *dev_adr = winfo->sata_adr; + atadev->obj_handle = winfo->obj_handle; + err = 0; + } + kfree(winfo); +out: + return err; +} + +/** + * do_drive_get_GTF - get the drive bootup default taskfile settings + * @ap: the ata_port for the drive + * @ix: target ata_device (drive) index + * @gtf_length: number of bytes of _GTF data returned at @gtf_address + * @gtf_address: buffer containing _GTF taskfile arrays + * + * This applies to both PATA and SATA drives. + * + * The _GTF method has no input parameters. + * It returns a variable number of register set values (registers + * hex 1F1..1F7, taskfiles). + * The <variable number> is not known in advance, so have ACPI-CA + * allocate the buffer as needed and return it, then free it later. + * + * The returned @gtf_length and @gtf_address are only valid if the + * function return value is 0. + */ +static int do_drive_get_GTF(struct ata_port *ap, int ix, + unsigned int *gtf_length, unsigned long *gtf_address, + unsigned long *obj_loc) +{ + acpi_status status; + acpi_handle dev_handle = NULL; + acpi_handle chan_handle, drive_handle; + acpi_integer pcidevfn = 0; + u32 dev_adr; + struct acpi_buffer output; + union acpi_object *out_obj; + struct device *dev = ap->host->dev; + struct ata_device *atadev = &ap->device[ix]; + int err = -ENODEV; + + *gtf_length = 0; + *gtf_address = 0UL; + *obj_loc = 0UL; + + if (noacpi) + return 0; + + if (ata_msg_probe(ap)) + ata_dev_printk(atadev, KERN_DEBUG, + "%s: ENTER: ap->id: %d, port#: %d\n", + __FUNCTION__, ap->id, ap->port_no); + + if (!ata_dev_enabled(atadev) || (ap->flags & ATA_FLAG_DISABLED)) { + if (ata_msg_probe(ap)) + ata_dev_printk(atadev, KERN_DEBUG, "%s: ERR: " + "ata_dev_present: %d, PORT_DISABLED: %lu\n", + __FUNCTION__, ata_dev_enabled(atadev), + ap->flags & ATA_FLAG_DISABLED); + goto out; + } + + /* Don't continue if device has no _ADR method. + * _GTF is intended for known motherboard devices. */ + if (!(ap->cbl == ATA_CBL_SATA)) { + err = pata_get_dev_handle(dev, &dev_handle, &pcidevfn); + if (err < 0) { + if (ata_msg_probe(ap)) + ata_dev_printk(atadev, KERN_DEBUG, + "%s: pata_get_dev_handle failed (%d)\n", + __FUNCTION__, err); + goto out; + } + } else { + err = sata_get_dev_handle(dev, &dev_handle, &pcidevfn); + if (err < 0) { + if (ata_msg_probe(ap)) + ata_dev_printk(atadev, KERN_DEBUG, + "%s: sata_get_dev_handle failed (%d\n", + __FUNCTION__, err); + goto out; + } + } + + /* Get this drive's _ADR info. if not already known. */ + if (!atadev->obj_handle) { + if (!(ap->cbl == ATA_CBL_SATA)) { + /* get child objects of dev_handle == channel objects, + * + _their_ children == drive objects */ + /* channel is ap->port_no */ + chan_handle = acpi_get_child(dev_handle, + ap->port_no); + if (ata_msg_probe(ap)) + ata_dev_printk(atadev, KERN_DEBUG, + "%s: chan adr=%d: chan_handle=0x%p\n", + __FUNCTION__, ap->port_no, + chan_handle); + if (!chan_handle) { + err = -ENODEV; + goto out; + } + /* TBD: could also check ACPI object VALID bits */ + drive_handle = acpi_get_child(chan_handle, ix); + if (!drive_handle) { + err = -ENODEV; + goto out; + } + dev_adr = ix; + atadev->obj_handle = drive_handle; + } else { /* for SATA mode */ + dev_adr = SATA_ADR_RSVD; + err = get_sata_adr(dev, dev_handle, pcidevfn, 0, + ap, atadev, &dev_adr); + } + if (err < 0 || dev_adr == SATA_ADR_RSVD || + !atadev->obj_handle) { + if (ata_msg_probe(ap)) + ata_dev_printk(atadev, KERN_DEBUG, + "%s: get_sata/pata_adr failed: " + "err=%d, dev_adr=%u, obj_handle=0x%p\n", + __FUNCTION__, err, dev_adr, + atadev->obj_handle); + goto out; + } + } + + /* Setting up output buffer */ + output.length = ACPI_ALLOCATE_BUFFER; + output.pointer = NULL; /* ACPI-CA sets this; save/free it later */ + + /* _GTF has no input parameters */ + err = -EIO; + status = acpi_evaluate_object(atadev->obj_handle, "_GTF", + NULL, &output); + if (ACPI_FAILURE(status)) { + if (ata_msg_probe(ap)) + ata_dev_printk(atadev, KERN_DEBUG, + "%s: Run _GTF error: status = 0x%x\n", + __FUNCTION__, status); + goto out; + } + + if (!output.length || !output.pointer) { + if (ata_msg_probe(ap)) + ata_dev_printk(atadev, KERN_DEBUG, "%s: Run _GTF: " + "length or ptr is NULL (0x%llx, 0x%p)\n", + __FUNCTION__, + (unsigned long long)output.length, + output.pointer); + kfree(output.pointer); + goto out; + } + + out_obj = output.pointer; + if (out_obj->type != ACPI_TYPE_BUFFER) { + kfree(output.pointer); + if (ata_msg_probe(ap)) + ata_dev_printk(atadev, KERN_DEBUG, "%s: Run _GTF: " + "error: expected object type of " + " ACPI_TYPE_BUFFER, got 0x%x\n", + __FUNCTION__, out_obj->type); + err = -ENOENT; + goto out; + } + + if (!out_obj->buffer.length || !out_obj->buffer.pointer || + out_obj->buffer.length % REGS_PER_GTF) { + if (ata_msg_drv(ap)) + ata_dev_printk(atadev, KERN_ERR, + "%s: unexpected GTF length (%d) or addr (0x%p)\n", + __FUNCTION__, out_obj->buffer.length, + out_obj->buffer.pointer); + err = -ENOENT; + goto out; + } + + *gtf_length = out_obj->buffer.length; + *gtf_address = (unsigned long)out_obj->buffer.pointer; + *obj_loc = (unsigned long)out_obj; + if (ata_msg_probe(ap)) + ata_dev_printk(atadev, KERN_DEBUG, "%s: returning " + "gtf_length=%d, gtf_address=0x%lx, obj_loc=0x%lx\n", + __FUNCTION__, *gtf_length, *gtf_address, *obj_loc); + err = 0; +out: + return err; +} + +/** + * taskfile_load_raw - send taskfile registers to host controller + * @ap: Port to which output is sent + * @gtf: raw ATA taskfile register set (0x1f1 - 0x1f7) + * + * Outputs ATA taskfile to standard ATA host controller using MMIO + * or PIO as indicated by the ATA_FLAG_MMIO flag. + * Writes the control, feature, nsect, lbal, lbam, and lbah registers. + * Optionally (ATA_TFLAG_LBA48) writes hob_feature, hob_nsect, + * hob_lbal, hob_lbam, and hob_lbah. + * + * This function waits for idle (!BUSY and !DRQ) after writing + * registers. If the control register has a new value, this + * function also waits for idle after writing control and before + * writing the remaining registers. + * + * LOCKING: TBD: + * Inherited from caller. + */ +static void taskfile_load_raw(struct ata_port *ap, + struct ata_device *atadev, + const struct taskfile_array *gtf) +{ + if (ata_msg_probe(ap)) + ata_dev_printk(atadev, KERN_DEBUG, "%s: (0x1f1-1f7): hex: " + "%02x %02x %02x %02x %02x %02x %02x\n", + __FUNCTION__, + gtf->tfa[0], gtf->tfa[1], gtf->tfa[2], + gtf->tfa[3], gtf->tfa[4], gtf->tfa[5], gtf->tfa[6]); + + if ((gtf->tfa[0] == 0) && (gtf->tfa[1] == 0) && (gtf->tfa[2] == 0) + && (gtf->tfa[3] == 0) && (gtf->tfa[4] == 0) && (gtf->tfa[5] == 0) + && (gtf->tfa[6] == 0)) + return; + + if (ap->ops->qc_issue) { + struct ata_taskfile tf; + unsigned int err; + + ata_tf_init(atadev, &tf); + + /* convert gtf to tf */ + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; /* TBD */ + tf.protocol = atadev->class == ATA_DEV_ATAPI ? + ATA_PROT_ATAPI_NODATA : ATA_PROT_NODATA; + tf.feature = gtf->tfa[0]; /* 0x1f1 */ + tf.nsect = gtf->tfa[1]; /* 0x1f2 */ + tf.lbal = gtf->tfa[2]; /* 0x1f3 */ + tf.lbam = gtf->tfa[3]; /* 0x1f4 */ + tf.lbah = gtf->tfa[4]; /* 0x1f5 */ + tf.device = gtf->tfa[5]; /* 0x1f6 */ + tf.command = gtf->tfa[6]; /* 0x1f7 */ + + err = ata_exec_internal(atadev, &tf, NULL, DMA_NONE, NULL, 0); + if (err && ata_msg_probe(ap)) + ata_dev_printk(atadev, KERN_ERR, + "%s: ata_exec_internal failed: %u\n", + __FUNCTION__, err); + } else + if (ata_msg_warn(ap)) + ata_dev_printk(atadev, KERN_WARNING, + "%s: SATA driver is missing qc_issue function" + " entry points\n", + __FUNCTION__); +} + +/** + * do_drive_set_taskfiles - write the drive taskfile settings from _GTF + * @ap: the ata_port for the drive + * @atadev: target ata_device + * @gtf_length: total number of bytes of _GTF taskfiles + * @gtf_address: location of _GTF taskfile arrays + * + * This applies to both PATA and SATA drives. + * + * Write {gtf_address, length gtf_length} in groups of + * REGS_PER_GTF bytes. + */ +static int do_drive_set_taskfiles(struct ata_port *ap, + struct ata_device *atadev, unsigned int gtf_length, + unsigned long gtf_address) +{ + int err = -ENODEV; + int gtf_count = gtf_length / REGS_PER_GTF; + int ix; + struct taskfile_array *gtf; + + if (ata_msg_probe(ap)) + ata_dev_printk(atadev, KERN_DEBUG, + "%s: ENTER: ap->id: %d, port#: %d\n", + __FUNCTION__, ap->id, ap->port_no); + + if (noacpi || !(ap->cbl == ATA_CBL_SATA)) + return 0; + + if (!ata_dev_enabled(atadev) || (ap->flags & ATA_FLAG_DISABLED)) + goto out; + if (!gtf_count) /* shouldn't be here */ + goto out; + + if (gtf_length % REGS_PER_GTF) { + if (ata_msg_drv(ap)) + ata_dev_printk(atadev, KERN_ERR, + "%s: unexpected GTF length (%d)\n", + __FUNCTION__, gtf_length); + goto out; + } + + for (ix = 0; ix < gtf_count; ix++) { + gtf = (struct taskfile_array *) + (gtf_address + ix * REGS_PER_GTF); + + /* send all TaskFile registers (0x1f1-0x1f7) *in*that*order* */ + taskfile_load_raw(ap, atadev, gtf); + } + + err = 0; +out: + return err; +} + +/** + * ata_acpi_exec_tfs - get then write drive taskfile settings + * @ap: the ata_port for the drive + * + * This applies to both PATA and SATA drives. + */ +int ata_acpi_exec_tfs(struct ata_port *ap) +{ + int ix; + int ret =0; + unsigned int gtf_length; + unsigned long gtf_address; + unsigned long obj_loc; + + if (noacpi) + return 0; + + for (ix = 0; ix < ATA_MAX_DEVICES; ix++) { + if (!ata_dev_enabled(&ap->device[ix])) + continue; + + ret = do_drive_get_GTF(ap, ix, + >f_length, >f_address, &obj_loc); + if (ret < 0) { + if (ata_msg_probe(ap)) + ata_port_printk(ap, KERN_DEBUG, + "%s: get_GTF error (%d)\n", + __FUNCTION__, ret); + break; + } + + ret = do_drive_set_taskfiles(ap, &ap->device[ix], + gtf_length, gtf_address); + kfree((void *)obj_loc); + if (ret < 0) { + if (ata_msg_probe(ap)) + ata_port_printk(ap, KERN_DEBUG, + "%s: set_taskfiles error (%d)\n", + __FUNCTION__, ret); + break; + } + } + + return ret; +} + +/** + * ata_acpi_push_id - send Identify data to drive + * @ap: the ata_port for the drive + * @ix: drive index + * + * _SDD ACPI object: for SATA mode only + * Must be after Identify (Packet) Device -- uses its data + * ATM this function never returns a failure. It is an optional + * method and if it fails for whatever reason, we should still + * just keep going. + */ +int ata_acpi_push_id(struct ata_port *ap, unsigned int ix) +{ + acpi_handle handle; + acpi_integer pcidevfn; + int err; + struct device *dev = ap->host->dev; + struct ata_device *atadev = &ap->device[ix]; + u32 dev_adr; + acpi_status status; + struct acpi_object_list input; + union acpi_object in_params[1]; + + if (noacpi) + return 0; + + if (ata_msg_probe(ap)) + ata_dev_printk(atadev, KERN_DEBUG, + "%s: ap->id: %d, ix = %d, port#: %d\n", + __FUNCTION__, ap->id, ix, ap->port_no); + + /* Don't continue if not a SATA device. */ + if (!(ap->cbl == ATA_CBL_SATA)) { + if (ata_msg_probe(ap)) + ata_dev_printk(atadev, KERN_DEBUG, + "%s: Not a SATA device\n", __FUNCTION__); + goto out; + } + + /* Don't continue if device has no _ADR method. + * _SDD is intended for known motherboard devices. */ + err = sata_get_dev_handle(dev, &handle, &pcidevfn); + if (err < 0) { + if (ata_msg_probe(ap)) + ata_dev_printk(atadev, KERN_DEBUG, + "%s: sata_get_dev_handle failed (%d\n", + __FUNCTION__, err); + goto out; + } + + /* Get this drive's _ADR info, if not already known */ + if (!atadev->obj_handle) { + dev_adr = SATA_ADR_RSVD; + err = get_sata_adr(dev, handle, pcidevfn, ix, ap, atadev, + &dev_adr); + if (err < 0 || dev_adr == SATA_ADR_RSVD || + !atadev->obj_handle) { + if (ata_msg_probe(ap)) + ata_dev_printk(atadev, KERN_DEBUG, + "%s: get_sata_adr failed: " + "err=%d, dev_adr=%u, obj_handle=0x%p\n", + __FUNCTION__, err, dev_adr, + atadev->obj_handle); + goto out; + } + } + + /* Give the drive Identify data to the drive via the _SDD method */ + /* _SDD: set up input parameters */ + input.count = 1; + input.pointer = in_params; + in_params[0].type = ACPI_TYPE_BUFFER; + in_params[0].buffer.length = sizeof(atadev->id[0]) * ATA_ID_WORDS; + in_params[0].buffer.pointer = (u8 *)atadev->id; + /* Output buffer: _SDD has no output */ + + /* It's OK for _SDD to be missing too. */ + swap_buf_le16(atadev->id, ATA_ID_WORDS); + status = acpi_evaluate_object(atadev->obj_handle, "_SDD", &input, NULL); + swap_buf_le16(atadev->id, ATA_ID_WORDS); + + err = ACPI_FAILURE(status) ? -EIO : 0; + if (err < 0) { + if (ata_msg_probe(ap)) + ata_dev_printk(atadev, KERN_DEBUG, + "ata%u(%u): %s _SDD error: status = 0x%x\n", + ap->id, ap->device->devno, + __FUNCTION__, status); + } + + /* always return success */ +out: + return 0; +} + + diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 2cf8251728d2..e900c5edefc4 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -93,6 +93,10 @@ static int ata_probe_timeout = ATA_TMOUT_INTERNAL / HZ; module_param(ata_probe_timeout, int, 0444); MODULE_PARM_DESC(ata_probe_timeout, "Set ATA probing timeout (seconds)"); +int noacpi; +module_param(noacpi, int, 0444); +MODULE_PARM_DESC(noacpi, "Disables the use of ACPI in suspend/resume when set"); + MODULE_AUTHOR("Jeff Garzik"); MODULE_DESCRIPTION("Library module for ATA devices"); MODULE_LICENSE("GPL"); @@ -1564,6 +1568,16 @@ int ata_dev_configure(struct ata_device *dev) ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER, host %u, dev %u\n", __FUNCTION__, ap->id, dev->devno); + /* set _SDD */ + rc = ata_acpi_push_id(ap, dev->devno); + if (rc) { + ata_dev_printk(dev, KERN_WARNING, "failed to set _SDD(%d)\n", + rc); + } + + /* retrieve and execute the ATA task file of _GTF */ + ata_acpi_exec_tfs(ap); + /* print device capabilities */ if (ata_msg_probe(ap)) ata_dev_printk(dev, KERN_DEBUG, diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index 06ccf230e3c2..0ad7781d72a3 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -47,6 +47,7 @@ extern struct workqueue_struct *ata_aux_wq; extern int atapi_enabled; extern int atapi_dmadir; extern int libata_fua; +extern int noacpi; extern struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev); extern int ata_build_rw_tf(struct ata_taskfile *tf, struct ata_device *dev, u64 block, u32 n_block, unsigned int tf_flags, @@ -87,6 +88,20 @@ extern void ata_port_init(struct ata_port *ap, struct ata_host *host, extern struct ata_probe_ent *ata_probe_ent_alloc(struct device *dev, const struct ata_port_info *port); +/* libata-acpi.c */ +#ifdef CONFIG_SATA_ACPI +extern int ata_acpi_exec_tfs(struct ata_port *ap); +extern int ata_acpi_push_id(struct ata_port *ap, unsigned int ix); +#else +static inline int ata_acpi_exec_tfs(struct ata_port *ap) +{ + return 0; +} +static inline int ata_acpi_push_id(struct ata_port *ap, unsigned int ix) +{ + return 0; +} +#endif /* libata-scsi.c */ extern struct scsi_transport_template ata_scsi_transport_template; diff --git a/drivers/atm/he.c b/drivers/atm/he.c index db33f6f4dd2a..8510026b690a 100644 --- a/drivers/atm/he.c +++ b/drivers/atm/he.c @@ -3017,7 +3017,7 @@ read_prom_byte(struct he_dev *he_dev, int addr) he_writel(he_dev, val, HOST_CNTL); /* Send READ instruction */ - for (i = 0; i < sizeof(readtab)/sizeof(readtab[0]); i++) { + for (i = 0; i < ARRAY_SIZE(readtab); i++) { he_writel(he_dev, val | readtab[i], HOST_CNTL); udelay(EEPROM_DELAY); } diff --git a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c index f40786121948..b4b80140c398 100644 --- a/drivers/atm/idt77252.c +++ b/drivers/atm/idt77252.c @@ -388,7 +388,7 @@ idt77252_eeprom_read_status(struct idt77252_dev *card) gp = idt77252_read_gp(card) & ~(SAR_GP_EESCLK|SAR_GP_EECS|SAR_GP_EEDO); - for (i = 0; i < sizeof(rdsrtab)/sizeof(rdsrtab[0]); i++) { + for (i = 0; i < ARRAY_SIZE(rdsrtab); i++) { idt77252_write_gp(card, gp | rdsrtab[i]); udelay(5); } @@ -422,7 +422,7 @@ idt77252_eeprom_read_byte(struct idt77252_dev *card, u8 offset) gp = idt77252_read_gp(card) & ~(SAR_GP_EESCLK|SAR_GP_EECS|SAR_GP_EEDO); - for (i = 0; i < sizeof(rdtab)/sizeof(rdtab[0]); i++) { + for (i = 0; i < ARRAY_SIZE(rdtab); i++) { idt77252_write_gp(card, gp | rdtab[i]); udelay(5); } @@ -469,14 +469,14 @@ idt77252_eeprom_write_byte(struct idt77252_dev *card, u8 offset, u8 data) gp = idt77252_read_gp(card) & ~(SAR_GP_EESCLK|SAR_GP_EECS|SAR_GP_EEDO); - for (i = 0; i < sizeof(wrentab)/sizeof(wrentab[0]); i++) { + for (i = 0; i < ARRAY_SIZE(wrentab); i++) { idt77252_write_gp(card, gp | wrentab[i]); udelay(5); } idt77252_write_gp(card, gp | SAR_GP_EECS); udelay(5); - for (i = 0; i < sizeof(wrtab)/sizeof(wrtab[0]); i++) { + for (i = 0; i < ARRAY_SIZE(wrtab); i++) { idt77252_write_gp(card, gp | wrtab[i]); udelay(5); } diff --git a/drivers/atm/nicstarmac.c b/drivers/atm/nicstarmac.c index 2c5e3ae77503..480947f4e01e 100644 --- a/drivers/atm/nicstarmac.c +++ b/drivers/atm/nicstarmac.c @@ -7,6 +7,8 @@ * Read this ForeRunner's MAC address from eprom/eeprom */ +#include <linux/kernel.h> + typedef void __iomem *virt_addr_t; #define CYCLE_DELAY 5 @@ -176,7 +178,7 @@ read_eprom_byte(virt_addr_t base, u_int8_t offset) val = NICSTAR_REG_READ( base, NICSTAR_REG_GENERAL_PURPOSE ) & 0xFFFFFFF0; /* Send READ instruction */ - for (i=0; i<sizeof readtab/sizeof readtab[0]; i++) + for (i=0; i<ARRAY_SIZE(readtab); i++) { NICSTAR_REG_WRITE( base, NICSTAR_REG_GENERAL_PURPOSE, (val | readtab[i]) ); diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 472810f8e6e7..253868e03c70 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -324,27 +324,25 @@ int bus_for_each_drv(struct bus_type * bus, struct device_driver * start, return error; } -static int device_add_attrs(struct bus_type * bus, struct device * dev) +static int device_add_attrs(struct bus_type *bus, struct device *dev) { int error = 0; int i; - if (bus->dev_attrs) { - for (i = 0; attr_name(bus->dev_attrs[i]); i++) { - error = device_create_file(dev,&bus->dev_attrs[i]); - if (error) - goto Err; + if (!bus->dev_attrs) + return 0; + + for (i = 0; attr_name(bus->dev_attrs[i]); i++) { + error = device_create_file(dev,&bus->dev_attrs[i]); + if (error) { + while (--i >= 0) + device_remove_file(dev, &bus->dev_attrs[i]); + break; } } - Done: return error; - Err: - while (--i >= 0) - device_remove_file(dev,&bus->dev_attrs[i]); - goto Done; } - static void device_remove_attrs(struct bus_type * bus, struct device * dev) { int i; diff --git a/drivers/base/class.c b/drivers/base/class.c index 96def1ddba19..1417e5cd4c6f 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -163,8 +163,7 @@ int class_register(struct class * cls) void class_unregister(struct class * cls) { pr_debug("device class '%s': unregistering\n", cls->name); - if (cls->virtual_dir) - kobject_unregister(cls->virtual_dir); + kobject_unregister(cls->virtual_dir); remove_class_attrs(cls); subsystem_unregister(&cls->subsys); } diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index 7fd095efaebd..fe7ef3394144 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -103,7 +103,7 @@ static SYSDEV_ATTR(crash_notes, 0400, show_crash_notes, NULL); #endif /* - * register_cpu - Setup a driverfs device for a CPU. + * register_cpu - Setup a sysfs device for a CPU. * @cpu - cpu->hotpluggable field set to 1 will generate a control file in * sysfs for this CPU. * @num - CPU number to use when creating the device. diff --git a/drivers/base/node.c b/drivers/base/node.c index 475e33f76e0d..cae346ef1b20 100644 --- a/drivers/base/node.c +++ b/drivers/base/node.c @@ -133,7 +133,7 @@ static SYSDEV_ATTR(distance, S_IRUGO, node_read_distance, NULL); /* - * register_node - Setup a driverfs device for a node. + * register_node - Setup a sysfs device for a node. * @num - Node number to use when creating the device. * * Initialize and register the node device. diff --git a/drivers/char/rio/rio_linux.c b/drivers/char/rio/rio_linux.c index 85c161845260..294e9cb0c449 100644 --- a/drivers/char/rio/rio_linux.c +++ b/drivers/char/rio/rio_linux.c @@ -1146,7 +1146,7 @@ static int __init rio_init(void) rio_dprintk(RIO_DEBUG_INIT, "Enabling interrupts on rio card.\n"); hp->Mode |= RIO_PCI_INT_ENABLE; } else - hp->Mode &= !RIO_PCI_INT_ENABLE; + hp->Mode &= ~RIO_PCI_INT_ENABLE; rio_dprintk(RIO_DEBUG_INIT, "New Mode: %x\n", hp->Mode); rio_start_card_running(hp); } diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 891ef6d0b1bf..c3d4856fb618 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -73,6 +73,17 @@ config SENSORS_ADM1026 This driver can also be built as a module. If so, the module will be called adm1026. +config SENSORS_ADM1029 + tristate "Analog Devices ADM1029" + depends on HWMON && I2C && EXPERIMENTAL + help + If you say yes here you get support for Analog Devices ADM1029 + sensor chip. + Very rare chip, please let us know you use it. + + This driver can also be built as a module. If so, the module + will be called adm1029. + config SENSORS_ADM1031 tristate "Analog Devices ADM1031 and compatibles" depends on HWMON && I2C && EXPERIMENTAL diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 31661124271e..4165c27a2f25 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_SENSORS_ABITUGURU) += abituguru.o obj-$(CONFIG_SENSORS_ADM1021) += adm1021.o obj-$(CONFIG_SENSORS_ADM1025) += adm1025.o obj-$(CONFIG_SENSORS_ADM1026) += adm1026.o +obj-$(CONFIG_SENSORS_ADM1029) += adm1029.o obj-$(CONFIG_SENSORS_ADM1031) += adm1031.o obj-$(CONFIG_SENSORS_ADM9240) += adm9240.o obj-$(CONFIG_SENSORS_AMS) += ams/ diff --git a/drivers/hwmon/abituguru.c b/drivers/hwmon/abituguru.c index b1dc63e4ac7b..bede4d990ea6 100644 --- a/drivers/hwmon/abituguru.c +++ b/drivers/hwmon/abituguru.c @@ -1267,30 +1267,42 @@ static int __devinit abituguru_probe(struct platform_device *pdev) printk(KERN_INFO ABIT_UGURU_NAME ": found Abit uGuru\n"); /* Register sysfs hooks */ - data->class_dev = hwmon_device_register(&pdev->dev); - if (IS_ERR(data->class_dev)) { - res = PTR_ERR(data->class_dev); - goto abituguru_probe_error; - } for (i = 0; i < sysfs_attr_i; i++) - device_create_file(&pdev->dev, &data->sysfs_attr[i].dev_attr); + if (device_create_file(&pdev->dev, + &data->sysfs_attr[i].dev_attr)) + goto abituguru_probe_error; for (i = 0; i < ARRAY_SIZE(abituguru_sysfs_attr); i++) - device_create_file(&pdev->dev, - &abituguru_sysfs_attr[i].dev_attr); + if (device_create_file(&pdev->dev, + &abituguru_sysfs_attr[i].dev_attr)) + goto abituguru_probe_error; - return 0; + data->class_dev = hwmon_device_register(&pdev->dev); + if (!IS_ERR(data->class_dev)) + return 0; /* success */ + res = PTR_ERR(data->class_dev); abituguru_probe_error: + for (i = 0; data->sysfs_attr[i].dev_attr.attr.name; i++) + device_remove_file(&pdev->dev, &data->sysfs_attr[i].dev_attr); + for (i = 0; i < ARRAY_SIZE(abituguru_sysfs_attr); i++) + device_remove_file(&pdev->dev, + &abituguru_sysfs_attr[i].dev_attr); kfree(data); return res; } static int __devexit abituguru_remove(struct platform_device *pdev) { + int i; struct abituguru_data *data = platform_get_drvdata(pdev); platform_set_drvdata(pdev, NULL); hwmon_device_unregister(data->class_dev); + for (i = 0; data->sysfs_attr[i].dev_attr.attr.name; i++) + device_remove_file(&pdev->dev, &data->sysfs_attr[i].dev_attr); + for (i = 0; i < ARRAY_SIZE(abituguru_sysfs_attr); i++) + device_remove_file(&pdev->dev, + &abituguru_sysfs_attr[i].dev_attr); kfree(data); return 0; diff --git a/drivers/hwmon/adm1026.c b/drivers/hwmon/adm1026.c index b4618b2705f7..ba80cd3258c6 100644 --- a/drivers/hwmon/adm1026.c +++ b/drivers/hwmon/adm1026.c @@ -261,7 +261,6 @@ struct pwm_data { struct adm1026_data { struct i2c_client client; struct class_device *class_dev; - struct mutex lock; enum chips type; struct mutex update_lock; diff --git a/drivers/hwmon/adm1029.c b/drivers/hwmon/adm1029.c new file mode 100644 index 000000000000..73ce31b31511 --- /dev/null +++ b/drivers/hwmon/adm1029.c @@ -0,0 +1,508 @@ +/* + * adm1029.c - Part of lm_sensors, Linux kernel modules for hardware monitoring + * + * Copyright (C) 2006 Corentin LABBE <corentin.labbe@geomatys.fr> + * + * Based on LM83 Driver by Jean Delvare <khali@linux-fr.org> + * + * Give only processor, motherboard temperatures and fan tachs + * Very rare chip please let me know if you use it + * + * http://www.analog.com/UploadedFiles/Data_Sheets/ADM1029.pdf + * + * + * 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 version 2 of the License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/jiffies.h> +#include <linux/i2c.h> +#include <linux/hwmon-sysfs.h> +#include <linux/hwmon.h> +#include <linux/err.h> +#include <linux/mutex.h> + +/* + * Addresses to scan + */ + +static unsigned short normal_i2c[] = { + 0x28, 0x29, 0x2a, + 0x2b, 0x2c, 0x2d, + 0x2e, 0x2f, I2C_CLIENT_END +}; + +/* + * Insmod parameters + */ + +I2C_CLIENT_INSMOD_1(adm1029); + +/* + * The ADM1029 registers + * Manufacturer ID is 0x41 for Analog Devices + */ + +#define ADM1029_REG_MAN_ID 0x0D +#define ADM1029_REG_CHIP_ID 0x0E +#define ADM1029_REG_CONFIG 0x01 +#define ADM1029_REG_NB_FAN_SUPPORT 0x02 + +#define ADM1029_REG_TEMP_DEVICES_INSTALLED 0x06 + +#define ADM1029_REG_LOCAL_TEMP 0xA0 +#define ADM1029_REG_REMOTE1_TEMP 0xA1 +#define ADM1029_REG_REMOTE2_TEMP 0xA2 + +#define ADM1029_REG_LOCAL_TEMP_HIGH 0x90 +#define ADM1029_REG_REMOTE1_TEMP_HIGH 0x91 +#define ADM1029_REG_REMOTE2_TEMP_HIGH 0x92 + +#define ADM1029_REG_LOCAL_TEMP_LOW 0x98 +#define ADM1029_REG_REMOTE1_TEMP_LOW 0x99 +#define ADM1029_REG_REMOTE2_TEMP_LOW 0x9A + +#define ADM1029_REG_FAN1 0x70 +#define ADM1029_REG_FAN2 0x71 + +#define ADM1029_REG_FAN1_MIN 0x78 +#define ADM1029_REG_FAN2_MIN 0x79 + +#define ADM1029_REG_FAN1_CONFIG 0x68 +#define ADM1029_REG_FAN2_CONFIG 0x69 + +#define TEMP_FROM_REG(val) ((val) * 1000) + +#define DIV_FROM_REG(val) ( 1 << (((val) >> 6) - 1)) + +/* Registers to be checked by adm1029_update_device() */ +static const u8 ADM1029_REG_TEMP[] = { + ADM1029_REG_LOCAL_TEMP, + ADM1029_REG_REMOTE1_TEMP, + ADM1029_REG_REMOTE2_TEMP, + ADM1029_REG_LOCAL_TEMP_HIGH, + ADM1029_REG_REMOTE1_TEMP_HIGH, + ADM1029_REG_REMOTE2_TEMP_HIGH, + ADM1029_REG_LOCAL_TEMP_LOW, + ADM1029_REG_REMOTE1_TEMP_LOW, + ADM1029_REG_REMOTE2_TEMP_LOW, +}; + +static const u8 ADM1029_REG_FAN[] = { + ADM1029_REG_FAN1, + ADM1029_REG_FAN2, + ADM1029_REG_FAN1_MIN, + ADM1029_REG_FAN2_MIN, +}; + +static const u8 ADM1029_REG_FAN_DIV[] = { + ADM1029_REG_FAN1_CONFIG, + ADM1029_REG_FAN2_CONFIG, +}; + +/* + * Functions declaration + */ + +static int adm1029_attach_adapter(struct i2c_adapter *adapter); +static int adm1029_detect(struct i2c_adapter *adapter, int address, int kind); +static int adm1029_detach_client(struct i2c_client *client); +static struct adm1029_data *adm1029_update_device(struct device *dev); +static int adm1029_init_client(struct i2c_client *client); + +/* + * Driver data (common to all clients) + */ + +static struct i2c_driver adm1029_driver = { + .driver = { + .name = "adm1029", + }, + .attach_adapter = adm1029_attach_adapter, + .detach_client = adm1029_detach_client, +}; + +/* + * Client data (each client gets its own) + */ + +struct adm1029_data { + struct i2c_client client; + struct class_device *class_dev; + struct mutex update_lock; + char valid; /* zero until following fields are valid */ + unsigned long last_updated; /* in jiffies */ + + /* registers values, signed for temperature, unsigned for other stuff */ + s8 temp[ARRAY_SIZE(ADM1029_REG_TEMP)]; + u8 fan[ARRAY_SIZE(ADM1029_REG_FAN)]; + u8 fan_div[ARRAY_SIZE(ADM1029_REG_FAN_DIV)]; +}; + +/* + * Sysfs stuff + */ + +static ssize_t +show_temp(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct adm1029_data *data = adm1029_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[attr->index])); +} + +static ssize_t +show_fan(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct adm1029_data *data = adm1029_update_device(dev); + u16 val; + if (data->fan[attr->index] == 0 || data->fan_div[attr->index] == 0 + || data->fan[attr->index] == 255) { + return sprintf(buf, "0\n"); + } + + val = 1880 * 120 / DIV_FROM_REG(data->fan_div[attr->index]) + / data->fan[attr->index]; + return sprintf(buf, "%d\n", val); +} + +static ssize_t +show_fan_div(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct adm1029_data *data = adm1029_update_device(dev); + if (data->fan_div[attr->index] == 0) + return sprintf(buf, "0\n"); + return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[attr->index])); +} + +static ssize_t set_fan_div(struct device *dev, + struct device_attribute *devattr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm1029_data *data = i2c_get_clientdata(client); + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + long val = simple_strtol(buf, NULL, 10); + u8 reg; + + mutex_lock(&data->update_lock); + + /*Read actual config */ + reg = i2c_smbus_read_byte_data(client, + ADM1029_REG_FAN_DIV[attr->index]); + + switch (val) { + case 1: + val = 1; + break; + case 2: + val = 2; + break; + case 4: + val = 3; + break; + default: + mutex_unlock(&data->update_lock); + dev_err(&client->dev, "fan_div value %ld not " + "supported. Choose one of 1, 2 or 4!\n", val); + return -EINVAL; + } + /* Update the value */ + reg = (reg & 0x3F) | (val << 6); + + /* Write value */ + i2c_smbus_write_byte_data(client, + ADM1029_REG_FAN_DIV[attr->index], reg); + mutex_unlock(&data->update_lock); + + return count; +} + +/* +Access rights on sysfs, S_IRUGO stand for Is Readable by User, Group and Others + S_IWUSR stand for Is Writable by User +*/ +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0); +static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1); +static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2); + +static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, show_temp, NULL, 3); +static SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO, show_temp, NULL, 4); +static SENSOR_DEVICE_ATTR(temp3_max, S_IRUGO, show_temp, NULL, 5); + +static SENSOR_DEVICE_ATTR(temp1_min, S_IRUGO, show_temp, NULL, 6); +static SENSOR_DEVICE_ATTR(temp2_min, S_IRUGO, show_temp, NULL, 7); +static SENSOR_DEVICE_ATTR(temp3_min, S_IRUGO, show_temp, NULL, 8); + +static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0); +static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1); + +static SENSOR_DEVICE_ATTR(fan1_min, S_IRUGO, show_fan, NULL, 2); +static SENSOR_DEVICE_ATTR(fan2_min, S_IRUGO, show_fan, NULL, 3); + +static SENSOR_DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR, + show_fan_div, set_fan_div, 0); +static SENSOR_DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR, + show_fan_div, set_fan_div, 1); + +static struct attribute *adm1029_attributes[] = { + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp1_min.dev_attr.attr, + &sensor_dev_attr_temp1_max.dev_attr.attr, + &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp2_min.dev_attr.attr, + &sensor_dev_attr_temp2_max.dev_attr.attr, + &sensor_dev_attr_temp3_input.dev_attr.attr, + &sensor_dev_attr_temp3_min.dev_attr.attr, + &sensor_dev_attr_temp3_max.dev_attr.attr, + &sensor_dev_attr_fan1_input.dev_attr.attr, + &sensor_dev_attr_fan2_input.dev_attr.attr, + &sensor_dev_attr_fan1_min.dev_attr.attr, + &sensor_dev_attr_fan2_min.dev_attr.attr, + &sensor_dev_attr_fan1_div.dev_attr.attr, + &sensor_dev_attr_fan2_div.dev_attr.attr, + NULL +}; + +static const struct attribute_group adm1029_group = { + .attrs = adm1029_attributes, +}; + +/* + * Real code + */ + +static int adm1029_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_probe(adapter, &addr_data, adm1029_detect); +} + +/* + * The following function does more than just detection. If detection + * succeeds, it also registers the new chip. + */ + +static int adm1029_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *client; + struct adm1029_data *data; + int err = 0; + const char *name = ""; + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + goto exit; + + if (!(data = kzalloc(sizeof(struct adm1029_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + + client = &data->client; + i2c_set_clientdata(client, data); + client->addr = address; + client->adapter = adapter; + client->driver = &adm1029_driver; + + /* Now we do the detection and identification. A negative kind + * means that the driver was loaded with no force parameter + * (default), so we must both detect and identify the chip + * (actually there is only one possible kind of chip for now, adm1029). + * A zero kind means that the driver was loaded with the force + * parameter, the detection step shall be skipped. A positive kind + * means that the driver was loaded with the force parameter and a + * given kind of chip is requested, so both the detection and the + * identification steps are skipped. */ + + /* Default to an adm1029 if forced */ + if (kind == 0) + kind = adm1029; + + /* ADM1029 doesn't have CHIP ID, check just MAN ID + * For better detection we check also ADM1029_TEMP_DEVICES_INSTALLED, + * ADM1029_REG_NB_FAN_SUPPORT and compare it with possible values + * documented + */ + + if (kind <= 0) { /* identification */ + u8 man_id, chip_id, temp_devices_installed, nb_fan_support; + + man_id = i2c_smbus_read_byte_data(client, ADM1029_REG_MAN_ID); + chip_id = i2c_smbus_read_byte_data(client, ADM1029_REG_CHIP_ID); + temp_devices_installed = i2c_smbus_read_byte_data(client, + ADM1029_REG_TEMP_DEVICES_INSTALLED); + nb_fan_support = i2c_smbus_read_byte_data(client, + ADM1029_REG_NB_FAN_SUPPORT); + /* 0x41 is Analog Devices */ + if (man_id == 0x41 && (temp_devices_installed & 0xf9) == 0x01 + && nb_fan_support == 0x03) { + if ((chip_id & 0xF0) == 0x00) { + kind = adm1029; + } else { + /* There are no "official" CHIP ID, so actually + * we use Major/Minor revision for that */ + printk(KERN_INFO + "adm1029: Unknown major revision %x, " + "please let us know\n", chip_id); + } + } + + if (kind <= 0) { /* identification failed */ + pr_debug("adm1029: Unsupported chip (man_id=0x%02X, " + "chip_id=0x%02X)\n", man_id, chip_id); + goto exit_free; + } + } + + if (kind == adm1029) { + name = "adm1029"; + } + + /* We can fill in the remaining client fields */ + strlcpy(client->name, name, I2C_NAME_SIZE); + mutex_init(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(client))) + goto exit_free; + + /* + * Initialize the ADM1029 chip + * Check config register + */ + if (adm1029_init_client(client) == 0) + goto exit_detach; + + /* Register sysfs hooks */ + if ((err = sysfs_create_group(&client->dev.kobj, &adm1029_group))) + goto exit_detach; + + data->class_dev = hwmon_device_register(&client->dev); + if (IS_ERR(data->class_dev)) { + err = PTR_ERR(data->class_dev); + goto exit_remove_files; + } + + return 0; + + exit_remove_files: + sysfs_remove_group(&client->dev.kobj, &adm1029_group); + exit_detach: + i2c_detach_client(client); + exit_free: + kfree(data); + exit: + return err; +} + +static int adm1029_init_client(struct i2c_client *client) +{ + u8 config; + config = i2c_smbus_read_byte_data(client, ADM1029_REG_CONFIG); + if ((config & 0x10) == 0) { + i2c_smbus_write_byte_data(client, ADM1029_REG_CONFIG, + config | 0x10); + } + /* recheck config */ + config = i2c_smbus_read_byte_data(client, ADM1029_REG_CONFIG); + if ((config & 0x10) == 0) { + dev_err(&client->dev, "Initialization failed!\n"); + return 0; + } + return 1; +} + +static int adm1029_detach_client(struct i2c_client *client) +{ + struct adm1029_data *data = i2c_get_clientdata(client); + int err; + + hwmon_device_unregister(data->class_dev); + sysfs_remove_group(&client->dev.kobj, &adm1029_group); + + if ((err = i2c_detach_client(client))) + return err; + + kfree(data); + return 0; +} + +/* +function that update the status of the chips (temperature for exemple) +*/ +static struct adm1029_data *adm1029_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm1029_data *data = i2c_get_clientdata(client); + + mutex_lock(&data->update_lock); + /* + * Use the "cache" Luke, don't recheck values + * if there are already checked not a long time later + */ + if (time_after(jiffies, data->last_updated + HZ * 2) + || !data->valid) { + int nr; + + dev_dbg(&client->dev, "Updating adm1029 data\n"); + + for (nr = 0; nr < ARRAY_SIZE(ADM1029_REG_TEMP); nr++) { + data->temp[nr] = + i2c_smbus_read_byte_data(client, + ADM1029_REG_TEMP[nr]); + } + for (nr = 0; nr < ARRAY_SIZE(ADM1029_REG_FAN); nr++) { + data->fan[nr] = + i2c_smbus_read_byte_data(client, + ADM1029_REG_FAN[nr]); + } + for (nr = 0; nr < ARRAY_SIZE(ADM1029_REG_FAN_DIV); nr++) { + data->fan_div[nr] = + i2c_smbus_read_byte_data(client, + ADM1029_REG_FAN_DIV[nr]); + } + + data->last_updated = jiffies; + data->valid = 1; + } + + mutex_unlock(&data->update_lock); + + return data; +} + +/* + Common module stuff +*/ +static int __init sensors_adm1029_init(void) +{ + + return i2c_add_driver(&adm1029_driver); +} + +static void __exit sensors_adm1029_exit(void) +{ + + i2c_del_driver(&adm1029_driver); +} + +MODULE_AUTHOR("Corentin LABBE <corentin.labbe@geomatys.fr>"); +MODULE_DESCRIPTION("adm1029 driver"); +MODULE_LICENSE("GPL v2"); + +module_init(sensors_adm1029_init); +module_exit(sensors_adm1029_exit); diff --git a/drivers/hwmon/f71805f.c b/drivers/hwmon/f71805f.c index a272cae8f60e..7c2973487122 100644 --- a/drivers/hwmon/f71805f.c +++ b/drivers/hwmon/f71805f.c @@ -146,7 +146,6 @@ superio_exit(int base) struct f71805f_data { unsigned short addr; const char *name; - struct mutex lock; struct class_device *class_dev; struct mutex update_lock; @@ -271,50 +270,42 @@ static inline u8 temp_to_reg(long val) * Device I/O access */ +/* Must be called with data->update_lock held, except during initialization */ static u8 f71805f_read8(struct f71805f_data *data, u8 reg) { - u8 val; - - mutex_lock(&data->lock); outb(reg, data->addr + ADDR_REG_OFFSET); - val = inb(data->addr + DATA_REG_OFFSET); - mutex_unlock(&data->lock); - - return val; + return inb(data->addr + DATA_REG_OFFSET); } +/* Must be called with data->update_lock held, except during initialization */ static void f71805f_write8(struct f71805f_data *data, u8 reg, u8 val) { - mutex_lock(&data->lock); outb(reg, data->addr + ADDR_REG_OFFSET); outb(val, data->addr + DATA_REG_OFFSET); - mutex_unlock(&data->lock); } /* It is important to read the MSB first, because doing so latches the - value of the LSB, so we are sure both bytes belong to the same value. */ + value of the LSB, so we are sure both bytes belong to the same value. + Must be called with data->update_lock held, except during initialization */ static u16 f71805f_read16(struct f71805f_data *data, u8 reg) { u16 val; - mutex_lock(&data->lock); outb(reg, data->addr + ADDR_REG_OFFSET); val = inb(data->addr + DATA_REG_OFFSET) << 8; outb(++reg, data->addr + ADDR_REG_OFFSET); val |= inb(data->addr + DATA_REG_OFFSET); - mutex_unlock(&data->lock); return val; } +/* Must be called with data->update_lock held, except during initialization */ static void f71805f_write16(struct f71805f_data *data, u8 reg, u16 val) { - mutex_lock(&data->lock); outb(reg, data->addr + ADDR_REG_OFFSET); outb(val >> 8, data->addr + DATA_REG_OFFSET); outb(++reg, data->addr + ADDR_REG_OFFSET); outb(val & 0xff, data->addr + DATA_REG_OFFSET); - mutex_unlock(&data->lock); } static struct f71805f_data *f71805f_update_device(struct device *dev) @@ -1150,7 +1141,6 @@ static int __devinit f71805f_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_IO, 0); data->addr = res->start; - mutex_init(&data->lock); data->name = names[sio_data->kind]; mutex_init(&data->update_lock); @@ -1300,14 +1290,11 @@ static int __init f71805f_device_add(unsigned short address, if (err) { printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n", err); - goto exit_kfree_data; + goto exit_device_put; } return 0; -exit_kfree_data: - kfree(pdev->dev.platform_data); - pdev->dev.platform_data = NULL; exit_device_put: platform_device_put(pdev); exit: @@ -1400,10 +1387,7 @@ exit: static void __exit f71805f_exit(void) { - kfree(pdev->dev.platform_data); - pdev->dev.platform_data = NULL; platform_device_unregister(pdev); - platform_driver_unregister(&f71805f_driver); } diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c index 106fa01cdb60..affcc00764d3 100644 --- a/drivers/hwmon/hwmon.c +++ b/drivers/hwmon/hwmon.c @@ -101,7 +101,7 @@ static void __exit hwmon_exit(void) class_destroy(hwmon_class); } -module_init(hwmon_init); +subsys_initcall(hwmon_init); module_exit(hwmon_exit); EXPORT_SYMBOL_GPL(hwmon_device_register); diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index 1ed8b7e2c35d..62afc63708a5 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -202,15 +202,23 @@ static int DIV_TO_REG(int val) } #define DIV_FROM_REG(val) (1 << (val)) +static const unsigned int pwm_freq[8] = { + 48000000 / 128, + 24000000 / 128, + 12000000 / 128, + 8000000 / 128, + 6000000 / 128, + 3000000 / 128, + 1500000 / 128, + 750000 / 128, +}; + -/* For each registered IT87, we need to keep some data in memory. That - data is pointed to by it87_list[NR]->data. The structure itself is - dynamically allocated, at the same time when a new it87 client is - allocated. */ +/* For each registered chip, we need to keep some data in memory. + The structure is dynamically allocated. */ struct it87_data { struct i2c_client client; struct class_device *class_dev; - struct mutex lock; enum chips type; struct mutex update_lock; @@ -232,6 +240,7 @@ struct it87_data { u8 vrm; u32 alarms; /* Register encoding, combined */ u8 fan_main_ctrl; /* Register value */ + u8 fan_ctl; /* Register value */ u8 manual_pwm_ctl[3]; /* manual PWM value set by user */ }; @@ -519,6 +528,14 @@ static ssize_t show_pwm(struct device *dev, struct device_attribute *attr, struct it87_data *data = it87_update_device(dev); return sprintf(buf,"%d\n", data->manual_pwm_ctl[nr]); } +static ssize_t show_pwm_freq(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct it87_data *data = it87_update_device(dev); + int index = (data->fan_ctl >> 4) & 0x07; + + return sprintf(buf, "%u\n", pwm_freq[index]); +} static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { @@ -528,9 +545,10 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, struct i2c_client *client = to_i2c_client(dev); struct it87_data *data = i2c_get_clientdata(client); int val = simple_strtol(buf, NULL, 10); - u8 reg = it87_read_value(client, IT87_REG_FAN_DIV); + u8 reg; mutex_lock(&data->update_lock); + reg = it87_read_value(client, IT87_REG_FAN_DIV); switch (nr) { case 0: data->fan_div[nr] = reg & 0x07; break; case 1: data->fan_div[nr] = (reg >> 3) & 0x07; break; @@ -639,6 +657,28 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, mutex_unlock(&data->update_lock); return count; } +static ssize_t set_pwm_freq(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct it87_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + int i; + + /* Search for the nearest available frequency */ + for (i = 0; i < 7; i++) { + if (val > (pwm_freq[i] + pwm_freq[i+1]) / 2) + break; + } + + mutex_lock(&data->update_lock); + data->fan_ctl = it87_read_value(client, IT87_REG_FAN_CTL) & 0x8f; + data->fan_ctl |= i << 4; + it87_write_value(client, IT87_REG_FAN_CTL, data->fan_ctl); + mutex_unlock(&data->update_lock); + + return count; +} #define show_fan_offset(offset) \ static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, \ @@ -656,7 +696,10 @@ show_fan_offset(3); static SENSOR_DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR, \ show_pwm_enable, set_pwm_enable, offset - 1); \ static SENSOR_DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \ - show_pwm, set_pwm, offset - 1); + show_pwm, set_pwm, offset - 1); \ +static DEVICE_ATTR(pwm##offset##_freq, \ + (offset == 1 ? S_IRUGO | S_IWUSR : S_IRUGO), \ + show_pwm_freq, (offset == 1 ? set_pwm_freq : NULL)); show_pwm_offset(1); show_pwm_offset(2); @@ -904,7 +947,6 @@ static int it87_detect(struct i2c_adapter *adapter) } new_client = &data->client; - mutex_init(&data->lock); i2c_set_clientdata(new_client, data); new_client->addr = isa_address; new_client->adapter = adapter; @@ -1021,7 +1063,13 @@ static int it87_detect(struct i2c_adapter *adapter) || (err = device_create_file(&new_client->dev, &sensor_dev_attr_pwm2.dev_attr)) || (err = device_create_file(&new_client->dev, - &sensor_dev_attr_pwm3.dev_attr))) + &sensor_dev_attr_pwm3.dev_attr)) + || (err = device_create_file(&new_client->dev, + &dev_attr_pwm1_freq)) + || (err = device_create_file(&new_client->dev, + &dev_attr_pwm2_freq)) + || (err = device_create_file(&new_client->dev, + &dev_attr_pwm3_freq))) goto ERROR4; } @@ -1076,33 +1124,22 @@ static int it87_detach_client(struct i2c_client *client) return 0; } -/* ISA access must be locked explicitly! +/* Must be called with data->update_lock held, except during initialization. We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks, would slow down the IT87 access and should not be necessary. */ static int it87_read_value(struct i2c_client *client, u8 reg) { - struct it87_data *data = i2c_get_clientdata(client); - int res; - - mutex_lock(&data->lock); outb_p(reg, client->addr + IT87_ADDR_REG_OFFSET); - res = inb_p(client->addr + IT87_DATA_REG_OFFSET); - mutex_unlock(&data->lock); - - return res; + return inb_p(client->addr + IT87_DATA_REG_OFFSET); } -/* ISA access must be locked explicitly! +/* Must be called with data->update_lock held, except during initialization. We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks, would slow down the IT87 access and should not be necessary. */ static void it87_write_value(struct i2c_client *client, u8 reg, u8 value) { - struct it87_data *data = i2c_get_clientdata(client); - - mutex_lock(&data->lock); outb_p(reg, client->addr + IT87_ADDR_REG_OFFSET); outb_p(value, client->addr + IT87_DATA_REG_OFFSET); - mutex_unlock(&data->lock); } /* Return 1 if and only if the PWM interface is safe to use */ @@ -1316,6 +1353,7 @@ static struct it87_data *it87_update_device(struct device *dev) (it87_read_value(client, IT87_REG_ALARM2) << 8) | (it87_read_value(client, IT87_REG_ALARM3) << 16); data->fan_main_ctrl = it87_read_value(client, IT87_REG_FAN_MAIN_CTRL); + data->fan_ctl = it87_read_value(client, IT87_REG_FAN_CTL); data->sensor = it87_read_value(client, IT87_REG_TEMP_ENABLE); /* The 8705 does not have VID capability */ diff --git a/drivers/hwmon/lm70.c b/drivers/hwmon/lm70.c index 6ba84731b9cd..7eaae3834e15 100644 --- a/drivers/hwmon/lm70.c +++ b/drivers/hwmon/lm70.c @@ -126,7 +126,7 @@ out_dev_reg_failed: return status; } -static int __exit lm70_remove(struct spi_device *spi) +static int __devexit lm70_remove(struct spi_device *spi) { struct lm70 *p_lm70 = dev_get_drvdata(&spi->dev); diff --git a/drivers/hwmon/lm78.c b/drivers/hwmon/lm78.c index 73bc2ffc598d..886786c33916 100644 --- a/drivers/hwmon/lm78.c +++ b/drivers/hwmon/lm78.c @@ -125,10 +125,8 @@ static inline int TEMP_FROM_REG(s8 val) bad. Quite a lot of bookkeeping is done. A real driver can often cut some corners. */ -/* For each registered LM78, we need to keep some data in memory. That - data is pointed to by lm78_list[NR]->data. The structure itself is - dynamically allocated, at the same time when a new lm78 client is - allocated. */ +/* For each registered chip, we need to keep some data in memory. + The structure is dynamically allocated. */ struct lm78_data { struct i2c_client client; struct class_device *class_dev; diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c index 2c3293cf69d1..20a8c648280d 100644 --- a/drivers/hwmon/lm85.c +++ b/drivers/hwmon/lm85.c @@ -298,11 +298,6 @@ static int ZONE_TO_REG( int zone ) #define LM85_DATA_INTERVAL (HZ + HZ / 2) #define LM85_CONFIG_INTERVAL (1 * 60 * HZ) -/* For each registered LM85, we need to keep some data in memory. That - data is pointed to by lm85_list[NR]->data. The structure itself is - dynamically allocated, at the same time when a new lm85 client is - allocated. */ - /* LM85 can automatically adjust fan speeds based on temperature * This structure encapsulates an entire Zone config. There are * three zones (one for each temperature input) on the lm85 @@ -329,10 +324,11 @@ struct lm85_autofan { u8 min_off; /* Min PWM or OFF below "limit", flag */ }; +/* For each registered chip, we need to keep some data in memory. + The structure is dynamically allocated. */ struct lm85_data { struct i2c_client client; struct class_device *class_dev; - struct mutex lock; enum chips type; struct mutex update_lock; diff --git a/drivers/hwmon/sis5595.c b/drivers/hwmon/sis5595.c index 95a4b5d9eaf2..3f400263fc0f 100644 --- a/drivers/hwmon/sis5595.c +++ b/drivers/hwmon/sis5595.c @@ -162,10 +162,8 @@ static inline u8 DIV_TO_REG(int val) } #define DIV_FROM_REG(val) (1 << (val)) -/* For the SIS5595, we need to keep some data in memory. That - data is pointed to by sis5595_list[NR]->data. The structure itself is - dynamically allocated, at the time when the new sis5595 client is - allocated. */ +/* For each registered chip, we need to keep some data in memory. + The structure is dynamically allocated. */ struct sis5595_data { struct i2c_client client; struct class_device *class_dev; diff --git a/drivers/hwmon/via686a.c b/drivers/hwmon/via686a.c index f8acada0537a..9a440c8cc520 100644 --- a/drivers/hwmon/via686a.c +++ b/drivers/hwmon/via686a.c @@ -292,9 +292,8 @@ static inline long TEMP_FROM_REG10(u16 val) #define DIV_FROM_REG(val) (1 << (val)) #define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1) -/* For the VIA686A, we need to keep some data in memory. - The structure is dynamically allocated, at the same time when a new - via686a client is allocated. */ +/* For each registered chip, we need to keep some data in memory. + The structure is dynamically allocated. */ struct via686a_data { struct i2c_client client; struct class_device *class_dev; diff --git a/drivers/hwmon/vt1211.c b/drivers/hwmon/vt1211.c index 25cc56003d7a..89c23d6add7b 100644 --- a/drivers/hwmon/vt1211.c +++ b/drivers/hwmon/vt1211.c @@ -178,9 +178,10 @@ struct vt1211_data { * Super-I/O constants and functions * --------------------------------------------------------------------- */ -/* Configuration & data index port registers */ -#define SIO_REG_CIP 0x2e -#define SIO_REG_DIP 0x2f +/* Configuration index port registers + * The vt1211 can live at 2 different addresses so we need to probe both */ +#define SIO_REG_CIP1 0x2e +#define SIO_REG_CIP2 0x4e /* Configuration registers */ #define SIO_VT1211_LDN 0x07 /* logical device number */ @@ -193,33 +194,33 @@ struct vt1211_data { /* VT1211 logical device numbers */ #define SIO_VT1211_LDN_HWMON 0x0b /* HW monitor */ -static inline void superio_outb(int reg, int val) +static inline void superio_outb(int sio_cip, int reg, int val) { - outb(reg, SIO_REG_CIP); - outb(val, SIO_REG_DIP); + outb(reg, sio_cip); + outb(val, sio_cip + 1); } -static inline int superio_inb(int reg) +static inline int superio_inb(int sio_cip, int reg) { - outb(reg, SIO_REG_CIP); - return inb(SIO_REG_DIP); + outb(reg, sio_cip); + return inb(sio_cip + 1); } -static inline void superio_select(int ldn) +static inline void superio_select(int sio_cip, int ldn) { - outb(SIO_VT1211_LDN, SIO_REG_CIP); - outb(ldn, SIO_REG_DIP); + outb(SIO_VT1211_LDN, sio_cip); + outb(ldn, sio_cip + 1); } -static inline void superio_enter(void) +static inline void superio_enter(int sio_cip) { - outb(0x87, SIO_REG_CIP); - outb(0x87, SIO_REG_CIP); + outb(0x87, sio_cip); + outb(0x87, sio_cip); } -static inline void superio_exit(void) +static inline void superio_exit(int sio_cip) { - outb(0xaa, SIO_REG_CIP); + outb(0xaa, sio_cip); } /* --------------------------------------------------------------------- @@ -1263,26 +1264,26 @@ EXIT: return err; } -static int __init vt1211_find(unsigned short *address) +static int __init vt1211_find(int sio_cip, unsigned short *address) { int err = -ENODEV; - superio_enter(); + superio_enter(sio_cip); - if (superio_inb(SIO_VT1211_DEVID) != SIO_VT1211_ID) { + if (superio_inb(sio_cip, SIO_VT1211_DEVID) != SIO_VT1211_ID) { goto EXIT; } - superio_select(SIO_VT1211_LDN_HWMON); + superio_select(sio_cip, SIO_VT1211_LDN_HWMON); - if ((superio_inb(SIO_VT1211_ACTIVE) & 1) == 0) { + if ((superio_inb(sio_cip, SIO_VT1211_ACTIVE) & 1) == 0) { printk(KERN_WARNING DRVNAME ": HW monitor is disabled, " "skipping\n"); goto EXIT; } - *address = ((superio_inb(SIO_VT1211_BADDR) << 8) | - (superio_inb(SIO_VT1211_BADDR + 1))) & 0xff00; + *address = ((superio_inb(sio_cip, SIO_VT1211_BADDR) << 8) | + (superio_inb(sio_cip, SIO_VT1211_BADDR + 1))) & 0xff00; if (*address == 0) { printk(KERN_WARNING DRVNAME ": Base address is not set, " "skipping\n"); @@ -1291,10 +1292,11 @@ static int __init vt1211_find(unsigned short *address) err = 0; printk(KERN_INFO DRVNAME ": Found VT1211 chip at 0x%04x, " - "revision %u\n", *address, superio_inb(SIO_VT1211_DEVREV)); + "revision %u\n", *address, + superio_inb(sio_cip, SIO_VT1211_DEVREV)); EXIT: - superio_exit(); + superio_exit(sio_cip); return err; } @@ -1303,8 +1305,8 @@ static int __init vt1211_init(void) int err; unsigned short address = 0; - err = vt1211_find(&address); - if (err) { + if ((err = vt1211_find(SIO_REG_CIP1, &address)) && + (err = vt1211_find(SIO_REG_CIP2, &address))) { goto EXIT; } diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c index 212a1558c63b..da5828f2dfc2 100644 --- a/drivers/hwmon/w83627ehf.c +++ b/drivers/hwmon/w83627ehf.c @@ -32,8 +32,10 @@ Supports the following chips: - Chip #vin #fan #pwm #temp chip_id man_id - w83627ehf 10 5 4 3 0x88,0xa1 0x5ca3 + Chip #vin #fan #pwm #temp chip IDs man ID + w83627ehf 10 5 4 3 0x8850 0x88 0x5ca3 + 0x8860 0xa1 + w83627dhg 9 5 4 3 0xa020 0xc1 0x5ca3 */ #include <linux/module.h> @@ -55,8 +57,18 @@ static unsigned short address; * Super-I/O constants and functions */ +/* + * The three following globals are initialized in w83627ehf_find(), before + * the i2c-isa device is created. Otherwise, they could be stored in + * w83627ehf_data. This is ugly, but necessary, and when the driver is next + * updated to become a platform driver, the globals will disappear. + */ static int REG; /* The register to read/write */ static int VAL; /* The value to read/write */ +/* The w83627ehf/ehg have 10 voltage inputs, but the w83627dhg has 9. This + * value is also used in w83627ehf_detect() to export a device name in sysfs + * (e.g. w83627ehf or w83627dhg) */ +static int w83627ehf_num_in; #define W83627EHF_LD_HWM 0x0b @@ -65,8 +77,10 @@ static int VAL; /* The value to read/write */ #define SIO_REG_ENABLE 0x30 /* Logical device enable */ #define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */ -#define SIO_W83627EHF_ID 0x8840 -#define SIO_ID_MASK 0xFFC0 +#define SIO_W83627EHF_ID 0x8850 +#define SIO_W83627EHG_ID 0x8860 +#define SIO_W83627DHG_ID 0xa020 +#define SIO_ID_MASK 0xFFF0 static inline void superio_outb(int reg, int val) @@ -115,8 +129,12 @@ superio_exit(void) #define W83627EHF_REG_BANK 0x4E #define W83627EHF_REG_CONFIG 0x40 -#define W83627EHF_REG_CHIP_ID 0x49 -#define W83627EHF_REG_MAN_ID 0x4F + +/* Not currently used: + * REG_MAN_ID has the value 0x5ca3 for all supported chips. + * REG_CHIP_ID == 0x88/0xa1/0xc1 depending on chip model. + * REG_MAN_ID is at port 0x4f + * REG_CHIP_ID is at port 0x58 */ static const u16 W83627EHF_REG_FAN[] = { 0x28, 0x29, 0x2a, 0x3f, 0x553 }; static const u16 W83627EHF_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d, 0x3e, 0x55c }; @@ -429,7 +447,7 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev) } /* Measured voltages and limits */ - for (i = 0; i < 10; i++) { + for (i = 0; i < w83627ehf_num_in; i++) { data->in[i] = w83627ehf_read_value(client, W83627EHF_REG_IN(i)); data->in_min[i] = w83627ehf_read_value(client, @@ -1121,7 +1139,7 @@ static void w83627ehf_device_remove_files(struct device *dev) device_remove_file(dev, &sda_sf3_arrays[i].dev_attr); for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++) device_remove_file(dev, &sda_sf3_arrays_fan4[i].dev_attr); - for (i = 0; i < 10; i++) { + for (i = 0; i < w83627ehf_num_in; i++) { device_remove_file(dev, &sda_in_input[i].dev_attr); device_remove_file(dev, &sda_in_alarm[i].dev_attr); device_remove_file(dev, &sda_in_min[i].dev_attr); @@ -1196,7 +1214,11 @@ static int w83627ehf_detect(struct i2c_adapter *adapter) client->flags = 0; dev = &client->dev; - strlcpy(client->name, "w83627ehf", I2C_NAME_SIZE); + if (w83627ehf_num_in == 9) + strlcpy(client->name, "w83627dhg", I2C_NAME_SIZE); + else /* just say ehf. 627EHG is 627EHF in lead-free packaging. */ + strlcpy(client->name, "w83627ehf", I2C_NAME_SIZE); + data->valid = 0; mutex_init(&data->update_lock); @@ -1246,7 +1268,7 @@ static int w83627ehf_detect(struct i2c_adapter *adapter) goto exit_remove; } - for (i = 0; i < 10; i++) + for (i = 0; i < w83627ehf_num_in; i++) if ((err = device_create_file(dev, &sda_in_input[i].dev_attr)) || (err = device_create_file(dev, &sda_in_alarm[i].dev_attr)) @@ -1340,7 +1362,17 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr) val = (superio_inb(SIO_REG_DEVID) << 8) | superio_inb(SIO_REG_DEVID + 1); - if ((val & SIO_ID_MASK) != SIO_W83627EHF_ID) { + switch (val & SIO_ID_MASK) { + case SIO_W83627DHG_ID: + w83627ehf_num_in = 9; + break; + case SIO_W83627EHF_ID: + case SIO_W83627EHG_ID: + w83627ehf_num_in = 10; + break; + default: + printk(KERN_WARNING "w83627ehf: unsupported chip ID: 0x%04x\n", + val); superio_exit(); return -ENODEV; } diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c index dfdc29c77123..d7e240635b3b 100644 --- a/drivers/hwmon/w83627hf.c +++ b/drivers/hwmon/w83627hf.c @@ -286,9 +286,8 @@ static inline u8 DIV_TO_REG(long val) return ((u8) i); } -/* For each registered chip, we need to keep some data in memory. That - data is pointed to by w83627hf_list[NR]->data. The structure itself is - dynamically allocated, at the same time when a new client is allocated. */ +/* For each registered chip, we need to keep some data in memory. + The structure is dynamically allocated. */ struct w83627hf_data { struct i2c_client client; struct class_device *class_dev; diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c index 1232171c3aad..a47da3ec5472 100644 --- a/drivers/hwmon/w83781d.c +++ b/drivers/hwmon/w83781d.c @@ -221,14 +221,8 @@ DIV_TO_REG(long val, enum chips type) a bit - except if there could be more than one SMBus. Groan. No solution for this yet. */ -/* This module may seem overly long and complicated. In fact, it is not so - bad. Quite a lot of bookkeeping is done. A real driver can often cut - some corners. */ - -/* For each registered W83781D, we need to keep some data in memory. That - data is pointed to by w83781d_list[NR]->data. The structure itself is - dynamically allocated, at the same time when a new w83781d client is - allocated. */ +/* For each registered chip, we need to keep some data in memory. + The structure is dynamically allocated. */ struct w83781d_data { struct i2c_client client; struct class_device *class_dev; diff --git a/drivers/i2c/busses/i2c-ali1535.c b/drivers/i2c/busses/i2c-ali1535.c index 6fd8ad7faa06..1e277ba5a9f3 100644 --- a/drivers/i2c/busses/i2c-ali1535.c +++ b/drivers/i2c/busses/i2c-ali1535.c @@ -494,7 +494,7 @@ static int __devinit ali1535_probe(struct pci_dev *dev, const struct pci_device_ return -ENODEV; } - /* set up the driverfs linkage to our parent device */ + /* set up the sysfs linkage to our parent device */ ali1535_adapter.dev.parent = &dev->dev; snprintf(ali1535_adapter.name, I2C_NAME_SIZE, diff --git a/drivers/i2c/busses/i2c-ali15x3.c b/drivers/i2c/busses/i2c-ali15x3.c index e4e0df106812..e47fe01bf42a 100644 --- a/drivers/i2c/busses/i2c-ali15x3.c +++ b/drivers/i2c/busses/i2c-ali15x3.c @@ -489,7 +489,7 @@ static int __devinit ali15x3_probe(struct pci_dev *dev, const struct pci_device_ return -ENODEV; } - /* set up the driverfs linkage to our parent device */ + /* set up the sysfs linkage to our parent device */ ali15x3_adapter.dev.parent = &dev->dev; snprintf(ali15x3_adapter.name, I2C_NAME_SIZE, diff --git a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c index fa6155a54cc3..7490dc1771ae 100644 --- a/drivers/i2c/busses/i2c-amd756.c +++ b/drivers/i2c/busses/i2c-amd756.c @@ -374,7 +374,7 @@ static int __devinit amd756_probe(struct pci_dev *pdev, dev_dbg(&pdev->dev, "SMBREV = 0x%X\n", temp); dev_dbg(&pdev->dev, "AMD756_smba = 0x%X\n", amd756_ioport); - /* set up the driverfs linkage to our parent device */ + /* set up the sysfs linkage to our parent device */ amd756_smbus.dev.parent = &pdev->dev; sprintf(amd756_smbus.name, "SMBus %s adapter at %04x", diff --git a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c index 5bba3fb50d71..e15f9e37716a 100644 --- a/drivers/i2c/busses/i2c-amd8111.c +++ b/drivers/i2c/busses/i2c-amd8111.c @@ -371,7 +371,7 @@ static int __devinit amd8111_probe(struct pci_dev *dev, smbus->adapter.algo = &smbus_algorithm; smbus->adapter.algo_data = smbus; - /* set up the driverfs linkage to our parent device */ + /* set up the sysfs linkage to our parent device */ smbus->adapter.dev.parent = &dev->dev; pci_write_config_dword(smbus->dev, AMD_PCI_MISC, 0); diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 21f2671f7220..6569a36985bd 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -522,7 +522,7 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id else dev_dbg(&dev->dev, "SMBus using PCI Interrupt\n"); - /* set up the driverfs linkage to our parent device */ + /* set up the sysfs linkage to our parent device */ i801_adapter.dev.parent = &dev->dev; snprintf(i801_adapter.name, I2C_NAME_SIZE, diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c index 20ee4f7c53a0..90e2d9350c1b 100644 --- a/drivers/i2c/busses/i2c-iop3xx.c +++ b/drivers/i2c/busses/i2c-iop3xx.c @@ -83,7 +83,7 @@ iop3xx_i2c_enable(struct i2c_algo_iop3xx_data *iop3xx_adap) * Every time unit enable is asserted, GPOD needs to be cleared * on IOP3XX to avoid data corruption on the bus. */ -#ifdef CONFIG_PLAT_IOP +#if defined(CONFIG_ARCH_IOP32X) || defined(CONFIG_ARCH_IOP33X) if (iop3xx_adap->id == 0) { gpio_line_set(IOP3XX_GPIO_LINE(7), GPIO_LOW); gpio_line_set(IOP3XX_GPIO_LINE(6), GPIO_LOW); diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c index d888293c1a9c..21b180904085 100644 --- a/drivers/i2c/busses/i2c-piix4.c +++ b/drivers/i2c/busses/i2c-piix4.c @@ -425,7 +425,7 @@ static int __devinit piix4_probe(struct pci_dev *dev, if (retval) return retval; - /* set up the driverfs linkage to our parent device */ + /* set up the sysfs linkage to our parent device */ piix4_adapter.dev.parent = &dev->dev; snprintf(piix4_adapter.name, I2C_NAME_SIZE, diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index c3b1567c852a..14e83d0aac8c 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -34,6 +34,7 @@ #include <asm/hardware.h> #include <asm/irq.h> +#include <asm/io.h> #include <asm/arch/i2c.h> #include <asm/arch/pxa-regs.h> @@ -54,8 +55,21 @@ struct pxa_i2c { unsigned int irqlogidx; u32 isrlog[32]; u32 icrlog[32]; + + void __iomem *reg_base; + + unsigned long iobase; + unsigned long iosize; + + int irq; }; +#define _IBMR(i2c) ((i2c)->reg_base + 0) +#define _IDBR(i2c) ((i2c)->reg_base + 8) +#define _ICR(i2c) ((i2c)->reg_base + 0x10) +#define _ISR(i2c) ((i2c)->reg_base + 0x18) +#define _ISAR(i2c) ((i2c)->reg_base + 0x20) + /* * I2C Slave mode address */ @@ -130,7 +144,8 @@ static unsigned int i2c_debug = DEBUG; static void i2c_pxa_show_state(struct pxa_i2c *i2c, int lno, const char *fname) { - dev_dbg(&i2c->adap.dev, "state:%s:%d: ISR=%08x, ICR=%08x, IBMR=%02x\n", fname, lno, ISR, ICR, IBMR); + dev_dbg(&i2c->adap.dev, "state:%s:%d: ISR=%08x, ICR=%08x, IBMR=%02x\n", fname, lno, + readl(_ISR(i2c)), readl(_ICR(i2c)), readl(_IBMR(i2c))); } #define show_state(i2c) i2c_pxa_show_state(i2c, __LINE__, __FUNCTION__) @@ -153,7 +168,7 @@ static void i2c_pxa_scream_blue_murder(struct pxa_i2c *i2c, const char *why) printk("i2c: msg_num: %d msg_idx: %d msg_ptr: %d\n", i2c->msg_num, i2c->msg_idx, i2c->msg_ptr); printk("i2c: ICR: %08x ISR: %08x\n" - "i2c: log: ", ICR, ISR); + "i2c: log: ", readl(_ICR(i2c)), readl(_ISR(i2c))); for (i = 0; i < i2c->irqlogidx; i++) printk("[%08x:%08x] ", i2c->isrlog[i], i2c->icrlog[i]); printk("\n"); @@ -161,7 +176,7 @@ static void i2c_pxa_scream_blue_murder(struct pxa_i2c *i2c, const char *why) static inline int i2c_pxa_is_slavemode(struct pxa_i2c *i2c) { - return !(ICR & ICR_SCLE); + return !(readl(_ICR(i2c)) & ICR_SCLE); } static void i2c_pxa_abort(struct pxa_i2c *i2c) @@ -173,28 +188,29 @@ static void i2c_pxa_abort(struct pxa_i2c *i2c) return; } - while (time_before(jiffies, timeout) && (IBMR & 0x1) == 0) { - unsigned long icr = ICR; + while (time_before(jiffies, timeout) && (readl(_IBMR(i2c)) & 0x1) == 0) { + unsigned long icr = readl(_ICR(i2c)); icr &= ~ICR_START; icr |= ICR_ACKNAK | ICR_STOP | ICR_TB; - ICR = icr; + writel(icr, _ICR(i2c)); show_state(i2c); msleep(1); } - ICR &= ~(ICR_MA | ICR_START | ICR_STOP); + writel(readl(_ICR(i2c)) & ~(ICR_MA | ICR_START | ICR_STOP), + _ICR(i2c)); } static int i2c_pxa_wait_bus_not_busy(struct pxa_i2c *i2c) { int timeout = DEF_TIMEOUT; - while (timeout-- && ISR & (ISR_IBB | ISR_UB)) { - if ((ISR & ISR_SAD) != 0) + while (timeout-- && readl(_ISR(i2c)) & (ISR_IBB | ISR_UB)) { + if ((readl(_ISR(i2c)) & ISR_SAD) != 0) timeout += 4; msleep(2); @@ -214,9 +230,9 @@ static int i2c_pxa_wait_master(struct pxa_i2c *i2c) while (time_before(jiffies, timeout)) { if (i2c_debug > 1) dev_dbg(&i2c->adap.dev, "%s: %ld: ISR=%08x, ICR=%08x, IBMR=%02x\n", - __func__, (long)jiffies, ISR, ICR, IBMR); + __func__, (long)jiffies, readl(_ISR(i2c)), readl(_ICR(i2c)), readl(_IBMR(i2c))); - if (ISR & ISR_SAD) { + if (readl(_ISR(i2c)) & ISR_SAD) { if (i2c_debug > 0) dev_dbg(&i2c->adap.dev, "%s: Slave detected\n", __func__); goto out; @@ -226,7 +242,7 @@ static int i2c_pxa_wait_master(struct pxa_i2c *i2c) * quick check of the i2c lines themselves to ensure they've * gone high... */ - if ((ISR & (ISR_UB | ISR_IBB)) == 0 && IBMR == 3) { + if ((readl(_ISR(i2c)) & (ISR_UB | ISR_IBB)) == 0 && readl(_IBMR(i2c)) == 3) { if (i2c_debug > 0) dev_dbg(&i2c->adap.dev, "%s: done\n", __func__); return 1; @@ -246,7 +262,7 @@ static int i2c_pxa_set_master(struct pxa_i2c *i2c) if (i2c_debug) dev_dbg(&i2c->adap.dev, "setting to bus master\n"); - if ((ISR & (ISR_UB | ISR_IBB)) != 0) { + if ((readl(_ISR(i2c)) & (ISR_UB | ISR_IBB)) != 0) { dev_dbg(&i2c->adap.dev, "%s: unit is busy\n", __func__); if (!i2c_pxa_wait_master(i2c)) { dev_dbg(&i2c->adap.dev, "%s: error: unit busy\n", __func__); @@ -254,7 +270,7 @@ static int i2c_pxa_set_master(struct pxa_i2c *i2c) } } - ICR |= ICR_SCLE; + writel(readl(_ICR(i2c)) | ICR_SCLE, _ICR(i2c)); return 0; } @@ -270,11 +286,11 @@ static int i2c_pxa_wait_slave(struct pxa_i2c *i2c) while (time_before(jiffies, timeout)) { if (i2c_debug > 1) dev_dbg(&i2c->adap.dev, "%s: %ld: ISR=%08x, ICR=%08x, IBMR=%02x\n", - __func__, (long)jiffies, ISR, ICR, IBMR); + __func__, (long)jiffies, readl(_ISR(i2c)), readl(_ICR(i2c)), readl(_IBMR(i2c))); - if ((ISR & (ISR_UB|ISR_IBB)) == 0 || - (ISR & ISR_SAD) != 0 || - (ICR & ICR_SCLE) == 0) { + if ((readl(_ISR(i2c)) & (ISR_UB|ISR_IBB)) == 0 || + (readl(_ISR(i2c)) & ISR_SAD) != 0 || + (readl(_ICR(i2c)) & ICR_SCLE) == 0) { if (i2c_debug > 1) dev_dbg(&i2c->adap.dev, "%s: done\n", __func__); return 1; @@ -302,9 +318,9 @@ static void i2c_pxa_set_slave(struct pxa_i2c *i2c, int errcode) /* we need to wait for the stop condition to end */ /* if we where in stop, then clear... */ - if (ICR & ICR_STOP) { + if (readl(_ICR(i2c)) & ICR_STOP) { udelay(100); - ICR &= ~ICR_STOP; + writel(readl(_ICR(i2c)) & ~ICR_STOP, _ICR(i2c)); } if (!i2c_pxa_wait_slave(i2c)) { @@ -314,12 +330,12 @@ static void i2c_pxa_set_slave(struct pxa_i2c *i2c, int errcode) } } - ICR &= ~(ICR_STOP|ICR_ACKNAK|ICR_MA); - ICR &= ~ICR_SCLE; + writel(readl(_ICR(i2c)) & ~(ICR_STOP|ICR_ACKNAK|ICR_MA), _ICR(i2c)); + writel(readl(_ICR(i2c)) & ~ICR_SCLE, _ICR(i2c)); if (i2c_debug) { - dev_dbg(&i2c->adap.dev, "ICR now %08x, ISR %08x\n", ICR, ISR); - decode_ICR(ICR); + dev_dbg(&i2c->adap.dev, "ICR now %08x, ISR %08x\n", readl(_ICR(i2c)), readl(_ISR(i2c))); + decode_ICR(readl(_ICR(i2c))); } } #else @@ -334,24 +350,24 @@ static void i2c_pxa_reset(struct pxa_i2c *i2c) i2c_pxa_abort(i2c); /* reset according to 9.8 */ - ICR = ICR_UR; - ISR = I2C_ISR_INIT; - ICR &= ~ICR_UR; + writel(ICR_UR, _ICR(i2c)); + writel(I2C_ISR_INIT, _ISR(i2c)); + writel(readl(_ICR(i2c)) & ~ICR_UR, _ICR(i2c)); - ISAR = i2c->slave_addr; + writel(i2c->slave_addr, _ISAR(i2c)); /* set control register values */ - ICR = I2C_ICR_INIT; + writel(I2C_ICR_INIT, _ICR(i2c)); #ifdef CONFIG_I2C_PXA_SLAVE dev_info(&i2c->adap.dev, "Enabling slave mode\n"); - ICR |= ICR_SADIE | ICR_ALDIE | ICR_SSDIE; + writel(readl(_ICR(i2c)) | ICR_SADIE | ICR_ALDIE | ICR_SSDIE, _ICR(i2c)); #endif i2c_pxa_set_slave(i2c, 0); /* enable unit */ - ICR |= ICR_IUE; + writel(readl(_ICR(i2c)) | ICR_IUE, _ICR(i2c)); udelay(100); } @@ -371,19 +387,19 @@ static void i2c_pxa_slave_txempty(struct pxa_i2c *i2c, u32 isr) if (i2c->slave != NULL) ret = i2c->slave->read(i2c->slave->data); - IDBR = ret; - ICR |= ICR_TB; /* allow next byte */ + writel(ret, _IDBR(i2c)); + writel(readl(_ICR(i2c)) | ICR_TB, _ICR(i2c)); /* allow next byte */ } } static void i2c_pxa_slave_rxfull(struct pxa_i2c *i2c, u32 isr) { - unsigned int byte = IDBR; + unsigned int byte = readl(_IDBR(i2c)); if (i2c->slave != NULL) i2c->slave->write(i2c->slave->data, byte); - ICR |= ICR_TB; + writel(readl(_ICR(i2c)) | ICR_TB, _ICR(i2c)); } static void i2c_pxa_slave_start(struct pxa_i2c *i2c, u32 isr) @@ -403,13 +419,13 @@ static void i2c_pxa_slave_start(struct pxa_i2c *i2c, u32 isr) * start condition... if this happens, we'd better back off * and stop holding the poor thing up */ - ICR &= ~(ICR_START|ICR_STOP); - ICR |= ICR_TB; + writel(readl(_ICR(i2c)) & ~(ICR_START|ICR_STOP), _ICR(i2c)); + writel(readl(_ICR(i2c)) | ICR_TB, _ICR(i2c)); timeout = 0x10000; while (1) { - if ((IBMR & 2) == 2) + if ((readl(_IBMR(i2c)) & 2) == 2) break; timeout--; @@ -420,7 +436,7 @@ static void i2c_pxa_slave_start(struct pxa_i2c *i2c, u32 isr) } } - ICR &= ~ICR_SCLE; + writel(readl(_ICR(i2c)) & ~ICR_SCLE, _ICR(i2c)); } static void i2c_pxa_slave_stop(struct pxa_i2c *i2c) @@ -447,14 +463,14 @@ static void i2c_pxa_slave_txempty(struct pxa_i2c *i2c, u32 isr) if (isr & ISR_BED) { /* what should we do here? */ } else { - IDBR = 0; - ICR |= ICR_TB; + writel(0, _IDBR(i2c)); + writel(readl(_ICR(i2c)) | ICR_TB, _ICR(i2c)); } } static void i2c_pxa_slave_rxfull(struct pxa_i2c *i2c, u32 isr) { - ICR |= ICR_TB | ICR_ACKNAK; + writel(readl(_ICR(i2c)) | ICR_TB | ICR_ACKNAK, _ICR(i2c)); } static void i2c_pxa_slave_start(struct pxa_i2c *i2c, u32 isr) @@ -466,13 +482,13 @@ static void i2c_pxa_slave_start(struct pxa_i2c *i2c, u32 isr) * start condition... if this happens, we'd better back off * and stop holding the poor thing up */ - ICR &= ~(ICR_START|ICR_STOP); - ICR |= ICR_TB | ICR_ACKNAK; + writel(readl(_ICR(i2c)) & ~(ICR_START|ICR_STOP), _ICR(i2c)); + writel(readl(_ICR(i2c)) | ICR_TB | ICR_ACKNAK, _ICR(i2c)); timeout = 0x10000; while (1) { - if ((IBMR & 2) == 2) + if ((readl(_IBMR(i2c)) & 2) == 2) break; timeout--; @@ -483,7 +499,7 @@ static void i2c_pxa_slave_start(struct pxa_i2c *i2c, u32 isr) } } - ICR &= ~ICR_SCLE; + writel(readl(_ICR(i2c)) & ~ICR_SCLE, _ICR(i2c)); } static void i2c_pxa_slave_stop(struct pxa_i2c *i2c) @@ -514,13 +530,13 @@ static inline void i2c_pxa_start_message(struct pxa_i2c *i2c) /* * Step 1: target slave address into IDBR */ - IDBR = i2c_pxa_addr_byte(i2c->msg); + writel(i2c_pxa_addr_byte(i2c->msg), _IDBR(i2c)); /* * Step 2: initiate the write. */ - icr = ICR & ~(ICR_STOP | ICR_ALDIE); - ICR = icr | ICR_START | ICR_TB; + icr = readl(_ICR(i2c)) & ~(ICR_STOP | ICR_ALDIE); + writel(icr | ICR_START | ICR_TB, _ICR(i2c)); } /* @@ -594,7 +610,7 @@ static void i2c_pxa_master_complete(struct pxa_i2c *i2c, int ret) static void i2c_pxa_irq_txempty(struct pxa_i2c *i2c, u32 isr) { - u32 icr = ICR & ~(ICR_START|ICR_STOP|ICR_ACKNAK|ICR_TB); + u32 icr = readl(_ICR(i2c)) & ~(ICR_START|ICR_STOP|ICR_ACKNAK|ICR_TB); again: /* @@ -645,7 +661,7 @@ static void i2c_pxa_irq_txempty(struct pxa_i2c *i2c, u32 isr) /* * Write mode. Write the next data byte. */ - IDBR = i2c->msg->buf[i2c->msg_ptr++]; + writel(i2c->msg->buf[i2c->msg_ptr++], _IDBR(i2c)); icr |= ICR_ALDIE | ICR_TB; @@ -675,7 +691,7 @@ static void i2c_pxa_irq_txempty(struct pxa_i2c *i2c, u32 isr) /* * Write the next address. */ - IDBR = i2c_pxa_addr_byte(i2c->msg); + writel(i2c_pxa_addr_byte(i2c->msg), _IDBR(i2c)); /* * And trigger a repeated start, and send the byte. @@ -696,18 +712,18 @@ static void i2c_pxa_irq_txempty(struct pxa_i2c *i2c, u32 isr) i2c->icrlog[i2c->irqlogidx-1] = icr; - ICR = icr; + writel(icr, _ICR(i2c)); show_state(i2c); } static void i2c_pxa_irq_rxfull(struct pxa_i2c *i2c, u32 isr) { - u32 icr = ICR & ~(ICR_START|ICR_STOP|ICR_ACKNAK|ICR_TB); + u32 icr = readl(_ICR(i2c)) & ~(ICR_START|ICR_STOP|ICR_ACKNAK|ICR_TB); /* * Read the byte. */ - i2c->msg->buf[i2c->msg_ptr++] = IDBR; + i2c->msg->buf[i2c->msg_ptr++] = readl(_IDBR(i2c)); if (i2c->msg_ptr < i2c->msg->len) { /* @@ -724,17 +740,17 @@ static void i2c_pxa_irq_rxfull(struct pxa_i2c *i2c, u32 isr) i2c->icrlog[i2c->irqlogidx-1] = icr; - ICR = icr; + writel(icr, _ICR(i2c)); } static irqreturn_t i2c_pxa_handler(int this_irq, void *dev_id) { struct pxa_i2c *i2c = dev_id; - u32 isr = ISR; + u32 isr = readl(_ISR(i2c)); if (i2c_debug > 2 && 0) { dev_dbg(&i2c->adap.dev, "%s: ISR=%08x, ICR=%08x, IBMR=%02x\n", - __func__, isr, ICR, IBMR); + __func__, isr, readl(_ICR(i2c)), readl(_IBMR(i2c))); decode_ISR(isr); } @@ -746,7 +762,7 @@ static irqreturn_t i2c_pxa_handler(int this_irq, void *dev_id) /* * Always clear all pending IRQs. */ - ISR = isr & (ISR_SSD|ISR_ALD|ISR_ITE|ISR_IRF|ISR_SAD|ISR_BED); + writel(isr & (ISR_SSD|ISR_ALD|ISR_ITE|ISR_IRF|ISR_SAD|ISR_BED), _ISR(i2c)); if (isr & ISR_SAD) i2c_pxa_slave_start(i2c, isr); @@ -779,7 +795,7 @@ static int i2c_pxa_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num /* If the I2C controller is disabled we need to reset it (probably due to a suspend/resume destroying state). We do this here as we can then avoid worrying about resuming the controller before its users. */ - if (!(ICR & ICR_IUE)) + if (!(readl(_ICR(i2c)) & ICR_IUE)) i2c_pxa_reset(i2c); for (i = adap->retries; i >= 0; i--) { @@ -810,28 +826,53 @@ static const struct i2c_algorithm i2c_pxa_algorithm = { static struct pxa_i2c i2c_pxa = { .lock = SPIN_LOCK_UNLOCKED, - .wait = __WAIT_QUEUE_HEAD_INITIALIZER(i2c_pxa.wait), .adap = { .owner = THIS_MODULE, .algo = &i2c_pxa_algorithm, - .name = "pxa2xx-i2c", + .name = "pxa2xx-i2c.0", .retries = 5, }, }; +#define res_len(r) ((r)->end - (r)->start + 1) static int i2c_pxa_probe(struct platform_device *dev) { struct pxa_i2c *i2c = &i2c_pxa; + struct resource *res; #ifdef CONFIG_I2C_PXA_SLAVE struct i2c_pxa_platform_data *plat = dev->dev.platform_data; #endif int ret; + int irq; -#ifdef CONFIG_PXA27x - pxa_gpio_mode(GPIO117_I2CSCL_MD); - pxa_gpio_mode(GPIO118_I2CSDA_MD); - udelay(100); -#endif + res = platform_get_resource(dev, IORESOURCE_MEM, 0); + irq = platform_get_irq(dev, 0); + if (res == NULL || irq < 0) + return -ENODEV; + + if (!request_mem_region(res->start, res_len(res), res->name)) + return -ENOMEM; + + i2c = kmalloc(sizeof(struct pxa_i2c), GFP_KERNEL); + if (!i2c) { + ret = -ENOMEM; + goto emalloc; + } + + memcpy(i2c, &i2c_pxa, sizeof(struct pxa_i2c)); + init_waitqueue_head(&i2c->wait); + i2c->adap.name[strlen(i2c->adap.name) - 1] = '0' + dev->id % 10; + + i2c->reg_base = ioremap(res->start, res_len(res)); + if (!i2c->reg_base) { + ret = -EIO; + goto eremap; + } + + i2c->iobase = res->start; + i2c->iosize = res_len(res); + + i2c->irq = irq; i2c->slave_addr = I2C_PXA_SLAVE_ADDR; @@ -842,11 +883,28 @@ static int i2c_pxa_probe(struct platform_device *dev) } #endif - pxa_set_cken(CKEN14_I2C, 1); - ret = request_irq(IRQ_I2C, i2c_pxa_handler, IRQF_DISABLED, - "pxa2xx-i2c", i2c); + switch (dev->id) { + case 0: +#ifdef CONFIG_PXA27x + pxa_gpio_mode(GPIO117_I2CSCL_MD); + pxa_gpio_mode(GPIO118_I2CSDA_MD); +#endif + pxa_set_cken(CKEN14_I2C, 1); + break; +#ifdef CONFIG_PXA27x + case 1: + local_irq_disable(); + PCFR |= PCFR_PI2CEN; + local_irq_enable(); + pxa_set_cken(CKEN15_PWRI2C, 1); +#endif + } + + ret = request_irq(irq, i2c_pxa_handler, IRQF_DISABLED, + i2c->adap.name, i2c); if (ret) - goto out; + goto ereqirq; + i2c_pxa_reset(i2c); @@ -856,7 +914,7 @@ static int i2c_pxa_probe(struct platform_device *dev) ret = i2c_add_adapter(&i2c->adap); if (ret < 0) { printk(KERN_INFO "I2C: Failed to add bus\n"); - goto err_irq; + goto eadapt; } platform_set_drvdata(dev, i2c); @@ -870,9 +928,25 @@ static int i2c_pxa_probe(struct platform_device *dev) #endif return 0; - err_irq: - free_irq(IRQ_I2C, i2c); - out: +eadapt: + free_irq(irq, i2c); +ereqirq: + switch (dev->id) { + case 0: + pxa_set_cken(CKEN14_I2C, 0); + break; +#ifdef CONFIG_PXA27x + case 1: + pxa_set_cken(CKEN15_PWRI2C, 0); + local_irq_disable(); + PCFR &= ~PCFR_PI2CEN; + local_irq_enable(); +#endif + } +eremap: + kfree(i2c); +emalloc: + release_mem_region(res->start, res_len(res)); return ret; } @@ -883,8 +957,21 @@ static int i2c_pxa_remove(struct platform_device *dev) platform_set_drvdata(dev, NULL); i2c_del_adapter(&i2c->adap); - free_irq(IRQ_I2C, i2c); - pxa_set_cken(CKEN14_I2C, 0); + free_irq(i2c->irq, i2c); + switch (dev->id) { + case 0: + pxa_set_cken(CKEN14_I2C, 0); + break; +#ifdef CONFIG_PXA27x + case 1: + pxa_set_cken(CKEN15_PWRI2C, 0); + local_irq_disable(); + PCFR &= ~PCFR_PI2CEN; + local_irq_enable(); +#endif + } + release_mem_region(i2c->iobase, i2c->iosize); + kfree(i2c); return 0; } diff --git a/drivers/i2c/busses/i2c-sis5595.c b/drivers/i2c/busses/i2c-sis5595.c index d333babe4ad3..a6feed449dbe 100644 --- a/drivers/i2c/busses/i2c-sis5595.c +++ b/drivers/i2c/busses/i2c-sis5595.c @@ -384,7 +384,7 @@ static int __devinit sis5595_probe(struct pci_dev *dev, const struct pci_device_ return -ENODEV; } - /* set up the driverfs linkage to our parent device */ + /* set up the sysfs linkage to our parent device */ sis5595_adapter.dev.parent = &dev->dev; sprintf(sis5595_adapter.name, "SMBus SIS5595 adapter at %04x", diff --git a/drivers/i2c/busses/i2c-sis630.c b/drivers/i2c/busses/i2c-sis630.c index 172bacf932a6..5fd734f99ee9 100644 --- a/drivers/i2c/busses/i2c-sis630.c +++ b/drivers/i2c/busses/i2c-sis630.c @@ -477,7 +477,7 @@ static int __devinit sis630_probe(struct pci_dev *dev, const struct pci_device_i return -ENODEV; } - /* set up the driverfs linkage to our parent device */ + /* set up the sysfs linkage to our parent device */ sis630_adapter.dev.parent = &dev->dev; sprintf(sis630_adapter.name, "SMBus SIS630 adapter at %04x", diff --git a/drivers/i2c/busses/i2c-sis96x.c b/drivers/i2c/busses/i2c-sis96x.c index 73dae449fb23..4157b0cd604c 100644 --- a/drivers/i2c/busses/i2c-sis96x.c +++ b/drivers/i2c/busses/i2c-sis96x.c @@ -297,7 +297,7 @@ static int __devinit sis96x_probe(struct pci_dev *dev, return -EINVAL; } - /* set up the driverfs linkage to our parent device */ + /* set up the sysfs linkage to our parent device */ sis96x_adapter.dev.parent = &dev->dev; snprintf(sis96x_adapter.name, I2C_NAME_SIZE, diff --git a/drivers/i2c/busses/i2c-via.c b/drivers/i2c/busses/i2c-via.c index bbcc62151f7c..81520868797b 100644 --- a/drivers/i2c/busses/i2c-via.c +++ b/drivers/i2c/busses/i2c-via.c @@ -138,7 +138,7 @@ static int __devinit vt586b_probe(struct pci_dev *dev, const struct pci_device_i outb(inb(I2C_DIR) & ~(I2C_SDA | I2C_SCL), I2C_DIR); outb(inb(I2C_OUT) & ~(I2C_SDA | I2C_SCL), I2C_OUT); - /* set up the driverfs linkage to our parent device */ + /* set up the sysfs linkage to our parent device */ vt586b_adapter.dev.parent = &dev->dev; res = i2c_bit_add_bus(&vt586b_adapter); diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig index ec03341d2bd8..49234e32fd16 100644 --- a/drivers/ide/Kconfig +++ b/drivers/ide/Kconfig @@ -383,6 +383,9 @@ config BLK_DEV_OFFBOARD config BLK_DEV_GENERIC tristate "Generic PCI IDE Chipset Support" depends on BLK_DEV_IDEPCI + help + This option provides generic support for various PCI IDE Chipsets + which otherwise might not be supported. config BLK_DEV_OPTI621 tristate "OPTi 82C621 chipset enhanced support (EXPERIMENTAL)" @@ -797,6 +800,14 @@ config BLK_DEV_IDEDMA_PMAC to transfer data to and from memory. Saying Y is safe and improves performance. +config BLK_DEV_IDE_CELLEB + bool "Toshiba's Cell Reference Set IDE support" + depends on PPC_CELLEB + help + This driver provides support for the built-in IDE controller on + Toshiba Cell Reference Board. + If unsure, say Y. + config BLK_DEV_IDE_SWARM tristate "IDE for Sibyte evaluation boards" depends on SIBYTE_SB1xxx_SOC diff --git a/drivers/ide/Makefile b/drivers/ide/Makefile index d9f029e8ff74..28feedfbd21d 100644 --- a/drivers/ide/Makefile +++ b/drivers/ide/Makefile @@ -37,6 +37,7 @@ ide-core-$(CONFIG_BLK_DEV_Q40IDE) += legacy/q40ide.o # built-in only drivers from ppc/ ide-core-$(CONFIG_BLK_DEV_MPC8xx_IDE) += ppc/mpc8xx.o ide-core-$(CONFIG_BLK_DEV_IDE_PMAC) += ppc/pmac.o +ide-core-$(CONFIG_BLK_DEV_IDE_CELLEB) += ppc/scc_pata.o # built-in only drivers from h8300/ ide-core-$(CONFIG_H8300) += h8300/ide-h8300.o diff --git a/drivers/ide/arm/icside.c b/drivers/ide/arm/icside.c index 8a1c27f28692..40e5c66b81ce 100644 --- a/drivers/ide/arm/icside.c +++ b/drivers/ide/arm/icside.c @@ -307,26 +307,24 @@ static int icside_set_speed(ide_drive_t *drive, u8 xfer_mode) return on; } -static int icside_dma_host_off(ide_drive_t *drive) +static void icside_dma_host_off(ide_drive_t *drive) { - return 0; } -static int icside_dma_off_quietly(ide_drive_t *drive) +static void icside_dma_off_quietly(ide_drive_t *drive) { drive->using_dma = 0; - return icside_dma_host_off(drive); } -static int icside_dma_host_on(ide_drive_t *drive) +static void icside_dma_host_on(ide_drive_t *drive) { - return 0; } static int icside_dma_on(ide_drive_t *drive) { drive->using_dma = 1; - return icside_dma_host_on(drive); + + return 0; } static int icside_dma_check(ide_drive_t *drive) @@ -365,10 +363,7 @@ static int icside_dma_check(ide_drive_t *drive) out: on = icside_set_speed(drive, xfer_mode); - if (on) - return icside_dma_on(drive); - else - return icside_dma_off_quietly(drive); + return on ? 0 : -1; } static int icside_dma_end(ide_drive_t *drive) @@ -497,9 +492,9 @@ static void icside_dma_init(ide_hwif_t *hwif) hwif->autodma = autodma; hwif->ide_dma_check = icside_dma_check; - hwif->ide_dma_host_off = icside_dma_host_off; - hwif->ide_dma_off_quietly = icside_dma_off_quietly; - hwif->ide_dma_host_on = icside_dma_host_on; + hwif->dma_host_off = icside_dma_host_off; + hwif->dma_off_quietly = icside_dma_off_quietly; + hwif->dma_host_on = icside_dma_host_on; hwif->ide_dma_on = icside_dma_on; hwif->dma_setup = icside_dma_setup; hwif->dma_exec_cmd = icside_dma_exec_cmd; @@ -556,7 +551,7 @@ icside_setup(void __iomem *base, struct cardinfo *info, struct expansion_card *e * Ensure we're using MMIO */ default_hwif_mmiops(hwif); - hwif->mmio = 2; + hwif->mmio = 1; for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) { hwif->hw.io_ports[i] = port; diff --git a/drivers/ide/arm/rapide.c b/drivers/ide/arm/rapide.c index 3058217767d6..9c6c49fdd2b1 100644 --- a/drivers/ide/arm/rapide.c +++ b/drivers/ide/arm/rapide.c @@ -46,7 +46,7 @@ rapide_locate_hwif(void __iomem *base, void __iomem *ctrl, unsigned int sz, int hwif->hw.io_ports[IDE_CONTROL_OFFSET] = (unsigned long)ctrl; hwif->io_ports[IDE_CONTROL_OFFSET] = (unsigned long)ctrl; hwif->hw.irq = hwif->irq = irq; - hwif->mmio = 2; + hwif->mmio = 1; default_hwif_mmiops(hwif); return hwif; diff --git a/drivers/ide/cris/ide-cris.c b/drivers/ide/cris/ide-cris.c index 5797e0b5a132..6b2d152351b3 100644 --- a/drivers/ide/cris/ide-cris.c +++ b/drivers/ide/cris/ide-cris.c @@ -682,9 +682,12 @@ static void cris_ide_input_data (ide_drive_t *drive, void *, unsigned int); static void cris_ide_output_data (ide_drive_t *drive, void *, unsigned int); static void cris_atapi_input_bytes(ide_drive_t *drive, void *, unsigned int); static void cris_atapi_output_bytes(ide_drive_t *drive, void *, unsigned int); -static int cris_dma_off (ide_drive_t *drive); static int cris_dma_on (ide_drive_t *drive); +static void cris_dma_off(ide_drive_t *drive) +{ +} + static void tune_cris_ide(ide_drive_t *drive, u8 pio) { int setup, strobe, hold; @@ -795,7 +798,7 @@ init_e100_ide (void) 0, 0, cris_ide_ack_intr, ide_default_irq(0)); ide_register_hw(&hw, &hwif); - hwif->mmio = 2; + hwif->mmio = 1; hwif->chipset = ide_etrax100; hwif->tuneproc = &tune_cris_ide; hwif->speedproc = &speed_cris_ide; @@ -814,13 +817,16 @@ init_e100_ide (void) hwif->OUTBSYNC = &cris_ide_outbsync; hwif->INB = &cris_ide_inb; hwif->INW = &cris_ide_inw; - hwif->ide_dma_host_off = &cris_dma_off; - hwif->ide_dma_host_on = &cris_dma_on; - hwif->ide_dma_off_quietly = &cris_dma_off; + hwif->dma_host_off = &cris_dma_off; + hwif->dma_host_on = &cris_dma_on; + hwif->dma_off_quietly = &cris_dma_off; hwif->udma_four = 0; hwif->ultra_mask = cris_ultra_mask; hwif->mwdma_mask = 0x07; /* Multiword DMA 0-2 */ hwif->swdma_mask = 0x07; /* Singleword DMA 0-2 */ + hwif->autodma = 1; + hwif->drives[0].autodma = 1; + hwif->drives[1].autodma = 1; } /* Reset pulse */ @@ -835,11 +841,6 @@ init_e100_ide (void) cris_ide_set_speed(TYPE_UDMA, ATA_UDMA2_CYC, ATA_UDMA2_DVS, 0); } -static int cris_dma_off (ide_drive_t *drive) -{ - return 0; -} - static int cris_dma_on (ide_drive_t *drive) { return 0; @@ -1045,17 +1046,10 @@ static ide_startstop_t cris_dma_intr (ide_drive_t *drive) static int cris_dma_check(ide_drive_t *drive) { - ide_hwif_t *hwif = drive->hwif; - struct hd_driveid* id = drive->id; - - if (id && (id->capability & 1)) { - if (ide_use_dma(drive)) { - if (cris_config_drive_for_dma(drive)) - return hwif->ide_dma_on(drive); - } - } + if (ide_use_dma(drive) && cris_config_drive_for_dma(drive)) + return 0; - return hwif->ide_dma_off_quietly(drive); + return -1; } static int cris_dma_end(ide_drive_t *drive) diff --git a/drivers/ide/h8300/ide-h8300.c b/drivers/ide/h8300/ide-h8300.c index 608ca871744b..88750a300337 100644 --- a/drivers/ide/h8300/ide-h8300.c +++ b/drivers/ide/h8300/ide-h8300.c @@ -76,13 +76,11 @@ static inline void hwif_setup(ide_hwif_t *hwif) { default_hwif_iops(hwif); - hwif->mmio = 2; + hwif->mmio = 1; hwif->OUTW = mm_outw; hwif->OUTSW = mm_outsw; hwif->INW = mm_inw; hwif->INSW = mm_insw; - hwif->OUTL = NULL; - hwif->INL = NULL; hwif->OUTSL = NULL; hwif->INSL = NULL; } diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index 5969cec58dc1..45a928c058cf 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -687,15 +687,8 @@ static void ide_dump_status_no_sense(ide_drive_t *drive, const char *msg, u8 sta static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret) { struct request *rq = HWGROUP(drive)->rq; - ide_hwif_t *hwif = HWIF(drive); int stat, err, sense_key; - /* We may have bogus DMA interrupts in PIO state here */ - if (HWIF(drive)->dma_status && hwif->atapi_irq_bogon) { - stat = hwif->INB(hwif->dma_status); - /* Should we force the bit as well ? */ - hwif->OUTB(stat, hwif->dma_status); - } /* Check for errors. */ stat = HWIF(drive)->INB(IDE_STATUS_REG); if (stat_ret) @@ -930,6 +923,10 @@ static ide_startstop_t cdrom_start_packet_command(ide_drive_t *drive, HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG); if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) { + /* waiting for CDB interrupt, not DMA yet. */ + if (info->dma) + drive->waiting_for_dma = 0; + /* packet command */ ide_execute_command(drive, WIN_PACKETCMD, handler, ATAPI_WAIT_PC, cdrom_timer_expiry); return ide_started; @@ -972,6 +969,10 @@ static ide_startstop_t cdrom_transfer_packet_command (ide_drive_t *drive, /* Check for errors. */ if (cdrom_decode_status(drive, DRQ_STAT, NULL)) return ide_stopped; + + /* Ok, next interrupt will be DMA interrupt. */ + if (info->dma) + drive->waiting_for_dma = 1; } else { /* Otherwise, we must wait for DRQ to get set. */ if (ide_wait_stat(&startstop, drive, DRQ_STAT, @@ -1103,7 +1104,7 @@ static ide_startstop_t cdrom_read_intr (ide_drive_t *drive) if (dma) { info->dma = 0; if ((dma_error = HWIF(drive)->ide_dma_end(drive))) - __ide_dma_off(drive); + ide_dma_off(drive); } if (cdrom_decode_status(drive, 0, &stat)) @@ -1699,7 +1700,7 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive) if (dma) { if (dma_error) { printk(KERN_ERR "ide-cd: dma error\n"); - __ide_dma_off(drive); + ide_dma_off(drive); return ide_error(drive, "dma error", stat); } @@ -1825,7 +1826,7 @@ static ide_startstop_t cdrom_write_intr(ide_drive_t *drive) info->dma = 0; if ((dma_error = HWIF(drive)->ide_dma_end(drive))) { printk(KERN_ERR "ide-cd: write dma error\n"); - __ide_dma_off(drive); + ide_dma_off(drive); } } @@ -3254,14 +3255,6 @@ int ide_cdrom_setup (ide_drive_t *drive) if (drive->autotune == IDE_TUNE_DEFAULT || drive->autotune == IDE_TUNE_AUTO) drive->dsc_overlap = (drive->next != drive); -#if 0 - drive->dsc_overlap = (HWIF(drive)->no_dsc) ? 0 : 1; - if (HWIF(drive)->no_dsc) { - printk(KERN_INFO "ide-cd: %s: disabling DSC overlap\n", - drive->name); - drive->dsc_overlap = 0; - } -#endif if (ide_cdrom_register(drive, nslots)) { printk (KERN_ERR "%s: ide_cdrom_setup failed to register device with the cdrom driver.\n", drive->name); @@ -3360,21 +3353,16 @@ static int idecd_open(struct inode * inode, struct file * file) { struct gendisk *disk = inode->i_bdev->bd_disk; struct cdrom_info *info; - ide_drive_t *drive; int rc = -ENOMEM; if (!(info = ide_cd_get(disk))) return -ENXIO; - drive = info->drive; - - drive->usage++; - if (!info->buffer) - info->buffer = kmalloc(SECTOR_BUFFER_SIZE, - GFP_KERNEL|__GFP_REPEAT); - if (!info->buffer || (rc = cdrom_open(&info->devinfo, inode, file))) - drive->usage--; + info->buffer = kmalloc(SECTOR_BUFFER_SIZE, GFP_KERNEL|__GFP_REPEAT); + + if (info->buffer) + rc = cdrom_open(&info->devinfo, inode, file); if (rc < 0) ide_cd_put(info); @@ -3386,10 +3374,8 @@ static int idecd_release(struct inode * inode, struct file * file) { struct gendisk *disk = inode->i_bdev->bd_disk; struct cdrom_info *info = ide_cd_g(disk); - ide_drive_t *drive = info->drive; cdrom_release (&info->devinfo, file); - drive->usage--; ide_cd_put(info); diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c index 0a05a377d66a..e2cea1889c4d 100644 --- a/drivers/ide/ide-disk.c +++ b/drivers/ide/ide-disk.c @@ -77,6 +77,7 @@ struct ide_disk_obj { ide_driver_t *driver; struct gendisk *disk; struct kref kref; + unsigned int openers; /* protected by BKL for now */ }; static DEFINE_MUTEX(idedisk_ref_mutex); @@ -1081,8 +1082,9 @@ static int idedisk_open(struct inode *inode, struct file *filp) drive = idkp->drive; - drive->usage++; - if (drive->removable && drive->usage == 1) { + idkp->openers++; + + if (drive->removable && idkp->openers == 1) { ide_task_t args; memset(&args, 0, sizeof(ide_task_t)); args.tfRegister[IDE_COMMAND_OFFSET] = WIN_DOORLOCK; @@ -1106,9 +1108,10 @@ static int idedisk_release(struct inode *inode, struct file *filp) struct ide_disk_obj *idkp = ide_disk_g(disk); ide_drive_t *drive = idkp->drive; - if (drive->usage == 1) + if (idkp->openers == 1) ide_cacheflush_p(drive); - if (drive->removable && drive->usage == 1) { + + if (drive->removable && idkp->openers == 1) { ide_task_t args; memset(&args, 0, sizeof(ide_task_t)); args.tfRegister[IDE_COMMAND_OFFSET] = WIN_DOORUNLOCK; @@ -1117,7 +1120,8 @@ static int idedisk_release(struct inode *inode, struct file *filp) if (drive->doorlocking && ide_raw_taskfile(drive, &args, NULL)) drive->doorlocking = 0; } - drive->usage--; + + idkp->openers--; ide_disk_put(idkp); diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c index 56efed6742d4..08e7cd043bcc 100644 --- a/drivers/ide/ide-dma.c +++ b/drivers/ide/ide-dma.c @@ -348,15 +348,14 @@ EXPORT_SYMBOL_GPL(ide_destroy_dmatable); static int config_drive_for_dma (ide_drive_t *drive) { struct hd_driveid *id = drive->id; - ide_hwif_t *hwif = HWIF(drive); - if ((id->capability & 1) && hwif->autodma) { + if ((id->capability & 1) && drive->hwif->autodma) { /* * Enable DMA on any drive that has * UltraDMA (mode 0/1/2/3/4/5/6) enabled */ if ((id->field_valid & 4) && ((id->dma_ultra >> 8) & 0x7f)) - return hwif->ide_dma_on(drive); + return 0; /* * Enable DMA on any drive that has mode2 DMA * (multi or single) enabled @@ -364,14 +363,14 @@ static int config_drive_for_dma (ide_drive_t *drive) if (id->field_valid & 2) /* regular DMA */ if ((id->dma_mword & 0x404) == 0x404 || (id->dma_1word & 0x404) == 0x404) - return hwif->ide_dma_on(drive); + return 0; /* Consult the list of known "good" drives */ if (__ide_dma_good_drive(drive)) - return hwif->ide_dma_on(drive); + return 0; } -// if (hwif->tuneproc != NULL) hwif->tuneproc(drive, 255); - return hwif->ide_dma_off_quietly(drive); + + return -1; } /** @@ -415,72 +414,68 @@ static int dma_timer_expiry (ide_drive_t *drive) } /** - * __ide_dma_host_off - Generic DMA kill + * ide_dma_host_off - Generic DMA kill * @drive: drive to control * * Perform the generic IDE controller DMA off operation. This * works for most IDE bus mastering controllers */ -int __ide_dma_host_off (ide_drive_t *drive) +void ide_dma_host_off(ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); u8 unit = (drive->select.b.unit & 0x01); u8 dma_stat = hwif->INB(hwif->dma_status); hwif->OUTB((dma_stat & ~(1<<(5+unit))), hwif->dma_status); - return 0; } -EXPORT_SYMBOL(__ide_dma_host_off); +EXPORT_SYMBOL(ide_dma_host_off); /** - * __ide_dma_host_off_quietly - Generic DMA kill + * ide_dma_off_quietly - Generic DMA kill * @drive: drive to control * * Turn off the current DMA on this IDE controller. */ -int __ide_dma_off_quietly (ide_drive_t *drive) +void ide_dma_off_quietly(ide_drive_t *drive) { drive->using_dma = 0; ide_toggle_bounce(drive, 0); - if (HWIF(drive)->ide_dma_host_off(drive)) - return 1; - - return 0; + drive->hwif->dma_host_off(drive); } -EXPORT_SYMBOL(__ide_dma_off_quietly); +EXPORT_SYMBOL(ide_dma_off_quietly); #endif /* CONFIG_BLK_DEV_IDEDMA_PCI */ /** - * __ide_dma_off - disable DMA on a device + * ide_dma_off - disable DMA on a device * @drive: drive to disable DMA on * * Disable IDE DMA for a device on this IDE controller. * Inform the user that DMA has been disabled. */ -int __ide_dma_off (ide_drive_t *drive) +void ide_dma_off(ide_drive_t *drive) { printk(KERN_INFO "%s: DMA disabled\n", drive->name); - return HWIF(drive)->ide_dma_off_quietly(drive); + drive->hwif->dma_off_quietly(drive); } -EXPORT_SYMBOL(__ide_dma_off); +EXPORT_SYMBOL(ide_dma_off); #ifdef CONFIG_BLK_DEV_IDEDMA_PCI /** - * __ide_dma_host_on - Enable DMA on a host + * ide_dma_host_on - Enable DMA on a host * @drive: drive to enable for DMA * * Enable DMA on an IDE controller following generic bus mastering * IDE controller behaviour */ - -int __ide_dma_host_on (ide_drive_t *drive) + +void ide_dma_host_on(ide_drive_t *drive) { if (drive->using_dma) { ide_hwif_t *hwif = HWIF(drive); @@ -488,12 +483,10 @@ int __ide_dma_host_on (ide_drive_t *drive) u8 dma_stat = hwif->INB(hwif->dma_status); hwif->OUTB((dma_stat|(1<<(5+unit))), hwif->dma_status); - return 0; } - return 1; } -EXPORT_SYMBOL(__ide_dma_host_on); +EXPORT_SYMBOL(ide_dma_host_on); /** * __ide_dma_on - Enable DMA on a device @@ -511,8 +504,7 @@ int __ide_dma_on (ide_drive_t *drive) drive->using_dma = 1; ide_toggle_bounce(drive, 1); - if (HWIF(drive)->ide_dma_host_on(drive)) - return 1; + drive->hwif->dma_host_on(drive); return 0; } @@ -565,7 +557,10 @@ int ide_dma_setup(ide_drive_t *drive) } /* PRD table */ - hwif->OUTL(hwif->dmatable_dma, hwif->dma_prdtable); + if (hwif->mmio) + writel(hwif->dmatable_dma, (void __iomem *)hwif->dma_prdtable); + else + outl(hwif->dmatable_dma, hwif->dma_prdtable); /* specify r/w */ hwif->OUTB(reading, hwif->dma_command); @@ -680,6 +675,9 @@ int ide_use_dma(ide_drive_t *drive) struct hd_driveid *id = drive->id; ide_hwif_t *hwif = drive->hwif; + if ((id->capability & 1) == 0 || drive->autodma == 0) + return 0; + /* consult the list of known "bad" drives */ if (__ide_dma_bad_drive(drive)) return 0; @@ -753,12 +751,37 @@ void ide_dma_verbose(ide_drive_t *drive) return; bug_dma_off: printk(", BUG DMA OFF"); - hwif->ide_dma_off_quietly(drive); + hwif->dma_off_quietly(drive); return; } EXPORT_SYMBOL(ide_dma_verbose); +int ide_set_dma(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + int rc; + + rc = hwif->ide_dma_check(drive); + + switch(rc) { + case -1: /* DMA needs to be disabled */ + hwif->dma_off_quietly(drive); + return 0; + case 0: /* DMA needs to be enabled */ + return hwif->ide_dma_on(drive); + case 1: /* DMA setting cannot be changed */ + break; + default: + BUG(); + break; + } + + return rc; +} + +EXPORT_SYMBOL_GPL(ide_set_dma); + #ifdef CONFIG_BLK_DEV_IDEDMA_PCI int __ide_dma_lostirq (ide_drive_t *drive) { @@ -809,7 +832,7 @@ int ide_release_dma(ide_hwif_t *hwif) { ide_release_dma_engine(hwif); - if (hwif->mmio == 2) + if (hwif->mmio) return 1; else return ide_release_iomio_dma(hwif); @@ -878,9 +901,9 @@ static int ide_iomio_dma(ide_hwif_t *hwif, unsigned long base, unsigned int port static int ide_dma_iobase(ide_hwif_t *hwif, unsigned long base, unsigned int ports) { - if (hwif->mmio == 2) + if (hwif->mmio) return ide_mapped_mmio_dma(hwif, base,ports); - BUG_ON(hwif->mmio == 1); + return ide_iomio_dma(hwif, base, ports); } @@ -908,14 +931,14 @@ void ide_setup_dma (ide_hwif_t *hwif, unsigned long dma_base, unsigned int num_p if (!(hwif->dma_prdtable)) hwif->dma_prdtable = (hwif->dma_base + 4); - if (!hwif->ide_dma_off_quietly) - hwif->ide_dma_off_quietly = &__ide_dma_off_quietly; - if (!hwif->ide_dma_host_off) - hwif->ide_dma_host_off = &__ide_dma_host_off; + if (!hwif->dma_off_quietly) + hwif->dma_off_quietly = &ide_dma_off_quietly; + if (!hwif->dma_host_off) + hwif->dma_host_off = &ide_dma_host_off; if (!hwif->ide_dma_on) hwif->ide_dma_on = &__ide_dma_on; - if (!hwif->ide_dma_host_on) - hwif->ide_dma_host_on = &__ide_dma_host_on; + if (!hwif->dma_host_on) + hwif->dma_host_on = &ide_dma_host_on; if (!hwif->ide_dma_check) hwif->ide_dma_check = &__ide_dma_check; if (!hwif->dma_setup) diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c index d33717c8afd4..57cd21c5b2c1 100644 --- a/drivers/ide/ide-floppy.c +++ b/drivers/ide/ide-floppy.c @@ -279,6 +279,7 @@ typedef struct ide_floppy_obj { ide_driver_t *driver; struct gendisk *disk; struct kref kref; + unsigned int openers; /* protected by BKL for now */ /* Current packet command */ idefloppy_pc_t *pc; @@ -866,7 +867,7 @@ static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive) if (test_and_clear_bit(PC_DMA_IN_PROGRESS, &pc->flags)) { printk(KERN_ERR "ide-floppy: The floppy wants to issue " "more interrupts in DMA mode\n"); - (void)__ide_dma_off(drive); + ide_dma_off(drive); return ide_do_reset(drive); } @@ -1096,9 +1097,9 @@ static ide_startstop_t idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *p pc->current_position = pc->buffer; bcount.all = min(pc->request_transfer, 63 * 1024); - if (test_and_clear_bit(PC_DMA_ERROR, &pc->flags)) { - (void)__ide_dma_off(drive); - } + if (test_and_clear_bit(PC_DMA_ERROR, &pc->flags)) + ide_dma_off(drive); + feature.all = 0; if (test_bit(PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma) @@ -1433,7 +1434,8 @@ static int idefloppy_get_capacity (ide_drive_t *drive) drive->bios_cyl = 0; drive->bios_head = drive->bios_sect = 0; - floppy->blocks = floppy->bs_factor = 0; + floppy->blocks = 0; + floppy->bs_factor = 1; set_capacity(floppy->disk, 0); idefloppy_create_read_capacity_cmd(&pc); @@ -1949,9 +1951,9 @@ static int idefloppy_open(struct inode *inode, struct file *filp) drive = floppy->drive; - drive->usage++; + floppy->openers++; - if (drive->usage == 1) { + if (floppy->openers == 1) { clear_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, &floppy->flags); /* Just in case */ @@ -1969,13 +1971,11 @@ static int idefloppy_open(struct inode *inode, struct file *filp) ** capacity of the drive or begin the format - Sam */ ) { - drive->usage--; ret = -EIO; goto out_put_floppy; } if (floppy->wp && (filp->f_mode & 2)) { - drive->usage--; ret = -EROFS; goto out_put_floppy; } @@ -1987,13 +1987,13 @@ static int idefloppy_open(struct inode *inode, struct file *filp) } check_disk_change(inode->i_bdev); } else if (test_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, &floppy->flags)) { - drive->usage--; ret = -EBUSY; goto out_put_floppy; } return 0; out_put_floppy: + floppy->openers--; ide_floppy_put(floppy); return ret; } @@ -2007,7 +2007,7 @@ static int idefloppy_release(struct inode *inode, struct file *filp) debug_log(KERN_INFO "Reached idefloppy_release\n"); - if (drive->usage == 1) { + if (floppy->openers == 1) { /* IOMEGA Clik! drives do not support lock/unlock commands */ if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags)) { idefloppy_create_prevent_cmd(&pc, 0); @@ -2016,7 +2016,8 @@ static int idefloppy_release(struct inode *inode, struct file *filp) clear_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, &floppy->flags); } - drive->usage--; + + floppy->openers--; ide_floppy_put(floppy); @@ -2050,7 +2051,7 @@ static int idefloppy_ioctl(struct inode *inode, struct file *file, prevent = 0; /* fall through */ case CDROM_LOCKDOOR: - if (drive->usage > 1) + if (floppy->openers > 1) return -EBUSY; /* The IOMEGA Clik! Drive doesn't support this command - no room for an eject mechanism */ @@ -2072,7 +2073,7 @@ static int idefloppy_ioctl(struct inode *inode, struct file *file, if (!(file->f_mode & 2)) return -EPERM; - if (drive->usage > 1) { + if (floppy->openers > 1) { /* Don't format if someone is using the disk */ clear_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index 2614f41b5074..c193553f6fe7 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c @@ -226,7 +226,7 @@ static ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request * break; if (drive->hwif->ide_dma_check == NULL) break; - drive->hwif->ide_dma_check(drive); + ide_set_dma(drive); break; } pm->pm_step = ide_pm_state_completed; @@ -1351,7 +1351,7 @@ static ide_startstop_t ide_dma_timeout_retry(ide_drive_t *drive, int error) */ drive->retry_pio++; drive->state = DMA_PIO_RETRY; - (void) hwif->ide_dma_off_quietly(drive); + hwif->dma_off_quietly(drive); /* * un-busy drive etc (hwgroup->busy is cleared on return) and @@ -1646,6 +1646,17 @@ irqreturn_t ide_intr (int irq, void *dev_id) del_timer(&hwgroup->timer); spin_unlock(&ide_lock); + /* Some controllers might set DMA INTR no matter DMA or PIO; + * bmdma status might need to be cleared even for + * PIO interrupts to prevent spurious/lost irq. + */ + if (hwif->ide_dma_clear_irq && !(drive->waiting_for_dma)) + /* ide_dma_end() needs bmdma status for error checking. + * So, skip clearing bmdma status here and leave it + * to ide_dma_end() if this is dma interrupt. + */ + hwif->ide_dma_clear_irq(drive); + if (drive->unmask) local_irq_enable_in_hardirq(); /* service this interrupt, may set handler for next interrupt */ diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c index badde6331775..c67b3b1e6f4c 100644 --- a/drivers/ide/ide-iops.c +++ b/drivers/ide/ide-iops.c @@ -49,11 +49,6 @@ static void ide_insw (unsigned long port, void *addr, u32 count) insw(port, addr, count); } -static u32 ide_inl (unsigned long port) -{ - return (u32) inl(port); -} - static void ide_insl (unsigned long port, void *addr, u32 count) { insl(port, addr, count); @@ -79,11 +74,6 @@ static void ide_outsw (unsigned long port, void *addr, u32 count) outsw(port, addr, count); } -static void ide_outl (u32 val, unsigned long port) -{ - outl(val, port); -} - static void ide_outsl (unsigned long port, void *addr, u32 count) { outsl(port, addr, count); @@ -94,12 +84,10 @@ void default_hwif_iops (ide_hwif_t *hwif) hwif->OUTB = ide_outb; hwif->OUTBSYNC = ide_outbsync; hwif->OUTW = ide_outw; - hwif->OUTL = ide_outl; hwif->OUTSW = ide_outsw; hwif->OUTSL = ide_outsl; hwif->INB = ide_inb; hwif->INW = ide_inw; - hwif->INL = ide_inl; hwif->INSW = ide_insw; hwif->INSL = ide_insl; } @@ -123,11 +111,6 @@ static void ide_mm_insw (unsigned long port, void *addr, u32 count) __ide_mm_insw((void __iomem *) port, addr, count); } -static u32 ide_mm_inl (unsigned long port) -{ - return (u32) readl((void __iomem *) port); -} - static void ide_mm_insl (unsigned long port, void *addr, u32 count) { __ide_mm_insl((void __iomem *) port, addr, count); @@ -153,11 +136,6 @@ static void ide_mm_outsw (unsigned long port, void *addr, u32 count) __ide_mm_outsw((void __iomem *) port, addr, count); } -static void ide_mm_outl (u32 value, unsigned long port) -{ - writel(value, (void __iomem *) port); -} - static void ide_mm_outsl (unsigned long port, void *addr, u32 count) { __ide_mm_outsl((void __iomem *) port, addr, count); @@ -170,12 +148,10 @@ void default_hwif_mmiops (ide_hwif_t *hwif) this one is controller specific! */ hwif->OUTBSYNC = ide_mm_outbsync; hwif->OUTW = ide_mm_outw; - hwif->OUTL = ide_mm_outl; hwif->OUTSW = ide_mm_outsw; hwif->OUTSL = ide_mm_outsl; hwif->INB = ide_mm_inb; hwif->INW = ide_mm_inw; - hwif->INL = ide_mm_inl; hwif->INSW = ide_mm_insw; hwif->INSL = ide_mm_insl; } @@ -777,7 +753,7 @@ int ide_config_drive_speed (ide_drive_t *drive, u8 speed) #ifdef CONFIG_BLK_DEV_IDEDMA if (hwif->ide_dma_check) /* check if host supports DMA */ - hwif->ide_dma_host_off(drive); + hwif->dma_host_off(drive); #endif /* @@ -854,9 +830,9 @@ int ide_config_drive_speed (ide_drive_t *drive, u8 speed) #ifdef CONFIG_BLK_DEV_IDEDMA if (speed >= XFER_SW_DMA_0) - hwif->ide_dma_host_on(drive); + hwif->dma_host_on(drive); else if (hwif->ide_dma_check) /* check if host supports DMA */ - hwif->ide_dma_off_quietly(drive); + hwif->dma_off_quietly(drive); #endif switch(speed) { @@ -1066,12 +1042,12 @@ static void check_dma_crc(ide_drive_t *drive) { #ifdef CONFIG_BLK_DEV_IDEDMA if (drive->crc_count) { - (void) HWIF(drive)->ide_dma_off_quietly(drive); + drive->hwif->dma_off_quietly(drive); ide_set_xfer_rate(drive, ide_auto_reduce_xfer(drive)); if (drive->current_speed >= XFER_SW_DMA_0) (void) HWIF(drive)->ide_dma_on(drive); } else - (void)__ide_dma_off(drive); + ide_dma_off(drive); #endif } diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c index 8237d89eec6e..8afce4ceea31 100644 --- a/drivers/ide/ide-lib.c +++ b/drivers/ide/ide-lib.c @@ -205,6 +205,21 @@ int ide_dma_enable (ide_drive_t *drive) EXPORT_SYMBOL(ide_dma_enable); +int ide_use_fast_pio(ide_drive_t *drive) +{ + struct hd_driveid *id = drive->id; + + if ((id->capability & 1) && drive->autodma) + return 1; + + if ((id->capability & 8) || (id->field_valid & 2)) + return 1; + + return 0; +} + +EXPORT_SYMBOL_GPL(ide_use_fast_pio); + /* * Standard (generic) timings for PIO modes, from ATA2 specification. * These timings are for access to the IDE data port register *only*. @@ -349,7 +364,6 @@ u8 ide_get_best_pio_mode (ide_drive_t *drive, u8 mode_wanted, u8 max_mode, ide_p int use_iordy = 0; struct hd_driveid* id = drive->id; int overridden = 0; - int blacklisted = 0; if (mode_wanted != 255) { pio_mode = mode_wanted; @@ -357,7 +371,6 @@ u8 ide_get_best_pio_mode (ide_drive_t *drive, u8 mode_wanted, u8 max_mode, ide_p pio_mode = 0; } else if ((pio_mode = ide_scan_pio_blacklist(id->model)) != -1) { overridden = 1; - blacklisted = 1; use_iordy = (pio_mode > 2); } else { pio_mode = id->tPIO; @@ -409,7 +422,6 @@ u8 ide_get_best_pio_mode (ide_drive_t *drive, u8 mode_wanted, u8 max_mode, ide_p d->cycle_time = cycle_time ? cycle_time : ide_pio_timings[pio_mode].cycle_time; d->use_iordy = use_iordy; d->overridden = overridden; - d->blacklisted = blacklisted; } return pio_mode; } @@ -462,8 +474,6 @@ int ide_set_xfer_rate(ide_drive_t *drive, u8 rate) return -1; } -EXPORT_SYMBOL_GPL(ide_set_xfer_rate); - static void ide_dump_opcode(ide_drive_t *drive) { struct request *rq; diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index 176bbc850d6b..8afbd6cb94be 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -853,11 +853,11 @@ static void probe_hwif(ide_hwif_t *hwif) * things, if not checked and cleared. * PARANOIA!!! */ - hwif->ide_dma_off_quietly(drive); + hwif->dma_off_quietly(drive); #ifdef CONFIG_IDEDMA_ONLYDISK if (drive->media == ide_disk) #endif - hwif->ide_dma_check(drive); + ide_set_dma(drive); } } } diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index c6eec0413a6c..4e59239fef75 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -1970,7 +1970,7 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive) printk(KERN_ERR "ide-tape: The tape wants to issue more " "interrupts in DMA mode\n"); printk(KERN_ERR "ide-tape: DMA disabled, reverting to PIO\n"); - (void)__ide_dma_off(drive); + ide_dma_off(drive); return ide_do_reset(drive); } /* Get the number of bytes to transfer on this interrupt. */ @@ -2176,7 +2176,7 @@ static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape if (test_and_clear_bit(PC_DMA_ERROR, &pc->flags)) { printk(KERN_WARNING "ide-tape: DMA disabled, " "reverting to PIO\n"); - (void)__ide_dma_off(drive); + ide_dma_off(drive); } if (test_bit(PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma) dma_ok = !hwif->dma_setup(drive); @@ -4792,15 +4792,10 @@ static int idetape_open(struct inode *inode, struct file *filp) { struct gendisk *disk = inode->i_bdev->bd_disk; struct ide_tape_obj *tape; - ide_drive_t *drive; if (!(tape = ide_tape_get(disk))) return -ENXIO; - drive = tape->drive; - - drive->usage++; - return 0; } @@ -4808,9 +4803,6 @@ static int idetape_release(struct inode *inode, struct file *filp) { struct gendisk *disk = inode->i_bdev->bd_disk; struct ide_tape_obj *tape = ide_tape_g(disk); - ide_drive_t *drive = tape->drive; - - drive->usage--; ide_tape_put(tape); diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index c750f6ce770a..b3c0818c5c6c 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -389,9 +389,8 @@ int ide_hwif_request_regions(ide_hwif_t *hwif) unsigned long addr; unsigned int i; - if (hwif->mmio == 2) + if (hwif->mmio) return 0; - BUG_ON(hwif->mmio == 1); addr = hwif->io_ports[IDE_CONTROL_OFFSET]; if (addr && !hwif_request_region(hwif, addr, 1)) goto control_region_busy; @@ -438,7 +437,7 @@ void ide_hwif_release_regions(ide_hwif_t *hwif) { u32 i = 0; - if (hwif->mmio == 2) + if (hwif->mmio) return; if (hwif->io_ports[IDE_CONTROL_OFFSET]) release_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1); @@ -507,23 +506,22 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif) hwif->ide_dma_end = tmp_hwif->ide_dma_end; hwif->ide_dma_check = tmp_hwif->ide_dma_check; hwif->ide_dma_on = tmp_hwif->ide_dma_on; - hwif->ide_dma_off_quietly = tmp_hwif->ide_dma_off_quietly; + hwif->dma_off_quietly = tmp_hwif->dma_off_quietly; hwif->ide_dma_test_irq = tmp_hwif->ide_dma_test_irq; - hwif->ide_dma_host_on = tmp_hwif->ide_dma_host_on; - hwif->ide_dma_host_off = tmp_hwif->ide_dma_host_off; + hwif->ide_dma_clear_irq = tmp_hwif->ide_dma_clear_irq; + hwif->dma_host_on = tmp_hwif->dma_host_on; + hwif->dma_host_off = tmp_hwif->dma_host_off; hwif->ide_dma_lostirq = tmp_hwif->ide_dma_lostirq; hwif->ide_dma_timeout = tmp_hwif->ide_dma_timeout; hwif->OUTB = tmp_hwif->OUTB; hwif->OUTBSYNC = tmp_hwif->OUTBSYNC; hwif->OUTW = tmp_hwif->OUTW; - hwif->OUTL = tmp_hwif->OUTL; hwif->OUTSW = tmp_hwif->OUTSW; hwif->OUTSL = tmp_hwif->OUTSL; hwif->INB = tmp_hwif->INB; hwif->INW = tmp_hwif->INW; - hwif->INL = tmp_hwif->INL; hwif->INSW = tmp_hwif->INSW; hwif->INSL = tmp_hwif->INSL; @@ -551,7 +549,6 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif) hwif->extra_ports = tmp_hwif->extra_ports; hwif->autodma = tmp_hwif->autodma; hwif->udma_four = tmp_hwif->udma_four; - hwif->no_dsc = tmp_hwif->no_dsc; hwif->hwif_data = tmp_hwif->hwif_data; } @@ -1138,12 +1135,11 @@ static int set_using_dma (ide_drive_t *drive, int arg) if (HWIF(drive)->ide_dma_check == NULL) return -EPERM; if (arg) { - if (HWIF(drive)->ide_dma_check(drive)) return -EIO; - if (HWIF(drive)->ide_dma_on(drive)) return -EIO; - } else { - if (__ide_dma_off(drive)) + if (ide_set_dma(drive)) return -EIO; - } + if (HWIF(drive)->ide_dma_on(drive)) return -EIO; + } else + ide_dma_off(drive); return 0; #else return -EPERM; diff --git a/drivers/ide/legacy/buddha.c b/drivers/ide/legacy/buddha.c index 0391a3122878..1ed224a01f79 100644 --- a/drivers/ide/legacy/buddha.c +++ b/drivers/ide/legacy/buddha.c @@ -215,7 +215,7 @@ fail_base2: index = ide_register_hw(&hw, &hwif); if (index != -1) { - hwif->mmio = 2; + hwif->mmio = 1; printk("ide%d: ", index); switch(type) { case BOARD_BUDDHA: diff --git a/drivers/ide/legacy/gayle.c b/drivers/ide/legacy/gayle.c index 64d42619ab06..dcfadbbf55d8 100644 --- a/drivers/ide/legacy/gayle.c +++ b/drivers/ide/legacy/gayle.c @@ -167,7 +167,7 @@ found: index = ide_register_hw(&hw, &hwif); if (index != -1) { - hwif->mmio = 2; + hwif->mmio = 1; switch (i) { case 0: printk("ide%d: Gayle IDE interface (A%d style)\n", index, diff --git a/drivers/ide/legacy/ht6560b.c b/drivers/ide/legacy/ht6560b.c index c48e87e512d3..19ccd006f205 100644 --- a/drivers/ide/legacy/ht6560b.c +++ b/drivers/ide/legacy/ht6560b.c @@ -143,16 +143,16 @@ static void ht6560b_selectproc (ide_drive_t *drive) current_timing = timing; if (drive->media != ide_disk || !drive->present) select |= HT_PREFETCH_MODE; - (void) HWIF(drive)->INB(HT_CONFIG_PORT); - (void) HWIF(drive)->INB(HT_CONFIG_PORT); - (void) HWIF(drive)->INB(HT_CONFIG_PORT); - (void) HWIF(drive)->INB(HT_CONFIG_PORT); - HWIF(drive)->OUTB(select, HT_CONFIG_PORT); + (void)inb(HT_CONFIG_PORT); + (void)inb(HT_CONFIG_PORT); + (void)inb(HT_CONFIG_PORT); + (void)inb(HT_CONFIG_PORT); + outb(select, HT_CONFIG_PORT); /* * Set timing for this drive: */ - HWIF(drive)->OUTB(timing, IDE_SELECT_REG); - (void) HWIF(drive)->INB(IDE_STATUS_REG); + outb(timing, IDE_SELECT_REG); + (void)inb(IDE_STATUS_REG); #ifdef DEBUG printk("ht6560b: %s: select=%#x timing=%#x\n", drive->name, select, timing); diff --git a/drivers/ide/legacy/macide.c b/drivers/ide/legacy/macide.c index b1730d7e414c..4c0079ad52ac 100644 --- a/drivers/ide/legacy/macide.c +++ b/drivers/ide/legacy/macide.c @@ -141,7 +141,7 @@ void macide_init(void) } if (index != -1) { - hwif->mmio = 2; + hwif->mmio = 1; if (macintosh_config->ide_type == MAC_IDE_QUADRA) printk(KERN_INFO "ide%d: Macintosh Quadra IDE interface\n", index); else if (macintosh_config->ide_type == MAC_IDE_PB) diff --git a/drivers/ide/legacy/q40ide.c b/drivers/ide/legacy/q40ide.c index 434a94faa3b7..74f08124eabb 100644 --- a/drivers/ide/legacy/q40ide.c +++ b/drivers/ide/legacy/q40ide.c @@ -145,7 +145,7 @@ void q40ide_init(void) index = ide_register_hw(&hw, &hwif); // **FIXME** if (index != -1) - hwif->mmio = 2; + hwif->mmio = 1; } } diff --git a/drivers/ide/mips/au1xxx-ide.c b/drivers/ide/mips/au1xxx-ide.c index c7854ea57b52..0a59d5ef1599 100644 --- a/drivers/ide/mips/au1xxx-ide.c +++ b/drivers/ide/mips/au1xxx-ide.c @@ -181,12 +181,6 @@ static int auide_tune_chipset (ide_drive_t *drive, u8 speed) { int mem_sttime; int mem_stcfg; - unsigned long mode; - -#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA - if (ide_use_dma(drive)) - mode = ide_dma_speed(drive, 0); -#endif mem_sttime = 0; mem_stcfg = au_readl(MEM_STCFG2); @@ -195,7 +189,7 @@ static int auide_tune_chipset (ide_drive_t *drive, u8 speed) auide_tune_drive(drive, speed - XFER_PIO_0); return 0; } - + switch(speed) { #ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA case XFER_MW_DMA_2: @@ -207,7 +201,6 @@ static int auide_tune_chipset (ide_drive_t *drive, u8 speed) mem_stcfg &= ~TOECS_MASK; mem_stcfg |= SBC_IDE_MDMA2_TCSOE | SBC_IDE_MDMA2_TOECS; - mode = XFER_MW_DMA_2; break; case XFER_MW_DMA_1: mem_sttime = SBC_IDE_TIMING(MDMA1); @@ -218,7 +211,6 @@ static int auide_tune_chipset (ide_drive_t *drive, u8 speed) mem_stcfg &= ~TOECS_MASK; mem_stcfg |= SBC_IDE_MDMA1_TCSOE | SBC_IDE_MDMA1_TOECS; - mode = XFER_MW_DMA_1; break; case XFER_MW_DMA_0: mem_sttime = SBC_IDE_TIMING(MDMA0); @@ -229,14 +221,13 @@ static int auide_tune_chipset (ide_drive_t *drive, u8 speed) mem_stcfg &= ~TOECS_MASK; mem_stcfg |= SBC_IDE_MDMA0_TCSOE | SBC_IDE_MDMA0_TOECS; - mode = XFER_MW_DMA_0; break; #endif default: return 1; } - - if (ide_config_drive_speed(drive, mode)) + + if (ide_config_drive_speed(drive, speed)) return 1; au_writel(mem_sttime,MEM_STTIME2); @@ -423,9 +414,9 @@ static int auide_dma_check(ide_drive_t *drive) speed = ide_find_best_mode(drive, XFER_PIO | XFER_MWDMA); if (drive->autodma && (speed & XFER_MODE) != XFER_PIO) - return HWIF(drive)->ide_dma_on(drive); + return 0; - return HWIF(drive)->ide_dma_off_quietly(drive); + return -1; } static int auide_dma_test_irq(ide_drive_t *drive) @@ -447,27 +438,24 @@ static int auide_dma_test_irq(ide_drive_t *drive) return 0; } -static int auide_dma_host_on(ide_drive_t *drive) +static void auide_dma_host_on(ide_drive_t *drive) { - return 0; } static int auide_dma_on(ide_drive_t *drive) { drive->using_dma = 1; - return auide_dma_host_on(drive); -} + return 0; +} -static int auide_dma_host_off(ide_drive_t *drive) +static void auide_dma_host_off(ide_drive_t *drive) { - return 0; } -static int auide_dma_off_quietly(ide_drive_t *drive) +static void auide_dma_off_quietly(ide_drive_t *drive) { drive->using_dma = 0; - return auide_dma_host_off(drive); } static int auide_dma_lostirq(ide_drive_t *drive) @@ -717,7 +705,8 @@ static int au_ide_probe(struct device *dev) /* hold should be on in all cases */ hwif->hold = 1; - hwif->mmio = 2; + + hwif->mmio = 1; /* If the user has selected DDMA assisted copies, then set up a few local I/O function entry points @@ -732,7 +721,7 @@ static int au_ide_probe(struct device *dev) hwif->speedproc = &auide_tune_chipset; #ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA - hwif->ide_dma_off_quietly = &auide_dma_off_quietly; + hwif->dma_off_quietly = &auide_dma_off_quietly; hwif->ide_dma_timeout = &auide_dma_timeout; hwif->ide_dma_check = &auide_dma_check; @@ -741,8 +730,8 @@ static int au_ide_probe(struct device *dev) hwif->ide_dma_end = &auide_dma_end; hwif->dma_setup = &auide_dma_setup; hwif->ide_dma_test_irq = &auide_dma_test_irq; - hwif->ide_dma_host_off = &auide_dma_host_off; - hwif->ide_dma_host_on = &auide_dma_host_on; + hwif->dma_host_off = &auide_dma_host_off; + hwif->dma_host_on = &auide_dma_host_on; hwif->ide_dma_lostirq = &auide_dma_lostirq; hwif->ide_dma_on = &auide_dma_on; diff --git a/drivers/ide/mips/swarm.c b/drivers/ide/mips/swarm.c index 09c9e7936b0d..81fa06851b27 100644 --- a/drivers/ide/mips/swarm.c +++ b/drivers/ide/mips/swarm.c @@ -115,7 +115,7 @@ static int __devinit swarm_ide_probe(struct device *dev) /* Setup MMIO ops. */ default_hwif_mmiops(hwif); /* Prevent resource map manipulation. */ - hwif->mmio = 2; + hwif->mmio = 1; hwif->noprobe = 0; for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) diff --git a/drivers/ide/pci/aec62xx.c b/drivers/ide/pci/aec62xx.c index d261bfbad222..990eafe5ea11 100644 --- a/drivers/ide/pci/aec62xx.c +++ b/drivers/ide/pci/aec62xx.c @@ -94,9 +94,9 @@ static u8 aec62xx_ratemask (ide_drive_t *drive) switch(hwif->pci_dev->device) { case PCI_DEVICE_ID_ARTOP_ATP865: case PCI_DEVICE_ID_ARTOP_ATP865R: - mode = (hwif->INB(((hwif->channel) ? - hwif->mate->dma_status : - hwif->dma_status)) & 0x10) ? 4 : 3; + mode = (inb(hwif->channel ? + hwif->mate->dma_status : + hwif->dma_status) & 0x10) ? 4 : 3; break; case PCI_DEVICE_ID_ARTOP_ATP860: case PCI_DEVICE_ID_ARTOP_ATP860R: @@ -209,25 +209,13 @@ static void aec62xx_tune_drive (ide_drive_t *drive, u8 pio) static int aec62xx_config_drive_xfer_rate (ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); - struct hd_driveid *id = drive->id; - - if ((id->capability & 1) && drive->autodma) { - - if (ide_use_dma(drive)) { - if (config_chipset_for_dma(drive)) - return hwif->ide_dma_on(drive); - } - - goto fast_ata_pio; + if (ide_use_dma(drive) && config_chipset_for_dma(drive)) + return 0; - } else if ((id->capability & 8) || (id->field_valid & 2)) { -fast_ata_pio: + if (ide_use_fast_pio(drive)) aec62xx_tune_drive(drive, 5); - return hwif->ide_dma_off_quietly(drive); - } - /* IORDY not supported */ - return 0; + + return -1; } static int aec62xx_irq_timeout (ide_drive_t *drive) @@ -286,10 +274,8 @@ static void __devinit init_hwif_aec62xx(ide_hwif_t *hwif) hwif->tuneproc = &aec62xx_tune_drive; hwif->speedproc = &aec62xx_tune_chipset; - if (hwif->pci_dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) { + if (hwif->pci_dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) hwif->serialized = hwif->channel; - hwif->no_dsc = 1; - } if (hwif->mate) hwif->mate->serialized = hwif->serialized; diff --git a/drivers/ide/pci/alim15x3.c b/drivers/ide/pci/alim15x3.c index 68df77ec502b..4debd18d52f8 100644 --- a/drivers/ide/pci/alim15x3.c +++ b/drivers/ide/pci/alim15x3.c @@ -507,17 +507,15 @@ static int config_chipset_for_dma (ide_drive_t *drive) * * Configure a drive for DMA operation. If DMA is not possible we * drop the drive into PIO mode instead. - * - * FIXME: exactly what are we trying to return here */ - + static int ali15x3_config_drive_for_dma(ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); struct hd_driveid *id = drive->id; if ((m5229_revision<=0x20) && (drive->media!=ide_disk)) - return hwif->ide_dma_off_quietly(drive); + goto no_dma_set; drive->init_speed = 0; @@ -552,9 +550,10 @@ try_dma_modes: ata_pio: hwif->tuneproc(drive, 255); no_dma_set: - return hwif->ide_dma_off_quietly(drive); + return -1; } - return hwif->ide_dma_on(drive); + + return 0; } /** @@ -852,8 +851,8 @@ static void __devinit init_dma_ali15x3 (ide_hwif_t *hwif, unsigned long dmabase) { if (m5229_revision < 0x20) return; - if (!(hwif->channel)) - hwif->OUTB(hwif->INB(dmabase+2) & 0x60, dmabase+2); + if (!hwif->channel) + outb(inb(dmabase + 2) & 0x60, dmabase + 2); ide_setup_dma(hwif, dmabase, 8); } diff --git a/drivers/ide/pci/amd74xx.c b/drivers/ide/pci/amd74xx.c index a4336995a410..7989bdd842a2 100644 --- a/drivers/ide/pci/amd74xx.c +++ b/drivers/ide/pci/amd74xx.c @@ -304,8 +304,9 @@ static int amd74xx_ide_dma_check(ide_drive_t *drive) amd_set_drive(drive, speed); if (drive->autodma && (speed & XFER_MODE) != XFER_PIO) - return HWIF(drive)->ide_dma_on(drive); - return HWIF(drive)->ide_dma_off_quietly(drive); + return 0; + + return -1; } /* diff --git a/drivers/ide/pci/atiixp.c b/drivers/ide/pci/atiixp.c index 982ac31fa995..2d48af32e3f4 100644 --- a/drivers/ide/pci/atiixp.c +++ b/drivers/ide/pci/atiixp.c @@ -101,7 +101,7 @@ static u8 atiixp_dma_2_pio(u8 xfer_rate) { } } -static int atiixp_ide_dma_host_on(ide_drive_t *drive) +static void atiixp_dma_host_on(ide_drive_t *drive) { struct pci_dev *dev = drive->hwif->pci_dev; unsigned long flags; @@ -118,10 +118,10 @@ static int atiixp_ide_dma_host_on(ide_drive_t *drive) spin_unlock_irqrestore(&atiixp_lock, flags); - return __ide_dma_host_on(drive); + ide_dma_host_on(drive); } -static int atiixp_ide_dma_host_off(ide_drive_t *drive) +static void atiixp_dma_host_off(ide_drive_t *drive) { struct pci_dev *dev = drive->hwif->pci_dev; unsigned long flags; @@ -135,7 +135,7 @@ static int atiixp_ide_dma_host_off(ide_drive_t *drive) spin_unlock_irqrestore(&atiixp_lock, flags); - return __ide_dma_host_off(drive); + ide_dma_host_off(drive); } /** @@ -235,11 +235,8 @@ static int atiixp_config_drive_for_dma(ide_drive_t *drive) { u8 speed = ide_dma_speed(drive, atiixp_ratemask(drive)); - /* If no DMA speed was available then disable DMA and use PIO. */ - if (!speed) { - u8 tspeed = ide_get_best_pio_mode(drive, 255, 5, NULL); - speed = atiixp_dma_2_pio(XFER_PIO_0 + tspeed) + XFER_PIO_0; - } + if (!speed) + return 0; (void) atiixp_speedproc(drive, speed); return ide_dma_enable(drive); @@ -255,30 +252,20 @@ static int atiixp_config_drive_for_dma(ide_drive_t *drive) static int atiixp_dma_check(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); - struct hd_driveid *id = drive->id; u8 tspeed, speed; drive->init_speed = 0; - if ((id->capability & 1) && drive->autodma) { - - if (ide_use_dma(drive)) { - if (atiixp_config_drive_for_dma(drive)) - return hwif->ide_dma_on(drive); - } - - goto fast_ata_pio; + if (ide_use_dma(drive) && atiixp_config_drive_for_dma(drive)) + return 0; - } else if ((id->capability & 8) || (id->field_valid & 2)) { -fast_ata_pio: + if (ide_use_fast_pio(drive)) { tspeed = ide_get_best_pio_mode(drive, 255, 5, NULL); speed = atiixp_dma_2_pio(XFER_PIO_0 + tspeed) + XFER_PIO_0; - hwif->speedproc(drive, speed); - return hwif->ide_dma_off_quietly(drive); + atiixp_speedproc(drive, speed); } - /* IORDY not supported */ - return 0; + + return -1; } /** @@ -318,8 +305,8 @@ static void __devinit init_hwif_atiixp(ide_hwif_t *hwif) 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->dma_host_on = &atiixp_dma_host_on; + hwif->dma_host_off = &atiixp_dma_host_off; hwif->ide_dma_check = &atiixp_dma_check; if (!noautodma) hwif->autodma = 1; diff --git a/drivers/ide/pci/cmd64x.c b/drivers/ide/pci/cmd64x.c index aee947e8fc38..49df27513da7 100644 --- a/drivers/ide/pci/cmd64x.c +++ b/drivers/ide/pci/cmd64x.c @@ -466,36 +466,21 @@ static int config_chipset_for_dma (ide_drive_t *drive) if (!speed) return 0; - if(ide_set_xfer_rate(drive, speed)) - return 0; - - if (!drive->init_speed) - drive->init_speed = speed; + if (cmd64x_tune_chipset(drive, speed)) + return 0; return ide_dma_enable(drive); } static int cmd64x_config_drive_for_dma (ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); - struct hd_driveid *id = drive->id; - - if ((id != NULL) && ((id->capability & 1) != 0) && drive->autodma) { - - if (ide_use_dma(drive)) { - if (config_chipset_for_dma(drive)) - return hwif->ide_dma_on(drive); - } - - goto fast_ata_pio; + if (ide_use_dma(drive) && config_chipset_for_dma(drive)) + return 0; - } else if ((id->capability & 8) || (id->field_valid & 2)) { -fast_ata_pio: + if (ide_use_fast_pio(drive)) config_chipset_for_pio(drive, 1); - return hwif->ide_dma_off_quietly(drive); - } - /* IORDY not supported */ - return 0; + + return -1; } static int cmd64x_alt_dma_status (struct pci_dev *dev) @@ -518,13 +503,13 @@ static int cmd64x_ide_dma_end (ide_drive_t *drive) drive->waiting_for_dma = 0; /* read DMA command state */ - dma_cmd = hwif->INB(hwif->dma_command); + dma_cmd = inb(hwif->dma_command); /* stop DMA */ - hwif->OUTB((dma_cmd & ~1), hwif->dma_command); + outb(dma_cmd & ~1, hwif->dma_command); /* get DMA status */ - dma_stat = hwif->INB(hwif->dma_status); + dma_stat = inb(hwif->dma_status); /* clear the INTR & ERROR bits */ - hwif->OUTB(dma_stat|6, hwif->dma_status); + outb(dma_stat | 6, hwif->dma_status); if (cmd64x_alt_dma_status(dev)) { u8 dma_intr = 0; u8 dma_mask = (hwif->channel) ? ARTTIM23_INTR_CH1 : @@ -546,7 +531,7 @@ static int cmd64x_ide_dma_test_irq (ide_drive_t *drive) struct pci_dev *dev = hwif->pci_dev; u8 dma_alt_stat = 0, mask = (hwif->channel) ? MRDMODE_INTR_CH1 : MRDMODE_INTR_CH0; - u8 dma_stat = hwif->INB(hwif->dma_status); + u8 dma_stat = inb(hwif->dma_status); (void) pci_read_config_byte(dev, MRDMODE, &dma_alt_stat); #ifdef DEBUG @@ -576,13 +561,13 @@ static int cmd646_1_ide_dma_end (ide_drive_t *drive) drive->waiting_for_dma = 0; /* get DMA status */ - dma_stat = hwif->INB(hwif->dma_status); + dma_stat = inb(hwif->dma_status); /* read DMA command state */ - dma_cmd = hwif->INB(hwif->dma_command); + dma_cmd = inb(hwif->dma_command); /* stop DMA */ - hwif->OUTB((dma_cmd & ~1), hwif->dma_command); + outb(dma_cmd & ~1, hwif->dma_command); /* clear the INTR & ERROR bits */ - hwif->OUTB(dma_stat|6, hwif->dma_status); + outb(dma_stat | 6, hwif->dma_status); /* and free any DMA resources */ ide_destroy_dmatable(drive); /* verify good DMA status */ diff --git a/drivers/ide/pci/cs5520.c b/drivers/ide/pci/cs5520.c index ba6786aabf3b..400859a839f7 100644 --- a/drivers/ide/pci/cs5520.c +++ b/drivers/ide/pci/cs5520.c @@ -132,12 +132,11 @@ static void cs5520_tune_drive(ide_drive_t *drive, u8 pio) static int cs5520_config_drive_xfer_rate(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); - /* Tune the drive for PIO modes up to PIO 4 */ cs5520_tune_drive(drive, 4); + /* Then tell the core to use DMA operations */ - return hwif->ide_dma_on(drive); + return 0; } /* diff --git a/drivers/ide/pci/cs5530.c b/drivers/ide/pci/cs5530.c index 9bf5fdfc5b1f..b2d7c132ef4b 100644 --- a/drivers/ide/pci/cs5530.c +++ b/drivers/ide/pci/cs5530.c @@ -81,8 +81,8 @@ static void cs5530_tuneproc (ide_drive_t *drive, u8 pio) /* pio=255 means "autot pio = ide_get_best_pio_mode(drive, pio, 4, NULL); if (!cs5530_set_xfer_mode(drive, modes[pio])) { - format = (hwif->INL(basereg+4) >> 31) & 1; - hwif->OUTL(cs5530_pio_timings[format][pio], + format = (inl(basereg + 4) >> 31) & 1; + outl(cs5530_pio_timings[format][pio], basereg+(drive->select.b.unit<<3)); } } @@ -103,16 +103,13 @@ static int cs5530_config_dma (ide_drive_t *drive) int unit = drive->select.b.unit; ide_drive_t *mate = &hwif->drives[unit^1]; struct hd_driveid *id = drive->id; - unsigned int reg, timings; + unsigned int reg, timings = 0; unsigned long basereg; /* * Default to DMA-off in case we run into trouble here. */ - hwif->ide_dma_off_quietly(drive); - /* turn off DMA while we fiddle */ - hwif->ide_dma_host_off(drive); - /* clear DMA_capable bit */ + hwif->dma_off_quietly(drive); /* * The CS5530 specifies that two drives sharing a cable cannot @@ -182,30 +179,24 @@ static int cs5530_config_dma (ide_drive_t *drive) case XFER_MW_DMA_1: timings = 0x00012121; break; case XFER_MW_DMA_2: timings = 0x00002020; break; default: - printk(KERN_ERR "%s: cs5530_config_dma: huh? mode=%02x\n", - drive->name, mode); - return 1; /* failure */ + BUG(); + break; } basereg = CS5530_BASEREG(hwif); - reg = hwif->INL(basereg+4); /* get drive0 config register */ + reg = inl(basereg + 4); /* get drive0 config register */ timings |= reg & 0x80000000; /* preserve PIO format bit */ if (unit == 0) { /* are we configuring drive0? */ - hwif->OUTL(timings, basereg+4); /* write drive0 config register */ + outl(timings, basereg + 4); /* write drive0 config register */ } else { if (timings & 0x00100000) reg |= 0x00100000; /* enable UDMA timings for both drives */ else reg &= ~0x00100000; /* disable UDMA timings for both drives */ - hwif->OUTL(reg, basereg+4); /* write drive0 config register */ - hwif->OUTL(timings, basereg+12); /* write drive1 config register */ + outl(reg, basereg + 4); /* write drive0 config register */ + outl(timings, basereg + 12); /* write drive1 config register */ } - (void) hwif->ide_dma_host_on(drive); - /* set DMA_capable bit */ - /* - * Finally, turn DMA on in software, and exit. - */ - return hwif->ide_dma_on(drive); /* success */ + return 0; /* success */ } /** @@ -321,17 +312,17 @@ static void __devinit init_hwif_cs5530 (ide_hwif_t *hwif) hwif->tuneproc = &cs5530_tuneproc; basereg = CS5530_BASEREG(hwif); - d0_timings = hwif->INL(basereg+0); + d0_timings = inl(basereg + 0); if (CS5530_BAD_PIO(d0_timings)) { /* PIO timings not initialized? */ - hwif->OUTL(cs5530_pio_timings[(d0_timings>>31)&1][0], basereg+0); + outl(cs5530_pio_timings[(d0_timings >> 31) & 1][0], basereg + 0); if (!hwif->drives[0].autotune) hwif->drives[0].autotune = 1; /* needs autotuning later */ } - if (CS5530_BAD_PIO(hwif->INL(basereg+8))) { - /* PIO timings not initialized? */ - hwif->OUTL(cs5530_pio_timings[(d0_timings>>31)&1][0], basereg+8); + if (CS5530_BAD_PIO(inl(basereg + 8))) { + /* PIO timings not initialized? */ + outl(cs5530_pio_timings[(d0_timings >> 31) & 1][0], basereg + 8); if (!hwif->drives[1].autotune) hwif->drives[1].autotune = 1; /* needs autotuning later */ diff --git a/drivers/ide/pci/cs5535.c b/drivers/ide/pci/cs5535.c index 5c5aec28e671..45f43efbf92c 100644 --- a/drivers/ide/pci/cs5535.c +++ b/drivers/ide/pci/cs5535.c @@ -195,28 +195,19 @@ static int cs5535_config_drive_for_dma(ide_drive_t *drive) static int cs5535_dma_check(ide_drive_t *drive) { - ide_hwif_t *hwif = drive->hwif; - struct hd_driveid *id = drive->id; u8 speed; drive->init_speed = 0; - if ((id->capability & 1) && drive->autodma) { - if (ide_use_dma(drive)) { - if (cs5535_config_drive_for_dma(drive)) - return hwif->ide_dma_on(drive); - } - - goto fast_ata_pio; + if (ide_use_dma(drive) && cs5535_config_drive_for_dma(drive)) + return 0; - } else if ((id->capability & 8) || (id->field_valid & 2)) { -fast_ata_pio: + if (ide_use_fast_pio(drive)) { speed = ide_get_best_pio_mode(drive, 255, 4, NULL); cs5535_set_drive(drive, speed); - return hwif->ide_dma_off_quietly(drive); } - /* IORDY not supported */ - return 0; + + return -1; } static u8 __devinit cs5535_cable_detect(struct pci_dev *dev) diff --git a/drivers/ide/pci/cy82c693.c b/drivers/ide/pci/cy82c693.c index 9eafcbf444f4..103b9db97853 100644 --- a/drivers/ide/pci/cy82c693.c +++ b/drivers/ide/pci/cy82c693.c @@ -197,8 +197,8 @@ static void cy82c693_dma_enable (ide_drive_t *drive, int mode, int single) #if CY82C693_DEBUG_LOGS /* for debug let's show the previous values */ - HWIF(drive)->OUTB(index, CY82_INDEX_PORT); - data = HWIF(drive)->INB(CY82_DATA_PORT); + outb(index, CY82_INDEX_PORT); + data = inb(CY82_DATA_PORT); printk (KERN_INFO "%s (ch=%d, dev=%d): DMA mode is %d (single=%d)\n", drive->name, HWIF(drive)->channel, drive->select.b.unit, @@ -207,8 +207,8 @@ static void cy82c693_dma_enable (ide_drive_t *drive, int mode, int single) data = (u8)mode|(u8)(single<<2); - HWIF(drive)->OUTB(index, CY82_INDEX_PORT); - HWIF(drive)->OUTB(data, CY82_DATA_PORT); + outb(index, CY82_INDEX_PORT); + outb(data, CY82_DATA_PORT); #if CY82C693_DEBUG_INFO printk(KERN_INFO "%s (ch=%d, dev=%d): set DMA mode to %d (single=%d)\n", @@ -227,8 +227,8 @@ static void cy82c693_dma_enable (ide_drive_t *drive, int mode, int single) */ data = BUSMASTER_TIMEOUT; - HWIF(drive)->OUTB(CY82_INDEX_TIMEOUT, CY82_INDEX_PORT); - HWIF(drive)->OUTB(data, CY82_DATA_PORT); + outb(CY82_INDEX_TIMEOUT, CY82_INDEX_PORT); + outb(data, CY82_DATA_PORT); #if CY82C693_DEBUG_INFO printk (KERN_INFO "%s: Set IDE Bus Master TimeOut Register to 0x%X\n", @@ -478,21 +478,18 @@ static void __devinit init_iops_cy82c693(ide_hwif_t *hwif) } } -static ide_pci_device_t cy82c693_chipsets[] __devinitdata = { - { /* 0 */ - .name = "CY82C693", - .init_chipset = init_chipset_cy82c693, - .init_iops = init_iops_cy82c693, - .init_hwif = init_hwif_cy82c693, - .channels = 1, - .autodma = AUTODMA, - .bootable = ON_BOARD, - } +static ide_pci_device_t cy82c693_chipset __devinitdata = { + .name = "CY82C693", + .init_chipset = init_chipset_cy82c693, + .init_iops = init_iops_cy82c693, + .init_hwif = init_hwif_cy82c693, + .channels = 1, + .autodma = AUTODMA, + .bootable = ON_BOARD, }; static int __devinit cy82c693_init_one(struct pci_dev *dev, const struct pci_device_id *id) { - ide_pci_device_t *d = &cy82c693_chipsets[id->driver_data]; struct pci_dev *dev2; int ret = -ENODEV; @@ -501,7 +498,7 @@ static int __devinit cy82c693_init_one(struct pci_dev *dev, const struct pci_dev if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && PCI_FUNC(dev->devfn) == 1) { dev2 = pci_get_slot(dev->bus, dev->devfn + 1); - ret = ide_setup_pci_devices(dev, dev2, d); + ret = ide_setup_pci_devices(dev, dev2, &cy82c693_chipset); /* We leak pci refs here but thats ok - we can't be unloaded */ } return ret; diff --git a/drivers/ide/pci/hpt34x.c b/drivers/ide/pci/hpt34x.c index ce7b08f08a09..924eaa3a5708 100644 --- a/drivers/ide/pci/hpt34x.c +++ b/drivers/ide/pci/hpt34x.c @@ -48,19 +48,6 @@ static u8 hpt34x_ratemask (ide_drive_t *drive) return 1; } -static void hpt34x_clear_chipset (ide_drive_t *drive) -{ - struct pci_dev *dev = HWIF(drive)->pci_dev; - u32 reg1 = 0, tmp1 = 0, reg2 = 0, tmp2 = 0; - - pci_read_config_dword(dev, 0x44, ®1); - pci_read_config_dword(dev, 0x48, ®2); - tmp1 = ((0x00 << (3*drive->dn)) | (reg1 & ~(7 << (3*drive->dn)))); - tmp2 = (reg2 & ~(0x11 << drive->dn)); - pci_write_config_dword(dev, 0x44, tmp1); - pci_write_config_dword(dev, 0x48, tmp2); -} - static int hpt34x_tune_chipset (ide_drive_t *drive, u8 xferspeed) { struct pci_dev *dev = HWIF(drive)->pci_dev; @@ -81,7 +68,7 @@ static int hpt34x_tune_chipset (ide_drive_t *drive, u8 xferspeed) pci_read_config_dword(dev, 0x44, ®1); pci_read_config_dword(dev, 0x48, ®2); tmp1 = ((lo_speed << (3*drive->dn)) | (reg1 & ~(7 << (3*drive->dn)))); - tmp2 = ((hi_speed << drive->dn) | reg2); + tmp2 = ((hi_speed << drive->dn) | (reg2 & ~(0x11 << drive->dn))); pci_write_config_dword(dev, 0x44, tmp1); pci_write_config_dword(dev, 0x48, tmp2); @@ -99,7 +86,6 @@ static int hpt34x_tune_chipset (ide_drive_t *drive, u8 xferspeed) static void hpt34x_tune_drive (ide_drive_t *drive, u8 pio) { pio = ide_get_best_pio_mode(drive, pio, 5, NULL); - hpt34x_clear_chipset(drive); (void) hpt34x_tune_chipset(drive, (XFER_PIO_0 + pio)); } @@ -117,38 +103,25 @@ static int config_chipset_for_dma (ide_drive_t *drive) if (!(speed)) return 0; - hpt34x_clear_chipset(drive); (void) hpt34x_tune_chipset(drive, speed); return ide_dma_enable(drive); } static int hpt34x_config_drive_xfer_rate (ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); - struct hd_driveid *id = drive->id; - drive->init_speed = 0; - if (id && (id->capability & 1) && drive->autodma) { - - if (ide_use_dma(drive)) { - if (config_chipset_for_dma(drive)) + if (ide_use_dma(drive) && config_chipset_for_dma(drive)) #ifndef CONFIG_HPT34X_AUTODMA - return hwif->ide_dma_off_quietly(drive); + return -1; #else - return hwif->ide_dma_on(drive); + return 0; #endif - } - - goto fast_ata_pio; - } else if ((id->capability & 8) || (id->field_valid & 2)) { -fast_ata_pio: + if (ide_use_fast_pio(drive)) hpt34x_tune_drive(drive, 255); - return hwif->ide_dma_off_quietly(drive); - } - /* IORDY not supported */ - return 0; + + return -1; } /* @@ -209,7 +182,6 @@ static void __devinit init_hwif_hpt34x(ide_hwif_t *hwif) hwif->tuneproc = &hpt34x_tune_drive; hwif->speedproc = &hpt34x_tune_chipset; - hwif->no_dsc = 1; hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; diff --git a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c index 05be8fadda7a..60ecdc258c7c 100644 --- a/drivers/ide/pci/hpt366.c +++ b/drivers/ide/pci/hpt366.c @@ -736,24 +736,15 @@ static void hpt3xx_maskproc(ide_drive_t *drive, int mask) static int hpt366_config_drive_xfer_rate(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); - struct hd_driveid *id = drive->id; - drive->init_speed = 0; - if ((id->capability & 1) && drive->autodma) { - if (ide_use_dma(drive) && config_chipset_for_dma(drive)) - return hwif->ide_dma_on(drive); - - goto fast_ata_pio; + if (ide_use_dma(drive) && config_chipset_for_dma(drive)) + return 0; - } else if ((id->capability & 8) || (id->field_valid & 2)) { -fast_ata_pio: + if (ide_use_fast_pio(drive)) hpt3xx_tune_drive(drive, 255); - return hwif->ide_dma_off_quietly(drive); - } - /* IORDY not supported */ - return 0; + + return -1; } /* @@ -841,7 +832,7 @@ static int hpt374_ide_dma_test_irq(ide_drive_t *drive) return 0; } - dma_stat = hwif->INB(hwif->dma_status); + dma_stat = inb(hwif->dma_status); /* return 1 if INTR asserted */ if (dma_stat & 4) return 1; @@ -1391,9 +1382,6 @@ static void __devinit init_dma_hpt366(ide_hwif_t *hwif, unsigned long dmabase) u8 dma_new = 0, dma_old = 0; unsigned long flags; - if (!dmabase) - return; - dma_old = hwif->INB(dmabase + 2); local_irq_save(flags); diff --git a/drivers/ide/pci/it8213.c b/drivers/ide/pci/it8213.c index 63248b6909fa..424f00bb160d 100644 --- a/drivers/ide/pci/it8213.c +++ b/drivers/ide/pci/it8213.c @@ -244,17 +244,15 @@ static int config_chipset_for_dma (ide_drive_t *drive) static int it8213_config_drive_for_dma (ide_drive_t *drive) { - ide_hwif_t *hwif = drive->hwif; + u8 pio; - if (ide_use_dma(drive)) { - if (config_chipset_for_dma(drive)) - return hwif->ide_dma_on(drive); - } + if (ide_use_dma(drive) && config_chipset_for_dma(drive)) + return 0; - hwif->speedproc(drive, XFER_PIO_0 - + ide_get_best_pio_mode(drive, 255, 4, NULL)); + pio = ide_get_best_pio_mode(drive, 255, 4, NULL); + it8213_tune_chipset(drive, XFER_PIO_0 + pio); - return hwif->ide_dma_off_quietly(drive); + return -1; } /** diff --git a/drivers/ide/pci/it821x.c b/drivers/ide/pci/it821x.c index e9bad185968a..a132767f7d90 100644 --- a/drivers/ide/pci/it821x.c +++ b/drivers/ide/pci/it821x.c @@ -520,14 +520,12 @@ static int config_chipset_for_dma (ide_drive_t *drive) static int it821x_config_drive_for_dma (ide_drive_t *drive) { - ide_hwif_t *hwif = drive->hwif; + if (ide_use_dma(drive) && config_chipset_for_dma(drive)) + return 0; - if (ide_use_dma(drive)) { - if (config_chipset_for_dma(drive)) - return hwif->ide_dma_on(drive); - } config_it821x_chipset_for_pio(drive, 1); - return hwif->ide_dma_off_quietly(drive); + + return -1; } /** @@ -608,11 +606,11 @@ static void __devinit it821x_fixups(ide_hwif_t *hwif) printk(".\n"); /* Now the core code will have wrongly decided no DMA so we need to fix this */ - hwif->ide_dma_off_quietly(drive); + hwif->dma_off_quietly(drive); #ifdef CONFIG_IDEDMA_ONLYDISK if (drive->media == ide_disk) #endif - hwif->ide_dma_check(drive); + ide_set_dma(drive); } else { /* Non RAID volume. Fixups to stop the core code doing unsupported things */ diff --git a/drivers/ide/pci/jmicron.c b/drivers/ide/pci/jmicron.c index f07bbbed1778..53f25500c22b 100644 --- a/drivers/ide/pci/jmicron.c +++ b/drivers/ide/pci/jmicron.c @@ -147,7 +147,9 @@ static int config_chipset_for_dma (ide_drive_t *drive) { u8 speed = ide_dma_speed(drive, jmicron_ratemask(drive)); - config_jmicron_chipset_for_pio(drive, !speed); + if (!speed) + return 0; + jmicron_tune_chipset(drive, speed); return ide_dma_enable(drive); } @@ -162,14 +164,12 @@ static int config_chipset_for_dma (ide_drive_t *drive) static int jmicron_config_drive_for_dma (ide_drive_t *drive) { - ide_hwif_t *hwif = drive->hwif; + if (ide_use_dma(drive) && config_chipset_for_dma(drive)) + return 0; - if (ide_use_dma(drive)) { - if (config_chipset_for_dma(drive)) - return hwif->ide_dma_on(drive); - } config_jmicron_chipset_for_pio(drive, 1); - return hwif->ide_dma_off_quietly(drive); + + return -1; } /** diff --git a/drivers/ide/pci/ns87415.c b/drivers/ide/pci/ns87415.c index 8aaea4ea5549..b310c4f51077 100644 --- a/drivers/ide/pci/ns87415.c +++ b/drivers/ide/pci/ns87415.c @@ -166,10 +166,10 @@ static int ns87415_ide_dma_end (ide_drive_t *drive) /* get dma command mode */ dma_cmd = hwif->INB(hwif->dma_command); /* stop DMA */ - hwif->OUTB(dma_cmd & ~1, hwif->dma_command); + outb(dma_cmd & ~1, hwif->dma_command); /* from ERRATA: clear the INTR & ERROR bits */ dma_cmd = hwif->INB(hwif->dma_command); - hwif->OUTB(dma_cmd|6, hwif->dma_command); + outb(dma_cmd | 6, hwif->dma_command); /* and free any DMA resources */ ide_destroy_dmatable(drive); /* verify good DMA status */ @@ -190,7 +190,8 @@ static int ns87415_ide_dma_setup(ide_drive_t *drive) static int ns87415_ide_dma_check (ide_drive_t *drive) { if (drive->media != ide_disk) - return HWIF(drive)->ide_dma_off_quietly(drive); + return -1; + return __ide_dma_check(drive); } @@ -243,9 +244,9 @@ static void __devinit init_hwif_ns87415 (ide_hwif_t *hwif) * to SELECT_DRIVE() properly during first probe_hwif(). */ timeout = 10000; - hwif->OUTB(12, hwif->io_ports[IDE_CONTROL_OFFSET]); + outb(12, hwif->io_ports[IDE_CONTROL_OFFSET]); udelay(10); - hwif->OUTB(8, hwif->io_ports[IDE_CONTROL_OFFSET]); + outb(8, hwif->io_ports[IDE_CONTROL_OFFSET]); do { udelay(50); stat = hwif->INB(hwif->io_ports[IDE_STATUS_OFFSET]); @@ -263,7 +264,7 @@ static void __devinit init_hwif_ns87415 (ide_hwif_t *hwif) if (!hwif->dma_base) return; - hwif->OUTB(0x60, hwif->dma_status); + outb(0x60, hwif->dma_status); hwif->dma_setup = &ns87415_ide_dma_setup; hwif->ide_dma_check = &ns87415_ide_dma_check; hwif->ide_dma_end = &ns87415_ide_dma_end; diff --git a/drivers/ide/pci/opti621.c b/drivers/ide/pci/opti621.c index 22bbf613f948..9ca60dd2185e 100644 --- a/drivers/ide/pci/opti621.c +++ b/drivers/ide/pci/opti621.c @@ -176,34 +176,35 @@ static int cmpt_clk(int time, int bus_speed) return ((time*bus_speed+999)/1000); } -static void write_reg(ide_hwif_t *hwif, u8 value, int reg) /* Write value to register reg, base of register * is at reg_base (0x1f0 primary, 0x170 secondary, * if not changed by PCI configuration). * This is from setupvic.exe program. */ +static void write_reg(u8 value, int reg) { - hwif->INW(reg_base+1); - hwif->INW(reg_base+1); - hwif->OUTB(3, reg_base+2); - hwif->OUTB(value, reg_base+reg); - hwif->OUTB(0x83, reg_base+2); + inw(reg_base + 1); + inw(reg_base + 1); + outb(3, reg_base + 2); + outb(value, reg_base + reg); + outb(0x83, reg_base + 2); } -static u8 read_reg(ide_hwif_t *hwif, int reg) /* Read value from register reg, base of register * is at reg_base (0x1f0 primary, 0x170 secondary, * if not changed by PCI configuration). * This is from setupvic.exe program. */ +static u8 read_reg(int reg) { u8 ret = 0; - hwif->INW(reg_base+1); - hwif->INW(reg_base+1); - hwif->OUTB(3, reg_base+2); - ret = hwif->INB(reg_base+reg); - hwif->OUTB(0x83, reg_base+2); + inw(reg_base + 1); + inw(reg_base + 1); + outb(3, reg_base + 2); + ret = inb(reg_base + reg); + outb(0x83, reg_base + 2); + return ret; } @@ -286,39 +287,39 @@ static void opti621_tune_drive (ide_drive_t *drive, u8 pio) reg_base = hwif->io_ports[IDE_DATA_OFFSET]; /* allow Register-B */ - hwif->OUTB(0xc0, reg_base+CNTRL_REG); + outb(0xc0, reg_base + CNTRL_REG); /* hmm, setupvic.exe does this ;-) */ - hwif->OUTB(0xff, reg_base+5); + outb(0xff, reg_base + 5); /* if reads 0xff, adapter not exist? */ - (void) hwif->INB(reg_base+CNTRL_REG); + (void)inb(reg_base + CNTRL_REG); /* if reads 0xc0, no interface exist? */ - read_reg(hwif, CNTRL_REG); + read_reg(CNTRL_REG); /* read version, probably 0 */ - read_reg(hwif, STRAP_REG); + read_reg(STRAP_REG); /* program primary drive */ - /* select Index-0 for Register-A */ - write_reg(hwif, 0, MISC_REG); - /* set read cycle timings */ - write_reg(hwif, cycle1, READ_REG); - /* set write cycle timings */ - write_reg(hwif, cycle1, WRITE_REG); + /* select Index-0 for Register-A */ + write_reg(0, MISC_REG); + /* set read cycle timings */ + write_reg(cycle1, READ_REG); + /* set write cycle timings */ + write_reg(cycle1, WRITE_REG); /* program secondary drive */ - /* select Index-1 for Register-B */ - write_reg(hwif, 1, MISC_REG); - /* set read cycle timings */ - write_reg(hwif, cycle2, READ_REG); - /* set write cycle timings */ - write_reg(hwif, cycle2, WRITE_REG); + /* select Index-1 for Register-B */ + write_reg(1, MISC_REG); + /* set read cycle timings */ + write_reg(cycle2, READ_REG); + /* set write cycle timings */ + write_reg(cycle2, WRITE_REG); /* use Register-A for drive 0 */ /* use Register-B for drive 1 */ - write_reg(hwif, 0x85, CNTRL_REG); + write_reg(0x85, CNTRL_REG); /* set address setup, DRDY timings, */ /* and read prefetch for both drives */ - write_reg(hwif, misc, MISC_REG); + write_reg(misc, MISC_REG); spin_unlock_irqrestore(&ide_lock, flags); } diff --git a/drivers/ide/pci/pdc202xx_new.c b/drivers/ide/pci/pdc202xx_new.c index 236a03144a27..6ceb25bc5a7b 100644 --- a/drivers/ide/pci/pdc202xx_new.c +++ b/drivers/ide/pci/pdc202xx_new.c @@ -101,8 +101,8 @@ static u8 get_indexed_reg(ide_hwif_t *hwif, u8 index) { u8 value; - hwif->OUTB(index, hwif->dma_vendor1); - value = hwif->INB(hwif->dma_vendor3); + outb(index, hwif->dma_vendor1); + value = inb(hwif->dma_vendor3); DBG("index[%02X] value[%02X]\n", index, value); return value; @@ -115,8 +115,8 @@ static u8 get_indexed_reg(ide_hwif_t *hwif, u8 index) */ static void set_indexed_reg(ide_hwif_t *hwif, u8 index, u8 value) { - hwif->OUTB(index, hwif->dma_vendor1); - hwif->OUTB(value, hwif->dma_vendor3); + outb(index, hwif->dma_vendor1); + outb(value, hwif->dma_vendor3); DBG("index[%02X] value[%02X]\n", index, value); } @@ -281,25 +281,15 @@ static int config_chipset_for_dma(ide_drive_t *drive) static int pdcnew_config_drive_xfer_rate(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); - struct hd_driveid *id = drive->id; - drive->init_speed = 0; - if ((id->capability & 1) && drive->autodma) { - - if (ide_use_dma(drive) && config_chipset_for_dma(drive)) - return hwif->ide_dma_on(drive); + if (ide_use_dma(drive) && config_chipset_for_dma(drive)) + return 0; - goto fast_ata_pio; + if (ide_use_fast_pio(drive)) + pdcnew_tune_drive(drive, 255); - } else if ((id->capability & 8) || (id->field_valid & 2)) { -fast_ata_pio: - hwif->tuneproc(drive, 255); - return hwif->ide_dma_off_quietly(drive); - } - /* IORDY not supported */ - return 0; + return -1; } static int pdcnew_quirkproc(ide_drive_t *drive) diff --git a/drivers/ide/pci/pdc202xx_old.c b/drivers/ide/pci/pdc202xx_old.c index 730e8d1ec2f5..a7a639fe1eaf 100644 --- a/drivers/ide/pci/pdc202xx_old.c +++ b/drivers/ide/pci/pdc202xx_old.c @@ -2,6 +2,7 @@ * linux/drivers/ide/pci/pdc202xx_old.c Version 0.36 Sept 11, 2002 * * Copyright (C) 1998-2002 Andre Hedrick <andre@linux-ide.org> + * Copyright (C) 2006-2007 MontaVista Software, Inc. * * Promise Ultra33 cards with BIOS v1.20 through 1.28 will need this * compiled into the kernel if you have more than one card installed. @@ -216,21 +217,10 @@ static int pdc202xx_tune_chipset (ide_drive_t *drive, u8 xferspeed) } -/* 0 1 2 3 4 5 6 7 8 - * 960, 480, 390, 300, 240, 180, 120, 90, 60 - * 180, 150, 120, 90, 60 - * DMA_Speed - * 180, 120, 90, 90, 90, 60, 30 - * 11, 5, 4, 3, 2, 1, 0 - */ -static void config_chipset_for_pio (ide_drive_t *drive, u8 pio) +static void pdc202xx_tune_drive(ide_drive_t *drive, u8 pio) { - u8 speed = 0; - - if (pio == 5) pio = 4; - speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, pio, NULL); - - pdc202xx_tune_chipset(drive, speed); + pio = ide_get_best_pio_mode(drive, pio, 4, NULL); + pdc202xx_tune_chipset(drive, XFER_PIO_0 + pio); } static u8 pdc202xx_old_cable_detect (ide_hwif_t *hwif) @@ -250,17 +240,17 @@ static u8 pdc202xx_old_cable_detect (ide_hwif_t *hwif) static void pdc_old_enable_66MHz_clock(ide_hwif_t *hwif) { unsigned long clock_reg = hwif->dma_master + 0x11; - u8 clock = hwif->INB(clock_reg); + u8 clock = inb(clock_reg); - hwif->OUTB(clock | (hwif->channel ? 0x08 : 0x02), clock_reg); + outb(clock | (hwif->channel ? 0x08 : 0x02), clock_reg); } static void pdc_old_disable_66MHz_clock(ide_hwif_t *hwif) { unsigned long clock_reg = hwif->dma_master + 0x11; - u8 clock = hwif->INB(clock_reg); + u8 clock = inb(clock_reg); - hwif->OUTB(clock & ~(hwif->channel ? 0x08 : 0x02), clock_reg); + outb(clock & ~(hwif->channel ? 0x08 : 0x02), clock_reg); } static int config_chipset_for_dma (ide_drive_t *drive) @@ -332,27 +322,15 @@ chipset_is_set: static int pdc202xx_config_drive_xfer_rate (ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); - struct hd_driveid *id = drive->id; - drive->init_speed = 0; - if (id && (id->capability & 1) && drive->autodma) { - - if (ide_use_dma(drive)) { - if (config_chipset_for_dma(drive)) - return hwif->ide_dma_on(drive); - } + if (ide_use_dma(drive) && config_chipset_for_dma(drive)) + return 0; - goto fast_ata_pio; + if (ide_use_fast_pio(drive)) + pdc202xx_tune_drive(drive, 255); - } else if ((id->capability & 8) || (id->field_valid & 2)) { -fast_ata_pio: - hwif->tuneproc(drive, 5); - return hwif->ide_dma_off_quietly(drive); - } - /* IORDY not supported */ - return 0; + return -1; } static int pdc202xx_quirkproc (ide_drive_t *drive) @@ -375,14 +353,14 @@ static void pdc202xx_old_ide_dma_start(ide_drive_t *drive) unsigned long high_16 = hwif->dma_master; unsigned long atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x20); u32 word_count = 0; - u8 clock = hwif->INB(high_16 + 0x11); + u8 clock = inb(high_16 + 0x11); - hwif->OUTB(clock|(hwif->channel ? 0x08 : 0x02), high_16+0x11); + outb(clock | (hwif->channel ? 0x08 : 0x02), high_16 + 0x11); word_count = (rq->nr_sectors << 8); word_count = (rq_data_dir(rq) == READ) ? word_count | 0x05000000 : word_count | 0x06000000; - hwif->OUTL(word_count, atapi_reg); + outl(word_count, atapi_reg); } ide_dma_start(drive); } @@ -395,9 +373,9 @@ static int pdc202xx_old_ide_dma_end(ide_drive_t *drive) unsigned long atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x20); u8 clock = 0; - hwif->OUTL(0, atapi_reg); /* zero out extra */ - clock = hwif->INB(high_16 + 0x11); - hwif->OUTB(clock & ~(hwif->channel ? 0x08:0x02), high_16+0x11); + outl(0, atapi_reg); /* zero out extra */ + clock = inb(high_16 + 0x11); + outb(clock & ~(hwif->channel ? 0x08:0x02), high_16 + 0x11); } if (drive->current_speed > XFER_UDMA_2) pdc_old_disable_66MHz_clock(drive->hwif); @@ -408,8 +386,8 @@ static int pdc202xx_old_ide_dma_test_irq(ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); unsigned long high_16 = hwif->dma_master; - u8 dma_stat = hwif->INB(hwif->dma_status); - u8 sc1d = hwif->INB((high_16 + 0x001d)); + u8 dma_stat = inb(hwif->dma_status); + u8 sc1d = inb(high_16 + 0x001d); if (hwif->channel) { /* bit7: Error, bit6: Interrupting, bit5: FIFO Full, bit4: FIFO Empty */ @@ -445,11 +423,11 @@ static int pdc202xx_ide_dma_timeout(ide_drive_t *drive) static void pdc202xx_reset_host (ide_hwif_t *hwif) { unsigned long high_16 = hwif->dma_master; - u8 udma_speed_flag = hwif->INB(high_16|0x001f); + u8 udma_speed_flag = inb(high_16 | 0x001f); - hwif->OUTB((udma_speed_flag | 0x10), (high_16|0x001f)); + outb(udma_speed_flag | 0x10, high_16 | 0x001f); mdelay(100); - hwif->OUTB((udma_speed_flag & ~0x10), (high_16|0x001f)); + outb(udma_speed_flag & ~0x10, high_16 | 0x001f); mdelay(2000); /* 2 seconds ?! */ printk(KERN_WARNING "PDC202XX: %s channel reset.\n", @@ -463,7 +441,7 @@ static void pdc202xx_reset (ide_drive_t *drive) pdc202xx_reset_host(hwif); pdc202xx_reset_host(mate); - hwif->tuneproc(drive, 5); + pdc202xx_tune_drive(drive, 255); } static unsigned int __devinit init_chipset_pdc202xx(struct pci_dev *dev, @@ -490,7 +468,7 @@ static void __devinit init_hwif_pdc202xx(ide_hwif_t *hwif) hwif->rqsize = 256; hwif->autodma = 0; - hwif->tuneproc = &config_chipset_for_pio; + hwif->tuneproc = &pdc202xx_tune_drive; hwif->quirkproc = &pdc202xx_quirkproc; if (hwif->pci_dev->device != PCI_DEVICE_ID_PROMISE_20246) @@ -537,9 +515,9 @@ static void __devinit init_dma_pdc202xx(ide_hwif_t *hwif, unsigned long dmabase) return; } - udma_speed_flag = hwif->INB((dmabase|0x1f)); - primary_mode = hwif->INB((dmabase|0x1a)); - secondary_mode = hwif->INB((dmabase|0x1b)); + udma_speed_flag = inb(dmabase | 0x1f); + primary_mode = inb(dmabase | 0x1a); + secondary_mode = inb(dmabase | 0x1b); printk(KERN_INFO "%s: (U)DMA Burst Bit %sABLED " \ "Primary %s Mode " \ "Secondary %s Mode.\n", hwif->cds->name, @@ -552,30 +530,10 @@ static void __devinit init_dma_pdc202xx(ide_hwif_t *hwif, unsigned long dmabase) printk(KERN_INFO "%s: FORCING BURST BIT 0x%02x->0x%02x ", hwif->cds->name, udma_speed_flag, (udma_speed_flag|1)); - hwif->OUTB(udma_speed_flag|1,(dmabase|0x1f)); - printk("%sACTIVE\n", - (hwif->INB(dmabase|0x1f)&1) ? "":"IN"); + outb(udma_speed_flag | 1, dmabase | 0x1f); + printk("%sACTIVE\n", (inb(dmabase | 0x1f) & 1) ? "" : "IN"); } #endif /* CONFIG_PDC202XX_BURST */ -#ifdef CONFIG_PDC202XX_MASTER - if (!(primary_mode & 1)) { - printk(KERN_INFO "%s: FORCING PRIMARY MODE BIT " - "0x%02x -> 0x%02x ", hwif->cds->name, - primary_mode, (primary_mode|1)); - hwif->OUTB(primary_mode|1, (dmabase|0x1a)); - printk("%s\n", - (hwif->INB((dmabase|0x1a)) & 1) ? "MASTER" : "PCI"); - } - - if (!(secondary_mode & 1)) { - printk(KERN_INFO "%s: FORCING SECONDARY MODE BIT " - "0x%02x -> 0x%02x ", hwif->cds->name, - secondary_mode, (secondary_mode|1)); - hwif->OUTB(secondary_mode|1, (dmabase|0x1b)); - printk("%s\n", - (hwif->INB((dmabase|0x1b)) & 1) ? "MASTER" : "PCI"); - } -#endif /* CONFIG_PDC202XX_MASTER */ ide_setup_dma(hwif, dmabase, 8); } diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c index 52cfc2ac22c1..569822f4cf55 100644 --- a/drivers/ide/pci/piix.c +++ b/drivers/ide/pci/piix.c @@ -369,7 +369,7 @@ static int piix_config_drive_for_dma (ide_drive_t *drive) * If no DMA speed was available or the chipset has DMA bugs * then disable DMA and use PIO */ - if (!speed || no_piix_dma) + if (!speed) return 0; (void) piix_tune_chipset(drive, speed); @@ -386,41 +386,28 @@ static int piix_config_drive_for_dma (ide_drive_t *drive) static int piix_config_drive_xfer_rate (ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); - struct hd_driveid *id = drive->id; - drive->init_speed = 0; - if ((id->capability & 1) && drive->autodma) { - - if (ide_use_dma(drive) && piix_config_drive_for_dma(drive)) - return hwif->ide_dma_on(drive); - - goto fast_ata_pio; + if (ide_use_dma(drive) && piix_config_drive_for_dma(drive)) + return 0; - } else if ((id->capability & 8) || (id->field_valid & 2)) { -fast_ata_pio: + if (ide_use_fast_pio(drive)) /* Find best PIO mode. */ - (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 */ - return 0; + piix_tune_chipset(drive, XFER_PIO_0 + + ide_get_best_pio_mode(drive, 255, 4, NULL)); + + return -1; } /** - * init_chipset_piix - set up the PIIX chipset - * @dev: PCI device to set up - * @name: Name of the device + * piix_is_ichx - check if ICHx + * @dev: PCI device to check * - * Initialize the PCI device as required. For the PIIX this turns - * out to be nice and simple + * returns 1 if ICHx, 0 otherwise. */ - -static unsigned int __devinit init_chipset_piix (struct pci_dev *dev, const char *name) +static int piix_is_ichx(struct pci_dev *dev) { - switch(dev->device) { + switch (dev->device) { case PCI_DEVICE_ID_INTEL_82801EB_1: case PCI_DEVICE_ID_INTEL_82801AA_1: case PCI_DEVICE_ID_INTEL_82801AB_1: @@ -438,19 +425,61 @@ static unsigned int __devinit init_chipset_piix (struct pci_dev *dev, const char case PCI_DEVICE_ID_INTEL_ICH7_21: case PCI_DEVICE_ID_INTEL_ESB2_18: case PCI_DEVICE_ID_INTEL_ICH8_6: - { - unsigned int extra = 0; - pci_read_config_dword(dev, 0x54, &extra); - pci_write_config_dword(dev, 0x54, extra|0x400); - } - default: - break; + return 1; } return 0; } /** + * init_chipset_piix - set up the PIIX chipset + * @dev: PCI device to set up + * @name: Name of the device + * + * Initialize the PCI device as required. For the PIIX this turns + * out to be nice and simple + */ + +static unsigned int __devinit init_chipset_piix (struct pci_dev *dev, const char *name) +{ + if (piix_is_ichx(dev)) { + unsigned int extra = 0; + pci_read_config_dword(dev, 0x54, &extra); + pci_write_config_dword(dev, 0x54, extra|0x400); + } + + return 0; +} + +/** + * piix_dma_clear_irq - clear BMDMA status + * @drive: IDE drive to clear + * + * Called from ide_intr() for PIO interrupts + * to clear BMDMA status as needed by ICHx + */ +static void piix_dma_clear_irq(ide_drive_t *drive) +{ + ide_hwif_t *hwif = HWIF(drive); + u8 dma_stat; + + /* clear the INTR & ERROR bits */ + dma_stat = hwif->INB(hwif->dma_status); + /* Should we force the bit as well ? */ + hwif->OUTB(dma_stat, hwif->dma_status); +} + +static int __devinit piix_cable_detect(ide_hwif_t *hwif) +{ + struct pci_dev *dev = hwif->pci_dev; + u8 reg54h = 0, mask = hwif->channel ? 0xc0 : 0x30; + + pci_read_config_byte(dev, 0x54, ®54h); + + return (reg54h & mask) ? 1 : 0; +} + +/** * init_hwif_piix - fill in the hwif for the PIIX * @hwif: IDE interface * @@ -460,9 +489,6 @@ static unsigned int __devinit init_chipset_piix (struct pci_dev *dev, const char static void __devinit init_hwif_piix(ide_hwif_t *hwif) { - u8 reg54h = 0, reg55h = 0, ata66 = 0; - u8 mask = hwif->channel ? 0xc0 : 0x30; - #ifndef CONFIG_IA64 if (!hwif->irq) hwif->irq = hwif->channel ? 15 : 14; @@ -472,10 +498,6 @@ static void __devinit init_hwif_piix(ide_hwif_t *hwif) /* This is a painful system best to let it self tune for now */ return; } - /* ESB2 appears to generate spurious DMA interrupts in PIO mode - when in native mode */ - if (hwif->pci_dev->device == PCI_DEVICE_ID_INTEL_ESB2_18) - hwif->atapi_irq_bogon = 1; hwif->autodma = 0; hwif->tuneproc = &piix_tune_drive; @@ -486,15 +508,16 @@ static void __devinit init_hwif_piix(ide_hwif_t *hwif) if (!hwif->dma_base) return; + /* ICHx need to clear the bmdma status for all interrupts */ + if (piix_is_ichx(hwif->pci_dev)) + hwif->ide_dma_clear_irq = &piix_dma_clear_irq; + hwif->atapi_dma = 1; hwif->ultra_mask = 0x3f; hwif->mwdma_mask = 0x06; hwif->swdma_mask = 0x04; switch(hwif->pci_dev->device) { - case PCI_DEVICE_ID_INTEL_82371MX: - hwif->mwdma_mask = 0x80; - hwif->swdma_mask = 0x80; case PCI_DEVICE_ID_INTEL_82371FB_0: case PCI_DEVICE_ID_INTEL_82371FB_1: case PCI_DEVICE_ID_INTEL_82371SB_1: @@ -507,14 +530,14 @@ static void __devinit init_hwif_piix(ide_hwif_t *hwif) hwif->ultra_mask = 0x07; break; default: - pci_read_config_byte(hwif->pci_dev, 0x54, ®54h); - pci_read_config_byte(hwif->pci_dev, 0x55, ®55h); - ata66 = (reg54h & mask) ? 1 : 0; + if (!hwif->udma_four) + hwif->udma_four = piix_cable_detect(hwif); break; } - if (!(hwif->udma_four)) - hwif->udma_four = ata66; + if (no_piix_dma) + hwif->ultra_mask = hwif->mwdma_mask = hwif->swdma_mask = 0; + hwif->ide_dma_check = &piix_config_drive_xfer_rate; if (!noautodma) hwif->autodma = 1; diff --git a/drivers/ide/pci/sc1200.c b/drivers/ide/pci/sc1200.c index 8d762d323f8b..b5ae0c50e216 100644 --- a/drivers/ide/pci/sc1200.c +++ b/drivers/ide/pci/sc1200.c @@ -161,7 +161,7 @@ static int sc1200_config_dma2 (ide_drive_t *drive, int mode) /* * Default to DMA-off in case we run into trouble here. */ - hwif->ide_dma_off_quietly(drive); /* turn off DMA while we fiddle */ + hwif->dma_off_quietly(drive); /* turn off DMA while we fiddle */ outb(inb(hwif->dma_base+2)&~(unit?0x40:0x20), hwif->dma_base+2); /* clear DMA_capable bit */ /* @@ -241,10 +241,7 @@ static int sc1200_config_dma2 (ide_drive_t *drive, int mode) outb(inb(hwif->dma_base+2)|(unit?0x40:0x20), hwif->dma_base+2); /* set DMA_capable bit */ - /* - * Finally, turn DMA on in software, and exit. - */ - return hwif->ide_dma_on(drive); /* success */ + return 0; /* success */ } /* @@ -442,10 +439,10 @@ static int sc1200_resume (struct pci_dev *dev) ide_drive_t *drive = &(hwif->drives[d]); if (drive->present && !__ide_dma_bad_drive(drive)) { int was_using_dma = drive->using_dma; - hwif->ide_dma_off_quietly(drive); + hwif->dma_off_quietly(drive); sc1200_config_dma(drive); if (!was_using_dma && drive->using_dma) { - hwif->ide_dma_off_quietly(drive); + hwif->dma_off_quietly(drive); } } } diff --git a/drivers/ide/pci/serverworks.c b/drivers/ide/pci/serverworks.c index ea9a28a45853..dbcd37a0c652 100644 --- a/drivers/ide/pci/serverworks.c +++ b/drivers/ide/pci/serverworks.c @@ -160,7 +160,7 @@ static int svwks_tune_chipset (ide_drive_t *drive, u8 xferspeed) if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) || (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) { if (!drive->init_speed) { - u8 dma_stat = hwif->INB(hwif->dma_status); + u8 dma_stat = inb(hwif->dma_status); dma_pio: if (((ultra_enable << (7-drive->dn) & 0x80) == 0x80) && @@ -315,35 +315,15 @@ static int config_chipset_for_dma (ide_drive_t *drive) static int svwks_config_drive_xfer_rate (ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); - struct hd_driveid *id = drive->id; - drive->init_speed = 0; - if ((id->capability & 1) && drive->autodma) { - - if (ide_use_dma(drive)) { - if (config_chipset_for_dma(drive)) - return hwif->ide_dma_on(drive); - } - - goto fast_ata_pio; + if (ide_use_dma(drive) && config_chipset_for_dma(drive)) + return 0; - } else if ((id->capability & 8) || (id->field_valid & 2)) { -fast_ata_pio: + if (ide_use_fast_pio(drive)) config_chipset_for_pio(drive); - // hwif->tuneproc(drive, 5); - return hwif->ide_dma_off_quietly(drive); - } - /* IORDY not supported */ - return 0; -} - -/* This can go soon */ -static int svwks_ide_dma_end (ide_drive_t *drive) -{ - return __ide_dma_end(drive); + return -1; } static unsigned int __devinit init_chipset_svwks (struct pci_dev *dev, const char *name) @@ -537,35 +517,20 @@ static void __devinit init_hwif_svwks (ide_hwif_t *hwif) } hwif->ide_dma_check = &svwks_config_drive_xfer_rate; - if (hwif->pci_dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) - hwif->ide_dma_end = &svwks_ide_dma_end; - else if (!(hwif->udma_four)) - hwif->udma_four = ata66_svwks(hwif); + if (hwif->pci_dev->device != PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) { + if (!hwif->udma_four) + hwif->udma_four = ata66_svwks(hwif); + } if (!noautodma) hwif->autodma = 1; - dma_stat = hwif->INB(hwif->dma_status); + dma_stat = inb(hwif->dma_status); hwif->drives[0].autodma = (dma_stat & 0x20); hwif->drives[1].autodma = (dma_stat & 0x40); hwif->drives[0].autotune = (!(dma_stat & 0x20)); hwif->drives[1].autotune = (!(dma_stat & 0x40)); } -/* - * We allow the BM-DMA driver to only work on enabled interfaces. - */ -static void __devinit init_dma_svwks (ide_hwif_t *hwif, unsigned long dmabase) -{ - struct pci_dev *dev = hwif->pci_dev; - - if (((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) || - (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) && - (!(PCI_FUNC(dev->devfn) & 1)) && (hwif->channel)) - return; - - ide_setup_dma(hwif, dmabase, 8); -} - static int __devinit init_setup_svwks (struct pci_dev *dev, ide_pci_device_t *d) { return ide_setup_pci_device(dev, d); @@ -600,7 +565,6 @@ static ide_pci_device_t serverworks_chipsets[] __devinitdata = { .init_setup = init_setup_svwks, .init_chipset = init_chipset_svwks, .init_hwif = init_hwif_svwks, - .init_dma = init_dma_svwks, .channels = 2, .autodma = AUTODMA, .bootable = ON_BOARD, @@ -609,7 +573,6 @@ static ide_pci_device_t serverworks_chipsets[] __devinitdata = { .init_setup = init_setup_csb6, .init_chipset = init_chipset_svwks, .init_hwif = init_hwif_svwks, - .init_dma = init_dma_svwks, .channels = 2, .autodma = AUTODMA, .bootable = ON_BOARD, @@ -618,7 +581,6 @@ static ide_pci_device_t serverworks_chipsets[] __devinitdata = { .init_setup = init_setup_csb6, .init_chipset = init_chipset_svwks, .init_hwif = init_hwif_svwks, - .init_dma = init_dma_svwks, .channels = 1, /* 2 */ .autodma = AUTODMA, .bootable = ON_BOARD, @@ -627,7 +589,6 @@ static ide_pci_device_t serverworks_chipsets[] __devinitdata = { .init_setup = init_setup_svwks, .init_chipset = init_chipset_svwks, .init_hwif = init_hwif_svwks, - .init_dma = init_dma_svwks, .channels = 1, /* 2 */ .autodma = AUTODMA, .bootable = ON_BOARD, diff --git a/drivers/ide/pci/sgiioc4.c b/drivers/ide/pci/sgiioc4.c index b0bf01809279..fd09b295a69d 100644 --- a/drivers/ide/pci/sgiioc4.c +++ b/drivers/ide/pci/sgiioc4.c @@ -110,24 +110,24 @@ sgiioc4_init_hwif_ports(hw_regs_t * hw, unsigned long data_port, static void sgiioc4_maskproc(ide_drive_t * drive, int mask) { - ide_hwif_t *hwif = HWIF(drive); - hwif->OUTB(mask ? (drive->ctl | 2) : (drive->ctl & ~2), - IDE_CONTROL_REG); + writeb(mask ? (drive->ctl | 2) : (drive->ctl & ~2), + (void __iomem *)IDE_CONTROL_REG); } static int sgiioc4_checkirq(ide_hwif_t * hwif) { - u8 intr_reg = - hwif->INL(hwif->io_ports[IDE_IRQ_OFFSET] + IOC4_INTR_REG * 4); + unsigned long intr_addr = + hwif->io_ports[IDE_IRQ_OFFSET] + IOC4_INTR_REG * 4; - if (intr_reg & 0x03) + if ((u8)readl((void __iomem *)intr_addr) & 0x03) return 1; return 0; } +static u8 sgiioc4_INB(unsigned long); static int sgiioc4_clearirq(ide_drive_t * drive) @@ -138,21 +138,21 @@ sgiioc4_clearirq(ide_drive_t * drive) hwif->io_ports[IDE_IRQ_OFFSET] + (IOC4_INTR_REG << 2); /* Code to check for PCI error conditions */ - intr_reg = hwif->INL(other_ir); + intr_reg = readl((void __iomem *)other_ir); if (intr_reg & 0x03) { /* Valid IOC4-IDE interrupt */ /* - * Using hwif->INB to read the IDE_STATUS_REG has a side effect + * Using sgiioc4_INB to read the IDE_STATUS_REG has a side effect * of clearing the interrupt. The first read should clear it * if it is set. The second read should return a "clear" status * if it got cleared. If not, then spin for a bit trying to * clear it. */ - u8 stat = hwif->INB(IDE_STATUS_REG); + u8 stat = sgiioc4_INB(IDE_STATUS_REG); int count = 0; - stat = hwif->INB(IDE_STATUS_REG); + stat = sgiioc4_INB(IDE_STATUS_REG); while ((stat & 0x80) && (count++ < 100)) { udelay(1); - stat = hwif->INB(IDE_STATUS_REG); + stat = sgiioc4_INB(IDE_STATUS_REG); } if (intr_reg & 0x02) { @@ -161,9 +161,9 @@ sgiioc4_clearirq(ide_drive_t * drive) pci_stat_cmd_reg; pci_err_addr_low = - hwif->INL(hwif->io_ports[IDE_IRQ_OFFSET]); + readl((void __iomem *)hwif->io_ports[IDE_IRQ_OFFSET]); pci_err_addr_high = - hwif->INL(hwif->io_ports[IDE_IRQ_OFFSET] + 4); + readl((void __iomem *)(hwif->io_ports[IDE_IRQ_OFFSET] + 4)); pci_read_config_dword(hwif->pci_dev, PCI_COMMAND, &pci_stat_cmd_reg); printk(KERN_ERR @@ -180,9 +180,9 @@ sgiioc4_clearirq(ide_drive_t * drive) } /* Clear the Interrupt, Error bits on the IOC4 */ - hwif->OUTL(0x03, other_ir); + writel(0x03, (void __iomem *)other_ir); - intr_reg = hwif->INL(other_ir); + intr_reg = readl((void __iomem *)other_ir); } return intr_reg & 3; @@ -191,23 +191,25 @@ sgiioc4_clearirq(ide_drive_t * drive) static void sgiioc4_ide_dma_start(ide_drive_t * drive) { ide_hwif_t *hwif = HWIF(drive); - unsigned int reg = hwif->INL(hwif->dma_base + IOC4_DMA_CTRL * 4); + unsigned long ioc4_dma_addr = hwif->dma_base + IOC4_DMA_CTRL * 4; + unsigned int reg = readl((void __iomem *)ioc4_dma_addr); unsigned int temp_reg = reg | IOC4_S_DMA_START; - hwif->OUTL(temp_reg, hwif->dma_base + IOC4_DMA_CTRL * 4); + writel(temp_reg, (void __iomem *)ioc4_dma_addr); } static u32 sgiioc4_ide_dma_stop(ide_hwif_t *hwif, u64 dma_base) { + unsigned long ioc4_dma_addr = dma_base + IOC4_DMA_CTRL * 4; u32 ioc4_dma; int count; count = 0; - ioc4_dma = hwif->INL(dma_base + IOC4_DMA_CTRL * 4); + ioc4_dma = readl((void __iomem *)ioc4_dma_addr); while ((ioc4_dma & IOC4_S_DMA_STOP) && (count++ < 200)) { udelay(1); - ioc4_dma = hwif->INL(dma_base + IOC4_DMA_CTRL * 4); + ioc4_dma = readl((void __iomem *)ioc4_dma_addr); } return ioc4_dma; } @@ -218,11 +220,11 @@ sgiioc4_ide_dma_end(ide_drive_t * drive) { u32 ioc4_dma, bc_dev, bc_mem, num, valid = 0, cnt = 0; ide_hwif_t *hwif = HWIF(drive); - u64 dma_base = hwif->dma_base; + unsigned long dma_base = hwif->dma_base; int dma_stat = 0; unsigned long *ending_dma = ide_get_hwifdata(hwif); - hwif->OUTL(IOC4_S_DMA_STOP, dma_base + IOC4_DMA_CTRL * 4); + writel(IOC4_S_DMA_STOP, (void __iomem *)(dma_base + IOC4_DMA_CTRL * 4)); ioc4_dma = sgiioc4_ide_dma_stop(hwif, dma_base); @@ -254,8 +256,8 @@ sgiioc4_ide_dma_end(ide_drive_t * drive) dma_stat = 1; } - bc_dev = hwif->INL(dma_base + IOC4_BC_DEV * 4); - bc_mem = hwif->INL(dma_base + IOC4_BC_MEM * 4); + bc_dev = readl((void __iomem *)(dma_base + IOC4_BC_DEV * 4)); + bc_mem = readl((void __iomem *)(dma_base + IOC4_BC_MEM * 4)); if ((bc_dev & 0x01FF) || (bc_mem & 0x1FF)) { if (bc_dev > bc_mem + 8) { @@ -273,34 +275,29 @@ sgiioc4_ide_dma_end(ide_drive_t * drive) } static int -sgiioc4_ide_dma_check(ide_drive_t * drive) +sgiioc4_ide_dma_on(ide_drive_t * drive) { - if (ide_config_drive_speed(drive, XFER_MW_DMA_2) != 0) { - printk(KERN_INFO - "Couldnot set %s in Multimode-2 DMA mode | " - "Drive %s using PIO instead\n", - drive->name, drive->name); - drive->using_dma = 0; - } else - drive->using_dma = 1; + drive->using_dma = 1; return 0; } -static int -sgiioc4_ide_dma_on(ide_drive_t * drive) +static void sgiioc4_dma_off_quietly(ide_drive_t *drive) { - drive->using_dma = 1; + drive->using_dma = 0; - return HWIF(drive)->ide_dma_host_on(drive); + drive->hwif->dma_host_off(drive); } -static int -sgiioc4_ide_dma_off_quietly(ide_drive_t * drive) +static int sgiioc4_ide_dma_check(ide_drive_t *drive) { - drive->using_dma = 0; - - return HWIF(drive)->ide_dma_host_off(drive); + /* FIXME: check for available DMA modes */ + if (ide_config_drive_speed(drive, XFER_MW_DMA_2) != 0) { + printk(KERN_WARNING "%s: couldn't set MWDMA2 mode, " + "using PIO instead\n", drive->name); + return -1; + } else + return 0; } /* returns 1 if dma irq issued, 0 otherwise */ @@ -310,21 +307,13 @@ sgiioc4_ide_dma_test_irq(ide_drive_t * drive) return sgiioc4_checkirq(HWIF(drive)); } -static int -sgiioc4_ide_dma_host_on(ide_drive_t * drive) +static void sgiioc4_dma_host_on(ide_drive_t * drive) { - if (drive->using_dma) - return 0; - - return 1; } -static int -sgiioc4_ide_dma_host_off(ide_drive_t * drive) +static void sgiioc4_dma_host_off(ide_drive_t * drive) { sgiioc4_clearirq(drive); - - return 0; } static int @@ -436,16 +425,17 @@ sgiioc4_configure_for_dma(int dma_direction, ide_drive_t * drive) { u32 ioc4_dma; ide_hwif_t *hwif = HWIF(drive); - u64 dma_base = hwif->dma_base; + unsigned long dma_base = hwif->dma_base; + unsigned long ioc4_dma_addr = dma_base + IOC4_DMA_CTRL * 4; u32 dma_addr, ending_dma_addr; - ioc4_dma = hwif->INL(dma_base + IOC4_DMA_CTRL * 4); + ioc4_dma = readl((void __iomem *)ioc4_dma_addr); if (ioc4_dma & IOC4_S_DMA_ACTIVE) { printk(KERN_WARNING "%s(%s):Warning!! DMA from previous transfer was still active\n", __FUNCTION__, drive->name); - hwif->OUTL(IOC4_S_DMA_STOP, dma_base + IOC4_DMA_CTRL * 4); + writel(IOC4_S_DMA_STOP, (void __iomem *)ioc4_dma_addr); ioc4_dma = sgiioc4_ide_dma_stop(hwif, dma_base); if (ioc4_dma & IOC4_S_DMA_STOP) @@ -454,13 +444,13 @@ sgiioc4_configure_for_dma(int dma_direction, ide_drive_t * drive) __FUNCTION__, drive->name); } - ioc4_dma = hwif->INL(dma_base + IOC4_DMA_CTRL * 4); + ioc4_dma = readl((void __iomem *)ioc4_dma_addr); if (ioc4_dma & IOC4_S_DMA_ERROR) { printk(KERN_WARNING "%s(%s) : Warning!! - DMA Error during Previous" " transfer | status 0x%x\n", __FUNCTION__, drive->name, ioc4_dma); - hwif->OUTL(IOC4_S_DMA_STOP, dma_base + IOC4_DMA_CTRL * 4); + writel(IOC4_S_DMA_STOP, (void __iomem *)ioc4_dma_addr); ioc4_dma = sgiioc4_ide_dma_stop(hwif, dma_base); if (ioc4_dma & IOC4_S_DMA_STOP) @@ -471,14 +461,14 @@ sgiioc4_configure_for_dma(int dma_direction, ide_drive_t * drive) /* Address of the Scatter Gather List */ dma_addr = cpu_to_le32(hwif->dmatable_dma); - hwif->OUTL(dma_addr, dma_base + IOC4_DMA_PTR_L * 4); + writel(dma_addr, (void __iomem *)(dma_base + IOC4_DMA_PTR_L * 4)); /* Address of the Ending DMA */ memset(ide_get_hwifdata(hwif), 0, IOC4_IDE_CACHELINE_SIZE); ending_dma_addr = cpu_to_le32(hwif->dma_status); - hwif->OUTL(ending_dma_addr, dma_base + IOC4_DMA_END_ADDR * 4); + writel(ending_dma_addr, (void __iomem *)(dma_base + IOC4_DMA_END_ADDR * 4)); - hwif->OUTL(dma_direction, dma_base + IOC4_DMA_CTRL * 4); + writel(dma_direction, (void __iomem *)ioc4_dma_addr); drive->waiting_for_dma = 1; } @@ -590,7 +580,7 @@ static int sgiioc4_ide_dma_setup(ide_drive_t *drive) static void __devinit ide_init_sgiioc4(ide_hwif_t * hwif) { - hwif->mmio = 2; + hwif->mmio = 1; hwif->autodma = 1; hwif->atapi_dma = 1; hwif->ultra_mask = 0x0; /* Disable Ultra DMA */ @@ -613,10 +603,10 @@ ide_init_sgiioc4(ide_hwif_t * hwif) hwif->ide_dma_end = &sgiioc4_ide_dma_end; hwif->ide_dma_check = &sgiioc4_ide_dma_check; hwif->ide_dma_on = &sgiioc4_ide_dma_on; - hwif->ide_dma_off_quietly = &sgiioc4_ide_dma_off_quietly; + hwif->dma_off_quietly = &sgiioc4_dma_off_quietly; hwif->ide_dma_test_irq = &sgiioc4_ide_dma_test_irq; - hwif->ide_dma_host_on = &sgiioc4_ide_dma_host_on; - hwif->ide_dma_host_off = &sgiioc4_ide_dma_host_off; + hwif->dma_host_on = &sgiioc4_dma_host_on; + hwif->dma_host_off = &sgiioc4_dma_host_off; hwif->ide_dma_lostirq = &sgiioc4_ide_dma_lostirq; hwif->ide_dma_timeout = &__ide_dma_timeout; @@ -688,7 +678,7 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev, ide_pci_device_t * d) default_hwif_mmiops(hwif); /* Initializing chipset IRQ Registers */ - hwif->OUTL(0x03, irqport + IOC4_INTR_SET * 4); + writel(0x03, (void __iomem *)(irqport + IOC4_INTR_SET * 4)); ide_init_sgiioc4(hwif); @@ -729,8 +719,7 @@ out: return ret; } -static ide_pci_device_t sgiioc4_chipsets[] __devinitdata = { - { +static ide_pci_device_t sgiioc4_chipset __devinitdata = { /* Channel 0 */ .name = "SGIIOC4", .init_hwif = ide_init_sgiioc4, @@ -739,7 +728,6 @@ static ide_pci_device_t sgiioc4_chipsets[] __devinitdata = { .autodma = AUTODMA, /* SGI IOC4 doesn't have enablebits. */ .bootable = ON_BOARD, - } }; int @@ -751,8 +739,7 @@ ioc4_ide_attach_one(struct ioc4_driver_data *idd) if (idd->idd_variant == IOC4_VARIANT_PCI_RT) return 0; - return pci_init_sgiioc4(idd->idd_pdev, - &sgiioc4_chipsets[idd->idd_pci_id->driver_data]); + return pci_init_sgiioc4(idd->idd_pdev, &sgiioc4_chipset); } static struct ioc4_submodule ioc4_ide_submodule = { diff --git a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c index 4ff89c7d990a..7b4c189a9d99 100644 --- a/drivers/ide/pci/siimage.c +++ b/drivers/ide/pci/siimage.c @@ -1,8 +1,9 @@ /* - * linux/drivers/ide/pci/siimage.c Version 1.07 Nov 30, 2003 + * linux/drivers/ide/pci/siimage.c Version 1.11 Jan 27, 2007 * * Copyright (C) 2001-2002 Andre Hedrick <andre@linux-ide.org> * Copyright (C) 2003 Red Hat <alan@redhat.com> + * Copyright (C) 2007 MontaVista Software, Inc. * * May be copied or modified under the terms of the GNU General Public License * @@ -205,41 +206,39 @@ static void siimage_tuneproc (ide_drive_t *drive, byte mode_wanted) unsigned long tfaddr = siimage_selreg(hwif, 0x02); /* cheat for now and use the docs */ - switch(mode_wanted) { - case 4: - speedp = 0x10c1; - speedt = 0x10c1; - break; - case 3: - speedp = 0x10C3; - speedt = 0x10C3; - break; - case 2: - speedp = 0x1104; - speedt = 0x1281; - break; - case 1: - speedp = 0x2283; - speedt = 0x1281; - break; - case 0: - default: - speedp = 0x328A; - speedt = 0x328A; - break; + switch (mode_wanted) { + case 4: + speedp = 0x10c1; + speedt = 0x10c1; + break; + case 3: + speedp = 0x10c3; + speedt = 0x10c3; + break; + case 2: + speedp = 0x1104; + speedt = 0x1281; + break; + case 1: + speedp = 0x2283; + speedt = 0x2283; + break; + case 0: + default: + speedp = 0x328a; + speedt = 0x328a; + break; } - if (hwif->mmio) - { - hwif->OUTW(speedt, addr); - hwif->OUTW(speedp, tfaddr); + + if (hwif->mmio) { + hwif->OUTW(speedp, addr); + hwif->OUTW(speedt, tfaddr); /* Now set up IORDY */ if(mode_wanted == 3 || mode_wanted == 4) hwif->OUTW(hwif->INW(tfaddr-2)|0x200, tfaddr-2); else hwif->OUTW(hwif->INW(tfaddr-2)&~0x200, tfaddr-2); - } - else - { + } else { pci_write_config_word(hwif->pci_dev, addr, speedp); pci_write_config_word(hwif->pci_dev, tfaddr, speedt); pci_read_config_word(hwif->pci_dev, tfaddr-2, &speedp); @@ -397,12 +396,9 @@ static int config_chipset_for_dma (ide_drive_t *drive) if (!speed) return 0; - if (ide_set_xfer_rate(drive, speed)) + if (siimage_tune_chipset(drive, speed)) return 0; - if (!drive->init_speed) - drive->init_speed = speed; - return ide_dma_enable(drive); } @@ -418,25 +414,13 @@ static int config_chipset_for_dma (ide_drive_t *drive) static int siimage_config_drive_for_dma (ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); - struct hd_driveid *id = drive->id; - - if ((id->capability & 1) != 0 && drive->autodma) { - - if (ide_use_dma(drive)) { - if (config_chipset_for_dma(drive)) - return hwif->ide_dma_on(drive); - } - - goto fast_ata_pio; + if (ide_use_dma(drive) && config_chipset_for_dma(drive)) + return 0; - } else if ((id->capability & 8) || (id->field_valid & 2)) { -fast_ata_pio: + if (ide_use_fast_pio(drive)) config_chipset_for_pio(drive, 1); - return hwif->ide_dma_off_quietly(drive); - } - /* IORDY not supported */ - return 0; + + return -1; } /* returns 1 if dma irq issued, 0 otherwise */ @@ -472,11 +456,11 @@ static int siimage_mmio_ide_dma_test_irq (ide_drive_t *drive) unsigned long addr = siimage_selreg(hwif, 0x1); if (SATA_ERROR_REG) { - u32 ext_stat = hwif->INL(base + 0x10); + u32 ext_stat = readl((void __iomem *)(base + 0x10)); u8 watchdog = 0; if (ext_stat & ((hwif->channel) ? 0x40 : 0x10)) { - u32 sata_error = hwif->INL(SATA_ERROR_REG); - hwif->OUTL(sata_error, SATA_ERROR_REG); + u32 sata_error = readl((void __iomem *)SATA_ERROR_REG); + writel(sata_error, (void __iomem *)SATA_ERROR_REG); watchdog = (sata_error & 0x00680000) ? 1 : 0; printk(KERN_WARNING "%s: sata_error = 0x%08x, " "watchdog = %d, %s\n", @@ -493,11 +477,11 @@ static int siimage_mmio_ide_dma_test_irq (ide_drive_t *drive) } /* return 1 if INTR asserted */ - if ((hwif->INB(hwif->dma_status) & 0x04) == 0x04) + if ((readb((void __iomem *)hwif->dma_status) & 0x04) == 0x04) return 1; /* return 1 if Device INTR asserted */ - if ((hwif->INB(addr) & 8) == 8) + if ((readb((void __iomem *)addr) & 8) == 8) return 0; //return 1; return 0; @@ -519,9 +503,9 @@ static int siimage_busproc (ide_drive_t * drive, int state) u32 stat_config = 0; unsigned long addr = siimage_selreg(hwif, 0); - if (hwif->mmio) { - stat_config = hwif->INL(addr); - } else + if (hwif->mmio) + stat_config = readl((void __iomem *)addr); + else pci_read_config_dword(hwif->pci_dev, addr, &stat_config); switch (state) { @@ -557,9 +541,10 @@ static int siimage_reset_poll (ide_drive_t *drive) if (SATA_STATUS_REG) { ide_hwif_t *hwif = HWIF(drive); - if ((hwif->INL(SATA_STATUS_REG) & 0x03) != 0x03) { + /* SATA_STATUS_REG is valid only when in MMIO mode */ + if ((readl((void __iomem *)SATA_STATUS_REG) & 0x03) != 0x03) { printk(KERN_WARNING "%s: reset phy dead, status=0x%08x\n", - hwif->name, hwif->INL(SATA_STATUS_REG)); + hwif->name, readl((void __iomem *)SATA_STATUS_REG)); HWGROUP(drive)->polling = 0; return ide_started; } @@ -619,7 +604,8 @@ static void siimage_reset (ide_drive_t *drive) } if (SATA_STATUS_REG) { - u32 sata_stat = hwif->INL(SATA_STATUS_REG); + /* SATA_STATUS_REG is valid only when in MMIO mode */ + u32 sata_stat = readl((void __iomem *)SATA_STATUS_REG); printk(KERN_WARNING "%s: reset phy, status=0x%08x, %s\n", hwif->name, sata_stat, __FUNCTION__); if (!(sata_stat)) { @@ -898,7 +884,8 @@ static void __devinit init_mmio_iops_siimage(ide_hwif_t *hwif) base = (unsigned long) addr; hwif->dma_base = base + (ch ? 0x08 : 0x00); - hwif->mmio = 2; + + hwif->mmio = 1; } static int is_dev_seagate_sata(ide_drive_t *drive) diff --git a/drivers/ide/pci/sis5513.c b/drivers/ide/pci/sis5513.c index 1afff659ab55..2ba0669f36a1 100644 --- a/drivers/ide/pci/sis5513.c +++ b/drivers/ide/pci/sis5513.c @@ -667,67 +667,20 @@ static int config_chipset_for_dma (ide_drive_t *drive) return ide_dma_enable(drive); } -static int sis5513_config_drive_xfer_rate (ide_drive_t *drive) +static int sis5513_config_xfer_rate(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); - struct hd_driveid *id = drive->id; + config_art_rwp_pio(drive, 5); drive->init_speed = 0; - if (id && (id->capability & 1) && drive->autodma) { - - if (ide_use_dma(drive)) { - if (config_chipset_for_dma(drive)) - return hwif->ide_dma_on(drive); - } - - goto fast_ata_pio; + if (ide_use_dma(drive) && config_chipset_for_dma(drive)) + return 0; - } else if ((id->capability & 8) || (id->field_valid & 2)) { -fast_ata_pio: + if (ide_use_fast_pio(drive)) sis5513_tune_drive(drive, 5); - return hwif->ide_dma_off_quietly(drive); - } - /* IORDY not supported */ - return 0; -} - -/* initiates/aborts (U)DMA read/write operations on a drive. */ -static int sis5513_config_xfer_rate (ide_drive_t *drive) -{ - config_drive_art_rwp(drive); - config_art_rwp_pio(drive, 5); - return sis5513_config_drive_xfer_rate(drive); -} - -/* - Future simpler config_xfer_rate : - When ide_find_best_mode is made bad-drive aware - - remove config_drive_xfer_rate and config_chipset_for_dma, - - replace config_xfer_rate with the following - -static int sis5513_config_xfer_rate (ide_drive_t *drive) -{ - u16 w80 = HWIF(drive)->udma_four; - u16 speed; - - config_drive_art_rwp(drive); - config_art_rwp_pio(drive, 5); - - speed = ide_find_best_mode(drive, - XFER_PIO | XFER_EPIO | XFER_SWDMA | XFER_MWDMA | - (chipset_family >= ATA_33 ? XFER_UDMA : 0) | - (w80 && chipset_family >= ATA_66 ? XFER_UDMA_66 : 0) | - (w80 && chipset_family >= ATA_100a ? XFER_UDMA_100 : 0) | - (w80 && chipset_family >= ATA_133a ? XFER_UDMA_133 : 0)); - - sis5513_tune_chipset(drive, speed); - if (drive->autodma && (speed & XFER_MODE) != XFER_PIO) - return HWIF(drive)->ide_dma_on(drive); - return HWIF(drive)->ide_dma_off_quietly(drive); + return -1; } -*/ /* Chip detection and general config */ static unsigned int __devinit init_chipset_sis5513 (struct pci_dev *dev, const char *name) diff --git a/drivers/ide/pci/sl82c105.c b/drivers/ide/pci/sl82c105.c index 170a26199050..3a8a76fc78c7 100644 --- a/drivers/ide/pci/sl82c105.c +++ b/drivers/ide/pci/sl82c105.c @@ -161,14 +161,14 @@ static int sl82c105_check_drive (ide_drive_t *drive) if (id->field_valid & 2) { if ((id->dma_mword & hwif->mwdma_mask) || (id->dma_1word & hwif->swdma_mask)) - return hwif->ide_dma_on(drive); + return 0; } - if (__ide_dma_good_drive(drive)) - return hwif->ide_dma_on(drive); + if (__ide_dma_good_drive(drive) && id->eide_dma_time < 150) + return 0; } while (0); - return hwif->ide_dma_off_quietly(drive); + return -1; } /* @@ -215,7 +215,7 @@ static int sl82c105_ide_dma_lost_irq(ide_drive_t *drive) * Was DMA enabled? If so, disable it - we're resetting the * host. The IDE layer will be handling the drive for us. */ - val = hwif->INB(dma_base); + val = inb(dma_base); if (val & 1) { outb(val & ~1, dma_base); printk("sl82c105: DMA was enabled\n"); @@ -259,28 +259,22 @@ static int sl82c105_ide_dma_on (ide_drive_t *drive) { DBG(("sl82c105_ide_dma_on(drive:%s)\n", drive->name)); - if (config_for_dma(drive)) { - config_for_pio(drive, 4, 0, 0); - return HWIF(drive)->ide_dma_off_quietly(drive); - } + if (config_for_dma(drive)) + return 1; printk(KERN_INFO "%s: DMA enabled\n", drive->name); return __ide_dma_on(drive); } -static int sl82c105_ide_dma_off_quietly (ide_drive_t *drive) +static void sl82c105_dma_off_quietly(ide_drive_t *drive) { u8 speed = XFER_PIO_0; - int rc; - - DBG(("sl82c105_ide_dma_off_quietly(drive:%s)\n", drive->name)); - rc = __ide_dma_off_quietly(drive); + DBG(("sl82c105_dma_off_quietly(drive:%s)\n", drive->name)); + + ide_dma_off_quietly(drive); if (drive->pio_speed) speed = drive->pio_speed - XFER_PIO_0; config_for_pio(drive, speed, 0, 1); - drive->current_speed = drive->pio_speed; - - return rc; } /* @@ -401,11 +395,9 @@ static unsigned int __devinit init_chipset_sl82c105(struct pci_dev *dev, const c /* * Initialise the chip */ - static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif) { unsigned int rev; - u8 dma_state; DBG(("init_hwif_sl82c105(hwif: ide%d)\n", hwif->index)); @@ -431,7 +423,6 @@ static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif) if (!hwif->dma_base) return; - dma_state = hwif->INB(hwif->dma_base + 2) & ~0x60; rev = sl82c105_bridge_revision(hwif->pci_dev); if (rev <= 5) { /* @@ -441,15 +432,12 @@ static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif) printk(" %s: Winbond 553 bridge revision %d, BM-DMA disabled\n", hwif->name, rev); } else { - dma_state |= 0x60; - hwif->atapi_dma = 1; - hwif->mwdma_mask = 0x07; - hwif->swdma_mask = 0x07; + hwif->mwdma_mask = 0x04; hwif->ide_dma_check = &sl82c105_check_drive; hwif->ide_dma_on = &sl82c105_ide_dma_on; - hwif->ide_dma_off_quietly = &sl82c105_ide_dma_off_quietly; + hwif->dma_off_quietly = &sl82c105_dma_off_quietly; hwif->ide_dma_lostirq = &sl82c105_ide_dma_lost_irq; hwif->dma_start = &sl82c105_ide_dma_start; hwif->ide_dma_timeout = &sl82c105_ide_dma_timeout; @@ -462,7 +450,6 @@ static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif) if (hwif->mate) hwif->serialized = hwif->mate->serialized = 1; } - hwif->OUTB(dma_state, hwif->dma_base + 2); } static ide_pci_device_t sl82c105_chipset __devinitdata = { diff --git a/drivers/ide/pci/slc90e66.c b/drivers/ide/pci/slc90e66.c index 2663ddbd9b67..ae7eb58d961c 100644 --- a/drivers/ide/pci/slc90e66.c +++ b/drivers/ide/pci/slc90e66.c @@ -179,26 +179,16 @@ static int slc90e66_config_drive_for_dma (ide_drive_t *drive) static int slc90e66_config_drive_xfer_rate (ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); - struct hd_driveid *id = drive->id; - drive->init_speed = 0; - if ((id->capability & 1) && drive->autodma) { - - if (ide_use_dma(drive) && slc90e66_config_drive_for_dma(drive)) - return hwif->ide_dma_on(drive); + if (ide_use_dma(drive) && slc90e66_config_drive_for_dma(drive)) + return 0; - goto fast_ata_pio; + if (ide_use_fast_pio(drive)) + (void)slc90e66_tune_chipset(drive, XFER_PIO_0 + + ide_get_best_pio_mode(drive, 255, 4, NULL)); - } else if ((id->capability & 8) || (id->field_valid & 2)) { -fast_ata_pio: - (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 */ - return 0; + return -1; } static void __devinit init_hwif_slc90e66 (ide_hwif_t *hwif) diff --git a/drivers/ide/pci/tc86c001.c b/drivers/ide/pci/tc86c001.c index 2ad72bbda342..0b6d81d6ce48 100644 --- a/drivers/ide/pci/tc86c001.c +++ b/drivers/ide/pci/tc86c001.c @@ -45,7 +45,7 @@ static int tc86c001_tune_chipset(ide_drive_t *drive, u8 speed) scr &= (speed < XFER_MW_DMA_0) ? 0xf8ff : 0xff0f; scr |= mode; - hwif->OUTW(scr, scr_port); + outw(scr, scr_port); return ide_config_drive_speed(drive, speed); } @@ -89,15 +89,15 @@ static int tc86c001_timer_expiry(ide_drive_t *drive) "attempting recovery...\n", drive->name); /* Stop DMA */ - hwif->OUTB(dma_cmd & ~0x01, hwif->dma_command); + outb(dma_cmd & ~0x01, hwif->dma_command); /* Setup the dummy DMA transfer */ - hwif->OUTW(0, sc_base + 0x0a); /* Sector Count */ - hwif->OUTW(0, twcr_port); /* Transfer Word Count 1 or 2 */ + outw(0, sc_base + 0x0a); /* Sector Count */ + outw(0, twcr_port); /* Transfer Word Count 1 or 2 */ /* Start the dummy DMA transfer */ - hwif->OUTB(0x00, hwif->dma_command); /* clear R_OR_WCTR for write */ - hwif->OUTB(0x01, hwif->dma_command); /* set START_STOPBM */ + outb(0x00, hwif->dma_command); /* clear R_OR_WCTR for write */ + outb(0x01, hwif->dma_command); /* set START_STOPBM */ /* * If an interrupt was pending, it should come thru shortly. @@ -128,8 +128,8 @@ static void tc86c001_dma_start(ide_drive_t *drive) * the appropriate system control registers for DMA to work * with LBA48 and ATAPI devices... */ - hwif->OUTW(nsectors, sc_base + 0x0a); /* Sector Count */ - hwif->OUTW(SECTOR_SIZE / 2, twcr_port); /* Transfer Word Count 1/2 */ + outw(nsectors, sc_base + 0x0a); /* Sector Count */ + outw(SECTOR_SIZE / 2, twcr_port); /* Transfer Word Count 1/2 */ /* Install our timeout expiry hook, saving the current handler... */ ide_set_hwifdata(hwif, hwgroup->expiry); @@ -168,7 +168,7 @@ static int tc86c001_busproc(ide_drive_t *drive, int state) } /* System Control 1 Register bit 11 (ATA Hard Reset) write */ - hwif->OUTW(scr1, sc_base + 0x00); + outw(scr1, sc_base + 0x00); return 0; } @@ -185,23 +185,13 @@ static int config_chipset_for_dma(ide_drive_t *drive) static int tc86c001_config_drive_xfer_rate(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); - struct hd_driveid *id = drive->id; - - if ((id->capability & 1) && drive->autodma) { - - if (ide_use_dma(drive) && config_chipset_for_dma(drive)) - return hwif->ide_dma_on(drive); - - goto fast_ata_pio; + if (ide_use_dma(drive) && config_chipset_for_dma(drive)) + return 0; - } else if ((id->capability & 8) || (id->field_valid & 2)) { -fast_ata_pio: + if (ide_use_fast_pio(drive)) tc86c001_tune_drive(drive, 255); - return hwif->ide_dma_off_quietly(drive); - } - /* IORDY not supported */ - return 0; + + return -1; } static void __devinit init_hwif_tc86c001(ide_hwif_t *hwif) @@ -210,13 +200,13 @@ static void __devinit init_hwif_tc86c001(ide_hwif_t *hwif) u16 scr1 = hwif->INW(sc_base + 0x00);; /* System Control 1 Register bit 15 (Soft Reset) set */ - hwif->OUTW(scr1 | 0x8000, sc_base + 0x00); + outw(scr1 | 0x8000, sc_base + 0x00); /* System Control 1 Register bit 14 (FIFO Reset) set */ - hwif->OUTW(scr1 | 0x4000, sc_base + 0x00); + outw(scr1 | 0x4000, sc_base + 0x00); /* System Control 1 Register: reset clear */ - hwif->OUTW(scr1 & ~0xc000, sc_base + 0x00); + outw(scr1 & ~0xc000, sc_base + 0x00); /* Store the system control register base for convenience... */ hwif->config_data = sc_base; @@ -234,7 +224,7 @@ static void __devinit init_hwif_tc86c001(ide_hwif_t *hwif) * Sector Count Control Register bits 0 and 1 set: * software sets Sector Count Register for master and slave device */ - hwif->OUTW(0x0003, sc_base + 0x0c); + outw(0x0003, sc_base + 0x0c); /* Sector Count Register limit */ hwif->rqsize = 0xffff; diff --git a/drivers/ide/pci/triflex.c b/drivers/ide/pci/triflex.c index b13cce1fd1a6..5e06179c3469 100644 --- a/drivers/ide/pci/triflex.c +++ b/drivers/ide/pci/triflex.c @@ -104,29 +104,21 @@ static int triflex_config_drive_for_dma(ide_drive_t *drive) { int speed = ide_dma_speed(drive, 0); /* No ultra speeds */ - if (!speed) { - u8 pspeed = ide_get_best_pio_mode(drive, 255, 4, NULL); - speed = XFER_PIO_0 + pspeed; - } - + if (!speed) + return 0; + (void) triflex_tune_chipset(drive, speed); return ide_dma_enable(drive); } static int triflex_config_drive_xfer_rate(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); - struct hd_driveid *id = drive->id; - - if ((id->capability & 1) && drive->autodma) { - if (ide_use_dma(drive)) { - if (triflex_config_drive_for_dma(drive)) - return hwif->ide_dma_on(drive); - } - } + if (ide_use_dma(drive) && triflex_config_drive_for_dma(drive)) + return 0; + + triflex_tune_drive(drive, 255); - hwif->tuneproc(drive, 255); - return hwif->ide_dma_off_quietly(drive); + return -1; } static void __devinit init_hwif_triflex(ide_hwif_t *hwif) diff --git a/drivers/ide/pci/trm290.c b/drivers/ide/pci/trm290.c index 174b88c4780e..cbb1b11119a5 100644 --- a/drivers/ide/pci/trm290.c +++ b/drivers/ide/pci/trm290.c @@ -157,16 +157,16 @@ static void trm290_prepare_drive (ide_drive_t *drive, unsigned int use_dma) if (reg != hwif->select_data) { hwif->select_data = reg; /* set PIO/DMA */ - hwif->OUTB(0x51|(hwif->channel<<3), hwif->config_data+1); - hwif->OUTW(reg & 0xff, hwif->config_data); + outb(0x51 | (hwif->channel << 3), hwif->config_data + 1); + outw(reg & 0xff, hwif->config_data); } /* enable IRQ if not probing */ if (drive->present) { - reg = hwif->INW(hwif->config_data + 3); + reg = inw(hwif->config_data + 3); reg &= 0x13; reg &= ~(1 << hwif->channel); - hwif->OUTW(reg, hwif->config_data+3); + outw(reg, hwif->config_data + 3); } local_irq_restore(flags); @@ -177,15 +177,12 @@ static void trm290_selectproc (ide_drive_t *drive) trm290_prepare_drive(drive, drive->using_dma); } -#ifdef CONFIG_BLK_DEV_IDEDMA static void trm290_ide_dma_exec_cmd(ide_drive_t *drive, u8 command) { - ide_hwif_t *hwif = HWIF(drive); - BUG_ON(HWGROUP(drive)->handler != NULL); /* paranoia check */ ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL); /* issue cmd to drive */ - hwif->OUTB(command, IDE_COMMAND_REG); + outb(command, IDE_COMMAND_REG); } static int trm290_ide_dma_setup(ide_drive_t *drive) @@ -211,10 +208,10 @@ static int trm290_ide_dma_setup(ide_drive_t *drive) } /* select DMA xfer */ trm290_prepare_drive(drive, 1); - hwif->OUTL(hwif->dmatable_dma|rw, hwif->dma_command); + outl(hwif->dmatable_dma | rw, hwif->dma_command); drive->waiting_for_dma = 1; /* start DMA */ - hwif->OUTW((count * 2) - 1, hwif->dma_status); + outw((count * 2) - 1, hwif->dma_status); return 0; } @@ -230,7 +227,7 @@ static int trm290_ide_dma_end (ide_drive_t *drive) drive->waiting_for_dma = 0; /* purge DMA mappings */ ide_destroy_dmatable(drive); - status = hwif->INW(hwif->dma_status); + status = inw(hwif->dma_status); return (status != 0x00ff); } @@ -239,10 +236,9 @@ static int trm290_ide_dma_test_irq (ide_drive_t *drive) ide_hwif_t *hwif = HWIF(drive); u16 status = 0; - status = hwif->INW(hwif->dma_status); + status = inw(hwif->dma_status); return (status == 0x00ff); } -#endif /* CONFIG_BLK_DEV_IDEDMA */ /* * Invoked from ide-dma.c at boot time. @@ -269,15 +265,15 @@ static void __devinit init_hwif_trm290(ide_hwif_t *hwif) local_irq_save(flags); /* put config reg into first byte of hwif->select_data */ - hwif->OUTB(0x51|(hwif->channel<<3), hwif->config_data+1); + outb(0x51 | (hwif->channel << 3), hwif->config_data + 1); /* select PIO as default */ hwif->select_data = 0x21; - hwif->OUTB(hwif->select_data, hwif->config_data); + outb(hwif->select_data, hwif->config_data); /* get IRQ info */ - reg = hwif->INB(hwif->config_data+3); + reg = inb(hwif->config_data + 3); /* mask IRQs for both ports */ reg = (reg & 0x10) | 0x03; - hwif->OUTB(reg, hwif->config_data+3); + outb(reg, hwif->config_data + 3); local_irq_restore(flags); if ((reg & 0x10)) @@ -289,13 +285,11 @@ static void __devinit init_hwif_trm290(ide_hwif_t *hwif) ide_setup_dma(hwif, (hwif->config_data + 4) ^ (hwif->channel ? 0x0080 : 0x0000), 3); -#ifdef CONFIG_BLK_DEV_IDEDMA hwif->dma_setup = &trm290_ide_dma_setup; hwif->dma_exec_cmd = &trm290_ide_dma_exec_cmd; hwif->dma_start = &trm290_ide_dma_start; hwif->ide_dma_end = &trm290_ide_dma_end; hwif->ide_dma_test_irq = &trm290_ide_dma_test_irq; -#endif /* CONFIG_BLK_DEV_IDEDMA */ hwif->selectproc = &trm290_selectproc; hwif->autodma = 0; /* play it safe for now */ @@ -312,16 +306,16 @@ static void __devinit init_hwif_trm290(ide_hwif_t *hwif) static u16 next_offset = 0; u8 old_mask; - hwif->OUTB(0x54|(hwif->channel<<3), hwif->config_data+1); - old = hwif->INW(hwif->config_data); + outb(0x54 | (hwif->channel << 3), hwif->config_data + 1); + old = inw(hwif->config_data); old &= ~1; - old_mask = hwif->INB(old+2); + old_mask = inb(old + 2); if (old != compat && old_mask == 0xff) { /* leave lower 10 bits untouched */ compat += (next_offset += 0x400); hwif->io_ports[IDE_CONTROL_OFFSET] = compat + 2; - hwif->OUTW(compat|1, hwif->config_data); - new = hwif->INW(hwif->config_data); + outw(compat | 1, hwif->config_data); + new = inw(hwif->config_data); printk(KERN_INFO "%s: control basereg workaround: " "old=0x%04x, new=0x%04x\n", hwif->name, old, new & ~1); diff --git a/drivers/ide/pci/via82cxxx.c b/drivers/ide/pci/via82cxxx.c index 6fb6e50b8231..a508550c4095 100644 --- a/drivers/ide/pci/via82cxxx.c +++ b/drivers/ide/pci/via82cxxx.c @@ -240,8 +240,9 @@ static int via82cxxx_ide_dma_check (ide_drive_t *drive) via_set_drive(drive, speed); if (drive->autodma && (speed & XFER_MODE) != XFER_PIO) - return hwif->ide_dma_on(drive); - return hwif->ide_dma_off_quietly(drive); + return 0; + + return -1; } static struct via_isa_bridge *via_config_find(struct pci_dev **isa) diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c index d8ea23710bf0..395d35253d5d 100644 --- a/drivers/ide/ppc/pmac.c +++ b/drivers/ide/ppc/pmac.c @@ -1237,7 +1237,7 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif) hwif->OUTBSYNC = pmac_outbsync; /* Tell common code _not_ to mess with resources */ - hwif->mmio = 2; + hwif->mmio = 1; hwif->hwif_data = pmif; pmac_ide_init_hwif_ports(&hwif->hw, pmif->regbase, 0, &hwif->irq); memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports)); @@ -1979,16 +1979,12 @@ pmac_ide_dma_test_irq (ide_drive_t *drive) return 1; } -static int -pmac_ide_dma_host_off (ide_drive_t *drive) +static void pmac_ide_dma_host_off(ide_drive_t *drive) { - return 0; } -static int -pmac_ide_dma_host_on (ide_drive_t *drive) +static int pmac_ide_dma_host_on(ide_drive_t *drive) { - return 0; } static int @@ -2034,7 +2030,7 @@ pmac_ide_setup_dma(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif) return; } - hwif->ide_dma_off_quietly = &__ide_dma_off_quietly; + hwif->dma_off_quietly = &ide_dma_off_quietly; hwif->ide_dma_on = &__ide_dma_on; hwif->ide_dma_check = &pmac_ide_dma_check; hwif->dma_setup = &pmac_ide_dma_setup; @@ -2042,8 +2038,8 @@ pmac_ide_setup_dma(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif) hwif->dma_start = &pmac_ide_dma_start; hwif->ide_dma_end = &pmac_ide_dma_end; hwif->ide_dma_test_irq = &pmac_ide_dma_test_irq; - hwif->ide_dma_host_off = &pmac_ide_dma_host_off; - hwif->ide_dma_host_on = &pmac_ide_dma_host_on; + hwif->dma_host_off = &pmac_ide_dma_host_off; + hwif->dma_host_on = &pmac_ide_dma_host_on; hwif->ide_dma_timeout = &__ide_dma_timeout; hwif->ide_dma_lostirq = &pmac_ide_dma_lostirq; diff --git a/drivers/ide/ppc/scc_pata.c b/drivers/ide/ppc/scc_pata.c new file mode 100644 index 000000000000..de64b022478b --- /dev/null +++ b/drivers/ide/ppc/scc_pata.c @@ -0,0 +1,831 @@ +/* + * Support for IDE interfaces on Celleb platform + * + * (C) Copyright 2006 TOSHIBA CORPORATION + * + * This code is based on drivers/ide/pci/siimage.c: + * Copyright (C) 2001-2002 Andre Hedrick <andre@linux-ide.org> + * Copyright (C) 2003 Red Hat <alan@redhat.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <linux/types.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/delay.h> +#include <linux/hdreg.h> +#include <linux/ide.h> +#include <linux/init.h> + +#define PCI_DEVICE_ID_TOSHIBA_SCC_ATA 0x01b4 + +#define SCC_PATA_NAME "scc IDE" + +#define TDVHSEL_MASTER 0x00000001 +#define TDVHSEL_SLAVE 0x00000004 + +#define MODE_JCUSFEN 0x00000080 + +#define CCKCTRL_ATARESET 0x00040000 +#define CCKCTRL_BUFCNT 0x00020000 +#define CCKCTRL_CRST 0x00010000 +#define CCKCTRL_OCLKEN 0x00000100 +#define CCKCTRL_ATACLKOEN 0x00000002 +#define CCKCTRL_LCLKEN 0x00000001 + +#define QCHCD_IOS_SS 0x00000001 + +#define QCHSD_STPDIAG 0x00020000 + +#define INTMASK_MSK 0xD1000012 +#define INTSTS_SERROR 0x80000000 +#define INTSTS_PRERR 0x40000000 +#define INTSTS_RERR 0x10000000 +#define INTSTS_ICERR 0x01000000 +#define INTSTS_BMSINT 0x00000010 +#define INTSTS_BMHE 0x00000008 +#define INTSTS_IOIRQS 0x00000004 +#define INTSTS_INTRQ 0x00000002 +#define INTSTS_ACTEINT 0x00000001 + +#define ECMODE_VALUE 0x01 + +static struct scc_ports { + unsigned long ctl, dma; + unsigned char hwif_id; /* for removing hwif from system */ +} scc_ports[MAX_HWIFS]; + +/* PIO transfer mode table */ +/* JCHST */ +static unsigned long JCHSTtbl[2][7] = { + {0x0E, 0x05, 0x02, 0x03, 0x02, 0x00, 0x00}, /* 100MHz */ + {0x13, 0x07, 0x04, 0x04, 0x03, 0x00, 0x00} /* 133MHz */ +}; + +/* JCHHT */ +static unsigned long JCHHTtbl[2][7] = { + {0x0E, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00}, /* 100MHz */ + {0x13, 0x03, 0x03, 0x03, 0x03, 0x00, 0x00} /* 133MHz */ +}; + +/* JCHCT */ +static unsigned long JCHCTtbl[2][7] = { + {0x1D, 0x1D, 0x1C, 0x0B, 0x06, 0x00, 0x00}, /* 100MHz */ + {0x27, 0x26, 0x26, 0x0E, 0x09, 0x00, 0x00} /* 133MHz */ +}; + + +/* DMA transfer mode table */ +/* JCHDCTM/JCHDCTS */ +static unsigned long JCHDCTxtbl[2][7] = { + {0x0A, 0x06, 0x04, 0x03, 0x01, 0x00, 0x00}, /* 100MHz */ + {0x0E, 0x09, 0x06, 0x04, 0x02, 0x01, 0x00} /* 133MHz */ +}; + +/* JCSTWTM/JCSTWTS */ +static unsigned long JCSTWTxtbl[2][7] = { + {0x06, 0x04, 0x03, 0x02, 0x02, 0x02, 0x00}, /* 100MHz */ + {0x09, 0x06, 0x04, 0x02, 0x02, 0x02, 0x02} /* 133MHz */ +}; + +/* JCTSS */ +static unsigned long JCTSStbl[2][7] = { + {0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x00}, /* 100MHz */ + {0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05} /* 133MHz */ +}; + +/* JCENVT */ +static unsigned long JCENVTtbl[2][7] = { + {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00}, /* 100MHz */ + {0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02} /* 133MHz */ +}; + +/* JCACTSELS/JCACTSELM */ +static unsigned long JCACTSELtbl[2][7] = { + {0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00}, /* 100MHz */ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01} /* 133MHz */ +}; + + +static u8 scc_ide_inb(unsigned long port) +{ + u32 data = in_be32((void*)port); + return (u8)data; +} + +static u16 scc_ide_inw(unsigned long port) +{ + u32 data = in_be32((void*)port); + return (u16)data; +} + +static void scc_ide_insw(unsigned long port, void *addr, u32 count) +{ + u16 *ptr = (u16 *)addr; + while (count--) { + *ptr++ = le16_to_cpu(in_be32((void*)port)); + } +} + +static void scc_ide_insl(unsigned long port, void *addr, u32 count) +{ + u16 *ptr = (u16 *)addr; + while (count--) { + *ptr++ = le16_to_cpu(in_be32((void*)port)); + *ptr++ = le16_to_cpu(in_be32((void*)port)); + } +} + +static void scc_ide_outb(u8 addr, unsigned long port) +{ + out_be32((void*)port, addr); +} + +static void scc_ide_outw(u16 addr, unsigned long port) +{ + out_be32((void*)port, addr); +} + +static void +scc_ide_outbsync(ide_drive_t * drive, u8 addr, unsigned long port) +{ + ide_hwif_t *hwif = HWIF(drive); + + out_be32((void*)port, addr); + __asm__ __volatile__("eieio":::"memory"); + in_be32((void*)(hwif->dma_base + 0x01c)); + __asm__ __volatile__("eieio":::"memory"); +} + +static void +scc_ide_outsw(unsigned long port, void *addr, u32 count) +{ + u16 *ptr = (u16 *)addr; + while (count--) { + out_be32((void*)port, cpu_to_le16(*ptr++)); + } +} + +static void +scc_ide_outsl(unsigned long port, void *addr, u32 count) +{ + u16 *ptr = (u16 *)addr; + while (count--) { + out_be32((void*)port, cpu_to_le16(*ptr++)); + out_be32((void*)port, cpu_to_le16(*ptr++)); + } +} + +/** + * scc_ratemask - Compute available modes + * @drive: IDE drive + * + * Compute the available speeds for the devices on the interface. + * Enforce UDMA33 as a limit if there is no 80pin cable present. + */ + +static u8 scc_ratemask(ide_drive_t *drive) +{ + u8 mode = 4; + + if (!eighty_ninty_three(drive)) + mode = min(mode, (u8)1); + return mode; +} + +/** + * scc_tuneproc - tune a drive PIO mode + * @drive: drive to tune + * @mode_wanted: the target operating mode + * + * Load the timing settings for this device mode into the + * controller. + */ + +static void scc_tuneproc(ide_drive_t *drive, byte mode_wanted) +{ + ide_hwif_t *hwif = HWIF(drive); + struct scc_ports *ports = ide_get_hwifdata(hwif); + unsigned long ctl_base = ports->ctl; + unsigned long cckctrl_port = ctl_base + 0xff0; + unsigned long piosht_port = ctl_base + 0x000; + unsigned long pioct_port = ctl_base + 0x004; + unsigned long reg; + unsigned char speed = XFER_PIO_0; + int offset; + + mode_wanted = ide_get_best_pio_mode(drive, mode_wanted, 4, NULL); + switch (mode_wanted) { + case 4: + speed = XFER_PIO_4; + break; + case 3: + speed = XFER_PIO_3; + break; + case 2: + speed = XFER_PIO_2; + break; + case 1: + speed = XFER_PIO_1; + break; + case 0: + default: + speed = XFER_PIO_0; + break; + } + + reg = in_be32((void __iomem *)cckctrl_port); + if (reg & CCKCTRL_ATACLKOEN) { + offset = 1; /* 133MHz */ + } else { + offset = 0; /* 100MHz */ + } + reg = JCHSTtbl[offset][mode_wanted] << 16 | JCHHTtbl[offset][mode_wanted]; + out_be32((void __iomem *)piosht_port, reg); + reg = JCHCTtbl[offset][mode_wanted]; + out_be32((void __iomem *)pioct_port, reg); + + ide_config_drive_speed(drive, speed); +} + +/** + * scc_tune_chipset - tune a drive DMA mode + * @drive: Drive to set up + * @xferspeed: speed we want to achieve + * + * Load the timing settings for this device mode into the + * controller. + */ + +static int scc_tune_chipset(ide_drive_t *drive, byte xferspeed) +{ + ide_hwif_t *hwif = HWIF(drive); + u8 speed = ide_rate_filter(scc_ratemask(drive), xferspeed); + struct scc_ports *ports = ide_get_hwifdata(hwif); + unsigned long ctl_base = ports->ctl; + unsigned long cckctrl_port = ctl_base + 0xff0; + unsigned long mdmact_port = ctl_base + 0x008; + unsigned long mcrcst_port = ctl_base + 0x00c; + unsigned long sdmact_port = ctl_base + 0x010; + unsigned long scrcst_port = ctl_base + 0x014; + unsigned long udenvt_port = ctl_base + 0x018; + unsigned long tdvhsel_port = ctl_base + 0x020; + int is_slave = (&hwif->drives[1] == drive); + int offset, idx; + unsigned long reg; + unsigned long jcactsel; + + reg = in_be32((void __iomem *)cckctrl_port); + if (reg & CCKCTRL_ATACLKOEN) { + offset = 1; /* 133MHz */ + } else { + offset = 0; /* 100MHz */ + } + + switch (speed) { + case XFER_UDMA_6: + idx = 6; + break; + case XFER_UDMA_5: + idx = 5; + break; + case XFER_UDMA_4: + idx = 4; + break; + case XFER_UDMA_3: + idx = 3; + break; + case XFER_UDMA_2: + idx = 2; + break; + case XFER_UDMA_1: + idx = 1; + break; + case XFER_UDMA_0: + idx = 0; + break; + default: + return 1; + } + + jcactsel = JCACTSELtbl[offset][idx]; + if (is_slave) { + out_be32((void __iomem *)sdmact_port, JCHDCTxtbl[offset][idx]); + out_be32((void __iomem *)scrcst_port, JCSTWTxtbl[offset][idx]); + jcactsel = jcactsel << 2; + out_be32((void __iomem *)tdvhsel_port, (in_be32((void __iomem *)tdvhsel_port) & ~TDVHSEL_SLAVE) | jcactsel); + } else { + out_be32((void __iomem *)mdmact_port, JCHDCTxtbl[offset][idx]); + out_be32((void __iomem *)mcrcst_port, JCSTWTxtbl[offset][idx]); + out_be32((void __iomem *)tdvhsel_port, (in_be32((void __iomem *)tdvhsel_port) & ~TDVHSEL_MASTER) | jcactsel); + } + reg = JCTSStbl[offset][idx] << 16 | JCENVTtbl[offset][idx]; + out_be32((void __iomem *)udenvt_port, reg); + + return ide_config_drive_speed(drive, speed); +} + +/** + * scc_config_chipset_for_dma - configure for DMA + * @drive: drive to configure + * + * Called by scc_config_drive_for_dma(). + */ + +static int scc_config_chipset_for_dma(ide_drive_t *drive) +{ + u8 speed = ide_dma_speed(drive, scc_ratemask(drive)); + + if (!speed) + return 0; + + if (scc_tune_chipset(drive, speed)) + return 0; + + return ide_dma_enable(drive); +} + +/** + * scc_configure_drive_for_dma - set up for DMA transfers + * @drive: drive we are going to set up + * + * Set up the drive for DMA, tune the controller and drive as + * required. + * If the drive isn't suitable for DMA or we hit other problems + * then we will drop down to PIO and set up PIO appropriately. + * (return 1) + */ + +static int scc_config_drive_for_dma(ide_drive_t *drive) +{ + if (ide_use_dma(drive) && scc_config_chipset_for_dma(drive)) + return 0; + + if (ide_use_fast_pio(drive)) + scc_tuneproc(drive, 4); + + return -1; +} + +/** + * scc_ide_dma_setup - begin a DMA phase + * @drive: target device + * + * Build an IDE DMA PRD (IDE speak for scatter gather table) + * and then set up the DMA transfer registers. + * + * Returns 0 on success. If a PIO fallback is required then 1 + * is returned. + */ + +static int scc_dma_setup(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + struct request *rq = HWGROUP(drive)->rq; + unsigned int reading; + u8 dma_stat; + + if (rq_data_dir(rq)) + reading = 0; + else + reading = 1 << 3; + + /* fall back to pio! */ + if (!ide_build_dmatable(drive, rq)) { + ide_map_sg(drive, rq); + return 1; + } + + /* PRD table */ + out_be32((void __iomem *)hwif->dma_prdtable, hwif->dmatable_dma); + + /* specify r/w */ + out_be32((void __iomem *)hwif->dma_command, reading); + + /* read dma_status for INTR & ERROR flags */ + dma_stat = in_be32((void __iomem *)hwif->dma_status); + + /* clear INTR & ERROR flags */ + out_be32((void __iomem *)hwif->dma_status, dma_stat|6); + drive->waiting_for_dma = 1; + return 0; +} + + +/** + * scc_ide_dma_end - Stop DMA + * @drive: IDE drive + * + * Check and clear INT Status register. + * Then call __ide_dma_end(). + */ + +static int scc_ide_dma_end(ide_drive_t * drive) +{ + ide_hwif_t *hwif = HWIF(drive); + unsigned long intsts_port = hwif->dma_base + 0x014; + u32 reg; + + while (1) { + reg = in_be32((void __iomem *)intsts_port); + + if (reg & INTSTS_SERROR) { + printk(KERN_WARNING "%s: SERROR\n", SCC_PATA_NAME); + out_be32((void __iomem *)intsts_port, INTSTS_SERROR|INTSTS_BMSINT); + + out_be32((void __iomem *)hwif->dma_command, in_be32((void __iomem *)hwif->dma_command) & ~QCHCD_IOS_SS); + continue; + } + + if (reg & INTSTS_PRERR) { + u32 maea0, maec0; + unsigned long ctl_base = hwif->config_data; + + maea0 = in_be32((void __iomem *)(ctl_base + 0xF50)); + maec0 = in_be32((void __iomem *)(ctl_base + 0xF54)); + + printk(KERN_WARNING "%s: PRERR [addr:%x cmd:%x]\n", SCC_PATA_NAME, maea0, maec0); + + out_be32((void __iomem *)intsts_port, INTSTS_PRERR|INTSTS_BMSINT); + + out_be32((void __iomem *)hwif->dma_command, in_be32((void __iomem *)hwif->dma_command) & ~QCHCD_IOS_SS); + continue; + } + + if (reg & INTSTS_RERR) { + printk(KERN_WARNING "%s: Response Error\n", SCC_PATA_NAME); + out_be32((void __iomem *)intsts_port, INTSTS_RERR|INTSTS_BMSINT); + + out_be32((void __iomem *)hwif->dma_command, in_be32((void __iomem *)hwif->dma_command) & ~QCHCD_IOS_SS); + continue; + } + + if (reg & INTSTS_ICERR) { + out_be32((void __iomem *)hwif->dma_command, in_be32((void __iomem *)hwif->dma_command) & ~QCHCD_IOS_SS); + + printk(KERN_WARNING "%s: Illegal Configuration\n", SCC_PATA_NAME); + out_be32((void __iomem *)intsts_port, INTSTS_ICERR|INTSTS_BMSINT); + continue; + } + + if (reg & INTSTS_BMSINT) { + printk(KERN_WARNING "%s: Internal Bus Error\n", SCC_PATA_NAME); + out_be32((void __iomem *)intsts_port, INTSTS_BMSINT); + + ide_do_reset(drive); + continue; + } + + if (reg & INTSTS_BMHE) { + out_be32((void __iomem *)intsts_port, INTSTS_BMHE); + continue; + } + + if (reg & INTSTS_ACTEINT) { + out_be32((void __iomem *)intsts_port, INTSTS_ACTEINT); + continue; + } + + if (reg & INTSTS_IOIRQS) { + out_be32((void __iomem *)intsts_port, INTSTS_IOIRQS); + continue; + } + break; + } + + return __ide_dma_end(drive); +} + +/** + * setup_mmio_scc - map CTRL/BMID region + * @dev: PCI device we are configuring + * @name: device name + * + */ + +static int setup_mmio_scc (struct pci_dev *dev, const char *name) +{ + unsigned long ctl_base = pci_resource_start(dev, 0); + unsigned long dma_base = pci_resource_start(dev, 1); + unsigned long ctl_size = pci_resource_len(dev, 0); + unsigned long dma_size = pci_resource_len(dev, 1); + void *ctl_addr; + void *dma_addr; + int i; + + for (i = 0; i < MAX_HWIFS; i++) { + if (scc_ports[i].ctl == 0) + break; + } + if (i >= MAX_HWIFS) + return -ENOMEM; + + if (!request_mem_region(ctl_base, ctl_size, name)) { + printk(KERN_WARNING "%s: IDE controller MMIO ports not available.\n", SCC_PATA_NAME); + goto fail_0; + } + + if (!request_mem_region(dma_base, dma_size, name)) { + printk(KERN_WARNING "%s: IDE controller MMIO ports not available.\n", SCC_PATA_NAME); + goto fail_1; + } + + if ((ctl_addr = ioremap(ctl_base, ctl_size)) == NULL) + goto fail_2; + + if ((dma_addr = ioremap(dma_base, dma_size)) == NULL) + goto fail_3; + + pci_set_master(dev); + scc_ports[i].ctl = (unsigned long)ctl_addr; + scc_ports[i].dma = (unsigned long)dma_addr; + pci_set_drvdata(dev, (void *) &scc_ports[i]); + + return 1; + + fail_3: + iounmap(ctl_addr); + fail_2: + release_mem_region(dma_base, dma_size); + fail_1: + release_mem_region(ctl_base, ctl_size); + fail_0: + return -ENOMEM; +} + +/** + * init_setup_scc - set up an SCC PATA Controller + * @dev: PCI device + * @d: IDE PCI device + * + * Perform the initial set up for this device. + */ + +static int __devinit init_setup_scc(struct pci_dev *dev, ide_pci_device_t *d) +{ + unsigned long ctl_base; + unsigned long dma_base; + unsigned long cckctrl_port; + unsigned long intmask_port; + unsigned long mode_port; + unsigned long ecmode_port; + unsigned long dma_status_port; + u32 reg = 0; + struct scc_ports *ports; + int rc; + + rc = setup_mmio_scc(dev, d->name); + if (rc < 0) { + return rc; + } + + ports = pci_get_drvdata(dev); + ctl_base = ports->ctl; + dma_base = ports->dma; + cckctrl_port = ctl_base + 0xff0; + intmask_port = dma_base + 0x010; + mode_port = ctl_base + 0x024; + ecmode_port = ctl_base + 0xf00; + dma_status_port = dma_base + 0x004; + + /* controller initialization */ + reg = 0; + out_be32((void*)cckctrl_port, reg); + reg |= CCKCTRL_ATACLKOEN; + out_be32((void*)cckctrl_port, reg); + reg |= CCKCTRL_LCLKEN | CCKCTRL_OCLKEN; + out_be32((void*)cckctrl_port, reg); + reg |= CCKCTRL_CRST; + out_be32((void*)cckctrl_port, reg); + + for (;;) { + reg = in_be32((void*)cckctrl_port); + if (reg & CCKCTRL_CRST) + break; + udelay(5000); + } + + reg |= CCKCTRL_ATARESET; + out_be32((void*)cckctrl_port, reg); + + out_be32((void*)ecmode_port, ECMODE_VALUE); + out_be32((void*)mode_port, MODE_JCUSFEN); + out_be32((void*)intmask_port, INTMASK_MSK); + + return ide_setup_pci_device(dev, d); +} + +/** + * init_mmio_iops_scc - set up the iops for MMIO + * @hwif: interface to set up + * + */ + +static void __devinit init_mmio_iops_scc(ide_hwif_t *hwif) +{ + struct pci_dev *dev = hwif->pci_dev; + struct scc_ports *ports = pci_get_drvdata(dev); + unsigned long dma_base = ports->dma; + + ide_set_hwifdata(hwif, ports); + + hwif->INB = scc_ide_inb; + hwif->INW = scc_ide_inw; + hwif->INSW = scc_ide_insw; + hwif->INSL = scc_ide_insl; + hwif->OUTB = scc_ide_outb; + hwif->OUTBSYNC = scc_ide_outbsync; + hwif->OUTW = scc_ide_outw; + hwif->OUTSW = scc_ide_outsw; + hwif->OUTSL = scc_ide_outsl; + + hwif->io_ports[IDE_DATA_OFFSET] = dma_base + 0x20; + hwif->io_ports[IDE_ERROR_OFFSET] = dma_base + 0x24; + hwif->io_ports[IDE_NSECTOR_OFFSET] = dma_base + 0x28; + hwif->io_ports[IDE_SECTOR_OFFSET] = dma_base + 0x2c; + hwif->io_ports[IDE_LCYL_OFFSET] = dma_base + 0x30; + hwif->io_ports[IDE_HCYL_OFFSET] = dma_base + 0x34; + hwif->io_ports[IDE_SELECT_OFFSET] = dma_base + 0x38; + hwif->io_ports[IDE_STATUS_OFFSET] = dma_base + 0x3c; + hwif->io_ports[IDE_CONTROL_OFFSET] = dma_base + 0x40; + + hwif->irq = hwif->pci_dev->irq; + hwif->dma_base = dma_base; + hwif->config_data = ports->ctl; + hwif->mmio = 1; +} + +/** + * init_iops_scc - set up iops + * @hwif: interface to set up + * + * Do the basic setup for the SCC hardware interface + * and then do the MMIO setup. + */ + +static void __devinit init_iops_scc(ide_hwif_t *hwif) +{ + struct pci_dev *dev = hwif->pci_dev; + hwif->hwif_data = NULL; + if (pci_get_drvdata(dev) == NULL) + return; + init_mmio_iops_scc(hwif); +} + +/** + * init_hwif_scc - set up hwif + * @hwif: interface to set up + * + * We do the basic set up of the interface structure. The SCC + * requires several custom handlers so we override the default + * ide DMA handlers appropriately. + */ + +static void __devinit init_hwif_scc(ide_hwif_t *hwif) +{ + struct scc_ports *ports = ide_get_hwifdata(hwif); + + ports->hwif_id = hwif->index; + + hwif->dma_command = hwif->dma_base; + hwif->dma_status = hwif->dma_base + 0x04; + hwif->dma_prdtable = hwif->dma_base + 0x08; + + /* PTERADD */ + out_be32((void __iomem *)(hwif->dma_base + 0x018), hwif->dmatable_dma); + + hwif->dma_setup = scc_dma_setup; + hwif->ide_dma_end = scc_ide_dma_end; + hwif->speedproc = scc_tune_chipset; + hwif->tuneproc = scc_tuneproc; + hwif->ide_dma_check = scc_config_drive_for_dma; + + hwif->drives[0].autotune = IDE_TUNE_AUTO; + hwif->drives[1].autotune = IDE_TUNE_AUTO; + + if (in_be32((void __iomem *)(hwif->config_data + 0xff0)) & CCKCTRL_ATACLKOEN) { + hwif->ultra_mask = 0x7f; /* 133MHz */ + } else { + hwif->ultra_mask = 0x3f; /* 100MHz */ + } + hwif->mwdma_mask = 0x00; + hwif->swdma_mask = 0x00; + hwif->atapi_dma = 1; + + /* we support 80c cable only. */ + hwif->udma_four = 1; + + hwif->autodma = 0; + if (!noautodma) + hwif->autodma = 1; + hwif->drives[0].autodma = hwif->autodma; + hwif->drives[1].autodma = hwif->autodma; +} + +#define DECLARE_SCC_DEV(name_str) \ + { \ + .name = name_str, \ + .init_setup = init_setup_scc, \ + .init_iops = init_iops_scc, \ + .init_hwif = init_hwif_scc, \ + .channels = 1, \ + .autodma = AUTODMA, \ + .bootable = ON_BOARD, \ + } + +static ide_pci_device_t scc_chipsets[] __devinitdata = { + /* 0 */ DECLARE_SCC_DEV("sccIDE"), +}; + +/** + * scc_init_one - pci layer discovery entry + * @dev: PCI device + * @id: ident table entry + * + * Called by the PCI code when it finds an SCC PATA controller. + * We then use the IDE PCI generic helper to do most of the work. + */ + +static int __devinit scc_init_one(struct pci_dev *dev, const struct pci_device_id *id) +{ + ide_pci_device_t *d = &scc_chipsets[id->driver_data]; + return d->init_setup(dev, d); +} + +/** + * scc_remove - pci layer remove entry + * @dev: PCI device + * + * Called by the PCI code when it removes an SCC PATA controller. + */ + +static void __devexit scc_remove(struct pci_dev *dev) +{ + struct scc_ports *ports = pci_get_drvdata(dev); + ide_hwif_t *hwif = &ide_hwifs[ports->hwif_id]; + unsigned long ctl_base = pci_resource_start(dev, 0); + unsigned long dma_base = pci_resource_start(dev, 1); + unsigned long ctl_size = pci_resource_len(dev, 0); + unsigned long dma_size = pci_resource_len(dev, 1); + + if (hwif->dmatable_cpu) { + pci_free_consistent(hwif->pci_dev, + PRD_ENTRIES * PRD_BYTES, + hwif->dmatable_cpu, + hwif->dmatable_dma); + hwif->dmatable_cpu = NULL; + } + + ide_unregister(hwif->index); + + hwif->chipset = ide_unknown; + iounmap((void*)ports->dma); + iounmap((void*)ports->ctl); + release_mem_region(dma_base, dma_size); + release_mem_region(ctl_base, ctl_size); + memset(ports, 0, sizeof(*ports)); +} + +static struct pci_device_id scc_pci_tbl[] = { + { PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_SCC_ATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { 0, }, +}; +MODULE_DEVICE_TABLE(pci, scc_pci_tbl); + +static struct pci_driver driver = { + .name = "SCC IDE", + .id_table = scc_pci_tbl, + .probe = scc_init_one, + .remove = scc_remove, +}; + +static int scc_ide_init(void) +{ + return ide_pci_register_driver(&driver); +} + +module_init(scc_ide_init); +/* -- No exit code? +static void scc_ide_exit(void) +{ + ide_pci_unregister_driver(&driver); +} +module_exit(scc_ide_exit); + */ + + +MODULE_DESCRIPTION("PCI driver module for Toshiba SCC IDE"); +MODULE_LICENSE("GPL"); diff --git a/drivers/ieee1394/ieee1394-ioctl.h b/drivers/ieee1394/ieee1394-ioctl.h index 8f207508ed1d..46878fef136c 100644 --- a/drivers/ieee1394/ieee1394-ioctl.h +++ b/drivers/ieee1394/ieee1394-ioctl.h @@ -100,5 +100,7 @@ _IO ('#', 0x28) #define RAW1394_IOC_ISO_RECV_FLUSH \ _IO ('#', 0x29) +#define RAW1394_IOC_GET_CYCLE_TIMER \ + _IOR ('#', 0x30, struct raw1394_cycle_timer) #endif /* __IEEE1394_IOCTL_H */ diff --git a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c index 1521e57e124b..d791d08c743c 100644 --- a/drivers/ieee1394/ieee1394_core.c +++ b/drivers/ieee1394/ieee1394_core.c @@ -33,7 +33,10 @@ #include <linux/skbuff.h> #include <linux/suspend.h> #include <linux/kthread.h> +#include <linux/preempt.h> +#include <linux/time.h> +#include <asm/system.h> #include <asm/byteorder.h> #include "ieee1394_types.h" @@ -186,6 +189,45 @@ int hpsb_reset_bus(struct hpsb_host *host, int type) } } +/** + * hpsb_read_cycle_timer - read cycle timer register and system time + * @host: host whose isochronous cycle timer register is read + * @cycle_timer: address of bitfield to return the register contents + * @local_time: address to return the system time + * + * The format of * @cycle_timer, is described in OHCI 1.1 clause 5.13. This + * format is also read from non-OHCI controllers. * @local_time contains the + * system time in microseconds since the Epoch, read at the moment when the + * cycle timer was read. + * + * Return value: 0 for success or error number otherwise. + */ +int hpsb_read_cycle_timer(struct hpsb_host *host, u32 *cycle_timer, + u64 *local_time) +{ + int ctr; + struct timeval tv; + unsigned long flags; + + if (!host || !cycle_timer || !local_time) + return -EINVAL; + + preempt_disable(); + local_irq_save(flags); + + ctr = host->driver->devctl(host, GET_CYCLE_COUNTER, 0); + if (ctr) + do_gettimeofday(&tv); + + local_irq_restore(flags); + preempt_enable(); + + if (!ctr) + return -EIO; + *cycle_timer = ctr; + *local_time = tv.tv_sec * 1000000ULL + tv.tv_usec; + return 0; +} int hpsb_bus_reset(struct hpsb_host *host) { @@ -1190,6 +1232,7 @@ EXPORT_SYMBOL(hpsb_alloc_packet); EXPORT_SYMBOL(hpsb_free_packet); EXPORT_SYMBOL(hpsb_send_packet); EXPORT_SYMBOL(hpsb_reset_bus); +EXPORT_SYMBOL(hpsb_read_cycle_timer); EXPORT_SYMBOL(hpsb_bus_reset); EXPORT_SYMBOL(hpsb_selfid_received); EXPORT_SYMBOL(hpsb_selfid_complete); diff --git a/drivers/ieee1394/ieee1394_core.h b/drivers/ieee1394/ieee1394_core.h index 536ba3f580fd..bd29d8ef5bbd 100644 --- a/drivers/ieee1394/ieee1394_core.h +++ b/drivers/ieee1394/ieee1394_core.h @@ -127,6 +127,9 @@ int hpsb_send_packet_and_wait(struct hpsb_packet *packet); * progress, 0 otherwise. */ int hpsb_reset_bus(struct hpsb_host *host, int type); +int hpsb_read_cycle_timer(struct hpsb_host *host, u32 *cycle_timer, + u64 *local_time); + /* * The following functions are exported for host driver module usage. All of * them are safe to use in interrupt contexts, although some are quite diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c index ba9faeff4793..c5ace190bfe6 100644 --- a/drivers/ieee1394/nodemgr.c +++ b/drivers/ieee1394/nodemgr.c @@ -1681,7 +1681,8 @@ static int nodemgr_host_thread(void *__hi) for (;;) { /* Sleep until next bus reset */ set_current_state(TASK_INTERRUPTIBLE); - if (get_hpsb_generation(host) == generation) + if (get_hpsb_generation(host) == generation && + !kthread_should_stop()) schedule(); __set_current_state(TASK_RUNNING); diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c index e982d60ac4b7..06fac0d21264 100644 --- a/drivers/ieee1394/ohci1394.c +++ b/drivers/ieee1394/ohci1394.c @@ -180,7 +180,7 @@ static int alloc_dma_trm_ctx(struct ti_ohci *ohci, struct dma_trm_ctx *d, static void ohci1394_pci_remove(struct pci_dev *pdev); #ifndef __LITTLE_ENDIAN -const static size_t hdr_sizes[] = { +static const size_t hdr_sizes[] = { 3, /* TCODE_WRITEQ */ 4, /* TCODE_WRITEB */ 3, /* TCODE_WRITE_RESPONSE */ diff --git a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c index aa9ca8385ec7..bb897a37d9f7 100644 --- a/drivers/ieee1394/raw1394.c +++ b/drivers/ieee1394/raw1394.c @@ -2669,6 +2669,18 @@ static void raw1394_iso_shutdown(struct file_info *fi) fi->iso_state = RAW1394_ISO_INACTIVE; } +static int raw1394_read_cycle_timer(struct file_info *fi, void __user * uaddr) +{ + struct raw1394_cycle_timer ct; + int err; + + err = hpsb_read_cycle_timer(fi->host, &ct.cycle_timer, &ct.local_time); + if (!err) + if (copy_to_user(uaddr, &ct, sizeof(ct))) + err = -EFAULT; + return err; +} + /* mmap the rawiso xmit/recv buffer */ static int raw1394_mmap(struct file *file, struct vm_area_struct *vma) { @@ -2777,6 +2789,14 @@ static int raw1394_ioctl(struct inode *inode, struct file *file, break; } + /* state-independent commands */ + switch(cmd) { + case RAW1394_IOC_GET_CYCLE_TIMER: + return raw1394_read_cycle_timer(fi, argp); + default: + break; + } + return -EINVAL; } diff --git a/drivers/ieee1394/raw1394.h b/drivers/ieee1394/raw1394.h index 35bfc38f013c..7bd22ee1afbb 100644 --- a/drivers/ieee1394/raw1394.h +++ b/drivers/ieee1394/raw1394.h @@ -178,4 +178,14 @@ struct raw1394_iso_status { __s16 xmit_cycle; }; +/* argument to RAW1394_IOC_GET_CYCLE_TIMER ioctl */ +struct raw1394_cycle_timer { + /* contents of Isochronous Cycle Timer register, + as in OHCI 1.1 clause 5.13 (also with non-OHCI hosts) */ + __u32 cycle_timer; + + /* local time in microseconds since Epoch, + simultaneously read with cycle timer */ + __u64 local_time; +}; #endif /* IEEE1394_RAW1394_H */ diff --git a/drivers/infiniband/core/Makefile b/drivers/infiniband/core/Makefile index 50fb1cd447b7..189e5d4b9b17 100644 --- a/drivers/infiniband/core/Makefile +++ b/drivers/infiniband/core/Makefile @@ -12,7 +12,7 @@ ib_core-y := packer.o ud_header.o verbs.o sysfs.o \ ib_mad-y := mad.o smi.o agent.o mad_rmpp.o -ib_sa-y := sa_query.o +ib_sa-y := sa_query.o multicast.o ib_cm-y := cm.o diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index db88e609bf42..f8d69b3fa307 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -71,6 +71,7 @@ static struct workqueue_struct *cma_wq; static DEFINE_IDR(sdp_ps); static DEFINE_IDR(tcp_ps); static DEFINE_IDR(udp_ps); +static DEFINE_IDR(ipoib_ps); static int next_port; struct cma_device { @@ -116,6 +117,7 @@ struct rdma_id_private { struct list_head list; struct list_head listen_list; struct cma_device *cma_dev; + struct list_head mc_list; enum cma_state state; spinlock_t lock; @@ -134,10 +136,23 @@ struct rdma_id_private { } cm_id; u32 seq_num; + u32 qkey; u32 qp_num; u8 srq; }; +struct cma_multicast { + struct rdma_id_private *id_priv; + union { + struct ib_sa_multicast *ib; + } multicast; + struct list_head list; + void *context; + struct sockaddr addr; + u8 pad[sizeof(struct sockaddr_in6) - + sizeof(struct sockaddr)]; +}; + struct cma_work { struct work_struct work; struct rdma_id_private *id; @@ -243,6 +258,11 @@ static inline void sdp_set_ip_ver(struct sdp_hh *hh, u8 ip_ver) hh->ip_version = (ip_ver << 4) | (hh->ip_version & 0xF); } +static inline int cma_is_ud_ps(enum rdma_port_space ps) +{ + return (ps == RDMA_PS_UDP || ps == RDMA_PS_IPOIB); +} + static void cma_attach_to_dev(struct rdma_id_private *id_priv, struct cma_device *cma_dev) { @@ -265,19 +285,41 @@ static void cma_detach_from_dev(struct rdma_id_private *id_priv) id_priv->cma_dev = NULL; } +static int cma_set_qkey(struct ib_device *device, u8 port_num, + enum rdma_port_space ps, + struct rdma_dev_addr *dev_addr, u32 *qkey) +{ + struct ib_sa_mcmember_rec rec; + int ret = 0; + + switch (ps) { + case RDMA_PS_UDP: + *qkey = RDMA_UDP_QKEY; + break; + case RDMA_PS_IPOIB: + ib_addr_get_mgid(dev_addr, &rec.mgid); + ret = ib_sa_get_mcmember_rec(device, port_num, &rec.mgid, &rec); + *qkey = be32_to_cpu(rec.qkey); + break; + default: + break; + } + return ret; +} + static int cma_acquire_dev(struct rdma_id_private *id_priv) { - enum rdma_node_type dev_type = id_priv->id.route.addr.dev_addr.dev_type; + struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; struct cma_device *cma_dev; union ib_gid gid; int ret = -ENODEV; - switch (rdma_node_get_transport(dev_type)) { + switch (rdma_node_get_transport(dev_addr->dev_type)) { case RDMA_TRANSPORT_IB: - ib_addr_get_sgid(&id_priv->id.route.addr.dev_addr, &gid); + ib_addr_get_sgid(dev_addr, &gid); break; case RDMA_TRANSPORT_IWARP: - iw_addr_get_sgid(&id_priv->id.route.addr.dev_addr, &gid); + iw_addr_get_sgid(dev_addr, &gid); break; default: return -ENODEV; @@ -287,7 +329,12 @@ static int cma_acquire_dev(struct rdma_id_private *id_priv) ret = ib_find_cached_gid(cma_dev->device, &gid, &id_priv->id.port_num, NULL); if (!ret) { - cma_attach_to_dev(id_priv, cma_dev); + ret = cma_set_qkey(cma_dev->device, + id_priv->id.port_num, + id_priv->id.ps, dev_addr, + &id_priv->qkey); + if (!ret) + cma_attach_to_dev(id_priv, cma_dev); break; } } @@ -325,40 +372,50 @@ struct rdma_cm_id *rdma_create_id(rdma_cm_event_handler event_handler, init_waitqueue_head(&id_priv->wait_remove); atomic_set(&id_priv->dev_remove, 0); INIT_LIST_HEAD(&id_priv->listen_list); + INIT_LIST_HEAD(&id_priv->mc_list); get_random_bytes(&id_priv->seq_num, sizeof id_priv->seq_num); return &id_priv->id; } EXPORT_SYMBOL(rdma_create_id); -static int cma_init_ib_qp(struct rdma_id_private *id_priv, struct ib_qp *qp) +static int cma_init_ud_qp(struct rdma_id_private *id_priv, struct ib_qp *qp) { struct ib_qp_attr qp_attr; - struct rdma_dev_addr *dev_addr; - int ret; + int qp_attr_mask, ret; - dev_addr = &id_priv->id.route.addr.dev_addr; - ret = ib_find_cached_pkey(id_priv->id.device, id_priv->id.port_num, - ib_addr_get_pkey(dev_addr), - &qp_attr.pkey_index); + qp_attr.qp_state = IB_QPS_INIT; + ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); if (ret) return ret; - qp_attr.qp_state = IB_QPS_INIT; - qp_attr.qp_access_flags = 0; - qp_attr.port_num = id_priv->id.port_num; - return ib_modify_qp(qp, &qp_attr, IB_QP_STATE | IB_QP_ACCESS_FLAGS | - IB_QP_PKEY_INDEX | IB_QP_PORT); + ret = ib_modify_qp(qp, &qp_attr, qp_attr_mask); + if (ret) + return ret; + + qp_attr.qp_state = IB_QPS_RTR; + ret = ib_modify_qp(qp, &qp_attr, IB_QP_STATE); + if (ret) + return ret; + + qp_attr.qp_state = IB_QPS_RTS; + qp_attr.sq_psn = 0; + ret = ib_modify_qp(qp, &qp_attr, IB_QP_STATE | IB_QP_SQ_PSN); + + return ret; } -static int cma_init_iw_qp(struct rdma_id_private *id_priv, struct ib_qp *qp) +static int cma_init_conn_qp(struct rdma_id_private *id_priv, struct ib_qp *qp) { struct ib_qp_attr qp_attr; + int qp_attr_mask, ret; qp_attr.qp_state = IB_QPS_INIT; - qp_attr.qp_access_flags = IB_ACCESS_LOCAL_WRITE; + ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); + if (ret) + return ret; - return ib_modify_qp(qp, &qp_attr, IB_QP_STATE | IB_QP_ACCESS_FLAGS); + return ib_modify_qp(qp, &qp_attr, qp_attr_mask); } int rdma_create_qp(struct rdma_cm_id *id, struct ib_pd *pd, @@ -376,18 +433,10 @@ int rdma_create_qp(struct rdma_cm_id *id, struct ib_pd *pd, if (IS_ERR(qp)) return PTR_ERR(qp); - switch (rdma_node_get_transport(id->device->node_type)) { - case RDMA_TRANSPORT_IB: - ret = cma_init_ib_qp(id_priv, qp); - break; - case RDMA_TRANSPORT_IWARP: - ret = cma_init_iw_qp(id_priv, qp); - break; - default: - ret = -ENOSYS; - break; - } - + if (cma_is_ud_ps(id_priv->id.ps)) + ret = cma_init_ud_qp(id_priv, qp); + else + ret = cma_init_conn_qp(id_priv, qp); if (ret) goto err; @@ -460,23 +509,55 @@ static int cma_modify_qp_err(struct rdma_cm_id *id) return ib_modify_qp(id->qp, &qp_attr, IB_QP_STATE); } +static int cma_ib_init_qp_attr(struct rdma_id_private *id_priv, + struct ib_qp_attr *qp_attr, int *qp_attr_mask) +{ + struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; + int ret; + + ret = ib_find_cached_pkey(id_priv->id.device, id_priv->id.port_num, + ib_addr_get_pkey(dev_addr), + &qp_attr->pkey_index); + if (ret) + return ret; + + qp_attr->port_num = id_priv->id.port_num; + *qp_attr_mask = IB_QP_STATE | IB_QP_PKEY_INDEX | IB_QP_PORT; + + if (cma_is_ud_ps(id_priv->id.ps)) { + qp_attr->qkey = id_priv->qkey; + *qp_attr_mask |= IB_QP_QKEY; + } else { + qp_attr->qp_access_flags = 0; + *qp_attr_mask |= IB_QP_ACCESS_FLAGS; + } + return 0; +} + int rdma_init_qp_attr(struct rdma_cm_id *id, struct ib_qp_attr *qp_attr, int *qp_attr_mask) { struct rdma_id_private *id_priv; - int ret; + int ret = 0; id_priv = container_of(id, struct rdma_id_private, id); switch (rdma_node_get_transport(id_priv->id.device->node_type)) { case RDMA_TRANSPORT_IB: - ret = ib_cm_init_qp_attr(id_priv->cm_id.ib, qp_attr, - qp_attr_mask); + if (!id_priv->cm_id.ib || cma_is_ud_ps(id_priv->id.ps)) + ret = cma_ib_init_qp_attr(id_priv, qp_attr, qp_attr_mask); + else + ret = ib_cm_init_qp_attr(id_priv->cm_id.ib, qp_attr, + qp_attr_mask); if (qp_attr->qp_state == IB_QPS_RTR) qp_attr->rq_psn = id_priv->seq_num; break; case RDMA_TRANSPORT_IWARP: - ret = iw_cm_init_qp_attr(id_priv->cm_id.iw, qp_attr, - qp_attr_mask); + if (!id_priv->cm_id.iw) { + qp_attr->qp_access_flags = IB_ACCESS_LOCAL_WRITE; + *qp_attr_mask = IB_QP_STATE | IB_QP_ACCESS_FLAGS; + } else + ret = iw_cm_init_qp_attr(id_priv->cm_id.iw, qp_attr, + qp_attr_mask); break; default: ret = -ENOSYS; @@ -698,6 +779,19 @@ static void cma_release_port(struct rdma_id_private *id_priv) mutex_unlock(&lock); } +static void cma_leave_mc_groups(struct rdma_id_private *id_priv) +{ + struct cma_multicast *mc; + + while (!list_empty(&id_priv->mc_list)) { + mc = container_of(id_priv->mc_list.next, + struct cma_multicast, list); + list_del(&mc->list); + ib_sa_free_multicast(mc->multicast.ib); + kfree(mc); + } +} + void rdma_destroy_id(struct rdma_cm_id *id) { struct rdma_id_private *id_priv; @@ -722,6 +816,7 @@ void rdma_destroy_id(struct rdma_cm_id *id) default: break; } + cma_leave_mc_groups(id_priv); mutex_lock(&lock); cma_detach_from_dev(id_priv); } @@ -972,7 +1067,7 @@ static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event) memset(&event, 0, sizeof event); offset = cma_user_data_offset(listen_id->id.ps); event.event = RDMA_CM_EVENT_CONNECT_REQUEST; - if (listen_id->id.ps == RDMA_PS_UDP) { + if (cma_is_ud_ps(listen_id->id.ps)) { conn_id = cma_new_udp_id(&listen_id->id, ib_event); event.param.ud.private_data = ib_event->private_data + offset; event.param.ud.private_data_len = @@ -1725,7 +1820,7 @@ static int cma_alloc_port(struct idr *ps, struct rdma_id_private *id_priv, struct rdma_bind_list *bind_list; int port, ret; - bind_list = kzalloc(sizeof *bind_list, GFP_KERNEL); + bind_list = kmalloc(sizeof *bind_list, GFP_KERNEL); if (!bind_list) return -ENOMEM; @@ -1847,6 +1942,9 @@ static int cma_get_port(struct rdma_id_private *id_priv) case RDMA_PS_UDP: ps = &udp_ps; break; + case RDMA_PS_IPOIB: + ps = &ipoib_ps; + break; default: return -EPROTONOSUPPORT; } @@ -1961,7 +2059,7 @@ static int cma_sidr_rep_handler(struct ib_cm_id *cm_id, event.status = ib_event->param.sidr_rep_rcvd.status; break; } - if (rep->qkey != RDMA_UD_QKEY) { + if (id_priv->qkey != rep->qkey) { event.event = RDMA_CM_EVENT_UNREACHABLE; event.status = -EINVAL; break; @@ -2160,7 +2258,7 @@ int rdma_connect(struct rdma_cm_id *id, struct rdma_conn_param *conn_param) switch (rdma_node_get_transport(id->device->node_type)) { case RDMA_TRANSPORT_IB: - if (id->ps == RDMA_PS_UDP) + if (cma_is_ud_ps(id->ps)) ret = cma_resolve_ib_udp(id_priv, conn_param); else ret = cma_connect_ib(id_priv, conn_param); @@ -2256,7 +2354,7 @@ static int cma_send_sidr_rep(struct rdma_id_private *id_priv, rep.status = status; if (status == IB_SIDR_SUCCESS) { rep.qp_num = id_priv->qp_num; - rep.qkey = RDMA_UD_QKEY; + rep.qkey = id_priv->qkey; } rep.private_data = private_data; rep.private_data_len = private_data_len; @@ -2280,7 +2378,7 @@ int rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param) switch (rdma_node_get_transport(id->device->node_type)) { case RDMA_TRANSPORT_IB: - if (id->ps == RDMA_PS_UDP) + if (cma_is_ud_ps(id->ps)) ret = cma_send_sidr_rep(id_priv, IB_SIDR_SUCCESS, conn_param->private_data, conn_param->private_data_len); @@ -2341,7 +2439,7 @@ int rdma_reject(struct rdma_cm_id *id, const void *private_data, switch (rdma_node_get_transport(id->device->node_type)) { case RDMA_TRANSPORT_IB: - if (id->ps == RDMA_PS_UDP) + if (cma_is_ud_ps(id->ps)) ret = cma_send_sidr_rep(id_priv, IB_SIDR_REJECT, private_data, private_data_len); else @@ -2392,6 +2490,178 @@ out: } EXPORT_SYMBOL(rdma_disconnect); +static int cma_ib_mc_handler(int status, struct ib_sa_multicast *multicast) +{ + struct rdma_id_private *id_priv; + struct cma_multicast *mc = multicast->context; + struct rdma_cm_event event; + int ret; + + id_priv = mc->id_priv; + atomic_inc(&id_priv->dev_remove); + if (!cma_comp(id_priv, CMA_ADDR_BOUND) && + !cma_comp(id_priv, CMA_ADDR_RESOLVED)) + goto out; + + if (!status && id_priv->id.qp) + status = ib_attach_mcast(id_priv->id.qp, &multicast->rec.mgid, + multicast->rec.mlid); + + memset(&event, 0, sizeof event); + event.status = status; + event.param.ud.private_data = mc->context; + if (!status) { + event.event = RDMA_CM_EVENT_MULTICAST_JOIN; + ib_init_ah_from_mcmember(id_priv->id.device, + id_priv->id.port_num, &multicast->rec, + &event.param.ud.ah_attr); + event.param.ud.qp_num = 0xFFFFFF; + event.param.ud.qkey = be32_to_cpu(multicast->rec.qkey); + } else + event.event = RDMA_CM_EVENT_MULTICAST_ERROR; + + ret = id_priv->id.event_handler(&id_priv->id, &event); + if (ret) { + cma_exch(id_priv, CMA_DESTROYING); + cma_release_remove(id_priv); + rdma_destroy_id(&id_priv->id); + return 0; + } +out: + cma_release_remove(id_priv); + return 0; +} + +static void cma_set_mgid(struct rdma_id_private *id_priv, + struct sockaddr *addr, union ib_gid *mgid) +{ + unsigned char mc_map[MAX_ADDR_LEN]; + struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; + struct sockaddr_in *sin = (struct sockaddr_in *) addr; + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) addr; + + if (cma_any_addr(addr)) { + memset(mgid, 0, sizeof *mgid); + } else if ((addr->sa_family == AF_INET6) && + ((be32_to_cpu(sin6->sin6_addr.s6_addr32[0]) & 0xFF10A01B) == + 0xFF10A01B)) { + /* IPv6 address is an SA assigned MGID. */ + memcpy(mgid, &sin6->sin6_addr, sizeof *mgid); + } else { + ip_ib_mc_map(sin->sin_addr.s_addr, mc_map); + if (id_priv->id.ps == RDMA_PS_UDP) + mc_map[7] = 0x01; /* Use RDMA CM signature */ + mc_map[8] = ib_addr_get_pkey(dev_addr) >> 8; + mc_map[9] = (unsigned char) ib_addr_get_pkey(dev_addr); + *mgid = *(union ib_gid *) (mc_map + 4); + } +} + +static int cma_join_ib_multicast(struct rdma_id_private *id_priv, + struct cma_multicast *mc) +{ + struct ib_sa_mcmember_rec rec; + struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; + ib_sa_comp_mask comp_mask; + int ret; + + ib_addr_get_mgid(dev_addr, &rec.mgid); + ret = ib_sa_get_mcmember_rec(id_priv->id.device, id_priv->id.port_num, + &rec.mgid, &rec); + if (ret) + return ret; + + cma_set_mgid(id_priv, &mc->addr, &rec.mgid); + if (id_priv->id.ps == RDMA_PS_UDP) + rec.qkey = cpu_to_be32(RDMA_UDP_QKEY); + ib_addr_get_sgid(dev_addr, &rec.port_gid); + rec.pkey = cpu_to_be16(ib_addr_get_pkey(dev_addr)); + rec.join_state = 1; + + comp_mask = IB_SA_MCMEMBER_REC_MGID | IB_SA_MCMEMBER_REC_PORT_GID | + IB_SA_MCMEMBER_REC_PKEY | IB_SA_MCMEMBER_REC_JOIN_STATE | + IB_SA_MCMEMBER_REC_QKEY | IB_SA_MCMEMBER_REC_SL | + IB_SA_MCMEMBER_REC_FLOW_LABEL | + IB_SA_MCMEMBER_REC_TRAFFIC_CLASS; + + mc->multicast.ib = ib_sa_join_multicast(&sa_client, id_priv->id.device, + id_priv->id.port_num, &rec, + comp_mask, GFP_KERNEL, + cma_ib_mc_handler, mc); + if (IS_ERR(mc->multicast.ib)) + return PTR_ERR(mc->multicast.ib); + + return 0; +} + +int rdma_join_multicast(struct rdma_cm_id *id, struct sockaddr *addr, + void *context) +{ + struct rdma_id_private *id_priv; + struct cma_multicast *mc; + int ret; + + id_priv = container_of(id, struct rdma_id_private, id); + if (!cma_comp(id_priv, CMA_ADDR_BOUND) && + !cma_comp(id_priv, CMA_ADDR_RESOLVED)) + return -EINVAL; + + mc = kmalloc(sizeof *mc, GFP_KERNEL); + if (!mc) + return -ENOMEM; + + memcpy(&mc->addr, addr, ip_addr_size(addr)); + mc->context = context; + mc->id_priv = id_priv; + + spin_lock(&id_priv->lock); + list_add(&mc->list, &id_priv->mc_list); + spin_unlock(&id_priv->lock); + + switch (rdma_node_get_transport(id->device->node_type)) { + case RDMA_TRANSPORT_IB: + ret = cma_join_ib_multicast(id_priv, mc); + break; + default: + ret = -ENOSYS; + break; + } + + if (ret) { + spin_lock_irq(&id_priv->lock); + list_del(&mc->list); + spin_unlock_irq(&id_priv->lock); + kfree(mc); + } + return ret; +} +EXPORT_SYMBOL(rdma_join_multicast); + +void rdma_leave_multicast(struct rdma_cm_id *id, struct sockaddr *addr) +{ + struct rdma_id_private *id_priv; + struct cma_multicast *mc; + + id_priv = container_of(id, struct rdma_id_private, id); + spin_lock_irq(&id_priv->lock); + list_for_each_entry(mc, &id_priv->mc_list, list) { + if (!memcmp(&mc->addr, addr, ip_addr_size(addr))) { + list_del(&mc->list); + spin_unlock_irq(&id_priv->lock); + + if (id->qp) + ib_detach_mcast(id->qp, + &mc->multicast.ib->rec.mgid, + mc->multicast.ib->rec.mlid); + ib_sa_free_multicast(mc->multicast.ib); + kfree(mc); + return; + } + } + spin_unlock_irq(&id_priv->lock); +} +EXPORT_SYMBOL(rdma_leave_multicast); + static void cma_add_one(struct ib_device *device) { struct cma_device *cma_dev; @@ -2522,6 +2792,7 @@ static void cma_cleanup(void) idr_destroy(&sdp_ps); idr_destroy(&tcp_ps); idr_destroy(&udp_ps); + idr_destroy(&ipoib_ps); } module_init(cma_init); diff --git a/drivers/infiniband/core/fmr_pool.c b/drivers/infiniband/core/fmr_pool.c index 8926a2bd4a87..1d796e7c8199 100644 --- a/drivers/infiniband/core/fmr_pool.c +++ b/drivers/infiniband/core/fmr_pool.c @@ -301,7 +301,7 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd, { struct ib_pool_fmr *fmr; - struct ib_fmr_attr attr = { + struct ib_fmr_attr fmr_attr = { .max_pages = params->max_pages_per_fmr, .max_maps = pool->max_remaps, .page_shift = params->page_shift @@ -321,7 +321,7 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd, fmr->ref_count = 0; INIT_HLIST_NODE(&fmr->cache_node); - fmr->fmr = ib_alloc_fmr(pd, params->access, &attr); + fmr->fmr = ib_alloc_fmr(pd, params->access, &fmr_attr); if (IS_ERR(fmr->fmr)) { printk(KERN_WARNING "fmr_create failed for FMR %d", i); kfree(fmr); diff --git a/drivers/infiniband/core/iwcm.c b/drivers/infiniband/core/iwcm.c index 1039ad57d53b..891d1fa7b2eb 100644 --- a/drivers/infiniband/core/iwcm.c +++ b/drivers/infiniband/core/iwcm.c @@ -146,6 +146,12 @@ static int copy_private_data(struct iw_cm_event *event) return 0; } +static void free_cm_id(struct iwcm_id_private *cm_id_priv) +{ + dealloc_work_entries(cm_id_priv); + kfree(cm_id_priv); +} + /* * Release a reference on cm_id. If the last reference is being * released, enable the waiting thread (in iw_destroy_cm_id) to @@ -153,21 +159,14 @@ static int copy_private_data(struct iw_cm_event *event) */ static int iwcm_deref_id(struct iwcm_id_private *cm_id_priv) { - int ret = 0; - BUG_ON(atomic_read(&cm_id_priv->refcount)==0); if (atomic_dec_and_test(&cm_id_priv->refcount)) { BUG_ON(!list_empty(&cm_id_priv->work_list)); - if (waitqueue_active(&cm_id_priv->destroy_comp.wait)) { - BUG_ON(cm_id_priv->state != IW_CM_STATE_DESTROYING); - BUG_ON(test_bit(IWCM_F_CALLBACK_DESTROY, - &cm_id_priv->flags)); - ret = 1; - } complete(&cm_id_priv->destroy_comp); + return 1; } - return ret; + return 0; } static void add_ref(struct iw_cm_id *cm_id) @@ -181,7 +180,11 @@ static void rem_ref(struct iw_cm_id *cm_id) { struct iwcm_id_private *cm_id_priv; cm_id_priv = container_of(cm_id, struct iwcm_id_private, id); - iwcm_deref_id(cm_id_priv); + if (iwcm_deref_id(cm_id_priv) && + test_bit(IWCM_F_CALLBACK_DESTROY, &cm_id_priv->flags)) { + BUG_ON(!list_empty(&cm_id_priv->work_list)); + free_cm_id(cm_id_priv); + } } static int cm_event_handler(struct iw_cm_id *cm_id, struct iw_cm_event *event); @@ -355,7 +358,9 @@ static void destroy_cm_id(struct iw_cm_id *cm_id) case IW_CM_STATE_CONN_RECV: /* * App called destroy before/without calling accept after - * receiving connection request event notification. + * receiving connection request event notification or + * returned non zero from the event callback function. + * In either case, must tell the provider to reject. */ cm_id_priv->state = IW_CM_STATE_DESTROYING; break; @@ -391,9 +396,7 @@ void iw_destroy_cm_id(struct iw_cm_id *cm_id) wait_for_completion(&cm_id_priv->destroy_comp); - dealloc_work_entries(cm_id_priv); - - kfree(cm_id_priv); + free_cm_id(cm_id_priv); } EXPORT_SYMBOL(iw_destroy_cm_id); @@ -647,10 +650,11 @@ static void cm_conn_req_handler(struct iwcm_id_private *listen_id_priv, /* Call the client CM handler */ ret = cm_id->cm_handler(cm_id, iw_event); if (ret) { + iw_cm_reject(cm_id, NULL, 0); set_bit(IWCM_F_CALLBACK_DESTROY, &cm_id_priv->flags); destroy_cm_id(cm_id); if (atomic_read(&cm_id_priv->refcount)==0) - kfree(cm_id); + free_cm_id(cm_id_priv); } out: @@ -854,13 +858,12 @@ static void cm_work_handler(struct work_struct *_work) destroy_cm_id(&cm_id_priv->id); } BUG_ON(atomic_read(&cm_id_priv->refcount)==0); - if (iwcm_deref_id(cm_id_priv)) - return; - - if (atomic_read(&cm_id_priv->refcount)==0 && - test_bit(IWCM_F_CALLBACK_DESTROY, &cm_id_priv->flags)) { - dealloc_work_entries(cm_id_priv); - kfree(cm_id_priv); + if (iwcm_deref_id(cm_id_priv)) { + if (test_bit(IWCM_F_CALLBACK_DESTROY, + &cm_id_priv->flags)) { + BUG_ON(!list_empty(&cm_id_priv->work_list)); + free_cm_id(cm_id_priv); + } return; } spin_lock_irqsave(&cm_id_priv->lock, flags); diff --git a/drivers/infiniband/core/multicast.c b/drivers/infiniband/core/multicast.c new file mode 100644 index 000000000000..4a579b3a1c90 --- /dev/null +++ b/drivers/infiniband/core/multicast.c @@ -0,0 +1,837 @@ +/* + * Copyright (c) 2006 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include <linux/completion.h> +#include <linux/dma-mapping.h> +#include <linux/err.h> +#include <linux/interrupt.h> +#include <linux/pci.h> +#include <linux/bitops.h> +#include <linux/random.h> + +#include <rdma/ib_cache.h> +#include "sa.h" + +static void mcast_add_one(struct ib_device *device); +static void mcast_remove_one(struct ib_device *device); + +static struct ib_client mcast_client = { + .name = "ib_multicast", + .add = mcast_add_one, + .remove = mcast_remove_one +}; + +static struct ib_sa_client sa_client; +static struct workqueue_struct *mcast_wq; +static union ib_gid mgid0; + +struct mcast_device; + +struct mcast_port { + struct mcast_device *dev; + spinlock_t lock; + struct rb_root table; + atomic_t refcount; + struct completion comp; + u8 port_num; +}; + +struct mcast_device { + struct ib_device *device; + struct ib_event_handler event_handler; + int start_port; + int end_port; + struct mcast_port port[0]; +}; + +enum mcast_state { + MCAST_IDLE, + MCAST_JOINING, + MCAST_MEMBER, + MCAST_BUSY, + MCAST_ERROR +}; + +struct mcast_member; + +struct mcast_group { + struct ib_sa_mcmember_rec rec; + struct rb_node node; + struct mcast_port *port; + spinlock_t lock; + struct work_struct work; + struct list_head pending_list; + struct list_head active_list; + struct mcast_member *last_join; + int members[3]; + atomic_t refcount; + enum mcast_state state; + struct ib_sa_query *query; + int query_id; +}; + +struct mcast_member { + struct ib_sa_multicast multicast; + struct ib_sa_client *client; + struct mcast_group *group; + struct list_head list; + enum mcast_state state; + atomic_t refcount; + struct completion comp; +}; + +static void join_handler(int status, struct ib_sa_mcmember_rec *rec, + void *context); +static void leave_handler(int status, struct ib_sa_mcmember_rec *rec, + void *context); + +static struct mcast_group *mcast_find(struct mcast_port *port, + union ib_gid *mgid) +{ + struct rb_node *node = port->table.rb_node; + struct mcast_group *group; + int ret; + + while (node) { + group = rb_entry(node, struct mcast_group, node); + ret = memcmp(mgid->raw, group->rec.mgid.raw, sizeof *mgid); + if (!ret) + return group; + + if (ret < 0) + node = node->rb_left; + else + node = node->rb_right; + } + return NULL; +} + +static struct mcast_group *mcast_insert(struct mcast_port *port, + struct mcast_group *group, + int allow_duplicates) +{ + struct rb_node **link = &port->table.rb_node; + struct rb_node *parent = NULL; + struct mcast_group *cur_group; + int ret; + + while (*link) { + parent = *link; + cur_group = rb_entry(parent, struct mcast_group, node); + + ret = memcmp(group->rec.mgid.raw, cur_group->rec.mgid.raw, + sizeof group->rec.mgid); + if (ret < 0) + link = &(*link)->rb_left; + else if (ret > 0) + link = &(*link)->rb_right; + else if (allow_duplicates) + link = &(*link)->rb_left; + else + return cur_group; + } + rb_link_node(&group->node, parent, link); + rb_insert_color(&group->node, &port->table); + return NULL; +} + +static void deref_port(struct mcast_port *port) +{ + if (atomic_dec_and_test(&port->refcount)) + complete(&port->comp); +} + +static void release_group(struct mcast_group *group) +{ + struct mcast_port *port = group->port; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + if (atomic_dec_and_test(&group->refcount)) { + rb_erase(&group->node, &port->table); + spin_unlock_irqrestore(&port->lock, flags); + kfree(group); + deref_port(port); + } else + spin_unlock_irqrestore(&port->lock, flags); +} + +static void deref_member(struct mcast_member *member) +{ + if (atomic_dec_and_test(&member->refcount)) + complete(&member->comp); +} + +static void queue_join(struct mcast_member *member) +{ + struct mcast_group *group = member->group; + unsigned long flags; + + spin_lock_irqsave(&group->lock, flags); + list_add(&member->list, &group->pending_list); + if (group->state == MCAST_IDLE) { + group->state = MCAST_BUSY; + atomic_inc(&group->refcount); + queue_work(mcast_wq, &group->work); + } + spin_unlock_irqrestore(&group->lock, flags); +} + +/* + * A multicast group has three types of members: full member, non member, and + * send only member. We need to keep track of the number of members of each + * type based on their join state. Adjust the number of members the belong to + * the specified join states. + */ +static void adjust_membership(struct mcast_group *group, u8 join_state, int inc) +{ + int i; + + for (i = 0; i < 3; i++, join_state >>= 1) + if (join_state & 0x1) + group->members[i] += inc; +} + +/* + * If a multicast group has zero members left for a particular join state, but + * the group is still a member with the SA, we need to leave that join state. + * Determine which join states we still belong to, but that do not have any + * active members. + */ +static u8 get_leave_state(struct mcast_group *group) +{ + u8 leave_state = 0; + int i; + + for (i = 0; i < 3; i++) + if (!group->members[i]) + leave_state |= (0x1 << i); + + return leave_state & group->rec.join_state; +} + +static int check_selector(ib_sa_comp_mask comp_mask, + ib_sa_comp_mask selector_mask, + ib_sa_comp_mask value_mask, + u8 selector, u8 src_value, u8 dst_value) +{ + int err; + + if (!(comp_mask & selector_mask) || !(comp_mask & value_mask)) + return 0; + + switch (selector) { + case IB_SA_GT: + err = (src_value <= dst_value); + break; + case IB_SA_LT: + err = (src_value >= dst_value); + break; + case IB_SA_EQ: + err = (src_value != dst_value); + break; + default: + err = 0; + break; + } + + return err; +} + +static int cmp_rec(struct ib_sa_mcmember_rec *src, + struct ib_sa_mcmember_rec *dst, ib_sa_comp_mask comp_mask) +{ + /* MGID must already match */ + + if (comp_mask & IB_SA_MCMEMBER_REC_PORT_GID && + memcmp(&src->port_gid, &dst->port_gid, sizeof src->port_gid)) + return -EINVAL; + if (comp_mask & IB_SA_MCMEMBER_REC_QKEY && src->qkey != dst->qkey) + return -EINVAL; + if (comp_mask & IB_SA_MCMEMBER_REC_MLID && src->mlid != dst->mlid) + return -EINVAL; + if (check_selector(comp_mask, IB_SA_MCMEMBER_REC_MTU_SELECTOR, + IB_SA_MCMEMBER_REC_MTU, dst->mtu_selector, + src->mtu, dst->mtu)) + return -EINVAL; + if (comp_mask & IB_SA_MCMEMBER_REC_TRAFFIC_CLASS && + src->traffic_class != dst->traffic_class) + return -EINVAL; + if (comp_mask & IB_SA_MCMEMBER_REC_PKEY && src->pkey != dst->pkey) + return -EINVAL; + if (check_selector(comp_mask, IB_SA_MCMEMBER_REC_RATE_SELECTOR, + IB_SA_MCMEMBER_REC_RATE, dst->rate_selector, + src->rate, dst->rate)) + return -EINVAL; + if (check_selector(comp_mask, + IB_SA_MCMEMBER_REC_PACKET_LIFE_TIME_SELECTOR, + IB_SA_MCMEMBER_REC_PACKET_LIFE_TIME, + dst->packet_life_time_selector, + src->packet_life_time, dst->packet_life_time)) + return -EINVAL; + if (comp_mask & IB_SA_MCMEMBER_REC_SL && src->sl != dst->sl) + return -EINVAL; + if (comp_mask & IB_SA_MCMEMBER_REC_FLOW_LABEL && + src->flow_label != dst->flow_label) + return -EINVAL; + if (comp_mask & IB_SA_MCMEMBER_REC_HOP_LIMIT && + src->hop_limit != dst->hop_limit) + return -EINVAL; + if (comp_mask & IB_SA_MCMEMBER_REC_SCOPE && src->scope != dst->scope) + return -EINVAL; + + /* join_state checked separately, proxy_join ignored */ + + return 0; +} + +static int send_join(struct mcast_group *group, struct mcast_member *member) +{ + struct mcast_port *port = group->port; + int ret; + + group->last_join = member; + ret = ib_sa_mcmember_rec_query(&sa_client, port->dev->device, + port->port_num, IB_MGMT_METHOD_SET, + &member->multicast.rec, + member->multicast.comp_mask, + 3000, GFP_KERNEL, join_handler, group, + &group->query); + if (ret >= 0) { + group->query_id = ret; + ret = 0; + } + return ret; +} + +static int send_leave(struct mcast_group *group, u8 leave_state) +{ + struct mcast_port *port = group->port; + struct ib_sa_mcmember_rec rec; + int ret; + + rec = group->rec; + rec.join_state = leave_state; + + ret = ib_sa_mcmember_rec_query(&sa_client, port->dev->device, + port->port_num, IB_SA_METHOD_DELETE, &rec, + IB_SA_MCMEMBER_REC_MGID | + IB_SA_MCMEMBER_REC_PORT_GID | + IB_SA_MCMEMBER_REC_JOIN_STATE, + 3000, GFP_KERNEL, leave_handler, + group, &group->query); + if (ret >= 0) { + group->query_id = ret; + ret = 0; + } + return ret; +} + +static void join_group(struct mcast_group *group, struct mcast_member *member, + u8 join_state) +{ + member->state = MCAST_MEMBER; + adjust_membership(group, join_state, 1); + group->rec.join_state |= join_state; + member->multicast.rec = group->rec; + member->multicast.rec.join_state = join_state; + list_move(&member->list, &group->active_list); +} + +static int fail_join(struct mcast_group *group, struct mcast_member *member, + int status) +{ + spin_lock_irq(&group->lock); + list_del_init(&member->list); + spin_unlock_irq(&group->lock); + return member->multicast.callback(status, &member->multicast); +} + +static void process_group_error(struct mcast_group *group) +{ + struct mcast_member *member; + int ret; + + spin_lock_irq(&group->lock); + while (!list_empty(&group->active_list)) { + member = list_entry(group->active_list.next, + struct mcast_member, list); + atomic_inc(&member->refcount); + list_del_init(&member->list); + adjust_membership(group, member->multicast.rec.join_state, -1); + member->state = MCAST_ERROR; + spin_unlock_irq(&group->lock); + + ret = member->multicast.callback(-ENETRESET, + &member->multicast); + deref_member(member); + if (ret) + ib_sa_free_multicast(&member->multicast); + spin_lock_irq(&group->lock); + } + + group->rec.join_state = 0; + group->state = MCAST_BUSY; + spin_unlock_irq(&group->lock); +} + +static void mcast_work_handler(struct work_struct *work) +{ + struct mcast_group *group; + struct mcast_member *member; + struct ib_sa_multicast *multicast; + int status, ret; + u8 join_state; + + group = container_of(work, typeof(*group), work); +retest: + spin_lock_irq(&group->lock); + while (!list_empty(&group->pending_list) || + (group->state == MCAST_ERROR)) { + + if (group->state == MCAST_ERROR) { + spin_unlock_irq(&group->lock); + process_group_error(group); + goto retest; + } + + member = list_entry(group->pending_list.next, + struct mcast_member, list); + multicast = &member->multicast; + join_state = multicast->rec.join_state; + atomic_inc(&member->refcount); + + if (join_state == (group->rec.join_state & join_state)) { + status = cmp_rec(&group->rec, &multicast->rec, + multicast->comp_mask); + if (!status) + join_group(group, member, join_state); + else + list_del_init(&member->list); + spin_unlock_irq(&group->lock); + ret = multicast->callback(status, multicast); + } else { + spin_unlock_irq(&group->lock); + status = send_join(group, member); + if (!status) { + deref_member(member); + return; + } + ret = fail_join(group, member, status); + } + + deref_member(member); + if (ret) + ib_sa_free_multicast(&member->multicast); + spin_lock_irq(&group->lock); + } + + join_state = get_leave_state(group); + if (join_state) { + group->rec.join_state &= ~join_state; + spin_unlock_irq(&group->lock); + if (send_leave(group, join_state)) + goto retest; + } else { + group->state = MCAST_IDLE; + spin_unlock_irq(&group->lock); + release_group(group); + } +} + +/* + * Fail a join request if it is still active - at the head of the pending queue. + */ +static void process_join_error(struct mcast_group *group, int status) +{ + struct mcast_member *member; + int ret; + + spin_lock_irq(&group->lock); + member = list_entry(group->pending_list.next, + struct mcast_member, list); + if (group->last_join == member) { + atomic_inc(&member->refcount); + list_del_init(&member->list); + spin_unlock_irq(&group->lock); + ret = member->multicast.callback(status, &member->multicast); + deref_member(member); + if (ret) + ib_sa_free_multicast(&member->multicast); + } else + spin_unlock_irq(&group->lock); +} + +static void join_handler(int status, struct ib_sa_mcmember_rec *rec, + void *context) +{ + struct mcast_group *group = context; + + if (status) + process_join_error(group, status); + else { + spin_lock_irq(&group->port->lock); + group->rec = *rec; + if (!memcmp(&mgid0, &group->rec.mgid, sizeof mgid0)) { + rb_erase(&group->node, &group->port->table); + mcast_insert(group->port, group, 1); + } + spin_unlock_irq(&group->port->lock); + } + mcast_work_handler(&group->work); +} + +static void leave_handler(int status, struct ib_sa_mcmember_rec *rec, + void *context) +{ + struct mcast_group *group = context; + + mcast_work_handler(&group->work); +} + +static struct mcast_group *acquire_group(struct mcast_port *port, + union ib_gid *mgid, gfp_t gfp_mask) +{ + struct mcast_group *group, *cur_group; + unsigned long flags; + int is_mgid0; + + is_mgid0 = !memcmp(&mgid0, mgid, sizeof mgid0); + if (!is_mgid0) { + spin_lock_irqsave(&port->lock, flags); + group = mcast_find(port, mgid); + if (group) + goto found; + spin_unlock_irqrestore(&port->lock, flags); + } + + group = kzalloc(sizeof *group, gfp_mask); + if (!group) + return NULL; + + group->port = port; + group->rec.mgid = *mgid; + INIT_LIST_HEAD(&group->pending_list); + INIT_LIST_HEAD(&group->active_list); + INIT_WORK(&group->work, mcast_work_handler); + spin_lock_init(&group->lock); + + spin_lock_irqsave(&port->lock, flags); + cur_group = mcast_insert(port, group, is_mgid0); + if (cur_group) { + kfree(group); + group = cur_group; + } else + atomic_inc(&port->refcount); +found: + atomic_inc(&group->refcount); + spin_unlock_irqrestore(&port->lock, flags); + return group; +} + +/* + * We serialize all join requests to a single group to make our lives much + * easier. Otherwise, two users could try to join the same group + * simultaneously, with different configurations, one could leave while the + * join is in progress, etc., which makes locking around error recovery + * difficult. + */ +struct ib_sa_multicast * +ib_sa_join_multicast(struct ib_sa_client *client, + struct ib_device *device, u8 port_num, + struct ib_sa_mcmember_rec *rec, + ib_sa_comp_mask comp_mask, gfp_t gfp_mask, + int (*callback)(int status, + struct ib_sa_multicast *multicast), + void *context) +{ + struct mcast_device *dev; + struct mcast_member *member; + struct ib_sa_multicast *multicast; + int ret; + + dev = ib_get_client_data(device, &mcast_client); + if (!dev) + return ERR_PTR(-ENODEV); + + member = kmalloc(sizeof *member, gfp_mask); + if (!member) + return ERR_PTR(-ENOMEM); + + ib_sa_client_get(client); + member->client = client; + member->multicast.rec = *rec; + member->multicast.comp_mask = comp_mask; + member->multicast.callback = callback; + member->multicast.context = context; + init_completion(&member->comp); + atomic_set(&member->refcount, 1); + member->state = MCAST_JOINING; + + member->group = acquire_group(&dev->port[port_num - dev->start_port], + &rec->mgid, gfp_mask); + if (!member->group) { + ret = -ENOMEM; + goto err; + } + + /* + * The user will get the multicast structure in their callback. They + * could then free the multicast structure before we can return from + * this routine. So we save the pointer to return before queuing + * any callback. + */ + multicast = &member->multicast; + queue_join(member); + return multicast; + +err: + ib_sa_client_put(client); + kfree(member); + return ERR_PTR(ret); +} +EXPORT_SYMBOL(ib_sa_join_multicast); + +void ib_sa_free_multicast(struct ib_sa_multicast *multicast) +{ + struct mcast_member *member; + struct mcast_group *group; + + member = container_of(multicast, struct mcast_member, multicast); + group = member->group; + + spin_lock_irq(&group->lock); + if (member->state == MCAST_MEMBER) + adjust_membership(group, multicast->rec.join_state, -1); + + list_del_init(&member->list); + + if (group->state == MCAST_IDLE) { + group->state = MCAST_BUSY; + spin_unlock_irq(&group->lock); + /* Continue to hold reference on group until callback */ + queue_work(mcast_wq, &group->work); + } else { + spin_unlock_irq(&group->lock); + release_group(group); + } + + deref_member(member); + wait_for_completion(&member->comp); + ib_sa_client_put(member->client); + kfree(member); +} +EXPORT_SYMBOL(ib_sa_free_multicast); + +int ib_sa_get_mcmember_rec(struct ib_device *device, u8 port_num, + union ib_gid *mgid, struct ib_sa_mcmember_rec *rec) +{ + struct mcast_device *dev; + struct mcast_port *port; + struct mcast_group *group; + unsigned long flags; + int ret = 0; + + dev = ib_get_client_data(device, &mcast_client); + if (!dev) + return -ENODEV; + + port = &dev->port[port_num - dev->start_port]; + spin_lock_irqsave(&port->lock, flags); + group = mcast_find(port, mgid); + if (group) + *rec = group->rec; + else + ret = -EADDRNOTAVAIL; + spin_unlock_irqrestore(&port->lock, flags); + + return ret; +} +EXPORT_SYMBOL(ib_sa_get_mcmember_rec); + +int ib_init_ah_from_mcmember(struct ib_device *device, u8 port_num, + struct ib_sa_mcmember_rec *rec, + struct ib_ah_attr *ah_attr) +{ + int ret; + u16 gid_index; + u8 p; + + ret = ib_find_cached_gid(device, &rec->port_gid, &p, &gid_index); + if (ret) + return ret; + + memset(ah_attr, 0, sizeof *ah_attr); + ah_attr->dlid = be16_to_cpu(rec->mlid); + ah_attr->sl = rec->sl; + ah_attr->port_num = port_num; + ah_attr->static_rate = rec->rate; + + ah_attr->ah_flags = IB_AH_GRH; + ah_attr->grh.dgid = rec->mgid; + + ah_attr->grh.sgid_index = (u8) gid_index; + ah_attr->grh.flow_label = be32_to_cpu(rec->flow_label); + ah_attr->grh.hop_limit = rec->hop_limit; + ah_attr->grh.traffic_class = rec->traffic_class; + + return 0; +} +EXPORT_SYMBOL(ib_init_ah_from_mcmember); + +static void mcast_groups_lost(struct mcast_port *port) +{ + struct mcast_group *group; + struct rb_node *node; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + for (node = rb_first(&port->table); node; node = rb_next(node)) { + group = rb_entry(node, struct mcast_group, node); + spin_lock(&group->lock); + if (group->state == MCAST_IDLE) { + atomic_inc(&group->refcount); + queue_work(mcast_wq, &group->work); + } + group->state = MCAST_ERROR; + spin_unlock(&group->lock); + } + spin_unlock_irqrestore(&port->lock, flags); +} + +static void mcast_event_handler(struct ib_event_handler *handler, + struct ib_event *event) +{ + struct mcast_device *dev; + + dev = container_of(handler, struct mcast_device, event_handler); + + switch (event->event) { + case IB_EVENT_PORT_ERR: + case IB_EVENT_LID_CHANGE: + case IB_EVENT_SM_CHANGE: + case IB_EVENT_CLIENT_REREGISTER: + mcast_groups_lost(&dev->port[event->element.port_num - + dev->start_port]); + break; + default: + break; + } +} + +static void mcast_add_one(struct ib_device *device) +{ + struct mcast_device *dev; + struct mcast_port *port; + int i; + + if (rdma_node_get_transport(device->node_type) != RDMA_TRANSPORT_IB) + return; + + dev = kmalloc(sizeof *dev + device->phys_port_cnt * sizeof *port, + GFP_KERNEL); + if (!dev) + return; + + if (device->node_type == RDMA_NODE_IB_SWITCH) + dev->start_port = dev->end_port = 0; + else { + dev->start_port = 1; + dev->end_port = device->phys_port_cnt; + } + + for (i = 0; i <= dev->end_port - dev->start_port; i++) { + port = &dev->port[i]; + port->dev = dev; + port->port_num = dev->start_port + i; + spin_lock_init(&port->lock); + port->table = RB_ROOT; + init_completion(&port->comp); + atomic_set(&port->refcount, 1); + } + + dev->device = device; + ib_set_client_data(device, &mcast_client, dev); + + INIT_IB_EVENT_HANDLER(&dev->event_handler, device, mcast_event_handler); + ib_register_event_handler(&dev->event_handler); +} + +static void mcast_remove_one(struct ib_device *device) +{ + struct mcast_device *dev; + struct mcast_port *port; + int i; + + dev = ib_get_client_data(device, &mcast_client); + if (!dev) + return; + + ib_unregister_event_handler(&dev->event_handler); + flush_workqueue(mcast_wq); + + for (i = 0; i <= dev->end_port - dev->start_port; i++) { + port = &dev->port[i]; + deref_port(port); + wait_for_completion(&port->comp); + } + + kfree(dev); +} + +int mcast_init(void) +{ + int ret; + + mcast_wq = create_singlethread_workqueue("ib_mcast"); + if (!mcast_wq) + return -ENOMEM; + + ib_sa_register_client(&sa_client); + + ret = ib_register_client(&mcast_client); + if (ret) + goto err; + return 0; + +err: + ib_sa_unregister_client(&sa_client); + destroy_workqueue(mcast_wq); + return ret; +} + +void mcast_cleanup(void) +{ + ib_unregister_client(&mcast_client); + ib_sa_unregister_client(&sa_client); + destroy_workqueue(mcast_wq); +} diff --git a/drivers/infiniband/core/sa.h b/drivers/infiniband/core/sa.h new file mode 100644 index 000000000000..24c93fd320fb --- /dev/null +++ b/drivers/infiniband/core/sa.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2004 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2006 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef SA_H +#define SA_H + +#include <rdma/ib_sa.h> + +static inline void ib_sa_client_get(struct ib_sa_client *client) +{ + atomic_inc(&client->users); +} + +static inline void ib_sa_client_put(struct ib_sa_client *client) +{ + if (atomic_dec_and_test(&client->users)) + complete(&client->comp); +} + +int ib_sa_mcmember_rec_query(struct ib_sa_client *client, + struct ib_device *device, u8 port_num, + u8 method, + struct ib_sa_mcmember_rec *rec, + ib_sa_comp_mask comp_mask, + int timeout_ms, gfp_t gfp_mask, + void (*callback)(int status, + struct ib_sa_mcmember_rec *resp, + void *context), + void *context, + struct ib_sa_query **sa_query); + +int mcast_init(void); +void mcast_cleanup(void); + +#endif /* SA_H */ diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c index e45afba75341..68db633711c5 100644 --- a/drivers/infiniband/core/sa_query.c +++ b/drivers/infiniband/core/sa_query.c @@ -47,8 +47,8 @@ #include <linux/workqueue.h> #include <rdma/ib_pack.h> -#include <rdma/ib_sa.h> #include <rdma/ib_cache.h> +#include "sa.h" MODULE_AUTHOR("Roland Dreier"); MODULE_DESCRIPTION("InfiniBand subnet administration query support"); @@ -425,17 +425,6 @@ void ib_sa_register_client(struct ib_sa_client *client) } EXPORT_SYMBOL(ib_sa_register_client); -static inline void ib_sa_client_get(struct ib_sa_client *client) -{ - atomic_inc(&client->users); -} - -static inline void ib_sa_client_put(struct ib_sa_client *client) -{ - if (atomic_dec_and_test(&client->users)) - complete(&client->comp); -} - void ib_sa_unregister_client(struct ib_sa_client *client) { ib_sa_client_put(client); @@ -482,6 +471,7 @@ int ib_init_ah_from_path(struct ib_device *device, u8 port_num, ah_attr->sl = rec->sl; ah_attr->src_path_bits = be16_to_cpu(rec->slid) & 0x7f; ah_attr->port_num = port_num; + ah_attr->static_rate = rec->rate; if (rec->hop_limit > 1) { ah_attr->ah_flags = IB_AH_GRH; @@ -901,7 +891,6 @@ err1: kfree(query); return ret; } -EXPORT_SYMBOL(ib_sa_mcmember_rec_query); static void send_handler(struct ib_mad_agent *agent, struct ib_mad_send_wc *mad_send_wc) @@ -1053,14 +1042,27 @@ static int __init ib_sa_init(void) get_random_bytes(&tid, sizeof tid); ret = ib_register_client(&sa_client); - if (ret) + if (ret) { printk(KERN_ERR "Couldn't register ib_sa client\n"); + goto err1; + } + + ret = mcast_init(); + if (ret) { + printk(KERN_ERR "Couldn't initialize multicast handling\n"); + goto err2; + } + return 0; +err2: + ib_unregister_client(&sa_client); +err1: return ret; } static void __exit ib_sa_cleanup(void) { + mcast_cleanup(); ib_unregister_client(&sa_client); idr_destroy(&query_idr); } diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c index 709323c14c5d..000c086bf2e9 100644 --- a/drivers/infiniband/core/sysfs.c +++ b/drivers/infiniband/core/sysfs.c @@ -714,8 +714,6 @@ int ib_device_register_sysfs(struct ib_device *device) if (ret) goto err_put; } else { - int i; - for (i = 1; i <= device->phys_port_cnt; ++i) { ret = add_port(device, i); if (ret) diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c index 6b81b98961c7..b516b93b8550 100644 --- a/drivers/infiniband/core/ucma.c +++ b/drivers/infiniband/core/ucma.c @@ -70,10 +70,24 @@ struct ucma_context { u64 uid; struct list_head list; + struct list_head mc_list; +}; + +struct ucma_multicast { + struct ucma_context *ctx; + int id; + int events_reported; + + u64 uid; + struct list_head list; + struct sockaddr addr; + u8 pad[sizeof(struct sockaddr_in6) - + sizeof(struct sockaddr)]; }; struct ucma_event { struct ucma_context *ctx; + struct ucma_multicast *mc; struct list_head list; struct rdma_cm_id *cm_id; struct rdma_ucm_event_resp resp; @@ -81,6 +95,7 @@ struct ucma_event { static DEFINE_MUTEX(mut); static DEFINE_IDR(ctx_idr); +static DEFINE_IDR(multicast_idr); static inline struct ucma_context *_ucma_find_context(int id, struct ucma_file *file) @@ -124,6 +139,7 @@ static struct ucma_context *ucma_alloc_ctx(struct ucma_file *file) atomic_set(&ctx->ref, 1); init_completion(&ctx->comp); + INIT_LIST_HEAD(&ctx->mc_list); ctx->file = file; do { @@ -147,6 +163,37 @@ error: return NULL; } +static struct ucma_multicast* ucma_alloc_multicast(struct ucma_context *ctx) +{ + struct ucma_multicast *mc; + int ret; + + mc = kzalloc(sizeof(*mc), GFP_KERNEL); + if (!mc) + return NULL; + + do { + ret = idr_pre_get(&multicast_idr, GFP_KERNEL); + if (!ret) + goto error; + + mutex_lock(&mut); + ret = idr_get_new(&multicast_idr, mc, &mc->id); + mutex_unlock(&mut); + } while (ret == -EAGAIN); + + if (ret) + goto error; + + mc->ctx = ctx; + list_add_tail(&mc->list, &ctx->mc_list); + return mc; + +error: + kfree(mc); + return NULL; +} + static void ucma_copy_conn_event(struct rdma_ucm_conn_param *dst, struct rdma_conn_param *src) { @@ -180,8 +227,19 @@ static void ucma_set_event_context(struct ucma_context *ctx, struct ucma_event *uevent) { uevent->ctx = ctx; - uevent->resp.uid = ctx->uid; - uevent->resp.id = ctx->id; + switch (event->event) { + case RDMA_CM_EVENT_MULTICAST_JOIN: + case RDMA_CM_EVENT_MULTICAST_ERROR: + uevent->mc = (struct ucma_multicast *) + event->param.ud.private_data; + uevent->resp.uid = uevent->mc->uid; + uevent->resp.id = uevent->mc->id; + break; + default: + uevent->resp.uid = ctx->uid; + uevent->resp.id = ctx->id; + break; + } } static int ucma_event_handler(struct rdma_cm_id *cm_id, @@ -199,7 +257,7 @@ static int ucma_event_handler(struct rdma_cm_id *cm_id, ucma_set_event_context(ctx, event, uevent); uevent->resp.event = event->event; uevent->resp.status = event->status; - if (cm_id->ps == RDMA_PS_UDP) + if (cm_id->ps == RDMA_PS_UDP || cm_id->ps == RDMA_PS_IPOIB) ucma_copy_ud_event(&uevent->resp.param.ud, &event->param.ud); else ucma_copy_conn_event(&uevent->resp.param.conn, @@ -290,6 +348,8 @@ static ssize_t ucma_get_event(struct ucma_file *file, const char __user *inbuf, list_del(&uevent->list); uevent->ctx->events_reported++; + if (uevent->mc) + uevent->mc->events_reported++; kfree(uevent); done: mutex_unlock(&file->mut); @@ -342,6 +402,19 @@ err1: return ret; } +static void ucma_cleanup_multicast(struct ucma_context *ctx) +{ + struct ucma_multicast *mc, *tmp; + + mutex_lock(&mut); + list_for_each_entry_safe(mc, tmp, &ctx->mc_list, list) { + list_del(&mc->list); + idr_remove(&multicast_idr, mc->id); + kfree(mc); + } + mutex_unlock(&mut); +} + static void ucma_cleanup_events(struct ucma_context *ctx) { struct ucma_event *uevent, *tmp; @@ -360,6 +433,19 @@ static void ucma_cleanup_events(struct ucma_context *ctx) } } +static void ucma_cleanup_mc_events(struct ucma_multicast *mc) +{ + struct ucma_event *uevent, *tmp; + + list_for_each_entry_safe(uevent, tmp, &mc->ctx->file->event_list, list) { + if (uevent->mc != mc) + continue; + + list_del(&uevent->list); + kfree(uevent); + } +} + static int ucma_free_ctx(struct ucma_context *ctx) { int events_reported; @@ -367,6 +453,8 @@ static int ucma_free_ctx(struct ucma_context *ctx) /* No new events will be generated after destroying the id. */ rdma_destroy_id(ctx->cm_id); + ucma_cleanup_multicast(ctx); + /* Cleanup events not yet reported to the user. */ mutex_lock(&ctx->file->mut); ucma_cleanup_events(ctx); @@ -731,6 +819,114 @@ static ssize_t ucma_notify(struct ucma_file *file, const char __user *inbuf, return ret; } +static ssize_t ucma_join_multicast(struct ucma_file *file, + const char __user *inbuf, + int in_len, int out_len) +{ + struct rdma_ucm_join_mcast cmd; + struct rdma_ucm_create_id_resp resp; + struct ucma_context *ctx; + struct ucma_multicast *mc; + int ret; + + if (out_len < sizeof(resp)) + return -ENOSPC; + + if (copy_from_user(&cmd, inbuf, sizeof(cmd))) + return -EFAULT; + + ctx = ucma_get_ctx(file, cmd.id); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + + mutex_lock(&file->mut); + mc = ucma_alloc_multicast(ctx); + if (IS_ERR(mc)) { + ret = PTR_ERR(mc); + goto err1; + } + + mc->uid = cmd.uid; + memcpy(&mc->addr, &cmd.addr, sizeof cmd.addr); + ret = rdma_join_multicast(ctx->cm_id, &mc->addr, mc); + if (ret) + goto err2; + + resp.id = mc->id; + if (copy_to_user((void __user *)(unsigned long)cmd.response, + &resp, sizeof(resp))) { + ret = -EFAULT; + goto err3; + } + + mutex_unlock(&file->mut); + ucma_put_ctx(ctx); + return 0; + +err3: + rdma_leave_multicast(ctx->cm_id, &mc->addr); + ucma_cleanup_mc_events(mc); +err2: + mutex_lock(&mut); + idr_remove(&multicast_idr, mc->id); + mutex_unlock(&mut); + list_del(&mc->list); + kfree(mc); +err1: + mutex_unlock(&file->mut); + ucma_put_ctx(ctx); + return ret; +} + +static ssize_t ucma_leave_multicast(struct ucma_file *file, + const char __user *inbuf, + int in_len, int out_len) +{ + struct rdma_ucm_destroy_id cmd; + struct rdma_ucm_destroy_id_resp resp; + struct ucma_multicast *mc; + int ret = 0; + + if (out_len < sizeof(resp)) + return -ENOSPC; + + if (copy_from_user(&cmd, inbuf, sizeof(cmd))) + return -EFAULT; + + mutex_lock(&mut); + mc = idr_find(&multicast_idr, cmd.id); + if (!mc) + mc = ERR_PTR(-ENOENT); + else if (mc->ctx->file != file) + mc = ERR_PTR(-EINVAL); + else { + idr_remove(&multicast_idr, mc->id); + atomic_inc(&mc->ctx->ref); + } + mutex_unlock(&mut); + + if (IS_ERR(mc)) { + ret = PTR_ERR(mc); + goto out; + } + + rdma_leave_multicast(mc->ctx->cm_id, &mc->addr); + mutex_lock(&mc->ctx->file->mut); + ucma_cleanup_mc_events(mc); + list_del(&mc->list); + mutex_unlock(&mc->ctx->file->mut); + + ucma_put_ctx(mc->ctx); + resp.events_reported = mc->events_reported; + kfree(mc); + + if (copy_to_user((void __user *)(unsigned long)cmd.response, + &resp, sizeof(resp))) + ret = -EFAULT; +out: + return ret; +} + static ssize_t (*ucma_cmd_table[])(struct ucma_file *file, const char __user *inbuf, int in_len, int out_len) = { @@ -750,6 +946,8 @@ static ssize_t (*ucma_cmd_table[])(struct ucma_file *file, [RDMA_USER_CM_CMD_GET_OPTION] = NULL, [RDMA_USER_CM_CMD_SET_OPTION] = NULL, [RDMA_USER_CM_CMD_NOTIFY] = ucma_notify, + [RDMA_USER_CM_CMD_JOIN_MCAST] = ucma_join_multicast, + [RDMA_USER_CM_CMD_LEAVE_MCAST] = ucma_leave_multicast, }; static ssize_t ucma_write(struct file *filp, const char __user *buf, diff --git a/drivers/infiniband/hw/cxgb3/cxio_dbg.c b/drivers/infiniband/hw/cxgb3/cxio_dbg.c index 5a7306f5efae..75f7b16a271d 100644 --- a/drivers/infiniband/hw/cxgb3/cxio_dbg.c +++ b/drivers/infiniband/hw/cxgb3/cxio_dbg.c @@ -1,6 +1,5 @@ /* * Copyright (c) 2006 Chelsio, Inc. All rights reserved. - * Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.c b/drivers/infiniband/hw/cxgb3/cxio_hal.c index 82fa72041989..114ac3b775dc 100644 --- a/drivers/infiniband/hw/cxgb3/cxio_hal.c +++ b/drivers/infiniband/hw/cxgb3/cxio_hal.c @@ -1,6 +1,5 @@ /* * Copyright (c) 2006 Chelsio, Inc. All rights reserved. - * Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.h b/drivers/infiniband/hw/cxgb3/cxio_hal.h index 1b97e80b8780..8ab04a7c6f6e 100644 --- a/drivers/infiniband/hw/cxgb3/cxio_hal.h +++ b/drivers/infiniband/hw/cxgb3/cxio_hal.h @@ -1,6 +1,5 @@ /* * Copyright (c) 2006 Chelsio, Inc. All rights reserved. - * Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/infiniband/hw/cxgb3/cxio_resource.c b/drivers/infiniband/hw/cxgb3/cxio_resource.c index 997aa32cbf07..65bf577311aa 100644 --- a/drivers/infiniband/hw/cxgb3/cxio_resource.c +++ b/drivers/infiniband/hw/cxgb3/cxio_resource.c @@ -1,6 +1,5 @@ /* * Copyright (c) 2006 Chelsio, Inc. All rights reserved. - * Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/infiniband/hw/cxgb3/cxio_resource.h b/drivers/infiniband/hw/cxgb3/cxio_resource.h index a6bbe8370d81..a2703a3d882d 100644 --- a/drivers/infiniband/hw/cxgb3/cxio_resource.h +++ b/drivers/infiniband/hw/cxgb3/cxio_resource.h @@ -1,6 +1,5 @@ /* * Copyright (c) 2006 Chelsio, Inc. All rights reserved. - * Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/infiniband/hw/cxgb3/cxio_wr.h b/drivers/infiniband/hw/cxgb3/cxio_wr.h index 103fc42d6976..90d7b8972cb4 100644 --- a/drivers/infiniband/hw/cxgb3/cxio_wr.h +++ b/drivers/infiniband/hw/cxgb3/cxio_wr.h @@ -1,6 +1,5 @@ /* * Copyright (c) 2006 Chelsio, Inc. All rights reserved. - * Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/infiniband/hw/cxgb3/iwch.c b/drivers/infiniband/hw/cxgb3/iwch.c index 4611afa52220..0315c9d9fce9 100644 --- a/drivers/infiniband/hw/cxgb3/iwch.c +++ b/drivers/infiniband/hw/cxgb3/iwch.c @@ -1,6 +1,5 @@ /* * Copyright (c) 2006 Chelsio, Inc. All rights reserved. - * Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/infiniband/hw/cxgb3/iwch.h b/drivers/infiniband/hw/cxgb3/iwch.h index 6517ef85026f..caf4e6007a44 100644 --- a/drivers/infiniband/hw/cxgb3/iwch.h +++ b/drivers/infiniband/hw/cxgb3/iwch.h @@ -1,6 +1,5 @@ /* * Copyright (c) 2006 Chelsio, Inc. All rights reserved. - * Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c index a522b1baa3b4..e5442e34b788 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_cm.c +++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c @@ -1,6 +1,5 @@ /* * Copyright (c) 2006 Chelsio, Inc. All rights reserved. - * Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.h b/drivers/infiniband/hw/cxgb3/iwch_cm.h index 7c810d904279..0c6f281bd4a0 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_cm.h +++ b/drivers/infiniband/hw/cxgb3/iwch_cm.h @@ -1,6 +1,5 @@ /* * Copyright (c) 2006 Chelsio, Inc. All rights reserved. - * Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/infiniband/hw/cxgb3/iwch_cq.c b/drivers/infiniband/hw/cxgb3/iwch_cq.c index 98b3bdb5de9e..d7624c170ee7 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_cq.c +++ b/drivers/infiniband/hw/cxgb3/iwch_cq.c @@ -1,6 +1,5 @@ /* * Copyright (c) 2006 Chelsio, Inc. All rights reserved. - * Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/infiniband/hw/cxgb3/iwch_ev.c b/drivers/infiniband/hw/cxgb3/iwch_ev.c index a6efa8fe15d8..54362afbf72f 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_ev.c +++ b/drivers/infiniband/hw/cxgb3/iwch_ev.c @@ -1,6 +1,5 @@ /* * Copyright (c) 2006 Chelsio, Inc. All rights reserved. - * Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/infiniband/hw/cxgb3/iwch_mem.c b/drivers/infiniband/hw/cxgb3/iwch_mem.c index 2b6cd53bb3fc..a6c2c4ba29e6 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_mem.c +++ b/drivers/infiniband/hw/cxgb3/iwch_mem.c @@ -1,6 +1,5 @@ /* * Copyright (c) 2006 Chelsio, Inc. All rights reserved. - * Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.c b/drivers/infiniband/hw/cxgb3/iwch_provider.c index 6861087d776c..2aef122f9955 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_provider.c +++ b/drivers/infiniband/hw/cxgb3/iwch_provider.c @@ -1,6 +1,5 @@ /* * Copyright (c) 2006 Chelsio, Inc. All rights reserved. - * Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.h b/drivers/infiniband/hw/cxgb3/iwch_provider.h index 61e3278fd7a8..2af3e93b607f 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_provider.h +++ b/drivers/infiniband/hw/cxgb3/iwch_provider.h @@ -1,6 +1,5 @@ /* * Copyright (c) 2006 Chelsio, Inc. All rights reserved. - * Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/infiniband/hw/cxgb3/iwch_qp.c b/drivers/infiniband/hw/cxgb3/iwch_qp.c index e066727504b6..4dda2f6da2de 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_qp.c +++ b/drivers/infiniband/hw/cxgb3/iwch_qp.c @@ -1,6 +1,5 @@ /* * Copyright (c) 2006 Chelsio, Inc. All rights reserved. - * Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -846,6 +845,8 @@ int iwch_modify_qp(struct iwch_dev *rhp, struct iwch_qp *qhp, break; case IWCH_QP_STATE_TERMINATE: qhp->attr.state = IWCH_QP_STATE_TERMINATE; + if (t3b_device(qhp->rhp)) + cxio_set_wq_in_error(&qhp->wq); if (!internal) terminate = 1; break; diff --git a/drivers/infiniband/hw/cxgb3/iwch_user.h b/drivers/infiniband/hw/cxgb3/iwch_user.h index c4e7fbea8bbd..cb7086f558c1 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_user.h +++ b/drivers/infiniband/hw/cxgb3/iwch_user.h @@ -1,6 +1,5 @@ /* * Copyright (c) 2006 Chelsio, Inc. All rights reserved. - * Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/infiniband/hw/ehca/Kconfig b/drivers/infiniband/hw/ehca/Kconfig index 727b10d89686..1a854598e0e6 100644 --- a/drivers/infiniband/hw/ehca/Kconfig +++ b/drivers/infiniband/hw/ehca/Kconfig @@ -7,11 +7,3 @@ config INFINIBAND_EHCA To compile the driver as a module, choose M here. The module will be called ib_ehca. -config INFINIBAND_EHCA_SCALING - bool "Scaling support (EXPERIMENTAL)" - depends on IBMEBUS && INFINIBAND_EHCA && HOTPLUG_CPU && EXPERIMENTAL - default y - ---help--- - eHCA scaling support schedules the CQ callbacks to different CPUs. - - To enable this feature choose Y here. diff --git a/drivers/infiniband/hw/ehca/ehca_classes.h b/drivers/infiniband/hw/ehca/ehca_classes.h index cf95ee474b0f..40404c9e2817 100644 --- a/drivers/infiniband/hw/ehca/ehca_classes.h +++ b/drivers/infiniband/hw/ehca/ehca_classes.h @@ -42,8 +42,6 @@ #ifndef __EHCA_CLASSES_H__ #define __EHCA_CLASSES_H__ -#include "ehca_classes.h" -#include "ipz_pt_fn.h" struct ehca_module; struct ehca_qp; @@ -54,14 +52,22 @@ struct ehca_mw; struct ehca_pd; struct ehca_av; +#include <rdma/ib_verbs.h> +#include <rdma/ib_user_verbs.h> + #ifdef CONFIG_PPC64 #include "ehca_classes_pSeries.h" #endif +#include "ipz_pt_fn.h" +#include "ehca_qes.h" +#include "ehca_irq.h" -#include <rdma/ib_verbs.h> -#include <rdma/ib_user_verbs.h> +#define EHCA_EQE_CACHE_SIZE 20 -#include "ehca_irq.h" +struct ehca_eqe_cache_entry { + struct ehca_eqe *eqe; + struct ehca_cq *cq; +}; struct ehca_eq { u32 length; @@ -74,6 +80,8 @@ struct ehca_eq { spinlock_t spinlock; struct tasklet_struct interrupt_task; u32 ist; + spinlock_t irq_spinlock; + struct ehca_eqe_cache_entry eqe_cache[EHCA_EQE_CACHE_SIZE]; }; struct ehca_sport { @@ -269,6 +277,7 @@ extern struct idr ehca_cq_idr; extern int ehca_static_rate; extern int ehca_port_act_time; extern int ehca_use_hp_mr; +extern int ehca_scaling_code; struct ipzu_queue_resp { u32 qe_size; /* queue entry size */ diff --git a/drivers/infiniband/hw/ehca/ehca_eq.c b/drivers/infiniband/hw/ehca/ehca_eq.c index 24ceab0bae4a..4961eb88827c 100644 --- a/drivers/infiniband/hw/ehca/ehca_eq.c +++ b/drivers/infiniband/hw/ehca/ehca_eq.c @@ -61,6 +61,7 @@ int ehca_create_eq(struct ehca_shca *shca, struct ib_device *ib_dev = &shca->ib_device; spin_lock_init(&eq->spinlock); + spin_lock_init(&eq->irq_spinlock); eq->is_initialized = 0; if (type != EHCA_EQ && type != EHCA_NEQ) { diff --git a/drivers/infiniband/hw/ehca/ehca_hca.c b/drivers/infiniband/hw/ehca/ehca_hca.c index b7be950ab47c..30eb45df9f0b 100644 --- a/drivers/infiniband/hw/ehca/ehca_hca.c +++ b/drivers/infiniband/hw/ehca/ehca_hca.c @@ -162,6 +162,9 @@ int ehca_query_port(struct ib_device *ibdev, props->active_width = IB_WIDTH_12X; props->active_speed = 0x1; + /* at the moment (logical) link state is always LINK_UP */ + props->phys_state = 0x5; + query_port1: ehca_free_fw_ctrlblock(rblock); diff --git a/drivers/infiniband/hw/ehca/ehca_irq.c b/drivers/infiniband/hw/ehca/ehca_irq.c index 6c4f9f91b15d..3ec53c687d08 100644 --- a/drivers/infiniband/hw/ehca/ehca_irq.c +++ b/drivers/infiniband/hw/ehca/ehca_irq.c @@ -63,15 +63,11 @@ #define ERROR_DATA_LENGTH EHCA_BMASK_IBM(52,63) #define ERROR_DATA_TYPE EHCA_BMASK_IBM(0,7) -#ifdef CONFIG_INFINIBAND_EHCA_SCALING - static void queue_comp_task(struct ehca_cq *__cq); static struct ehca_comp_pool* pool; static struct notifier_block comp_pool_callback_nb; -#endif - static inline void comp_event_callback(struct ehca_cq *cq) { if (!cq->ib_cq.comp_handler) @@ -206,7 +202,7 @@ static void qp_event_callback(struct ehca_shca *shca, } static void cq_event_callback(struct ehca_shca *shca, - u64 eqe) + u64 eqe) { struct ehca_cq *cq; unsigned long flags; @@ -318,7 +314,7 @@ static void parse_ec(struct ehca_shca *shca, u64 eqe) "disruptive port %x configuration change", port); ehca_info(&shca->ib_device, - "port %x is inactive.", port); + "port %x is inactive.", port); event.device = &shca->ib_device; event.event = IB_EVENT_PORT_ERR; event.element.port_num = port; @@ -326,7 +322,7 @@ static void parse_ec(struct ehca_shca *shca, u64 eqe) ib_dispatch_event(&event); ehca_info(&shca->ib_device, - "port %x is active.", port); + "port %x is active.", port); event.device = &shca->ib_device; event.event = IB_EVENT_PORT_ACTIVE; event.element.port_num = port; @@ -401,115 +397,170 @@ irqreturn_t ehca_interrupt_eq(int irq, void *dev_id) return IRQ_HANDLED; } -void ehca_tasklet_eq(unsigned long data) -{ - struct ehca_shca *shca = (struct ehca_shca*)data; - struct ehca_eqe *eqe; - int int_state; - int query_cnt = 0; - do { - eqe = (struct ehca_eqe *)ehca_poll_eq(shca, &shca->eq); +static inline void process_eqe(struct ehca_shca *shca, struct ehca_eqe *eqe) +{ + u64 eqe_value; + u32 token; + unsigned long flags; + struct ehca_cq *cq; + eqe_value = eqe->entry; + ehca_dbg(&shca->ib_device, "eqe_value=%lx", eqe_value); + if (EHCA_BMASK_GET(EQE_COMPLETION_EVENT, eqe_value)) { + ehca_dbg(&shca->ib_device, "... completion event"); + token = EHCA_BMASK_GET(EQE_CQ_TOKEN, eqe_value); + spin_lock_irqsave(&ehca_cq_idr_lock, flags); + cq = idr_find(&ehca_cq_idr, token); + if (cq == NULL) { + spin_unlock_irqrestore(&ehca_cq_idr_lock, flags); + ehca_err(&shca->ib_device, + "Invalid eqe for non-existing cq token=%x", + token); + return; + } + reset_eq_pending(cq); + if (ehca_scaling_code) { + queue_comp_task(cq); + spin_unlock_irqrestore(&ehca_cq_idr_lock, flags); + } else { + spin_unlock_irqrestore(&ehca_cq_idr_lock, flags); + comp_event_callback(cq); + } + } else { + ehca_dbg(&shca->ib_device, + "Got non completion event"); + parse_identifier(shca, eqe_value); + } +} - if ((shca->hw_level >= 2) && eqe) - int_state = 1; - else - int_state = 0; - - while ((int_state == 1) || eqe) { - while (eqe) { - u64 eqe_value = eqe->entry; - - ehca_dbg(&shca->ib_device, - "eqe_value=%lx", eqe_value); - - /* TODO: better structure */ - if (EHCA_BMASK_GET(EQE_COMPLETION_EVENT, - eqe_value)) { - unsigned long flags; - u32 token; - struct ehca_cq *cq; - - ehca_dbg(&shca->ib_device, - "... completion event"); - token = - EHCA_BMASK_GET(EQE_CQ_TOKEN, - eqe_value); - spin_lock_irqsave(&ehca_cq_idr_lock, - flags); - cq = idr_find(&ehca_cq_idr, token); - - if (cq == NULL) { - spin_unlock_irqrestore(&ehca_cq_idr_lock, - flags); - break; - } - - reset_eq_pending(cq); -#ifdef CONFIG_INFINIBAND_EHCA_SCALING - queue_comp_task(cq); - spin_unlock_irqrestore(&ehca_cq_idr_lock, - flags); -#else - spin_unlock_irqrestore(&ehca_cq_idr_lock, - flags); - comp_event_callback(cq); -#endif - } else { - ehca_dbg(&shca->ib_device, - "... non completion event"); - parse_identifier(shca, eqe_value); - } - eqe = - (struct ehca_eqe *)ehca_poll_eq(shca, - &shca->eq); - } +void ehca_process_eq(struct ehca_shca *shca, int is_irq) +{ + struct ehca_eq *eq = &shca->eq; + struct ehca_eqe_cache_entry *eqe_cache = eq->eqe_cache; + u64 eqe_value; + unsigned long flags; + int eqe_cnt, i; + int eq_empty = 0; + + spin_lock_irqsave(&eq->irq_spinlock, flags); + if (is_irq) { + const int max_query_cnt = 100; + int query_cnt = 0; + int int_state = 1; + do { + int_state = hipz_h_query_int_state( + shca->ipz_hca_handle, eq->ist); + query_cnt++; + iosync(); + } while (int_state && query_cnt < max_query_cnt); + if (unlikely((query_cnt == max_query_cnt))) + ehca_dbg(&shca->ib_device, "int_state=%x query_cnt=%x", + int_state, query_cnt); + } - if (shca->hw_level >= 2) { - int_state = - hipz_h_query_int_state(shca->ipz_hca_handle, - shca->eq.ist); - query_cnt++; - iosync(); - if (query_cnt >= 100) { - query_cnt = 0; - int_state = 0; - } + /* read out all eqes */ + eqe_cnt = 0; + do { + u32 token; + eqe_cache[eqe_cnt].eqe = + (struct ehca_eqe *)ehca_poll_eq(shca, eq); + if (!eqe_cache[eqe_cnt].eqe) + break; + eqe_value = eqe_cache[eqe_cnt].eqe->entry; + if (EHCA_BMASK_GET(EQE_COMPLETION_EVENT, eqe_value)) { + token = EHCA_BMASK_GET(EQE_CQ_TOKEN, eqe_value); + spin_lock(&ehca_cq_idr_lock); + eqe_cache[eqe_cnt].cq = idr_find(&ehca_cq_idr, token); + if (!eqe_cache[eqe_cnt].cq) { + spin_unlock(&ehca_cq_idr_lock); + ehca_err(&shca->ib_device, + "Invalid eqe for non-existing cq " + "token=%x", token); + continue; } - eqe = (struct ehca_eqe *)ehca_poll_eq(shca, &shca->eq); - + spin_unlock(&ehca_cq_idr_lock); + } else + eqe_cache[eqe_cnt].cq = NULL; + eqe_cnt++; + } while (eqe_cnt < EHCA_EQE_CACHE_SIZE); + if (!eqe_cnt) { + if (is_irq) + ehca_dbg(&shca->ib_device, + "No eqe found for irq event"); + goto unlock_irq_spinlock; + } else if (!is_irq) + ehca_dbg(&shca->ib_device, "deadman found %x eqe", eqe_cnt); + if (unlikely(eqe_cnt == EHCA_EQE_CACHE_SIZE)) + ehca_dbg(&shca->ib_device, "too many eqes for one irq event"); + /* enable irq for new packets */ + for (i = 0; i < eqe_cnt; i++) { + if (eq->eqe_cache[i].cq) + reset_eq_pending(eq->eqe_cache[i].cq); + } + /* check eq */ + spin_lock(&eq->spinlock); + eq_empty = (!ipz_eqit_eq_peek_valid(&shca->eq.ipz_queue)); + spin_unlock(&eq->spinlock); + /* call completion handler for cached eqes */ + for (i = 0; i < eqe_cnt; i++) + if (eq->eqe_cache[i].cq) { + if (ehca_scaling_code) { + spin_lock(&ehca_cq_idr_lock); + queue_comp_task(eq->eqe_cache[i].cq); + spin_unlock(&ehca_cq_idr_lock); + } else + comp_event_callback(eq->eqe_cache[i].cq); + } else { + ehca_dbg(&shca->ib_device, "Got non completion event"); + parse_identifier(shca, eq->eqe_cache[i].eqe->entry); } - } while (int_state != 0); - - return; + /* poll eq if not empty */ + if (eq_empty) + goto unlock_irq_spinlock; + do { + struct ehca_eqe *eqe; + eqe = (struct ehca_eqe *)ehca_poll_eq(shca, &shca->eq); + if (!eqe) + break; + process_eqe(shca, eqe); + eqe_cnt++; + } while (1); + +unlock_irq_spinlock: + spin_unlock_irqrestore(&eq->irq_spinlock, flags); } -#ifdef CONFIG_INFINIBAND_EHCA_SCALING +void ehca_tasklet_eq(unsigned long data) +{ + ehca_process_eq((struct ehca_shca*)data, 1); +} static inline int find_next_online_cpu(struct ehca_comp_pool* pool) { - unsigned long flags_last_cpu; + int cpu; + unsigned long flags; + WARN_ON_ONCE(!in_interrupt()); if (ehca_debug_level) ehca_dmp(&cpu_online_map, sizeof(cpumask_t), ""); - spin_lock_irqsave(&pool->last_cpu_lock, flags_last_cpu); - pool->last_cpu = next_cpu(pool->last_cpu, cpu_online_map); - if (pool->last_cpu == NR_CPUS) - pool->last_cpu = first_cpu(cpu_online_map); - spin_unlock_irqrestore(&pool->last_cpu_lock, flags_last_cpu); + spin_lock_irqsave(&pool->last_cpu_lock, flags); + cpu = next_cpu(pool->last_cpu, cpu_online_map); + if (cpu == NR_CPUS) + cpu = first_cpu(cpu_online_map); + pool->last_cpu = cpu; + spin_unlock_irqrestore(&pool->last_cpu_lock, flags); - return pool->last_cpu; + return cpu; } static void __queue_comp_task(struct ehca_cq *__cq, struct ehca_cpu_comp_task *cct) { - unsigned long flags_cct; - unsigned long flags_cq; + unsigned long flags; - spin_lock_irqsave(&cct->task_lock, flags_cct); - spin_lock_irqsave(&__cq->task_lock, flags_cq); + spin_lock_irqsave(&cct->task_lock, flags); + spin_lock(&__cq->task_lock); if (__cq->nr_callbacks == 0) { __cq->nr_callbacks++; @@ -520,8 +571,8 @@ static void __queue_comp_task(struct ehca_cq *__cq, else __cq->nr_callbacks++; - spin_unlock_irqrestore(&__cq->task_lock, flags_cq); - spin_unlock_irqrestore(&cct->task_lock, flags_cct); + spin_unlock(&__cq->task_lock); + spin_unlock_irqrestore(&cct->task_lock, flags); } static void queue_comp_task(struct ehca_cq *__cq) @@ -532,69 +583,69 @@ static void queue_comp_task(struct ehca_cq *__cq) cpu = get_cpu(); cpu_id = find_next_online_cpu(pool); - BUG_ON(!cpu_online(cpu_id)); cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu_id); + BUG_ON(!cct); if (cct->cq_jobs > 0) { cpu_id = find_next_online_cpu(pool); cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu_id); + BUG_ON(!cct); } __queue_comp_task(__cq, cct); - - put_cpu(); - - return; } static void run_comp_task(struct ehca_cpu_comp_task* cct) { struct ehca_cq *cq; - unsigned long flags_cct; - unsigned long flags_cq; + unsigned long flags; - spin_lock_irqsave(&cct->task_lock, flags_cct); + spin_lock_irqsave(&cct->task_lock, flags); while (!list_empty(&cct->cq_list)) { cq = list_entry(cct->cq_list.next, struct ehca_cq, entry); - spin_unlock_irqrestore(&cct->task_lock, flags_cct); + spin_unlock_irqrestore(&cct->task_lock, flags); comp_event_callback(cq); - spin_lock_irqsave(&cct->task_lock, flags_cct); + spin_lock_irqsave(&cct->task_lock, flags); - spin_lock_irqsave(&cq->task_lock, flags_cq); + spin_lock(&cq->task_lock); cq->nr_callbacks--; if (cq->nr_callbacks == 0) { list_del_init(cct->cq_list.next); cct->cq_jobs--; } - spin_unlock_irqrestore(&cq->task_lock, flags_cq); - + spin_unlock(&cq->task_lock); } - spin_unlock_irqrestore(&cct->task_lock, flags_cct); - - return; + spin_unlock_irqrestore(&cct->task_lock, flags); } static int comp_task(void *__cct) { struct ehca_cpu_comp_task* cct = __cct; + int cql_empty; DECLARE_WAITQUEUE(wait, current); set_current_state(TASK_INTERRUPTIBLE); while(!kthread_should_stop()) { add_wait_queue(&cct->wait_queue, &wait); - if (list_empty(&cct->cq_list)) + spin_lock_irq(&cct->task_lock); + cql_empty = list_empty(&cct->cq_list); + spin_unlock_irq(&cct->task_lock); + if (cql_empty) schedule(); else __set_current_state(TASK_RUNNING); remove_wait_queue(&cct->wait_queue, &wait); - if (!list_empty(&cct->cq_list)) + spin_lock_irq(&cct->task_lock); + cql_empty = list_empty(&cct->cq_list); + spin_unlock_irq(&cct->task_lock); + if (!cql_empty) run_comp_task(__cct); set_current_state(TASK_INTERRUPTIBLE); @@ -637,8 +688,6 @@ static void destroy_comp_task(struct ehca_comp_pool *pool, if (task) kthread_stop(task); - - return; } static void take_over_work(struct ehca_comp_pool *pool, @@ -654,11 +703,11 @@ static void take_over_work(struct ehca_comp_pool *pool, list_splice_init(&cct->cq_list, &list); while(!list_empty(&list)) { - cq = list_entry(cct->cq_list.next, struct ehca_cq, entry); + cq = list_entry(cct->cq_list.next, struct ehca_cq, entry); - list_del(&cq->entry); - __queue_comp_task(cq, per_cpu_ptr(pool->cpu_comp_tasks, - smp_processor_id())); + list_del(&cq->entry); + __queue_comp_task(cq, per_cpu_ptr(pool->cpu_comp_tasks, + smp_processor_id())); } spin_unlock_irqrestore(&cct->task_lock, flags_cct); @@ -708,14 +757,14 @@ static int comp_pool_callback(struct notifier_block *nfb, return NOTIFY_OK; } -#endif - int ehca_create_comp_pool(void) { -#ifdef CONFIG_INFINIBAND_EHCA_SCALING int cpu; struct task_struct *task; + if (!ehca_scaling_code) + return 0; + pool = kzalloc(sizeof(struct ehca_comp_pool), GFP_KERNEL); if (pool == NULL) return -ENOMEM; @@ -740,16 +789,19 @@ int ehca_create_comp_pool(void) comp_pool_callback_nb.notifier_call = comp_pool_callback; comp_pool_callback_nb.priority =0; register_cpu_notifier(&comp_pool_callback_nb); -#endif + + printk(KERN_INFO "eHCA scaling code enabled\n"); return 0; } void ehca_destroy_comp_pool(void) { -#ifdef CONFIG_INFINIBAND_EHCA_SCALING int i; + if (!ehca_scaling_code) + return; + unregister_cpu_notifier(&comp_pool_callback_nb); for (i = 0; i < NR_CPUS; i++) { @@ -758,7 +810,4 @@ void ehca_destroy_comp_pool(void) } free_percpu(pool->cpu_comp_tasks); kfree(pool); -#endif - - return; } diff --git a/drivers/infiniband/hw/ehca/ehca_irq.h b/drivers/infiniband/hw/ehca/ehca_irq.h index be579cc0adf6..6ed06ee033ed 100644 --- a/drivers/infiniband/hw/ehca/ehca_irq.h +++ b/drivers/infiniband/hw/ehca/ehca_irq.h @@ -56,6 +56,7 @@ void ehca_tasklet_neq(unsigned long data); irqreturn_t ehca_interrupt_eq(int irq, void *dev_id); void ehca_tasklet_eq(unsigned long data); +void ehca_process_eq(struct ehca_shca *shca, int is_irq); struct ehca_cpu_comp_task { wait_queue_head_t wait_queue; diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c index 1155bcf48212..c1835121a822 100644 --- a/drivers/infiniband/hw/ehca/ehca_main.c +++ b/drivers/infiniband/hw/ehca/ehca_main.c @@ -52,7 +52,7 @@ MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("Christoph Raisch <raisch@de.ibm.com>"); MODULE_DESCRIPTION("IBM eServer HCA InfiniBand Device Driver"); -MODULE_VERSION("SVNEHCA_0020"); +MODULE_VERSION("SVNEHCA_0021"); int ehca_open_aqp1 = 0; int ehca_debug_level = 0; @@ -62,6 +62,7 @@ int ehca_use_hp_mr = 0; int ehca_port_act_time = 30; int ehca_poll_all_eqs = 1; int ehca_static_rate = -1; +int ehca_scaling_code = 1; module_param_named(open_aqp1, ehca_open_aqp1, int, 0); module_param_named(debug_level, ehca_debug_level, int, 0); @@ -71,6 +72,7 @@ module_param_named(use_hp_mr, ehca_use_hp_mr, int, 0); module_param_named(port_act_time, ehca_port_act_time, int, 0); module_param_named(poll_all_eqs, ehca_poll_all_eqs, int, 0); module_param_named(static_rate, ehca_static_rate, int, 0); +module_param_named(scaling_code, ehca_scaling_code, int, 0); MODULE_PARM_DESC(open_aqp1, "AQP1 on startup (0: no (default), 1: yes)"); @@ -91,6 +93,8 @@ MODULE_PARM_DESC(poll_all_eqs, " (0: no, 1: yes (default))"); MODULE_PARM_DESC(static_rate, "set permanent static rate (default: disabled)"); +MODULE_PARM_DESC(scaling_code, + "set scaling code (0: disabled, 1: enabled/default)"); spinlock_t ehca_qp_idr_lock; spinlock_t ehca_cq_idr_lock; @@ -432,8 +436,8 @@ static int ehca_destroy_aqp1(struct ehca_sport *sport) static ssize_t ehca_show_debug_level(struct device_driver *ddp, char *buf) { - return snprintf(buf, PAGE_SIZE, "%d\n", - ehca_debug_level); + return snprintf(buf, PAGE_SIZE, "%d\n", + ehca_debug_level); } static ssize_t ehca_store_debug_level(struct device_driver *ddp, @@ -778,8 +782,24 @@ void ehca_poll_eqs(unsigned long data) spin_lock(&shca_list_lock); list_for_each_entry(shca, &shca_list, shca_list) { - if (shca->eq.is_initialized) - ehca_tasklet_eq((unsigned long)(void*)shca); + if (shca->eq.is_initialized) { + /* call deadman proc only if eq ptr does not change */ + struct ehca_eq *eq = &shca->eq; + int max = 3; + volatile u64 q_ofs, q_ofs2; + u64 flags; + spin_lock_irqsave(&eq->spinlock, flags); + q_ofs = eq->ipz_queue.current_q_offset; + spin_unlock_irqrestore(&eq->spinlock, flags); + do { + spin_lock_irqsave(&eq->spinlock, flags); + q_ofs2 = eq->ipz_queue.current_q_offset; + spin_unlock_irqrestore(&eq->spinlock, flags); + max--; + } while (q_ofs == q_ofs2 && max > 0); + if (q_ofs == q_ofs2) + ehca_process_eq(shca, 0); + } } mod_timer(&poll_eqs_timer, jiffies + HZ); spin_unlock(&shca_list_lock); @@ -790,7 +810,7 @@ int __init ehca_module_init(void) int ret; printk(KERN_INFO "eHCA Infiniband Device Driver " - "(Rel.: SVNEHCA_0020)\n"); + "(Rel.: SVNEHCA_0021)\n"); idr_init(&ehca_qp_idr); idr_init(&ehca_cq_idr); spin_lock_init(&ehca_qp_idr_lock); diff --git a/drivers/infiniband/hw/ehca/ipz_pt_fn.h b/drivers/infiniband/hw/ehca/ipz_pt_fn.h index dc3bda2634b7..8199c45768a3 100644 --- a/drivers/infiniband/hw/ehca/ipz_pt_fn.h +++ b/drivers/infiniband/hw/ehca/ipz_pt_fn.h @@ -79,7 +79,7 @@ static inline void *ipz_qeit_calc(struct ipz_queue *queue, u64 q_offset) if (q_offset >= queue->queue_length) return NULL; current_page = (queue->queue_pages)[q_offset >> EHCA_PAGESHIFT]; - return ¤t_page->entries[q_offset & (EHCA_PAGESIZE - 1)]; + return ¤t_page->entries[q_offset & (EHCA_PAGESIZE - 1)]; } /* @@ -247,6 +247,15 @@ static inline void *ipz_eqit_eq_get_inc_valid(struct ipz_queue *queue) return ret; } +static inline void *ipz_eqit_eq_peek_valid(struct ipz_queue *queue) +{ + void *ret = ipz_qeit_get(queue); + u32 qe = *(u8 *) ret; + if ((qe >> 7) != (queue->toggle_state & 1)) + return NULL; + return ret; +} + /* returns address (GX) of first queue entry */ static inline u64 ipz_qpt_get_firstpage(struct ipz_qpt *qpt) { diff --git a/drivers/infiniband/hw/ipath/ipath_dma.c b/drivers/infiniband/hw/ipath/ipath_dma.c index 6e0f2b8918ce..f6f949040825 100644 --- a/drivers/infiniband/hw/ipath/ipath_dma.c +++ b/drivers/infiniband/hw/ipath/ipath_dma.c @@ -96,8 +96,8 @@ static void ipath_dma_unmap_page(struct ib_device *dev, BUG_ON(!valid_dma_direction(direction)); } -int ipath_map_sg(struct ib_device *dev, struct scatterlist *sg, int nents, - enum dma_data_direction direction) +static int ipath_map_sg(struct ib_device *dev, struct scatterlist *sg, int nents, + enum dma_data_direction direction) { u64 addr; int i; diff --git a/drivers/infiniband/hw/ipath/ipath_iba6110.c b/drivers/infiniband/hw/ipath/ipath_iba6110.c index 7468477ba837..993482545021 100644 --- a/drivers/infiniband/hw/ipath/ipath_iba6110.c +++ b/drivers/infiniband/hw/ipath/ipath_iba6110.c @@ -1534,7 +1534,7 @@ static int ipath_ht_early_init(struct ipath_devdata *dd) * @kbase: ipath_base_info pointer * * We set the PCIE flag because the lower bandwidth on PCIe vs - * HyperTransport can affect some user packet algorithims. + * HyperTransport can affect some user packet algorithms. */ static int ipath_ht_get_base_info(struct ipath_portdata *pd, void *kbase) { diff --git a/drivers/infiniband/hw/ipath/ipath_iba6120.c b/drivers/infiniband/hw/ipath/ipath_iba6120.c index ae8bf9950c6d..05918e1e7c36 100644 --- a/drivers/infiniband/hw/ipath/ipath_iba6120.c +++ b/drivers/infiniband/hw/ipath/ipath_iba6120.c @@ -1293,7 +1293,7 @@ int __attribute__((weak)) ipath_unordered_wc(void) * @kbase: ipath_base_info pointer * * We set the PCIE flag because the lower bandwidth on PCIe vs - * HyperTransport can affect some user packet algorithims. + * HyperTransport can affect some user packet algorithms. */ static int ipath_pe_get_base_info(struct ipath_portdata *pd, void *kbase) { diff --git a/drivers/infiniband/hw/mthca/mthca_memfree.c b/drivers/infiniband/hw/mthca/mthca_memfree.c index 0b9d053a599d..48f7c65e9aed 100644 --- a/drivers/infiniband/hw/mthca/mthca_memfree.c +++ b/drivers/infiniband/hw/mthca/mthca_memfree.c @@ -175,7 +175,9 @@ struct mthca_icm *mthca_alloc_icm(struct mthca_dev *dev, int npages, if (!ret) { ++chunk->npages; - if (!coherent && chunk->npages == MTHCA_ICM_CHUNK_LEN) { + if (coherent) + ++chunk->nsg; + else if (chunk->npages == MTHCA_ICM_CHUNK_LEN) { chunk->nsg = pci_map_sg(dev->pdev, chunk->mem, chunk->npages, PCI_DMA_BIDIRECTIONAL); diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c index 224c93dd29eb..71dc84bd4254 100644 --- a/drivers/infiniband/hw/mthca/mthca_qp.c +++ b/drivers/infiniband/hw/mthca/mthca_qp.c @@ -573,6 +573,11 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask, goto out; } + if (cur_state == new_state && cur_state == IB_QPS_RESET) { + err = 0; + goto out; + } + if ((attr_mask & IB_QP_PKEY_INDEX) && attr->pkey_index >= dev->limits.pkey_table_len) { mthca_dbg(dev, "P_Key index (%u) too large. max is %d\n", diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c index 2d483874a589..4d59682f7d4a 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c @@ -145,7 +145,7 @@ partial_error: for (; i >= 0; --i) ib_dma_unmap_single(priv->ca, mapping[i + 1], PAGE_SIZE, DMA_FROM_DEVICE); - kfree_skb(skb); + dev_kfree_skb_any(skb); return -ENOMEM; } @@ -1138,7 +1138,7 @@ static ssize_t set_mode(struct device *d, struct device_attribute *attr, return -EINVAL; } -static DEVICE_ATTR(mode, S_IWUGO | S_IRUGO, show_mode, set_mode); +static DEVICE_ATTR(mode, S_IWUSR | S_IRUGO, show_mode, set_mode); int ipoib_cm_add_mode_attr(struct net_device *dev) { diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index fea737f520fd..b303ce6bc21e 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c @@ -60,14 +60,11 @@ static DEFINE_MUTEX(mcast_mutex); /* Used for all multicast joins (broadcast, IPv4 mcast and IPv6 mcast) */ struct ipoib_mcast { struct ib_sa_mcmember_rec mcmember; + struct ib_sa_multicast *mc; struct ipoib_ah *ah; struct rb_node rb_node; struct list_head list; - struct completion done; - - int query_id; - struct ib_sa_query *query; unsigned long created; unsigned long backoff; @@ -299,18 +296,22 @@ static int ipoib_mcast_join_finish(struct ipoib_mcast *mcast, return 0; } -static void +static int ipoib_mcast_sendonly_join_complete(int status, - struct ib_sa_mcmember_rec *mcmember, - void *mcast_ptr) + struct ib_sa_multicast *multicast) { - struct ipoib_mcast *mcast = mcast_ptr; + struct ipoib_mcast *mcast = multicast->context; struct net_device *dev = mcast->dev; struct ipoib_dev_priv *priv = netdev_priv(dev); + /* We trap for port events ourselves. */ + if (status == -ENETRESET) + return 0; + if (!status) - ipoib_mcast_join_finish(mcast, mcmember); - else { + status = ipoib_mcast_join_finish(mcast, &multicast->rec); + + if (status) { if (mcast->logcount++ < 20) ipoib_dbg_mcast(netdev_priv(dev), "multicast join failed for " IPOIB_GID_FMT ", status %d\n", @@ -325,11 +326,10 @@ ipoib_mcast_sendonly_join_complete(int status, spin_unlock_irq(&priv->tx_lock); /* Clear the busy flag so we try again */ - clear_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags); - mcast->query = NULL; + status = test_and_clear_bit(IPOIB_MCAST_FLAG_BUSY, + &mcast->flags); } - - complete(&mcast->done); + return status; } static int ipoib_mcast_sendonly_join(struct ipoib_mcast *mcast) @@ -359,35 +359,33 @@ static int ipoib_mcast_sendonly_join(struct ipoib_mcast *mcast) rec.port_gid = priv->local_gid; rec.pkey = cpu_to_be16(priv->pkey); - init_completion(&mcast->done); - - ret = ib_sa_mcmember_rec_set(&ipoib_sa_client, priv->ca, priv->port, &rec, - IB_SA_MCMEMBER_REC_MGID | - IB_SA_MCMEMBER_REC_PORT_GID | - IB_SA_MCMEMBER_REC_PKEY | - IB_SA_MCMEMBER_REC_JOIN_STATE, - 1000, GFP_ATOMIC, - ipoib_mcast_sendonly_join_complete, - mcast, &mcast->query); - if (ret < 0) { - ipoib_warn(priv, "ib_sa_mcmember_rec_set failed (ret = %d)\n", + mcast->mc = ib_sa_join_multicast(&ipoib_sa_client, priv->ca, + priv->port, &rec, + IB_SA_MCMEMBER_REC_MGID | + IB_SA_MCMEMBER_REC_PORT_GID | + IB_SA_MCMEMBER_REC_PKEY | + IB_SA_MCMEMBER_REC_JOIN_STATE, + GFP_ATOMIC, + ipoib_mcast_sendonly_join_complete, + mcast); + if (IS_ERR(mcast->mc)) { + ret = PTR_ERR(mcast->mc); + clear_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags); + ipoib_warn(priv, "ib_sa_join_multicast failed (ret = %d)\n", ret); } else { ipoib_dbg_mcast(priv, "no multicast record for " IPOIB_GID_FMT ", starting join\n", IPOIB_GID_ARG(mcast->mcmember.mgid)); - - mcast->query_id = ret; } return ret; } -static void ipoib_mcast_join_complete(int status, - struct ib_sa_mcmember_rec *mcmember, - void *mcast_ptr) +static int ipoib_mcast_join_complete(int status, + struct ib_sa_multicast *multicast) { - struct ipoib_mcast *mcast = mcast_ptr; + struct ipoib_mcast *mcast = multicast->context; struct net_device *dev = mcast->dev; struct ipoib_dev_priv *priv = netdev_priv(dev); @@ -395,24 +393,25 @@ static void ipoib_mcast_join_complete(int status, " (status %d)\n", IPOIB_GID_ARG(mcast->mcmember.mgid), status); - if (!status && !ipoib_mcast_join_finish(mcast, mcmember)) { + /* We trap for port events ourselves. */ + if (status == -ENETRESET) + return 0; + + if (!status) + status = ipoib_mcast_join_finish(mcast, &multicast->rec); + + if (!status) { mcast->backoff = 1; mutex_lock(&mcast_mutex); if (test_bit(IPOIB_MCAST_RUN, &priv->flags)) queue_delayed_work(ipoib_workqueue, &priv->mcast_task, 0); mutex_unlock(&mcast_mutex); - complete(&mcast->done); - return; - } - - if (status == -EINTR) { - complete(&mcast->done); - return; + return 0; } - if (status && mcast->logcount++ < 20) { - if (status == -ETIMEDOUT || status == -EINTR) { + if (mcast->logcount++ < 20) { + if (status == -ETIMEDOUT) { ipoib_dbg_mcast(priv, "multicast join failed for " IPOIB_GID_FMT ", status %d\n", IPOIB_GID_ARG(mcast->mcmember.mgid), @@ -429,24 +428,18 @@ static void ipoib_mcast_join_complete(int status, if (mcast->backoff > IPOIB_MAX_BACKOFF_SECONDS) mcast->backoff = IPOIB_MAX_BACKOFF_SECONDS; - mutex_lock(&mcast_mutex); + /* Clear the busy flag so we try again */ + status = test_and_clear_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags); + mutex_lock(&mcast_mutex); spin_lock_irq(&priv->lock); - mcast->query = NULL; - - if (test_bit(IPOIB_MCAST_RUN, &priv->flags)) { - if (status == -ETIMEDOUT) - queue_delayed_work(ipoib_workqueue, &priv->mcast_task, - 0); - else - queue_delayed_work(ipoib_workqueue, &priv->mcast_task, - mcast->backoff * HZ); - } else - complete(&mcast->done); + if (test_bit(IPOIB_MCAST_RUN, &priv->flags)) + queue_delayed_work(ipoib_workqueue, &priv->mcast_task, + mcast->backoff * HZ); spin_unlock_irq(&priv->lock); mutex_unlock(&mcast_mutex); - return; + return status; } static void ipoib_mcast_join(struct net_device *dev, struct ipoib_mcast *mcast, @@ -495,15 +488,14 @@ static void ipoib_mcast_join(struct net_device *dev, struct ipoib_mcast *mcast, rec.hop_limit = priv->broadcast->mcmember.hop_limit; } - init_completion(&mcast->done); - - ret = ib_sa_mcmember_rec_set(&ipoib_sa_client, priv->ca, priv->port, - &rec, comp_mask, mcast->backoff * 1000, - GFP_ATOMIC, ipoib_mcast_join_complete, - mcast, &mcast->query); - - if (ret < 0) { - ipoib_warn(priv, "ib_sa_mcmember_rec_set failed, status %d\n", ret); + set_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags); + mcast->mc = ib_sa_join_multicast(&ipoib_sa_client, priv->ca, priv->port, + &rec, comp_mask, GFP_KERNEL, + ipoib_mcast_join_complete, mcast); + if (IS_ERR(mcast->mc)) { + clear_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags); + ret = PTR_ERR(mcast->mc); + ipoib_warn(priv, "ib_sa_join_multicast failed, status %d\n", ret); mcast->backoff *= 2; if (mcast->backoff > IPOIB_MAX_BACKOFF_SECONDS) @@ -515,8 +507,7 @@ static void ipoib_mcast_join(struct net_device *dev, struct ipoib_mcast *mcast, &priv->mcast_task, mcast->backoff * HZ); mutex_unlock(&mcast_mutex); - } else - mcast->query_id = ret; + } } void ipoib_mcast_join_task(struct work_struct *work) @@ -541,7 +532,7 @@ void ipoib_mcast_join_task(struct work_struct *work) priv->local_rate = attr.active_speed * ib_width_enum_to_int(attr.active_width); } else - ipoib_warn(priv, "ib_query_port failed\n"); + ipoib_warn(priv, "ib_query_port failed\n"); } if (!priv->broadcast) { @@ -568,7 +559,8 @@ void ipoib_mcast_join_task(struct work_struct *work) } if (!test_bit(IPOIB_MCAST_FLAG_ATTACHED, &priv->broadcast->flags)) { - ipoib_mcast_join(dev, priv->broadcast, 0); + if (!test_bit(IPOIB_MCAST_FLAG_BUSY, &priv->broadcast->flags)) + ipoib_mcast_join(dev, priv->broadcast, 0); return; } @@ -625,26 +617,9 @@ int ipoib_mcast_start_thread(struct net_device *dev) return 0; } -static void wait_for_mcast_join(struct ipoib_dev_priv *priv, - struct ipoib_mcast *mcast) -{ - spin_lock_irq(&priv->lock); - if (mcast && mcast->query) { - ib_sa_cancel_query(mcast->query_id, mcast->query); - mcast->query = NULL; - spin_unlock_irq(&priv->lock); - ipoib_dbg_mcast(priv, "waiting for MGID " IPOIB_GID_FMT "\n", - IPOIB_GID_ARG(mcast->mcmember.mgid)); - wait_for_completion(&mcast->done); - } - else - spin_unlock_irq(&priv->lock); -} - int ipoib_mcast_stop_thread(struct net_device *dev, int flush) { struct ipoib_dev_priv *priv = netdev_priv(dev); - struct ipoib_mcast *mcast; ipoib_dbg_mcast(priv, "stopping multicast thread\n"); @@ -660,52 +635,27 @@ int ipoib_mcast_stop_thread(struct net_device *dev, int flush) if (flush) flush_workqueue(ipoib_workqueue); - wait_for_mcast_join(priv, priv->broadcast); - - list_for_each_entry(mcast, &priv->multicast_list, list) - wait_for_mcast_join(priv, mcast); - return 0; } static int ipoib_mcast_leave(struct net_device *dev, struct ipoib_mcast *mcast) { struct ipoib_dev_priv *priv = netdev_priv(dev); - struct ib_sa_mcmember_rec rec = { - .join_state = 1 - }; int ret = 0; - if (!test_and_clear_bit(IPOIB_MCAST_FLAG_ATTACHED, &mcast->flags)) - return 0; - - ipoib_dbg_mcast(priv, "leaving MGID " IPOIB_GID_FMT "\n", - IPOIB_GID_ARG(mcast->mcmember.mgid)); - - rec.mgid = mcast->mcmember.mgid; - rec.port_gid = priv->local_gid; - rec.pkey = cpu_to_be16(priv->pkey); + if (test_and_clear_bit(IPOIB_MCAST_FLAG_ATTACHED, &mcast->flags)) { + ipoib_dbg_mcast(priv, "leaving MGID " IPOIB_GID_FMT "\n", + IPOIB_GID_ARG(mcast->mcmember.mgid)); - /* Remove ourselves from the multicast group */ - ret = ipoib_mcast_detach(dev, be16_to_cpu(mcast->mcmember.mlid), - &mcast->mcmember.mgid); - if (ret) - ipoib_warn(priv, "ipoib_mcast_detach failed (result = %d)\n", ret); + /* Remove ourselves from the multicast group */ + ret = ipoib_mcast_detach(dev, be16_to_cpu(mcast->mcmember.mlid), + &mcast->mcmember.mgid); + if (ret) + ipoib_warn(priv, "ipoib_mcast_detach failed (result = %d)\n", ret); + } - /* - * Just make one shot at leaving and don't wait for a reply; - * if we fail, too bad. - */ - ret = ib_sa_mcmember_rec_delete(&ipoib_sa_client, priv->ca, priv->port, &rec, - IB_SA_MCMEMBER_REC_MGID | - IB_SA_MCMEMBER_REC_PORT_GID | - IB_SA_MCMEMBER_REC_PKEY | - IB_SA_MCMEMBER_REC_JOIN_STATE, - 0, GFP_ATOMIC, NULL, - mcast, &mcast->query); - if (ret < 0) - ipoib_warn(priv, "ib_sa_mcmember_rec_delete failed " - "for leave (result = %d)\n", ret); + if (test_and_clear_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags)) + ib_sa_free_multicast(mcast->mc); return 0; } @@ -758,7 +708,7 @@ void ipoib_mcast_send(struct net_device *dev, void *mgid, struct sk_buff *skb) dev_kfree_skb_any(skb); } - if (mcast->query) + if (test_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags)) ipoib_dbg_mcast(priv, "no address vector, " "but multicast join already started\n"); else if (test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags)) @@ -916,7 +866,6 @@ void ipoib_mcast_restart_task(struct work_struct *work) /* We have to cancel outside of the spinlock */ list_for_each_entry_safe(mcast, tmcast, &remove_list, list) { - wait_for_mcast_join(priv, mcast); ipoib_mcast_leave(mcast->dev, mcast); ipoib_mcast_free(mcast); } diff --git a/drivers/input/input.c b/drivers/input/input.c index efa1b1f75393..a9a706f8fff9 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -588,18 +588,9 @@ static inline void input_proc_exit(void) { } static ssize_t input_dev_show_##name(struct class_device *dev, char *buf) \ { \ struct input_dev *input_dev = to_input_dev(dev); \ - int retval; \ \ - retval = mutex_lock_interruptible(&input_dev->mutex); \ - if (retval) \ - return retval; \ - \ - retval = scnprintf(buf, PAGE_SIZE, \ - "%s\n", input_dev->name ? input_dev->name : ""); \ - \ - mutex_unlock(&input_dev->mutex); \ - \ - return retval; \ + return scnprintf(buf, PAGE_SIZE, "%s\n", \ + input_dev->name ? input_dev->name : ""); \ } \ static CLASS_DEVICE_ATTR(name, S_IRUGO, input_dev_show_##name, NULL); @@ -1049,10 +1040,6 @@ void input_unregister_device(struct input_dev *dev) sysfs_remove_group(&dev->cdev.kobj, &input_dev_id_attr_group); sysfs_remove_group(&dev->cdev.kobj, &input_dev_attr_group); - mutex_lock(&dev->mutex); - dev->name = dev->phys = dev->uniq = NULL; - mutex_unlock(&dev->mutex); - class_device_unregister(&dev->cdev); input_wakeup_procfs_readers(); diff --git a/drivers/input/joystick/amijoy.c b/drivers/input/joystick/amijoy.c index e608691b5a61..b0f5541ec3e6 100644 --- a/drivers/input/joystick/amijoy.c +++ b/drivers/input/joystick/amijoy.c @@ -50,8 +50,6 @@ static int amijoy[2] = { 0, 1 }; module_param_array_named(map, amijoy, uint, NULL, 0); MODULE_PARM_DESC(map, "Map of attached joysticks in form of <a>,<b> (default is 0,1)"); -__obsolete_setup("amijoy="); - static int amijoy_used; static DEFINE_MUTEX(amijoy_mutex); static struct input_dev *amijoy_dev[2]; diff --git a/drivers/input/joystick/analog.c b/drivers/input/joystick/analog.c index 7ef68456d7d6..51f1e4bfff3e 100644 --- a/drivers/input/joystick/analog.c +++ b/drivers/input/joystick/analog.c @@ -58,8 +58,6 @@ static int analog_options[ANALOG_PORTS]; module_param_array_named(map, js, charp, &js_nargs, 0); MODULE_PARM_DESC(map, "Describes analog joysticks type/capabilities"); -__obsolete_setup("js="); - /* * Times, feature definitions. */ diff --git a/drivers/input/joystick/db9.c b/drivers/input/joystick/db9.c index 5080e15c6d30..b41bd2eb37dd 100644 --- a/drivers/input/joystick/db9.c +++ b/drivers/input/joystick/db9.c @@ -59,10 +59,6 @@ MODULE_PARM_DESC(dev2, "Describes second attached device (<parport#>,<type>)"); module_param_array_named(dev3, db9[2].args, int, &db9[2].nargs, 0); MODULE_PARM_DESC(dev3, "Describes third attached device (<parport#>,<type>)"); -__obsolete_setup("db9="); -__obsolete_setup("db9_2="); -__obsolete_setup("db9_3="); - #define DB9_ARG_PARPORT 0 #define DB9_ARG_MODE 1 diff --git a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c index fe12aa37393d..711e4b3e9e61 100644 --- a/drivers/input/joystick/gamecon.c +++ b/drivers/input/joystick/gamecon.c @@ -60,10 +60,6 @@ MODULE_PARM_DESC(map2, "Describes second set of devices"); module_param_array_named(map3, gc[2].args, int, &gc[2].nargs, 0); MODULE_PARM_DESC(map3, "Describes third set of devices"); -__obsolete_setup("gc="); -__obsolete_setup("gc_2="); -__obsolete_setup("gc_3="); - /* see also gs_psx_delay parameter in PSX support section */ #define GC_SNES 1 @@ -403,8 +399,6 @@ static int gc_psx_delay = GC_PSX_DELAY; module_param_named(psx_delay, gc_psx_delay, uint, 0); MODULE_PARM_DESC(psx_delay, "Delay when accessing Sony PSX controller (usecs)"); -__obsolete_setup("gc_psx_delay="); - static short gc_psx_abs[] = { ABS_X, ABS_Y, ABS_RX, ABS_RY, ABS_HAT0X, ABS_HAT0Y }; static short gc_psx_btn[] = { BTN_TL, BTN_TR, BTN_TL2, BTN_TR2, BTN_A, BTN_B, BTN_X, BTN_Y, BTN_START, BTN_SELECT, BTN_THUMBL, BTN_THUMBR }; diff --git a/drivers/input/joystick/turbografx.c b/drivers/input/joystick/turbografx.c index 5570fd5487c7..037d3487fcc7 100644 --- a/drivers/input/joystick/turbografx.c +++ b/drivers/input/joystick/turbografx.c @@ -60,10 +60,6 @@ MODULE_PARM_DESC(map2, "Describes second set of devices"); module_param_array_named(map3, tgfx[2].args, int, &tgfx[2].nargs, 0); MODULE_PARM_DESC(map3, "Describes third set of devices"); -__obsolete_setup("tgfx="); -__obsolete_setup("tgfx_2="); -__obsolete_setup("tgfx_3="); - #define TGFX_REFRESH_TIME HZ/100 /* 10 ms */ #define TGFX_TRIGGER 0x08 diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 1b81a72e19d9..64509689fa65 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -215,11 +215,11 @@ config KEYBOARD_AAED2000 module will be called aaed2000_kbd. config KEYBOARD_GPIO - tristate "Buttons on CPU GPIOs (PXA)" - depends on ARCH_PXA + tristate "Buttons on CPU GPIOs (PXA)" + depends on (ARCH_SA1100 || ARCH_PXA || ARCH_S3C2410) help This driver implements support for buttons connected - directly to GPIO pins of PXA CPUs. + directly to GPIO pins of SA1100, PXA or S3C24xx CPUs. Say Y here if your device has buttons connected directly to GPIO pins of the CPU. diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index c621a9177a56..663877076bc7 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c @@ -63,10 +63,6 @@ static int atkbd_extra; module_param_named(extra, atkbd_extra, bool, 0); MODULE_PARM_DESC(extra, "Enable extra LEDs and keys on IBM RapidAcces, EzKey and similar keyboards"); -__obsolete_setup("atkbd_set="); -__obsolete_setup("atkbd_reset"); -__obsolete_setup("atkbd_softrepeat="); - /* * Scancode to keycode tables. These are just the default setting, and * are loadable via an userland utility. diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index 7ad479e4e3b3..fa03a00b4c6d 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -24,7 +24,7 @@ #include <linux/input.h> #include <linux/irq.h> -#include <asm/arch/pxa-regs.h> +#include <asm/gpio.h> #include <asm/arch/hardware.h> #include <asm/hardware/gpio_keys.h> @@ -38,8 +38,8 @@ static irqreturn_t gpio_keys_isr(int irq, void *dev_id) for (i = 0; i < pdata->nbuttons; i++) { int gpio = pdata->buttons[i].gpio; - if (irq == IRQ_GPIO(gpio)) { - int state = ((GPLR(gpio) & GPIO_bit(gpio)) ? 1 : 0) ^ (pdata->buttons[i].active_low); + if (irq == gpio_to_irq(gpio)) { + int state = (gpio_get_value(gpio) ? 1 : 0) ^ (pdata->buttons[i].active_low); input_report_key(input, pdata->buttons[i].keycode, state); input_sync(input); @@ -75,14 +75,15 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) for (i = 0; i < pdata->nbuttons; i++) { int code = pdata->buttons[i].keycode; - int irq = IRQ_GPIO(pdata->buttons[i].gpio); + int irq = gpio_to_irq(pdata->buttons[i].gpio); set_irq_type(irq, IRQ_TYPE_EDGE_BOTH); error = request_irq(irq, gpio_keys_isr, IRQF_SAMPLE_RANDOM, pdata->buttons[i].desc ? pdata->buttons[i].desc : "gpio_keys", pdev); if (error) { - printk(KERN_ERR "gpio-keys: unable to claim irq %d; error %d\n", irq, ret); + printk(KERN_ERR "gpio-keys: unable to claim irq %d; error %d\n", + irq, error); goto fail; } set_bit(code, input->keybit); @@ -98,7 +99,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) fail: for (i = i - 1; i >= 0; i--) - free_irq(IRQ_GPIO(pdata->buttons[i].gpio), pdev); + free_irq(gpio_to_irq(pdata->buttons[i].gpio), pdev); input_free_device(input); @@ -112,7 +113,7 @@ static int __devexit gpio_keys_remove(struct platform_device *pdev) int i; for (i = 0; i < pdata->nbuttons; i++) { - int irq = IRQ_GPIO(pdata->buttons[i].gpio); + int irq = gpio_to_irq(pdata->buttons[i].gpio); free_irq(irq, pdev); } diff --git a/drivers/input/keyboard/hilkbd.c b/drivers/input/keyboard/hilkbd.c index 255a6ec75a48..4de4dc297d50 100644 --- a/drivers/input/keyboard/hilkbd.c +++ b/drivers/input/keyboard/hilkbd.c @@ -294,8 +294,10 @@ err3: disable_irq(HIL_IRQ); free_irq(HIL_IRQ, hil_dev.dev_id); err2: +#if defined(CONFIG_HP300) release_region(HILBASE + HIL_DATA, 2); err1: +#endif input_free_device(hil_dev.dev); hil_dev.dev = NULL; return err; diff --git a/drivers/input/mouse/inport.c b/drivers/input/mouse/inport.c index 701ebd5473cf..79b624fe8994 100644 --- a/drivers/input/mouse/inport.c +++ b/drivers/input/mouse/inport.c @@ -84,8 +84,6 @@ static int inport_irq = INPORT_IRQ; module_param_named(irq, inport_irq, uint, 0); MODULE_PARM_DESC(irq, "IRQ number (5=default)"); -__obsolete_setup("inport_irq="); - static struct input_dev *inport_dev; static irqreturn_t inport_interrupt(int irq, void *dev_id) diff --git a/drivers/input/mouse/logibm.c b/drivers/input/mouse/logibm.c index db205995bffd..26c3b2e2ca94 100644 --- a/drivers/input/mouse/logibm.c +++ b/drivers/input/mouse/logibm.c @@ -75,8 +75,6 @@ static int logibm_irq = LOGIBM_IRQ; module_param_named(irq, logibm_irq, uint, 0); MODULE_PARM_DESC(irq, "IRQ number (5=default)"); -__obsolete_setup("logibm_irq="); - static struct input_dev *logibm_dev; static irqreturn_t logibm_interrupt(int irq, void *dev_id) diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index a0e4a033e2db..0fe5869d7d4c 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -93,12 +93,6 @@ static struct attribute_group psmouse_attribute_group = { .attrs = psmouse_attributes, }; -__obsolete_setup("psmouse_noext"); -__obsolete_setup("psmouse_resolution="); -__obsolete_setup("psmouse_smartscroll="); -__obsolete_setup("psmouse_resetafter="); -__obsolete_setup("psmouse_rate="); - /* * psmouse_mutex protects all operations changing state of mouse * (connecting, disconnecting, changing rate or resolution via @@ -987,8 +981,36 @@ static void psmouse_resync(struct work_struct *work) static void psmouse_cleanup(struct serio *serio) { struct psmouse *psmouse = serio_get_drvdata(serio); + struct psmouse *parent = NULL; + + mutex_lock(&psmouse_mutex); + + if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) { + parent = serio_get_drvdata(serio->parent); + psmouse_deactivate(parent); + } + + psmouse_deactivate(psmouse); + + if (psmouse->cleanup) + psmouse->cleanup(psmouse); psmouse_reset(psmouse); + +/* + * Some boxes, such as HP nx7400, get terribly confused if mouse + * is not fully enabled before suspending/shutting down. + */ + ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE); + + if (parent) { + if (parent->pt_deactivate) + parent->pt_deactivate(parent); + + psmouse_activate(parent); + } + + mutex_unlock(&psmouse_mutex); } /* diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h index 1b74cae8a556..cf1de95b6f27 100644 --- a/drivers/input/mouse/psmouse.h +++ b/drivers/input/mouse/psmouse.h @@ -68,6 +68,7 @@ struct psmouse { int (*reconnect)(struct psmouse *psmouse); void (*disconnect)(struct psmouse *psmouse); + void (*cleanup)(struct psmouse *psmouse); int (*poll)(struct psmouse *psmouse); void (*pt_activate)(struct psmouse *psmouse); diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 49ac696d6cff..f0f9413d762c 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -652,6 +652,7 @@ int synaptics_init(struct psmouse *psmouse) psmouse->set_rate = synaptics_set_rate; psmouse->disconnect = synaptics_disconnect; psmouse->reconnect = synaptics_reconnect; + psmouse->cleanup = synaptics_reset; psmouse->pktsize = 6; /* Synaptics can usually stay in sync without extra help */ psmouse->resync_time = 0; diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index c3fdfc1f342a..ec195a36e8f6 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -76,13 +76,6 @@ module_param_named(debug, i8042_debug, bool, 0600); MODULE_PARM_DESC(debug, "Turn i8042 debugging mode on and off"); #endif -__obsolete_setup("i8042_noaux"); -__obsolete_setup("i8042_nomux"); -__obsolete_setup("i8042_unlock"); -__obsolete_setup("i8042_reset"); -__obsolete_setup("i8042_direct"); -__obsolete_setup("i8042_dumbkbd"); - #include "i8042.h" static DEFINE_SPINLOCK(i8042_lock); @@ -724,7 +717,7 @@ static int i8042_controller_init(void) if (~i8042_read_status() & I8042_STR_KEYLOCK) { if (i8042_unlock) i8042_ctr |= I8042_CTR_IGNKEYLOCK; - else + else printk(KERN_WARNING "i8042.c: Warning: Keylock active.\n"); } spin_unlock_irqrestore(&i8042_lock, flags); @@ -791,27 +784,6 @@ static void i8042_controller_reset(void) /* - * Here we try to reset everything back to a state in which the BIOS will be - * able to talk to the hardware when rebooting. - */ - -static void i8042_controller_cleanup(void) -{ - int i; - -/* - * Reset anything that is connected to the ports. - */ - - for (i = 0; i < I8042_NUM_PORTS; i++) - if (i8042_ports[i].serio) - serio_cleanup(i8042_ports[i].serio); - - i8042_controller_reset(); -} - - -/* * i8042_panic_blink() will flash the keyboard LEDs and is called when * kernel panics. Flashing LEDs is useful for users running X who may * not see the console and will help distingushing panics from "real" @@ -857,13 +829,22 @@ static long i8042_panic_blink(long count) #undef DELAY +#ifdef CONFIG_PM /* - * Here we try to restore the original BIOS settings + * Here we try to restore the original BIOS settings. We only want to + * do that once, when we really suspend, not when we taking memory + * snapshot for swsusp (in this case we'll perform required cleanup + * as part of shutdown process). */ static int i8042_suspend(struct platform_device *dev, pm_message_t state) { - i8042_controller_cleanup(); + if (dev->dev.power.power_state.event != state.event) { + if (state.event == PM_EVENT_SUSPEND) + i8042_controller_reset(); + + dev->dev.power.power_state = state; + } return 0; } @@ -877,6 +858,12 @@ static int i8042_resume(struct platform_device *dev) { int error; +/* + * Do not bother with restoring state if we haven't suspened yet + */ + if (dev->dev.power.power_state.event == PM_EVENT_ON) + return 0; + error = i8042_controller_check(); if (error) return error; @@ -886,9 +873,12 @@ static int i8042_resume(struct platform_device *dev) return error; /* - * Restore pre-resume CTR value and disable all ports + * Restore original CTR value and disable all ports */ + i8042_ctr = i8042_initial_ctr; + if (i8042_direct) + i8042_ctr &= ~I8042_CTR_XLATE; i8042_ctr |= I8042_CTR_AUXDIS | I8042_CTR_KBDDIS; i8042_ctr &= ~(I8042_CTR_AUXINT | I8042_CTR_KBDINT); if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { @@ -909,8 +899,11 @@ static int i8042_resume(struct platform_device *dev) i8042_interrupt(0, NULL); + dev->dev.power.power_state = PMSG_ON; + return 0; } +#endif /* CONFIG_PM */ /* * We need to reset the 8042 back to original mode on system shutdown, @@ -919,7 +912,7 @@ static int i8042_resume(struct platform_device *dev) static void i8042_shutdown(struct platform_device *dev) { - i8042_controller_cleanup(); + i8042_controller_reset(); } static int __devinit i8042_create_kbd_port(void) @@ -1154,9 +1147,11 @@ static struct platform_driver i8042_driver = { }, .probe = i8042_probe, .remove = __devexit_p(i8042_remove), + .shutdown = i8042_shutdown, +#ifdef CONFIG_PM .suspend = i8042_suspend, .resume = i8042_resume, - .shutdown = i8042_shutdown, +#endif }; static int __init i8042_init(void) diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c index b3e84d3bb7f7..10d9d74ae43a 100644 --- a/drivers/input/serio/libps2.c +++ b/drivers/input/serio/libps2.c @@ -97,7 +97,7 @@ EXPORT_SYMBOL(ps2_drain); int ps2_is_keyboard_id(char id_byte) { - const static char keyboard_ids[] = { + static const char keyboard_ids[] = { 0xab, /* Regular keyboards */ 0xac, /* NCD Sun keyboard */ 0x2b, /* Trust keyboard, translated */ diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index 17c8c63cbe1a..a15e531ec755 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -778,6 +778,19 @@ static int serio_driver_remove(struct device *dev) return 0; } +static void serio_cleanup(struct serio *serio) +{ + if (serio->drv && serio->drv->cleanup) + serio->drv->cleanup(serio); +} + +static void serio_shutdown(struct device *dev) +{ + struct serio *serio = to_serio_port(dev); + + serio_cleanup(serio); +} + static void serio_attach_driver(struct serio_driver *drv) { int error; @@ -910,11 +923,25 @@ static int serio_uevent(struct device *dev, char **envp, int num_envp, char *buf #endif /* CONFIG_HOTPLUG */ +#ifdef CONFIG_PM +static int serio_suspend(struct device *dev, pm_message_t state) +{ + if (dev->power.power_state.event != state.event) { + if (state.event == PM_EVENT_SUSPEND) + serio_cleanup(to_serio_port(dev)); + + dev->power.power_state = state; + } + + return 0; +} + static int serio_resume(struct device *dev) { struct serio *serio = to_serio_port(dev); - if (serio_reconnect_driver(serio)) { + if (dev->power.power_state.event != PM_EVENT_ON && + serio_reconnect_driver(serio)) { /* * Driver re-probing can take a while, so better let kseriod * deal with it. @@ -922,8 +949,11 @@ static int serio_resume(struct device *dev) serio_rescan(serio); } + dev->power.power_state = PMSG_ON; + return 0; } +#endif /* CONFIG_PM */ /* called from serio_driver->connect/disconnect methods under serio_mutex */ int serio_open(struct serio *serio, struct serio_driver *drv) @@ -974,7 +1004,11 @@ static struct bus_type serio_bus = { .uevent = serio_uevent, .probe = serio_driver_probe, .remove = serio_driver_remove, + .shutdown = serio_shutdown, +#ifdef CONFIG_PM + .suspend = serio_suspend, .resume = serio_resume, +#endif }; static int __init serio_init(void) diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c index 4e3f127e4003..1b2df80c3bce 100644 --- a/drivers/isdn/i4l/isdn_ppp.c +++ b/drivers/isdn/i4l/isdn_ppp.c @@ -1680,7 +1680,7 @@ static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, * - we hit a gap in the sequence, so no reassembly/processing is * possible ('start' would be set to NULL) * - * algorightm for this code is derived from code in the book + * algorithm for this code is derived from code in the book * 'PPP Design And Debugging' by James Carlson (Addison-Wesley) */ while (start != NULL || newfrag != NULL) { diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index e85972222ab4..7c42d53a1cc7 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -915,7 +915,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, fetunesettings.parameters.inversion = INVERSION_AUTO; } if (fe->ops.info.type == FE_OFDM) { - /* without hierachical coding code_rate_LP is irrelevant, + /* without hierarchical coding code_rate_LP is irrelevant, * so we tolerate the otherwise invalid FEC_NONE setting */ if (fepriv->parameters.u.ofdm.hierarchy_information == HIERARCHY_NONE && fepriv->parameters.u.ofdm.code_rate_LP == FEC_NONE) diff --git a/drivers/media/dvb/frontends/dib3000mb.c b/drivers/media/dvb/frontends/dib3000mb.c index adbabfdb04a9..b6adea5ffeb8 100644 --- a/drivers/media/dvb/frontends/dib3000mb.c +++ b/drivers/media/dvb/frontends/dib3000mb.c @@ -239,7 +239,7 @@ static int dib3000mb_set_frontend(struct dvb_frontend* fe, default: return -EINVAL; } - deb_setf("hierachy: "); + deb_setf("hierarchy: "); switch (ofdm->hierarchy_information) { case HIERARCHY_NONE: deb_setf("none "); diff --git a/drivers/media/video/pvrusb2/pvrusb2-audio.c b/drivers/media/video/pvrusb2/pvrusb2-audio.c index 9846c464ec80..122496f36845 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-audio.c +++ b/drivers/media/video/pvrusb2/pvrusb2-audio.c @@ -158,7 +158,7 @@ static unsigned int pvr2_msp3400_describe(struct pvr2_msp3400_handler *ctxt, } -const static struct pvr2_i2c_handler_functions msp3400_funcs = { +static const struct pvr2_i2c_handler_functions msp3400_funcs = { .detach = (void (*)(void *))pvr2_msp3400_detach, .check = (int (*)(void *))msp3400_check, .update = (void (*)(void *))msp3400_update, diff --git a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c index 848fb233d808..8df969c4874c 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c +++ b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c @@ -226,7 +226,7 @@ static void decoder_reset(struct pvr2_v4l_cx2584x *ctxt) } -const static struct pvr2_i2c_handler_functions hfuncs = { +static const struct pvr2_i2c_handler_functions hfuncs = { .detach = (void (*)(void *))decoder_detach, .check = (int (*)(void *))decoder_check, .update = (void (*)(void *))decoder_update, diff --git a/drivers/media/video/pvrusb2/pvrusb2-std.c b/drivers/media/video/pvrusb2/pvrusb2-std.c index f95c598ff627..c08925557ed4 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-std.c +++ b/drivers/media/video/pvrusb2/pvrusb2-std.c @@ -78,14 +78,14 @@ struct std_name { #define CSTD_ALL (CSTD_PAL|CSTD_NTSC|CSTD_SECAM) /* Mapping of standard bits to color system */ -const static struct std_name std_groups[] = { +static const struct std_name std_groups[] = { {"PAL",CSTD_PAL}, {"NTSC",CSTD_NTSC}, {"SECAM",CSTD_SECAM}, }; /* Mapping of standard bits to modulation system */ -const static struct std_name std_items[] = { +static const struct std_name std_items[] = { {"B",TSTD_B}, {"B1",TSTD_B1}, {"D",TSTD_D}, diff --git a/drivers/media/video/pvrusb2/pvrusb2-tuner.c b/drivers/media/video/pvrusb2/pvrusb2-tuner.c index af9f246f8d3f..bb17db3f6434 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-tuner.c +++ b/drivers/media/video/pvrusb2/pvrusb2-tuner.c @@ -80,7 +80,7 @@ static unsigned int pvr2_tuner_describe(struct pvr2_tuner_handler *ctxt,char *bu } -const static struct pvr2_i2c_handler_functions tuner_funcs = { +static const struct pvr2_i2c_handler_functions tuner_funcs = { .detach = (void (*)(void *))pvr2_tuner_detach, .check = (int (*)(void *))tuner_check, .update = (void (*)(void *))tuner_update, diff --git a/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c b/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c index 05f2cddeb47b..2a826464911a 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c +++ b/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c @@ -201,7 +201,7 @@ static unsigned int decoder_describe(struct pvr2_v4l_decoder *ctxt,char *buf,uns } -const static struct pvr2_i2c_handler_functions hfuncs = { +static const struct pvr2_i2c_handler_functions hfuncs = { .detach = (void (*)(void *))decoder_detach, .check = (int (*)(void *))decoder_check, .update = (void (*)(void *))decoder_update, diff --git a/drivers/media/video/pvrusb2/pvrusb2-wm8775.c b/drivers/media/video/pvrusb2/pvrusb2-wm8775.c index 2413e5198e16..7794c34c355e 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-wm8775.c +++ b/drivers/media/video/pvrusb2/pvrusb2-wm8775.c @@ -126,7 +126,7 @@ static void wm8775_update(struct pvr2_v4l_wm8775 *ctxt) } -const static struct pvr2_i2c_handler_functions hfuncs = { +static const struct pvr2_i2c_handler_functions hfuncs = { .detach = (void (*)(void *))wm8775_detach, .check = (int (*)(void *))wm8775_check, .update = (void (*)(void *))wm8775_update, diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index bedae4ad3f74..80b199fa0aa9 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -107,4 +107,19 @@ config MSI_LAPTOP If you have an MSI S270 laptop, say Y or M here. +config SONY_LAPTOP + tristate "Sony Laptop Extras" + depends on X86 && ACPI + select BACKLIGHT_CLASS_DEVICE + ---help--- + This mini-driver drives the SNC device present in the ACPI BIOS of + the Sony Vaio laptops. + + It gives access to some extra laptop functionalities. In its current + form, this driver let the user set or query the screen brightness + through the backlight subsystem and remove/apply power to some + devices. + + Read <file:Documentation/sony-laptop.txt> for more information. + endmenu diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 35da53c409c0..7793ccd79049 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -11,3 +11,4 @@ obj-$(CONFIG_LKDTM) += lkdtm.o obj-$(CONFIG_TIFM_CORE) += tifm_core.o obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o obj-$(CONFIG_SGI_IOC4) += ioc4.o +obj-$(CONFIG_SONY_LAPTOP) += sony-laptop.o diff --git a/drivers/misc/asus-laptop.c b/drivers/misc/asus-laptop.c index 861c39935f99..e4e2b707a353 100644 --- a/drivers/misc/asus-laptop.c +++ b/drivers/misc/asus-laptop.c @@ -1088,11 +1088,6 @@ static int __init asus_laptop_init(void) if (acpi_disabled) return -ENODEV; - if (!acpi_specific_hotkey_enabled) { - printk(ASUS_ERR "Using generic hotkey driver\n"); - return -ENODEV; - } - result = acpi_bus_register_driver(&asus_hotk_driver); if (result < 0) return result; diff --git a/drivers/misc/sony-laptop.c b/drivers/misc/sony-laptop.c new file mode 100644 index 000000000000..cabbed0015e4 --- /dev/null +++ b/drivers/misc/sony-laptop.c @@ -0,0 +1,562 @@ +/* + * ACPI Sony Notebook Control Driver (SNC) + * + * Copyright (C) 2004-2005 Stelian Pop <stelian@popies.net> + * Copyright (C) 2007 Mattia Dongili <malattia@linux.it> + * + * Parts of this driver inspired from asus_acpi.c and ibm_acpi.c + * which are copyrighted by their respective authors. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/backlight.h> +#include <linux/platform_device.h> +#include <linux/err.h> +#include <acpi/acpi_drivers.h> +#include <acpi/acpi_bus.h> +#include <asm/uaccess.h> + +#define ACPI_SNC_CLASS "sony" +#define ACPI_SNC_HID "SNY5001" +#define ACPI_SNC_DRIVER_NAME "ACPI Sony Notebook Control Driver v0.4" + +/* the device uses 1-based values, while the backlight subsystem uses + 0-based values */ +#define SONY_MAX_BRIGHTNESS 8 + +#define LOG_PFX KERN_WARNING "sony-laptop: " + +MODULE_AUTHOR("Stelian Pop, Mattia Dongili"); +MODULE_DESCRIPTION(ACPI_SNC_DRIVER_NAME); +MODULE_LICENSE("GPL"); + +static int debug; +module_param(debug, int, 0); +MODULE_PARM_DESC(debug, "set this to 1 (and RTFM) if you want to help " + "the development of this driver"); + +static ssize_t sony_acpi_show(struct device *, struct device_attribute *, + char *); +static ssize_t sony_acpi_store(struct device *, struct device_attribute *, + const char *, size_t); +static int boolean_validate(const int, const int); +static int brightness_default_validate(const int, const int); + +#define SNC_VALIDATE_IN 0 +#define SNC_VALIDATE_OUT 1 + +struct sony_acpi_value { + char *name; /* name of the entry */ + char **acpiget; /* names of the ACPI get function */ + char **acpiset; /* names of the ACPI set function */ + int (*validate)(const int, const int); /* input/output validation */ + int value; /* current setting */ + int valid; /* Has ever been set */ + int debug; /* active only in debug mode ? */ + struct device_attribute devattr; /* sysfs atribute */ +}; + +#define HANDLE_NAMES(_name, _values...) \ + static char *snc_##_name[] = { _values, NULL } + +#define SONY_ACPI_VALUE(_name, _getters, _setters, _validate, _debug) \ + { \ + .name = __stringify(_name), \ + .acpiget = _getters, \ + .acpiset = _setters, \ + .validate = _validate, \ + .debug = _debug, \ + .devattr = __ATTR(_name, 0, sony_acpi_show, sony_acpi_store), \ + } + +#define SONY_ACPI_VALUE_NULL { .name = NULL } + +HANDLE_NAMES(fnkey_get, "GHKE"); + +HANDLE_NAMES(brightness_def_get, "GPBR"); +HANDLE_NAMES(brightness_def_set, "SPBR"); + +HANDLE_NAMES(cdpower_get, "GCDP"); +HANDLE_NAMES(cdpower_set, "SCDP", "CDPW"); + +HANDLE_NAMES(audiopower_get, "GAZP"); +HANDLE_NAMES(audiopower_set, "AZPW"); + +HANDLE_NAMES(lanpower_get, "GLNP"); +HANDLE_NAMES(lanpower_set, "LNPW"); + +HANDLE_NAMES(PID_get, "GPID"); + +HANDLE_NAMES(CTR_get, "GCTR"); +HANDLE_NAMES(CTR_set, "SCTR"); + +HANDLE_NAMES(PCR_get, "GPCR"); +HANDLE_NAMES(PCR_set, "SPCR"); + +HANDLE_NAMES(CMI_get, "GCMI"); +HANDLE_NAMES(CMI_set, "SCMI"); + +static struct sony_acpi_value sony_acpi_values[] = { + SONY_ACPI_VALUE(brightness_default, snc_brightness_def_get, + snc_brightness_def_set, brightness_default_validate, 0), + SONY_ACPI_VALUE(fnkey, snc_fnkey_get, NULL, NULL, 0), + SONY_ACPI_VALUE(cdpower, snc_cdpower_get, snc_cdpower_set, boolean_validate, 0), + SONY_ACPI_VALUE(audiopower, snc_audiopower_get, snc_audiopower_set, + boolean_validate, 0), + SONY_ACPI_VALUE(lanpower, snc_lanpower_get, snc_lanpower_set, + boolean_validate, 1), + /* unknown methods */ + SONY_ACPI_VALUE(PID, snc_PID_get, NULL, NULL, 1), + SONY_ACPI_VALUE(CTR, snc_CTR_get, snc_CTR_set, NULL, 1), + SONY_ACPI_VALUE(PCR, snc_PCR_get, snc_PCR_set, NULL, 1), + SONY_ACPI_VALUE(CMI, snc_CMI_get, snc_CMI_set, NULL, 1), + SONY_ACPI_VALUE_NULL +}; + +static acpi_handle sony_acpi_handle; +static struct acpi_device *sony_acpi_acpi_device = NULL; + +/* + * acpi_evaluate_object wrappers + */ +static int acpi_callgetfunc(acpi_handle handle, char *name, int *result) +{ + struct acpi_buffer output; + union acpi_object out_obj; + acpi_status status; + + output.length = sizeof(out_obj); + output.pointer = &out_obj; + + status = acpi_evaluate_object(handle, name, NULL, &output); + if ((status == AE_OK) && (out_obj.type == ACPI_TYPE_INTEGER)) { + *result = out_obj.integer.value; + return 0; + } + + printk(LOG_PFX "acpi_callreadfunc failed\n"); + + return -1; +} + +static int acpi_callsetfunc(acpi_handle handle, char *name, int value, + int *result) +{ + struct acpi_object_list params; + union acpi_object in_obj; + struct acpi_buffer output; + union acpi_object out_obj; + acpi_status status; + + params.count = 1; + params.pointer = &in_obj; + in_obj.type = ACPI_TYPE_INTEGER; + in_obj.integer.value = value; + + output.length = sizeof(out_obj); + output.pointer = &out_obj; + + status = acpi_evaluate_object(handle, name, ¶ms, &output); + if (status == AE_OK) { + if (result != NULL) { + if (out_obj.type != ACPI_TYPE_INTEGER) { + printk(LOG_PFX "acpi_evaluate_object bad " + "return type\n"); + return -1; + } + *result = out_obj.integer.value; + } + return 0; + } + + printk(LOG_PFX "acpi_evaluate_object failed\n"); + + return -1; +} + +/* + * sony_acpi_values input/output validate functions + */ + +/* brightness_default_validate: + * + * manipulate input output values to keep consistency with the + * backlight framework for which brightness values are 0-based. + */ +static int brightness_default_validate(const int direction, const int value) +{ + switch (direction) { + case SNC_VALIDATE_OUT: + return value - 1; + case SNC_VALIDATE_IN: + if (value >= 0 && value < SONY_MAX_BRIGHTNESS) + return value + 1; + } + return -EINVAL; +} + +/* boolean_validate: + * + * on input validate boolean values 0/1, on output just pass the + * received value. + */ +static int boolean_validate(const int direction, const int value) +{ + if (direction == SNC_VALIDATE_IN) { + if (value != 0 && value != 1) + return -EINVAL; + } + return value; +} + +/* + * Sysfs show/store common to all sony_acpi_values + */ +static ssize_t sony_acpi_show(struct device *dev, struct device_attribute *attr, + char *buffer) +{ + int value; + struct sony_acpi_value *item = + container_of(attr, struct sony_acpi_value, devattr); + + if (!*item->acpiget) + return -EIO; + + if (acpi_callgetfunc(sony_acpi_handle, *item->acpiget, &value) < 0) + return -EIO; + + if (item->validate) + value = item->validate(SNC_VALIDATE_OUT, value); + + return snprintf(buffer, PAGE_SIZE, "%d\n", value); +} + +static ssize_t sony_acpi_store(struct device *dev, + struct device_attribute *attr, + const char *buffer, size_t count) +{ + int value; + struct sony_acpi_value *item = + container_of(attr, struct sony_acpi_value, devattr); + + if (!item->acpiset) + return -EIO; + + if (count > 31) + return -EINVAL; + + value = simple_strtoul(buffer, NULL, 10); + + if (item->validate) + value = item->validate(SNC_VALIDATE_IN, value); + + if (value < 0) + return value; + + if (acpi_callsetfunc(sony_acpi_handle, *item->acpiset, value, NULL) < 0) + return -EIO; + item->value = value; + item->valid = 1; + return count; +} + +/* + * Platform device + */ +static struct platform_driver sncpf_driver = { + .driver = { + .name = "sony-laptop", + .owner = THIS_MODULE, + } +}; +static struct platform_device *sncpf_device; + +static int sony_snc_pf_add(void) +{ + acpi_handle handle; + struct sony_acpi_value *item; + int ret = 0; + + ret = platform_driver_register(&sncpf_driver); + if (ret) + goto out; + + sncpf_device = platform_device_alloc("sony-laptop", -1); + if (!sncpf_device) { + ret = -ENOMEM; + goto out_platform_registered; + } + + ret = platform_device_add(sncpf_device); + if (ret) + goto out_platform_alloced; + + for (item = sony_acpi_values; item->name; ++item) { + + if (!debug && item->debug) + continue; + + /* find the available acpiget as described in the DSDT */ + for (; item->acpiget && *item->acpiget; ++item->acpiget) { + if (ACPI_SUCCESS(acpi_get_handle(sony_acpi_handle, + *item->acpiget, + &handle))) { + if (debug) + printk(LOG_PFX "Found %s getter: %s\n", + item->name, *item->acpiget); + item->devattr.attr.mode |= S_IRUGO; + break; + } + } + + /* find the available acpiset as described in the DSDT */ + for (; item->acpiset && *item->acpiset; ++item->acpiset) { + if (ACPI_SUCCESS(acpi_get_handle(sony_acpi_handle, + *item->acpiset, + &handle))) { + if (debug) + printk(LOG_PFX "Found %s setter: %s\n", + item->name, *item->acpiset); + item->devattr.attr.mode |= S_IWUSR; + break; + } + } + + if (item->devattr.attr.mode != 0) { + ret = + device_create_file(&sncpf_device->dev, + &item->devattr); + if (ret) + goto out_sysfs; + } + } + + return 0; + + out_sysfs: + for (item = sony_acpi_values; item->name; ++item) { + device_remove_file(&sncpf_device->dev, &item->devattr); + } + platform_device_del(sncpf_device); + out_platform_alloced: + platform_device_put(sncpf_device); + out_platform_registered: + platform_driver_unregister(&sncpf_driver); + out: + return ret; +} + +static void sony_snc_pf_remove(void) +{ + struct sony_acpi_value *item; + + for (item = sony_acpi_values; item->name; ++item) { + device_remove_file(&sncpf_device->dev, &item->devattr); + } + + platform_device_del(sncpf_device); + platform_device_put(sncpf_device); + platform_driver_unregister(&sncpf_driver); +} + +/* + * Backlight device + */ +static int sony_backlight_update_status(struct backlight_device *bd) +{ + return acpi_callsetfunc(sony_acpi_handle, "SBRT", + bd->props->brightness + 1, NULL); +} + +static int sony_backlight_get_brightness(struct backlight_device *bd) +{ + int value; + + if (acpi_callgetfunc(sony_acpi_handle, "GBRT", &value)) + return 0; + /* brightness levels are 1-based, while backlight ones are 0-based */ + return value - 1; +} + +static struct backlight_device *sony_backlight_device; +static struct backlight_properties sony_backlight_properties = { + .owner = THIS_MODULE, + .update_status = sony_backlight_update_status, + .get_brightness = sony_backlight_get_brightness, + .max_brightness = SONY_MAX_BRIGHTNESS - 1, +}; + +/* + * ACPI callbacks + */ +static void sony_acpi_notify(acpi_handle handle, u32 event, void *data) +{ + if (debug) + printk(LOG_PFX "sony_acpi_notify, event: %d\n", event); + acpi_bus_generate_event(sony_acpi_acpi_device, 1, event); +} + +static acpi_status sony_walk_callback(acpi_handle handle, u32 level, + void *context, void **return_value) +{ + struct acpi_namespace_node *node; + union acpi_operand_object *operand; + + node = (struct acpi_namespace_node *)handle; + operand = (union acpi_operand_object *)node->object; + + printk(LOG_PFX "method: name: %4.4s, args %X\n", node->name.ascii, + (u32) operand->method.param_count); + + return AE_OK; +} + +/* + * ACPI device + */ +static int sony_acpi_resume(struct acpi_device *device) +{ + struct sony_acpi_value *item; + + for (item = sony_acpi_values; item->name; item++) { + int ret; + + if (!item->valid) + continue; + ret = acpi_callsetfunc(sony_acpi_handle, *item->acpiset, + item->value, NULL); + if (ret < 0) { + printk("%s: %d\n", __FUNCTION__, ret); + break; + } + } + return 0; +} + +static int sony_acpi_add(struct acpi_device *device) +{ + acpi_status status; + int result; + acpi_handle handle; + + sony_acpi_acpi_device = device; + + sony_acpi_handle = device->handle; + + if (debug) { + status = acpi_walk_namespace(ACPI_TYPE_METHOD, sony_acpi_handle, + 1, sony_walk_callback, NULL, NULL); + if (ACPI_FAILURE(status)) { + printk(LOG_PFX "unable to walk acpi resources\n"); + result = -ENODEV; + goto outwalk; + } + } + + status = acpi_install_notify_handler(sony_acpi_handle, + ACPI_DEVICE_NOTIFY, + sony_acpi_notify, NULL); + if (ACPI_FAILURE(status)) { + printk(LOG_PFX "unable to install notify handler\n"); + result = -ENODEV; + goto outwalk; + } + + if (ACPI_SUCCESS(acpi_get_handle(sony_acpi_handle, "GBRT", &handle))) { + sony_backlight_device = backlight_device_register("sony", NULL, + NULL, + &sony_backlight_properties); + + if (IS_ERR(sony_backlight_device)) { + printk(LOG_PFX "unable to register backlight device\n"); + sony_backlight_device = NULL; + } else + sony_backlight_properties.brightness = + sony_backlight_get_brightness + (sony_backlight_device); + } + + if (sony_snc_pf_add()) + goto outbacklight; + + printk(KERN_INFO ACPI_SNC_DRIVER_NAME " successfully installed\n"); + + return 0; + + outbacklight: + if (sony_backlight_device) + backlight_device_unregister(sony_backlight_device); + + status = acpi_remove_notify_handler(sony_acpi_handle, + ACPI_DEVICE_NOTIFY, + sony_acpi_notify); + if (ACPI_FAILURE(status)) + printk(LOG_PFX "unable to remove notify handler\n"); + outwalk: + return result; +} + +static int sony_acpi_remove(struct acpi_device *device, int type) +{ + acpi_status status; + + if (sony_backlight_device) + backlight_device_unregister(sony_backlight_device); + + sony_acpi_acpi_device = NULL; + + status = acpi_remove_notify_handler(sony_acpi_handle, + ACPI_DEVICE_NOTIFY, + sony_acpi_notify); + if (ACPI_FAILURE(status)) + printk(LOG_PFX "unable to remove notify handler\n"); + + sony_snc_pf_remove(); + + printk(KERN_INFO ACPI_SNC_DRIVER_NAME " successfully removed\n"); + + return 0; +} + +static struct acpi_driver sony_acpi_driver = { + .name = ACPI_SNC_DRIVER_NAME, + .class = ACPI_SNC_CLASS, + .ids = ACPI_SNC_HID, + .ops = { + .add = sony_acpi_add, + .remove = sony_acpi_remove, + .resume = sony_acpi_resume, + }, +}; + +static int __init sony_acpi_init(void) +{ + return acpi_bus_register_driver(&sony_acpi_driver); +} + +static void __exit sony_acpi_exit(void) +{ + acpi_bus_unregister_driver(&sony_acpi_driver); +} + +module_init(sony_acpi_init); +module_exit(sony_acpi_exit); diff --git a/drivers/mmc/at91_mci.c b/drivers/mmc/at91_mci.c index 2ce50f38e3c7..459f4b4feded 100644 --- a/drivers/mmc/at91_mci.c +++ b/drivers/mmc/at91_mci.c @@ -64,6 +64,7 @@ #include <linux/err.h> #include <linux/dma-mapping.h> #include <linux/clk.h> +#include <linux/atmel_pdc.h> #include <linux/mmc/host.h> #include <linux/mmc/protocol.h> @@ -75,7 +76,6 @@ #include <asm/arch/cpu.h> #include <asm/arch/gpio.h> #include <asm/arch/at91_mci.h> -#include <asm/arch/at91_pdc.h> #define DRIVER_NAME "at91_mci" @@ -211,13 +211,13 @@ static void at91mci_pre_dma_read(struct at91mci_host *host) /* Check to see if this needs filling */ if (i == 0) { - if (at91_mci_read(host, AT91_PDC_RCR) != 0) { + if (at91_mci_read(host, ATMEL_PDC_RCR) != 0) { pr_debug("Transfer active in current\n"); continue; } } else { - if (at91_mci_read(host, AT91_PDC_RNCR) != 0) { + if (at91_mci_read(host, ATMEL_PDC_RNCR) != 0) { pr_debug("Transfer active in next\n"); continue; } @@ -234,12 +234,12 @@ static void at91mci_pre_dma_read(struct at91mci_host *host) pr_debug("dma address = %08X, length = %d\n", sg->dma_address, sg->length); if (i == 0) { - at91_mci_write(host, AT91_PDC_RPR, sg->dma_address); - at91_mci_write(host, AT91_PDC_RCR, sg->length / 4); + at91_mci_write(host, ATMEL_PDC_RPR, sg->dma_address); + at91_mci_write(host, ATMEL_PDC_RCR, sg->length / 4); } else { - at91_mci_write(host, AT91_PDC_RNPR, sg->dma_address); - at91_mci_write(host, AT91_PDC_RNCR, sg->length / 4); + at91_mci_write(host, ATMEL_PDC_RNPR, sg->dma_address); + at91_mci_write(host, ATMEL_PDC_RNCR, sg->length / 4); } } @@ -303,7 +303,7 @@ static void at91mci_post_dma_read(struct at91mci_host *host) at91mci_pre_dma_read(host); else { at91_mci_write(host, AT91_MCI_IER, AT91_MCI_RXBUFF); - at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_RXTDIS | AT91_PDC_TXTDIS); + at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS); } pr_debug("post dma read done\n"); @@ -320,7 +320,7 @@ static void at91_mci_handle_transmitted(struct at91mci_host *host) pr_debug("Handling the transmit\n"); /* Disable the transfer */ - at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_RXTDIS | AT91_PDC_TXTDIS); + at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS); /* Now wait for cmd ready */ at91_mci_write(host, AT91_MCI_IDR, AT91_MCI_TXBUFE); @@ -431,15 +431,15 @@ static unsigned int at91_mci_send_command(struct at91mci_host *host, struct mmc_ cmd->opcode, cmdr, cmd->arg, blocks, block_length, at91_mci_read(host, AT91_MCI_MR)); if (!data) { - at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_TXTDIS | AT91_PDC_RXTDIS); - at91_mci_write(host, AT91_PDC_RPR, 0); - at91_mci_write(host, AT91_PDC_RCR, 0); - at91_mci_write(host, AT91_PDC_RNPR, 0); - at91_mci_write(host, AT91_PDC_RNCR, 0); - at91_mci_write(host, AT91_PDC_TPR, 0); - at91_mci_write(host, AT91_PDC_TCR, 0); - at91_mci_write(host, AT91_PDC_TNPR, 0); - at91_mci_write(host, AT91_PDC_TNCR, 0); + at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_TXTDIS | ATMEL_PDC_RXTDIS); + at91_mci_write(host, ATMEL_PDC_RPR, 0); + at91_mci_write(host, ATMEL_PDC_RCR, 0); + at91_mci_write(host, ATMEL_PDC_RNPR, 0); + at91_mci_write(host, ATMEL_PDC_RNCR, 0); + at91_mci_write(host, ATMEL_PDC_TPR, 0); + at91_mci_write(host, ATMEL_PDC_TCR, 0); + at91_mci_write(host, ATMEL_PDC_TNPR, 0); + at91_mci_write(host, ATMEL_PDC_TNCR, 0); at91_mci_write(host, AT91_MCI_ARGR, cmd->arg); at91_mci_write(host, AT91_MCI_CMDR, cmdr); @@ -452,7 +452,7 @@ static unsigned int at91_mci_send_command(struct at91mci_host *host, struct mmc_ /* * Disable the PDC controller */ - at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_RXTDIS | AT91_PDC_TXTDIS); + at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS); if (cmdr & AT91_MCI_TRCMD_START) { data->bytes_xfered = 0; @@ -481,8 +481,8 @@ static unsigned int at91_mci_send_command(struct at91mci_host *host, struct mmc_ pr_debug("Transmitting %d bytes\n", host->total_length); - at91_mci_write(host, AT91_PDC_TPR, host->physical_address); - at91_mci_write(host, AT91_PDC_TCR, host->total_length / 4); + at91_mci_write(host, ATMEL_PDC_TPR, host->physical_address); + at91_mci_write(host, ATMEL_PDC_TCR, host->total_length / 4); ier = AT91_MCI_TXBUFE; } } @@ -497,9 +497,9 @@ static unsigned int at91_mci_send_command(struct at91mci_host *host, struct mmc_ if (cmdr & AT91_MCI_TRCMD_START) { if (cmdr & AT91_MCI_TRDIR) - at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_RXTEN); + at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTEN); else - at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_TXTEN); + at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_TXTEN); } return ier; } diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index f69184a92eb2..f334959a335b 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c @@ -397,9 +397,23 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary) cfi_fixup(mtd, fixup_table); for (i=0; i< cfi->numchips; i++) { - cfi->chips[i].word_write_time = 1<<cfi->cfiq->WordWriteTimeoutTyp; - cfi->chips[i].buffer_write_time = 1<<cfi->cfiq->BufWriteTimeoutTyp; - cfi->chips[i].erase_time = 1000<<cfi->cfiq->BlockEraseTimeoutTyp; + if (cfi->cfiq->WordWriteTimeoutTyp) + cfi->chips[i].word_write_time = + 1<<cfi->cfiq->WordWriteTimeoutTyp; + else + cfi->chips[i].word_write_time = 50000; + + if (cfi->cfiq->BufWriteTimeoutTyp) + cfi->chips[i].buffer_write_time = + 1<<cfi->cfiq->BufWriteTimeoutTyp; + /* No default; if it isn't specified, we won't use it */ + + if (cfi->cfiq->BlockEraseTimeoutTyp) + cfi->chips[i].erase_time = + 1000<<cfi->cfiq->BlockEraseTimeoutTyp; + else + cfi->chips[i].erase_time = 2000000; + cfi->chips[i].ref_point_counter = 0; init_waitqueue_head(&(cfi->chips[i].wq)); } @@ -546,13 +560,11 @@ static int cfi_intelext_partition_fixup(struct mtd_info *mtd, struct cfi_intelext_programming_regioninfo *prinfo; prinfo = (struct cfi_intelext_programming_regioninfo *)&extp->extra[offs]; mtd->writesize = cfi->interleave << prinfo->ProgRegShift; - MTD_PROGREGION_CTRLMODE_VALID(mtd) = cfi->interleave * prinfo->ControlValid; - MTD_PROGREGION_CTRLMODE_INVALID(mtd) = cfi->interleave * prinfo->ControlInvalid; mtd->flags &= ~MTD_BIT_WRITEABLE; printk(KERN_DEBUG "%s: program region size/ctrl_valid/ctrl_inval = %d/%d/%d\n", map->name, mtd->writesize, - MTD_PROGREGION_CTRLMODE_VALID(mtd), - MTD_PROGREGION_CTRLMODE_INVALID(mtd)); + cfi->interleave * prinfo->ControlValid, + cfi->interleave * prinfo->ControlInvalid); } /* diff --git a/drivers/mtd/chips/cfi_cmdset_0020.c b/drivers/mtd/chips/cfi_cmdset_0020.c index d56849f5f107..69d49e0250a9 100644 --- a/drivers/mtd/chips/cfi_cmdset_0020.c +++ b/drivers/mtd/chips/cfi_cmdset_0020.c @@ -662,7 +662,7 @@ static int cfi_staa_write_buffers (struct mtd_info *mtd, loff_t to, * a small buffer for this. * XXX: If the buffer size is not a multiple of 2, this will break */ -#define ECCBUF_SIZE (mtd->eccsize) +#define ECCBUF_SIZE (mtd->writesize) #define ECCBUF_DIV(x) ((x) & ~(ECCBUF_SIZE - 1)) #define ECCBUF_MOD(x) ((x) & (ECCBUF_SIZE - 1)) static int diff --git a/drivers/mtd/devices/doc2000.c b/drivers/mtd/devices/doc2000.c index 603a7951ac9b..8a0c4dec6351 100644 --- a/drivers/mtd/devices/doc2000.c +++ b/drivers/mtd/devices/doc2000.c @@ -569,7 +569,6 @@ void DoC2k_init(struct mtd_info *mtd) mtd->type = MTD_NANDFLASH; mtd->flags = MTD_CAP_NANDFLASH; - mtd->ecctype = MTD_ECC_RS_DiskOnChip; mtd->size = 0; mtd->erasesize = 0; mtd->writesize = 512; diff --git a/drivers/mtd/devices/doc2001.c b/drivers/mtd/devices/doc2001.c index fe71a12c2627..6f368aec5d5d 100644 --- a/drivers/mtd/devices/doc2001.c +++ b/drivers/mtd/devices/doc2001.c @@ -348,7 +348,6 @@ void DoCMil_init(struct mtd_info *mtd) mtd->type = MTD_NANDFLASH; mtd->flags = MTD_CAP_NANDFLASH; - mtd->ecctype = MTD_ECC_RS_DiskOnChip; mtd->size = 0; /* FIXME: erase size is not always 8KiB */ diff --git a/drivers/mtd/devices/doc2001plus.c b/drivers/mtd/devices/doc2001plus.c index ba4db686285a..88ba82df0fbb 100644 --- a/drivers/mtd/devices/doc2001plus.c +++ b/drivers/mtd/devices/doc2001plus.c @@ -472,7 +472,6 @@ void DoCMilPlus_init(struct mtd_info *mtd) mtd->type = MTD_NANDFLASH; mtd->flags = MTD_CAP_NANDFLASH; - mtd->ecctype = MTD_ECC_RS_DiskOnChip; mtd->size = 0; mtd->erasesize = 0; diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index f457315579db..bbf0553bdb2e 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig @@ -204,7 +204,7 @@ config MTD_ESB2ROM config MTD_CK804XROM tristate "BIOS flash chip on Nvidia CK804" - depends on X86 && MTD_JEDECPROBE + depends on X86 && MTD_JEDECPROBE && PCI help Support for treating the BIOS flash chip on nvidia motherboards as an MTD device - with this you can reprogram your BIOS. diff --git a/drivers/mtd/maps/amd76xrom.c b/drivers/mtd/maps/amd76xrom.c index 78b671172bb2..728aed6ad722 100644 --- a/drivers/mtd/maps/amd76xrom.c +++ b/drivers/mtd/maps/amd76xrom.c @@ -205,8 +205,8 @@ static int __devinit amd76xrom_init_one (struct pci_dev *pdev, (((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); + sprintf(map->map_name, "%s @%08Lx", + MOD_NAME, (unsigned long long)map->map.phys); /* There is no generic VPP support */ for(map->map.bankwidth = 32; map->map.bankwidth; diff --git a/drivers/mtd/maps/ck804xrom.c b/drivers/mtd/maps/ck804xrom.c index 238d42e88ec5..3d4a4d8ac789 100644 --- a/drivers/mtd/maps/ck804xrom.c +++ b/drivers/mtd/maps/ck804xrom.c @@ -207,8 +207,8 @@ static int __devinit ck804xrom_init_one (struct pci_dev *pdev, (((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); + sprintf(map->map_name, "%s @%08Lx", + MOD_NAME, (unsigned long long)map->map.phys); /* There is no generic VPP support */ for(map->map.bankwidth = 32; map->map.bankwidth; @@ -327,7 +327,7 @@ static int __init init_ck804xrom(void) pdev = NULL; for(id = ck804xrom_pci_tbl; id->vendor; id++) { - pdev = pci_find_device(id->vendor, id->device, NULL); + pdev = pci_get_device(id->vendor, id->device, NULL); if (pdev) break; } diff --git a/drivers/mtd/maps/esb2rom.c b/drivers/mtd/maps/esb2rom.c index a9d808a617c9..0bc013fd66a3 100644 --- a/drivers/mtd/maps/esb2rom.c +++ b/drivers/mtd/maps/esb2rom.c @@ -289,8 +289,8 @@ static int __devinit esb2rom_init_one(struct pci_dev *pdev, (((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); + sprintf(map->map_name, "%s @%08Lx", + MOD_NAME, (unsigned long long)map->map.phys); /* Firmware hubs only use vpp when being programmed * in a factory setting. So in-place programming diff --git a/drivers/mtd/maps/ichxrom.c b/drivers/mtd/maps/ichxrom.c index 2bb3e63606e5..2c884c49e84a 100644 --- a/drivers/mtd/maps/ichxrom.c +++ b/drivers/mtd/maps/ichxrom.c @@ -227,8 +227,8 @@ static int __devinit ichxrom_init_one (struct pci_dev *pdev, (((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); + sprintf(map->map_name, "%s @%08Lx", + MOD_NAME, (unsigned long long)map->map.phys); /* Firmware hubs only use vpp when being programmed * in a factory setting. So in-place programming diff --git a/drivers/mtd/maps/netsc520.c b/drivers/mtd/maps/netsc520.c index ed215470158b..95dcab2146ad 100644 --- a/drivers/mtd/maps/netsc520.c +++ b/drivers/mtd/maps/netsc520.c @@ -94,7 +94,9 @@ static struct mtd_info *mymtd; static int __init init_netsc520(void) { - printk(KERN_NOTICE "NetSc520 flash device: 0x%lx at 0x%lx\n", netsc520_map.size, netsc520_map.phys); + printk(KERN_NOTICE "NetSc520 flash device: 0x%Lx at 0x%Lx\n", + (unsigned long long)netsc520_map.size, + (unsigned long long)netsc520_map.phys); netsc520_map.virt = ioremap_nocache(netsc520_map.phys, netsc520_map.size); if (!netsc520_map.virt) { diff --git a/drivers/mtd/maps/sc520cdp.c b/drivers/mtd/maps/sc520cdp.c index 9b50cfc355b1..4045e372b90d 100644 --- a/drivers/mtd/maps/sc520cdp.c +++ b/drivers/mtd/maps/sc520cdp.c @@ -237,8 +237,9 @@ static int __init init_sc520cdp(void) #endif for (i = 0; i < NUM_FLASH_BANKS; i++) { - printk(KERN_NOTICE "SC520 CDP flash device: 0x%lx at 0x%lx\n", - sc520cdp_map[i].size, sc520cdp_map[i].phys); + printk(KERN_NOTICE "SC520 CDP flash device: 0x%Lx at 0x%Lx\n", + (unsigned long long)sc520cdp_map[i].size, + (unsigned long long)sc520cdp_map[i].phys); sc520cdp_map[i].virt = ioremap_nocache(sc520cdp_map[i].phys, sc520cdp_map[i].size); diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index 61a994ea8af1..1592eac64e57 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -419,8 +419,9 @@ static int mtd_ioctl(struct inode *inode, struct file *file, info.erasesize = mtd->erasesize; info.writesize = mtd->writesize; info.oobsize = mtd->oobsize; - info.ecctype = mtd->ecctype; - info.eccsize = mtd->eccsize; + /* The below fields are obsolete */ + info.ecctype = -1; + info.eccsize = 0; if (copy_to_user(argp, &info, sizeof(struct mtd_info_user))) return -EFAULT; break; diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c index 06902683bc2a..880580c44e01 100644 --- a/drivers/mtd/mtdconcat.c +++ b/drivers/mtd/mtdconcat.c @@ -727,8 +727,6 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c concat->mtd.erasesize = subdev[0]->erasesize; concat->mtd.writesize = subdev[0]->writesize; concat->mtd.oobsize = subdev[0]->oobsize; - concat->mtd.ecctype = subdev[0]->ecctype; - concat->mtd.eccsize = subdev[0]->eccsize; if (subdev[0]->writev) concat->mtd.writev = concat_writev; if (subdev[0]->read_oob) @@ -774,8 +772,6 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c 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 || !concat->mtd.read_oob != !subdev[i]->read_oob || !concat->mtd.write_oob != !subdev[i]->write_oob) { kfree(concat); diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index bafd2fba87bd..633def3fb087 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -338,8 +338,6 @@ int add_mtd_partitions(struct mtd_info *master, slave->mtd.size = parts[i].size; slave->mtd.writesize = master->writesize; 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; diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 358f55a82dbe..2d12dcdd740c 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -126,10 +126,6 @@ config MTD_NAND_S3C2410_HWECC incorrect ECC generation, and if using these, the default of software ECC is preferable. - If you lay down a device with the hardware ECC, then you will - currently not be able to switch to software, as there is no - implementation for ECC method used by the S3C2410 - config MTD_NAND_NDFC tristate "NDFC NanD Flash Controller" depends on MTD_NAND && 44x @@ -221,9 +217,17 @@ config MTD_NAND_SHARPSL tristate "Support for NAND Flash on Sharp SL Series (C7xx + others)" depends on MTD_NAND && ARCH_PXA +config MTD_NAND_BASLER_EXCITE + tristate "Support for NAND Flash on Basler eXcite" + depends on MTD_NAND && BASLER_EXCITE + help + This enables the driver for the NAND flash device found on the + Basler eXcite Smart Camera. If built as a module, the driver + will be named "excite_nandflash.ko". + config MTD_NAND_CAFE tristate "NAND support for OLPC CAFÉ chip" - depends on PCI + depends on MTD_NAND && PCI help Use NAND flash attached to the CAFÉ chip designed for the $100 laptop. diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index f7a53f0b7017..80f1dfc77949 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -24,6 +24,7 @@ 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 +obj-$(CONFIG_MTD_NAND_BASLER_EXCITE) += excite_nandflash.o nand-objs := nand_base.o nand_bbt.o cafe_nand-objs := cafe.o cafe_ecc.o diff --git a/drivers/mtd/nand/cafe.c b/drivers/mtd/nand/cafe.c index 08cb060dfa3d..fd6bb3ed40df 100644 --- a/drivers/mtd/nand/cafe.c +++ b/drivers/mtd/nand/cafe.c @@ -78,8 +78,9 @@ module_param(regdebug, int, 0644); static int checkecc = 1; module_param(checkecc, int, 0644); -static int slowtiming = 0; -module_param(slowtiming, int, 0644); +static int numtimings; +static int timing[3]; +module_param_array(timing, int, &numtimings, 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) @@ -264,10 +265,10 @@ static void cafe_nand_cmdfunc(struct mtd_info *mtd, unsigned command, ndelay(100); if (1) { - int c = 500000; + int c; uint32_t irqs; - while (c--) { + for (c = 500000; c != 0; c--) { irqs = cafe_readl(cafe, NAND_IRQ); if (irqs & doneint) break; @@ -529,6 +530,7 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev, { struct mtd_info *mtd; struct cafe_priv *cafe; + uint32_t timing1, timing2, timing3; uint32_t ctrl; int err = 0; @@ -580,31 +582,45 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev, cafe->nand.block_bad = cafe_nand_block_bad; } + if (numtimings && numtimings != 3) { + dev_warn(&cafe->pdev->dev, "%d timing register values ignored; precisely three are required\n", numtimings); + } + + if (numtimings == 3) { + timing1 = timing[0]; + timing2 = timing[1]; + timing3 = timing[2]; + cafe_dev_dbg(&cafe->pdev->dev, "Using provided timings (%08x %08x %08x)\n", + timing1, timing2, timing3); + } else { + timing1 = cafe_readl(cafe, NAND_TIMING1); + timing2 = cafe_readl(cafe, NAND_TIMING2); + timing3 = cafe_readl(cafe, NAND_TIMING3); + + if (timing1 | timing2 | timing3) { + cafe_dev_dbg(&cafe->pdev->dev, "Timing registers already set (%08x %08x %08x)\n", timing1, timing2, timing3); + } else { + dev_warn(&cafe->pdev->dev, "Timing registers unset; using most conservative defaults\n"); + timing1 = timing2 = timing3 = 0xffffffff; + } + } + /* 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); + cafe_writel(cafe, timing1, NAND_TIMING1); + cafe_writel(cafe, timing2, NAND_TIMING2); + cafe_writel(cafe, timing3, NAND_TIMING3); - /* 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, IRQF_SHARED, "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; @@ -631,32 +647,8 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev, 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 */ + + /* Scan to find existence of the device */ if (nand_scan_ident(mtd, 1)) { err = -ENXIO; goto out_irq; @@ -760,13 +752,4 @@ 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 -*/ +MODULE_DESCRIPTION("NAND flash driver for OLPC CAFÉ chip"); diff --git a/drivers/mtd/nand/cafe_ecc.c b/drivers/mtd/nand/cafe_ecc.c index 1b9fa05a4474..ea5c8491d2c5 100644 --- a/drivers/mtd/nand/cafe_ecc.c +++ b/drivers/mtd/nand/cafe_ecc.c @@ -1045,7 +1045,7 @@ static unsigned short err_pos_lut[4096] = { static unsigned short err_pos(unsigned short din) { - BUG_ON(din > 4096); + BUG_ON(din >= ARRAY_SIZE(err_pos_lut)); return err_pos_lut[din]; } static int chk_no_err_only(unsigned short *chk_syndrome_list, unsigned short *err_info) diff --git a/drivers/mtd/nand/excite_nandflash.c b/drivers/mtd/nand/excite_nandflash.c new file mode 100644 index 000000000000..7e9afc4c7757 --- /dev/null +++ b/drivers/mtd/nand/excite_nandflash.c @@ -0,0 +1,248 @@ +/* +* Copyright (C) 2005 - 2007 by Basler Vision Technologies AG +* Author: Thomas Koeller <thomas.koeller.qbaslerweb.com> +* Original code by Thies Moeller <thies.moeller@baslerweb.com> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include <linux/module.h> +#include <linux/types.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/ioport.h> +#include <linux/platform_device.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/kernel.h> + +#include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> +#include <linux/mtd/nand_ecc.h> +#include <linux/mtd/partitions.h> + +#include <asm/io.h> +#include <asm/rm9k-ocd.h> + +#include <excite_nandflash.h> + +#define EXCITE_NANDFLASH_VERSION "0.1" + +/* I/O register offsets */ +#define EXCITE_NANDFLASH_DATA_BYTE 0x00 +#define EXCITE_NANDFLASH_STATUS_BYTE 0x0c +#define EXCITE_NANDFLASH_ADDR_BYTE 0x10 +#define EXCITE_NANDFLASH_CMD_BYTE 0x14 + +/* prefix for debug output */ +static const char module_id[] = "excite_nandflash"; + +/* + * partition definition + */ +static const struct mtd_partition partition_info[] = { + { + .name = "eXcite RootFS", + .offset = 0, + .size = MTDPART_SIZ_FULL + } +}; + +static inline const struct resource * +excite_nand_get_resource(struct platform_device *d, unsigned long flags, + const char *basename) +{ + char buf[80]; + + if (snprintf(buf, sizeof buf, "%s_%u", basename, d->id) >= sizeof buf) + return NULL; + return platform_get_resource_byname(d, flags, buf); +} + +static inline void __iomem * +excite_nand_map_regs(struct platform_device *d, const char *basename) +{ + void *result = NULL; + const struct resource *const r = + excite_nand_get_resource(d, IORESOURCE_MEM, basename); + + if (r) + result = ioremap_nocache(r->start, r->end + 1 - r->start); + return result; +} + +/* controller and mtd information */ +struct excite_nand_drvdata { + struct mtd_info board_mtd; + struct nand_chip board_chip; + void __iomem *regs; + void __iomem *tgt; +}; + +/* Control function */ +static void excite_nand_control(struct mtd_info *mtd, int cmd, + unsigned int ctrl) +{ + struct excite_nand_drvdata * const d = + container_of(mtd, struct excite_nand_drvdata, board_mtd); + + switch (ctrl) { + case NAND_CTRL_CHANGE | NAND_CTRL_CLE: + d->tgt = d->regs + EXCITE_NANDFLASH_CMD_BYTE; + break; + case NAND_CTRL_CHANGE | NAND_CTRL_ALE: + d->tgt = d->regs + EXCITE_NANDFLASH_ADDR_BYTE; + break; + case NAND_CTRL_CHANGE | NAND_NCE: + d->tgt = d->regs + EXCITE_NANDFLASH_DATA_BYTE; + break; + } + + if (cmd != NAND_CMD_NONE) + __raw_writeb(cmd, d->tgt); +} + +/* Return 0 if flash is busy, 1 if ready */ +static int excite_nand_devready(struct mtd_info *mtd) +{ + struct excite_nand_drvdata * const drvdata = + container_of(mtd, struct excite_nand_drvdata, board_mtd); + + return __raw_readb(drvdata->regs + EXCITE_NANDFLASH_STATUS_BYTE); +} + +/* + * Called by device layer to remove the driver. + * The binding to the mtd and all allocated + * resources are released. + */ +static int __exit excite_nand_remove(struct device *dev) +{ + struct excite_nand_drvdata * const this = dev_get_drvdata(dev); + + dev_set_drvdata(dev, NULL); + + if (unlikely(!this)) { + printk(KERN_ERR "%s: called %s without private data!!", + module_id, __func__); + return -EINVAL; + } + + /* first thing we need to do is release our mtd + * then go through freeing the resource used + */ + nand_release(&this->board_mtd); + + /* free the common resources */ + iounmap(this->regs); + kfree(this); + + DEBUG(MTD_DEBUG_LEVEL1, "%s: removed\n", module_id); + return 0; +} + +/* + * Called by device layer when it finds a device matching + * one our driver can handle. This code checks to see if + * it can allocate all necessary resources then calls the + * nand layer to look for devices. +*/ +static int __init excite_nand_probe(struct device *dev) +{ + struct platform_device * const pdev = to_platform_device(dev); + struct excite_nand_drvdata *drvdata; /* private driver data */ + struct nand_chip *board_chip; /* private flash chip data */ + struct mtd_info *board_mtd; /* mtd info for this board */ + int scan_res; + + drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL); + if (unlikely(!drvdata)) { + printk(KERN_ERR "%s: no memory for drvdata\n", + module_id); + return -ENOMEM; + } + + /* bind private data into driver */ + dev_set_drvdata(dev, drvdata); + + /* allocate and map the resource */ + drvdata->regs = + excite_nand_map_regs(pdev, EXCITE_NANDFLASH_RESOURCE_REGS); + + if (unlikely(!drvdata->regs)) { + printk(KERN_ERR "%s: cannot reserve register region\n", + module_id); + kfree(drvdata); + return -ENXIO; + } + + drvdata->tgt = drvdata->regs + EXCITE_NANDFLASH_DATA_BYTE; + + /* initialise our chip */ + board_chip = &drvdata->board_chip; + board_chip->IO_ADDR_R = board_chip->IO_ADDR_W = + drvdata->regs + EXCITE_NANDFLASH_DATA_BYTE; + board_chip->cmd_ctrl = excite_nand_control; + board_chip->dev_ready = excite_nand_devready; + board_chip->chip_delay = 25; + board_chip->ecc.mode = NAND_ECC_SOFT; + + /* link chip to mtd */ + board_mtd = &drvdata->board_mtd; + board_mtd->priv = board_chip; + + DEBUG(MTD_DEBUG_LEVEL2, "%s: device scan\n", module_id); + scan_res = nand_scan(&drvdata->board_mtd, 1); + + if (likely(!scan_res)) { + DEBUG(MTD_DEBUG_LEVEL2, "%s: register partitions\n", module_id); + add_mtd_partitions(&drvdata->board_mtd, partition_info, + sizeof partition_info / sizeof partition_info[0]); + } else { + iounmap(drvdata->regs); + kfree(drvdata); + printk(KERN_ERR "%s: device scan failed\n", module_id); + return -EIO; + } + return 0; +} + +static struct device_driver excite_nand_driver = { + .name = "excite_nand", + .bus = &platform_bus_type, + .probe = excite_nand_probe, + .remove = __exit_p(excite_nand_remove) +}; + +static int __init excite_nand_init(void) +{ + pr_info("Basler eXcite nand flash driver Version " + EXCITE_NANDFLASH_VERSION "\n"); + return driver_register(&excite_nand_driver); +} + +static void __exit excite_nand_exit(void) +{ + driver_unregister(&excite_nand_driver); +} + +module_init(excite_nand_init); +module_exit(excite_nand_exit); + +MODULE_AUTHOR("Thomas Koeller <thomas.koeller@baslerweb.com>"); +MODULE_DESCRIPTION("Basler eXcite NAND-Flash driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(EXCITE_NANDFLASH_VERSION) diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index dfe56e03e48b..acaf97bc80d1 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -1272,10 +1272,25 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, 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 + if (ops->mode == MTD_OOB_AUTO) len = chip->ecc.layout->oobavail; + else + len = mtd->oobsize; + + if (unlikely(ops->ooboffs >= len)) { + DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: " + "Attempt to start read outside oob\n"); + return -EINVAL; + } + + /* Do not allow reads past end of device */ + if (unlikely(from >= mtd->size || + ops->ooboffs + readlen > ((mtd->size >> chip->page_shift) - + (from >> chip->page_shift)) * len)) { + DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: " + "Attempt read beyond end of device\n"); + return -EINVAL; + } chipnr = (int)(from >> chip->chip_shift); chip->select_chip(mtd, chipnr); @@ -1742,19 +1757,40 @@ static int nand_write(struct mtd_info *mtd, loff_t to, size_t len, static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops) { - int chipnr, page, status; + int chipnr, page, status, len; struct nand_chip *chip = mtd->priv; DEBUG(MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n", (unsigned int)to, (int)ops->ooblen); + if (ops->mode == MTD_OOB_AUTO) + len = chip->ecc.layout->oobavail; + else + len = mtd->oobsize; + /* Do not allow write past end of page */ - if ((ops->ooboffs + ops->ooblen) > mtd->oobsize) { + if ((ops->ooboffs + ops->ooblen) > len) { DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: " "Attempt to write past end of page\n"); return -EINVAL; } + if (unlikely(ops->ooboffs >= len)) { + DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: " + "Attempt to start write outside oob\n"); + return -EINVAL; + } + + /* Do not allow reads past end of device */ + if (unlikely(to >= mtd->size || + ops->ooboffs + ops->ooblen > + ((mtd->size >> chip->page_shift) - + (to >> chip->page_shift)) * len)) { + DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: " + "Attempt write beyond end of device\n"); + return -EINVAL; + } + chipnr = (int)(to >> chip->chip_shift); chip->select_chip(mtd, chipnr); @@ -2530,7 +2566,6 @@ int nand_scan_tail(struct mtd_info *mtd) /* Fill in remaining MTD driver data */ mtd->type = MTD_NANDFLASH; mtd->flags = MTD_CAP_NANDFLASH; - mtd->ecctype = MTD_ECC_SW; mtd->erase = nand_erase; mtd->point = NULL; mtd->unpoint = NULL; diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index 8b3203571eeb..0ddfd6de75c5 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c @@ -337,17 +337,69 @@ static int s3c2412_nand_devready(struct mtd_info *mtd) static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc) { - pr_debug("s3c2410_nand_correct_data(%p,%p,%p,%p)\n", mtd, dat, read_ecc, calc_ecc); + struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); + unsigned int diff0, diff1, diff2; + unsigned int bit, byte; - pr_debug("eccs: read %02x,%02x,%02x vs calc %02x,%02x,%02x\n", - read_ecc[0], read_ecc[1], read_ecc[2], calc_ecc[0], calc_ecc[1], calc_ecc[2]); + pr_debug("%s(%p,%p,%p,%p)\n", __func__, mtd, dat, read_ecc, calc_ecc); - if (read_ecc[0] == calc_ecc[0] && read_ecc[1] == calc_ecc[1] && read_ecc[2] == calc_ecc[2]) - return 0; + diff0 = read_ecc[0] ^ calc_ecc[0]; + diff1 = read_ecc[1] ^ calc_ecc[1]; + diff2 = read_ecc[2] ^ calc_ecc[2]; + + pr_debug("%s: rd %02x%02x%02x calc %02x%02x%02x diff %02x%02x%02x\n", + __func__, + read_ecc[0], read_ecc[1], read_ecc[2], + calc_ecc[0], calc_ecc[1], calc_ecc[2], + diff0, diff1, diff2); + + if (diff0 == 0 && diff1 == 0 && diff2 == 0) + return 0; /* ECC is ok */ + + /* Can we correct this ECC (ie, one row and column change). + * Note, this is similar to the 256 error code on smartmedia */ + + if (((diff0 ^ (diff0 >> 1)) & 0x55) == 0x55 && + ((diff1 ^ (diff1 >> 1)) & 0x55) == 0x55 && + ((diff2 ^ (diff2 >> 1)) & 0x55) == 0x55) { + /* calculate the bit position of the error */ + + bit = (diff2 >> 2) & 1; + bit |= (diff2 >> 3) & 2; + bit |= (diff2 >> 4) & 4; + + /* calculate the byte position of the error */ + + byte = (diff1 << 1) & 0x80; + byte |= (diff1 << 2) & 0x40; + byte |= (diff1 << 3) & 0x20; + byte |= (diff1 << 4) & 0x10; + + byte |= (diff0 >> 3) & 0x08; + byte |= (diff0 >> 2) & 0x04; + byte |= (diff0 >> 1) & 0x02; + byte |= (diff0 >> 0) & 0x01; - /* we curently have no method for correcting the error */ + byte |= (diff2 << 8) & 0x100; - return -1; + dev_dbg(info->device, "correcting error bit %d, byte %d\n", + bit, byte); + + dat[byte] ^= (1 << bit); + return 1; + } + + /* if there is only one bit difference in the ECC, then + * one of only a row or column parity has changed, which + * means the error is most probably in the ECC itself */ + + diff0 |= (diff1 << 8); + diff0 |= (diff2 << 16); + + if ((diff0 & ~(1<<fls(diff0))) == 0) + return 1; + + return 0; } /* ECC functions @@ -366,6 +418,15 @@ static void s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode) writel(ctrl, info->regs + S3C2410_NFCONF); } +static void s3c2412_nand_enable_hwecc(struct mtd_info *mtd, int mode) +{ + struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); + unsigned long ctrl; + + ctrl = readl(info->regs + S3C2440_NFCONT); + writel(ctrl | S3C2412_NFCONT_INIT_MAIN_ECC, info->regs + S3C2440_NFCONT); +} + static void s3c2440_nand_enable_hwecc(struct mtd_info *mtd, int mode) { struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); @@ -383,6 +444,21 @@ static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u ecc_code[1] = readb(info->regs + S3C2410_NFECC + 1); ecc_code[2] = readb(info->regs + S3C2410_NFECC + 2); + pr_debug("%s: returning ecc %02x%02x%02x\n", __func__, + ecc_code[0], ecc_code[1], ecc_code[2]); + + return 0; +} + +static int s3c2412_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code) +{ + struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); + unsigned long ecc = readl(info->regs + S3C2412_NFMECC0); + + ecc_code[0] = ecc; + ecc_code[1] = ecc >> 8; + ecc_code[2] = ecc >> 16; + pr_debug("calculate_ecc: returning ecc %02x,%02x,%02x\n", ecc_code[0], ecc_code[1], ecc_code[2]); return 0; @@ -397,7 +473,7 @@ static int s3c2440_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u ecc_code[1] = ecc >> 8; ecc_code[2] = ecc >> 16; - pr_debug("calculate_ecc: returning ecc %02x,%02x,%02x\n", ecc_code[0], ecc_code[1], ecc_code[2]); + pr_debug("%s: returning ecc %06x\n", __func__, ecc); return 0; } @@ -565,6 +641,10 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info, break; case TYPE_S3C2412: + chip->ecc.hwctl = s3c2412_nand_enable_hwecc; + chip->ecc.calculate = s3c2412_nand_calculate_ecc; + break; + case TYPE_S3C2440: chip->ecc.hwctl = s3c2440_nand_enable_hwecc; chip->ecc.calculate = s3c2440_nand_calculate_ecc; diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 2da6bb26353e..7f1cb6e5dccb 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -1,7 +1,7 @@ /* * linux/drivers/mtd/onenand/onenand_base.c * - * Copyright (C) 2005-2006 Samsung Electronics + * Copyright (C) 2005-2007 Samsung Electronics * Kyungmin Park <kyungmin.park@samsung.com> * * This program is free software; you can redistribute it and/or modify @@ -94,16 +94,9 @@ static void onenand_writew(unsigned short value, void __iomem *addr) */ static int onenand_block_address(struct onenand_chip *this, int block) { - if (this->device_id & ONENAND_DEVICE_IS_DDP) { - /* Device Flash Core select, NAND Flash Block Address */ - int dfs = 0; - - if (block & this->density_mask) - dfs = 1; - - return (dfs << ONENAND_DDP_SHIFT) | - (block & (this->density_mask - 1)); - } + /* Device Flash Core select, NAND Flash Block Address */ + if (block & this->density_mask) + return ONENAND_DDP_CHIP1 | (block ^ this->density_mask); return block; } @@ -118,17 +111,11 @@ static int onenand_block_address(struct onenand_chip *this, int block) */ static int onenand_bufferram_address(struct onenand_chip *this, int block) { - if (this->device_id & ONENAND_DEVICE_IS_DDP) { - /* Device BufferRAM Select */ - int dbs = 0; - - if (block & this->density_mask) - dbs = 1; + /* Device BufferRAM Select */ + if (block & this->density_mask) + return ONENAND_DDP_CHIP1; - return (dbs << ONENAND_DDP_SHIFT); - } - - return 0; + return ONENAND_DDP_CHIP0; } /** @@ -317,22 +304,25 @@ 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) { - DEBUG(MTD_DEBUG_LEVEL0, "onenand_wait: controller error = 0x%04x\n", ctrl); + printk(KERN_ERR "onenand_wait: controller error = 0x%04x\n", ctrl); if (ctrl & ONENAND_CTRL_LOCK) - DEBUG(MTD_DEBUG_LEVEL0, "onenand_wait: it's locked error.\n"); + printk(KERN_ERR "onenand_wait: it's locked error.\n"); return ctrl; } if (interrupt & ONENAND_INT_READ) { 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); + printk(KERN_ERR "onenand_wait: ECC error = 0x%04x\n", ecc); if (ecc & ONENAND_ECC_2BIT_ALL) { mtd->ecc_stats.failed++; return ecc; } else if (ecc & ONENAND_ECC_1BIT_ALL) mtd->ecc_stats.corrected++; } + } else if (state == FL_READING) { + printk(KERN_ERR "onenand_wait: read timeout! ctrl=0x%04x intr=0x%04x\n", ctrl, interrupt); + return -EIO; } return 0; @@ -587,22 +577,32 @@ static int onenand_write_bufferram(struct mtd_info *mtd, int area, static int onenand_check_bufferram(struct mtd_info *mtd, loff_t addr) { struct onenand_chip *this = mtd->priv; - int block, page; - int i; + int blockpage, found = 0; + unsigned int i; - block = (int) (addr >> this->erase_shift); - page = (int) (addr >> this->page_shift); - page &= this->page_mask; + blockpage = (int) (addr >> this->page_shift); + /* Is there valid data? */ i = ONENAND_CURRENT_BUFFERRAM(this); + if (this->bufferram[i].blockpage == blockpage) + found = 1; + else { + /* Check another BufferRAM */ + i = ONENAND_NEXT_BUFFERRAM(this); + if (this->bufferram[i].blockpage == blockpage) { + ONENAND_SET_NEXT_BUFFERRAM(this); + found = 1; + } + } - /* Is there valid data? */ - if (this->bufferram[i].block == block && - this->bufferram[i].page == page && - this->bufferram[i].valid) - return 1; + if (found && ONENAND_IS_DDP(this)) { + /* Select DataRAM for DDP */ + int block = (int) (addr >> this->erase_shift); + int value = onenand_bufferram_address(this, block); + this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2); + } - return 0; + return found; } /** @@ -613,31 +613,49 @@ static int onenand_check_bufferram(struct mtd_info *mtd, loff_t addr) * * Update BufferRAM information */ -static int onenand_update_bufferram(struct mtd_info *mtd, loff_t addr, +static void onenand_update_bufferram(struct mtd_info *mtd, loff_t addr, int valid) { struct onenand_chip *this = mtd->priv; - int block, page; - int i; + int blockpage; + unsigned int i; - block = (int) (addr >> this->erase_shift); - page = (int) (addr >> this->page_shift); - page &= this->page_mask; + blockpage = (int) (addr >> this->page_shift); - /* Invalidate BufferRAM */ - for (i = 0; i < MAX_BUFFERRAM; i++) { - if (this->bufferram[i].block == block && - this->bufferram[i].page == page) - this->bufferram[i].valid = 0; - } + /* Invalidate another BufferRAM */ + i = ONENAND_NEXT_BUFFERRAM(this); + if (this->bufferram[i].blockpage == blockpage) + this->bufferram[i].blockpage = -1; /* Update BufferRAM */ i = ONENAND_CURRENT_BUFFERRAM(this); - this->bufferram[i].block = block; - this->bufferram[i].page = page; - this->bufferram[i].valid = valid; + if (valid) + this->bufferram[i].blockpage = blockpage; + else + this->bufferram[i].blockpage = -1; +} - return 0; +/** + * onenand_invalidate_bufferram - [GENERIC] Invalidate BufferRAM information + * @param mtd MTD data structure + * @param addr start address to invalidate + * @param len length to invalidate + * + * Invalidate BufferRAM information + */ +static void onenand_invalidate_bufferram(struct mtd_info *mtd, loff_t addr, + unsigned int len) +{ + struct onenand_chip *this = mtd->priv; + int i; + loff_t end_addr = addr + len; + + /* Invalidate BufferRAM */ + for (i = 0; i < MAX_BUFFERRAM; i++) { + loff_t buf_addr = this->bufferram[i].blockpage << this->page_shift; + if (buf_addr >= addr && buf_addr < end_addr) + this->bufferram[i].blockpage = -1; + } } /** @@ -716,7 +734,7 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, /* Do not allow reads past end of device */ if ((from + len) > mtd->size) { - DEBUG(MTD_DEBUG_LEVEL0, "onenand_read: Attempt read beyond end of device\n"); + printk(KERN_ERR "onenand_read: Attempt read beyond end of device\n"); *retlen = 0; return -EINVAL; } @@ -724,8 +742,6 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, /* Grab the lock and see if the device is available */ onenand_get_device(mtd, FL_READING); - /* TODO handling oob */ - stats = mtd->ecc_stats; /* Read-while-load method */ @@ -754,9 +770,9 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, * 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); + if (ONENAND_IS_DDP(this) && + unlikely(from == (this->chipsize >> 1))) { + this->write_word(ONENAND_DDP_CHIP0, this->base + ONENAND_REG_START_ADDRESS2); boundary = 1; } else boundary = 0; @@ -770,7 +786,7 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, break; /* Set up for next read from bufferRAM */ if (unlikely(boundary)) - this->write_word(0x8000, this->base + ONENAND_REG_START_ADDRESS2); + this->write_word(ONENAND_DDP_CHIP1, this->base + ONENAND_REG_START_ADDRESS2); ONENAND_SET_NEXT_BUFFERRAM(this); buf += thislen; thislen = min_t(int, mtd->writesize, len - read); @@ -801,20 +817,59 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, } /** + * onenand_transfer_auto_oob - [Internal] oob auto-placement transfer + * @param mtd MTD device structure + * @param buf destination address + * @param column oob offset to read from + * @param thislen oob length to read + */ +static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf, int column, + int thislen) +{ + struct onenand_chip *this = mtd->priv; + struct nand_oobfree *free; + int readcol = column; + int readend = column + thislen; + int lastgap = 0; + uint8_t *oob_buf = this->page_buf + mtd->writesize; + + for (free = this->ecclayout->oobfree; free->length; ++free) { + if (readcol >= lastgap) + readcol += free->offset - lastgap; + if (readend >= lastgap) + readend += free->offset - lastgap; + lastgap = free->offset + free->length; + } + this->read_bufferram(mtd, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize); + for (free = this->ecclayout->oobfree; free->length; ++free) { + int free_end = free->offset + free->length; + if (free->offset < readend && free_end > readcol) { + int st = max_t(int,free->offset,readcol); + int ed = min_t(int,free_end,readend); + int n = ed - st; + memcpy(buf, oob_buf + st, n); + buf += n; + } + } + return 0; +} + +/** * onenand_do_read_oob - [MTD Interface] OneNAND read out-of-band * @param mtd MTD device structure * @param from offset to read from * @param len number of bytes to read * @param retlen pointer to variable to store the number of read bytes * @param buf the databuffer to put data + * @param mode operation mode * * OneNAND read out-of-band data from the spare area */ -int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, u_char *buf) +static int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf, mtd_oob_mode_t mode) { struct onenand_chip *this = mtd->priv; - int read = 0, thislen, column; + int read = 0, thislen, column, oobsize; int ret = 0; DEBUG(MTD_DEBUG_LEVEL3, "onenand_read_oob: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); @@ -822,21 +877,33 @@ int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len, /* Initialize return length value */ *retlen = 0; + if (mode == MTD_OOB_AUTO) + oobsize = this->ecclayout->oobavail; + else + oobsize = mtd->oobsize; + + column = from & (mtd->oobsize - 1); + + if (unlikely(column >= oobsize)) { + printk(KERN_ERR "onenand_read_oob: Attempted to start read outside oob\n"); + return -EINVAL; + } + /* Do not allow reads past end of device */ - if (unlikely((from + len) > mtd->size)) { - DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_oob: Attempt read beyond end of device\n"); + if (unlikely(from >= mtd->size || + column + len > ((mtd->size >> this->page_shift) - + (from >> this->page_shift)) * oobsize)) { + printk(KERN_ERR "onenand_read_oob: Attempted to read beyond end of device\n"); return -EINVAL; } /* Grab the lock and see if the device is available */ onenand_get_device(mtd, FL_READING); - column = from & (mtd->oobsize - 1); - while (read < len) { cond_resched(); - thislen = mtd->oobsize - column; + thislen = oobsize - column; thislen = min_t(int, thislen, len); this->command(mtd, ONENAND_CMD_READOOB, from, mtd->oobsize); @@ -846,11 +913,14 @@ int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len, ret = this->wait(mtd, FL_READING); /* First copy data and check return value for ECC handling */ - this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen); + if (mode == MTD_OOB_AUTO) + onenand_transfer_auto_oob(mtd, buf, column, thislen); + else + 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; + printk(KERN_ERR "onenand_read_oob: read failed = 0x%x\n", ret); + break; } read += thislen; @@ -868,7 +938,6 @@ int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len, } } -out: /* Deselect and wake up anyone waiting on the device */ onenand_release_device(mtd); @@ -885,10 +954,132 @@ out: static int onenand_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) { - BUG_ON(ops->mode != MTD_OOB_PLACE); - + switch (ops->mode) { + case MTD_OOB_PLACE: + case MTD_OOB_AUTO: + break; + case MTD_OOB_RAW: + /* Not implemented yet */ + default: + return -EINVAL; + } return onenand_do_read_oob(mtd, from + ops->ooboffs, ops->ooblen, - &ops->oobretlen, ops->oobbuf); + &ops->oobretlen, ops->oobbuf, ops->mode); +} + +/** + * onenand_bbt_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_bbt_wait(struct mtd_info *mtd, int state) +{ + struct onenand_chip *this = mtd->priv; + unsigned long timeout; + unsigned int interrupt; + unsigned int ctrl; + + /* The 20 msec is enough */ + timeout = jiffies + msecs_to_jiffies(20); + while (time_before(jiffies, timeout)) { + interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT); + if (interrupt & ONENAND_INT_MASTER) + break; + } + /* To get correct interrupt status in timeout case */ + interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT); + ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS); + + if (ctrl & ONENAND_CTRL_ERROR) { + printk(KERN_DEBUG "onenand_bbt_wait: controller error = 0x%04x\n", ctrl); + /* Initial bad block case */ + if (ctrl & ONENAND_CTRL_LOAD) + return ONENAND_BBT_READ_ERROR; + return ONENAND_BBT_READ_FATAL_ERROR; + } + + if (interrupt & ONENAND_INT_READ) { + int ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS); + if (ecc & ONENAND_ECC_2BIT_ALL) + return ONENAND_BBT_READ_ERROR; + } else { + printk(KERN_ERR "onenand_bbt_wait: read timeout!" + "ctrl=0x%04x intr=0x%04x\n", ctrl, interrupt); + return ONENAND_BBT_READ_FATAL_ERROR; + } + + return 0; +} + +/** + * onenand_bbt_read_oob - [MTD Interface] OneNAND read out-of-band for bbt scan + * @param mtd MTD device structure + * @param from offset to read from + * @param @ops oob operation description structure + * + * OneNAND read out-of-band data from the spare area for bbt scan + */ +int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from, + struct mtd_oob_ops *ops) +{ + struct onenand_chip *this = mtd->priv; + int read = 0, thislen, column; + int ret = 0; + size_t len = ops->ooblen; + u_char *buf = ops->oobbuf; + + DEBUG(MTD_DEBUG_LEVEL3, "onenand_bbt_read_oob: from = 0x%08x, len = %zi\n", (unsigned int) from, len); + + /* Initialize return value */ + ops->oobretlen = 0; + + /* Do not allow reads past end of device */ + if (unlikely((from + len) > mtd->size)) { + printk(KERN_ERR "onenand_bbt_read_oob: Attempt read beyond end of device\n"); + return ONENAND_BBT_READ_FATAL_ERROR; + } + + /* Grab the lock and see if the device is available */ + onenand_get_device(mtd, FL_READING); + + column = from & (mtd->oobsize - 1); + + while (read < len) { + cond_resched(); + + thislen = mtd->oobsize - column; + thislen = min_t(int, thislen, len); + + this->command(mtd, ONENAND_CMD_READOOB, from, mtd->oobsize); + + onenand_update_bufferram(mtd, from, 0); + + ret = onenand_bbt_wait(mtd, FL_READING); + if (ret) + break; + + this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen); + read += thislen; + if (read == len) + break; + + buf += thislen; + + /* Read more? */ + if (read < len) { + /* Update Page size */ + from += mtd->writesize; + column = 0; + } + } + + /* Deselect and wake up anyone waiting on the device */ + onenand_release_device(mtd); + + ops->oobretlen = read; + return ret; } #ifdef CONFIG_MTD_ONENAND_VERIFY_WRITE @@ -897,14 +1088,12 @@ static int onenand_read_oob(struct mtd_info *mtd, loff_t from, * @param mtd MTD device structure * @param buf the databuffer to verify * @param to offset to read from - * @param len number of bytes to read and compare * */ -static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to, int len) +static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to) { struct onenand_chip *this = mtd->priv; - char *readp = this->page_buf; - int column = to & (mtd->oobsize - 1); + char *readp = this->page_buf + mtd->writesize; int status, i; this->command(mtd, ONENAND_CMD_READOOB, to, mtd->oobsize); @@ -913,9 +1102,8 @@ static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to if (status) return status; - this->read_bufferram(mtd, ONENAND_SPARERAM, readp, column, len); - - for(i = 0; i < len; i++) + this->read_bufferram(mtd, ONENAND_SPARERAM, readp, 0, mtd->oobsize); + for(i = 0; i < mtd->oobsize; i++) if (buf[i] != 0xFF && buf[i] != readp[i]) return -EBADMSG; @@ -923,41 +1111,51 @@ static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to } /** - * onenand_verify_page - [GENERIC] verify the chip contents after a write - * @param mtd MTD device structure - * @param buf the databuffer to verify + * onenand_verify - [GENERIC] verify the chip contents after a write + * @param mtd MTD device structure + * @param buf the databuffer to verify + * @param addr offset to read from + * @param len number of bytes to read and compare * - * Check DataRAM area directly */ -static int onenand_verify_page(struct mtd_info *mtd, u_char *buf, loff_t addr) +static int onenand_verify(struct mtd_info *mtd, const u_char *buf, loff_t addr, size_t len) { struct onenand_chip *this = mtd->priv; - void __iomem *dataram0, *dataram1; + void __iomem *dataram; int ret = 0; + int thislen, column; - /* In partial page write, just skip it */ - if ((addr & (mtd->writesize - 1)) != 0) - return 0; + while (len != 0) { + thislen = min_t(int, mtd->writesize, len); + column = addr & (mtd->writesize - 1); + if (column + thislen > mtd->writesize) + thislen = mtd->writesize - column; - this->command(mtd, ONENAND_CMD_READ, addr, mtd->writesize); + this->command(mtd, ONENAND_CMD_READ, addr, mtd->writesize); - ret = this->wait(mtd, FL_READING); - if (ret) - return ret; + onenand_update_bufferram(mtd, addr, 0); + + ret = this->wait(mtd, FL_READING); + if (ret) + return ret; - onenand_update_bufferram(mtd, addr, 1); + onenand_update_bufferram(mtd, addr, 1); - /* Check, if the two dataram areas are same */ - dataram0 = this->base + ONENAND_DATARAM; - dataram1 = dataram0 + mtd->writesize; + dataram = this->base + ONENAND_DATARAM; + dataram += onenand_bufferram_offset(mtd, ONENAND_DATARAM); - if (memcmp(dataram0, dataram1, mtd->writesize)) - return -EBADMSG; + if (memcmp(buf, dataram + column, thislen)) + return -EBADMSG; + + len -= thislen; + buf += thislen; + addr += thislen; + } return 0; } #else -#define onenand_verify_page(...) (0) +#define onenand_verify(...) (0) #define onenand_verify_oob(...) (0) #endif @@ -988,60 +1186,57 @@ static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len, /* Do not allow writes past end of device */ if (unlikely((to + len) > mtd->size)) { - DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: Attempt write to past end of device\n"); + printk(KERN_ERR "onenand_write: Attempt write to past end of device\n"); return -EINVAL; } /* Reject writes, which are not page aligned */ if (unlikely(NOTALIGNED(to)) || unlikely(NOTALIGNED(len))) { - DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: Attempt to write not page aligned data\n"); + printk(KERN_ERR "onenand_write: Attempt to write not page aligned data\n"); 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 bytes = mtd->writesize; - int thislen = min_t(int, bytes, len - written); + int thislen = min_t(int, mtd->writesize - column, len - written); u_char *wbuf = (u_char *) buf; cond_resched(); - this->command(mtd, ONENAND_CMD_BUFFERRAM, to, bytes); + this->command(mtd, ONENAND_CMD_BUFFERRAM, to, thislen); /* Partial page write */ + subpage = thislen < mtd->writesize; if (subpage) { - bytes = min_t(int, bytes - column, (int) len); memset(this->page_buf, 0xff, mtd->writesize); - memcpy(this->page_buf + column, buf, bytes); + memcpy(this->page_buf + column, buf, thislen); wbuf = this->page_buf; - /* Even though partial write, we need page size */ - thislen = mtd->writesize; } - this->write_bufferram(mtd, ONENAND_DATARAM, wbuf, 0, thislen); + this->write_bufferram(mtd, ONENAND_DATARAM, wbuf, 0, mtd->writesize); this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize); this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize); + ret = this->wait(mtd, FL_WRITING); + /* In partial page write we don't update bufferram */ - onenand_update_bufferram(mtd, to, !subpage); + onenand_update_bufferram(mtd, to, !ret && !subpage); - ret = this->wait(mtd, FL_WRITING); if (ret) { - DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: write filaed %d\n", ret); + printk(KERN_ERR "onenand_write: write filaed %d\n", ret); break; } /* Only check verify write turn on */ - ret = onenand_verify_page(mtd, (u_char *) wbuf, to); + ret = onenand_verify(mtd, (u_char *) wbuf, to, thislen); if (ret) { - DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: verify failed %d\n", ret); + printk(KERN_ERR "onenand_write: verify failed %d\n", ret); break; } @@ -1064,20 +1259,58 @@ static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len, } /** + * onenand_fill_auto_oob - [Internal] oob auto-placement transfer + * @param mtd MTD device structure + * @param oob_buf oob buffer + * @param buf source address + * @param column oob offset to write to + * @param thislen oob length to write + */ +static int onenand_fill_auto_oob(struct mtd_info *mtd, u_char *oob_buf, + const u_char *buf, int column, int thislen) +{ + struct onenand_chip *this = mtd->priv; + struct nand_oobfree *free; + int writecol = column; + int writeend = column + thislen; + int lastgap = 0; + + for (free = this->ecclayout->oobfree; free->length; ++free) { + if (writecol >= lastgap) + writecol += free->offset - lastgap; + if (writeend >= lastgap) + writeend += free->offset - lastgap; + lastgap = free->offset + free->length; + } + for (free = this->ecclayout->oobfree; free->length; ++free) { + int free_end = free->offset + free->length; + if (free->offset < writeend && free_end > writecol) { + int st = max_t(int,free->offset,writecol); + int ed = min_t(int,free_end,writeend); + int n = ed - st; + memcpy(oob_buf + st, buf, n); + buf += n; + } + } + return 0; +} + +/** * onenand_do_write_oob - [Internal] OneNAND write out-of-band * @param mtd MTD device structure * @param to offset to write to * @param len number of bytes to write * @param retlen pointer to variable to store the number of written bytes * @param buf the data to write + * @param mode operation mode * * OneNAND write out-of-band */ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const u_char *buf) + size_t *retlen, const u_char *buf, mtd_oob_mode_t mode) { struct onenand_chip *this = mtd->priv; - int column, ret = 0; + int column, ret = 0, oobsize; int written = 0; DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_oob: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); @@ -1085,9 +1318,30 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len, /* Initialize retlen, in case of early exit */ *retlen = 0; - /* Do not allow writes past end of device */ - if (unlikely((to + len) > mtd->size)) { - DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_oob: Attempt write to past end of device\n"); + if (mode == MTD_OOB_AUTO) + oobsize = this->ecclayout->oobavail; + else + oobsize = mtd->oobsize; + + column = to & (mtd->oobsize - 1); + + if (unlikely(column >= oobsize)) { + printk(KERN_ERR "onenand_write_oob: Attempted to start write outside oob\n"); + return -EINVAL; + } + + /* For compatibility with NAND: Do not allow write past end of page */ + if (column + len > oobsize) { + printk(KERN_ERR "onenand_write_oob: " + "Attempt to write past end of page\n"); + return -EINVAL; + } + + /* Do not allow reads past end of device */ + if (unlikely(to >= mtd->size || + column + len > ((mtd->size >> this->page_shift) - + (to >> this->page_shift)) * oobsize)) { + printk(KERN_ERR "onenand_write_oob: Attempted to write past end of device\n"); return -EINVAL; } @@ -1096,18 +1350,19 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len, /* Loop until all data write */ while (written < len) { - int thislen = min_t(int, mtd->oobsize, len - written); + int thislen = min_t(int, oobsize, len - written); cond_resched(); - column = to & (mtd->oobsize - 1); - this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->oobsize); /* We send data to spare ram with oobsize * to prevent byte access */ memset(this->page_buf, 0xff, mtd->oobsize); - memcpy(this->page_buf + column, buf, thislen); + if (mode == MTD_OOB_AUTO) + onenand_fill_auto_oob(mtd, this->page_buf, buf, column, thislen); + else + memcpy(this->page_buf + column, buf, thislen); this->write_bufferram(mtd, ONENAND_SPARERAM, this->page_buf, 0, mtd->oobsize); this->command(mtd, ONENAND_CMD_PROGOOB, to, mtd->oobsize); @@ -1116,26 +1371,25 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len, ret = this->wait(mtd, FL_WRITING); if (ret) { - DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_oob: write filaed %d\n", ret); - goto out; + printk(KERN_ERR "onenand_write_oob: write failed %d\n", ret); + break; } - ret = onenand_verify_oob(mtd, buf, to, thislen); + ret = onenand_verify_oob(mtd, this->page_buf, to); if (ret) { - DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_oob: verify failed %d\n", ret); - goto out; + printk(KERN_ERR "onenand_write_oob: verify failed %d\n", ret); + break; } written += thislen; - if (written == len) break; - to += thislen; + to += mtd->writesize; buf += thislen; + column = 0; } -out: /* Deselect and wake up anyone waiting on the device */ onenand_release_device(mtd); @@ -1153,10 +1407,17 @@ out: static int onenand_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops) { - BUG_ON(ops->mode != MTD_OOB_PLACE); - + switch (ops->mode) { + case MTD_OOB_PLACE: + case MTD_OOB_AUTO: + break; + case MTD_OOB_RAW: + /* Not implemented yet */ + default: + return -EINVAL; + } return onenand_do_write_oob(mtd, to + ops->ooboffs, ops->ooblen, - &ops->oobretlen, ops->oobbuf); + &ops->oobretlen, ops->oobbuf, ops->mode); } /** @@ -1199,19 +1460,19 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr) /* Start address must align on block boundary */ if (unlikely(instr->addr & (block_size - 1))) { - DEBUG(MTD_DEBUG_LEVEL0, "onenand_erase: Unaligned address\n"); + printk(KERN_ERR "onenand_erase: Unaligned address\n"); return -EINVAL; } /* Length must align on block boundary */ if (unlikely(instr->len & (block_size - 1))) { - DEBUG(MTD_DEBUG_LEVEL0, "onenand_erase: Length not block aligned\n"); + printk(KERN_ERR "onenand_erase: Length not block aligned\n"); return -EINVAL; } /* Do not allow erase past end of device */ if (unlikely((instr->len + instr->addr) > mtd->size)) { - DEBUG(MTD_DEBUG_LEVEL0, "onenand_erase: Erase past end of device\n"); + printk(KERN_ERR "onenand_erase: Erase past end of device\n"); return -EINVAL; } @@ -1238,10 +1499,12 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr) this->command(mtd, ONENAND_CMD_ERASE, addr, block_size); + onenand_invalidate_bufferram(mtd, addr, block_size); + ret = this->wait(mtd, FL_ERASING); /* Check, if it is write protected */ if (ret) { - DEBUG(MTD_DEBUG_LEVEL0, "onenand_erase: Failed erase, block %d\n", (unsigned) (addr >> this->erase_shift)); + printk(KERN_ERR "onenand_erase: Failed erase, block %d\n", (unsigned) (addr >> this->erase_shift)); instr->state = MTD_ERASE_FAILED; instr->fail_addr = addr; goto erase_exit; @@ -1322,7 +1585,7 @@ static int onenand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) /* We write two bytes, so we dont have to mess with 16 bit access */ ofs += mtd->oobsize + (bbm->badblockpos & ~0x01); - return onenand_do_write_oob(mtd, ofs , 2, &retlen, buf); + return onenand_do_write_oob(mtd, ofs , 2, &retlen, buf, MTD_OOB_PLACE); } /** @@ -1491,6 +1754,8 @@ static int onenand_unlock_all(struct mtd_info *mtd) struct onenand_chip *this = mtd->priv; if (this->options & ONENAND_HAS_UNLOCK_ALL) { + /* Set start block address */ + this->write_word(0, this->base + ONENAND_REG_START_BLOCK_ADDRESS); /* Write unlock command */ this->command(mtd, ONENAND_CMD_UNLOCK_ALL, 0, 0); @@ -1503,13 +1768,10 @@ static int onenand_unlock_all(struct mtd_info *mtd) continue; /* Workaround for all block unlock in DDP */ - if (this->device_id & ONENAND_DEVICE_IS_DDP) { - loff_t ofs; - size_t len; - + if (ONENAND_IS_DDP(this)) { /* 1st block on another chip */ - ofs = this->chipsize >> 1; - len = 1 << this->erase_shift; + loff_t ofs = this->chipsize >> 1; + size_t len = mtd->erasesize; onenand_unlock(mtd, ofs, len); } @@ -1617,7 +1879,7 @@ static int do_otp_lock(struct mtd_info *mtd, loff_t from, size_t len, this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0); this->wait(mtd, FL_OTPING); - ret = onenand_do_write_oob(mtd, from, len, retlen, buf); + ret = onenand_do_write_oob(mtd, from, len, retlen, buf, MTD_OOB_PLACE); /* Exit OTP access mode */ this->command(mtd, ONENAND_CMD_RESET, 0, 0); @@ -1823,12 +2085,13 @@ static int onenand_lock_user_prot_reg(struct mtd_info *mtd, loff_t from, #endif /* CONFIG_MTD_ONENAND_OTP */ /** - * onenand_lock_scheme - Check and set OneNAND lock scheme + * onenand_check_features - Check and set OneNAND features * @param mtd MTD data structure * - * Check and set OneNAND lock scheme + * Check and set OneNAND features + * - lock scheme */ -static void onenand_lock_scheme(struct mtd_info *mtd) +static void onenand_check_features(struct mtd_info *mtd) { struct onenand_chip *this = mtd->priv; unsigned int density, process; @@ -1961,26 +2224,28 @@ static int onenand_probe(struct mtd_info *mtd) density = dev_id >> ONENAND_DEVICE_DENSITY_SHIFT; this->chipsize = (16 << density) << 20; /* Set density mask. it is used for DDP */ - this->density_mask = (1 << (density + 6)); + if (ONENAND_IS_DDP(this)) + this->density_mask = (1 << (density + 6)); + else + this->density_mask = 0; /* OneNAND page size & block size */ /* The data buffer size is equal to page size */ mtd->writesize = this->read_word(this->base + ONENAND_REG_DATA_BUFFER_SIZE); mtd->oobsize = mtd->writesize >> 5; - /* Pagers per block is always 64 in OneNAND */ + /* Pages per a block are always 64 in OneNAND */ mtd->erasesize = mtd->writesize << 6; this->erase_shift = ffs(mtd->erasesize) - 1; this->page_shift = ffs(mtd->writesize) - 1; - this->ppb_shift = (this->erase_shift - this->page_shift); - this->page_mask = (mtd->erasesize / mtd->writesize) - 1; + this->page_mask = (1 << (this->erase_shift - this->page_shift)) - 1; /* REVIST: Multichip handling */ mtd->size = this->chipsize; - /* Check OneNAND lock scheme */ - onenand_lock_scheme(mtd); + /* Check OneNAND features */ + onenand_check_features(mtd); return 0; } @@ -2021,6 +2286,7 @@ static void onenand_resume(struct mtd_info *mtd) */ int onenand_scan(struct mtd_info *mtd, int maxchips) { + int i; struct onenand_chip *this = mtd->priv; if (!this->read_word) @@ -2092,12 +2358,21 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) } this->subpagesize = mtd->writesize >> mtd->subpage_sft; + + /* + * The number of bytes available for a client to place data into + * the out of band area + */ + this->ecclayout->oobavail = 0; + for (i = 0; this->ecclayout->oobfree[i].length; i++) + this->ecclayout->oobavail += + this->ecclayout->oobfree[i].length; + mtd->ecclayout = this->ecclayout; /* Fill in remaining MTD driver data */ mtd->type = MTD_NANDFLASH; mtd->flags = MTD_CAP_NANDFLASH; - mtd->ecctype = MTD_ECC_SW; mtd->erase = onenand_erase; mtd->point = NULL; mtd->unpoint = NULL; @@ -2144,8 +2419,11 @@ void onenand_release(struct mtd_info *mtd) del_mtd_device (mtd); /* Free bad block table memory, if allocated */ - if (this->bbm) + if (this->bbm) { + struct bbm_info *bbm = this->bbm; + kfree(bbm->bbt); kfree(this->bbm); + } /* Buffer allocated by onenand_scan */ if (this->options & ONENAND_PAGEBUF_ALLOC) kfree(this->page_buf); diff --git a/drivers/mtd/onenand/onenand_bbt.c b/drivers/mtd/onenand/onenand_bbt.c index 98f8fd1c6375..aecdd50a1781 100644 --- a/drivers/mtd/onenand/onenand_bbt.c +++ b/drivers/mtd/onenand/onenand_bbt.c @@ -17,8 +17,8 @@ #include <linux/mtd/onenand.h> #include <linux/mtd/compatmac.h> -extern int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, u_char *buf); +extern int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from, + struct mtd_oob_ops *ops); /** * check_short_pattern - [GENERIC] check if a pattern is in the buffer @@ -65,10 +65,11 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr int startblock; loff_t from; size_t readlen, ooblen; + struct mtd_oob_ops ops; printk(KERN_INFO "Scanning device for bad blocks\n"); - len = 1; + len = 2; /* We need only read few bytes from the OOB area */ scanlen = ooblen = 0; @@ -82,22 +83,24 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr startblock = 0; from = 0; + ops.mode = MTD_OOB_PLACE; + ops.ooblen = readlen; + ops.oobbuf = buf; + ops.len = ops.ooboffs = ops.retlen = ops.oobretlen = 0; + for (i = startblock; i < numblocks; ) { int ret; for (j = 0; j < len; j++) { - size_t retlen; - /* No need to read pages fully, * just read required OOB bytes */ - ret = onenand_do_read_oob(mtd, from + j * mtd->writesize + bd->offs, - readlen, &retlen, &buf[0]); + ret = onenand_bbt_read_oob(mtd, from + j * mtd->writesize + bd->offs, &ops); /* If it is a initial bad block, just ignore it */ - if (ret && !(ret & ONENAND_CTRL_LOAD)) - return ret; + if (ret == ONENAND_BBT_READ_FATAL_ERROR) + return -EIO; - if (check_short_pattern(&buf[j * scanlen], scanlen, mtd->writesize, bd)) { + if (ret || 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); @@ -168,8 +171,8 @@ static int onenand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt) * marked good / bad blocks and writes the bad block table(s) to * the selected place. * - * The bad block table memory is allocated here. It must be freed - * by calling the onenand_free_bbt function. + * The bad block table memory is allocated here. It is freed + * by the onenand_release function. * */ int onenand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) diff --git a/drivers/mtd/redboot.c b/drivers/mtd/redboot.c index 035cd9b0cc08..a61351f88ec0 100644 --- a/drivers/mtd/redboot.c +++ b/drivers/mtd/redboot.c @@ -94,8 +94,19 @@ static int parse_redboot_partitions(struct mtd_info *master, * (NOTE: this is 'size' not 'data_length'; size is * the full size of the entry.) */ - if (swab32(buf[i].size) == master->erasesize) { + + /* RedBoot can combine the FIS directory and + config partitions into a single eraseblock; + we assume wrong-endian if either the swapped + 'size' matches the eraseblock size precisely, + or if the swapped size actually fits in an + eraseblock while the unswapped size doesn't. */ + if (swab32(buf[i].size) == master->erasesize || + (buf[i].size > master->erasesize + && swab32(buf[i].size) < master->erasesize)) { int j; + /* Update numslots based on actual FIS directory size */ + numslots = swab32(buf[i].size) / sizeof (struct fis_image_desc); for (j = 0; j < numslots; ++j) { /* A single 0xff denotes a deleted entry. @@ -120,11 +131,11 @@ static int parse_redboot_partitions(struct mtd_info *master, swab32s(&buf[j].desc_cksum); swab32s(&buf[j].file_cksum); } + } else if (buf[i].size < master->erasesize) { + /* Update numslots based on actual FIS directory size */ + numslots = buf[i].size / sizeof(struct fis_image_desc); } break; - } else { - /* re-calculate of real numslots */ - numslots = buf[i].size / sizeof(struct fis_image_desc); } } if (i == numslots) { diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 38f41a593b12..d9400ef87195 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -1284,8 +1284,8 @@ config PCNET32 will be called pcnet32. config PCNET32_NAPI - bool "Use RX polling (NAPI) (EXPERIMENTAL)" - depends on PCNET32 && EXPERIMENTAL + bool "Use RX polling (NAPI)" + depends on PCNET32 help NAPI is a new driver API designed to reduce CPU and interrupt load when the driver is receiving lots of packets from the card. It is @@ -2125,14 +2125,16 @@ config SKY2 will be called sky2. This is recommended. config SK98LIN - tristate "Marvell Yukon Chipset / SysKonnect SK-98xx Support" + tristate "Marvell Yukon Chipset / SysKonnect SK-98xx Support (DEPRECATED)" depends on PCI ---help--- Say Y here if you have a Marvell Yukon or SysKonnect SK-98xx/SK-95xx compliant Gigabit Ethernet Adapter. - This driver supports the original Yukon chipset. A cleaner driver is - also available (skge) which seems to work better than this one. + This driver supports the original Yukon chipset. This driver is + deprecated and will be removed from the kernel in the near future, + it has been replaced by the skge driver. skge is cleaner and + seems to work better. This driver does not support the newer Yukon2 chipset. A separate driver, sky2, is provided to support Yukon2-based adapters. @@ -2337,7 +2339,7 @@ config QLA3XXX config ATL1 tristate "Attansic L1 Gigabit Ethernet support (EXPERIMENTAL)" - depends on NET_PCI && PCI && EXPERIMENTAL + depends on PCI && EXPERIMENTAL select CRC32 select MII help diff --git a/drivers/net/arcnet/arc-rawmode.c b/drivers/net/arcnet/arc-rawmode.c index e7555d4e6ff1..6318814a11a8 100644 --- a/drivers/net/arcnet/arc-rawmode.c +++ b/drivers/net/arcnet/arc-rawmode.c @@ -94,7 +94,7 @@ static void rx(struct net_device *dev, int bufnum, BUGMSG(D_DURING, "it's a raw packet (length=%d)\n", length); - if (length >= MinTU) + if (length > MTU) ofs = 512 - length; else ofs = 256 - length; @@ -183,7 +183,7 @@ static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length, length, XMTU); length = XMTU; } - if (length > MinTU) { + if (length >= MinTU) { hard->offset[0] = 0; hard->offset[1] = ofs = 512 - length; } else if (length > MTU) { diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c index 4e91dab1f17f..83004fdab0a4 100644 --- a/drivers/net/arcnet/arcnet.c +++ b/drivers/net/arcnet/arcnet.c @@ -41,7 +41,7 @@ * <jojo@repas.de> */ -#define VERSION "arcnet: v3.93 BETA 2000/04/29 - by Avery Pennarun et al.\n" +#define VERSION "arcnet: v3.94 BETA 2007/02/08 - by Avery Pennarun et al.\n" #include <linux/module.h> #include <linux/types.h> diff --git a/drivers/net/arcnet/com20020-pci.c b/drivers/net/arcnet/com20020-pci.c index 98d326b23c92..b8c0fa6d401d 100644 --- a/drivers/net/arcnet/com20020-pci.c +++ b/drivers/net/arcnet/com20020-pci.c @@ -155,6 +155,7 @@ static struct pci_device_id com20020pci_id_table[] = { { 0x1571, 0xa00b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_IS_5MBIT }, { 0x1571, 0xa00c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_IS_5MBIT }, { 0x1571, 0xa00d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_IS_5MBIT }, + { 0x1571, 0xa00e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_IS_5MBIT }, { 0x1571, 0xa201, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, { 0x1571, 0xa202, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, { 0x1571, 0xa203, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, @@ -163,6 +164,8 @@ static struct pci_device_id com20020pci_id_table[] = { { 0x1571, 0xa206, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, { 0x10B5, 0x9030, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, { 0x10B5, 0x9050, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, + { 0x14BA, 0x6000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, + { 0x10B5, 0x2200, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, {0,} }; diff --git a/drivers/net/arcnet/com20020.c b/drivers/net/arcnet/com20020.c index 4218075c8aa3..7cf0a2511697 100644 --- a/drivers/net/arcnet/com20020.c +++ b/drivers/net/arcnet/com20020.c @@ -104,7 +104,7 @@ int com20020_check(struct net_device *dev) SET_SUBADR(SUB_SETUP1); outb(lp->setup, _XREG); - if (lp->card_flags & ARC_CAN_10MBIT) + if (lp->clockm != 0) { SET_SUBADR(SUB_SETUP2); outb(lp->setup2, _XREG); diff --git a/drivers/net/atl1/atl1_hw.c b/drivers/net/atl1/atl1_hw.c index 08b2d785469d..314dbaabb642 100644 --- a/drivers/net/atl1/atl1_hw.c +++ b/drivers/net/atl1/atl1_hw.c @@ -243,14 +243,8 @@ static int atl1_get_permanent_address(struct atl1_hw *hw) i += 4; } -/* - * The following 2 lines are the Attansic originals. Saving for posterity. - * *(u32 *) & eth_addr[2] = LONGSWAP(addr[0]); - * *(u16 *) & eth_addr[0] = SHORTSWAP(*(u16 *) & addr[1]); - */ - *(u32 *) & eth_addr[2] = swab32(addr[0]); - *(u16 *) & eth_addr[0] = swab16(*(u16 *) & addr[1]); - + *(u32 *) ð_addr[2] = swab32(addr[0]); + *(u16 *) ð_addr[0] = swab16(*(u16 *) &addr[1]); if (is_valid_ether_addr(eth_addr)) { memcpy(hw->perm_mac_addr, eth_addr, ETH_ALEN); return 0; @@ -281,17 +275,28 @@ static int atl1_get_permanent_address(struct atl1_hw *hw) i += 4; } -/* - * The following 2 lines are the Attansic originals. Saving for posterity. - * *(u32 *) & eth_addr[2] = LONGSWAP(addr[0]); - * *(u16 *) & eth_addr[0] = SHORTSWAP(*(u16 *) & addr[1]); - */ - *(u32 *) & eth_addr[2] = swab32(addr[0]); - *(u16 *) & eth_addr[0] = swab16(*(u16 *) & addr[1]); + *(u32 *) ð_addr[2] = swab32(addr[0]); + *(u16 *) ð_addr[0] = swab16(*(u16 *) &addr[1]); if (is_valid_ether_addr(eth_addr)) { memcpy(hw->perm_mac_addr, eth_addr, ETH_ALEN); return 0; } + + /* + * On some motherboards, the MAC address is written by the + * BIOS directly to the MAC register during POST, and is + * not stored in eeprom. If all else thus far has failed + * to fetch the permanent MAC address, try reading it directly. + */ + addr[0] = ioread32(hw->hw_addr + REG_MAC_STA_ADDR); + addr[1] = ioread16(hw->hw_addr + (REG_MAC_STA_ADDR + 4)); + *(u32 *) ð_addr[2] = swab32(addr[0]); + *(u16 *) ð_addr[0] = swab16(*(u16 *) &addr[1]); + if (is_valid_ether_addr(eth_addr)) { + memcpy(hw->perm_mac_addr, eth_addr, ETH_ALEN); + return 0; + } + return 1; } @@ -357,7 +362,7 @@ void atl1_hash_set(struct atl1_hw *hw, u32 hash_value) */ hash_reg = (hash_value >> 31) & 0x1; hash_bit = (hash_value >> 26) & 0x1F; - mta = ioread32((hw + REG_RX_HASH_TABLE) + (hash_reg << 2)); + mta = ioread32((hw->hw_addr + REG_RX_HASH_TABLE) + (hash_reg << 2)); mta |= (1 << hash_bit); iowrite32(mta, (hw->hw_addr + REG_RX_HASH_TABLE) + (hash_reg << 2)); } diff --git a/drivers/net/atl1/atl1_main.c b/drivers/net/atl1/atl1_main.c index 6655640eb4ca..65673485bb6b 100644 --- a/drivers/net/atl1/atl1_main.c +++ b/drivers/net/atl1/atl1_main.c @@ -82,8 +82,7 @@ #include "atl1.h" -#define RUN_REALTIME 0 -#define DRIVER_VERSION "2.0.6" +#define DRIVER_VERSION "2.0.7" char atl1_driver_name[] = "atl1"; static const char atl1_driver_string[] = "Attansic L1 Ethernet Network Driver"; @@ -100,7 +99,7 @@ MODULE_VERSION(DRIVER_VERSION); * atl1_pci_tbl - PCI Device ID Table */ static const struct pci_device_id atl1_pci_tbl[] = { - {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, 0x1048)}, + {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATTANSIC_L1)}, /* required last entry */ {0,} }; diff --git a/drivers/net/b44.c b/drivers/net/b44.c index 5ff7882297d6..aaada572732a 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -59,7 +59,6 @@ #define B44_DEF_TX_RING_PENDING (B44_TX_RING_SIZE - 1) #define B44_TX_RING_BYTES (sizeof(struct dma_desc) * \ B44_TX_RING_SIZE) -#define B44_DMA_MASK 0x3fffffff #define TX_RING_GAP(BP) \ (B44_TX_RING_SIZE - (BP)->tx_pending) @@ -665,7 +664,7 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked) /* Hardware bug work-around, the chip is unable to do PCI DMA to/from anything above 1GB :-( */ if (dma_mapping_error(mapping) || - mapping + RX_PKT_BUF_SZ > B44_DMA_MASK) { + mapping + RX_PKT_BUF_SZ > DMA_30BIT_MASK) { /* Sigh... */ if (!dma_mapping_error(mapping)) pci_unmap_single(bp->pdev, mapping, RX_PKT_BUF_SZ,PCI_DMA_FROMDEVICE); @@ -677,7 +676,7 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked) RX_PKT_BUF_SZ, PCI_DMA_FROMDEVICE); if (dma_mapping_error(mapping) || - mapping + RX_PKT_BUF_SZ > B44_DMA_MASK) { + mapping + RX_PKT_BUF_SZ > DMA_30BIT_MASK) { if (!dma_mapping_error(mapping)) pci_unmap_single(bp->pdev, mapping, RX_PKT_BUF_SZ,PCI_DMA_FROMDEVICE); dev_kfree_skb_any(skb); @@ -988,7 +987,7 @@ static int b44_start_xmit(struct sk_buff *skb, struct net_device *dev) } mapping = pci_map_single(bp->pdev, skb->data, len, PCI_DMA_TODEVICE); - if (dma_mapping_error(mapping) || mapping + len > B44_DMA_MASK) { + if (dma_mapping_error(mapping) || mapping + len > DMA_30BIT_MASK) { /* Chip can't handle DMA to/from >1GB, use bounce buffer */ if (!dma_mapping_error(mapping)) pci_unmap_single(bp->pdev, mapping, len, PCI_DMA_TODEVICE); @@ -1000,7 +999,7 @@ static int b44_start_xmit(struct sk_buff *skb, struct net_device *dev) mapping = pci_map_single(bp->pdev, bounce_skb->data, len, PCI_DMA_TODEVICE); - if (dma_mapping_error(mapping) || mapping + len > B44_DMA_MASK) { + if (dma_mapping_error(mapping) || mapping + len > DMA_30BIT_MASK) { if (!dma_mapping_error(mapping)) pci_unmap_single(bp->pdev, mapping, len, PCI_DMA_TODEVICE); @@ -1227,7 +1226,7 @@ static int b44_alloc_consistent(struct b44 *bp) DMA_BIDIRECTIONAL); if (dma_mapping_error(rx_ring_dma) || - rx_ring_dma + size > B44_DMA_MASK) { + rx_ring_dma + size > DMA_30BIT_MASK) { kfree(rx_ring); goto out_err; } @@ -1254,7 +1253,7 @@ static int b44_alloc_consistent(struct b44 *bp) DMA_TO_DEVICE); if (dma_mapping_error(tx_ring_dma) || - tx_ring_dma + size > B44_DMA_MASK) { + tx_ring_dma + size > DMA_30BIT_MASK) { kfree(tx_ring); goto out_err; } @@ -1289,7 +1288,7 @@ static void b44_chip_reset(struct b44 *bp) if (ssb_is_core_up(bp)) { bw32(bp, B44_RCV_LAZY, 0); bw32(bp, B44_ENET_CTRL, ENET_CTRL_DISABLE); - b44_wait_bit(bp, B44_ENET_CTRL, ENET_CTRL_DISABLE, 100, 1); + b44_wait_bit(bp, B44_ENET_CTRL, ENET_CTRL_DISABLE, 200, 1); bw32(bp, B44_DMATX_CTRL, 0); bp->tx_prod = bp->tx_cons = 0; if (br32(bp, B44_DMARX_STAT) & DMARX_STAT_EMASK) { @@ -2151,13 +2150,13 @@ static int __devinit b44_init_one(struct pci_dev *pdev, pci_set_master(pdev); - err = pci_set_dma_mask(pdev, (u64) B44_DMA_MASK); + err = pci_set_dma_mask(pdev, (u64) DMA_30BIT_MASK); if (err) { dev_err(&pdev->dev, "No usable DMA configuration, aborting.\n"); goto err_out_free_res; } - err = pci_set_consistent_dma_mask(pdev, (u64) B44_DMA_MASK); + err = pci_set_consistent_dma_mask(pdev, (u64) DMA_30BIT_MASK); if (err) { dev_err(&pdev->dev, "No usable DMA configuration, aborting.\n"); goto err_out_free_res; diff --git a/drivers/net/cxgb3/cxgb3_defs.h b/drivers/net/cxgb3/cxgb3_defs.h index 16e004990c59..e14862b43d17 100644 --- a/drivers/net/cxgb3/cxgb3_defs.h +++ b/drivers/net/cxgb3/cxgb3_defs.h @@ -1,6 +1,5 @@ /* * Copyright (c) 2006-2007 Chelsio, Inc. All rights reserved. - * Copyright (c) 2006-2007 Open Grid Computing, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/net/cxgb3/cxgb3_offload.c b/drivers/net/cxgb3/cxgb3_offload.c index c6b726643185..b2cf5f6feb4a 100644 --- a/drivers/net/cxgb3/cxgb3_offload.c +++ b/drivers/net/cxgb3/cxgb3_offload.c @@ -1,6 +1,5 @@ /* * Copyright (c) 2006-2007 Chelsio, Inc. All rights reserved. - * Copyright (c) 2006-2007 Open Grid Computing, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/net/cxgb3/cxgb3_offload.h b/drivers/net/cxgb3/cxgb3_offload.h index 0e6beb69ba17..f15446a32efc 100644 --- a/drivers/net/cxgb3/cxgb3_offload.h +++ b/drivers/net/cxgb3/cxgb3_offload.h @@ -1,6 +1,5 @@ /* * Copyright (c) 2006-2007 Chelsio, Inc. All rights reserved. - * Copyright (c) 2006-2007 Open Grid Computing, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/net/cxgb3/l2t.c b/drivers/net/cxgb3/l2t.c index 3c0cb8557058..d660af74606e 100644 --- a/drivers/net/cxgb3/l2t.c +++ b/drivers/net/cxgb3/l2t.c @@ -1,6 +1,5 @@ /* * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved. - * Copyright (c) 2006-2007 Open Grid Computing, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/net/cxgb3/l2t.h b/drivers/net/cxgb3/l2t.h index ba5d2cbd7241..d79001336cfd 100644 --- a/drivers/net/cxgb3/l2t.h +++ b/drivers/net/cxgb3/l2t.h @@ -1,6 +1,5 @@ /* * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved. - * Copyright (c) 2006-2007 Open Grid Computing, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/net/cxgb3/t3cdev.h b/drivers/net/cxgb3/t3cdev.h index 9af3bcd64b3b..fa4099bc0416 100644 --- a/drivers/net/cxgb3/t3cdev.h +++ b/drivers/net/cxgb3/t3cdev.h @@ -1,6 +1,5 @@ /* * Copyright (C) 2006-2007 Chelsio Communications. All rights reserved. - * Copyright (C) 2006-2007 Open Grid Computing, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h index 689f158a469e..dd4b728ac4b5 100644 --- a/drivers/net/e1000/e1000.h +++ b/drivers/net/e1000/e1000.h @@ -337,7 +337,6 @@ struct e1000_adapter { struct e1000_rx_ring test_rx_ring; - uint32_t *config_space; int msg_enable; #ifdef CONFIG_PCI_MSI boolean_t have_msi; diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index 44ebc72962dc..6777887295f5 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -166,7 +166,7 @@ e1000_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) ecmd->transceiver = XCVR_EXTERNAL; } - if (netif_carrier_ok(adapter->netdev)) { + if (E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU) { e1000_get_speed_and_duplex(hw, &adapter->link_speed, &adapter->link_duplex); diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h index d67105883341..bd000b802ee7 100644 --- a/drivers/net/e1000/e1000_hw.h +++ b/drivers/net/e1000/e1000_hw.h @@ -3253,7 +3253,7 @@ struct e1000_host_command_info { #define IFE_PMC_AUTO_MDIX 0x0080 /* 1=enable MDI/MDI-X feature, default 0=disabled */ #define IFE_PMC_FORCE_MDIX 0x0040 /* 1=force MDIX-X, 0=force MDI */ #define IFE_PMC_MDIX_STATUS 0x0020 /* 1=MDI-X, 0=MDI */ -#define IFE_PMC_AUTO_MDIX_COMPLETE 0x0010 /* Resolution algorthm is completed */ +#define IFE_PMC_AUTO_MDIX_COMPLETE 0x0010 /* Resolution algorithm is completed */ #define IFE_PMC_MDIX_MODE_SHIFT 6 #define IFE_PHC_MDIX_RESET_ALL_MASK 0x0000 /* Disable auto MDI-X */ diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 619c89218b4b..a71023741c3a 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -1417,10 +1417,6 @@ e1000_open(struct net_device *netdev) if ((err = e1000_setup_all_rx_resources(adapter))) goto err_setup_rx; - err = e1000_request_irq(adapter); - if (err) - goto err_req_irq; - e1000_power_up_phy(adapter); if ((err = e1000_up(adapter))) @@ -1431,6 +1427,10 @@ e1000_open(struct net_device *netdev) e1000_update_mng_vlan(adapter); } + err = e1000_request_irq(adapter); + if (err) + goto err_req_irq; + /* If AMT is enabled, let the firmware know that the network * interface is now open */ if (adapter->hw.mac_type == e1000_82573 && @@ -1439,10 +1439,10 @@ e1000_open(struct net_device *netdev) return E1000_SUCCESS; +err_req_irq: + e1000_down(adapter); err_up: e1000_power_down_phy(adapter); - e1000_free_irq(adapter); -err_req_irq: e1000_free_all_rx_resources(adapter); err_setup_rx: e1000_free_all_tx_resources(adapter); @@ -5071,58 +5071,6 @@ e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx) return 0; } -#ifdef CONFIG_PM -/* Save/restore 16 or 64 dwords of PCI config space depending on which - * bus we're on (PCI(X) vs. PCI-E) - */ -#define PCIE_CONFIG_SPACE_LEN 256 -#define PCI_CONFIG_SPACE_LEN 64 -static int -e1000_pci_save_state(struct e1000_adapter *adapter) -{ - struct pci_dev *dev = adapter->pdev; - int size; - int i; - - if (adapter->hw.mac_type >= e1000_82571) - size = PCIE_CONFIG_SPACE_LEN; - else - size = PCI_CONFIG_SPACE_LEN; - - WARN_ON(adapter->config_space != NULL); - - adapter->config_space = kmalloc(size, GFP_KERNEL); - if (!adapter->config_space) { - DPRINTK(PROBE, ERR, "unable to allocate %d bytes\n", size); - return -ENOMEM; - } - for (i = 0; i < (size / 4); i++) - pci_read_config_dword(dev, i * 4, &adapter->config_space[i]); - return 0; -} - -static void -e1000_pci_restore_state(struct e1000_adapter *adapter) -{ - struct pci_dev *dev = adapter->pdev; - int size; - int i; - - if (adapter->config_space == NULL) - return; - - if (adapter->hw.mac_type >= e1000_82571) - size = PCIE_CONFIG_SPACE_LEN; - else - size = PCI_CONFIG_SPACE_LEN; - for (i = 0; i < (size / 4); i++) - pci_write_config_dword(dev, i * 4, adapter->config_space[i]); - kfree(adapter->config_space); - adapter->config_space = NULL; - return; -} -#endif /* CONFIG_PM */ - static int e1000_suspend(struct pci_dev *pdev, pm_message_t state) { @@ -5142,9 +5090,7 @@ e1000_suspend(struct pci_dev *pdev, pm_message_t state) } #ifdef CONFIG_PM - /* Implement our own version of pci_save_state(pdev) because pci- - * express adapters have 256-byte config spaces. */ - retval = e1000_pci_save_state(adapter); + retval = pci_save_state(pdev); if (retval) return retval; #endif @@ -5231,7 +5177,7 @@ e1000_resume(struct pci_dev *pdev) uint32_t err; pci_set_power_state(pdev, PCI_D0); - e1000_pci_restore_state(adapter); + pci_restore_state(pdev); if ((err = pci_enable_device(pdev))) { printk(KERN_ERR "e1000: Cannot enable PCI device from suspend\n"); return err; diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c index 4a50fcb5ad6b..3868b8031266 100644 --- a/drivers/net/eexpress.c +++ b/drivers/net/eexpress.c @@ -714,13 +714,6 @@ static int eexp_xmit(struct sk_buff *buf, struct net_device *dev) * check to make sure we've not become wedged. */ -/* - * Handle an EtherExpress interrupt - * If we've finished initializing, start the RU and CU up. - * If we've already started, reap tx buffers, handle any received packets, - * check to make sure we've not become wedged. - */ - static unsigned short eexp_start_irq(struct net_device *dev, unsigned short status) { diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h index 272e1ec51aa2..42295d61ecd8 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_0045" +#define DRV_VERSION "EHEA_0046" #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 38b2fa424b2d..88ad1c8bcee4 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -76,7 +76,7 @@ void ehea_dump(void *adr, int len, char *msg) { int x; unsigned char *deb = adr; for (x = 0; x < len; x += 16) { - printk(DRV_NAME "%s adr=%p ofs=%04x %016lx %016lx\n", msg, + printk(DRV_NAME " %s adr=%p ofs=%04x %016lx %016lx\n", msg, deb, x, *((u64*)&deb[0]), *((u64*)&deb[8])); deb += 16; } @@ -555,6 +555,7 @@ static irqreturn_t ehea_qp_aff_irq_handler(int irq, void *param) { struct ehea_port *port = param; struct ehea_eqe *eqe; + struct ehea_qp *qp; u32 qp_token; eqe = ehea_poll_eq(port->qp_eq); @@ -563,9 +564,14 @@ static irqreturn_t ehea_qp_aff_irq_handler(int irq, void *param) qp_token = EHEA_BMASK_GET(EHEA_EQE_QP_TOKEN, eqe->entry); ehea_error("QP aff_err: entry=0x%lx, token=0x%x", eqe->entry, qp_token); + + qp = port->port_res[qp_token].qp; + ehea_error_data(port->adapter, qp->fw_handle); eqe = ehea_poll_eq(port->qp_eq); } + queue_work(port->adapter->ehea_wq, &port->reset_task); + return IRQ_HANDLED; } diff --git a/drivers/net/ehea/ehea_phyp.c b/drivers/net/ehea/ehea_phyp.c index 37716e05e808..bc3c00547264 100644 --- a/drivers/net/ehea/ehea_phyp.c +++ b/drivers/net/ehea/ehea_phyp.c @@ -612,3 +612,13 @@ u64 ehea_h_reset_events(const u64 adapter_handle, const u64 neq_handle, event_mask, /* R6 */ 0, 0, 0, 0); /* R7-R12 */ } + +u64 ehea_h_error_data(const u64 adapter_handle, const u64 ressource_handle, + void *rblock) +{ + return ehea_plpar_hcall_norets(H_ERROR_DATA, + adapter_handle, /* R4 */ + ressource_handle, /* R5 */ + virt_to_abs(rblock), /* R6 */ + 0, 0, 0, 0); /* R7-R12 */ +} diff --git a/drivers/net/ehea/ehea_phyp.h b/drivers/net/ehea/ehea_phyp.h index 919f94b75933..90acddb068a1 100644 --- a/drivers/net/ehea/ehea_phyp.h +++ b/drivers/net/ehea/ehea_phyp.h @@ -454,4 +454,7 @@ u64 ehea_h_reg_dereg_bcmc(const u64 adapter_handle, const u16 port_num, u64 ehea_h_reset_events(const u64 adapter_handle, const u64 neq_handle, const u64 event_mask); +u64 ehea_h_error_data(const u64 adapter_handle, const u64 ressource_handle, + void *rblock); + #endif /* __EHEA_PHYP_H__ */ diff --git a/drivers/net/ehea/ehea_qmr.c b/drivers/net/ehea/ehea_qmr.c index f143e13b229d..96ff3b679996 100644 --- a/drivers/net/ehea/ehea_qmr.c +++ b/drivers/net/ehea/ehea_qmr.c @@ -486,6 +486,7 @@ int ehea_destroy_qp(struct ehea_qp *qp) if (!qp) return 0; + ehea_h_disable_and_get_hea(qp->adapter->handle, qp->fw_handle); hret = ehea_h_free_resource(qp->adapter->handle, qp->fw_handle); if (hret != H_SUCCESS) { ehea_error("destroy_qp failed"); @@ -581,4 +582,45 @@ out: return ret; } +void print_error_data(u64 *data) +{ + int length; + u64 type = EHEA_BMASK_GET(ERROR_DATA_TYPE, data[2]); + u64 resource = data[1]; + + length = EHEA_BMASK_GET(ERROR_DATA_LENGTH, data[0]); + + if (length > EHEA_PAGESIZE) + length = EHEA_PAGESIZE; + + if (type == 0x8) /* Queue Pair */ + ehea_error("QP (resource=%lX) state: AER=0x%lX, AERR=0x%lX, " + "port=%lX", resource, data[6], data[12], data[22]); + + ehea_dump(data, length, "error data"); +} + +void ehea_error_data(struct ehea_adapter *adapter, u64 res_handle) +{ + unsigned long ret; + u64 *rblock; + + rblock = kzalloc(PAGE_SIZE, GFP_KERNEL); + if (!rblock) { + ehea_error("Cannot allocate rblock memory."); + return; + } + ret = ehea_h_error_data(adapter->handle, + res_handle, + rblock); + + if (ret == H_R_STATE) + ehea_error("No error data is available: %lX.", res_handle); + else if (ret == H_SUCCESS) + print_error_data(rblock); + else + ehea_error("Error data could not be fetched: %lX", res_handle); + + kfree(rblock); +} diff --git a/drivers/net/ehea/ehea_qmr.h b/drivers/net/ehea/ehea_qmr.h index 7efdc96919ca..1ff60983504d 100644 --- a/drivers/net/ehea/ehea_qmr.h +++ b/drivers/net/ehea/ehea_qmr.h @@ -180,6 +180,9 @@ struct ehea_eqe { u64 entry; }; +#define ERROR_DATA_LENGTH EHEA_BMASK_IBM(52,63) +#define ERROR_DATA_TYPE EHEA_BMASK_IBM(0,7) + static inline void *hw_qeit_calc(struct hw_queue *queue, u64 q_offset) { struct ehea_page *current_page; @@ -355,4 +358,6 @@ int ehea_destroy_qp(struct ehea_qp *qp); int ehea_reg_mr_adapter(struct ehea_adapter *adapter); +void ehea_error_data(struct ehea_adapter *adapter, u64 res_handle); + #endif /* __EHEA_QMR_H__ */ diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 1be4a84dce0e..1f83988a6a64 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -10,6 +10,7 @@ * Maintainer: Kumar Gala * * Copyright (c) 2002-2006 Freescale Semiconductor, Inc. + * Copyright (c) 2007 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 @@ -1612,71 +1613,17 @@ static irqreturn_t gfar_interrupt(int irq, void *dev_id) /* Save ievent for future reference */ u32 events = gfar_read(&priv->regs->ievent); - /* Clear IEVENT */ - gfar_write(&priv->regs->ievent, events); - /* Check for reception */ - if ((events & IEVENT_RXF0) || (events & IEVENT_RXB0)) + if (events & IEVENT_RX_MASK) gfar_receive(irq, dev_id); /* Check for transmit completion */ - if ((events & IEVENT_TXF) || (events & IEVENT_TXB)) + if (events & IEVENT_TX_MASK) gfar_transmit(irq, dev_id); - /* Update error statistics */ - if (events & IEVENT_TXE) { - priv->stats.tx_errors++; - - if (events & IEVENT_LC) - priv->stats.tx_window_errors++; - if (events & IEVENT_CRL) - priv->stats.tx_aborted_errors++; - if (events & IEVENT_XFUN) { - if (netif_msg_tx_err(priv)) - printk(KERN_WARNING "%s: tx underrun. dropped packet\n", dev->name); - priv->stats.tx_dropped++; - priv->extra_stats.tx_underrun++; - - /* Reactivate the Tx Queues */ - gfar_write(&priv->regs->tstat, TSTAT_CLEAR_THALT); - } - } - if (events & IEVENT_BSY) { - priv->stats.rx_errors++; - priv->extra_stats.rx_bsy++; - - gfar_receive(irq, dev_id); - -#ifndef CONFIG_GFAR_NAPI - /* Clear the halt bit in RSTAT */ - gfar_write(&priv->regs->rstat, RSTAT_CLEAR_RHALT); -#endif - - if (netif_msg_rx_err(priv)) - printk(KERN_DEBUG "%s: busy error (rhalt: %x)\n", - dev->name, - gfar_read(&priv->regs->rstat)); - } - if (events & IEVENT_BABR) { - priv->stats.rx_errors++; - priv->extra_stats.rx_babr++; - - if (netif_msg_rx_err(priv)) - printk(KERN_DEBUG "%s: babbling error\n", dev->name); - } - if (events & IEVENT_EBERR) { - priv->extra_stats.eberr++; - if (netif_msg_rx_err(priv)) - printk(KERN_DEBUG "%s: EBERR\n", dev->name); - } - if ((events & IEVENT_RXC) && (netif_msg_rx_err(priv))) - printk(KERN_DEBUG "%s: control frame\n", dev->name); - - if (events & IEVENT_BABT) { - priv->extra_stats.tx_babt++; - if (netif_msg_rx_err(priv)) - printk(KERN_DEBUG "%s: babt error\n", dev->name); - } + /* Check for errors */ + if (events & IEVENT_ERR_MASK) + gfar_error(irq, dev_id); return IRQ_HANDLED; } @@ -1938,7 +1885,7 @@ static irqreturn_t gfar_error(int irq, void *dev_id) /* Hmm... */ if (netif_msg_rx_err(priv) || netif_msg_tx_err(priv)) printk(KERN_DEBUG "%s: error interrupt (ievent=0x%08x imask=0x%08x)\n", - dev->name, events, gfar_read(&priv->regs->imask)); + dev->name, events, gfar_read(&priv->regs->imask)); /* Update the error counters */ if (events & IEVENT_TXE) { @@ -1950,8 +1897,8 @@ static irqreturn_t gfar_error(int irq, void *dev_id) priv->stats.tx_aborted_errors++; if (events & IEVENT_XFUN) { if (netif_msg_tx_err(priv)) - printk(KERN_DEBUG "%s: underrun. packet dropped.\n", - dev->name); + printk(KERN_DEBUG "%s: TX FIFO underrun, " + "packet dropped.\n", dev->name); priv->stats.tx_dropped++; priv->extra_stats.tx_underrun++; @@ -1973,30 +1920,28 @@ static irqreturn_t gfar_error(int irq, void *dev_id) #endif if (netif_msg_rx_err(priv)) - printk(KERN_DEBUG "%s: busy error (rhalt: %x)\n", - dev->name, - gfar_read(&priv->regs->rstat)); + printk(KERN_DEBUG "%s: busy error (rstat: %x)\n", + dev->name, gfar_read(&priv->regs->rstat)); } if (events & IEVENT_BABR) { priv->stats.rx_errors++; priv->extra_stats.rx_babr++; if (netif_msg_rx_err(priv)) - printk(KERN_DEBUG "%s: babbling error\n", dev->name); + printk(KERN_DEBUG "%s: babbling RX error\n", dev->name); } if (events & IEVENT_EBERR) { priv->extra_stats.eberr++; if (netif_msg_rx_err(priv)) - printk(KERN_DEBUG "%s: EBERR\n", dev->name); + printk(KERN_DEBUG "%s: bus error\n", dev->name); } if ((events & IEVENT_RXC) && netif_msg_rx_status(priv)) - if (netif_msg_rx_status(priv)) - printk(KERN_DEBUG "%s: control frame\n", dev->name); + printk(KERN_DEBUG "%s: control frame\n", dev->name); if (events & IEVENT_BABT) { priv->extra_stats.tx_babt++; if (netif_msg_tx_err(priv)) - printk(KERN_DEBUG "%s: babt error\n", dev->name); + printk(KERN_DEBUG "%s: babbling TX error\n", dev->name); } return IRQ_HANDLED; } diff --git a/drivers/net/gianfar_sysfs.c b/drivers/net/gianfar_sysfs.c index 45ffb5d0ca33..aec9ab17a9a5 100644 --- a/drivers/net/gianfar_sysfs.c +++ b/drivers/net/gianfar_sysfs.c @@ -38,13 +38,15 @@ #include "gianfar.h" #define GFAR_ATTR(_name) \ -static ssize_t gfar_show_##_name(struct class_device *cdev, char *buf); \ -static ssize_t gfar_set_##_name(struct class_device *cdev, \ +static ssize_t gfar_show_##_name(struct device *dev, \ + struct device_attribute *attr, char *buf); \ +static ssize_t gfar_set_##_name(struct device *dev, \ + struct device_attribute *attr, \ const char *buf, size_t count); \ -static CLASS_DEVICE_ATTR(_name, 0644, gfar_show_##_name, gfar_set_##_name) +static DEVICE_ATTR(_name, 0644, gfar_show_##_name, gfar_set_##_name) #define GFAR_CREATE_FILE(_dev, _name) \ - class_device_create_file(&_dev->class_dev, &class_device_attr_##_name) + device_create_file(&_dev->dev, &dev_attr_##_name) GFAR_ATTR(bd_stash); GFAR_ATTR(rx_stash_size); @@ -53,29 +55,28 @@ GFAR_ATTR(fifo_threshold); GFAR_ATTR(fifo_starve); GFAR_ATTR(fifo_starve_off); -#define to_net_dev(cd) container_of(cd, struct net_device, class_dev) - -static ssize_t gfar_show_bd_stash(struct class_device *cdev, char *buf) +static ssize_t gfar_show_bd_stash(struct device *dev, + struct device_attribute *attr, char *buf) { - struct net_device *dev = to_net_dev(cdev); - struct gfar_private *priv = netdev_priv(dev); + struct gfar_private *priv = netdev_priv(to_net_dev(dev)); - return sprintf(buf, "%s\n", priv->bd_stash_en? "on" : "off"); + return sprintf(buf, "%s\n", priv->bd_stash_en ? "on" : "off"); } -static ssize_t gfar_set_bd_stash(struct class_device *cdev, - const char *buf, size_t count) +static ssize_t gfar_set_bd_stash(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { - struct net_device *dev = to_net_dev(cdev); - struct gfar_private *priv = netdev_priv(dev); + struct gfar_private *priv = netdev_priv(to_net_dev(dev)); int new_setting = 0; u32 temp; unsigned long flags; /* Find out the new setting */ - if (!strncmp("on", buf, count-1) || !strncmp("1", buf, count-1)) + if (!strncmp("on", buf, count - 1) || !strncmp("1", buf, count - 1)) new_setting = 1; - else if (!strncmp("off", buf, count-1) || !strncmp("0", buf, count-1)) + else if (!strncmp("off", buf, count - 1) + || !strncmp("0", buf, count - 1)) new_setting = 0; else return count; @@ -99,19 +100,19 @@ static ssize_t gfar_set_bd_stash(struct class_device *cdev, return count; } -static ssize_t gfar_show_rx_stash_size(struct class_device *cdev, char *buf) +static ssize_t gfar_show_rx_stash_size(struct device *dev, + struct device_attribute *attr, char *buf) { - struct net_device *dev = to_net_dev(cdev); - struct gfar_private *priv = netdev_priv(dev); + struct gfar_private *priv = netdev_priv(to_net_dev(dev)); return sprintf(buf, "%d\n", priv->rx_stash_size); } -static ssize_t gfar_set_rx_stash_size(struct class_device *cdev, - const char *buf, size_t count) +static ssize_t gfar_set_rx_stash_size(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { - struct net_device *dev = to_net_dev(cdev); - struct gfar_private *priv = netdev_priv(dev); + struct gfar_private *priv = netdev_priv(to_net_dev(dev)); unsigned int length = simple_strtoul(buf, NULL, 0); u32 temp; unsigned long flags; @@ -145,21 +146,21 @@ static ssize_t gfar_set_rx_stash_size(struct class_device *cdev, return count; } - /* Stashing will only be enabled when rx_stash_size != 0 */ -static ssize_t gfar_show_rx_stash_index(struct class_device *cdev, char *buf) +static ssize_t gfar_show_rx_stash_index(struct device *dev, + struct device_attribute *attr, + char *buf) { - struct net_device *dev = to_net_dev(cdev); - struct gfar_private *priv = netdev_priv(dev); + struct gfar_private *priv = netdev_priv(to_net_dev(dev)); return sprintf(buf, "%d\n", priv->rx_stash_index); } -static ssize_t gfar_set_rx_stash_index(struct class_device *cdev, - const char *buf, size_t count) +static ssize_t gfar_set_rx_stash_index(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { - struct net_device *dev = to_net_dev(cdev); - struct gfar_private *priv = netdev_priv(dev); + struct gfar_private *priv = netdev_priv(to_net_dev(dev)); unsigned short index = simple_strtoul(buf, NULL, 0); u32 temp; unsigned long flags; @@ -183,19 +184,20 @@ static ssize_t gfar_set_rx_stash_index(struct class_device *cdev, return count; } -static ssize_t gfar_show_fifo_threshold(struct class_device *cdev, char *buf) +static ssize_t gfar_show_fifo_threshold(struct device *dev, + struct device_attribute *attr, + char *buf) { - struct net_device *dev = to_net_dev(cdev); - struct gfar_private *priv = netdev_priv(dev); + struct gfar_private *priv = netdev_priv(to_net_dev(dev)); return sprintf(buf, "%d\n", priv->fifo_threshold); } -static ssize_t gfar_set_fifo_threshold(struct class_device *cdev, - const char *buf, size_t count) +static ssize_t gfar_set_fifo_threshold(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { - struct net_device *dev = to_net_dev(cdev); - struct gfar_private *priv = netdev_priv(dev); + struct gfar_private *priv = netdev_priv(to_net_dev(dev)); unsigned int length = simple_strtoul(buf, NULL, 0); u32 temp; unsigned long flags; @@ -217,20 +219,19 @@ static ssize_t gfar_set_fifo_threshold(struct class_device *cdev, return count; } -static ssize_t gfar_show_fifo_starve(struct class_device *cdev, char *buf) +static ssize_t gfar_show_fifo_starve(struct device *dev, + struct device_attribute *attr, char *buf) { - struct net_device *dev = to_net_dev(cdev); - struct gfar_private *priv = netdev_priv(dev); + struct gfar_private *priv = netdev_priv(to_net_dev(dev)); return sprintf(buf, "%d\n", priv->fifo_starve); } - -static ssize_t gfar_set_fifo_starve(struct class_device *cdev, - const char *buf, size_t count) +static ssize_t gfar_set_fifo_starve(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { - struct net_device *dev = to_net_dev(cdev); - struct gfar_private *priv = netdev_priv(dev); + struct gfar_private *priv = netdev_priv(to_net_dev(dev)); unsigned int num = simple_strtoul(buf, NULL, 0); u32 temp; unsigned long flags; @@ -252,19 +253,20 @@ static ssize_t gfar_set_fifo_starve(struct class_device *cdev, return count; } -static ssize_t gfar_show_fifo_starve_off(struct class_device *cdev, char *buf) +static ssize_t gfar_show_fifo_starve_off(struct device *dev, + struct device_attribute *attr, + char *buf) { - struct net_device *dev = to_net_dev(cdev); - struct gfar_private *priv = netdev_priv(dev); + struct gfar_private *priv = netdev_priv(to_net_dev(dev)); return sprintf(buf, "%d\n", priv->fifo_starve_off); } -static ssize_t gfar_set_fifo_starve_off(struct class_device *cdev, - const char *buf, size_t count) +static ssize_t gfar_set_fifo_starve_off(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { - struct net_device *dev = to_net_dev(cdev); - struct gfar_private *priv = netdev_priv(dev); + struct gfar_private *priv = netdev_priv(to_net_dev(dev)); unsigned int num = simple_strtoul(buf, NULL, 0); u32 temp; unsigned long flags; diff --git a/drivers/net/hamradio/Kconfig b/drivers/net/hamradio/Kconfig index feb0ada7a025..6e90619b3b41 100644 --- a/drivers/net/hamradio/Kconfig +++ b/drivers/net/hamradio/Kconfig @@ -138,7 +138,7 @@ config BAYCOM_SER_HDX ---help--- This is one of two drivers for Baycom style simple amateur radio modems that connect to a serial interface. The driver supports the - ser12 design in full-duplex mode. This is the old driver. It is + ser12 design in half-duplex mode. This is the old driver. It is still provided in case your serial interface chip does not work with the full-duplex driver. This driver is depreciated. To configure the driver, use the sethdlc utility available in the standard ax25 @@ -190,3 +190,4 @@ config YAM To compile this driver as a module, choose M here: the module will be called yam. + diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c index f0d30cf67b5f..4ad780719a84 100644 --- a/drivers/net/ioc3-eth.c +++ b/drivers/net/ioc3-eth.c @@ -836,13 +836,17 @@ static int ioc3_mii_init(struct ioc3_private *ip) } ip->mii.phy_id = i; + +out: + return res; +} + +static void ioc3_mii_start(struct ioc3_private *ip) +{ ip->ioc3_timer.expires = jiffies + (12 * HZ)/10; /* 1.2 sec. */ ip->ioc3_timer.data = (unsigned long) ip; ip->ioc3_timer.function = &ioc3_timer; add_timer(&ip->ioc3_timer); - -out: - return res; } static inline void ioc3_clean_rx_ring(struct ioc3_private *ip) @@ -1071,6 +1075,7 @@ static int ioc3_open(struct net_device *dev) ip->ehar_h = 0; ip->ehar_l = 0; ioc3_init(dev); + ioc3_mii_start(ip); netif_start_queue(dev); return 0; @@ -1274,6 +1279,7 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto out_stop; } + ioc3_mii_start(ip); ioc3_ssram_disc(ip); ioc3_get_eaddr(ip); @@ -1314,6 +1320,7 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *ent) out_stop: ioc3_stop(ip); + del_timer_sync(&ip->ioc3_timer); ioc3_free_rings(ip); out_res: pci_release_regions(pdev); @@ -1335,6 +1342,8 @@ static void __devexit ioc3_remove_one (struct pci_dev *pdev) struct ioc3 *ioc3 = ip->regs; unregister_netdev(dev); + del_timer_sync(&ip->ioc3_timer); + iounmap(ioc3); pci_release_regions(pdev); free_netdev(dev); @@ -1492,6 +1501,7 @@ static void ioc3_timeout(struct net_device *dev) ioc3_stop(ip); ioc3_init(dev); ioc3_mii_init(ip); + ioc3_mii_start(ip); spin_unlock_irq(&ip->ioc3_lock); diff --git a/drivers/net/macb.c b/drivers/net/macb.c index a41418b3c518..2e9571bf0736 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -881,27 +881,15 @@ static struct net_device_stats *macb_get_stats(struct net_device *dev) static int macb_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct macb *bp = netdev_priv(dev); - int ret; - unsigned long flags; - - spin_lock_irqsave(&bp->lock, flags); - ret = mii_ethtool_gset(&bp->mii, cmd); - spin_unlock_irqrestore(&bp->lock, flags); - return ret; + return mii_ethtool_gset(&bp->mii, cmd); } static int macb_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct macb *bp = netdev_priv(dev); - int ret; - unsigned long flags; - - spin_lock_irqsave(&bp->lock, flags); - ret = mii_ethtool_sset(&bp->mii, cmd); - spin_unlock_irqrestore(&bp->lock, flags); - return ret; + return mii_ethtool_sset(&bp->mii, cmd); } static void macb_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) @@ -930,17 +918,11 @@ static struct ethtool_ops macb_ethtool_ops = { static int macb_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct macb *bp = netdev_priv(dev); - int ret; - unsigned long flags; if (!netif_running(dev)) return -EINVAL; - spin_lock_irqsave(&bp->lock, flags); - ret = generic_mii_ioctl(&bp->mii, if_mii(rq), cmd, NULL); - spin_unlock_irqrestore(&bp->lock, flags); - - return ret; + return generic_mii_ioctl(&bp->mii, if_mii(rq), cmd, NULL); } static ssize_t macb_mii_show(const struct device *_dev, char *buf, diff --git a/drivers/net/meth.c b/drivers/net/meth.c index d38b7c723620..7e69ca6edd91 100644 --- a/drivers/net/meth.c +++ b/drivers/net/meth.c @@ -170,7 +170,7 @@ static int mdio_probe(struct meth_private *priv) static void meth_check_link(struct net_device *dev) { - struct meth_private *priv = (struct meth_private *) dev->priv; + struct meth_private *priv = netdev_priv(dev); unsigned long mii_advertising = mdio_read(priv, 4); unsigned long mii_partner = mdio_read(priv, 5); unsigned long negotiated = mii_advertising & mii_partner; @@ -268,7 +268,7 @@ static void meth_free_rx_ring(struct meth_private *priv) int meth_reset(struct net_device *dev) { - struct meth_private *priv = (struct meth_private *) dev->priv; + struct meth_private *priv = netdev_priv(dev); /* Reset card */ mace->eth.mac_ctrl = SGI_MAC_RESET; @@ -310,7 +310,7 @@ int meth_reset(struct net_device *dev) */ static int meth_open(struct net_device *dev) { - struct meth_private *priv = dev->priv; + struct meth_private *priv = netdev_priv(dev); int ret; priv->phy_addr = -1; /* No PHY is known yet... */ @@ -354,7 +354,7 @@ out_free_tx_ring: static int meth_release(struct net_device *dev) { - struct meth_private *priv = dev->priv; + struct meth_private *priv = netdev_priv(dev); DPRINTK("Stopping queue\n"); netif_stop_queue(dev); /* can't transmit any more */ @@ -376,7 +376,7 @@ static void meth_rx(struct net_device* dev, unsigned long int_status) { struct sk_buff *skb; unsigned long status; - struct meth_private *priv = (struct meth_private *) dev->priv; + struct meth_private *priv = netdev_priv(dev); unsigned long fifo_rptr = (int_status & METH_INT_RX_RPTR_MASK) >> 8; spin_lock(&priv->meth_lock); @@ -466,14 +466,14 @@ static void meth_rx(struct net_device* dev, unsigned long int_status) static int meth_tx_full(struct net_device *dev) { - struct meth_private *priv = (struct meth_private *) dev->priv; + struct meth_private *priv = netdev_priv(dev); return (priv->tx_count >= TX_RING_ENTRIES - 1); } static void meth_tx_cleanup(struct net_device* dev, unsigned long int_status) { - struct meth_private *priv = dev->priv; + struct meth_private *priv = netdev_priv(dev); unsigned long status; struct sk_buff *skb; unsigned long rptr = (int_status&TX_INFO_RPTR) >> 16; @@ -536,7 +536,7 @@ static void meth_tx_cleanup(struct net_device* dev, unsigned long int_status) static void meth_error(struct net_device* dev, unsigned status) { - struct meth_private *priv = (struct meth_private *) dev->priv; + struct meth_private *priv = netdev_priv(dev); printk(KERN_WARNING "meth: error status: 0x%08x\n",status); /* check for errors too... */ @@ -570,7 +570,7 @@ static void meth_error(struct net_device* dev, unsigned status) static irqreturn_t meth_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *)dev_id; - struct meth_private *priv = (struct meth_private *) dev->priv; + struct meth_private *priv = netdev_priv(dev); unsigned long status; status = mace->eth.int_stat; @@ -695,7 +695,7 @@ static void meth_add_to_tx_ring(struct meth_private *priv, struct sk_buff *skb) */ static int meth_tx(struct sk_buff *skb, struct net_device *dev) { - struct meth_private *priv = (struct meth_private *) dev->priv; + struct meth_private *priv = netdev_priv(dev); unsigned long flags; spin_lock_irqsave(&priv->meth_lock, flags); @@ -726,7 +726,7 @@ static int meth_tx(struct sk_buff *skb, struct net_device *dev) */ static void meth_tx_timeout(struct net_device *dev) { - struct meth_private *priv = (struct meth_private *) dev->priv; + struct meth_private *priv = netdev_priv(dev); unsigned long flags; printk(KERN_WARNING "%s: transmit timed out\n", dev->name); @@ -778,7 +778,7 @@ static int meth_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) */ static struct net_device_stats *meth_stats(struct net_device *dev) { - struct meth_private *priv = (struct meth_private *) dev->priv; + struct meth_private *priv = netdev_priv(dev); return &priv->stats; } @@ -807,7 +807,7 @@ static struct net_device *meth_init(void) dev->irq = MACE_ETHERNET_IRQ; dev->base_addr = (unsigned long)&mace->eth; - priv = (struct meth_private *) dev->priv; + priv = netdev_priv(dev); spin_lock_init(&priv->meth_lock); ret = register_netdev(dev); diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index 3f3896e98879..2807ef400fb5 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -252,7 +252,7 @@ typedef u32 netxen_ctx_msg; #define netxen_set_msg_ctxid(config_word, val) \ ((config_word) &= ~(0x3ff<<18), (config_word) |= (val & 0x3ff) << 18) #define netxen_set_msg_opcode(config_word, val) \ - ((config_word) &= ~(0xf<<24), (config_word) |= (val & 0xf) << 24) + ((config_word) &= ~(0xf<<28), (config_word) |= (val & 0xf) << 28) struct netxen_rcv_context { __le64 rcv_ring_addr; @@ -303,14 +303,14 @@ struct netxen_ring_ctx { (cmd_desc)->flags_opcode |= cpu_to_le16((val) & 0x7f)) #define netxen_set_cmd_desc_opcode(cmd_desc, val) \ ((cmd_desc)->flags_opcode &= ~cpu_to_le16(0x3f<<7), \ - (cmd_desc)->flags_opcode |= cpu_to_le16((val) & (0x3f<<7))) + (cmd_desc)->flags_opcode |= cpu_to_le16(((val & 0x3f)<<7))) #define netxen_set_cmd_desc_num_of_buff(cmd_desc, 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) \ - ((cmd_desc)->num_of_buffers_total_length &= cpu_to_le32(0xff), \ - (cmd_desc)->num_of_buffers_total_length |= cpu_to_le32(val << 24)) + ((cmd_desc)->num_of_buffers_total_length &= ~cpu_to_le32(0xffffff00), \ + (cmd_desc)->num_of_buffers_total_length |= cpu_to_le32(val << 8)) #define netxen_get_cmd_desc_opcode(cmd_desc) \ ((le16_to_cpu((cmd_desc)->flags_opcode) >> 7) & 0x003F) @@ -1040,6 +1040,7 @@ int netxen_flash_unlock(struct netxen_adapter *adapter); int netxen_backup_crbinit(struct netxen_adapter *adapter); int netxen_flash_erase_secondary(struct netxen_adapter *adapter); int netxen_flash_erase_primary(struct netxen_adapter *adapter); +void netxen_halt_pegs(struct netxen_adapter *adapter); int netxen_rom_fast_write(struct netxen_adapter *adapter, int addr, int data); int netxen_rom_se(struct netxen_adapter *adapter, int addr); diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c index cc0efe213e01..6252e9a87278 100644 --- a/drivers/net/netxen/netxen_nic_ethtool.c +++ b/drivers/net/netxen/netxen_nic_ethtool.c @@ -402,7 +402,7 @@ netxen_nic_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) wol->wolopts = 0; } -static u32 netxen_nic_get_link(struct net_device *dev) +static u32 netxen_nic_test_link(struct net_device *dev) { struct netxen_port *port = netdev_priv(dev); struct netxen_adapter *adapter = port->adapter; @@ -459,6 +459,7 @@ netxen_nic_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, int ret; if (flash_start == 0) { + netxen_halt_pegs(adapter); ret = netxen_flash_unlock(adapter); if (ret < 0) { printk(KERN_ERR "%s: Flash unlock failed.\n", @@ -712,7 +713,7 @@ netxen_nic_diag_test(struct net_device *dev, struct ethtool_test *eth_test, { if (eth_test->flags == ETH_TEST_FL_OFFLINE) { /* offline tests */ /* link test */ - if (!(data[4] = (u64) netxen_nic_get_link(dev))) + if (!(data[4] = (u64) netxen_nic_test_link(dev))) eth_test->flags |= ETH_TEST_FL_FAILED; if (netif_running(dev)) @@ -727,7 +728,7 @@ netxen_nic_diag_test(struct net_device *dev, struct ethtool_test *eth_test, dev->open(dev); } else { /* online tests */ /* link test */ - if (!(data[4] = (u64) netxen_nic_get_link(dev))) + if (!(data[4] = (u64) netxen_nic_test_link(dev))) eth_test->flags |= ETH_TEST_FL_FAILED; /* other tests pass by default */ @@ -783,7 +784,7 @@ struct ethtool_ops netxen_nic_ethtool_ops = { .get_regs_len = netxen_nic_get_regs_len, .get_regs = netxen_nic_get_regs, .get_wol = netxen_nic_get_wol, - .get_link = netxen_nic_get_link, + .get_link = ethtool_op_get_link, .get_eeprom_len = netxen_nic_get_eeprom_len, .get_eeprom = netxen_nic_get_eeprom, .set_eeprom = netxen_nic_set_eeprom, diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index f263232f499f..7195af3e8f3d 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -420,6 +420,7 @@ static int netxen_get_flash_block(struct netxen_adapter *adapter, int base, for (i = 0; i < size / sizeof(u32); i++) { if (netxen_rom_fast_read(adapter, addr, ptr32) == -1) return -1; + *ptr32 = cpu_to_le32(*ptr32); ptr32++; addr += sizeof(u32); } @@ -428,6 +429,7 @@ static int netxen_get_flash_block(struct netxen_adapter *adapter, int base, if (netxen_rom_fast_read(adapter, addr, &local) == -1) return -1; + local = cpu_to_le32(local); memcpy(ptr32, &local, (char *)buf + size - (char *)ptr32); } diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index f7bb8c90537c..2f324366784d 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -717,6 +717,14 @@ netxen_flash_erase_primary(struct netxen_adapter *adapter) return ret; } +void netxen_halt_pegs(struct netxen_adapter *adapter) +{ + netxen_crb_writelit_adapter(adapter, NETXEN_CRB_PEG_NET_0 + 0x3c, 1); + netxen_crb_writelit_adapter(adapter, NETXEN_CRB_PEG_NET_1 + 0x3c, 1); + netxen_crb_writelit_adapter(adapter, NETXEN_CRB_PEG_NET_2 + 0x3c, 1); + netxen_crb_writelit_adapter(adapter, NETXEN_CRB_PEG_NET_3 + 0x3c, 1); +} + int netxen_flash_unlock(struct netxen_adapter *adapter) { int ret = 0; @@ -1246,7 +1254,7 @@ int netxen_process_cmd_ring(unsigned long data) * the netdev which is associated with that device. */ - consumer = *(adapter->cmd_consumer); + consumer = le32_to_cpu(*(adapter->cmd_consumer)); if (last_consumer == consumer) { /* Ring is empty */ DPRINTK(INFO, "last_consumer %d == consumer %d\n", last_consumer, consumer); @@ -1340,7 +1348,7 @@ int netxen_process_cmd_ring(unsigned long data) if (adapter->last_cmd_consumer == consumer && (((adapter->cmd_producer + 1) % adapter->max_tx_desc_count) == adapter->last_cmd_consumer)) { - consumer = *(adapter->cmd_consumer); + consumer = le32_to_cpu(*(adapter->cmd_consumer)); } done = (adapter->last_cmd_consumer == consumer); diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 36ba6a1aa363..225ff55527c4 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -434,12 +434,13 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) adapter->port_count++; adapter->port[i] = port; } - +#ifndef CONFIG_PPC64 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); +#endif /* * delay a while to ensure that the Pegs are up & running. * Otherwise, we might see some flaky behaviour. diff --git a/drivers/net/netxen/netxen_nic_niu.c b/drivers/net/netxen/netxen_nic_niu.c index 40d7003a371c..d5d95074e569 100644 --- a/drivers/net/netxen/netxen_nic_niu.c +++ b/drivers/net/netxen/netxen_nic_niu.c @@ -458,7 +458,7 @@ int netxen_niu_gbe_init_port(struct netxen_adapter *adapter, int port) int netxen_niu_xg_init_port(struct netxen_adapter *adapter, int port) { - long reg = 0, ret = 0; + u32 reg = 0, ret = 0; if (adapter->ahw.boardcfg.board_type == NETXEN_BRDTYPE_P2_SB31_10G_IMEZ) { netxen_crb_writelit_adapter(adapter, diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c index 448bf4a78016..c7bd9c1c7f31 100644 --- a/drivers/net/pcmcia/3c574_cs.c +++ b/drivers/net/pcmcia/3c574_cs.c @@ -915,7 +915,7 @@ static void media_check(unsigned long arg) if ((inw(ioaddr + EL3_STATUS) & IntLatch) && (inb(ioaddr + Timer) == 0xff)) { if (!lp->fast_poll) printk(KERN_INFO "%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/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c index 530df8883fe5..2561f76033ea 100644 --- a/drivers/net/pcmcia/smc91c92_cs.c +++ b/drivers/net/pcmcia/smc91c92_cs.c @@ -1927,7 +1927,7 @@ static void media_check(u_long arg) if (smc->watchdog++ && ((i>>8) & i)) { if (!smc->fast_poll) printk(KERN_INFO "%s: interrupt(s) dropped!\n", dev->name); - smc_interrupt(dev->irq, smc); + smc_interrupt(dev->irq, dev); smc->fast_poll = HZ; } if (smc->fast_poll) { diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index f4d4eb659cad..22aec5cce683 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -42,6 +42,19 @@ #define MII_M1011_IMASK_INIT 0x6400 #define MII_M1011_IMASK_CLEAR 0x0000 +#define MII_M1011_PHY_SCR 0x10 +#define MII_M1011_PHY_SCR_AUTO_CROSS 0x0060 + +#define MII_M1145_PHY_EXT_CR 0x14 +#define MII_M1145_RGMII_RX_DELAY 0x0080 +#define MII_M1145_RGMII_TX_DELAY 0x0002 + +#define M1145_DEV_FLAGS_RESISTANCE 0x00000001 + +#define MII_M1111_PHY_LED_CONTROL 0x18 +#define MII_M1111_PHY_LED_DIRECT 0x4100 +#define MII_M1111_PHY_LED_COMBINE 0x411c + MODULE_DESCRIPTION("Marvell PHY driver"); MODULE_AUTHOR("Andy Fleming"); MODULE_LICENSE("GPL"); @@ -63,7 +76,7 @@ static int marvell_config_intr(struct phy_device *phydev) { int err; - if(phydev->interrupts == PHY_INTERRUPT_ENABLED) + if (phydev->interrupts == PHY_INTERRUPT_ENABLED) err = phy_write(phydev, MII_M1011_IMASK, MII_M1011_IMASK_INIT); else err = phy_write(phydev, MII_M1011_IMASK, MII_M1011_IMASK_CLEAR); @@ -103,34 +116,153 @@ static int marvell_config_aneg(struct phy_device *phydev) if (err < 0) return err; + err = phy_write(phydev, MII_M1011_PHY_SCR, + MII_M1011_PHY_SCR_AUTO_CROSS); + if (err < 0) + return err; + + err = phy_write(phydev, MII_M1111_PHY_LED_CONTROL, + MII_M1111_PHY_LED_DIRECT); + if (err < 0) + return err; err = genphy_config_aneg(phydev); return err; } +static int m88e1145_config_init(struct phy_device *phydev) +{ + int err; + + /* Take care of errata E0 & E1 */ + err = phy_write(phydev, 0x1d, 0x001b); + if (err < 0) + return err; + + err = phy_write(phydev, 0x1e, 0x418f); + if (err < 0) + return err; + + err = phy_write(phydev, 0x1d, 0x0016); + if (err < 0) + return err; + + err = phy_write(phydev, 0x1e, 0xa2da); + if (err < 0) + return err; + + if (phydev->interface == PHY_INTERFACE_MODE_RGMII) { + int temp = phy_read(phydev, MII_M1145_PHY_EXT_CR); + if (temp < 0) + return temp; + + temp |= (MII_M1145_RGMII_RX_DELAY | MII_M1145_RGMII_TX_DELAY); + + err = phy_write(phydev, MII_M1145_PHY_EXT_CR, temp); + if (err < 0) + return err; + + if (phydev->dev_flags & M1145_DEV_FLAGS_RESISTANCE) { + err = phy_write(phydev, 0x1d, 0x0012); + if (err < 0) + return err; + + temp = phy_read(phydev, 0x1e); + if (temp < 0) + return temp; + + temp &= 0xf03f; + temp |= 2 << 9; /* 36 ohm */ + temp |= 2 << 6; /* 39 ohm */ + + err = phy_write(phydev, 0x1e, temp); + if (err < 0) + return err; + + err = phy_write(phydev, 0x1d, 0x3); + if (err < 0) + return err; + + err = phy_write(phydev, 0x1e, 0x8000); + if (err < 0) + return err; + } + } + + return 0; +} static struct phy_driver m88e1101_driver = { - .phy_id = 0x01410c00, - .phy_id_mask = 0xffffff00, - .name = "Marvell 88E1101", - .features = PHY_GBIT_FEATURES, - .flags = PHY_HAS_INTERRUPT, - .config_aneg = &marvell_config_aneg, - .read_status = &genphy_read_status, - .ack_interrupt = &marvell_ack_interrupt, - .config_intr = &marvell_config_intr, - .driver = { .owner = THIS_MODULE,}, + .phy_id = 0x01410c60, + .phy_id_mask = 0xfffffff0, + .name = "Marvell 88E1101", + .features = PHY_GBIT_FEATURES, + .flags = PHY_HAS_INTERRUPT, + .config_aneg = &marvell_config_aneg, + .read_status = &genphy_read_status, + .ack_interrupt = &marvell_ack_interrupt, + .config_intr = &marvell_config_intr, + .driver = {.owner = THIS_MODULE,}, +}; + +static struct phy_driver m88e1111s_driver = { + .phy_id = 0x01410cc0, + .phy_id_mask = 0xfffffff0, + .name = "Marvell 88E1111", + .features = PHY_GBIT_FEATURES, + .flags = PHY_HAS_INTERRUPT, + .config_aneg = &marvell_config_aneg, + .read_status = &genphy_read_status, + .ack_interrupt = &marvell_ack_interrupt, + .config_intr = &marvell_config_intr, + .driver = {.owner = THIS_MODULE,}, +}; + +static struct phy_driver m88e1145_driver = { + .phy_id = 0x01410cd0, + .phy_id_mask = 0xfffffff0, + .name = "Marvell 88E1145", + .features = PHY_GBIT_FEATURES, + .flags = PHY_HAS_INTERRUPT, + .config_init = &m88e1145_config_init, + .config_aneg = &marvell_config_aneg, + .read_status = &genphy_read_status, + .ack_interrupt = &marvell_ack_interrupt, + .config_intr = &marvell_config_intr, + .driver = {.owner = THIS_MODULE,}, }; static int __init marvell_init(void) { - return phy_driver_register(&m88e1101_driver); + int ret; + + ret = phy_driver_register(&m88e1101_driver); + if (ret) + return ret; + + ret = phy_driver_register(&m88e1111s_driver); + if (ret) + goto err1111s; + + ret = phy_driver_register(&m88e1145_driver); + if (ret) + goto err1145; + + return 0; + + err1145: + phy_driver_unregister(&m88e1111s_driver); + err1111s: + phy_driver_unregister(&m88e1101_driver); + return ret; } static void __exit marvell_exit(void) { phy_driver_unregister(&m88e1101_driver); + phy_driver_unregister(&m88e1111s_driver); + phy_driver_unregister(&m88e1145_driver); } module_init(marvell_init); diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index fdf45fdb6731..7d5b6d1838c8 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -138,7 +138,7 @@ void phy_prepare_link(struct phy_device *phydev, */ struct phy_device * phy_connect(struct net_device *dev, const char *phy_id, void (*handler)(struct net_device *), u32 flags, - u32 interface) + phy_interface_t interface) { struct phy_device *phydev; @@ -187,7 +187,7 @@ static int phy_compare_id(struct device *dev, void *data) } struct phy_device *phy_attach(struct net_device *dev, - const char *phy_id, u32 flags, u32 interface) + const char *phy_id, u32 flags, phy_interface_t interface) { struct bus_type *bus = &mdio_bus_type; struct phy_device *phydev; diff --git a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c index 92d11b961db8..e94ab256b540 100644 --- a/drivers/net/sk98lin/skge.c +++ b/drivers/net/sk98lin/skge.c @@ -5188,6 +5188,9 @@ static struct pci_driver skge_driver = { static int __init skge_init(void) { + printk(KERN_NOTICE "sk98lin: driver has been replaced by the skge driver" + " and is scheduled for removal\n"); + return pci_register_driver(&skge_driver); } diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index f2ab3d56e565..52edbd7ac17e 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -49,7 +49,7 @@ #include "sky2.h" #define DRV_NAME "sky2" -#define DRV_VERSION "1.12" +#define DRV_VERSION "1.13" #define PFX DRV_NAME " " /* @@ -1742,13 +1742,6 @@ static void sky2_link_down(struct sky2_port *sky2) reg &= ~(GM_GPCR_RX_ENA | GM_GPCR_TX_ENA); gma_write16(hw, port, GM_GP_CTRL, reg); - if (sky2->flow_status == FC_RX) { - /* restore Asymmetric Pause bit */ - gm_phy_write(hw, port, PHY_MARV_AUNE_ADV, - gm_phy_read(hw, port, PHY_MARV_AUNE_ADV) - | PHY_M_AN_ASP); - } - netif_carrier_off(sky2->netdev); netif_stop_queue(sky2->netdev); @@ -1773,10 +1766,10 @@ static int sky2_autoneg_done(struct sky2_port *sky2, u16 aux) { struct sky2_hw *hw = sky2->hw; unsigned port = sky2->port; - u16 lpa; + u16 advert, lpa; + advert = gm_phy_read(hw, port, PHY_MARV_AUNE_ADV); lpa = gm_phy_read(hw, port, PHY_MARV_AUNE_LP); - if (lpa & PHY_M_AN_RF) { printk(KERN_ERR PFX "%s: remote fault", sky2->netdev->name); return -1; @@ -1791,20 +1784,40 @@ static int sky2_autoneg_done(struct sky2_port *sky2, u16 aux) sky2->speed = sky2_phy_speed(hw, aux); sky2->duplex = (aux & PHY_M_PS_FULL_DUP) ? DUPLEX_FULL : DUPLEX_HALF; - /* Pause bits are offset (9..8) */ - if (hw->chip_id == CHIP_ID_YUKON_XL - || hw->chip_id == CHIP_ID_YUKON_EC_U - || hw->chip_id == CHIP_ID_YUKON_EX) - aux >>= 6; - - sky2->flow_status = sky2_flow(aux & PHY_M_PS_RX_P_EN, - aux & PHY_M_PS_TX_P_EN); + /* Since the pause result bits seem to in different positions on + * different chips. look at registers. + */ + if (!sky2_is_copper(hw)) { + /* Shift for bits in fiber PHY */ + advert &= ~(ADVERTISE_PAUSE_CAP|ADVERTISE_PAUSE_ASYM); + lpa &= ~(LPA_PAUSE_CAP|LPA_PAUSE_ASYM); + + if (advert & ADVERTISE_1000XPAUSE) + advert |= ADVERTISE_PAUSE_CAP; + if (advert & ADVERTISE_1000XPSE_ASYM) + advert |= ADVERTISE_PAUSE_ASYM; + if (lpa & LPA_1000XPAUSE) + lpa |= LPA_PAUSE_CAP; + if (lpa & LPA_1000XPAUSE_ASYM) + lpa |= LPA_PAUSE_ASYM; + } + + sky2->flow_status = FC_NONE; + if (advert & ADVERTISE_PAUSE_CAP) { + if (lpa & LPA_PAUSE_CAP) + sky2->flow_status = FC_BOTH; + else if (advert & ADVERTISE_PAUSE_ASYM) + sky2->flow_status = FC_RX; + } else if (advert & ADVERTISE_PAUSE_ASYM) { + if ((lpa & LPA_PAUSE_CAP) && (lpa & LPA_PAUSE_ASYM)) + sky2->flow_status = FC_TX; + } if (sky2->duplex == DUPLEX_HALF && sky2->speed < SPEED_1000 && !(hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX)) sky2->flow_status = FC_NONE; - if (aux & PHY_M_PS_RX_P_EN) + if (sky2->flow_status & FC_TX) sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_ON); else sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF); @@ -1853,16 +1866,13 @@ out: spin_unlock(&sky2->phy_lock); } - /* Transmit timeout is only called if we are running, carrier is up * and tx queue is full (stopped). - * Called with netif_tx_lock held. */ static void sky2_tx_timeout(struct net_device *dev) { struct sky2_port *sky2 = netdev_priv(dev); struct sky2_hw *hw = sky2->hw; - u32 imask; if (netif_msg_timer(sky2)) printk(KERN_ERR PFX "%s: tx timeout\n", dev->name); @@ -1872,19 +1882,8 @@ static void sky2_tx_timeout(struct net_device *dev) sky2_read16(hw, sky2->port == 0 ? STAT_TXA1_RIDX : STAT_TXA2_RIDX), sky2_read16(hw, Q_ADDR(txqaddr[sky2->port], Q_DONE))); - imask = sky2_read32(hw, B0_IMSK); /* block IRQ in hw */ - sky2_write32(hw, B0_IMSK, 0); - sky2_read32(hw, B0_IMSK); - - netif_poll_disable(hw->dev[0]); /* stop NAPI poll */ - synchronize_irq(hw->pdev->irq); - - netif_start_queue(dev); /* don't wakeup during flush */ - sky2_tx_complete(sky2, sky2->tx_prod); /* Flush transmit queue */ - - sky2_write32(hw, B0_IMSK, imask); - - sky2_phy_reinit(sky2); /* this clears flow control etc */ + /* can't restart safely under softirq */ + schedule_work(&hw->restart_work); } static int sky2_change_mtu(struct net_device *dev, int new_mtu) @@ -2057,9 +2056,6 @@ static struct sk_buff *sky2_receive(struct net_device *dev, if (!(status & GMR_FS_RX_OK)) goto resubmit; - if (length > dev->mtu + ETH_HLEN) - goto oversize; - if (length < copybreak) skb = receive_copy(sky2, re, length); else @@ -2069,14 +2065,10 @@ resubmit: return skb; -oversize: - ++sky2->net_stats.rx_over_errors; - goto resubmit; - error: ++sky2->net_stats.rx_errors; if (status & GMR_FS_RX_FF_OV) { - sky2->net_stats.rx_fifo_errors++; + sky2->net_stats.rx_over_errors++; goto resubmit; } @@ -2638,6 +2630,49 @@ static void sky2_reset(struct sky2_hw *hw) sky2_write8(hw, STAT_ISR_TIMER_CTRL, TIM_START); } +static void sky2_restart(struct work_struct *work) +{ + struct sky2_hw *hw = container_of(work, struct sky2_hw, restart_work); + struct net_device *dev; + int i, err; + + dev_dbg(&hw->pdev->dev, "restarting\n"); + + del_timer_sync(&hw->idle_timer); + + rtnl_lock(); + sky2_write32(hw, B0_IMSK, 0); + sky2_read32(hw, B0_IMSK); + + netif_poll_disable(hw->dev[0]); + + for (i = 0; i < hw->ports; i++) { + dev = hw->dev[i]; + if (netif_running(dev)) + sky2_down(dev); + } + + sky2_reset(hw); + sky2_write32(hw, B0_IMSK, Y2_IS_BASE); + netif_poll_enable(hw->dev[0]); + + for (i = 0; i < hw->ports; i++) { + dev = hw->dev[i]; + if (netif_running(dev)) { + err = sky2_up(dev); + if (err) { + printk(KERN_INFO PFX "%s: could not restart %d\n", + dev->name, err); + dev_close(dev); + } + } + } + + sky2_idle_start(hw); + + rtnl_unlock(); +} + static inline u8 sky2_wol_supported(const struct sky2_hw *hw) { return sky2_is_copper(hw) ? (WAKE_PHY | WAKE_MAGIC) : 0; @@ -3600,6 +3635,8 @@ static int __devinit sky2_probe(struct pci_dev *pdev, } setup_timer(&hw->idle_timer, sky2_idle, (unsigned long) hw); + INIT_WORK(&hw->restart_work, sky2_restart); + sky2_idle_start(hw); pci_set_drvdata(pdev, hw); @@ -3636,6 +3673,8 @@ static void __devexit sky2_remove(struct pci_dev *pdev) del_timer_sync(&hw->idle_timer); + flush_scheduled_work(); + sky2_write32(hw, B0_IMSK, 0); synchronize_irq(hw->pdev->irq); diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index 3b0189569d52..ac24bdc42976 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -1589,7 +1589,7 @@ enum { GMR_FS_ANY_ERR = GMR_FS_RX_FF_OV | GMR_FS_CRC_ERR | GMR_FS_FRAGMENT | GMR_FS_LONG_ERR | - GMR_FS_MII_ERR | GMR_FS_GOOD_FC | GMR_FS_BAD_FC | + GMR_FS_MII_ERR | GMR_FS_BAD_FC | GMR_FS_UN_SIZE | GMR_FS_JABBER, }; @@ -1933,6 +1933,7 @@ struct sky2_hw { dma_addr_t st_dma; struct timer_list idle_timer; + struct work_struct restart_work; int msi; wait_queue_head_t msi_wait; }; diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig index 61708cf4c85d..8897f538a7c7 100644 --- a/drivers/net/wan/Kconfig +++ b/drivers/net/wan/Kconfig @@ -26,7 +26,7 @@ config WAN # There is no way to detect a comtrol sv11 - force it modular for now. config HOSTESS_SV11 tristate "Comtrol Hostess SV-11 support" - depends on WAN && ISA && m && ISA_DMA_API + depends on WAN && ISA && m && ISA_DMA_API && INET help Driver for Comtrol Hostess SV-11 network card which operates on low speed synchronous serial links at up to diff --git a/drivers/net/wan/pc300too.c b/drivers/net/wan/pc300too.c index bc156b51678a..aff05dba720a 100644 --- a/drivers/net/wan/pc300too.c +++ b/drivers/net/wan/pc300too.c @@ -542,7 +542,7 @@ static int __init pc300_init_module(void) CLOCK_BASE = use_crystal_clock ? 24576000 : pci_clock_freq; - return pci_module_init(&pc300_pci_driver); + return pci_register_driver(&pc300_pci_driver); } diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h index 3a064def162e..0e790efae683 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx.h @@ -771,6 +771,7 @@ struct bcm43xx_private { * This is currently always BCM43xx_BUSTYPE_PCI */ u8 bustype; + u64 dma_mask; u16 board_vendor; u16 board_type; diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c index 978ed099e285..6e0dc76400e5 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c @@ -145,16 +145,14 @@ dma_addr_t map_descbuffer(struct bcm43xx_dmaring *ring, int tx) { dma_addr_t dmaaddr; + int direction = PCI_DMA_FROMDEVICE; - if (tx) { - dmaaddr = dma_map_single(&ring->bcm->pci_dev->dev, - buf, len, - DMA_TO_DEVICE); - } else { - dmaaddr = dma_map_single(&ring->bcm->pci_dev->dev, + if (tx) + direction = PCI_DMA_TODEVICE; + + dmaaddr = pci_map_single(ring->bcm->pci_dev, buf, len, - DMA_FROM_DEVICE); - } + direction); return dmaaddr; } @@ -166,13 +164,13 @@ void unmap_descbuffer(struct bcm43xx_dmaring *ring, int tx) { if (tx) { - dma_unmap_single(&ring->bcm->pci_dev->dev, + pci_unmap_single(ring->bcm->pci_dev, addr, len, - DMA_TO_DEVICE); + PCI_DMA_TODEVICE); } else { - dma_unmap_single(&ring->bcm->pci_dev->dev, + pci_unmap_single(ring->bcm->pci_dev, addr, len, - DMA_FROM_DEVICE); + PCI_DMA_FROMDEVICE); } } @@ -183,8 +181,8 @@ void sync_descbuffer_for_cpu(struct bcm43xx_dmaring *ring, { assert(!ring->tx); - dma_sync_single_for_cpu(&ring->bcm->pci_dev->dev, - addr, len, DMA_FROM_DEVICE); + pci_dma_sync_single_for_cpu(ring->bcm->pci_dev, + addr, len, PCI_DMA_FROMDEVICE); } static inline @@ -194,8 +192,8 @@ void sync_descbuffer_for_device(struct bcm43xx_dmaring *ring, { assert(!ring->tx); - dma_sync_single_for_device(&ring->bcm->pci_dev->dev, - addr, len, DMA_FROM_DEVICE); + pci_dma_sync_single_for_cpu(ring->bcm->pci_dev, + addr, len, PCI_DMA_TODEVICE); } /* Unmap and free a descriptor buffer. */ @@ -214,17 +212,53 @@ void free_descriptor_buffer(struct bcm43xx_dmaring *ring, static int alloc_ringmemory(struct bcm43xx_dmaring *ring) { - struct device *dev = &(ring->bcm->pci_dev->dev); - - ring->descbase = dma_alloc_coherent(dev, BCM43xx_DMA_RINGMEMSIZE, - &(ring->dmabase), GFP_KERNEL); + ring->descbase = pci_alloc_consistent(ring->bcm->pci_dev, BCM43xx_DMA_RINGMEMSIZE, + &(ring->dmabase)); if (!ring->descbase) { - printk(KERN_ERR PFX "DMA ringmemory allocation failed\n"); - return -ENOMEM; + /* Allocation may have failed due to pci_alloc_consistent + insisting on use of GFP_DMA, which is more restrictive + than necessary... */ + struct dma_desc *rx_ring; + dma_addr_t rx_ring_dma; + + rx_ring = kzalloc(BCM43xx_DMA_RINGMEMSIZE, GFP_KERNEL); + if (!rx_ring) + goto out_err; + + rx_ring_dma = pci_map_single(ring->bcm->pci_dev, rx_ring, + BCM43xx_DMA_RINGMEMSIZE, + PCI_DMA_BIDIRECTIONAL); + + if (pci_dma_mapping_error(rx_ring_dma) || + rx_ring_dma + BCM43xx_DMA_RINGMEMSIZE > ring->bcm->dma_mask) { + /* Sigh... */ + if (!pci_dma_mapping_error(rx_ring_dma)) + pci_unmap_single(ring->bcm->pci_dev, + rx_ring_dma, BCM43xx_DMA_RINGMEMSIZE, + PCI_DMA_BIDIRECTIONAL); + rx_ring_dma = pci_map_single(ring->bcm->pci_dev, + rx_ring, BCM43xx_DMA_RINGMEMSIZE, + PCI_DMA_BIDIRECTIONAL); + if (pci_dma_mapping_error(rx_ring_dma) || + rx_ring_dma + BCM43xx_DMA_RINGMEMSIZE > ring->bcm->dma_mask) { + assert(0); + if (!pci_dma_mapping_error(rx_ring_dma)) + pci_unmap_single(ring->bcm->pci_dev, + rx_ring_dma, BCM43xx_DMA_RINGMEMSIZE, + PCI_DMA_BIDIRECTIONAL); + goto out_err; + } + } + + ring->descbase = rx_ring; + ring->dmabase = rx_ring_dma; } memset(ring->descbase, 0, BCM43xx_DMA_RINGMEMSIZE); return 0; +out_err: + printk(KERN_ERR PFX "DMA ringmemory allocation failed\n"); + return -ENOMEM; } static void free_ringmemory(struct bcm43xx_dmaring *ring) @@ -407,6 +441,29 @@ static int setup_rx_descbuffer(struct bcm43xx_dmaring *ring, if (unlikely(!skb)) return -ENOMEM; dmaaddr = map_descbuffer(ring, skb->data, ring->rx_buffersize, 0); + /* This hardware bug work-around adapted from the b44 driver. + The chip may be unable to do PCI DMA to/from anything above 1GB */ + if (pci_dma_mapping_error(dmaaddr) || + dmaaddr + ring->rx_buffersize > ring->bcm->dma_mask) { + /* This one has 30-bit addressing... */ + if (!pci_dma_mapping_error(dmaaddr)) + pci_unmap_single(ring->bcm->pci_dev, + dmaaddr, ring->rx_buffersize, + PCI_DMA_FROMDEVICE); + dev_kfree_skb_any(skb); + skb = __dev_alloc_skb(ring->rx_buffersize,GFP_DMA); + if (skb == NULL) + return -ENOMEM; + dmaaddr = pci_map_single(ring->bcm->pci_dev, + skb->data, ring->rx_buffersize, + PCI_DMA_FROMDEVICE); + if (pci_dma_mapping_error(dmaaddr) || + dmaaddr + ring->rx_buffersize > ring->bcm->dma_mask) { + assert(0); + dev_kfree_skb_any(skb); + return -ENOMEM; + } + } meta->skb = skb; meta->dmaaddr = dmaaddr; skb->dev = ring->bcm->net_dev; @@ -636,8 +693,10 @@ struct bcm43xx_dmaring * bcm43xx_setup_dmaring(struct bcm43xx_private *bcm, err = dmacontroller_setup(ring); if (err) goto err_free_ringmemory; + return ring; out: + printk(KERN_ERR PFX "Error in bcm43xx_setup_dmaring\n"); return ring; err_free_ringmemory: @@ -705,30 +764,16 @@ int bcm43xx_dma_init(struct bcm43xx_private *bcm) struct bcm43xx_dmaring *ring; int err = -ENOMEM; int dma64 = 0; - u64 mask = bcm43xx_get_supported_dma_mask(bcm); - int nobits; - if (mask == DMA_64BIT_MASK) { + bcm->dma_mask = bcm43xx_get_supported_dma_mask(bcm); + if (bcm->dma_mask == DMA_64BIT_MASK) dma64 = 1; - nobits = 64; - } else if (mask == DMA_32BIT_MASK) - nobits = 32; - else - nobits = 30; - err = pci_set_dma_mask(bcm->pci_dev, mask); - err |= pci_set_consistent_dma_mask(bcm->pci_dev, mask); - if (err) { -#ifdef CONFIG_BCM43XX_PIO - printk(KERN_WARNING PFX "DMA not supported on this device." - " Falling back to PIO.\n"); - bcm->__using_pio = 1; - return -ENOSYS; -#else - printk(KERN_ERR PFX "FATAL: DMA not supported and PIO not configured. " - "Please recompile the driver with PIO support.\n"); - return -ENODEV; -#endif /* CONFIG_BCM43XX_PIO */ - } + err = pci_set_dma_mask(bcm->pci_dev, bcm->dma_mask); + if (err) + goto no_dma; + err = pci_set_consistent_dma_mask(bcm->pci_dev, bcm->dma_mask); + if (err) + goto no_dma; /* setup TX DMA channels. */ ring = bcm43xx_setup_dmaring(bcm, 0, 1, dma64); @@ -774,7 +819,9 @@ int bcm43xx_dma_init(struct bcm43xx_private *bcm) dma->rx_ring3 = ring; } - dprintk(KERN_INFO PFX "%d-bit DMA initialized\n", nobits); + dprintk(KERN_INFO PFX "%d-bit DMA initialized\n", + (bcm->dma_mask == DMA_64BIT_MASK) ? 64 : + (bcm->dma_mask == DMA_32BIT_MASK) ? 32 : 30); err = 0; out: return err; @@ -800,7 +847,17 @@ err_destroy_tx1: err_destroy_tx0: bcm43xx_destroy_dmaring(dma->tx_ring0); dma->tx_ring0 = NULL; - goto out; +no_dma: +#ifdef CONFIG_BCM43XX_PIO + printk(KERN_WARNING PFX "DMA not supported on this device." + " Falling back to PIO.\n"); + bcm->__using_pio = 1; + return -ENOSYS; +#else + printk(KERN_ERR PFX "FATAL: DMA not supported and PIO not configured. " + "Please recompile the driver with PIO support.\n"); + return -ENODEV; +#endif /* CONFIG_BCM43XX_PIO */ } /* Generate a cookie for the TX header. */ @@ -905,6 +962,7 @@ static void dma_tx_fragment(struct bcm43xx_dmaring *ring, struct bcm43xx_dmadesc_generic *desc; struct bcm43xx_dmadesc_meta *meta; dma_addr_t dmaaddr; + struct sk_buff *bounce_skb; assert(skb_shinfo(skb)->nr_frags == 0); @@ -924,9 +982,28 @@ static void dma_tx_fragment(struct bcm43xx_dmaring *ring, skb->len - sizeof(struct bcm43xx_txhdr), (cur_frag == 0), generate_cookie(ring, slot)); + dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1); + if (dma_mapping_error(dmaaddr) || dmaaddr + skb->len > ring->bcm->dma_mask) { + /* chip cannot handle DMA to/from > 1GB, use bounce buffer (copied from b44 driver) */ + if (!dma_mapping_error(dmaaddr)) + unmap_descbuffer(ring, dmaaddr, skb->len, 1); + bounce_skb = __dev_alloc_skb(skb->len, GFP_ATOMIC|GFP_DMA); + if (!bounce_skb) + return; + dmaaddr = map_descbuffer(ring, bounce_skb->data, bounce_skb->len, 1); + if (dma_mapping_error(dmaaddr) || dmaaddr + skb->len > ring->bcm->dma_mask) { + if (!dma_mapping_error(dmaaddr)) + unmap_descbuffer(ring, dmaaddr, skb->len, 1); + dev_kfree_skb_any(bounce_skb); + assert(0); + return; + } + memcpy(skb_put(bounce_skb, skb->len), skb->data, skb->len); + dev_kfree_skb_any(skb); + skb = bounce_skb; + } meta->skb = skb; - dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1); meta->dmaaddr = dmaaddr; fill_descriptor(ring, desc, dmaaddr, diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 23aaf1ed8541..2e400aacc436 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -95,13 +95,9 @@ static int modparam_noleds; module_param_named(noleds, modparam_noleds, int, 0444); MODULE_PARM_DESC(noleds, "Turn off all LED activity"); -#ifdef CONFIG_BCM43XX_DEBUG static char modparam_fwpostfix[64]; module_param_string(fwpostfix, modparam_fwpostfix, 64, 0444); -MODULE_PARM_DESC(fwpostfix, "Postfix for .fw files. Useful for debugging."); -#else -# define modparam_fwpostfix "" -#endif /* CONFIG_BCM43XX_DEBUG*/ +MODULE_PARM_DESC(fwpostfix, "Postfix for .fw files. Useful for using multiple firmware image versions."); /* If you want to debug with just a single device, enable this, @@ -2983,8 +2979,10 @@ static int bcm43xx_chipset_attach(struct bcm43xx_private *bcm) err = bcm43xx_pctl_set_crystal(bcm, 1); if (err) goto out; - bcm43xx_pci_read_config16(bcm, PCI_STATUS, &pci_status); - bcm43xx_pci_write_config16(bcm, PCI_STATUS, pci_status & ~PCI_STATUS_SIG_TARGET_ABORT); + err = bcm43xx_pci_read_config16(bcm, PCI_STATUS, &pci_status); + if (err) + goto out; + err = bcm43xx_pci_write_config16(bcm, PCI_STATUS, pci_status & ~PCI_STATUS_SIG_TARGET_ABORT); out: return err; @@ -3796,12 +3794,18 @@ static int bcm43xx_attach_board(struct bcm43xx_private *bcm) } net_dev->base_addr = (unsigned long)bcm->mmio_addr; - bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_VENDOR_ID, + err = bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_VENDOR_ID, &bcm->board_vendor); - bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_ID, + if (err) + goto err_iounmap; + err = bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_ID, &bcm->board_type); - bcm43xx_pci_read_config16(bcm, PCI_REVISION_ID, + if (err) + goto err_iounmap; + err = bcm43xx_pci_read_config16(bcm, PCI_REVISION_ID, &bcm->board_revision); + if (err) + goto err_iounmap; err = bcm43xx_chipset_attach(bcm); if (err) @@ -3892,6 +3896,7 @@ err_pci_release: pci_release_regions(pci_dev); err_pci_disable: pci_disable_device(pci_dev); + printk(KERN_ERR PFX "Unable to attach board\n"); goto out; } diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c index d2ca949174fe..7b665e2386a8 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c @@ -260,22 +260,22 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev, if (phy->type == BCM43xx_PHYTYPE_A || phy->type == BCM43xx_PHYTYPE_G) { range->num_bitrates = 8; - range->bitrate[i++] = IEEE80211_OFDM_RATE_6MB; - range->bitrate[i++] = IEEE80211_OFDM_RATE_9MB; - range->bitrate[i++] = IEEE80211_OFDM_RATE_12MB; - range->bitrate[i++] = IEEE80211_OFDM_RATE_18MB; - range->bitrate[i++] = IEEE80211_OFDM_RATE_24MB; - range->bitrate[i++] = IEEE80211_OFDM_RATE_36MB; - range->bitrate[i++] = IEEE80211_OFDM_RATE_48MB; - range->bitrate[i++] = IEEE80211_OFDM_RATE_54MB; + range->bitrate[i++] = IEEE80211_OFDM_RATE_6MB * 500000; + range->bitrate[i++] = IEEE80211_OFDM_RATE_9MB * 500000; + range->bitrate[i++] = IEEE80211_OFDM_RATE_12MB * 500000; + range->bitrate[i++] = IEEE80211_OFDM_RATE_18MB * 500000; + range->bitrate[i++] = IEEE80211_OFDM_RATE_24MB * 500000; + range->bitrate[i++] = IEEE80211_OFDM_RATE_36MB * 500000; + range->bitrate[i++] = IEEE80211_OFDM_RATE_48MB * 500000; + range->bitrate[i++] = IEEE80211_OFDM_RATE_54MB * 500000; } if (phy->type == BCM43xx_PHYTYPE_B || phy->type == BCM43xx_PHYTYPE_G) { range->num_bitrates += 4; - range->bitrate[i++] = IEEE80211_CCK_RATE_1MB; - range->bitrate[i++] = IEEE80211_CCK_RATE_2MB; - range->bitrate[i++] = IEEE80211_CCK_RATE_5MB; - range->bitrate[i++] = IEEE80211_CCK_RATE_11MB; + range->bitrate[i++] = IEEE80211_CCK_RATE_1MB * 500000; + range->bitrate[i++] = IEEE80211_CCK_RATE_2MB * 500000; + range->bitrate[i++] = IEEE80211_CCK_RATE_5MB * 500000; + range->bitrate[i++] = IEEE80211_CCK_RATE_11MB * 500000; } geo = ieee80211_get_geo(bcm->ieee); @@ -285,7 +285,7 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev, if (j == IW_MAX_FREQUENCIES) break; range->freq[j].i = j + 1; - range->freq[j].m = geo->a[i].freq;//FIXME? + range->freq[j].m = geo->a[i].freq * 100000; range->freq[j].e = 1; j++; } @@ -293,7 +293,7 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev, if (j == IW_MAX_FREQUENCIES) break; range->freq[j].i = j + 1; - range->freq[j].m = geo->bg[i].freq;//FIXME? + range->freq[j].m = geo->bg[i].freq * 100000; range->freq[j].e = 1; j++; } diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index b85857a84870..d0639a45cd2c 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c @@ -175,7 +175,7 @@ that only one external action is invoked at a time. /* Debugging stuff */ #ifdef CONFIG_IPW2100_DEBUG -#define CONFIG_IPW2100_RX_DEBUG /* Reception debugging */ +#define IPW2100_RX_DEBUG /* Reception debugging */ #endif MODULE_DESCRIPTION(DRV_DESCRIPTION); @@ -2239,7 +2239,7 @@ static void ipw2100_snapshot_free(struct ipw2100_priv *priv) priv->snapshot[0] = NULL; } -#ifdef CONFIG_IPW2100_DEBUG_C3 +#ifdef IPW2100_DEBUG_C3 static int ipw2100_snapshot_alloc(struct ipw2100_priv *priv) { int i; @@ -2314,13 +2314,13 @@ static u32 ipw2100_match_buf(struct ipw2100_priv *priv, u8 * in_buf, * The size of the constructed ethernet * */ -#ifdef CONFIG_IPW2100_RX_DEBUG +#ifdef IPW2100_RX_DEBUG static u8 packet_data[IPW_RX_NIC_BUFFER_LENGTH]; #endif static void ipw2100_corruption_detected(struct ipw2100_priv *priv, int i) { -#ifdef CONFIG_IPW2100_DEBUG_C3 +#ifdef IPW2100_DEBUG_C3 struct ipw2100_status *status = &priv->status_queue.drv[i]; u32 match, reg; int j; @@ -2342,7 +2342,7 @@ static void ipw2100_corruption_detected(struct ipw2100_priv *priv, int i) } #endif -#ifdef CONFIG_IPW2100_DEBUG_C3 +#ifdef IPW2100_DEBUG_C3 /* Halt the fimrware so we can get a good image */ write_register(priv->net_dev, IPW_REG_RESET_REG, IPW_AUX_HOST_RESET_REG_STOP_MASTER); @@ -2413,7 +2413,7 @@ static void isr_rx(struct ipw2100_priv *priv, int i, skb_put(packet->skb, status->frame_size); -#ifdef CONFIG_IPW2100_RX_DEBUG +#ifdef IPW2100_RX_DEBUG /* Make a copy of the frame so we can dump it to the logs if * ieee80211_rx fails */ memcpy(packet_data, packet->skb->data, @@ -2421,7 +2421,7 @@ static void isr_rx(struct ipw2100_priv *priv, int i, #endif if (!ieee80211_rx(priv->ieee, packet->skb, stats)) { -#ifdef CONFIG_IPW2100_RX_DEBUG +#ifdef IPW2100_RX_DEBUG IPW_DEBUG_DROP("%s: Non consumed packet:\n", priv->net_dev->name); printk_buf(IPW_DL_DROP, packet_data, status->frame_size); @@ -4912,7 +4912,7 @@ static int ipw2100_set_power_mode(struct ipw2100_priv *priv, int power_level) else priv->power_mode = IPW_POWER_ENABLED | power_level; -#ifdef CONFIG_IPW2100_TX_POWER +#ifdef IPW2100_TX_POWER if (priv->port_type == IBSS && priv->adhoc_power != DFTL_IBSS_TX_POWER) { /* Set beacon interval */ cmd.host_command = TX_POWER_INDEX; diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c index 5eb81638e846..b04239792f63 100644 --- a/drivers/net/wireless/wavelan_cs.c +++ b/drivers/net/wireless/wavelan_cs.c @@ -1168,7 +1168,7 @@ wv_mmc_show(struct net_device * dev) m.mmr_unused0[6], m.mmr_unused0[7]); #endif /* DEBUG_SHOW_UNUSED */ - printk(KERN_DEBUG "Encryption algorythm: %02X - Status: %02X\n", + printk(KERN_DEBUG "Encryption algorithm: %02X - Status: %02X\n", m.mmr_des_avail, m.mmr_des_status); #ifdef DEBUG_SHOW_UNUSED printk(KERN_DEBUG "mmc_unused1[]: %02X:%02X:%02X:%02X:%02X\n", @@ -3590,9 +3590,9 @@ wv_82593_config(struct net_device * dev) cfblk.acloc = TRUE; /* Disable source addr insertion by i82593 */ cfblk.preamb_len = 0; /* 2 bytes preamble (SFD) */ cfblk.loopback = FALSE; - cfblk.lin_prio = 0; /* conform to 802.3 backoff algoritm */ - cfblk.exp_prio = 5; /* conform to 802.3 backoff algoritm */ - cfblk.bof_met = 1; /* conform to 802.3 backoff algoritm */ + cfblk.lin_prio = 0; /* conform to 802.3 backoff algorithm */ + cfblk.exp_prio = 5; /* conform to 802.3 backoff algorithm */ + cfblk.bof_met = 1; /* conform to 802.3 backoff algorithm */ cfblk.ifrm_spc = 0x20 >> 4; /* 32 bit times interframe spacing */ cfblk.slottim_low = 0x20 >> 5; /* 32 bit times slot time */ cfblk.slottim_hi = 0x0; diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index a08524191b5d..4c5f78eac349 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -156,7 +156,7 @@ void zd_mac_clear(struct zd_mac *mac) static int reset_mode(struct zd_mac *mac) { struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); - struct zd_ioreq32 ioreqs[3] = { + struct zd_ioreq32 ioreqs[] = { { CR_RX_FILTER, STA_RX_FILTER }, { CR_SNIFFER_ON, 0U }, }; @@ -164,10 +164,9 @@ static int reset_mode(struct zd_mac *mac) if (ieee->iw_mode == IW_MODE_MONITOR) { ioreqs[0].value = 0xffffffff; ioreqs[1].value = 0x1; - ioreqs[2].value = ENC_SNIFFER; } - return zd_iowrite32a(&mac->chip, ioreqs, 3); + return zd_iowrite32a(&mac->chip, ioreqs, ARRAY_SIZE(ioreqs)); } int zd_mac_open(struct net_device *netdev) @@ -904,16 +903,21 @@ static int fill_ctrlset(struct zd_mac *mac, static int zd_mac_tx(struct zd_mac *mac, struct ieee80211_txb *txb, int pri) { int i, r; + struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); for (i = 0; i < txb->nr_frags; i++) { struct sk_buff *skb = txb->fragments[i]; r = fill_ctrlset(mac, txb, i); - if (r) + if (r) { + ieee->stats.tx_dropped++; return r; + } r = zd_usb_tx(&mac->chip.usb, skb->data, skb->len); - if (r) + if (r) { + ieee->stats.tx_dropped++; return r; + } } /* FIXME: shouldn't this be handled by the upper layers? */ @@ -1063,9 +1067,23 @@ static int fill_rx_stats(struct ieee80211_rx_stats *stats, *pstatus = status = zd_tail(buffer, length, sizeof(struct rx_status)); if (status->frame_status & ZD_RX_ERROR) { - /* FIXME: update? */ + struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); + ieee->stats.rx_errors++; + if (status->frame_status & ZD_RX_TIMEOUT_ERROR) + ieee->stats.rx_missed_errors++; + else if (status->frame_status & ZD_RX_FIFO_OVERRUN_ERROR) + ieee->stats.rx_fifo_errors++; + else if (status->frame_status & ZD_RX_DECRYPTION_ERROR) + ieee->ieee_stats.rx_discards_undecryptable++; + else if (status->frame_status & ZD_RX_CRC32_ERROR) { + ieee->stats.rx_crc_errors++; + ieee->ieee_stats.rx_fcs_errors++; + } + else if (status->frame_status & ZD_RX_CRC16_ERROR) + ieee->stats.rx_crc_errors++; return -EINVAL; } + memset(stats, 0, sizeof(struct ieee80211_rx_stats)); stats->len = length - (ZD_PLCP_HEADER_SIZE + IEEE80211_FCS_LEN + + sizeof(struct rx_status)); @@ -1094,14 +1112,16 @@ static void zd_mac_rx(struct zd_mac *mac, struct sk_buff *skb) 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); + ieee->stats.rx_errors++; + ieee->stats.rx_length_errors++; goto free_skb; } r = fill_rx_stats(&stats, &status, mac, skb->data, skb->len); if (r) { - /* Only packets with rx errors are included here. */ + /* Only packets with rx errors are included here. + * The error stats have already been set in fill_rx_stats. + */ goto free_skb; } @@ -1114,8 +1134,10 @@ static void zd_mac_rx(struct zd_mac *mac, struct sk_buff *skb) r = filter_rx(ieee, skb->data, skb->len, &stats); if (r <= 0) { - if (r < 0) + if (r < 0) { + ieee->stats.rx_errors++; dev_dbg_f(zd_mac_dev(mac), "Error in packet.\n"); + } goto free_skb; } @@ -1146,7 +1168,9 @@ int zd_mac_rx_irq(struct zd_mac *mac, const u8 *buffer, unsigned int length) skb = dev_alloc_skb(sizeof(struct zd_rt_hdr) + length); if (!skb) { + struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); dev_warn(zd_mac_dev(mac), "Could not allocate skb.\n"); + ieee->stats.rx_dropped++; return -ENOMEM; } skb_reserve(skb, sizeof(struct zd_rt_hdr)); diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index 75ef55624d7f..aac8a1c5ba08 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -313,6 +313,12 @@ out: static inline void handle_retry_failed_int(struct urb *urb) { + struct zd_usb *usb = urb->context; + struct zd_mac *mac = zd_usb_to_mac(usb); + struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); + + ieee->stats.tx_errors++; + ieee->ieee_stats.tx_retry_limit_exceeded++; dev_dbg_f(urb_dev(urb), "retry failed interrupt\n"); } @@ -487,6 +493,9 @@ static void handle_rx_packet(struct zd_usb *usb, const u8 *buffer, if (length < sizeof(struct rx_length_info)) { /* It's not a complete packet anyhow. */ + struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); + ieee->stats.rx_errors++; + ieee->stats.rx_length_errors++; return; } length_info = (struct rx_length_info *) @@ -923,6 +932,8 @@ static int probe(struct usb_interface *intf, const struct usb_device_id *id) goto error; } + usb_reset_device(interface_to_usbdev(intf)); + netdev = zd_netdev_alloc(intf); if (netdev == NULL) { r = -ENOMEM; @@ -1024,6 +1035,7 @@ static int __init usb_init(void) r = usb_register(&driver); if (r) { + destroy_workqueue(zd_workqueue); printk(KERN_ERR "%s usb_register() failed. Error number %d\n", driver.name, r); return r; diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 4438ae1ede4f..a3c1755b2f28 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -415,6 +415,7 @@ static struct kobj_type pci_driver_kobj_type = { * __pci_register_driver - register a new pci driver * @drv: the driver structure to register * @owner: owner module of drv + * @mod_name: module name string * * Adds the driver structure to the list of registered drivers. * Returns a negative value on error, otherwise 0. diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 7a94076752d0..cd913a2a416f 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -143,6 +143,14 @@ static ssize_t is_enabled_show(struct device *dev, return sprintf (buf, "%u\n", atomic_read(&pdev->enable_cnt)); } +#ifdef CONFIG_NUMA +static ssize_t +numa_node_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf (buf, "%d\n", dev->numa_node); +} +#endif + static ssize_t msi_bus_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -194,6 +202,9 @@ struct device_attribute pci_dev_attrs[] = { __ATTR_RO(irq), __ATTR_RO(local_cpus), __ATTR_RO(modalias), +#ifdef CONFIG_NUMA + __ATTR_RO(numa_node), +#endif __ATTR(enable, 0600, is_enabled_show, is_enabled_store), __ATTR(broken_parity_status,(S_IRUGO|S_IWUSR), broken_parity_status_show,broken_parity_status_store), diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 8b44cff2c176..1e74e1ee8bd8 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -21,6 +21,12 @@ unsigned int pci_pm_d3_delay = 10; +#define DEFAULT_CARDBUS_IO_SIZE (256) +#define DEFAULT_CARDBUS_MEM_SIZE (64*1024*1024) +/* pci=cbmemsize=nnM,cbiosize=nn can override this */ +unsigned long pci_cardbus_io_size = DEFAULT_CARDBUS_IO_SIZE; +unsigned long pci_cardbus_mem_size = DEFAULT_CARDBUS_MEM_SIZE; + /** * pci_bus_max_busnr - returns maximum PCI bus number of given bus' children * @bus: pointer to PCI bus structure to search @@ -1300,7 +1306,7 @@ pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask) /** * pci_select_bars - Make BAR mask from the type of resource - * @pdev: the PCI device for which BAR mask is made + * @dev: the PCI device for which BAR mask is made * @flags: resource type mask to be selected * * This helper routine makes bar mask from the type of resource. @@ -1333,6 +1339,10 @@ static int __devinit pci_setup(char *str) if (*str && (str = pcibios_setup(str)) && *str) { if (!strcmp(str, "nomsi")) { pci_no_msi(); + } else if (!strncmp(str, "cbiosize=", 9)) { + pci_cardbus_io_size = memparse(str + 9, &str); + } else if (!strncmp(str, "cbmemsize=", 10)) { + pci_cardbus_mem_size = memparse(str + 10, &str); } else { printk(KERN_ERR "PCI: Unknown option `%s'\n", str); diff --git a/drivers/pci/pcie/aer/aerdrv.h b/drivers/pci/pcie/aer/aerdrv.h index 3c0a58f64dd8..bf655dbaf8e2 100644 --- a/drivers/pci/pcie/aer/aerdrv.h +++ b/drivers/pci/pcie/aer/aerdrv.h @@ -85,7 +85,7 @@ struct aer_rpc { struct mutex rpc_mutex; /* * only one thread could do * recovery on the same - * root port hierachy + * root port hierarchy */ wait_queue_head_t wait_release; }; diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 89f3036f0de8..3554f3948814 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -36,13 +36,6 @@ #define ROUND_UP(x, a) (((x) + (a) - 1) & ~((a) - 1)) -/* - * FIXME: IO should be max 256 bytes. However, since we may - * have a P2P bridge below a cardbus bridge, we need 4K. - */ -#define CARDBUS_IO_SIZE (256) -#define CARDBUS_MEM_SIZE (64*1024*1024) - static void __devinit pbus_assign_resources_sorted(struct pci_bus *bus) { @@ -415,12 +408,12 @@ pci_bus_size_cardbus(struct pci_bus *bus) * Reserve some resources for CardBus. We reserve * a fixed amount of bus space for CardBus bridges. */ - b_res[0].start = CARDBUS_IO_SIZE; - b_res[0].end = b_res[0].start + CARDBUS_IO_SIZE - 1; + b_res[0].start = pci_cardbus_io_size; + b_res[0].end = b_res[0].start + pci_cardbus_io_size - 1; b_res[0].flags |= IORESOURCE_IO; - b_res[1].start = CARDBUS_IO_SIZE; - b_res[1].end = b_res[1].start + CARDBUS_IO_SIZE - 1; + b_res[1].start = pci_cardbus_io_size; + b_res[1].end = b_res[1].start + pci_cardbus_io_size - 1; b_res[1].flags |= IORESOURCE_IO; /* @@ -440,16 +433,16 @@ pci_bus_size_cardbus(struct pci_bus *bus) * twice the size. */ if (ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM0) { - b_res[2].start = CARDBUS_MEM_SIZE; - b_res[2].end = b_res[2].start + CARDBUS_MEM_SIZE - 1; + b_res[2].start = pci_cardbus_mem_size; + b_res[2].end = b_res[2].start + pci_cardbus_mem_size - 1; b_res[2].flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH; - b_res[3].start = CARDBUS_MEM_SIZE; - b_res[3].end = b_res[3].start + CARDBUS_MEM_SIZE - 1; + b_res[3].start = pci_cardbus_mem_size; + b_res[3].end = b_res[3].start + pci_cardbus_mem_size - 1; b_res[3].flags |= IORESOURCE_MEM; } else { - b_res[3].start = CARDBUS_MEM_SIZE * 2; - b_res[3].end = b_res[3].start + CARDBUS_MEM_SIZE * 2 - 1; + b_res[3].start = pci_cardbus_mem_size * 2; + b_res[3].end = b_res[3].start + pci_cardbus_mem_size * 2 - 1; b_res[3].flags |= IORESOURCE_MEM; } } diff --git a/drivers/pci/setup-irq.c b/drivers/pci/setup-irq.c index a251289c9958..568f1877315c 100644 --- a/drivers/pci/setup-irq.c +++ b/drivers/pci/setup-irq.c @@ -24,7 +24,7 @@ pdev_fixup_irq(struct pci_dev *dev, int (*map_irq)(struct pci_dev *, u8, u8)) { u8 pin, slot; - int irq; + int irq = 0; /* If this device is not on the primary bus, we need to figure out which interrupt pin it will come in on. We know which slot it @@ -33,16 +33,18 @@ pdev_fixup_irq(struct pci_dev *dev, apply the swizzle function. */ pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); - /* Cope with 0 and illegal. */ - if (pin == 0 || pin > 4) + /* Cope with illegal. */ + if (pin > 4) pin = 1; - /* Follow the chain of bridges, swizzling as we go. */ - slot = (*swizzle)(dev, &pin); + if (pin != 0) { + /* Follow the chain of bridges, swizzling as we go. */ + slot = (*swizzle)(dev, &pin); - irq = (*map_irq)(dev, slot, pin); - if (irq == -1) - irq = 0; + irq = (*map_irq)(dev, slot, pin); + if (irq == -1) + irq = 0; + } dev->irq = irq; pr_debug("PCI: fixup irq: (%s) got %d\n", diff --git a/drivers/pcmcia/at91_cf.c b/drivers/pcmcia/at91_cf.c index b31862837534..99baabc23599 100644 --- a/drivers/pcmcia/at91_cf.c +++ b/drivers/pcmcia/at91_cf.c @@ -277,7 +277,7 @@ static int __init at91_cf_probe(struct platform_device *pdev) board->det_pin, board->irq_pin); cf->socket.owner = THIS_MODULE; - cf->socket.dev.dev = &pdev->dev; + cf->socket.dev.parent = &pdev->dev; cf->socket.ops = &at91_cf_ops; cf->socket.resource_ops = &pccard_static_ops; cf->socket.features = SS_CAP_PCCARD | SS_CAP_STATIC_MAP diff --git a/drivers/pcmcia/cardbus.c b/drivers/pcmcia/cardbus.c index 2d7effe7990d..a1bd763b4e33 100644 --- a/drivers/pcmcia/cardbus.c +++ b/drivers/pcmcia/cardbus.c @@ -40,8 +40,6 @@ /*====================================================================*/ -#define FIND_FIRST_BIT(n) ((n) - ((n) & ((n)-1))) - /* Offsets in the Expansion ROM Image Header */ #define ROM_SIGNATURE 0x0000 /* 2 bytes */ #define ROM_DATA_PTR 0x0018 /* 2 bytes */ diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c index d2a3bea55de2..aa7779d89752 100644 --- a/drivers/pcmcia/soc_common.c +++ b/drivers/pcmcia/soc_common.c @@ -478,7 +478,7 @@ dump_bits(char **p, const char *prefix, unsigned int val, struct bittbl *bits, i * * Returns: the number of characters added to the buffer */ -static ssize_t show_status(struct device *dev, char *buf) +static ssize_t show_status(struct device *dev, struct device_attribute *attr, char *buf) { struct soc_pcmcia_socket *skt = container_of(dev, struct soc_pcmcia_socket, socket.dev); @@ -501,7 +501,7 @@ static ssize_t show_status(struct device *dev, char *buf) return p-buf; } -static CLASS_DEVICE_ATTR(status, S_IRUGO, show_status, NULL); +static DEVICE_ATTR(status, S_IRUGO, show_status, NULL); static struct pccard_operations soc_common_pcmcia_operations = { @@ -660,7 +660,7 @@ int soc_common_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops skt->socket.ops = &soc_common_pcmcia_operations; skt->socket.owner = ops->owner; - skt->socket.dev.dev = dev; + skt->socket.dev.parent = dev; init_timer(&skt->poll_timer); skt->poll_timer.function = soc_common_pcmcia_poll_event; @@ -747,7 +747,7 @@ int soc_common_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops add_timer(&skt->poll_timer); - device_create_file(&skt->socket.dev, &device_attr_status); + device_create_file(&skt->socket.dev, &dev_attr_status); } dev_set_drvdata(dev, sinfo); diff --git a/drivers/pnp/pnpacpi/Kconfig b/drivers/pnp/pnpacpi/Kconfig index ad27e5e0101f..b04767ce273e 100644 --- a/drivers/pnp/pnpacpi/Kconfig +++ b/drivers/pnp/pnpacpi/Kconfig @@ -2,17 +2,5 @@ # Plug and Play ACPI configuration # config PNPACPI - bool "Plug and Play ACPI support" - depends on PNP && ACPI - default y - ---help--- - Linux uses the PNPACPI to autodetect built-in - mainboard resources (e.g. parallel port resources). - - Some features (e.g. real hotplug) are not currently - implemented. - - If you would like the kernel to detect and allocate resources to - your mainboard devices (on some systems they are disabled by the - BIOS) say Y here. Also the PNPACPI can help prevent resource - conflicts between mainboard devices and other bus devices. + bool + default (PNP && ACPI) diff --git a/drivers/ps3/Makefile b/drivers/ps3/Makefile index 96958c03cf61..e251d1c1171c 100644 --- a/drivers/ps3/Makefile +++ b/drivers/ps3/Makefile @@ -1,2 +1,3 @@ obj-$(CONFIG_PS3_VUART) += vuart.o obj-$(CONFIG_PS3_PS3AV) += ps3av.o ps3av_cmd.o +obj-$(CONFIG_PS3_SYS_MANAGER) += sys-manager.o diff --git a/drivers/ps3/sys-manager.c b/drivers/ps3/sys-manager.c new file mode 100644 index 000000000000..0fc30be8b81e --- /dev/null +++ b/drivers/ps3/sys-manager.c @@ -0,0 +1,604 @@ +/* + * PS3 System Manager. + * + * Copyright (C) 2007 Sony Computer Entertainment Inc. + * Copyright 2007 Sony Corp. + * + * 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; version 2 of the License. + * + * 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/workqueue.h> +#include <linux/reboot.h> +#include <asm/ps3.h> +#include "vuart.h" + +MODULE_AUTHOR("Sony Corporation"); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("PS3 System Manager"); + +/** + * ps3_sys_manager - PS3 system manager driver. + * + * The system manager provides an asyncronous system event notification + * mechanism for reporting events like thermal alert and button presses to + * guests. It also provides support to control system shutdown and startup. + * + * The actual system manager is implemented as an application running in the + * system policy module in lpar_1. Guests communicate with the system manager + * through port 2 of the vuart using a simple packet message protocol. + * Messages are comprised of a fixed field header followed by a message + * specific payload. + */ + +/** + * struct ps3_sys_manager_header - System manager message header. + * @version: Header version, currently 1. + * @size: Header size in bytes, curently 16. + * @payload_size: Message payload size in bytes. + * @service_id: Message type, one of enum ps3_sys_manager_service_id. + */ + +struct ps3_sys_manager_header { + /* version 1 */ + u8 version; + u8 size; + u16 reserved_1; + u32 payload_size; + u16 service_id; + u16 reserved_2[3]; +}; + +/** + * @PS3_SM_RX_MSG_LEN - System manager received message length. + * + * Currently all messages received from the system manager are the same length + * (16 bytes header + 16 bytes payload = 32 bytes). This knowlege is used to + * simplify the logic. + */ + +enum { + PS3_SM_RX_MSG_LEN = 32, +}; + +/** + * enum ps3_sys_manager_service_id - Message header service_id. + * @PS3_SM_SERVICE_ID_REQUEST: guest --> sys_manager. + * @PS3_SM_SERVICE_ID_COMMAND: guest <-- sys_manager. + * @PS3_SM_SERVICE_ID_RESPONSE: guest --> sys_manager. + * @PS3_SM_SERVICE_ID_SET_ATTR: guest --> sys_manager. + * @PS3_SM_SERVICE_ID_EXTERN_EVENT: guest <-- sys_manager. + * @PS3_SM_SERVICE_ID_SET_NEXT_OP: guest --> sys_manager. + */ + +enum ps3_sys_manager_service_id { + /* version 1 */ + PS3_SM_SERVICE_ID_REQUEST = 1, + PS3_SM_SERVICE_ID_RESPONSE = 2, + PS3_SM_SERVICE_ID_COMMAND = 3, + PS3_SM_SERVICE_ID_EXTERN_EVENT = 4, + PS3_SM_SERVICE_ID_SET_NEXT_OP = 5, + PS3_SM_SERVICE_ID_SET_ATTR = 8, +}; + +/** + * enum ps3_sys_manager_attr - Notification attribute (bit position mask). + * @PS3_SM_ATTR_POWER: Power button. + * @PS3_SM_ATTR_RESET: Reset button, not available on retail console. + * @PS3_SM_ATTR_THERMAL: Sytem thermal alert. + * @PS3_SM_ATTR_CONTROLLER: Remote controller event. + * @PS3_SM_ATTR_ALL: Logical OR of all. + * + * The guest tells the system manager which events it is interested in receiving + * notice of by sending the system manager a logical OR of notification + * attributes via the ps3_sys_manager_send_attr() routine. + */ + +enum ps3_sys_manager_attr { + /* version 1 */ + PS3_SM_ATTR_POWER = 1, + PS3_SM_ATTR_RESET = 2, + PS3_SM_ATTR_THERMAL = 4, + PS3_SM_ATTR_CONTROLLER = 8, /* bogus? */ + PS3_SM_ATTR_ALL = 0x0f, +}; + +/** + * enum ps3_sys_manager_event - External event type, reported by system manager. + * @PS3_SM_EVENT_POWER_PRESSED: payload.value not used. + * @PS3_SM_EVENT_POWER_RELEASED: payload.value = time pressed in millisec. + * @PS3_SM_EVENT_RESET_PRESSED: payload.value not used. + * @PS3_SM_EVENT_RESET_RELEASED: payload.value = time pressed in millisec. + * @PS3_SM_EVENT_THERMAL_ALERT: payload.value = thermal zone id. + * @PS3_SM_EVENT_THERMAL_CLEARED: payload.value = thermal zone id. + */ + +enum ps3_sys_manager_event { + /* version 1 */ + PS3_SM_EVENT_POWER_PRESSED = 3, + PS3_SM_EVENT_POWER_RELEASED = 4, + PS3_SM_EVENT_RESET_PRESSED = 5, + PS3_SM_EVENT_RESET_RELEASED = 6, + PS3_SM_EVENT_THERMAL_ALERT = 7, + PS3_SM_EVENT_THERMAL_CLEARED = 8, + /* no info on controller events */ +}; + +/** + * enum ps3_sys_manager_next_op - Operation to perform after lpar is destroyed. + */ + +enum ps3_sys_manager_next_op { + /* version 3 */ + PS3_SM_NEXT_OP_SYS_SHUTDOWN = 1, + PS3_SM_NEXT_OP_SYS_REBOOT = 2, + PS3_SM_NEXT_OP_LPAR_REBOOT = 0x82, +}; + +/** + * enum ps3_sys_manager_wake_source - Next-op wakeup source (bit position mask). + * @PS3_SM_WAKE_DEFAULT: Disk insert, power button, eject button, IR + * controller, and bluetooth controller. + * @PS3_SM_WAKE_RTC: + * @PS3_SM_WAKE_RTC_ERROR: + * @PS3_SM_WAKE_P_O_R: Power on reset. + * + * Additional wakeup sources when specifying PS3_SM_NEXT_OP_SYS_SHUTDOWN. + * System will always wake from the PS3_SM_WAKE_DEFAULT sources. + */ + +enum ps3_sys_manager_wake_source { + /* version 3 */ + PS3_SM_WAKE_DEFAULT = 0, + PS3_SM_WAKE_RTC = 0x00000040, + PS3_SM_WAKE_RTC_ERROR = 0x00000080, + PS3_SM_WAKE_P_O_R = 0x10000000, +}; + +/** + * enum ps3_sys_manager_cmd - Command from system manager to guest. + * + * The guest completes the actions needed, then acks or naks the command via + * ps3_sys_manager_send_response(). In the case of @PS3_SM_CMD_SHUTDOWN, + * the guest must be fully prepared for a system poweroff prior to acking the + * command. + */ + +enum ps3_sys_manager_cmd { + /* version 1 */ + PS3_SM_CMD_SHUTDOWN = 1, /* shutdown guest OS */ +}; + +/** + * ps3_sys_manager_write - Helper to write a two part message to the vuart. + * + */ + +static int ps3_sys_manager_write(struct ps3_vuart_port_device *dev, + const struct ps3_sys_manager_header *header, const void *payload) +{ + int result; + + BUG_ON(header->version != 1); + BUG_ON(header->size != 16); + BUG_ON(header->payload_size != 8 && header->payload_size != 16); + BUG_ON(header->service_id > 8); + + result = ps3_vuart_write(dev, header, + sizeof(struct ps3_sys_manager_header)); + + if (!result) + result = ps3_vuart_write(dev, payload, header->payload_size); + + return result; +} + +/** + * ps3_sys_manager_send_attr - Send a 'set attribute' to the system manager. + * + */ + +static int ps3_sys_manager_send_attr(struct ps3_vuart_port_device *dev, + enum ps3_sys_manager_attr attr) +{ + static const struct ps3_sys_manager_header header = { + .version = 1, + .size = 16, + .payload_size = 16, + .service_id = PS3_SM_SERVICE_ID_SET_ATTR, + }; + struct { + u8 version; + u8 reserved_1[3]; + u32 attribute; + } payload; + + BUILD_BUG_ON(sizeof(payload) != 8); + + dev_dbg(&dev->core, "%s:%d: %xh\n", __func__, __LINE__, attr); + + memset(&payload, 0, sizeof(payload)); + payload.version = 1; + payload.attribute = attr; + + return ps3_sys_manager_write(dev, &header, &payload); +} + +/** + * ps3_sys_manager_send_next_op - Send a 'set next op' to the system manager. + * + * Tell the system manager what to do after this lpar is destroyed. + */ + +static int ps3_sys_manager_send_next_op(struct ps3_vuart_port_device *dev, + enum ps3_sys_manager_next_op op, + enum ps3_sys_manager_wake_source wake_source) +{ + static const struct ps3_sys_manager_header header = { + .version = 1, + .size = 16, + .payload_size = 16, + .service_id = PS3_SM_SERVICE_ID_SET_NEXT_OP, + }; + struct { + u8 version; + u8 type; + u8 gos_id; + u8 reserved_1; + u32 wake_source; + u8 reserved_2[8]; + } payload; + + BUILD_BUG_ON(sizeof(payload) != 16); + + dev_dbg(&dev->core, "%s:%d: (%xh)\n", __func__, __LINE__, op); + + memset(&payload, 0, sizeof(payload)); + payload.version = 3; + payload.type = op; + payload.gos_id = 3; /* other os */ + payload.wake_source = wake_source; + + return ps3_sys_manager_write(dev, &header, &payload); +} + +/** + * ps3_sys_manager_send_request_shutdown - Send 'request' to the system manager. + * + * The guest sends this message to request an operation or action of the system + * manager. The reply is a command message from the system manager. In the + * command handler the guest performs the requested operation. The result of + * the command is then communicated back to the system manager with a response + * message. + * + * Currently, the only supported request it the 'shutdown self' request. + */ + +static int ps3_sys_manager_send_request_shutdown(struct ps3_vuart_port_device *dev) +{ + static const struct ps3_sys_manager_header header = { + .version = 1, + .size = 16, + .payload_size = 16, + .service_id = PS3_SM_SERVICE_ID_REQUEST, + }; + struct { + u8 version; + u8 type; + u8 gos_id; + u8 reserved_1[13]; + } static const payload = { + .version = 1, + .type = 1, /* shutdown */ + .gos_id = 0, /* self */ + }; + + BUILD_BUG_ON(sizeof(payload) != 16); + + dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); + + return ps3_sys_manager_write(dev, &header, &payload); +} + +/** + * ps3_sys_manager_send_response - Send a 'response' to the system manager. + * @status: zero = success, others fail. + * + * The guest sends this message to the system manager to acnowledge success or + * failure of a command sent by the system manager. + */ + +static int ps3_sys_manager_send_response(struct ps3_vuart_port_device *dev, + u64 status) +{ + static const struct ps3_sys_manager_header header = { + .version = 1, + .size = 16, + .payload_size = 16, + .service_id = PS3_SM_SERVICE_ID_RESPONSE, + }; + struct { + u8 version; + u8 reserved_1[3]; + u8 status; + u8 reserved_2[11]; + } payload; + + BUILD_BUG_ON(sizeof(payload) != 16); + + dev_dbg(&dev->core, "%s:%d: (%s)\n", __func__, __LINE__, + (status ? "nak" : "ack")); + + memset(&payload, 0, sizeof(payload)); + payload.version = 1; + payload.status = status; + + return ps3_sys_manager_write(dev, &header, &payload); +} + +/** + * ps3_sys_manager_handle_event - Second stage event msg handler. + * + */ + +static int ps3_sys_manager_handle_event(struct ps3_vuart_port_device *dev) +{ + int result; + struct { + u8 version; + u8 type; + u8 reserved_1[2]; + u32 value; + u8 reserved_2[8]; + } event; + + BUILD_BUG_ON(sizeof(event) != 16); + + result = ps3_vuart_read(dev, &event, sizeof(event)); + BUG_ON(result); + + if (event.version != 1) { + dev_dbg(&dev->core, "%s:%d: unsupported event version (%u)\n", + __func__, __LINE__, event.version); + return -EIO; + } + + switch (event.type) { + case PS3_SM_EVENT_POWER_PRESSED: + dev_dbg(&dev->core, "%s:%d: POWER_PRESSED\n", + __func__, __LINE__); + break; + case PS3_SM_EVENT_POWER_RELEASED: + dev_dbg(&dev->core, "%s:%d: POWER_RELEASED (%u ms)\n", + __func__, __LINE__, event.value); + kill_cad_pid(SIGINT, 1); + break; + case PS3_SM_EVENT_THERMAL_ALERT: + dev_dbg(&dev->core, "%s:%d: THERMAL_ALERT (zone %u)\n", + __func__, __LINE__, event.value); + printk(KERN_INFO "PS3 Thermal Alert Zone %u\n", event.value); + break; + case PS3_SM_EVENT_THERMAL_CLEARED: + dev_dbg(&dev->core, "%s:%d: THERMAL_CLEARED (zone %u)\n", + __func__, __LINE__, event.value); + break; + default: + dev_dbg(&dev->core, "%s:%d: unknown event (%u)\n", + __func__, __LINE__, event.type); + return -EIO; + } + + return 0; +} +/** + * ps3_sys_manager_handle_cmd - Second stage command msg handler. + * + * The system manager sends this in reply to a 'request' message from the guest. + */ + +static int ps3_sys_manager_handle_cmd(struct ps3_vuart_port_device *dev) +{ + int result; + struct { + u8 version; + u8 type; + u8 reserved_1[14]; + } cmd; + + BUILD_BUG_ON(sizeof(cmd) != 16); + + dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); + + result = ps3_vuart_read(dev, &cmd, sizeof(cmd)); + + if(result) + return result; + + if (cmd.version != 1) { + dev_dbg(&dev->core, "%s:%d: unsupported cmd version (%u)\n", + __func__, __LINE__, cmd.version); + return -EIO; + } + + if (cmd.type != PS3_SM_CMD_SHUTDOWN) { + dev_dbg(&dev->core, "%s:%d: unknown cmd (%u)\n", + __func__, __LINE__, cmd.type); + return -EIO; + } + + ps3_sys_manager_send_response(dev, 0); + return 0; +} + +/** + * ps3_sys_manager_handle_msg - First stage msg handler. + * + */ + +static int ps3_sys_manager_handle_msg(struct ps3_vuart_port_device *dev) +{ + int result; + struct ps3_sys_manager_header header; + + result = ps3_vuart_read(dev, &header, + sizeof(struct ps3_sys_manager_header)); + + if(result) + return result; + + if (header.version != 1) { + dev_dbg(&dev->core, "%s:%d: unsupported header version (%u)\n", + __func__, __LINE__, header.version); + goto fail_header; + } + + BUILD_BUG_ON(sizeof(header) != 16); + BUG_ON(header.size != 16); + BUG_ON(header.payload_size != 16); + + switch (header.service_id) { + case PS3_SM_SERVICE_ID_EXTERN_EVENT: + dev_dbg(&dev->core, "%s:%d: EVENT\n", __func__, __LINE__); + return ps3_sys_manager_handle_event(dev); + case PS3_SM_SERVICE_ID_COMMAND: + dev_dbg(&dev->core, "%s:%d: COMMAND\n", __func__, __LINE__); + return ps3_sys_manager_handle_cmd(dev); + default: + dev_dbg(&dev->core, "%s:%d: unknown service_id (%u)\n", + __func__, __LINE__, header.service_id); + break; + } + goto fail_id; + +fail_header: + ps3_vuart_clear_rx_bytes(dev, 0); + return -EIO; +fail_id: + ps3_vuart_clear_rx_bytes(dev, header.payload_size); + return -EIO; +} + +/** + * ps3_sys_manager_work - Asyncronous read handler. + * + * Signaled when a complete message arrives at the vuart port. + */ + +static void ps3_sys_manager_work(struct work_struct *work) +{ + struct ps3_vuart_port_device *dev = ps3_vuart_work_to_port_device(work); + + ps3_sys_manager_handle_msg(dev); + ps3_vuart_read_async(dev, ps3_sys_manager_work, PS3_SM_RX_MSG_LEN); +} + +struct { + struct ps3_vuart_port_device *dev; +} static drv_priv; + +/** + * ps3_sys_manager_restart - The final platform machine_restart routine. + * + * This routine never returns. The routine disables asyncronous vuart reads + * then spins calling ps3_sys_manager_handle_msg() to receive and acknowledge + * the shutdown command sent from the system manager. Soon after the + * acknowledgement is sent the lpar is destroyed by the HV. This routine + * should only be called from ps3_restart(). + */ + +void ps3_sys_manager_restart(void) +{ + struct ps3_vuart_port_device *dev = drv_priv.dev; + + BUG_ON(!drv_priv.dev); + + dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); + + ps3_vuart_cancel_async(dev); + + ps3_sys_manager_send_attr(dev, 0); + ps3_sys_manager_send_next_op(dev, PS3_SM_NEXT_OP_LPAR_REBOOT, + PS3_SM_WAKE_DEFAULT); + ps3_sys_manager_send_request_shutdown(dev); + + printk(KERN_EMERG "System Halted, OK to turn off power\n"); + + while(1) + ps3_sys_manager_handle_msg(dev); +} + +/** + * ps3_sys_manager_power_off - The final platform machine_power_off routine. + * + * This routine never returns. The routine disables asyncronous vuart reads + * then spins calling ps3_sys_manager_handle_msg() to receive and acknowledge + * the shutdown command sent from the system manager. Soon after the + * acknowledgement is sent the lpar is destroyed by the HV. This routine + * should only be called from ps3_power_off(). + */ + +void ps3_sys_manager_power_off(void) +{ + struct ps3_vuart_port_device *dev = drv_priv.dev; + + BUG_ON(!drv_priv.dev); + + dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); + + ps3_vuart_cancel_async(dev); + + ps3_sys_manager_send_next_op(dev, PS3_SM_NEXT_OP_SYS_SHUTDOWN, + PS3_SM_WAKE_DEFAULT); + ps3_sys_manager_send_request_shutdown(dev); + + printk(KERN_EMERG "System Halted, OK to turn off power\n"); + + while(1) + ps3_sys_manager_handle_msg(dev); +} + +static int ps3_sys_manager_probe(struct ps3_vuart_port_device *dev) +{ + int result; + + dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); + + BUG_ON(drv_priv.dev); + drv_priv.dev = dev; + + result = ps3_sys_manager_send_attr(dev, PS3_SM_ATTR_ALL); + BUG_ON(result); + + result = ps3_vuart_read_async(dev, ps3_sys_manager_work, + PS3_SM_RX_MSG_LEN); + BUG_ON(result); + + return result; +} + +static struct ps3_vuart_port_driver ps3_sys_manager = { + .match_id = PS3_MATCH_ID_SYSTEM_MANAGER, + .core = { + .name = "ps3_sys_manager", + }, + .probe = ps3_sys_manager_probe, +}; + +static int __init ps3_sys_manager_init(void) +{ + return ps3_vuart_port_driver_register(&ps3_sys_manager); +} + +module_init(ps3_sys_manager_init); diff --git a/drivers/ps3/vuart.c b/drivers/ps3/vuart.c index ef8fd4c30875..746298107d6f 100644 --- a/drivers/ps3/vuart.c +++ b/drivers/ps3/vuart.c @@ -21,8 +21,10 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/interrupt.h> +#include <linux/workqueue.h> #include <asm/ps3.h> +#include <asm/firmware.h> #include <asm/lv1call.h> #include <asm/bitops.h> @@ -30,7 +32,7 @@ MODULE_AUTHOR("Sony Corporation"); MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("ps3 vuart"); +MODULE_DESCRIPTION("PS3 vuart"); /** * vuart - An inter-partition data link service. @@ -157,7 +159,7 @@ int ps3_vuart_get_triggers(struct ps3_vuart_port_device *dev, unsigned long size; unsigned long val; - result = lv1_get_virtual_uart_param(dev->port_number, + result = lv1_get_virtual_uart_param(dev->priv->port_number, PARAM_TX_TRIGGER, &trig->tx); if (result) { @@ -166,7 +168,7 @@ int ps3_vuart_get_triggers(struct ps3_vuart_port_device *dev, return result; } - result = lv1_get_virtual_uart_param(dev->port_number, + result = lv1_get_virtual_uart_param(dev->priv->port_number, PARAM_RX_BUF_SIZE, &size); if (result) { @@ -175,7 +177,7 @@ int ps3_vuart_get_triggers(struct ps3_vuart_port_device *dev, return result; } - result = lv1_get_virtual_uart_param(dev->port_number, + result = lv1_get_virtual_uart_param(dev->priv->port_number, PARAM_RX_TRIGGER, &val); if (result) { @@ -198,7 +200,7 @@ int ps3_vuart_set_triggers(struct ps3_vuart_port_device *dev, unsigned int tx, int result; unsigned long size; - result = lv1_set_virtual_uart_param(dev->port_number, + result = lv1_set_virtual_uart_param(dev->priv->port_number, PARAM_TX_TRIGGER, tx); if (result) { @@ -207,7 +209,7 @@ int ps3_vuart_set_triggers(struct ps3_vuart_port_device *dev, unsigned int tx, return result; } - result = lv1_get_virtual_uart_param(dev->port_number, + result = lv1_get_virtual_uart_param(dev->priv->port_number, PARAM_RX_BUF_SIZE, &size); if (result) { @@ -216,7 +218,7 @@ int ps3_vuart_set_triggers(struct ps3_vuart_port_device *dev, unsigned int tx, return result; } - result = lv1_set_virtual_uart_param(dev->port_number, + result = lv1_set_virtual_uart_param(dev->priv->port_number, PARAM_RX_TRIGGER, size - rx); if (result) { @@ -232,9 +234,9 @@ int ps3_vuart_set_triggers(struct ps3_vuart_port_device *dev, unsigned int tx, } static int ps3_vuart_get_rx_bytes_waiting(struct ps3_vuart_port_device *dev, - unsigned long *bytes_waiting) + u64 *bytes_waiting) { - int result = lv1_get_virtual_uart_param(dev->port_number, + int result = lv1_get_virtual_uart_param(dev->priv->port_number, PARAM_RX_BYTES, bytes_waiting); if (result) @@ -253,10 +255,10 @@ static int ps3_vuart_set_interrupt_mask(struct ps3_vuart_port_device *dev, dev_dbg(&dev->core, "%s:%d: %lxh\n", __func__, __LINE__, mask); - dev->interrupt_mask = mask; + dev->priv->interrupt_mask = mask; - result = lv1_set_virtual_uart_param(dev->port_number, - PARAM_INTERRUPT_MASK, dev->interrupt_mask); + result = lv1_set_virtual_uart_param(dev->priv->port_number, + PARAM_INTERRUPT_MASK, dev->priv->interrupt_mask); if (result) dev_dbg(&dev->core, "%s:%d: interrupt_mask failed: %s\n", @@ -265,62 +267,64 @@ static int ps3_vuart_set_interrupt_mask(struct ps3_vuart_port_device *dev, return result; } -static int ps3_vuart_get_interrupt_mask(struct ps3_vuart_port_device *dev, +static int ps3_vuart_get_interrupt_status(struct ps3_vuart_port_device *dev, unsigned long *status) { - int result = lv1_get_virtual_uart_param(dev->port_number, - PARAM_INTERRUPT_STATUS, status); + u64 tmp; + int result = lv1_get_virtual_uart_param(dev->priv->port_number, + PARAM_INTERRUPT_STATUS, &tmp); if (result) dev_dbg(&dev->core, "%s:%d: interrupt_status failed: %s\n", __func__, __LINE__, ps3_result(result)); + *status = tmp & dev->priv->interrupt_mask; + dev_dbg(&dev->core, "%s:%d: m %lxh, s %lxh, m&s %lxh\n", - __func__, __LINE__, dev->interrupt_mask, *status, - dev->interrupt_mask & *status); + __func__, __LINE__, dev->priv->interrupt_mask, tmp, *status); return result; } int ps3_vuart_enable_interrupt_tx(struct ps3_vuart_port_device *dev) { - return (dev->interrupt_mask & INTERRUPT_MASK_TX) ? 0 - : ps3_vuart_set_interrupt_mask(dev, dev->interrupt_mask + return (dev->priv->interrupt_mask & INTERRUPT_MASK_TX) ? 0 + : ps3_vuart_set_interrupt_mask(dev, dev->priv->interrupt_mask | INTERRUPT_MASK_TX); } int ps3_vuart_enable_interrupt_rx(struct ps3_vuart_port_device *dev) { - return (dev->interrupt_mask & INTERRUPT_MASK_RX) ? 0 - : ps3_vuart_set_interrupt_mask(dev, dev->interrupt_mask + return (dev->priv->interrupt_mask & INTERRUPT_MASK_RX) ? 0 + : ps3_vuart_set_interrupt_mask(dev, dev->priv->interrupt_mask | INTERRUPT_MASK_RX); } int ps3_vuart_enable_interrupt_disconnect(struct ps3_vuart_port_device *dev) { - return (dev->interrupt_mask & INTERRUPT_MASK_DISCONNECT) ? 0 - : ps3_vuart_set_interrupt_mask(dev, dev->interrupt_mask + return (dev->priv->interrupt_mask & INTERRUPT_MASK_DISCONNECT) ? 0 + : ps3_vuart_set_interrupt_mask(dev, dev->priv->interrupt_mask | INTERRUPT_MASK_DISCONNECT); } int ps3_vuart_disable_interrupt_tx(struct ps3_vuart_port_device *dev) { - return (dev->interrupt_mask & INTERRUPT_MASK_TX) - ? ps3_vuart_set_interrupt_mask(dev, dev->interrupt_mask + return (dev->priv->interrupt_mask & INTERRUPT_MASK_TX) + ? ps3_vuart_set_interrupt_mask(dev, dev->priv->interrupt_mask & ~INTERRUPT_MASK_TX) : 0; } int ps3_vuart_disable_interrupt_rx(struct ps3_vuart_port_device *dev) { - return (dev->interrupt_mask & INTERRUPT_MASK_RX) - ? ps3_vuart_set_interrupt_mask(dev, dev->interrupt_mask + return (dev->priv->interrupt_mask & INTERRUPT_MASK_RX) + ? ps3_vuart_set_interrupt_mask(dev, dev->priv->interrupt_mask & ~INTERRUPT_MASK_RX) : 0; } int ps3_vuart_disable_interrupt_disconnect(struct ps3_vuart_port_device *dev) { - return (dev->interrupt_mask & INTERRUPT_MASK_DISCONNECT) - ? ps3_vuart_set_interrupt_mask(dev, dev->interrupt_mask + return (dev->priv->interrupt_mask & INTERRUPT_MASK_DISCONNECT) + ? ps3_vuart_set_interrupt_mask(dev, dev->priv->interrupt_mask & ~INTERRUPT_MASK_DISCONNECT) : 0; } @@ -335,9 +339,7 @@ static int ps3_vuart_raw_write(struct ps3_vuart_port_device *dev, { int result; - dev_dbg(&dev->core, "%s:%d: %xh\n", __func__, __LINE__, bytes); - - result = lv1_write_virtual_uart(dev->port_number, + result = lv1_write_virtual_uart(dev->priv->port_number, ps3_mm_phys_to_lpar(__pa(buf)), bytes, bytes_written); if (result) { @@ -346,10 +348,10 @@ static int ps3_vuart_raw_write(struct ps3_vuart_port_device *dev, return result; } - dev->stats.bytes_written += *bytes_written; + dev->priv->stats.bytes_written += *bytes_written; - dev_dbg(&dev->core, "%s:%d: wrote %lxh/%xh=>%lxh\n", __func__, - __LINE__, *bytes_written, bytes, dev->stats.bytes_written); + dev_dbg(&dev->core, "%s:%d: wrote %lxh/%xh=>%lxh\n", __func__, __LINE__, + *bytes_written, bytes, dev->priv->stats.bytes_written); return result; } @@ -367,7 +369,7 @@ static int ps3_vuart_raw_read(struct ps3_vuart_port_device *dev, void* buf, dev_dbg(&dev->core, "%s:%d: %xh\n", __func__, __LINE__, bytes); - result = lv1_read_virtual_uart(dev->port_number, + result = lv1_read_virtual_uart(dev->priv->port_number, ps3_mm_phys_to_lpar(__pa(buf)), bytes, bytes_read); if (result) { @@ -376,15 +378,58 @@ static int ps3_vuart_raw_read(struct ps3_vuart_port_device *dev, void* buf, return result; } - dev->stats.bytes_read += *bytes_read; + dev->priv->stats.bytes_read += *bytes_read; dev_dbg(&dev->core, "%s:%d: read %lxh/%xh=>%lxh\n", __func__, __LINE__, - *bytes_read, bytes, dev->stats.bytes_read); + *bytes_read, bytes, dev->priv->stats.bytes_read); return result; } /** + * ps3_vuart_clear_rx_bytes - Discard bytes received. + * @bytes: Max byte count to discard, zero = all pending. + * + * Used to clear pending rx interrupt source. Will not block. + */ + +void ps3_vuart_clear_rx_bytes(struct ps3_vuart_port_device *dev, + unsigned int bytes) +{ + int result; + u64 bytes_waiting; + void* tmp; + + result = ps3_vuart_get_rx_bytes_waiting(dev, &bytes_waiting); + + BUG_ON(result); + + bytes = bytes ? min(bytes, (unsigned int)bytes_waiting) : bytes_waiting; + + dev_dbg(&dev->core, "%s:%d: %u\n", __func__, __LINE__, bytes); + + if (!bytes) + return; + + /* Add some extra space for recently arrived data. */ + + bytes += 128; + + tmp = kmalloc(bytes, GFP_KERNEL); + + if (!tmp) + return; + + ps3_vuart_raw_read(dev, tmp, bytes, &bytes_waiting); + + kfree(tmp); + + /* Don't include these bytes in the stats. */ + + dev->priv->stats.bytes_read -= bytes_waiting; +} + +/** * struct list_buffer - An element for a port device fifo buffer list. */ @@ -416,14 +461,14 @@ int ps3_vuart_write(struct ps3_vuart_port_device *dev, const void* buf, dev_dbg(&dev->core, "%s:%d: %u(%xh) bytes\n", __func__, __LINE__, bytes, bytes); - spin_lock_irqsave(&dev->tx_list.lock, flags); + spin_lock_irqsave(&dev->priv->tx_list.lock, flags); - if (list_empty(&dev->tx_list.head)) { + if (list_empty(&dev->priv->tx_list.head)) { unsigned long bytes_written; result = ps3_vuart_raw_write(dev, buf, bytes, &bytes_written); - spin_unlock_irqrestore(&dev->tx_list.lock, flags); + spin_unlock_irqrestore(&dev->priv->tx_list.lock, flags); if (result) { dev_dbg(&dev->core, @@ -441,7 +486,7 @@ int ps3_vuart_write(struct ps3_vuart_port_device *dev, const void* buf, bytes -= bytes_written; buf += bytes_written; } else - spin_unlock_irqrestore(&dev->tx_list.lock, flags); + spin_unlock_irqrestore(&dev->priv->tx_list.lock, flags); lb = kmalloc(sizeof(struct list_buffer) + bytes, GFP_KERNEL); @@ -454,10 +499,10 @@ int ps3_vuart_write(struct ps3_vuart_port_device *dev, const void* buf, lb->tail = lb->data + bytes; lb->dbg_number = ++dbg_number; - spin_lock_irqsave(&dev->tx_list.lock, flags); - list_add_tail(&lb->link, &dev->tx_list.head); + spin_lock_irqsave(&dev->priv->tx_list.lock, flags); + list_add_tail(&lb->link, &dev->priv->tx_list.head); ps3_vuart_enable_interrupt_tx(dev); - spin_unlock_irqrestore(&dev->tx_list.lock, flags); + spin_unlock_irqrestore(&dev->priv->tx_list.lock, flags); dev_dbg(&dev->core, "%s:%d: queued buf_%lu, %xh bytes\n", __func__, __LINE__, lb->dbg_number, bytes); @@ -484,47 +529,83 @@ int ps3_vuart_read(struct ps3_vuart_port_device *dev, void* buf, dev_dbg(&dev->core, "%s:%d: %u(%xh) bytes\n", __func__, __LINE__, bytes, bytes); - spin_lock_irqsave(&dev->rx_list.lock, flags); + spin_lock_irqsave(&dev->priv->rx_list.lock, flags); - if (dev->rx_list.bytes_held < bytes) { - spin_unlock_irqrestore(&dev->rx_list.lock, flags); + if (dev->priv->rx_list.bytes_held < bytes) { + spin_unlock_irqrestore(&dev->priv->rx_list.lock, flags); dev_dbg(&dev->core, "%s:%d: starved for %lxh bytes\n", - __func__, __LINE__, bytes - dev->rx_list.bytes_held); + __func__, __LINE__, + bytes - dev->priv->rx_list.bytes_held); return -EAGAIN; } - list_for_each_entry_safe(lb, n, &dev->rx_list.head, link) { + list_for_each_entry_safe(lb, n, &dev->priv->rx_list.head, link) { bytes_read = min((unsigned int)(lb->tail - lb->head), bytes); memcpy(buf, lb->head, bytes_read); buf += bytes_read; bytes -= bytes_read; - dev->rx_list.bytes_held -= bytes_read; + dev->priv->rx_list.bytes_held -= bytes_read; if (bytes_read < lb->tail - lb->head) { lb->head += bytes_read; - spin_unlock_irqrestore(&dev->rx_list.lock, flags); - - dev_dbg(&dev->core, - "%s:%d: dequeued buf_%lu, %lxh bytes\n", - __func__, __LINE__, lb->dbg_number, bytes_read); + dev_dbg(&dev->core, "%s:%d: buf_%lu: dequeued %lxh " + "bytes\n", __func__, __LINE__, lb->dbg_number, + bytes_read); + spin_unlock_irqrestore(&dev->priv->rx_list.lock, flags); return 0; } - dev_dbg(&dev->core, "%s:%d free buf_%lu\n", __func__, __LINE__, - lb->dbg_number); + dev_dbg(&dev->core, "%s:%d: buf_%lu: free, dequeued %lxh " + "bytes\n", __func__, __LINE__, lb->dbg_number, + bytes_read); list_del(&lb->link); kfree(lb); } - spin_unlock_irqrestore(&dev->rx_list.lock, flags); - dev_dbg(&dev->core, "%s:%d: dequeued buf_%lu, %xh bytes\n", - __func__, __LINE__, lb->dbg_number, bytes); + spin_unlock_irqrestore(&dev->priv->rx_list.lock, flags); + return 0; +} + +int ps3_vuart_read_async(struct ps3_vuart_port_device *dev, work_func_t func, + unsigned int bytes) +{ + unsigned long flags; + + if(dev->priv->work.trigger) { + dev_dbg(&dev->core, "%s:%d: warning, multiple calls\n", + __func__, __LINE__); + return -EAGAIN; + } + + BUG_ON(!bytes); + + PREPARE_WORK(&dev->priv->work.work, func); + + spin_lock_irqsave(&dev->priv->work.lock, flags); + if(dev->priv->rx_list.bytes_held >= bytes) { + dev_dbg(&dev->core, "%s:%d: schedule_work %xh bytes\n", + __func__, __LINE__, bytes); + schedule_work(&dev->priv->work.work); + spin_unlock_irqrestore(&dev->priv->work.lock, flags); + return 0; + } + + dev->priv->work.trigger = bytes; + spin_unlock_irqrestore(&dev->priv->work.lock, flags); + + dev_dbg(&dev->core, "%s:%d: waiting for %u(%xh) bytes\n", __func__, + __LINE__, bytes, bytes); return 0; } +void ps3_vuart_cancel_async(struct ps3_vuart_port_device *dev) +{ + dev->priv->work.trigger = 0; +} + /** * ps3_vuart_handle_interrupt_tx - third stage transmit interrupt handler * @@ -542,9 +623,9 @@ static int ps3_vuart_handle_interrupt_tx(struct ps3_vuart_port_device *dev) dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); - spin_lock_irqsave(&dev->tx_list.lock, flags); + spin_lock_irqsave(&dev->priv->tx_list.lock, flags); - list_for_each_entry_safe(lb, n, &dev->tx_list.head, link) { + list_for_each_entry_safe(lb, n, &dev->priv->tx_list.head, link) { unsigned long bytes_written; @@ -578,7 +659,7 @@ static int ps3_vuart_handle_interrupt_tx(struct ps3_vuart_port_device *dev) ps3_vuart_disable_interrupt_tx(dev); port_full: - spin_unlock_irqrestore(&dev->tx_list.lock, flags); + spin_unlock_irqrestore(&dev->priv->tx_list.lock, flags); dev_dbg(&dev->core, "%s:%d wrote %lxh bytes total\n", __func__, __LINE__, bytes_total); return result; @@ -609,7 +690,7 @@ static int ps3_vuart_handle_interrupt_rx(struct ps3_vuart_port_device *dev) BUG_ON(!bytes); - /* add some extra space for recently arrived data */ + /* Add some extra space for recently arrived data. */ bytes += 128; @@ -624,14 +705,23 @@ static int ps3_vuart_handle_interrupt_rx(struct ps3_vuart_port_device *dev) lb->tail = lb->data + bytes; lb->dbg_number = ++dbg_number; - spin_lock_irqsave(&dev->rx_list.lock, flags); - list_add_tail(&lb->link, &dev->rx_list.head); - dev->rx_list.bytes_held += bytes; - spin_unlock_irqrestore(&dev->rx_list.lock, flags); + spin_lock_irqsave(&dev->priv->rx_list.lock, flags); + list_add_tail(&lb->link, &dev->priv->rx_list.head); + dev->priv->rx_list.bytes_held += bytes; + spin_unlock_irqrestore(&dev->priv->rx_list.lock, flags); - dev_dbg(&dev->core, "%s:%d: queued buf_%lu, %lxh bytes\n", + dev_dbg(&dev->core, "%s:%d: buf_%lu: queued %lxh bytes\n", __func__, __LINE__, lb->dbg_number, bytes); + spin_lock_irqsave(&dev->priv->work.lock, flags); + if(dev->priv->work.trigger + && dev->priv->rx_list.bytes_held >= dev->priv->work.trigger) { + dev_dbg(&dev->core, "%s:%d: schedule_work %lxh bytes\n", + __func__, __LINE__, dev->priv->work.trigger); + dev->priv->work.trigger = 0; + schedule_work(&dev->priv->work.work); + } + spin_unlock_irqrestore(&dev->priv->work.lock, flags); return 0; } @@ -656,7 +746,7 @@ static int ps3_vuart_handle_port_interrupt(struct ps3_vuart_port_device *dev) int result; unsigned long status; - result = ps3_vuart_get_interrupt_mask(dev, &status); + result = ps3_vuart_get_interrupt_status(dev, &status); if (result) return result; @@ -665,21 +755,21 @@ static int ps3_vuart_handle_port_interrupt(struct ps3_vuart_port_device *dev) status); if (status & INTERRUPT_MASK_DISCONNECT) { - dev->stats.disconnect_interrupts++; + dev->priv->stats.disconnect_interrupts++; result = ps3_vuart_handle_interrupt_disconnect(dev); if (result) ps3_vuart_disable_interrupt_disconnect(dev); } if (status & INTERRUPT_MASK_TX) { - dev->stats.tx_interrupts++; + dev->priv->stats.tx_interrupts++; result = ps3_vuart_handle_interrupt_tx(dev); if (result) ps3_vuart_disable_interrupt_tx(dev); } if (status & INTERRUPT_MASK_RX) { - dev->stats.rx_interrupts++; + dev->priv->stats.rx_interrupts++; result = ps3_vuart_handle_interrupt_rx(dev); if (result) ps3_vuart_disable_interrupt_rx(dev); @@ -688,12 +778,13 @@ static int ps3_vuart_handle_port_interrupt(struct ps3_vuart_port_device *dev) return 0; } -struct vuart_private { - unsigned int in_use; +struct vuart_bus_priv { + const struct ports_bmp bmp; unsigned int virq; + struct semaphore probe_mutex; + int use_count; struct ps3_vuart_port_device *devices[PORT_COUNT]; - const struct ports_bmp bmp; -}; +} static vuart_bus_priv; /** * ps3_vuart_irq_handler - first stage interrupt handler @@ -705,25 +796,25 @@ struct vuart_private { static irqreturn_t ps3_vuart_irq_handler(int irq, void *_private) { - struct vuart_private *private; + struct vuart_bus_priv *bus_priv; BUG_ON(!_private); - private = (struct vuart_private *)_private; + bus_priv = (struct vuart_bus_priv *)_private; while (1) { unsigned int port; - dump_ports_bmp(&private->bmp); + dump_ports_bmp(&bus_priv->bmp); - port = (BITS_PER_LONG - 1) - __ilog2(private->bmp.status); + port = (BITS_PER_LONG - 1) - __ilog2(bus_priv->bmp.status); if (port == BITS_PER_LONG) break; BUG_ON(port >= PORT_COUNT); - BUG_ON(!private->devices[port]); + BUG_ON(!bus_priv->devices[port]); - ps3_vuart_handle_port_interrupt(private->devices[port]); + ps3_vuart_handle_port_interrupt(bus_priv->devices[port]); } return IRQ_HANDLED; @@ -744,12 +835,10 @@ static int ps3_vuart_match(struct device *_dev, struct device_driver *_drv) return result; } -static struct vuart_private vuart_private; - static int ps3_vuart_probe(struct device *_dev) { int result; - unsigned long tmp; + unsigned int port_number; struct ps3_vuart_port_device *dev = to_ps3_vuart_port_device(_dev); struct ps3_vuart_port_driver *drv = to_ps3_vuart_port_driver(_dev->driver); @@ -758,7 +847,12 @@ static int ps3_vuart_probe(struct device *_dev) BUG_ON(!drv); - result = ps3_vuart_match_id_to_port(dev->match_id, &dev->port_number); + down(&vuart_bus_priv.probe_mutex); + + /* Setup vuart_bus_priv.devices[]. */ + + result = ps3_vuart_match_id_to_port(dev->match_id, + &port_number); if (result) { dev_dbg(&dev->core, "%s:%d: unknown match_id (%d)\n", @@ -767,24 +861,41 @@ static int ps3_vuart_probe(struct device *_dev) goto fail_match; } - if (vuart_private.devices[dev->port_number]) { + if (vuart_bus_priv.devices[port_number]) { dev_dbg(&dev->core, "%s:%d: port busy (%d)\n", __func__, - __LINE__, dev->port_number); + __LINE__, port_number); result = -EBUSY; goto fail_match; } - vuart_private.devices[dev->port_number] = dev; + vuart_bus_priv.devices[port_number] = dev; + + /* Setup dev->priv. */ + + dev->priv = kzalloc(sizeof(struct ps3_vuart_port_priv), GFP_KERNEL); + + if (!dev->priv) { + result = -ENOMEM; + goto fail_alloc; + } - INIT_LIST_HEAD(&dev->tx_list.head); - spin_lock_init(&dev->tx_list.lock); - INIT_LIST_HEAD(&dev->rx_list.head); - spin_lock_init(&dev->rx_list.lock); + dev->priv->port_number = port_number; + + INIT_LIST_HEAD(&dev->priv->tx_list.head); + spin_lock_init(&dev->priv->tx_list.lock); + + INIT_LIST_HEAD(&dev->priv->rx_list.head); + spin_lock_init(&dev->priv->rx_list.lock); + + INIT_WORK(&dev->priv->work.work, NULL); + spin_lock_init(&dev->priv->work.lock); + dev->priv->work.trigger = 0; + dev->priv->work.dev = dev; + + if (++vuart_bus_priv.use_count == 1) { - vuart_private.in_use++; - if (vuart_private.in_use == 1) { result = ps3_alloc_vuart_irq(PS3_BINDING_CPU_ANY, - (void*)&vuart_private.bmp.status, &vuart_private.virq); + (void*)&vuart_bus_priv.bmp.status, &vuart_bus_priv.virq); if (result) { dev_dbg(&dev->core, @@ -794,8 +905,8 @@ static int ps3_vuart_probe(struct device *_dev) goto fail_alloc_irq; } - result = request_irq(vuart_private.virq, ps3_vuart_irq_handler, - IRQF_DISABLED, "vuart", &vuart_private); + result = request_irq(vuart_bus_priv.virq, ps3_vuart_irq_handler, + IRQF_DISABLED, "vuart", &vuart_bus_priv); if (result) { dev_info(&dev->core, "%s:%d: request_irq failed (%d)\n", @@ -804,10 +915,11 @@ static int ps3_vuart_probe(struct device *_dev) } } - ps3_vuart_set_interrupt_mask(dev, INTERRUPT_MASK_RX); - /* clear stale pending interrupts */ - ps3_vuart_get_interrupt_mask(dev, &tmp); + + ps3_vuart_clear_rx_bytes(dev, 0); + + ps3_vuart_set_interrupt_mask(dev, INTERRUPT_MASK_RX); ps3_vuart_set_triggers(dev, 1, 1); @@ -822,20 +934,27 @@ static int ps3_vuart_probe(struct device *_dev) if (result) { dev_dbg(&dev->core, "%s:%d: drv->probe failed\n", __func__, __LINE__); + down(&vuart_bus_priv.probe_mutex); goto fail_probe; } + up(&vuart_bus_priv.probe_mutex); + return result; fail_probe: + ps3_vuart_set_interrupt_mask(dev, 0); fail_request_irq: - vuart_private.in_use--; - if (!vuart_private.in_use) { - ps3_free_vuart_irq(vuart_private.virq); - vuart_private.virq = NO_IRQ; - } + ps3_free_vuart_irq(vuart_bus_priv.virq); + vuart_bus_priv.virq = NO_IRQ; fail_alloc_irq: + --vuart_bus_priv.use_count; + kfree(dev->priv); + dev->priv = NULL; +fail_alloc: + vuart_bus_priv.devices[port_number] = 0; fail_match: + up(&vuart_bus_priv.probe_mutex); dev_dbg(&dev->core, "%s:%d failed\n", __func__, __LINE__); return result; } @@ -846,10 +965,12 @@ static int ps3_vuart_remove(struct device *_dev) struct ps3_vuart_port_driver *drv = to_ps3_vuart_port_driver(_dev->driver); + down(&vuart_bus_priv.probe_mutex); + dev_dbg(&dev->core, "%s:%d: %s\n", __func__, __LINE__, dev->core.bus_id); - BUG_ON(vuart_private.in_use < 1); + BUG_ON(vuart_bus_priv.use_count < 1); if (drv->remove) drv->remove(dev); @@ -857,13 +978,19 @@ static int ps3_vuart_remove(struct device *_dev) dev_dbg(&dev->core, "%s:%d: %s no remove method\n", __func__, __LINE__, dev->core.bus_id); - vuart_private.in_use--; + vuart_bus_priv.devices[dev->priv->port_number] = 0; - if (!vuart_private.in_use) { - free_irq(vuart_private.virq, &vuart_private); - ps3_free_vuart_irq(vuart_private.virq); - vuart_private.virq = NO_IRQ; + if (--vuart_bus_priv.use_count == 0) { + BUG(); + free_irq(vuart_bus_priv.virq, &vuart_bus_priv); + ps3_free_vuart_irq(vuart_bus_priv.virq); + vuart_bus_priv.virq = NO_IRQ; } + + kfree(dev->priv); + dev->priv = NULL; + + up(&vuart_bus_priv.probe_mutex); return 0; } @@ -884,12 +1011,12 @@ static void ps3_vuart_shutdown(struct device *_dev) } /** - * ps3_vuart - The vuart instance. + * ps3_vuart_bus - The vuart bus instance. * * The vuart is managed as a bus that port devices connect to. */ -struct bus_type ps3_vuart = { +struct bus_type ps3_vuart_bus = { .name = "ps3_vuart", .match = ps3_vuart_match, .probe = ps3_vuart_probe, @@ -897,24 +1024,30 @@ struct bus_type ps3_vuart = { .shutdown = ps3_vuart_shutdown, }; -int __init ps3_vuart_init(void) +int __init ps3_vuart_bus_init(void) { int result; pr_debug("%s:%d:\n", __func__, __LINE__); - result = bus_register(&ps3_vuart); + + if (!firmware_has_feature(FW_FEATURE_PS3_LV1)) + return 0; + + init_MUTEX(&vuart_bus_priv.probe_mutex); + result = bus_register(&ps3_vuart_bus); BUG_ON(result); + return result; } -void __exit ps3_vuart_exit(void) +void __exit ps3_vuart_bus_exit(void) { pr_debug("%s:%d:\n", __func__, __LINE__); - bus_unregister(&ps3_vuart); + bus_unregister(&ps3_vuart_bus); } -core_initcall(ps3_vuart_init); -module_exit(ps3_vuart_exit); +core_initcall(ps3_vuart_bus_init); +module_exit(ps3_vuart_bus_exit); /** * ps3_vuart_port_release_device - Remove a vuart port device. @@ -922,11 +1055,14 @@ module_exit(ps3_vuart_exit); static void ps3_vuart_port_release_device(struct device *_dev) { - struct ps3_vuart_port_device *dev = to_ps3_vuart_port_device(_dev); #if defined(DEBUG) - memset(dev, 0xad, sizeof(struct ps3_vuart_port_device)); + struct ps3_vuart_port_device *dev = to_ps3_vuart_port_device(_dev); + + dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); + + BUG_ON(dev->priv && "forgot to free"); + memset(&dev->core, 0, sizeof(dev->core)); #endif - kfree(dev); } /** @@ -935,11 +1071,12 @@ static void ps3_vuart_port_release_device(struct device *_dev) int ps3_vuart_port_device_register(struct ps3_vuart_port_device *dev) { - int result; static unsigned int dev_count = 1; + BUG_ON(dev->priv && "forgot to free"); + dev->core.parent = NULL; - dev->core.bus = &ps3_vuart; + dev->core.bus = &ps3_vuart_bus; dev->core.release = ps3_vuart_port_release_device; snprintf(dev->core.bus_id, sizeof(dev->core.bus_id), "vuart_%02x", @@ -947,9 +1084,7 @@ int ps3_vuart_port_device_register(struct ps3_vuart_port_device *dev) dev_dbg(&dev->core, "%s:%d register\n", __func__, __LINE__); - result = device_register(&dev->core); - - return result; + return device_register(&dev->core); } EXPORT_SYMBOL_GPL(ps3_vuart_port_device_register); @@ -963,7 +1098,7 @@ int ps3_vuart_port_driver_register(struct ps3_vuart_port_driver *drv) int result; pr_debug("%s:%d: (%s)\n", __func__, __LINE__, drv->core.name); - drv->core.bus = &ps3_vuart; + drv->core.bus = &ps3_vuart_bus; result = driver_register(&drv->core); return result; } @@ -976,6 +1111,7 @@ EXPORT_SYMBOL_GPL(ps3_vuart_port_driver_register); void ps3_vuart_port_driver_unregister(struct ps3_vuart_port_driver *drv) { + pr_debug("%s:%d: (%s)\n", __func__, __LINE__, drv->core.name); driver_unregister(&drv->core); } diff --git a/drivers/ps3/vuart.h b/drivers/ps3/vuart.h index 2cbf728a3a0b..1be992d568c8 100644 --- a/drivers/ps3/vuart.h +++ b/drivers/ps3/vuart.h @@ -21,6 +21,44 @@ #if !defined(_PS3_VUART_H) #define _PS3_VUART_H +#include <asm/ps3.h> + +struct ps3_vuart_stats { + unsigned long bytes_written; + unsigned long bytes_read; + unsigned long tx_interrupts; + unsigned long rx_interrupts; + unsigned long disconnect_interrupts; +}; + +struct ps3_vuart_work { + struct work_struct work; + unsigned long trigger; + spinlock_t lock; + struct ps3_vuart_port_device* dev; /* to convert work to device */ +}; + +/** + * struct ps3_vuart_port_priv - private vuart device data. + */ + +struct ps3_vuart_port_priv { + unsigned int port_number; + u64 interrupt_mask; + + struct { + spinlock_t lock; + struct list_head head; + } tx_list; + struct { + unsigned long bytes_held; + spinlock_t lock; + struct list_head head; + } rx_list; + struct ps3_vuart_stats stats; + struct ps3_vuart_work work; +}; + /** * struct ps3_vuart_port_driver - a driver for a device on a vuart port */ @@ -41,10 +79,6 @@ struct ps3_vuart_port_driver { int ps3_vuart_port_driver_register(struct ps3_vuart_port_driver *drv); void ps3_vuart_port_driver_unregister(struct ps3_vuart_port_driver *drv); -int ps3_vuart_write(struct ps3_vuart_port_device *dev, - const void* buf, unsigned int bytes); -int ps3_vuart_read(struct ps3_vuart_port_device *dev, void* buf, - unsigned int bytes); static inline struct ps3_vuart_port_driver *to_ps3_vuart_port_driver( struct device_driver *_drv) { @@ -55,5 +89,22 @@ static inline struct ps3_vuart_port_device *to_ps3_vuart_port_device( { return container_of(_dev, struct ps3_vuart_port_device, core); } +static inline struct ps3_vuart_port_device *ps3_vuart_work_to_port_device( + struct work_struct *_work) +{ + struct ps3_vuart_work *vw = container_of(_work, struct ps3_vuart_work, + work); + return vw->dev; +} + +int ps3_vuart_write(struct ps3_vuart_port_device *dev, const void* buf, + unsigned int bytes); +int ps3_vuart_read(struct ps3_vuart_port_device *dev, void* buf, + unsigned int bytes); +int ps3_vuart_read_async(struct ps3_vuart_port_device *dev, work_func_t func, + unsigned int bytes); +void ps3_vuart_cancel_async(struct ps3_vuart_port_device *dev); +void ps3_vuart_clear_rx_bytes(struct ps3_vuart_port_device *dev, + unsigned int bytes); #endif diff --git a/drivers/sbus/char/vfc_i2c.c b/drivers/sbus/char/vfc_i2c.c index ceec30648f4f..9efed771f6c0 100644 --- a/drivers/sbus/char/vfc_i2c.c +++ b/drivers/sbus/char/vfc_i2c.c @@ -14,7 +14,7 @@ /* NOTE: It seems to me that the documentation regarding the pcd8584t/pcf8584 does not show the correct way to address the i2c bus. Based on the information on the I2C bus itself and the remainder of -the Phillips docs the following algorithims apper to be correct. I am +the Phillips docs the following algorithms appear to be correct. I am fairly certain that the flowcharts in the phillips docs are wrong. */ diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 5bf3f07870ba..4cd280e86966 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -230,6 +230,7 @@ config SCSI_SCAN_ASYNC The SCSI subsystem can probe for devices while the rest of the system continues booting, and even probe devices on different busses in parallel, leading to a significant speed-up. + If you have built SCSI as modules, enabling this option can be a problem as the devices may not have been found by the time your system expects them to have been. You can load the @@ -237,8 +238,8 @@ config SCSI_SCAN_ASYNC If you build your SCSI drivers into the kernel, then everything will work fine if you say Y here. - You can override this choice by specifying scsi_mod.scan="sync" - or "async" on the kernel's command line. + You can override this choice by specifying "scsi_mod.scan=sync" + or async on the kernel's command line. menu "SCSI Transports" depends on SCSI diff --git a/drivers/scsi/a100u2w.c b/drivers/scsi/a100u2w.c index 2650a5d0a161..7f4241bfb9c4 100644 --- a/drivers/scsi/a100u2w.c +++ b/drivers/scsi/a100u2w.c @@ -1067,7 +1067,7 @@ static int __devinit inia100_probe_one(struct pci_dev *pdev, goto out_disable_device; } - /* <02> read from base address + 0x50 offset to get the bios balue. */ + /* <02> read from base address + 0x50 offset to get the bios value. */ bios = ORC_RDWORD(port, 0x50); diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c index c7fe478f4813..2be03e975d97 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c @@ -418,7 +418,6 @@ ahd_linux_info(struct Scsi_Host *host) strcat(bp, " "); ahd_controller_info(ahd, ahd_info); strcat(bp, ahd_info); - strcat(bp, "\n"); return (bp); } diff --git a/drivers/scsi/aic94xx/aic94xx_seq.c b/drivers/scsi/aic94xx/aic94xx_seq.c index eae7a247bece..c750fbf7013b 100644 --- a/drivers/scsi/aic94xx/aic94xx_seq.c +++ b/drivers/scsi/aic94xx/aic94xx_seq.c @@ -44,7 +44,6 @@ #define PAUSE_TRIES 1000 static const struct firmware *sequencer_fw; -static const char *sequencer_version; static u16 cseq_vecs[CSEQ_NUM_VECS], lseq_vecs[LSEQ_NUM_VECS], mode2_task, cseq_idle_loop, lseq_idle_loop; static u8 *cseq_code, *lseq_code; @@ -1276,7 +1275,6 @@ static int asd_request_firmware(struct asd_ha_struct *asd_ha) header.csum = le32_to_cpu(hdr_ptr->csum); header.major = le32_to_cpu(hdr_ptr->major); header.minor = le32_to_cpu(hdr_ptr->minor); - sequencer_version = hdr_ptr->version; header.cseq_table_offset = le32_to_cpu(hdr_ptr->cseq_table_offset); header.cseq_table_size = le32_to_cpu(hdr_ptr->cseq_table_size); header.lseq_table_offset = le32_to_cpu(hdr_ptr->lseq_table_offset); @@ -1303,6 +1301,16 @@ static int asd_request_firmware(struct asd_ha_struct *asd_ha) return -EINVAL; } + asd_printk("Found sequencer Firmware version %d.%d (%s)\n", + header.major, header.minor, hdr_ptr->version); + + if (header.major != SAS_RAZOR_SEQUENCER_FW_MAJOR) { + asd_printk("Firmware Major Version Mismatch;" + "driver requires version %d.X", + SAS_RAZOR_SEQUENCER_FW_MAJOR); + return -EINVAL; + } + ptr_cseq_vecs = (u16 *)&sequencer_fw->data[header.cseq_table_offset]; ptr_lseq_vecs = (u16 *)&sequencer_fw->data[header.lseq_table_offset]; mode2_task = header.mode2_task; @@ -1335,7 +1343,6 @@ int asd_init_seqs(struct asd_ha_struct *asd_ha) return err; } - asd_printk("using sequencer %s\n", sequencer_version); err = asd_seq_download_seqs(asd_ha); if (err) { asd_printk("couldn't download sequencers for %s\n", diff --git a/drivers/scsi/aic94xx/aic94xx_seq.h b/drivers/scsi/aic94xx/aic94xx_seq.h index 9437ff0ae3a4..2ea6a0d52208 100644 --- a/drivers/scsi/aic94xx/aic94xx_seq.h +++ b/drivers/scsi/aic94xx/aic94xx_seq.h @@ -31,6 +31,7 @@ #define LSEQ_NUM_VECS 11 #define SAS_RAZOR_SEQUENCER_FW_FILE "aic94xx-seq.fw" +#define SAS_RAZOR_SEQUENCER_FW_MAJOR 1 /* Note: All quantites in the sequencer file are little endian */ struct sequencer_file_header { diff --git a/drivers/scsi/arm/eesox.c b/drivers/scsi/arm/eesox.c index 4677152142d9..d4136524fc46 100644 --- a/drivers/scsi/arm/eesox.c +++ b/drivers/scsi/arm/eesox.c @@ -196,7 +196,7 @@ static void eesoxscsi_buffer_in(void *buf, int length, void __iomem *base) const void __iomem *reg_fas = base + EESOX_FAS216_OFFSET; const void __iomem *reg_dmastat = base + EESOX_DMASTAT; const void __iomem *reg_dmadata = base + EESOX_DMADATA; - const register unsigned long mask = 0xffff; + register const unsigned long mask = 0xffff; do { unsigned int status; diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c index 8f6b5bf580f6..2b5b8a93bc10 100644 --- a/drivers/scsi/ide-scsi.c +++ b/drivers/scsi/ide-scsi.c @@ -801,15 +801,10 @@ static int idescsi_ide_open(struct inode *inode, struct file *filp) { struct gendisk *disk = inode->i_bdev->bd_disk; struct ide_scsi_obj *scsi; - ide_drive_t *drive; if (!(scsi = ide_scsi_get(disk))) return -ENXIO; - drive = scsi->drive; - - drive->usage++; - return 0; } @@ -817,9 +812,6 @@ static int idescsi_ide_release(struct inode *inode, struct file *filp) { struct gendisk *disk = inode->i_bdev->bd_disk; struct ide_scsi_obj *scsi = ide_scsi_g(disk); - ide_drive_t *drive = scsi->drive; - - drive->usage--; ide_scsi_put(scsi); diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index afca45cdbcef..9d014e5a81c4 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -518,6 +518,10 @@ lpfc_handle_eratt(struct lpfc_hba * phba) struct lpfc_sli *psli = &phba->sli; struct lpfc_sli_ring *pring; uint32_t event_data; + /* If the pci channel is offline, ignore possible errors, + * since we cannot communicate with the pci card anyway. */ + if (pci_channel_offline(phba->pcidev)) + return; if (phba->work_hs & HS_FFER6 || phba->work_hs & HS_FFER5) { @@ -1797,6 +1801,92 @@ lpfc_pci_remove_one(struct pci_dev *pdev) pci_set_drvdata(pdev, NULL); } +/** + * lpfc_io_error_detected - called when PCI error is detected + * @pdev: Pointer to PCI device + * @state: The current pci conneection state + * + * This function is called after a PCI bus error affecting + * this device has been detected. + */ +static pci_ers_result_t lpfc_io_error_detected(struct pci_dev *pdev, + pci_channel_state_t state) +{ + struct Scsi_Host *host = pci_get_drvdata(pdev); + struct lpfc_hba *phba = (struct lpfc_hba *)host->hostdata; + struct lpfc_sli *psli = &phba->sli; + struct lpfc_sli_ring *pring; + + if (state == pci_channel_io_perm_failure) { + lpfc_pci_remove_one(pdev); + return PCI_ERS_RESULT_DISCONNECT; + } + pci_disable_device(pdev); + /* + * There may be I/Os dropped by the firmware. + * Error iocb (I/O) on txcmplq and let the SCSI layer + * retry it after re-establishing link. + */ + pring = &psli->ring[psli->fcp_ring]; + lpfc_sli_abort_iocb_ring(phba, pring); + + /* Request a slot reset. */ + return PCI_ERS_RESULT_NEED_RESET; +} + +/** + * lpfc_io_slot_reset - called after the pci bus has been reset. + * @pdev: Pointer to PCI device + * + * Restart the card from scratch, as if from a cold-boot. + */ +static pci_ers_result_t lpfc_io_slot_reset(struct pci_dev *pdev) +{ + struct Scsi_Host *host = pci_get_drvdata(pdev); + struct lpfc_hba *phba = (struct lpfc_hba *)host->hostdata; + struct lpfc_sli *psli = &phba->sli; + int bars = pci_select_bars(pdev, IORESOURCE_MEM); + + dev_printk(KERN_INFO, &pdev->dev, "recovering from a slot reset.\n"); + if (pci_enable_device_bars(pdev, bars)) { + printk(KERN_ERR "lpfc: Cannot re-enable " + "PCI device after reset.\n"); + return PCI_ERS_RESULT_DISCONNECT; + } + + pci_set_master(pdev); + + /* Re-establishing Link */ + spin_lock_irq(phba->host->host_lock); + phba->fc_flag |= FC_ESTABLISH_LINK; + psli->sli_flag &= ~LPFC_SLI2_ACTIVE; + spin_unlock_irq(phba->host->host_lock); + + + /* Take device offline; this will perform cleanup */ + lpfc_offline(phba); + lpfc_sli_brdrestart(phba); + + return PCI_ERS_RESULT_RECOVERED; +} + +/** + * lpfc_io_resume - called when traffic can start flowing again. + * @pdev: Pointer to PCI device + * + * This callback is called when the error recovery driver tells us that + * its OK to resume normal operation. + */ +static void lpfc_io_resume(struct pci_dev *pdev) +{ + struct Scsi_Host *host = pci_get_drvdata(pdev); + struct lpfc_hba *phba = (struct lpfc_hba *)host->hostdata; + + if (lpfc_online(phba) == 0) { + mod_timer(&phba->fc_estabtmo, jiffies + HZ * 60); + } +} + static struct pci_device_id lpfc_id_table[] = { {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_VIPER, PCI_ANY_ID, PCI_ANY_ID, }, @@ -1857,11 +1947,18 @@ static struct pci_device_id lpfc_id_table[] = { MODULE_DEVICE_TABLE(pci, lpfc_id_table); +static struct pci_error_handlers lpfc_err_handler = { + .error_detected = lpfc_io_error_detected, + .slot_reset = lpfc_io_slot_reset, + .resume = lpfc_io_resume, +}; + static struct pci_driver lpfc_driver = { .name = LPFC_DRIVER_NAME, .id_table = lpfc_id_table, .probe = lpfc_pci_probe_one, .remove = __devexit_p(lpfc_pci_remove_one), + .err_handler = &lpfc_err_handler, }; static int __init diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index a4128e19338a..9fb6960a8ada 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -2104,6 +2104,10 @@ lpfc_sli_issue_mbox(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmbox, uint32_t flag) volatile uint32_t word0, ldata; void __iomem *to_slim; + /* If the PCI channel is in offline state, do not post mbox. */ + if (unlikely(pci_channel_offline(phba->pcidev))) + return MBX_NOT_FINISHED; + psli = &phba->sli; spin_lock_irqsave(phba->host->host_lock, drvr_flag); @@ -2407,6 +2411,10 @@ lpfc_sli_issue_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, struct lpfc_iocbq *nextiocb; IOCB_t *iocb; + /* If the PCI channel is in offline state, do not post iocbs. */ + if (unlikely(pci_channel_offline(phba->pcidev))) + return IOCB_ERROR; + /* * We should never get an IOCB if we are in a < LINK_DOWN state */ @@ -3154,6 +3162,10 @@ lpfc_intr_handler(int irq, void *dev_id) if (unlikely(!phba)) return IRQ_NONE; + /* If the pci channel is offline, ignore all the interrupts. */ + if (unlikely(pci_channel_offline(phba->pcidev))) + return IRQ_NONE; + phba->sli.slistat.sli_intr++; /* diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index 808a1b8c4043..0aa3304f6b9b 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c @@ -5072,7 +5072,7 @@ static int __init megaraid_init(void) "megaraid: failed to create megaraid root\n"); } #endif - error = pci_module_init(&megaraid_pci_driver); + error = pci_register_driver(&megaraid_pci_driver); if (error) { #ifdef CONFIG_PROC_FS remove_proc_entry("megaraid", &proc_root); diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c index 15e24fcc84f3..7a812677ff8a 100644 --- a/drivers/scsi/megaraid/megaraid_sas.c +++ b/drivers/scsi/megaraid/megaraid_sas.c @@ -10,11 +10,13 @@ * 2 of the License, or (at your option) any later version. * * FILE : megaraid_sas.c - * Version : v00.00.03.05 + * Version : v00.00.03.10-rc1 * * Authors: - * Sreenivas Bagalkote <Sreenivas.Bagalkote@lsi.com> - * Sumant Patro <Sumant.Patro@lsi.com> + * (email-id : megaraidlinux@lsi.com) + * Sreenivas Bagalkote + * Sumant Patro + * Bo Yang * * List of supported controllers * @@ -35,6 +37,7 @@ #include <asm/uaccess.h> #include <linux/fs.h> #include <linux/compat.h> +#include <linux/blkdev.h> #include <linux/mutex.h> #include <scsi/scsi.h> @@ -841,6 +844,11 @@ megasas_queue_command(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd *)) instance = (struct megasas_instance *) scmd->device->host->hostdata; + + /* Don't process if we have already declared adapter dead */ + if (instance->hw_crit_error) + return SCSI_MLQUEUE_HOST_BUSY; + scmd->scsi_done = done; scmd->result = 0; @@ -850,6 +858,18 @@ megasas_queue_command(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd *)) goto out_done; } + switch (scmd->cmnd[0]) { + case SYNCHRONIZE_CACHE: + /* + * FW takes care of flush cache on its own + * No need to send it down + */ + scmd->result = DID_OK << 16; + goto out_done; + default: + break; + } + cmd = megasas_get_cmd(instance); if (!cmd) return SCSI_MLQUEUE_HOST_BUSY; @@ -1010,6 +1030,49 @@ static int megasas_reset_bus_host(struct scsi_cmnd *scmd) } /** + * megasas_bios_param - Returns disk geometry for a disk + * @sdev: device handle + * @bdev: block device + * @capacity: drive capacity + * @geom: geometry parameters + */ +static int +megasas_bios_param(struct scsi_device *sdev, struct block_device *bdev, + sector_t capacity, int geom[]) +{ + int heads; + int sectors; + sector_t cylinders; + unsigned long tmp; + /* Default heads (64) & sectors (32) */ + heads = 64; + sectors = 32; + + tmp = heads * sectors; + cylinders = capacity; + + sector_div(cylinders, tmp); + + /* + * Handle extended translation size for logical drives > 1Gb + */ + + if (capacity >= 0x200000) { + heads = 255; + sectors = 63; + tmp = heads*sectors; + cylinders = capacity; + sector_div(cylinders, tmp); + } + + geom[0] = heads; + geom[1] = sectors; + geom[2] = cylinders; + + return 0; +} + +/** * megasas_service_aen - Processes an event notification * @instance: Adapter soft state * @cmd: AEN command completed by the ISR @@ -1049,6 +1112,7 @@ static struct scsi_host_template megasas_template = { .eh_device_reset_handler = megasas_reset_device, .eh_bus_reset_handler = megasas_reset_bus_host, .eh_host_reset_handler = megasas_reset_bus_host, + .bios_param = megasas_bios_param, .use_clustering = ENABLE_CLUSTERING, }; @@ -1282,11 +1346,13 @@ megasas_deplete_reply_queue(struct megasas_instance *instance, u8 alt_status) if(instance->instancet->clear_intr(instance->reg_set)) return IRQ_NONE; + if (instance->hw_crit_error) + goto out_done; /* * Schedule the tasklet for cmd completion */ tasklet_schedule(&instance->isr_tasklet); - +out_done: return IRQ_HANDLED; } @@ -1741,6 +1807,10 @@ static void megasas_complete_cmd_dpc(unsigned long instance_addr) struct megasas_cmd *cmd; struct megasas_instance *instance = (struct megasas_instance *)instance_addr; + /* If we have already declared adapter dead, donot complete cmds */ + if (instance->hw_crit_error) + return; + producer = *instance->producer; consumer = *instance->consumer; @@ -2655,9 +2725,9 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance, * For each user buffer, create a mirror buffer and copy in */ for (i = 0; i < ioc->sge_count; i++) { - kbuff_arr[i] = pci_alloc_consistent(instance->pdev, + kbuff_arr[i] = dma_alloc_coherent(&instance->pdev->dev, ioc->sgl[i].iov_len, - &buf_handle); + &buf_handle, GFP_KERNEL); if (!kbuff_arr[i]) { printk(KERN_DEBUG "megasas: Failed to alloc " "kernel SGL buffer for IOCTL \n"); @@ -2684,8 +2754,8 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance, } if (ioc->sense_len) { - sense = pci_alloc_consistent(instance->pdev, ioc->sense_len, - &sense_handle); + sense = dma_alloc_coherent(&instance->pdev->dev, ioc->sense_len, + &sense_handle, GFP_KERNEL); if (!sense) { error = -ENOMEM; goto out; @@ -2744,12 +2814,12 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance, out: if (sense) { - pci_free_consistent(instance->pdev, ioc->sense_len, + dma_free_coherent(&instance->pdev->dev, ioc->sense_len, sense, sense_handle); } for (i = 0; i < ioc->sge_count && kbuff_arr[i]; i++) { - pci_free_consistent(instance->pdev, + dma_free_coherent(&instance->pdev->dev, kern_sge32[i].length, kbuff_arr[i], kern_sge32[i].phys_addr); } diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index cacb3ad92527..e862992ee377 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -18,9 +18,9 @@ /* * MegaRAID SAS Driver meta data */ -#define MEGASAS_VERSION "00.00.03.05" -#define MEGASAS_RELDATE "Oct 02, 2006" -#define MEGASAS_EXT_VERSION "Mon Oct 02 11:21:32 PDT 2006" +#define MEGASAS_VERSION "00.00.03.10-rc1" +#define MEGASAS_RELDATE "Feb 14, 2007" +#define MEGASAS_EXT_VERSION "Wed Feb 14 10:14:25 PST 2007" /* * Device IDs diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c index 9668b73872c7..a967fadb7439 100644 --- a/drivers/scsi/osst.c +++ b/drivers/scsi/osst.c @@ -5574,14 +5574,14 @@ static ssize_t osst_version_show(struct device_driver *ddd, char *buf) static DRIVER_ATTR(version, S_IRUGO, osst_version_show, NULL); -static int osst_create_driverfs_files(struct device_driver *driverfs) +static int osst_create_sysfs_files(struct device_driver *sysfs) { - return driver_create_file(driverfs, &driver_attr_version); + return driver_create_file(sysfs, &driver_attr_version); } -static void osst_remove_driverfs_files(struct device_driver *driverfs) +static void osst_remove_sysfs_files(struct device_driver *sysfs) { - driver_remove_file(driverfs, &driver_attr_version); + driver_remove_file(sysfs, &driver_attr_version); } /* @@ -5953,7 +5953,7 @@ static int __init init_osst(void) if (err) goto err_out_chrdev; - err = osst_create_driverfs_files(&osst_template.gendrv); + err = osst_create_sysfs_files(&osst_template.gendrv); if (err) goto err_out_scsidrv; @@ -5973,7 +5973,7 @@ static void __exit exit_osst (void) int i; struct osst_tape * STp; - osst_remove_driverfs_files(&osst_template.gendrv); + osst_remove_sysfs_files(&osst_template.gendrv); scsi_unregister_driver(&osst_template.gendrv); unregister_chrdev(OSST_MAJOR, "osst"); osst_sysfs_cleanup(); diff --git a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c index 69d6e9b198c4..bb6f051beda8 100644 --- a/drivers/scsi/scsi_proc.c +++ b/drivers/scsi/scsi_proc.c @@ -179,9 +179,8 @@ static int proc_print_scsidevice(struct device *dev, void *data) seq_printf(s, "\n"); seq_printf(s, " Type: %s ", scsi_device_type(sdev->type)); - seq_printf(s, " ANSI" - " SCSI revision: %02x", (sdev->scsi_level - 1) ? - sdev->scsi_level - 1 : 1); + seq_printf(s, " ANSI SCSI revision: %02x", + sdev->scsi_level - (sdev->scsi_level > 1)); if (sdev->scsi_level == 2) seq_printf(s, " CCS\n"); else diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index a43b9ec3aefd..0949145304ea 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -54,7 +54,7 @@ #define SCSI_TIMEOUT (2*HZ) /* - * Prefix values for the SCSI id's (stored in driverfs name field) + * Prefix values for the SCSI id's (stored in sysfs name field) */ #define SCSI_UID_SER_NUM 'S' #define SCSI_UID_UNKNOWN 'Z' @@ -385,6 +385,7 @@ static struct scsi_target *scsi_alloc_target(struct device *parent, INIT_LIST_HEAD(&starget->siblings); INIT_LIST_HEAD(&starget->devices); starget->state = STARGET_RUNNING; + starget->scsi_level = SCSI_2; retry: spin_lock_irqsave(shost->host_lock, flags); @@ -654,6 +655,19 @@ static int scsi_probe_lun(struct scsi_device *sdev, unsigned char *inq_result, * short INQUIRY), an abort here prevents any further use of the * device, including spin up. * + * On the whole, the best approach seems to be to assume the first + * 36 bytes are valid no matter what the device says. That's + * better than copying < 36 bytes to the inquiry-result buffer + * and displaying garbage for the Vendor, Product, or Revision + * strings. + */ + if (sdev->inquiry_len < 36) { + printk(KERN_INFO "scsi scan: INQUIRY result too short (%d)," + " using 36\n", sdev->inquiry_len); + sdev->inquiry_len = 36; + } + + /* * Related to the above issue: * * XXX Devices (disk or all?) should be sent a TEST UNIT READY, diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 259c90cfa367..c275dcac3f18 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -922,7 +922,7 @@ void scsi_sysfs_device_initialize(struct scsi_device *sdev) snprintf(sdev->sdev_classdev.class_id, BUS_ID_SIZE, "%d:%d:%d:%d", sdev->host->host_no, sdev->channel, sdev->id, sdev->lun); - sdev->scsi_level = SCSI_2; + sdev->scsi_level = starget->scsi_level; transport_setup_device(&sdev->sdev_gendev); spin_lock_irqsave(shost->host_lock, flags); list_add_tail(&sdev->same_target_siblings, &starget->devices); diff --git a/drivers/scsi/scsi_tgt_if.c b/drivers/scsi/scsi_tgt_if.c index f2344ab8deff..0e08817fdecf 100644 --- a/drivers/scsi/scsi_tgt_if.c +++ b/drivers/scsi/scsi_tgt_if.c @@ -33,6 +33,14 @@ #include "scsi_tgt_priv.h" +#if TGT_RING_SIZE < PAGE_SIZE +# define TGT_RING_SIZE PAGE_SIZE +#endif + +#define TGT_RING_PAGES (TGT_RING_SIZE >> PAGE_SHIFT) +#define TGT_EVENT_PER_PAGE (PAGE_SIZE / sizeof(struct tgt_event)) +#define TGT_MAX_EVENTS (TGT_EVENT_PER_PAGE * TGT_RING_PAGES) + struct tgt_ring { u32 tr_idx; unsigned long tr_pages[TGT_RING_PAGES]; diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index 0d3c10f2134c..58afdb401703 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -855,7 +855,7 @@ static FC_CLASS_DEVICE_ATTR(rport, fast_io_fail_tmo, S_IRUGO | S_IWUSR, /* * Note: in the target show function we recognize when the remote - * port is in the heirarchy and do not allow the driver to get + * port is in the hierarchy and do not allow the driver to get * involved in sysfs functions. The driver only gets involved if * it's the "old" style that doesn't use rports. */ diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c index 6d39150e205b..b2ef71a86292 100644 --- a/drivers/scsi/scsi_transport_sas.c +++ b/drivers/scsi/scsi_transport_sas.c @@ -500,7 +500,7 @@ struct sas_phy *sas_phy_alloc(struct device *parent, int number) EXPORT_SYMBOL(sas_phy_alloc); /** - * sas_phy_add -- add a SAS PHY to the device hierachy + * sas_phy_add -- add a SAS PHY to the device hierarchy * @phy: The PHY to be added * * Publishes a SAS PHY to the rest of the system. @@ -1265,7 +1265,7 @@ struct sas_rphy *sas_expander_alloc(struct sas_port *parent, EXPORT_SYMBOL(sas_expander_alloc); /** - * sas_rphy_add -- add a SAS remote PHY to the device hierachy + * sas_rphy_add -- add a SAS remote PHY to the device hierarchy * @rphy: The remote PHY to be added * * Publishes a SAS remote PHY to the rest of the system. diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 3f048bd6326d..5a8f55fea5ff 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1269,9 +1269,18 @@ repeat: /* Some devices return the total number of sectors, not the * highest sector number. Make the necessary adjustment. */ - if (sdp->fix_capacity) + if (sdp->fix_capacity) { --sdkp->capacity; + /* Some devices have version which report the correct sizes + * and others which do not. We guess size according to a heuristic + * and err on the side of lowering the capacity. */ + } else { + if (sdp->guess_capacity) + if (sdkp->capacity & 0x01) /* odd sizes are odd */ + --sdkp->capacity; + } + got_data: if (sector_size == 0) { sector_size = 512; diff --git a/drivers/scsi/sgiwd93.c b/drivers/scsi/sgiwd93.c index e81f97a35bc8..a15752b37990 100644 --- a/drivers/scsi/sgiwd93.c +++ b/drivers/scsi/sgiwd93.c @@ -244,9 +244,10 @@ static struct Scsi_Host * __init sgiwd93_setup_scsi( regs.SASR = wdregs + 3; regs.SCMD = wdregs + 7; - wd33c93_init(host, regs, dma_setup, dma_stop, WD33C93_FS_16_20); + wd33c93_init(host, regs, dma_setup, dma_stop, WD33C93_FS_MHZ(20)); - hdata->wh.no_sync = 0; + if (hdata->wh.no_sync == 0xff) + hdata->wh.no_sync = 0; if (request_irq(irq, sgiwd93_intr, 0, "SGI WD93", (void *) host)) { printk(KERN_WARNING "sgiwd93: Could not register irq %d " diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 3d2e02381e92..98d8411bbccc 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -195,8 +195,8 @@ static int sgl_unmap_user_pages(struct scatterlist *, const unsigned int, int); static int st_probe(struct device *); static int st_remove(struct device *); -static int do_create_driverfs_files(void); -static void do_remove_driverfs_files(void); +static int do_create_sysfs_files(void); +static void do_remove_sysfs_files(void); static int do_create_class_files(struct scsi_tape *, int, int); static struct scsi_driver st_template = { @@ -4193,7 +4193,7 @@ static int __init init_st(void) if (err) goto err_chrdev; - err = do_create_driverfs_files(); + err = do_create_sysfs_files(); if (err) goto err_scsidrv; @@ -4211,7 +4211,7 @@ err_class: static void __exit exit_st(void) { - do_remove_driverfs_files(); + do_remove_sysfs_files(); scsi_unregister_driver(&st_template.gendrv); unregister_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0), ST_MAX_TAPE_ENTRIES); @@ -4249,43 +4249,43 @@ static ssize_t st_version_show(struct device_driver *ddd, char *buf) } static DRIVER_ATTR(version, S_IRUGO, st_version_show, NULL); -static int do_create_driverfs_files(void) +static int do_create_sysfs_files(void) { - struct device_driver *driverfs = &st_template.gendrv; + struct device_driver *sysfs = &st_template.gendrv; int err; - err = driver_create_file(driverfs, &driver_attr_try_direct_io); + err = driver_create_file(sysfs, &driver_attr_try_direct_io); if (err) return err; - err = driver_create_file(driverfs, &driver_attr_fixed_buffer_size); + err = driver_create_file(sysfs, &driver_attr_fixed_buffer_size); if (err) goto err_try_direct_io; - err = driver_create_file(driverfs, &driver_attr_max_sg_segs); + err = driver_create_file(sysfs, &driver_attr_max_sg_segs); if (err) goto err_attr_fixed_buf; - err = driver_create_file(driverfs, &driver_attr_version); + err = driver_create_file(sysfs, &driver_attr_version); if (err) goto err_attr_max_sg; return 0; err_attr_max_sg: - driver_remove_file(driverfs, &driver_attr_max_sg_segs); + driver_remove_file(sysfs, &driver_attr_max_sg_segs); err_attr_fixed_buf: - driver_remove_file(driverfs, &driver_attr_fixed_buffer_size); + driver_remove_file(sysfs, &driver_attr_fixed_buffer_size); err_try_direct_io: - driver_remove_file(driverfs, &driver_attr_try_direct_io); + driver_remove_file(sysfs, &driver_attr_try_direct_io); return err; } -static void do_remove_driverfs_files(void) +static void do_remove_sysfs_files(void) { - struct device_driver *driverfs = &st_template.gendrv; + struct device_driver *sysfs = &st_template.gendrv; - driver_remove_file(driverfs, &driver_attr_version); - driver_remove_file(driverfs, &driver_attr_max_sg_segs); - driver_remove_file(driverfs, &driver_attr_fixed_buffer_size); - driver_remove_file(driverfs, &driver_attr_try_direct_io); + driver_remove_file(sysfs, &driver_attr_version); + driver_remove_file(sysfs, &driver_attr_max_sg_segs); + driver_remove_file(sysfs, &driver_attr_fixed_buffer_size); + driver_remove_file(sysfs, &driver_attr_try_direct_io); } diff --git a/drivers/scsi/sym53c8xx_2/sym_fw1.h b/drivers/scsi/sym53c8xx_2/sym_fw1.h index 7b39f4a35e98..7b08d6caaa99 100644 --- a/drivers/scsi/sym53c8xx_2/sym_fw1.h +++ b/drivers/scsi/sym53c8xx_2/sym_fw1.h @@ -1020,7 +1020,7 @@ static struct SYM_FWA_SCR SYM_FWA_SCR = { * It shall be a tagged command. * Read SIMPLE+TAG. * The C code will deal with errors. - * Agressive optimization, is'nt it? :) + * Aggressive optimization, isn't it? :) */ SCR_MOVE_ABS (2) ^ SCR_MSG_IN, HADDR_1 (msgin), @@ -1044,7 +1044,7 @@ static struct SYM_FWA_SCR SYM_FWA_SCR = { RADDR_1 (dsa), /* * The SIDL still contains the TAG value. - * Agressive optimization, isn't it? :):) + * Aggressive optimization, isn't it? :):) */ SCR_REG_SFBR (sidl, SCR_SHL, 0), 0, diff --git a/drivers/scsi/sym53c8xx_2/sym_fw2.h b/drivers/scsi/sym53c8xx_2/sym_fw2.h index 851f2706f220..6e5b952312e3 100644 --- a/drivers/scsi/sym53c8xx_2/sym_fw2.h +++ b/drivers/scsi/sym53c8xx_2/sym_fw2.h @@ -956,7 +956,7 @@ static struct SYM_FWA_SCR SYM_FWA_SCR = { * It shall be a tagged command. * Read SIMPLE+TAG. * The C code will deal with errors. - * Agressive optimization, is'nt it? :) + * Aggressive optimization, isn't it? :) */ SCR_MOVE_ABS (2) ^ SCR_MSG_IN, HADDR_1 (msgin), @@ -968,7 +968,7 @@ static struct SYM_FWA_SCR SYM_FWA_SCR = { offsetof(struct sym_lcb, head.itlq_tbl_sa), /* * The SIDL still contains the TAG value. - * Agressive optimization, isn't it? :):) + * Aggressive optimization, isn't it? :):) */ SCR_REG_SFBR (sidl, SCR_SHL, 0), 0, diff --git a/drivers/scsi/wd33c93.c b/drivers/scsi/wd33c93.c index 835751600e93..fa4e08e508ad 100644 --- a/drivers/scsi/wd33c93.c +++ b/drivers/scsi/wd33c93.c @@ -69,6 +69,11 @@ * Added support for pre -A chips, which don't have advanced features * and will generate CSR_RESEL rather than CSR_RESEL_AM. * Richard Hirst <richard@sleepie.demon.co.uk> August 2000 + * + * Added support for Burst Mode DMA and Fast SCSI. Enabled the use of + * default_sx_per for asynchronous data transfers. Added adjustment + * of transfer periods in sx_table to the actual input-clock. + * peter fuerst <post@pfrst.de> February 2007 */ #include <linux/module.h> @@ -86,9 +91,11 @@ #include "wd33c93.h" +#define optimum_sx_per(hostdata) (hostdata)->sx_table[1].period_ns + -#define WD33C93_VERSION "1.26" -#define WD33C93_DATE "22/Feb/2003" +#define WD33C93_VERSION "1.26++" +#define WD33C93_DATE "10/Feb/2007" MODULE_AUTHOR("John Shifflett"); MODULE_DESCRIPTION("Generic WD33C93 SCSI driver"); @@ -122,6 +129,13 @@ MODULE_LICENSE("GPL"); * defines in wd33c93.h * - clock:x -x = clock input in MHz for WD33c93 chip. Normal values * would be from 8 through 20. Default is 8. + * - burst:x -x = 1 to use Burst Mode (or Demand-Mode) DMA, x = 0 to use + * Single Byte DMA, which is the default. Argument is + * optional - if not present, same as "burst:1". + * - fast:x -x = 1 to enable Fast SCSI, which is only effective with + * input-clock divisor 4 (WD33C93_FS_16_20), x = 0 to disable + * it, which is the default. Argument is optional - if not + * present, same as "fast:1". * - next -No argument. Used to separate blocks of keywords when * there's more than one host adapter in the system. * @@ -148,7 +162,7 @@ MODULE_LICENSE("GPL"); */ /* Normally, no defaults are specified */ -static char *setup_args[] = { "", "", "", "", "", "", "", "", "" }; +static char *setup_args[] = { "", "", "", "", "", "", "", "", "", "" }; static char *setup_strings; module_param(setup_strings, charp, 0); @@ -298,20 +312,8 @@ read_1_byte(const wd33c93_regs regs) return x; } -static struct sx_period sx_table[] = { - {1, 0x20}, - {252, 0x20}, - {376, 0x30}, - {500, 0x40}, - {624, 0x50}, - {752, 0x60}, - {876, 0x70}, - {1000, 0x00}, - {0, 0} -}; - static int -round_period(unsigned int period) +round_period(unsigned int period, const struct sx_period *sx_table) { int x; @@ -324,17 +326,49 @@ round_period(unsigned int period) return 7; } +/* + * Calculate Synchronous Transfer Register value from SDTR code. + */ static uchar -calc_sync_xfer(unsigned int period, unsigned int offset) +calc_sync_xfer(unsigned int period, unsigned int offset, unsigned int fast, + const struct sx_period *sx_table) { + /* When doing Fast SCSI synchronous data transfers, the corresponding + * value in 'sx_table' is two times the actually used transfer period. + */ uchar result; + if (offset && fast) { + fast = STR_FSS; + period *= 2; + } else { + fast = 0; + } period *= 4; /* convert SDTR code to ns */ - result = sx_table[round_period(period)].reg_value; + result = sx_table[round_period(period,sx_table)].reg_value; result |= (offset < OPTIMUM_SX_OFF) ? offset : OPTIMUM_SX_OFF; + result |= fast; return result; } +/* + * Calculate SDTR code bytes [3],[4] from period and offset. + */ +static inline void +calc_sync_msg(unsigned int period, unsigned int offset, unsigned int fast, + uchar msg[2]) +{ + /* 'period' is a "normal"-mode value, like the ones in 'sx_table'. The + * actually used transfer period for Fast SCSI synchronous data + * transfers is half that value. + */ + period /= 4; + if (offset && fast) + period /= 2; + msg[0] = period; + msg[1] = offset; +} + int wd33c93_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) @@ -632,7 +666,7 @@ wd33c93_execute(struct Scsi_Host *instance) write_wd33c93_count(regs, cmd->SCp.this_residual); write_wd33c93(regs, WD_CONTROL, - CTRL_IDI | CTRL_EDI | CTRL_DMA); + CTRL_IDI | CTRL_EDI | hostdata->dma_mode); hostdata->dma = D_DMA_RUNNING; } } else @@ -712,6 +746,8 @@ transfer_bytes(const wd33c93_regs regs, struct scsi_cmnd *cmd, cmd->SCp.ptr = page_address(cmd->SCp.buffer->page) + cmd->SCp.buffer->offset; } + if (!cmd->SCp.this_residual) /* avoid bogus setups */ + return; write_wd33c93(regs, WD_SYNCHRONOUS_TRANSFER, hostdata->sync_xfer[cmd->device->id]); @@ -744,7 +780,7 @@ transfer_bytes(const wd33c93_regs regs, struct scsi_cmnd *cmd, #ifdef PROC_STATISTICS hostdata->dma_cnt++; #endif - write_wd33c93(regs, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_DMA); + write_wd33c93(regs, WD_CONTROL, CTRL_IDI | CTRL_EDI | hostdata->dma_mode); write_wd33c93_count(regs, cmd->SCp.this_residual); if ((hostdata->level2 >= L2_DATA) || @@ -862,9 +898,6 @@ wd33c93_intr(struct Scsi_Host *instance) hostdata->outgoing_msg[0] |= 0x40; if (hostdata->sync_stat[cmd->device->id] == SS_FIRST) { -#ifdef SYNC_DEBUG - printk(" sending SDTR "); -#endif hostdata->sync_stat[cmd->device->id] = SS_WAITING; @@ -878,14 +911,20 @@ wd33c93_intr(struct Scsi_Host *instance) hostdata->outgoing_msg[2] = 3; hostdata->outgoing_msg[3] = EXTENDED_SDTR; if (hostdata->no_sync & (1 << cmd->device->id)) { - hostdata->outgoing_msg[4] = - hostdata->default_sx_per / 4; - hostdata->outgoing_msg[5] = 0; + calc_sync_msg(hostdata->default_sx_per, 0, + 0, hostdata->outgoing_msg + 4); } else { - hostdata->outgoing_msg[4] = OPTIMUM_SX_PER / 4; - hostdata->outgoing_msg[5] = OPTIMUM_SX_OFF; + calc_sync_msg(optimum_sx_per(hostdata), + OPTIMUM_SX_OFF, + hostdata->fast, + hostdata->outgoing_msg + 4); } hostdata->outgoing_len = 6; +#ifdef SYNC_DEBUG + ucp = hostdata->outgoing_msg + 1; + printk(" sending SDTR %02x03%02x%02x%02x ", + ucp[0], ucp[2], ucp[3], ucp[4]); +#endif } else hostdata->outgoing_len = 1; @@ -1001,8 +1040,13 @@ wd33c93_intr(struct Scsi_Host *instance) #ifdef SYNC_DEBUG printk("-REJ-"); #endif - if (hostdata->sync_stat[cmd->device->id] == SS_WAITING) + if (hostdata->sync_stat[cmd->device->id] == SS_WAITING) { hostdata->sync_stat[cmd->device->id] = SS_SET; + /* we want default_sx_per, not DEFAULT_SX_PER */ + hostdata->sync_xfer[cmd->device->id] = + calc_sync_xfer(hostdata->default_sx_per + / 4, 0, 0, hostdata->sx_table); + } write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK); hostdata->state = S_CONNECTED; break; @@ -1022,7 +1066,10 @@ wd33c93_intr(struct Scsi_Host *instance) switch (ucp[2]) { /* what's the EXTENDED code? */ case EXTENDED_SDTR: - id = calc_sync_xfer(ucp[3], ucp[4]); + /* default to default async period */ + id = calc_sync_xfer(hostdata-> + default_sx_per / 4, 0, + 0, hostdata->sx_table); if (hostdata->sync_stat[cmd->device->id] != SS_WAITING) { @@ -1041,20 +1088,22 @@ wd33c93_intr(struct Scsi_Host *instance) hostdata->outgoing_msg[1] = 3; hostdata->outgoing_msg[2] = EXTENDED_SDTR; - hostdata->outgoing_msg[3] = - hostdata->default_sx_per / - 4; - hostdata->outgoing_msg[4] = 0; + calc_sync_msg(hostdata-> + default_sx_per, 0, + 0, hostdata->outgoing_msg + 3); hostdata->outgoing_len = 5; - hostdata->sync_xfer[cmd->device->id] = - calc_sync_xfer(hostdata-> - default_sx_per - / 4, 0); } else { - hostdata->sync_xfer[cmd->device->id] = id; + if (ucp[4]) /* well, sync transfer */ + id = calc_sync_xfer(ucp[3], ucp[4], + hostdata->fast, + hostdata->sx_table); + else if (ucp[3]) /* very unlikely... */ + id = calc_sync_xfer(ucp[3], ucp[4], + 0, hostdata->sx_table); } + hostdata->sync_xfer[cmd->device->id] = id; #ifdef SYNC_DEBUG - printk("sync_xfer=%02x", + printk(" sync_xfer=%02x\n", hostdata->sync_xfer[cmd->device->id]); #endif hostdata->sync_stat[cmd->device->id] = @@ -1486,7 +1535,7 @@ reset_wd33c93(struct Scsi_Host *instance) write_wd33c93(regs, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED); write_wd33c93(regs, WD_SYNCHRONOUS_TRANSFER, calc_sync_xfer(hostdata->default_sx_per / 4, - DEFAULT_SX_OFF)); + DEFAULT_SX_OFF, 0, hostdata->sx_table)); write_wd33c93(regs, WD_COMMAND, WD_CMD_RESET); @@ -1512,6 +1561,9 @@ reset_wd33c93(struct Scsi_Host *instance) } else hostdata->chip = C_UNKNOWN_CHIP; + if (hostdata->chip != C_WD33C93B) /* Fast SCSI unavailable */ + hostdata->fast = 0; + write_wd33c93(regs, WD_TIMEOUT_PERIOD, TIMEOUT_PERIOD_VALUE); write_wd33c93(regs, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED); } @@ -1533,7 +1585,8 @@ wd33c93_host_reset(struct scsi_cmnd * SCpnt) for (i = 0; i < 8; i++) { hostdata->busy[i] = 0; hostdata->sync_xfer[i] = - calc_sync_xfer(DEFAULT_SX_PER / 4, DEFAULT_SX_OFF); + calc_sync_xfer(DEFAULT_SX_PER / 4, DEFAULT_SX_OFF, + 0, hostdata->sx_table); hostdata->sync_stat[i] = SS_UNSET; /* using default sync values */ } hostdata->input_Q = NULL; @@ -1782,6 +1835,98 @@ check_setup_args(char *key, int *flags, int *val, char *buf) return ++x; } +/* + * Calculate internal data-transfer-clock cycle from input-clock + * frequency (/MHz) and fill 'sx_table'. + * + * The original driver used to rely on a fixed sx_table, containing periods + * for (only) the lower limits of the respective input-clock-frequency ranges + * (8-10/12-15/16-20 MHz). Although it seems, that no problems ocurred with + * this setting so far, it might be desirable to adjust the transfer periods + * closer to the really attached, possibly 25% higher, input-clock, since + * - the wd33c93 may really use a significant shorter period, than it has + * negotiated (eg. thrashing the target, which expects 4/8MHz, with 5/10MHz + * instead). + * - the wd33c93 may ask the target for a lower transfer rate, than the target + * is capable of (eg. negotiating for an assumed minimum of 252ns instead of + * possible 200ns, which indeed shows up in tests as an approx. 10% lower + * transfer rate). + */ +static inline unsigned int +round_4(unsigned int x) +{ + switch (x & 3) { + case 1: --x; + break; + case 2: ++x; + case 3: ++x; + } + return x; +} + +static void +calc_sx_table(unsigned int mhz, struct sx_period sx_table[9]) +{ + unsigned int d, i; + if (mhz < 11) + d = 2; /* divisor for 8-10 MHz input-clock */ + else if (mhz < 16) + d = 3; /* divisor for 12-15 MHz input-clock */ + else + d = 4; /* divisor for 16-20 MHz input-clock */ + + d = (100000 * d) / 2 / mhz; /* 100 x DTCC / nanosec */ + + sx_table[0].period_ns = 1; + sx_table[0].reg_value = 0x20; + for (i = 1; i < 8; i++) { + sx_table[i].period_ns = round_4((i+1)*d / 100); + sx_table[i].reg_value = (i+1)*0x10; + } + sx_table[7].reg_value = 0; + sx_table[8].period_ns = 0; + sx_table[8].reg_value = 0; +} + +/* + * check and, maybe, map an init- or "clock:"- argument. + */ +static uchar +set_clk_freq(int freq, int *mhz) +{ + int x = freq; + if (WD33C93_FS_8_10 == freq) + freq = 8; + else if (WD33C93_FS_12_15 == freq) + freq = 12; + else if (WD33C93_FS_16_20 == freq) + freq = 16; + else if (freq > 7 && freq < 11) + x = WD33C93_FS_8_10; + else if (freq > 11 && freq < 16) + x = WD33C93_FS_12_15; + else if (freq > 15 && freq < 21) + x = WD33C93_FS_16_20; + else { + /* Hmm, wouldn't it be safer to assume highest freq here? */ + x = WD33C93_FS_8_10; + freq = 8; + } + *mhz = freq; + return x; +} + +/* + * to be used with the resync: fast: ... options + */ +static inline void set_resync ( struct WD33C93_hostdata *hd, int mask ) +{ + int i; + for (i = 0; i < 8; i++) + if (mask & (1 << i)) + hd->sync_stat[i] = SS_UNSET; +} + void wd33c93_init(struct Scsi_Host *instance, const wd33c93_regs regs, dma_setup_t setup, dma_stop_t stop, int clock_freq) @@ -1798,7 +1943,8 @@ wd33c93_init(struct Scsi_Host *instance, const wd33c93_regs regs, hostdata = (struct WD33C93_hostdata *) instance->hostdata; hostdata->regs = regs; - hostdata->clock_freq = clock_freq; + hostdata->clock_freq = set_clk_freq(clock_freq, &i); + calc_sx_table(i, hostdata->sx_table); hostdata->dma_setup = setup; hostdata->dma_stop = stop; hostdata->dma_bounce_buffer = NULL; @@ -1806,7 +1952,8 @@ wd33c93_init(struct Scsi_Host *instance, const wd33c93_regs regs, for (i = 0; i < 8; i++) { hostdata->busy[i] = 0; hostdata->sync_xfer[i] = - calc_sync_xfer(DEFAULT_SX_PER / 4, DEFAULT_SX_OFF); + calc_sync_xfer(DEFAULT_SX_PER / 4, DEFAULT_SX_OFF, + 0, hostdata->sx_table); hostdata->sync_stat[i] = SS_UNSET; /* using default sync values */ #ifdef PROC_STATISTICS hostdata->cmd_cnt[i] = 0; @@ -1828,6 +1975,8 @@ wd33c93_init(struct Scsi_Host *instance, const wd33c93_regs regs, hostdata->default_sx_per = DEFAULT_SX_PER; hostdata->no_sync = 0xff; /* sync defaults to off */ hostdata->no_dma = 0; /* default is DMA enabled */ + hostdata->fast = 0; /* default is Fast SCSI transfers disabled */ + hostdata->dma_mode = CTRL_DMA; /* default is Single Byte DMA */ #ifdef PROC_INTERFACE hostdata->proc = PR_VERSION | PR_INFO | PR_STATISTICS | @@ -1839,6 +1988,11 @@ wd33c93_init(struct Scsi_Host *instance, const wd33c93_regs regs, #endif #endif + if (check_setup_args("clock", &flags, &val, buf)) { + hostdata->clock_freq = set_clk_freq(val, &val); + calc_sx_table(val, hostdata->sx_table); + } + if (check_setup_args("nosync", &flags, &val, buf)) hostdata->no_sync = val; @@ -1847,7 +2001,8 @@ wd33c93_init(struct Scsi_Host *instance, const wd33c93_regs regs, if (check_setup_args("period", &flags, &val, buf)) hostdata->default_sx_per = - sx_table[round_period((unsigned int) val)].period_ns; + hostdata->sx_table[round_period((unsigned int) val, + hostdata->sx_table)].period_ns; if (check_setup_args("disconnect", &flags, &val, buf)) { if ((val >= DIS_NEVER) && (val <= DIS_ALWAYS)) @@ -1862,17 +2017,12 @@ wd33c93_init(struct Scsi_Host *instance, const wd33c93_regs regs, if (check_setup_args("debug", &flags, &val, buf)) hostdata->args = val & DB_MASK; - if (check_setup_args("clock", &flags, &val, buf)) { - if (val > 7 && val < 11) - val = WD33C93_FS_8_10; - else if (val > 11 && val < 16) - val = WD33C93_FS_12_15; - else if (val > 15 && val < 21) - val = WD33C93_FS_16_20; - else - val = WD33C93_FS_8_10; - hostdata->clock_freq = val; - } + if (check_setup_args("burst", &flags, &val, buf)) + hostdata->dma_mode = val ? CTRL_BURST:CTRL_DMA; + + if (WD33C93_FS_16_20 == hostdata->clock_freq /* divisor 4 */ + && check_setup_args("fast", &flags, &val, buf)) + hostdata->fast = !!val; if ((i = check_setup_args("next", &flags, &val, buf))) { while (i) @@ -1917,53 +2067,65 @@ wd33c93_proc_info(struct Scsi_Host *instance, char *buf, char **start, off_t off char tbuf[128]; struct WD33C93_hostdata *hd; struct scsi_cmnd *cmd; - int x, i; + int x; static int stop = 0; hd = (struct WD33C93_hostdata *) instance->hostdata; /* If 'in' is TRUE we need to _read_ the proc file. We accept the following - * keywords (same format as command-line, but only ONE per read): + * keywords (same format as command-line, but arguments are not optional): * debug * disconnect * period * resync * proc * nodma + * level2 + * burst + * fast + * nosync */ if (in) { buf[len] = '\0'; - bp = buf; + for (bp = buf; *bp; ) { + while (',' == *bp || ' ' == *bp) + ++bp; if (!strncmp(bp, "debug:", 6)) { - bp += 6; - hd->args = simple_strtoul(bp, NULL, 0) & DB_MASK; + hd->args = simple_strtoul(bp+6, &bp, 0) & DB_MASK; } else if (!strncmp(bp, "disconnect:", 11)) { - bp += 11; - x = simple_strtoul(bp, NULL, 0); + x = simple_strtoul(bp+11, &bp, 0); if (x < DIS_NEVER || x > DIS_ALWAYS) x = DIS_ADAPTIVE; hd->disconnect = x; } else if (!strncmp(bp, "period:", 7)) { - bp += 7; - x = simple_strtoul(bp, NULL, 0); + x = simple_strtoul(bp+7, &bp, 0); hd->default_sx_per = - sx_table[round_period((unsigned int) x)].period_ns; + hd->sx_table[round_period((unsigned int) x, + hd->sx_table)].period_ns; } else if (!strncmp(bp, "resync:", 7)) { - bp += 7; - x = simple_strtoul(bp, NULL, 0); - for (i = 0; i < 7; i++) - if (x & (1 << i)) - hd->sync_stat[i] = SS_UNSET; + set_resync(hd, (int)simple_strtoul(bp+7, &bp, 0)); } else if (!strncmp(bp, "proc:", 5)) { - bp += 5; - hd->proc = simple_strtoul(bp, NULL, 0); + hd->proc = simple_strtoul(bp+5, &bp, 0); } else if (!strncmp(bp, "nodma:", 6)) { - bp += 6; - hd->no_dma = simple_strtoul(bp, NULL, 0); + hd->no_dma = simple_strtoul(bp+6, &bp, 0); } else if (!strncmp(bp, "level2:", 7)) { - bp += 7; - hd->level2 = simple_strtoul(bp, NULL, 0); + hd->level2 = simple_strtoul(bp+7, &bp, 0); + } else if (!strncmp(bp, "burst:", 6)) { + hd->dma_mode = + simple_strtol(bp+6, &bp, 0) ? CTRL_BURST:CTRL_DMA; + } else if (!strncmp(bp, "fast:", 5)) { + x = !!simple_strtol(bp+5, &bp, 0); + if (x != hd->fast) + set_resync(hd, 0xff); + hd->fast = x; + } else if (!strncmp(bp, "nosync:", 7)) { + x = simple_strtoul(bp+7, &bp, 0); + set_resync(hd, x ^ hd->no_sync); + hd->no_sync = x; + } else { + break; /* unknown keyword,syntax-error,... */ + } } return len; } @@ -1977,8 +2139,9 @@ wd33c93_proc_info(struct Scsi_Host *instance, char *buf, char **start, off_t off strcat(bp, tbuf); } if (hd->proc & PR_INFO) { - sprintf(tbuf, "\nclock_freq=%02x no_sync=%02x no_dma=%d", - hd->clock_freq, hd->no_sync, hd->no_dma); + sprintf(tbuf, "\nclock_freq=%02x no_sync=%02x no_dma=%d" + " dma_mode=%02x fast=%d", + hd->clock_freq, hd->no_sync, hd->no_dma, hd->dma_mode, hd->fast); strcat(bp, tbuf); strcat(bp, "\nsync_xfer[] = "); for (x = 0; x < 7; x++) { diff --git a/drivers/scsi/wd33c93.h b/drivers/scsi/wd33c93.h index edcb0365cf0c..61ffb860dacc 100644 --- a/drivers/scsi/wd33c93.h +++ b/drivers/scsi/wd33c93.h @@ -155,6 +155,9 @@ #define WD33C93_FS_12_15 OWNID_FS_12 #define WD33C93_FS_16_20 OWNID_FS_16 + /* pass input-clock explicitely. accepted mhz values are 8-10,12-20 */ +#define WD33C93_FS_MHZ(mhz) (mhz) + /* Control register */ #define CTRL_HSP 0x01 #define CTRL_HA 0x02 @@ -253,6 +256,9 @@ struct WD33C93_hostdata { uchar sync_stat[8]; /* status of sync negotiation per target */ uchar no_sync; /* bitmask: don't do sync on these targets */ uchar no_dma; /* set this flag to disable DMA */ + uchar dma_mode; /* DMA Burst Mode or Single Byte DMA */ + uchar fast; /* set this flag to enable Fast SCSI */ + struct sx_period sx_table[9]; /* transfer periods for actual DTC-setting */ #ifdef PROC_INTERFACE uchar proc; /* bitmask: what's in proc output */ #ifdef PROC_STATISTICS diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index e8dd71df9165..ad9f321968e1 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -262,7 +262,8 @@ config SERIAL_AMBA_PL010 select SERIAL_CORE help This selects the ARM(R) AMBA(R) PrimeCell PL010 UART. If you have - an Integrator/AP or Integrator/PP2 platform, say Y or M here. + an Integrator/AP or Integrator/PP2 platform, or if you have a + Cirrus Logic EP93xx CPU, say Y or M here. If unsure, say N. diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c index df45a7ac773f..935f48fa501d 100644 --- a/drivers/serial/atmel_serial.c +++ b/drivers/serial/atmel_serial.c @@ -33,12 +33,13 @@ #include <linux/sysrq.h> #include <linux/tty_flip.h> #include <linux/platform_device.h> +#include <linux/atmel_pdc.h> #include <asm/io.h> #include <asm/mach/serial_at91.h> #include <asm/arch/board.h> -#include <asm/arch/at91_pdc.h> + #ifdef CONFIG_ARM #include <asm/arch/cpu.h> #include <asm/arch/gpio.h> diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.c b/drivers/serial/cpm_uart/cpm_uart_cpm2.c index 787a8f134677..fa455996ad8f 100644 --- a/drivers/serial/cpm_uart/cpm_uart_cpm2.c +++ b/drivers/serial/cpm_uart/cpm_uart_cpm2.c @@ -285,7 +285,7 @@ void cpm_uart_freebuf(struct uart_cpm_port *pinfo) int __init cpm_uart_init_portdesc(void) { #if defined(CONFIG_SERIAL_CPM_SMC1) || defined(CONFIG_SERIAL_CPM_SMC2) - u32 addr; + u16 *addr; #endif pr_debug("CPM uart[-]:init portdesc\n"); diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c index e216dcf29376..04cc88cc528c 100644 --- a/drivers/serial/imx.c +++ b/drivers/serial/imx.c @@ -154,7 +154,7 @@ static inline void imx_transmit_buffer(struct imx_port *sport) { struct circ_buf *xmit = &sport->port.info->xmit; - do { + while (!(UTS((u32)sport->port.membase) & UTS_TXFULL)) { /* send xmit->buf[xmit->tail] * out the port here */ URTX0((u32)sport->port.membase) = xmit->buf[xmit->tail]; @@ -163,7 +163,7 @@ static inline void imx_transmit_buffer(struct imx_port *sport) sport->port.icount.tx++; if (uart_circ_empty(xmit)) break; - } while (!(UTS((u32)sport->port.membase) & UTS_TXFULL)); + } if (uart_circ_empty(xmit)) imx_stop_tx(&sport->port); @@ -178,8 +178,7 @@ static void imx_start_tx(struct uart_port *port) UCR1((u32)sport->port.membase) |= UCR1_TXMPTYEN; - if(UTS((u32)sport->port.membase) & UTS_TXEMPTY) - imx_transmit_buffer(sport); + imx_transmit_buffer(sport); } static irqreturn_t imx_rtsint(int irq, void *dev_id) @@ -404,7 +403,8 @@ static int imx_startup(struct uart_port *port) if (retval) goto error_out2; retval = request_irq(sport->rtsirq, imx_rtsint, - IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, + (sport->rtsirq < IMX_IRQS) ? 0 : + IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, DRIVER_NAME, sport); if (retval) goto error_out3; @@ -678,7 +678,7 @@ static struct imx_port imx_ports[] = { .mapbase = IMX_UART1_BASE, /* FIXME */ .irq = UART1_MINT_RX, .uartclk = 16000000, - .fifosize = 8, + .fifosize = 32, .flags = UPF_BOOT_AUTOCONF, .ops = &imx_pops, .line = 0, @@ -694,7 +694,7 @@ static struct imx_port imx_ports[] = { .mapbase = IMX_UART2_BASE, /* FIXME */ .irq = UART2_MINT_RX, .uartclk = 16000000, - .fifosize = 8, + .fifosize = 32, .flags = UPF_BOOT_AUTOCONF, .ops = &imx_pops, .line = 1, diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c index 955bbd653e22..8d24cd521056 100644 --- a/drivers/serial/mpc52xx_uart.c +++ b/drivers/serial/mpc52xx_uart.c @@ -995,8 +995,10 @@ mpc52xx_uart_of_remove(struct of_device *op) struct uart_port *port = dev_get_drvdata(&op->dev); dev_set_drvdata(&op->dev, NULL); - if (port) + if (port) { uart_remove_one_port(&mpc52xx_uart_driver, port); + irq_dispose_mapping(port->irq); + } return 0; } diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c index c2f1012449da..6b76babc7fbf 100644 --- a/drivers/serial/serial_cs.c +++ b/drivers/serial/serial_cs.c @@ -248,6 +248,10 @@ static const struct serial_quirk quirks[] = { .multi = 2, }, { .manfid = MANFID_QUATECH, + .prodid = PRODID_QUATECH_DUAL_RS232_G, + .multi = 2, + }, { + .manfid = MANFID_QUATECH, .prodid = PRODID_QUATECH_QUAD_RS232, .multi = 4, }, { @@ -891,6 +895,7 @@ static struct pcmcia_device_id serial_ids[] = { PCMCIA_DEVICE_PROD_ID12("OEM ", "C288MX ", 0xb572d360, 0xd2385b7a), PCMCIA_DEVICE_PROD_ID12("PCMCIA ", "C336MX ", 0x99bcafe9, 0xaa25bcab), PCMCIA_DEVICE_PROD_ID12("Quatech Inc", "PCMCIA Dual RS-232 Serial Port Card", 0xc4420b35, 0x92abc92f), + PCMCIA_DEVICE_PROD_ID12("Quatech Inc", "Dual RS-232 Serial Port PC Card", 0xc4420b35, 0x031a380d), PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "PCMCIA", "EN2218-LAN/MODEM", 0x281f1c5d, 0x570f348e, "PCMLM28.cis"), PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "PCMCIA", "UE2218-LAN/MODEM", 0x281f1c5d, 0x6fdcacee, "PCMLM28.cis"), PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "Psion Dacom", "Gold Card V34 Ethernet", 0xf5f025c2, 0x338e8155, "PCMLM28.cis"), diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index 825bf884537a..8b7ff467d262 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -51,6 +51,7 @@ obj-$(CONFIG_USB_SERIAL) += serial/ obj-$(CONFIG_USB_ADUTUX) += misc/ obj-$(CONFIG_USB_APPLEDISPLAY) += misc/ obj-$(CONFIG_USB_AUERSWALD) += misc/ +obj-$(CONFIG_USB_BERRY_CHARGE) += misc/ obj-$(CONFIG_USB_CYPRESS_CY7C63)+= misc/ obj-$(CONFIG_USB_CYTHERM) += misc/ obj-$(CONFIG_USB_EMI26) += misc/ diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index dae4ef1e8fe5..4973e147bc79 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -61,6 +61,7 @@ #include <linux/usb.h> #include <linux/firmware.h> #include <linux/ctype.h> +#include <linux/sched.h> #include <linux/kthread.h> #include <linux/version.h> #include <linux/mutex.h> diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 98199628e394..d38a25f36ea5 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -326,10 +326,16 @@ static void acm_rx_tasklet(unsigned long _acm) struct tty_struct *tty = acm->tty; struct acm_ru *rcv; unsigned long flags; - int i = 0; + unsigned char throttled; dbg("Entering acm_rx_tasklet"); - if (!ACM_READY(acm) || acm->throttle) + if (!ACM_READY(acm)) + return; + + spin_lock(&acm->throttle_lock); + throttled = acm->throttle; + spin_unlock(&acm->throttle_lock); + if (throttled) return; next_buffer: @@ -346,22 +352,20 @@ next_buffer: dbg("acm_rx_tasklet: procesing buf 0x%p, size = %d", buf, buf->size); tty_buffer_request_room(tty, buf->size); - if (!acm->throttle) + spin_lock(&acm->throttle_lock); + throttled = acm->throttle; + spin_unlock(&acm->throttle_lock); + if (!throttled) tty_insert_flip_string(tty, buf->base, buf->size); tty_flip_buffer_push(tty); - spin_lock(&acm->throttle_lock); - if (acm->throttle) { - dbg("Throtteling noticed"); - memmove(buf->base, buf->base + i, buf->size - i); - buf->size -= i; - spin_unlock(&acm->throttle_lock); + if (throttled) { + dbg("Throttling noticed"); spin_lock_irqsave(&acm->read_lock, flags); list_add(&buf->list, &acm->filled_read_bufs); spin_unlock_irqrestore(&acm->read_lock, flags); return; } - spin_unlock(&acm->throttle_lock); spin_lock_irqsave(&acm->read_lock, flags); list_add(&buf->list, &acm->spare_read_bufs); @@ -467,7 +471,8 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp) goto bail_out; } - if (0 > acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS)) + if (0 > acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS) && + (acm->ctrl_caps & USB_CDC_CAP_LINE)) goto full_bailout; INIT_LIST_HEAD(&acm->spare_read_urbs); @@ -480,6 +485,8 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp) list_add(&(acm->rb[i].list), &acm->spare_read_bufs); } + acm->throttle = 0; + tasklet_schedule(&acm->urb_task); done: @@ -1092,6 +1099,10 @@ static struct usb_device_id acm_ids[] = { { USB_DEVICE(0x0ace, 0x1611), /* ZyDAS 56K USB MODEM - new version */ .driver_info = SINGLE_RX_URB, /* firmware bug */ }, + { USB_DEVICE(0x22b8, 0x7000), /* Motorola Q Phone */ + .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ + }, + /* control interfaces with various AT-command sets */ { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, USB_CDC_ACM_PROTO_AT_V25TER) }, diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c index a47c30b2d764..aefc7987120d 100644 --- a/drivers/usb/core/devices.c +++ b/drivers/usb/core/devices.c @@ -604,10 +604,6 @@ static unsigned int usb_device_poll(struct file *file, struct poll_table_struct lock_kernel(); if (!st) { st = kmalloc(sizeof(struct usb_device_status), GFP_KERNEL); - if (!st) { - unlock_kernel(); - return POLLIN; - } /* we may have dropped BKL - need to check for having lost the race */ if (file->private_data) { @@ -615,6 +611,11 @@ static unsigned int usb_device_poll(struct file *file, struct poll_table_struct st = file->private_data; goto lost_race; } + /* we haven't lost - check for allocation failure now */ + if (!st) { + unlock_kernel(); + return POLLIN; + } /* * need to prevent the module from being unloaded, since diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 2087766f9e88..274f14f1633e 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -857,11 +857,11 @@ static int proc_setintf(struct dev_state *ps, void __user *arg) static int proc_setconfig(struct dev_state *ps, void __user *arg) { - unsigned int u; + int u; int status = 0; struct usb_host_config *actconfig; - if (get_user(u, (unsigned int __user *)arg)) + if (get_user(u, (int __user *)arg)) return -EFAULT; actconfig = ps->dev->actconfig; diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 600d1bc8272a..2aded261f42c 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -743,6 +743,7 @@ EXPORT_SYMBOL_GPL(usb_deregister_device_driver); * usb_register_driver - register a USB interface driver * @new_driver: USB operations for the interface driver * @owner: module owner of this driver. + * @mod_name: module name string * * Registers a USB interface driver with the USB core. The list of * unattached interfaces will be rescanned whenever a new driver is diff --git a/drivers/usb/core/endpoint.c b/drivers/usb/core/endpoint.c index 5e628ae3aec7..e0ec7045e865 100644 --- a/drivers/usb/core/endpoint.c +++ b/drivers/usb/core/endpoint.c @@ -229,7 +229,7 @@ static int init_endpoint_class(void) kref_init(&ep_class->kref); ep_class->class = class_create(THIS_MODULE, "usb_endpoint"); if (IS_ERR(ep_class->class)) { - result = IS_ERR(ep_class->class); + result = PTR_ERR(ep_class->class); goto class_create_error; } diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c index b531a4fd30c2..9bbcb20e2d94 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c @@ -184,7 +184,7 @@ static void generic_disconnect(struct usb_device *udev) /* if this is only an unbind, not a physical disconnect, then * unconfigure the device */ if (udev->actconfig) - usb_set_configuration(udev, 0); + usb_set_configuration(udev, -1); usb_remove_sysfs_dev_files(udev); } diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 590ec82d0515..50c0db15304a 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -44,6 +44,7 @@ struct usb_hub { struct usb_hub_status hub; struct usb_port_status port; } *status; /* buffer for status reports */ + struct mutex status_mutex; /* for the status buffer */ int error; /* last reported error */ int nerrors; /* track consecutive errors */ @@ -535,6 +536,7 @@ static int hub_hub_status(struct usb_hub *hub, { int ret; + mutex_lock(&hub->status_mutex); ret = get_hub_status(hub->hdev, &hub->status->hub); if (ret < 0) dev_err (hub->intfdev, @@ -544,6 +546,7 @@ static int hub_hub_status(struct usb_hub *hub, *change = le16_to_cpu(hub->status->hub.wHubChange); ret = 0; } + mutex_unlock(&hub->status_mutex); return ret; } @@ -617,6 +620,7 @@ static int hub_configure(struct usb_hub *hub, ret = -ENOMEM; goto fail; } + mutex_init(&hub->status_mutex); hub->descriptor = kmalloc(sizeof(*hub->descriptor), GFP_KERNEL); if (!hub->descriptor) { @@ -1396,6 +1400,7 @@ static int hub_port_status(struct usb_hub *hub, int port1, { int ret; + mutex_lock(&hub->status_mutex); ret = get_port_status(hub->hdev, port1, &hub->status->port); if (ret < 4) { dev_err (hub->intfdev, @@ -1407,6 +1412,7 @@ static int hub_port_status(struct usb_hub *hub, int port1, *change = le16_to_cpu(hub->status->port.wPortChange); ret = 0; } + mutex_unlock(&hub->status_mutex); return ret; } @@ -1904,6 +1910,7 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg) struct usb_hub *hub = usb_get_intfdata (intf); struct usb_device *hdev = hub->hdev; unsigned port1; + int status = 0; /* fail if children aren't already suspended */ for (port1 = 1; port1 <= hdev->maxchild; port1++) { @@ -1927,24 +1934,18 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg) dev_dbg(&intf->dev, "%s\n", __FUNCTION__); + /* stop khubd and related activity */ + hub_quiesce(hub); + /* "global suspend" of the downstream HC-to-USB interface */ if (!hdev->parent) { - struct usb_bus *bus = hdev->bus; - if (bus) { - int status = hcd_bus_suspend (bus); - - if (status != 0) { - dev_dbg(&hdev->dev, "'global' suspend %d\n", - status); - return status; - } - } else - return -EOPNOTSUPP; + status = hcd_bus_suspend(hdev->bus); + if (status != 0) { + dev_dbg(&hdev->dev, "'global' suspend %d\n", status); + hub_activate(hub); + } } - - /* stop khubd and related activity */ - hub_quiesce(hub); - return 0; + return status; } static int hub_resume(struct usb_interface *intf) diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 8aca3574c2b5..74edaea5665d 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1316,6 +1316,14 @@ static void release_interface(struct device *dev) * use this kind of configurability; many devices only have one * configuration. * + * @configuration is the value of the configuration to be installed. + * According to the USB spec (e.g. section 9.1.1.5), configuration values + * must be non-zero; a value of zero indicates that the device in + * unconfigured. However some devices erroneously use 0 as one of their + * configuration values. To help manage such devices, this routine will + * accept @configuration = -1 as indicating the device should be put in + * an unconfigured state. + * * USB device configurations may affect Linux interoperability, * power consumption and the functionality available. For example, * the default configuration is limited to using 100mA of bus power, @@ -1347,10 +1355,15 @@ int usb_set_configuration(struct usb_device *dev, int configuration) struct usb_interface **new_interfaces = NULL; int n, nintf; - for (i = 0; i < dev->descriptor.bNumConfigurations; i++) { - if (dev->config[i].desc.bConfigurationValue == configuration) { - cp = &dev->config[i]; - break; + if (configuration == -1) + configuration = 0; + else { + for (i = 0; i < dev->descriptor.bNumConfigurations; i++) { + if (dev->config[i].desc.bConfigurationValue == + configuration) { + cp = &dev->config[i]; + break; + } } } if ((!cp && configuration != 0)) @@ -1359,6 +1372,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration) /* The USB spec says configuration 0 means unconfigured. * But if a device includes a configuration numbered 0, * we will accept it as a correctly configured state. + * Use -1 if you really want to unconfigure the device. */ if (cp && configuration == 0) dev_warn(&dev->dev, "config 0 descriptor??\n"); diff --git a/drivers/usb/core/otg_whitelist.h b/drivers/usb/core/otg_whitelist.h index 627a5a2fc9cf..7f31a495a25d 100644 --- a/drivers/usb/core/otg_whitelist.h +++ b/drivers/usb/core/otg_whitelist.h @@ -31,7 +31,7 @@ static struct usb_device_id whitelist_table [] = { { USB_DEVICE_INFO(7, 1, 3) }, #endif -#ifdef CONFIG_USB_CDCETHER +#ifdef CONFIG_USB_NET_CDCETHER /* Linux-USB CDC Ethernet gadget */ { USB_DEVICE(0x0525, 0xa4a1), }, /* Linux-USB CDC Ethernet + RNDIS gadget */ diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index 4eaa0ee8e72f..0edfbafd702c 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -63,7 +63,7 @@ set_bConfigurationValue(struct device *dev, struct device_attribute *attr, struct usb_device *udev = to_usb_device(dev); int config, value; - if (sscanf(buf, "%u", &config) != 1 || config > 255) + if (sscanf(buf, "%d", &config) != 1 || config < -1 || config > 255) return -EINVAL; usb_lock_device(udev); value = usb_set_configuration(udev, config); diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index 36b36e0175fc..a4677802fb20 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -784,7 +784,7 @@ static int at91_ep_set_halt(struct usb_ep *_ep, int value) return status; } -static struct usb_ep_ops at91_ep_ops = { +static const struct usb_ep_ops at91_ep_ops = { .enable = at91_ep_enable, .disable = at91_ep_disable, .alloc_request = at91_ep_alloc_request, @@ -912,7 +912,7 @@ static void pullup(struct at91_udc *udc, int is_on) 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()) { + else if (cpu_is_at91sam9260() || cpu_is_at91sam9263()) { u32 txvc = at91_udp_read(udc, AT91_UDP_TXVC); txvc |= AT91_UDP_TXVC_PUON; @@ -929,7 +929,7 @@ static void pullup(struct at91_udc *udc, int is_on) 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()) { + else if (cpu_is_at91sam9260() || cpu_is_at91sam9263()) { u32 txvc = at91_udp_read(udc, AT91_UDP_TXVC); txvc &= ~AT91_UDP_TXVC_PUON; @@ -1651,7 +1651,7 @@ static void at91udc_shutdown(struct platform_device *dev) pullup(platform_get_drvdata(dev), 0); } -static int __devinit at91udc_probe(struct platform_device *pdev) +static int __init at91udc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct at91_udc *udc; @@ -1762,7 +1762,7 @@ fail0: return retval; } -static int __devexit at91udc_remove(struct platform_device *pdev) +static int __exit at91udc_remove(struct platform_device *pdev) { struct at91_udc *udc = platform_get_drvdata(pdev); struct resource *res; @@ -1836,8 +1836,7 @@ static int at91udc_resume(struct platform_device *pdev) #endif static struct platform_driver at91_udc = { - .probe = at91udc_probe, - .remove = __devexit_p(at91udc_remove), + .remove = __exit_p(at91udc_remove), .shutdown = at91udc_shutdown, .suspend = at91udc_suspend, .resume = at91udc_resume, @@ -1847,13 +1846,13 @@ static struct platform_driver at91_udc = { }, }; -static int __devinit udc_init_module(void) +static int __init udc_init_module(void) { - return platform_driver_register(&at91_udc); + return platform_driver_probe(&at91_udc, at91udc_probe); } module_init(udc_init_module); -static void __devexit udc_exit_module(void) +static void __exit udc_exit_module(void) { platform_driver_unregister(&at91_udc); } diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c index 27904a56494b..f01890dc8751 100644 --- a/drivers/usb/gadget/pxa2xx_udc.c +++ b/drivers/usb/gadget/pxa2xx_udc.c @@ -155,7 +155,7 @@ static int is_vbus_present(void) struct pxa2xx_udc_mach_info *mach = the_controller->mach; if (mach->gpio_vbus) - return pxa_gpio_get(mach->gpio_vbus); + return udc_gpio_get(mach->gpio_vbus); if (mach->udc_is_connected) return mach->udc_is_connected(); return 1; @@ -167,7 +167,7 @@ static void pullup_off(void) struct pxa2xx_udc_mach_info *mach = the_controller->mach; if (mach->gpio_pullup) - pxa_gpio_set(mach->gpio_pullup, 0); + udc_gpio_set(mach->gpio_pullup, 0); else if (mach->udc_command) mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT); } @@ -177,7 +177,7 @@ static void pullup_on(void) struct pxa2xx_udc_mach_info *mach = the_controller->mach; if (mach->gpio_pullup) - pxa_gpio_set(mach->gpio_pullup, 1); + udc_gpio_set(mach->gpio_pullup, 1); else if (mach->udc_command) mach->udc_command(PXA2XX_UDC_CMD_CONNECT); } @@ -1755,7 +1755,7 @@ lubbock_vbus_irq(int irq, void *_dev) static irqreturn_t udc_vbus_irq(int irq, void *_dev) { struct pxa2xx_udc *dev = _dev; - int vbus = pxa_gpio_get(dev->mach->gpio_vbus); + int vbus = udc_gpio_get(dev->mach->gpio_vbus); pxa2xx_udc_vbus_session(&dev->gadget, vbus); return IRQ_HANDLED; @@ -2545,15 +2545,13 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev) dev->dev = &pdev->dev; dev->mach = pdev->dev.platform_data; if (dev->mach->gpio_vbus) { - vbus_irq = IRQ_GPIO(dev->mach->gpio_vbus & GPIO_MD_MASK_NR); - pxa_gpio_mode((dev->mach->gpio_vbus & GPIO_MD_MASK_NR) - | GPIO_IN); + udc_gpio_init_vbus(dev->mach->gpio_vbus); + vbus_irq = udc_gpio_to_irq(dev->mach->gpio_vbus); set_irq_type(vbus_irq, IRQT_BOTHEDGE); } else vbus_irq = 0; if (dev->mach->gpio_pullup) - pxa_gpio_mode((dev->mach->gpio_pullup & GPIO_MD_MASK_NR) - | GPIO_OUT | GPIO_DFLT_LOW); + udc_gpio_init_pullup(dev->mach->gpio_pullup); init_timer(&dev->timer); dev->timer.function = udc_watchdog; diff --git a/drivers/usb/gadget/pxa2xx_udc.h b/drivers/usb/gadget/pxa2xx_udc.h index 8e598c8bf4e3..773e549aff3f 100644 --- a/drivers/usb/gadget/pxa2xx_udc.h +++ b/drivers/usb/gadget/pxa2xx_udc.h @@ -177,21 +177,6 @@ struct pxa2xx_udc { static struct pxa2xx_udc *the_controller; -static inline int pxa_gpio_get(unsigned gpio) -{ - return (GPLR(gpio) & GPIO_bit(gpio)) != 0; -} - -static inline void pxa_gpio_set(unsigned gpio, int is_on) -{ - int mask = GPIO_bit(gpio); - - if (is_on) - GPSR(gpio) = mask; - else - GPCR(gpio) = mask; -} - /*-------------------------------------------------------------------------*/ /* diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index e6c19aa4bef3..e552668d36b3 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c @@ -1699,6 +1699,7 @@ static int gs_setup_class(struct usb_gadget *gadget, memcpy(&port->port_line_coding, req->buf, ret); spin_unlock(&port->port_lock); } + ret = 0; break; case USB_CDC_REQ_GET_LINE_CODING: diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c index 246afea9e83b..43eddaecc3dd 100644 --- a/drivers/usb/host/ehci-dbg.c +++ b/drivers/usb/host/ehci-dbg.c @@ -322,7 +322,7 @@ static inline void remove_debug_files (struct ehci_hcd *bus) { } #else -/* troubleshooting help: expose state in driverfs */ +/* troubleshooting help: expose state in sysfs */ #define speed_char(info1) ({ char tmp; \ switch (info1 & (3 << 12)) { \ diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 185721dba42b..a74056488234 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -42,6 +42,9 @@ #include <asm/irq.h> #include <asm/system.h> #include <asm/unaligned.h> +#ifdef CONFIG_PPC_PS3 +#include <asm/firmware.h> +#endif /*-------------------------------------------------------------------------*/ @@ -299,6 +302,19 @@ static void ehci_watchdog (unsigned long param) spin_unlock_irqrestore (&ehci->lock, flags); } +/* On some systems, leaving remote wakeup enabled prevents system shutdown. + * The firmware seems to think that powering off is a wakeup event! + * This routine turns off remote wakeup and everything else, on all ports. + */ +static void ehci_turn_off_all_ports(struct ehci_hcd *ehci) +{ + int port = HCS_N_PORTS(ehci->hcs_params); + + while (port--) + ehci_writel(ehci, PORT_RWC_BITS, + &ehci->regs->port_status[port]); +} + /* ehci_shutdown kick in for silicon on any bus (not just pci, etc). * This forcibly disables dma and IRQs, helping kexec and other cases * where the next system software may expect clean state. @@ -310,9 +326,13 @@ ehci_shutdown (struct usb_hcd *hcd) ehci = hcd_to_ehci (hcd); (void) ehci_halt (ehci); + ehci_turn_off_all_ports(ehci); /* make BIOS/etc use companion controller during reboot */ ehci_writel(ehci, 0, &ehci->regs->configured_flag); + + /* unblock posted writes */ + ehci_readl(ehci, &ehci->regs->configured_flag); } static void ehci_port_power (struct ehci_hcd *ehci, int is_on) @@ -951,15 +971,18 @@ static int __init ehci_hcd_init(void) #endif #ifdef PS3_SYSTEM_BUS_DRIVER - retval = ps3_system_bus_driver_register(&PS3_SYSTEM_BUS_DRIVER); - if (retval < 0) { + if (firmware_has_feature(FW_FEATURE_PS3_LV1)) { + retval = ps3_system_bus_driver_register( + &PS3_SYSTEM_BUS_DRIVER); + if (retval < 0) { #ifdef PLATFORM_DRIVER - platform_driver_unregister(&PLATFORM_DRIVER); + platform_driver_unregister(&PLATFORM_DRIVER); #endif #ifdef PCI_DRIVER - pci_unregister_driver(&PCI_DRIVER); + pci_unregister_driver(&PCI_DRIVER); #endif - return retval; + return retval; + } } #endif @@ -976,7 +999,8 @@ static void __exit ehci_hcd_cleanup(void) pci_unregister_driver(&PCI_DRIVER); #endif #ifdef PS3_SYSTEM_BUS_DRIVER - ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER); + if (firmware_has_feature(FW_FEATURE_PS3_LV1)) + ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER); #endif } module_exit(ehci_hcd_cleanup); diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 0d83c6df1a3b..9af529d22b3e 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -36,6 +36,8 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) int port; int mask; + ehci_dbg(ehci, "suspend root hub\n"); + if (time_before (jiffies, ehci->next_statechange)) msleep(5); diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index 2718b5dc4ec1..46873f2534b5 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -1577,7 +1577,7 @@ static int isp116x_remove(struct platform_device *pdev) #define resource_len(r) (((r)->end - (r)->start) + 1) -static int __init isp116x_probe(struct platform_device *pdev) +static int __devinit isp116x_probe(struct platform_device *pdev) { struct usb_hcd *hcd; struct isp116x *isp116x; diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index 930346487278..d849c809acbd 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -18,19 +18,38 @@ #include <asm/mach-types.h> #include <asm/hardware.h> #include <asm/arch/board.h> +#include <asm/arch/cpu.h> #ifndef CONFIG_ARCH_AT91 #error "CONFIG_ARCH_AT91 must be defined." #endif -/* interface and function clocks */ -static struct clk *iclk, *fclk; +/* interface and function clocks; sometimes also an AHB clock */ +static struct clk *iclk, *fclk, *hclk; static int clocked; extern int usb_disabled(void); /*-------------------------------------------------------------------------*/ +static void at91_start_clock(void) +{ + if (cpu_is_at91sam9261()) + clk_enable(hclk); + clk_enable(iclk); + clk_enable(fclk); + clocked = 1; +} + +static void at91_stop_clock(void) +{ + clk_disable(fclk); + clk_disable(iclk); + if (cpu_is_at91sam9261()) + clk_disable(hclk); + clocked = 0; +} + static void at91_start_hc(struct platform_device *pdev) { struct usb_hcd *hcd = platform_get_drvdata(pdev); @@ -41,9 +60,7 @@ static void at91_start_hc(struct platform_device *pdev) /* * Start the USB clocks. */ - clk_enable(iclk); - clk_enable(fclk); - clocked = 1; + at91_start_clock(); /* * The USB host controller must remain in reset. @@ -66,9 +83,7 @@ static void at91_stop_hc(struct platform_device *pdev) /* * Stop the USB clocks. */ - clk_disable(fclk); - clk_disable(iclk); - clocked = 0; + at91_stop_clock(); } @@ -126,6 +141,8 @@ static int usb_hcd_at91_probe(const struct hc_driver *driver, iclk = clk_get(&pdev->dev, "ohci_clk"); fclk = clk_get(&pdev->dev, "uhpck"); + if (cpu_is_at91sam9261()) + hclk = clk_get(&pdev->dev, "hck0"); at91_start_hc(pdev); ohci_hcd_init(hcd_to_ohci(hcd)); @@ -137,6 +154,8 @@ static int usb_hcd_at91_probe(const struct hc_driver *driver, /* Error handling */ at91_stop_hc(pdev); + if (cpu_is_at91sam9261()) + clk_put(hclk); clk_put(fclk); clk_put(iclk); @@ -171,9 +190,11 @@ static int usb_hcd_at91_remove(struct usb_hcd *hcd, iounmap(hcd->regs); release_mem_region(hcd->rsrc_start, hcd->rsrc_len); + if (cpu_is_at91sam9261()) + clk_put(hclk); clk_put(fclk); clk_put(iclk); - fclk = iclk = NULL; + fclk = iclk = hclk = NULL; dev_set_drvdata(&pdev->dev, NULL); return 0; @@ -280,9 +301,7 @@ ohci_hcd_at91_drv_suspend(struct platform_device *pdev, pm_message_t mesg) */ if (at91_suspend_entering_slow_clock()) { ohci_usb_reset (ohci); - clk_disable(fclk); - clk_disable(iclk); - clocked = 0; + at91_stop_clock(); } return 0; @@ -295,11 +314,8 @@ static int ohci_hcd_at91_drv_resume(struct platform_device *pdev) if (device_may_wakeup(&pdev->dev)) disable_irq_wake(hcd->irq); - if (!clocked) { - clk_enable(iclk); - clk_enable(fclk); - clocked = 1; - } + if (!clocked) + at91_start_clock(); return 0; } diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index fa6a7ceaa0db..f0d29eda3c6d 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -42,6 +42,9 @@ #include <asm/system.h> #include <asm/unaligned.h> #include <asm/byteorder.h> +#ifdef CONFIG_PPC_PS3 +#include <asm/firmware.h> +#endif #include "../core/hcd.h" @@ -944,9 +947,12 @@ static int __init ohci_hcd_mod_init(void) sizeof (struct ed), sizeof (struct td)); #ifdef PS3_SYSTEM_BUS_DRIVER - retval = ps3_system_bus_driver_register(&PS3_SYSTEM_BUS_DRIVER); - if (retval < 0) - goto error_ps3; + if (firmware_has_feature(FW_FEATURE_PS3_LV1)) { + retval = ps3_system_bus_driver_register( + &PS3_SYSTEM_BUS_DRIVER); + if (retval < 0) + goto error_ps3; + } #endif #ifdef PLATFORM_DRIVER @@ -992,7 +998,8 @@ static int __init ohci_hcd_mod_init(void) error_platform: #endif #ifdef PS3_SYSTEM_BUS_DRIVER - ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER); + if (firmware_has_feature(FW_FEATURE_PS3_LV1)) + ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER); error_ps3: #endif return retval; @@ -1014,7 +1021,8 @@ static void __exit ohci_hcd_mod_exit(void) platform_driver_unregister(&PLATFORM_DRIVER); #endif #ifdef PS3_SYSTEM_BUS_DRIVER - ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER); + if (firmware_has_feature(FW_FEATURE_PS3_LV1)) + ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER); #endif } module_exit(ohci_hcd_mod_exit); diff --git a/drivers/usb/input/Kconfig b/drivers/usb/input/Kconfig index 2e71d3cca198..69a9f3b6d0a9 100644 --- a/drivers/usb/input/Kconfig +++ b/drivers/usb/input/Kconfig @@ -58,13 +58,17 @@ config HID_PID devices. config LOGITECH_FF - bool "Logitech WingMan *3D support" + bool "Logitech devices support" depends on HID_FF select INPUT_FF_MEMLESS if USB_HID help Say Y here if you have one of these devices: - Logitech WingMan Cordless RumblePad + - Logitech WingMan Cordless RumblePad 2 - Logitech WingMan Force 3D + - Logitech Formula Force EX + - Logitech MOMO Force wheel + and if you want to enable force feedback for them. Note: if you say N here, this device will still be supported, but without force feedback. diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 4d8ed3d71a15..ef09952f2039 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -515,6 +515,7 @@ void usbhid_close(struct hid_device *hid) #define USB_VENDOR_ID_TURBOX 0x062a #define USB_DEVICE_ID_TURBOX_KEYBOARD 0x0201 +#define USB_VENDOR_ID_CIDC 0x1677 /* * Initialize all reports @@ -548,7 +549,6 @@ 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 @@ -594,8 +594,6 @@ 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 @@ -854,8 +852,6 @@ 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 }, @@ -953,6 +949,8 @@ static const struct hid_blacklist { { USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER, HID_QUIRK_SONY_PS3_CONTROLLER }, + { USB_VENDOR_ID_CIDC, 0x0103, HID_QUIRK_IGNORE }, + { 0, 0 } }; diff --git a/drivers/usb/input/hid-ff.c b/drivers/usb/input/hid-ff.c index bc7f8e6f8c97..e431faaa6abc 100644 --- a/drivers/usb/input/hid-ff.c +++ b/drivers/usb/input/hid-ff.c @@ -54,9 +54,10 @@ struct hid_ff_initializer { static struct hid_ff_initializer inits[] = { #ifdef CONFIG_LOGITECH_FF { 0x46d, 0xc211, hid_lgff_init }, /* Logitech Cordless rumble pad */ + { 0x46d, 0xc219, hid_lgff_init }, /* Logitech Cordless rumble pad 2 */ { 0x46d, 0xc283, hid_lgff_init }, /* Logitech Wingman Force 3d */ + { 0x46d, 0xc294, hid_lgff_init }, /* Logitech Formula Force EX */ { 0x46d, 0xc295, hid_lgff_init }, /* Logitech MOMO force wheel */ - { 0x46d, 0xc219, hid_lgff_init }, /* Logitech Cordless rumble pad 2 */ { 0x46d, 0xca03, hid_lgff_init }, /* Logitech MOMO force wheel */ #endif #ifdef CONFIG_PANTHERLORD_FF diff --git a/drivers/usb/input/hid-lgff.c b/drivers/usb/input/hid-lgff.c index 4df0968f852e..e6f3af3e66d1 100644 --- a/drivers/usb/input/hid-lgff.c +++ b/drivers/usb/input/hid-lgff.c @@ -52,8 +52,9 @@ static const struct dev_type devices[] = { { 0x046d, 0xc211, ff_rumble }, { 0x046d, 0xc219, ff_rumble }, { 0x046d, 0xc283, ff_joystick }, + { 0x046d, 0xc294, ff_joystick }, + { 0x046d, 0xc295, ff_joystick }, { 0x046d, 0xca03, ff_joystick }, - { 0x0000, 0x0000, ff_joystick } }; static int hid_lgff_play(struct input_dev *dev, void *data, struct ff_effect *effect) @@ -105,8 +106,9 @@ int hid_lgff_init(struct hid_device* hid) struct input_dev *dev = hidinput->input; struct hid_report *report; struct hid_field *field; + const signed short *ff_bits = ff_joystick; int error; - int i, j; + int i; /* Find the report to use */ if (list_empty(report_list)) { @@ -130,12 +132,14 @@ int hid_lgff_init(struct hid_device* hid) for (i = 0; i < ARRAY_SIZE(devices); i++) { if (dev->id.vendor == devices[i].idVendor && dev->id.product == devices[i].idProduct) { - for (j = 0; devices[i].ff[j] >= 0; j++) - set_bit(devices[i].ff[j], dev->ffbit); + ff_bits = devices[i].ff; break; } } + for (i = 0; ff_bits[i] >= 0; i++) + set_bit(ff_bits[i], dev->ffbit); + error = input_ff_create_memless(dev, NULL, hid_lgff_play); if (error) return error; diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index a74bf8617e7f..4907e8b80070 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig @@ -88,6 +88,17 @@ config USB_LCD To compile this driver as a module, choose M here: the module will be called usblcd. +config USB_BERRY_CHARGE + tristate "USB BlackBerry recharge support" + depends on USB + help + Say Y here if you want to connect a BlackBerry device to your + computer's USB port and have it automatically switch to "recharge" + mode. + + To compile this driver as a module, choose M here: the + module will be called berry_charge. + config USB_LED tristate "USB LED driver support" depends on USB diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile index 2cba07d31971..dac2d5b71566 100644 --- a/drivers/usb/misc/Makefile +++ b/drivers/usb/misc/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_USB_ADUTUX) += adutux.o obj-$(CONFIG_USB_APPLEDISPLAY) += appledisplay.o obj-$(CONFIG_USB_AUERSWALD) += auerswald.o +obj-$(CONFIG_USB_BERRY_CHARGE) += berry_charge.o obj-$(CONFIG_USB_CYPRESS_CY7C63)+= cypress_cy7c63.o obj-$(CONFIG_USB_CYTHERM) += cytherm.o obj-$(CONFIG_USB_EMI26) += emi26.o diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c index 32f0e3a5b022..e573c8ba9785 100644 --- a/drivers/usb/misc/appledisplay.c +++ b/drivers/usb/misc/appledisplay.c @@ -281,8 +281,8 @@ 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, NULL, - pdata, &appledisplay_bl_data); + pdata->bd = backlight_device_register(bl_name, NULL, pdata, + &appledisplay_bl_data); if (IS_ERR(pdata->bd)) { err("appledisplay: Backlight registration failed"); goto error; diff --git a/drivers/usb/misc/berry_charge.c b/drivers/usb/misc/berry_charge.c new file mode 100644 index 000000000000..60893c6c8221 --- /dev/null +++ b/drivers/usb/misc/berry_charge.c @@ -0,0 +1,140 @@ +/* + * USB BlackBerry charging module + * + * Copyright (C) 2007 Greg Kroah-Hartman <gregkh@suse.de> + * + * 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, version 2. + * + * Information on how to switch configs was taken by the bcharge.cc file + * created by the barry.sf.net project. + * + * bcharge.cc has the following copyright: + * Copyright (C) 2006, Net Direct Inc. (http://www.netdirect.ca/) + * and is released under the GPLv2. + * + * + */ + +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/usb.h> + +#define RIM_VENDOR 0x0fca +#define BLACKBERRY 0x0001 + +static int debug; + +#ifdef dbg +#undef dbg +#endif +#define dbg(dev, format, arg...) \ + if (debug) \ + dev_printk(KERN_DEBUG , dev , format , ## arg) + +static struct usb_device_id id_table [] = { + { USB_DEVICE(RIM_VENDOR, BLACKBERRY) }, + { }, /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(usb, id_table); + +static int magic_charge(struct usb_device *udev) +{ + char *dummy_buffer = kzalloc(2, GFP_KERNEL); + int retval; + + if (!dummy_buffer) + return -ENOMEM; + + /* send two magic commands and then set the configuration. The device + * will then reset itself with the new power usage and should start + * charging. */ + + /* Note, with testing, it only seems that the first message is really + * needed (at least for the 8700c), but to be safe, we emulate what + * other operating systems seem to be sending to their device. We + * really need to get some specs for this device to be sure about what + * is going on here. + */ + dbg(&udev->dev, "Sending first magic command\n"); + retval = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + 0xa5, 0xc0, 0, 1, dummy_buffer, 2, 100); + if (retval != 2) { + dev_err(&udev->dev, "First magic command failed: %d.\n", + retval); + return retval; + } + + dbg(&udev->dev, "Sending first magic command\n"); + retval = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + 0xa2, 0x40, 0, 1, dummy_buffer, 0, 100); + if (retval != 0) { + dev_err(&udev->dev, "Second magic command failed: %d.\n", + retval); + return retval; + } + + dbg(&udev->dev, "Calling set_configuration\n"); + retval = usb_driver_set_configuration(udev, 1); + if (retval) + dev_err(&udev->dev, "Set Configuration failed :%d.\n", retval); + + return retval; +} + +static int berry_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_device *udev = interface_to_usbdev(intf); + + dbg(&udev->dev, "Power is set to %dmA\n", + udev->actconfig->desc.bMaxPower * 2); + + /* check the power usage so we don't try to enable something that is + * already enabled */ + if ((udev->actconfig->desc.bMaxPower * 2) == 500) { + dbg(&udev->dev, "device is already charging, power is " + "set to %dmA\n", udev->actconfig->desc.bMaxPower * 2); + return -ENODEV; + } + + /* turn the power on */ + magic_charge(udev); + + /* we don't really want to bind to the device, userspace programs can + * handle the syncing just fine, so get outta here. */ + return -ENODEV; +} + +static void berry_disconnect(struct usb_interface *intf) +{ +} + +static struct usb_driver berry_driver = { + .name = "berry_charge", + .probe = berry_probe, + .disconnect = berry_disconnect, + .id_table = id_table, +}; + +static int __init berry_init(void) +{ + return usb_register(&berry_driver); +} + +static void __exit berry_exit(void) +{ + usb_deregister(&berry_driver); +} + +module_init(berry_init); +module_exit(berry_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@suse.de>"); +module_param(debug, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/drivers/usb/net/Kconfig b/drivers/usb/net/Kconfig index a2b94ef512bc..0f3d7dbb537f 100644 --- a/drivers/usb/net/Kconfig +++ b/drivers/usb/net/Kconfig @@ -84,6 +84,7 @@ config USB_PEGASUS config USB_RTL8150 tristate "USB RTL8150 based ethernet device support (EXPERIMENTAL)" depends on EXPERIMENTAL + select MII help Say Y here if you have RTL8150 based usb-ethernet adapter. Send me <petkan@users.sourceforge.net> any comments you may have. @@ -98,7 +99,7 @@ config USB_USBNET_MII config USB_USBNET tristate "Multi-purpose USB Networking Framework" - select MII if USBNET_MII != n + select MII if USB_USBNET_MII != n ---help--- This driver supports several kinds of network links over USB, with "minidrivers" built around a common network driver core @@ -239,6 +240,7 @@ config USB_NET_RNDIS_HOST config USB_NET_CDC_SUBSET tristate "Simple USB Network Links (CDC Ethernet subset)" depends on USB_USBNET + default y help This driver module supports USB network devices that can work without any device-specific information. Select it if you have @@ -298,6 +300,13 @@ config USB_EPSON2888 Choose this option to support the usb networking links used by some sample firmware from Epson. +config USB_KC2190 + boolean "KT Technology KC2190 based cables (InstaNet)" + depends on USB_NET_CDC_SUBSET && EXPERIMENTAL + help + Choose this option if you're using a host-to-host cable + with one of these chips. + config USB_NET_ZAURUS tristate "Sharp Zaurus (stock ROMs) and compatible" depends on USB_USBNET diff --git a/drivers/usb/net/asix.c b/drivers/usb/net/asix.c index bd357e178e55..7ef2e4b5e39b 100644 --- a/drivers/usb/net/asix.c +++ b/drivers/usb/net/asix.c @@ -351,9 +351,11 @@ static struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb, skb_push(skb, 4); packet_len = (((skb->len - 4) ^ 0x0000ffff) << 16) + (skb->len - 4); + cpu_to_le32s(&packet_len); memcpy(skb->data, &packet_len, sizeof(packet_len)); if ((skb->len % 512) == 0) { + cpu_to_le32s(&padbytes); memcpy( skb->tail, &padbytes, sizeof(padbytes)); skb_put(skb, sizeof(padbytes)); } diff --git a/drivers/usb/net/cdc_subset.c b/drivers/usb/net/cdc_subset.c index ae8fb06cf38e..bc62b012602b 100644 --- a/drivers/usb/net/cdc_subset.c +++ b/drivers/usb/net/cdc_subset.c @@ -79,13 +79,19 @@ static int always_connected (struct usbnet *dev) * * ALi M5632 driver ... does high speed * + * NOTE that the MS-Windows drivers for this chip use some funky and + * (naturally) undocumented 7-byte prefix to each packet, so this is a + * case where we don't currently interoperate. Also, once you unplug + * one end of the cable, you need to replug the other end too ... since + * chip docs are unavailable, there's no way to reset the relevant state + * short of a power cycle. + * *-------------------------------------------------------------------------*/ static const struct driver_info ali_m5632_info = { .description = "ALi M5632", }; - #endif @@ -159,6 +165,11 @@ static const struct driver_info epson2888_info = { #endif /* CONFIG_USB_EPSON2888 */ +/*------------------------------------------------------------------------- + * + * info from Jonathan McDowell <noodles@earth.li> + * + *-------------------------------------------------------------------------*/ #ifdef CONFIG_USB_KC2190 #define HAVE_HARDWARE static const struct driver_info kc2190_info = { @@ -223,6 +234,10 @@ static const struct usb_device_id products [] = { USB_DEVICE (0x0402, 0x5632), // ALi defaults .driver_info = (unsigned long) &ali_m5632_info, }, +{ + USB_DEVICE (0x182d,0x207c), // SiteCom CN-124 + .driver_info = (unsigned long) &ali_m5632_info, +}, #endif #ifdef CONFIG_USB_AN2720 @@ -314,13 +329,13 @@ static struct usb_driver cdc_subset_driver = { static int __init cdc_subset_init(void) { - return usb_register(&cdc_subset_driver); + return usb_register(&cdc_subset_driver); } module_init(cdc_subset_init); static void __exit cdc_subset_exit(void) { - usb_deregister(&cdc_subset_driver); + usb_deregister(&cdc_subset_driver); } module_exit(cdc_subset_exit); diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c index 43ba61abfcc5..de69b183bd2f 100644 --- a/drivers/usb/net/usbnet.c +++ b/drivers/usb/net/usbnet.c @@ -147,7 +147,7 @@ int usbnet_get_endpoints(struct usbnet *dev, struct usb_interface *intf) if (tmp < 0) return tmp; } - + dev->in = usb_rcvbulkpipe (dev->udev, in->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); dev->out = usb_sndbulkpipe (dev->udev, @@ -327,7 +327,7 @@ static void rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags) if (netif_running (dev->net) && netif_device_present (dev->net) && !test_bit (EVENT_RX_HALT, &dev->flags)) { - switch (retval = usb_submit_urb (urb, GFP_ATOMIC)){ + switch (retval = usb_submit_urb (urb, GFP_ATOMIC)){ case -EPIPE: usbnet_defer_kevent (dev, EVENT_RX_HALT); break; @@ -443,7 +443,7 @@ block: case -EOVERFLOW: dev->stats.rx_over_errors++; // FALLTHROUGH - + default: entry->state = rx_cleanup; dev->stats.rx_errors++; @@ -560,7 +560,7 @@ static int usbnet_stop (struct net_device *net) if (netif_msg_ifdown (dev)) devinfo (dev, "stop stats: rx/tx %ld/%ld, errs %ld/%ld", - dev->stats.rx_packets, dev->stats.tx_packets, + dev->stats.rx_packets, dev->stats.tx_packets, dev->stats.rx_errors, dev->stats.tx_errors ); @@ -578,7 +578,7 @@ static int usbnet_stop (struct net_device *net) devdbg (dev, "waited for %d urb completions", temp); } dev->wait = NULL; - remove_wait_queue (&unlink_wakeup, &wait); + remove_wait_queue (&unlink_wakeup, &wait); usb_kill_urb(dev->interrupt); @@ -834,7 +834,7 @@ kevent (struct work_struct *work) } if (test_bit (EVENT_LINK_RESET, &dev->flags)) { - struct driver_info *info = dev->driver_info; + struct driver_info *info = dev->driver_info; int retval = 0; clear_bit (EVENT_LINK_RESET, &dev->flags); @@ -1066,7 +1066,7 @@ static void usbnet_bh (unsigned long param) * USB Device Driver support * *-------------------------------------------------------------------------*/ - + // precondition: never called in_interrupt void usbnet_disconnect (struct usb_interface *intf) @@ -1087,7 +1087,7 @@ void usbnet_disconnect (struct usb_interface *intf) intf->dev.driver->name, xdev->bus->bus_name, xdev->devpath, dev->driver_info->description); - + net = dev->net; unregister_netdev (net); @@ -1111,7 +1111,7 @@ int usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) { struct usbnet *dev; - struct net_device *net; + struct net_device *net; struct usb_host_interface *interface; struct driver_info *info; struct usb_device *xdev; @@ -1181,6 +1181,9 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) // NOTE net->name still not usable ... if (info->bind) { status = info->bind (dev, udev); + if (status < 0) + goto out1; + // heuristic: "usb%d" for links we know are two-host, // else "eth%d" when there's reasonable doubt. userspace // can rename the link if it knows better. @@ -1207,12 +1210,12 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) if (status == 0 && dev->status) status = init_status (dev, udev); if (status < 0) - goto out1; + goto out3; if (!dev->rx_urb_size) dev->rx_urb_size = dev->hard_mtu; dev->maxpacket = usb_maxpacket (dev->udev, dev->out, 1); - + SET_NETDEV_DEV(net, &udev->dev); status = register_netdev (net); if (status) @@ -1255,7 +1258,7 @@ EXPORT_SYMBOL_GPL(usbnet_probe); int usbnet_suspend (struct usb_interface *intf, pm_message_t message) { struct usbnet *dev = usb_get_intfdata(intf); - + /* accelerate emptying of the rx and queues, to avoid * having everything error out. */ @@ -1286,7 +1289,7 @@ static int __init usbnet_init(void) < sizeof (struct skb_data)); random_ether_addr(node_id); - return 0; + return 0; } module_init(usbnet_init); diff --git a/drivers/usb/serial/airprime.c b/drivers/usb/serial/airprime.c index 0af42e32fa0a..18816bf96a4d 100644 --- a/drivers/usb/serial/airprime.c +++ b/drivers/usb/serial/airprime.c @@ -58,11 +58,6 @@ static void airprime_read_bulk_callback(struct urb *urb) if (urb->status) { dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status); - /* something happened, so free up the memory for this urb */ - if (urb->transfer_buffer) { - kfree (urb->transfer_buffer); - urb->transfer_buffer = NULL; - } return; } usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data); @@ -146,6 +141,8 @@ static int airprime_open(struct usb_serial_port *port, struct file *filp) airprime_read_bulk_callback, port); result = usb_submit_urb(urb, GFP_KERNEL); if (result) { + usb_free_urb(urb); + kfree(buffer); dev_err(&port->dev, "%s - failed submitting read urb %d for port %d, error %d\n", __FUNCTION__, i, port->number, result); @@ -160,27 +157,12 @@ static int airprime_open(struct usb_serial_port *port, struct file *filp) /* some error happened, cancel any submitted urbs and clean up anything that got allocated successfully */ - for ( ; i >= 0; --i) { + while (i-- != 0) { urb = priv->read_urbp[i]; - if (urb) { - /* This urb was submitted successfully. So we have to - cancel it. - Unlinking the urb will invoke read_bulk_callback() - with an error status, so its transfer buffer will - be freed there */ - if (usb_unlink_urb (urb) != -EINPROGRESS) { - /* comments in drivers/usb/core/urb.c say this - can only happen if the urb was never submitted, - or has completed already. - Either way we may have to free the transfer - buffer here. */ - if (urb->transfer_buffer) { - kfree (urb->transfer_buffer); - urb->transfer_buffer = NULL; - } - } - usb_free_urb (urb); - } + buffer = urb->transfer_buffer; + usb_kill_urb (urb); + usb_free_urb (urb); + kfree (buffer); } out: @@ -194,10 +176,9 @@ static void airprime_close(struct usb_serial_port *port, struct file * filp) dbg("%s - port %d", __FUNCTION__, port->number); - /* killing the urb will invoke read_bulk_callback() with an error status, - so the transfer buffer will be freed there */ for (i = 0; i < NUM_READ_URBS; ++i) { usb_kill_urb (priv->read_urbp[i]); + kfree (priv->read_urbp[i]->transfer_buffer); usb_free_urb (priv->read_urbp[i]); } diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c index 3ec24870bca9..db623e754899 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(0x10C5, 0xEA61) }, /* Silicon Labs MobiData GPRS USB Modem */ { USB_DEVICE(0x13AD, 0x9999) }, /* Baltech card reader */ { USB_DEVICE(0x16D6, 0x0001) }, /* Jablotron serial interface */ { } /* Terminating Entry */ diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index 601e0648dec6..53baeec8f265 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c @@ -66,6 +66,8 @@ struct usb_serial_driver usb_serial_generic_device = { .num_bulk_out = NUM_DONT_CARE, .num_ports = 1, .shutdown = usb_serial_generic_shutdown, + .throttle = usb_serial_generic_throttle, + .unthrottle = usb_serial_generic_unthrottle, }; static int generic_probe(struct usb_interface *interface, @@ -115,6 +117,7 @@ int usb_serial_generic_open (struct usb_serial_port *port, struct file *filp) { struct usb_serial *serial = port->serial; int result = 0; + unsigned long flags; dbg("%s - port %d", __FUNCTION__, port->number); @@ -124,7 +127,13 @@ int usb_serial_generic_open (struct usb_serial_port *port, struct file *filp) if (port->tty) port->tty->low_latency = 1; - /* if we have a bulk interrupt, start reading from it */ + /* clear the throttle flags */ + spin_lock_irqsave(&port->lock, flags); + port->throttled = 0; + port->throttle_req = 0; + spin_unlock_irqrestore(&port->lock, flags); + + /* if we have a bulk endpoint, start reading from it */ if (serial->num_bulk_in) { /* Start reading from the device */ usb_fill_bulk_urb (port->read_urb, serial->dev, @@ -253,31 +262,22 @@ int usb_serial_generic_chars_in_buffer (struct usb_serial_port *port) return (chars); } -void usb_serial_generic_read_bulk_callback (struct urb *urb) +/* Push data to tty layer and resubmit the bulk read URB */ +static void flush_and_resubmit_read_urb (struct usb_serial_port *port) { - struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct usb_serial *serial = port->serial; - struct tty_struct *tty; - unsigned char *data = urb->transfer_buffer; + struct urb *urb = port->read_urb; + struct tty_struct *tty = port->tty; int result; - dbg("%s - port %d", __FUNCTION__, port->number); - - if (urb->status) { - dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status); - return; - } - - usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data); - - tty = port->tty; + /* Push data to tty */ if (tty && urb->actual_length) { tty_buffer_request_room(tty, urb->actual_length); - tty_insert_flip_string(tty, data, urb->actual_length); - tty_flip_buffer_push(tty); + tty_insert_flip_string(tty, urb->transfer_buffer, urb->actual_length); + tty_flip_buffer_push(tty); /* is this allowed from an URB callback ? */ } - /* Continue trying to always read */ + /* Continue reading from device */ usb_fill_bulk_urb (port->read_urb, serial->dev, usb_rcvbulkpipe (serial->dev, port->bulk_in_endpointAddress), @@ -290,6 +290,40 @@ void usb_serial_generic_read_bulk_callback (struct urb *urb) if (result) dev_err(&port->dev, "%s - failed resubmitting read urb, error %d\n", __FUNCTION__, result); } + +void usb_serial_generic_read_bulk_callback (struct urb *urb) +{ + struct usb_serial_port *port = (struct usb_serial_port *)urb->context; + unsigned char *data = urb->transfer_buffer; + int is_throttled; + unsigned long flags; + + dbg("%s - port %d", __FUNCTION__, port->number); + + if (urb->status) { + dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status); + return; + } + + usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data); + + /* Throttle the device if requested by tty */ + if (urb->actual_length) { + spin_lock_irqsave(&port->lock, flags); + is_throttled = port->throttled = port->throttle_req; + spin_unlock_irqrestore(&port->lock, flags); + if (is_throttled) { + /* Let the received data linger in the read URB; + * usb_serial_generic_unthrottle() will pick it + * up later. */ + dbg("%s - throttling device", __FUNCTION__); + return; + } + } + + /* Handle data and continue reading from device */ + flush_and_resubmit_read_urb(port); +} EXPORT_SYMBOL_GPL(usb_serial_generic_read_bulk_callback); void usb_serial_generic_write_bulk_callback (struct urb *urb) @@ -308,6 +342,38 @@ void usb_serial_generic_write_bulk_callback (struct urb *urb) } EXPORT_SYMBOL_GPL(usb_serial_generic_write_bulk_callback); +void usb_serial_generic_throttle (struct usb_serial_port *port) +{ + unsigned long flags; + + dbg("%s - port %d", __FUNCTION__, port->number); + + /* Set the throttle request flag. It will be picked up + * by usb_serial_generic_read_bulk_callback(). */ + spin_lock_irqsave(&port->lock, flags); + port->throttle_req = 1; + spin_unlock_irqrestore(&port->lock, flags); +} + +void usb_serial_generic_unthrottle (struct usb_serial_port *port) +{ + int was_throttled; + unsigned long flags; + + dbg("%s - port %d", __FUNCTION__, port->number); + + /* Clear the throttle flags */ + spin_lock_irqsave(&port->lock, flags); + was_throttled = port->throttled; + port->throttled = port->throttle_req = 0; + spin_unlock_irqrestore(&port->lock, flags); + + if (was_throttled) { + /* Handle pending data and resume reading from device */ + flush_and_resubmit_read_urb(port); + } +} + void usb_serial_generic_shutdown (struct usb_serial *serial) { int i; diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index ced9f32b29d9..9963a8b75840 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -69,7 +69,6 @@ static int option_send_setup(struct usb_serial_port *port); /* Vendor and product IDs */ #define OPTION_VENDOR_ID 0x0AF0 #define HUAWEI_VENDOR_ID 0x12D1 -#define AUDIOVOX_VENDOR_ID 0x0F3D #define NOVATELWIRELESS_VENDOR_ID 0x1410 #define ANYDATA_VENDOR_ID 0x16d5 @@ -81,7 +80,6 @@ static int option_send_setup(struct usb_serial_port *port); #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 @@ -94,7 +92,6 @@ static struct usb_device_id option_ids[] = { { 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) }, { } /* Terminating entry */ @@ -109,7 +106,6 @@ static struct usb_device_id option_ids1[] = { { 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) }, { } /* Terminating entry */ diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 6c083d4e2c9b..83dfae93a45d 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -83,6 +83,7 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(BELKIN_VENDOR_ID, BELKIN_PRODUCT_ID) }, { USB_DEVICE(ALCOR_VENDOR_ID, ALCOR_PRODUCT_ID) }, { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_ID) }, + { USB_DEVICE(WS002IN_VENDOR_ID, WS002IN_PRODUCT_ID) }, { } /* Terminating entry */ }; diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h index 65a5039665e7..f9a71d0c102e 100644 --- a/drivers/usb/serial/pl2303.h +++ b/drivers/usb/serial/pl2303.h @@ -97,3 +97,8 @@ /* Huawei E620 UMTS/HSDPA card (ID: 12d1:1001) */ #define HUAWEI_VENDOR_ID 0x12d1 #define HUAWEI_PRODUCT_ID 0x1001 + +/* Willcom WS002IN Data Driver (by NetIndex Inc.) */ +#define WS002IN_VENDOR_ID 0x11f6 +#define WS002IN_PRODUCT_ID 0x2001 + diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c index 70234f5dbeeb..e227f64d5641 100644 --- a/drivers/usb/storage/scsiglue.c +++ b/drivers/usb/storage/scsiglue.c @@ -153,6 +153,12 @@ static int slave_configure(struct scsi_device *sdev) if (us->flags & US_FL_FIX_CAPACITY) sdev->fix_capacity = 1; + /* A few disks have two indistinguishable version, one of + * which reports the correct capacity and the other does not. + * The sd driver has to guess which is the case. */ + if (us->flags & US_FL_CAPACITY_HEURISTICS) + sdev->guess_capacity = 1; + /* Some devices report a SCSI revision level above 2 but are * unable to handle the REPORT LUNS command (for which * support is mandatory at level 3). Since we already have diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index f49a62fc32d2..9644a8ea4aa7 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -1101,6 +1101,15 @@ UNUSUAL_DEV( 0x08bd, 0x1100, 0x0000, 0x0000, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_SINGLE_LUN), +/* Submitted by Dylan Taft <d13f00l@gmail.com> + * US_FL_IGNORE_RESIDUE Needed + */ +UNUSUAL_DEV( 0x08ca, 0x3103, 0x0100, 0x0100, + "AIPTEK", + "Aiptek USB Keychain MP3 Player", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_IGNORE_RESIDUE), + /* Entry needed for flags. Moreover, all devices with this ID use * bulk-only transport, but _some_ falsely report Control/Bulk instead. * One example is "Trumpion Digital Research MYMP3". @@ -1311,12 +1320,13 @@ UNUSUAL_DEV( 0x0fce, 0xd008, 0x0000, 0x0000, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_NO_WP_DETECT ), -/* Reported by Jan Mate <mate@fiit.stuba.sk> */ +/* Reported by Jan Mate <mate@fiit.stuba.sk> + * and by Soeren Sonnenburg <kernel@nn7.de> */ UNUSUAL_DEV( 0x0fce, 0xe030, 0x0000, 0x0000, "Sony Ericsson", "P990i", US_SC_DEVICE, US_PR_DEVICE, NULL, - US_FL_FIX_CAPACITY ), + US_FL_FIX_CAPACITY | US_FL_IGNORE_RESIDUE ), /* Reported by Emmanuel Vasilakis <evas@forthnet.gr> */ UNUSUAL_DEV( 0x0fce, 0xe031, 0x0000, 0x0000, @@ -1385,6 +1395,16 @@ UNUSUAL_DEV( 0x1652, 0x6600, 0x0201, 0x0201, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE ), +/* Reported by Thomas Baechler <thomas@archlinux.org> + * Fixes I/O errors with Teac HD-35PU devices + */ + +UNUSUAL_DEV( 0x1652, 0x6600, 0x0201, 0x0201, + "Super Top", + "USB 2.0 IDE DEVICE", + 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> */ @@ -1423,7 +1443,7 @@ UNUSUAL_DEV( 0xed06, 0x4500, 0x0001, 0x0001, "DataStor", "USB4500 FW1.04", US_SC_DEVICE, US_PR_DEVICE, NULL, - US_FL_FIX_CAPACITY), + US_FL_CAPACITY_HEURISTICS), /* Control/Bulk transport for all SubClass values */ USUAL_DEV(US_SC_RBC, US_PR_CB, USB_US_TYPE_STOR), diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c index 296b091cf168..46929a1b6f24 100644 --- a/drivers/usb/usb-skeleton.c +++ b/drivers/usb/usb-skeleton.c @@ -90,13 +90,15 @@ static int skel_open(struct inode *inode, struct file *file) goto exit; } + /* increment our usage count for the device */ + kref_get(&dev->kref); + /* prevent the device from being autosuspended */ retval = usb_autopm_get_interface(interface); - if (retval) + if (retval) { + kref_put(&dev->kref, skel_delete); goto exit; - - /* increment our usage count for the device */ - kref_get(&dev->kref); + } /* save our object in the file's private structure */ file->private_data = dev; |