diff options
author | Trond Myklebust | 2008-03-19 22:59:44 +0100 |
---|---|---|
committer | Trond Myklebust | 2008-03-19 22:59:44 +0100 |
commit | c7c350e92aab1bba68f26a6027b734adcf9824ba (patch) | |
tree | aa99bd94c3049dd871d9c030d70a5f3d87591a95 /drivers | |
parent | NFS: fix encode_fsinfo_maxsz (diff) | |
parent | nfs: don't ignore return value from nfs_pageio_add_request (diff) | |
download | kernel-qcow2-linux-c7c350e92aab1bba68f26a6027b734adcf9824ba.tar.gz kernel-qcow2-linux-c7c350e92aab1bba68f26a6027b734adcf9824ba.tar.xz kernel-qcow2-linux-c7c350e92aab1bba68f26a6027b734adcf9824ba.zip |
Merge branch 'hotfixes' into devel
Diffstat (limited to 'drivers')
181 files changed, 3971 insertions, 2531 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index f688c214be0c..b4f5e8542829 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -283,34 +283,22 @@ config ACPI_TOSHIBA If you have a legacy free Toshiba laptop (such as the Libretto L1 series), say Y. -config ACPI_CUSTOM_DSDT - bool "Include Custom DSDT" +config ACPI_CUSTOM_DSDT_FILE + string "Custom DSDT Table file to include" + default "" depends on !STANDALONE - default n help This option supports a custom DSDT by linking it into the kernel. See Documentation/acpi/dsdt-override.txt - If unsure, say N. - -config ACPI_CUSTOM_DSDT_FILE - string "Custom DSDT Table file to include" - depends on ACPI_CUSTOM_DSDT - default "" - help Enter the full path name to the file which includes the AmlCode declaration. -config ACPI_CUSTOM_DSDT_INITRD - bool "Read Custom DSDT from initramfs" - depends on BLK_DEV_INITRD - default n - help - This option supports a custom DSDT by optionally loading it from initrd. - See Documentation/acpi/dsdt-override.txt + If unsure, don't enter a file name. - If you are not using this feature now, but may use it later, - it is safe to say Y here. +config ACPI_CUSTOM_DSDT + bool + default ACPI_CUSTOM_DSDT_FILE != "" config ACPI_BLACKLIST_YEAR int "Disable ACPI for systems before Jan 1st this year" if X86_32 diff --git a/drivers/acpi/asus_acpi.c b/drivers/acpi/asus_acpi.c index d25ef961415c..44ad90c03c2e 100644 --- a/drivers/acpi/asus_acpi.c +++ b/drivers/acpi/asus_acpi.c @@ -610,7 +610,7 @@ write_led(const char __user * buffer, unsigned long count, (led_out) ? (hotk->status | ledmask) : (hotk->status & ~ledmask); if (invert) /* invert target value */ - led_out = !led_out & 0x1; + led_out = !led_out; if (!write_acpi_int(hotk->handle, ledname, led_out, NULL)) printk(KERN_WARNING "Asus ACPI: LED (%s) write failed\n", diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index f6215e809808..d5729d5dc190 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -293,13 +293,12 @@ static int extract_package(struct acpi_battery *battery, strncpy(ptr, (u8 *)&element->integer.value, sizeof(acpi_integer)); ptr[sizeof(acpi_integer)] = 0; - } else return -EFAULT; + } else + *ptr = 0; /* don't have value */ } else { - if (element->type == ACPI_TYPE_INTEGER) { - int *x = (int *)((u8 *)battery + - offsets[i].offset); - *x = element->integer.value; - } else return -EFAULT; + int *x = (int *)((u8 *)battery + offsets[i].offset); + *x = (element->type == ACPI_TYPE_INTEGER) ? + element->integer.value : -1; } } return 0; diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index ce3c0a2cbac4..5b6760e0f957 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -776,7 +776,7 @@ static int __init acpi_init(void) acpi_kobj = kobject_create_and_add("acpi", firmware_kobj); if (!acpi_kobj) { - printk(KERN_WARNING "%s: kset create error\n", __FUNCTION__); + printk(KERN_WARNING "%s: kset create error\n", __func__); acpi_kobj = NULL; } diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index 24a7865a57cb..6c5da83cdb68 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -449,6 +449,7 @@ static int acpi_button_add(struct acpi_device *device) input->phys = button->phys; input->id.bustype = BUS_HOST; input->id.product = button->type; + input->dev.parent = &device->dev; switch (button->type) { case ACPI_BUTTON_TYPE_POWER: diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 307cef65c247..fa44fb96fc34 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -710,6 +710,7 @@ static ssize_t write_undock(struct device *dev, struct device_attribute *attr, if (!count) return -EINVAL; + begin_undock(dock_station); ret = handle_eject_request(dock_station, ACPI_NOTIFY_EJECT_REQUEST); return ret ? ret: count; } diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index caf873c14bfb..7222a18a0319 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -943,11 +943,7 @@ int __init acpi_ec_ecdt_probe(void) boot_ec->command_addr = ecdt_ptr->control.address; boot_ec->data_addr = ecdt_ptr->data.address; boot_ec->gpe = ecdt_ptr->gpe; - if (ACPI_FAILURE(acpi_get_handle(NULL, ecdt_ptr->id, - &boot_ec->handle))) { - pr_info("Failed to locate handle for boot EC\n"); - boot_ec->handle = ACPI_ROOT_OBJECT; - } + boot_ec->handle = ACPI_ROOT_OBJECT; } else { /* This workaround is needed only on some broken machines, * which require early EC, but fail to provide ECDT */ diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 8edba7b678eb..a697fb6cf050 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -91,10 +91,6 @@ static DEFINE_SPINLOCK(acpi_res_lock); #define OSI_STRING_LENGTH_MAX 64 /* arbitrary */ static char osi_additional_string[OSI_STRING_LENGTH_MAX]; -#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD -static int acpi_no_initrd_override; -#endif - /* * "Ode to _OSI(Linux)" * @@ -324,67 +320,6 @@ acpi_os_predefined_override(const struct acpi_predefined_names *init_val, return AE_OK; } -#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD -static struct acpi_table_header *acpi_find_dsdt_initrd(void) -{ - struct file *firmware_file; - mm_segment_t oldfs; - unsigned long len, len2; - struct acpi_table_header *dsdt_buffer, *ret = NULL; - struct kstat stat; - char *ramfs_dsdt_name = "/DSDT.aml"; - - printk(KERN_INFO PREFIX "Checking initramfs for custom DSDT\n"); - - /* - * Never do this at home, only the user-space is allowed to open a file. - * The clean way would be to use the firmware loader. - * But this code must be run before there is any userspace available. - * A static/init firmware infrastructure doesn't exist yet... - */ - if (vfs_stat(ramfs_dsdt_name, &stat) < 0) - return ret; - - len = stat.size; - /* check especially against empty files */ - if (len <= 4) { - printk(KERN_ERR PREFIX "Failed: DSDT only %lu bytes.\n", len); - return ret; - } - - firmware_file = filp_open(ramfs_dsdt_name, O_RDONLY, 0); - if (IS_ERR(firmware_file)) { - printk(KERN_ERR PREFIX "Failed to open %s.\n", ramfs_dsdt_name); - return ret; - } - - dsdt_buffer = kmalloc(len, GFP_ATOMIC); - if (!dsdt_buffer) { - printk(KERN_ERR PREFIX "Failed to allocate %lu bytes.\n", len); - goto err; - } - - oldfs = get_fs(); - set_fs(KERNEL_DS); - len2 = vfs_read(firmware_file, (char __user *)dsdt_buffer, len, - &firmware_file->f_pos); - set_fs(oldfs); - if (len2 < len) { - printk(KERN_ERR PREFIX "Failed to read %lu bytes from %s.\n", - len, ramfs_dsdt_name); - ACPI_FREE(dsdt_buffer); - goto err; - } - - printk(KERN_INFO PREFIX "Found %lu byte DSDT in %s.\n", - len, ramfs_dsdt_name); - ret = dsdt_buffer; -err: - filp_close(firmware_file, NULL); - return ret; -} -#endif - acpi_status acpi_os_table_override(struct acpi_table_header * existing_table, struct acpi_table_header ** new_table) @@ -398,16 +333,6 @@ acpi_os_table_override(struct acpi_table_header * existing_table, if (strncmp(existing_table->signature, "DSDT", 4) == 0) *new_table = (struct acpi_table_header *)AmlCode; #endif -#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD - if ((strncmp(existing_table->signature, "DSDT", 4) == 0) && - !acpi_no_initrd_override) { - struct acpi_table_header *initrd_table; - - initrd_table = acpi_find_dsdt_initrd(); - if (initrd_table) - *new_table = initrd_table; - } -#endif if (*new_table != NULL) { printk(KERN_WARNING PREFIX "Override [%4.4s-%8.8s], " "this is unsafe: tainting kernel\n", @@ -418,15 +343,6 @@ acpi_os_table_override(struct acpi_table_header * existing_table, return AE_OK; } -#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD -static int __init acpi_no_initrd_override_setup(char *s) -{ - acpi_no_initrd_override = 1; - return 1; -} -__setup("acpi_no_initrd_override", acpi_no_initrd_override_setup); -#endif - static irqreturn_t acpi_irq(int irq, void *dev_id) { u32 handled; @@ -1237,7 +1153,7 @@ int acpi_check_resource_conflict(struct resource *res) if (clash) { if (acpi_enforce_resources != ENFORCE_RESOURCES_NO) { - printk(KERN_INFO "%sACPI: %s resource %s [0x%llx-0x%llx]" + printk("%sACPI: %s resource %s [0x%llx-0x%llx]" " conflicts with ACPI region %s" " [0x%llx-0x%llx]\n", acpi_enforce_resources == ENFORCE_RESOURCES_LAX diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c index 7f19859580c7..7af414a3c63e 100644 --- a/drivers/acpi/pci_irq.c +++ b/drivers/acpi/pci_irq.c @@ -25,6 +25,7 @@ */ +#include <linux/dmi.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> @@ -76,6 +77,101 @@ static struct acpi_prt_entry *acpi_pci_irq_find_prt_entry(int segment, return NULL; } +/* http://bugzilla.kernel.org/show_bug.cgi?id=4773 */ +static struct dmi_system_id medion_md9580[] = { + { + .ident = "Medion MD9580-F laptop", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "MEDIONNB"), + DMI_MATCH(DMI_PRODUCT_NAME, "A555"), + }, + }, + { } +}; + +/* http://bugzilla.kernel.org/show_bug.cgi?id=5044 */ +static struct dmi_system_id dell_optiplex[] = { + { + .ident = "Dell Optiplex GX1", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex GX1 600S+"), + }, + }, + { } +}; + +/* http://bugzilla.kernel.org/show_bug.cgi?id=10138 */ +static struct dmi_system_id hp_t5710[] = { + { + .ident = "HP t5710", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "hp t5000 series"), + DMI_MATCH(DMI_BOARD_NAME, "098Ch"), + }, + }, + { } +}; + +struct prt_quirk { + struct dmi_system_id *system; + unsigned int segment; + unsigned int bus; + unsigned int device; + unsigned char pin; + char *source; /* according to BIOS */ + char *actual_source; +}; + +/* + * These systems have incorrect _PRT entries. The BIOS claims the PCI + * interrupt at the listed segment/bus/device/pin is connected to the first + * link device, but it is actually connected to the second. + */ +static struct prt_quirk prt_quirks[] = { + { medion_md9580, 0, 0, 9, 'A', + "\\_SB_.PCI0.ISA.LNKA", + "\\_SB_.PCI0.ISA.LNKB"}, + { dell_optiplex, 0, 0, 0xd, 'A', + "\\_SB_.LNKB", + "\\_SB_.LNKA"}, + { hp_t5710, 0, 0, 1, 'A', + "\\_SB_.PCI0.LNK1", + "\\_SB_.PCI0.LNK3"}, +}; + +static void +do_prt_fixups(struct acpi_prt_entry *entry, struct acpi_pci_routing_table *prt) +{ + int i; + struct prt_quirk *quirk; + + for (i = 0; i < ARRAY_SIZE(prt_quirks); i++) { + quirk = &prt_quirks[i]; + + /* All current quirks involve link devices, not GSIs */ + if (!prt->source) + continue; + + if (dmi_check_system(quirk->system) && + entry->id.segment == quirk->segment && + entry->id.bus == quirk->bus && + entry->id.device == quirk->device && + entry->pin + 'A' == quirk->pin && + !strcmp(prt->source, quirk->source) && + strlen(prt->source) >= strlen(quirk->actual_source)) { + printk(KERN_WARNING PREFIX "firmware reports " + "%04x:%02x:%02x[%c] connected to %s; " + "changing to %s\n", + entry->id.segment, entry->id.bus, + entry->id.device, 'A' + entry->pin, + prt->source, quirk->actual_source); + strcpy(prt->source, quirk->actual_source); + } + } +} + static int acpi_pci_irq_add_entry(acpi_handle handle, int segment, int bus, struct acpi_pci_routing_table *prt) @@ -96,6 +192,8 @@ acpi_pci_irq_add_entry(acpi_handle handle, entry->id.function = prt->address & 0xFFFF; entry->pin = prt->pin; + do_prt_fixups(entry, prt); + /* * Type 1: Dynamic * --------------- diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index f14ff1ffab29..c3fed31166b5 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -184,7 +184,7 @@ static void acpi_pci_bridge_scan(struct acpi_device *device) } } -static int acpi_pci_root_add(struct acpi_device *device) +static int __devinit acpi_pci_root_add(struct acpi_device *device) { int result = 0; struct acpi_pci_root *root = NULL; diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index a3cc8a98255c..36a68fa114e3 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -840,17 +840,19 @@ static int is_processor_present(acpi_handle handle) status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); - /* - * if a processor object does not have an _STA object, - * OSPM assumes that the processor is present. - */ - if (status == AE_NOT_FOUND) - return 1; if (ACPI_SUCCESS(status) && (sta & ACPI_STA_DEVICE_PRESENT)) return 1; - ACPI_EXCEPTION((AE_INFO, status, "Processor Device is not present")); + /* + * _STA is mandatory for a processor that supports hot plug + */ + if (status == AE_NOT_FOUND) + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Processor does not support hot plug\n")); + else + ACPI_EXCEPTION((AE_INFO, status, + "Processor Device is not present")); return 0; } @@ -886,8 +888,8 @@ int acpi_processor_device_add(acpi_handle handle, struct acpi_device **device) return 0; } -static void -acpi_processor_hotplug_notify(acpi_handle handle, u32 event, void *data) +static void __ref acpi_processor_hotplug_notify(acpi_handle handle, + u32 event, void *data) { struct acpi_processor *pr; struct acpi_device *device = NULL; @@ -897,9 +899,10 @@ acpi_processor_hotplug_notify(acpi_handle handle, u32 event, void *data) switch (event) { case ACPI_NOTIFY_BUS_CHECK: case ACPI_NOTIFY_DEVICE_CHECK: - printk("Processor driver received %s event\n", + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Processor driver received %s event\n", (event == ACPI_NOTIFY_BUS_CHECK) ? - "ACPI_NOTIFY_BUS_CHECK" : "ACPI_NOTIFY_DEVICE_CHECK"); + "ACPI_NOTIFY_BUS_CHECK" : "ACPI_NOTIFY_DEVICE_CHECK")); if (!is_processor_present(handle)) break; diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 6f3b217699e9..e8e2d8869236 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -216,8 +216,10 @@ static void acpi_safe_halt(void) * test NEED_RESCHED: */ smp_mb(); - if (!need_resched()) + if (!need_resched()) { safe_halt(); + local_irq_disable(); + } current_thread_info()->status |= TS_POLLING; } @@ -421,7 +423,9 @@ static void acpi_processor_idle(void) else acpi_safe_halt(); - local_irq_enable(); + if (irqs_disabled()) + local_irq_enable(); + return; } @@ -530,7 +534,9 @@ static void acpi_processor_idle(void) * skew otherwise. */ sleep_ticks = 0xFFFFFFFF; - local_irq_enable(); + if (irqs_disabled()) + local_irq_enable(); + break; case ACPI_STATE_C2: diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 3fac011f9cf9..57570ac47803 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -609,7 +609,8 @@ acpi_bus_get_ejd(acpi_handle handle, acpi_handle *ejd) status = acpi_evaluate_object(handle, "_EJD", NULL, &buffer); if (ACPI_SUCCESS(status)) { obj = buffer.pointer; - status = acpi_get_handle(NULL, obj->string.pointer, ejd); + status = acpi_get_handle(ACPI_ROOT_OBJECT, obj->string.pointer, + ejd); kfree(buffer.pointer); } return status; @@ -966,7 +967,7 @@ static void acpi_device_set_id(struct acpi_device *device, case ACPI_BUS_TYPE_DEVICE: status = acpi_get_object_info(handle, &buffer); if (ACPI_FAILURE(status)) { - printk(KERN_ERR PREFIX "%s: Error reading device info\n", __FUNCTION__); + printk(KERN_ERR PREFIX "%s: Error reading device info\n", __func__); return; } diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c index 293a1cbb47c0..d2f71a54726c 100644 --- a/drivers/acpi/sleep/main.c +++ b/drivers/acpi/sleep/main.c @@ -504,7 +504,7 @@ static void acpi_power_off_prepare(void) static void acpi_power_off(void) { /* acpi_sleep_prepare(ACPI_STATE_S5) should have already been called */ - printk("%s called\n", __FUNCTION__); + printk("%s called\n", __func__); local_irq_disable(); acpi_enable_wakeup_device(ACPI_STATE_S5); acpi_enter_sleep_state(ACPI_STATE_S5); diff --git a/drivers/acpi/system.c b/drivers/acpi/system.c index 55cf4c05bb74..4749f379a915 100644 --- a/drivers/acpi/system.c +++ b/drivers/acpi/system.c @@ -319,7 +319,7 @@ void acpi_irq_stats_init(void) goto fail; for (i = 0; i < num_counters; ++i) { - char buffer[10]; + char buffer[12]; char *name; if (i < num_gpes) diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 8d4b79b4f933..c4e00ac8ea85 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -879,6 +879,8 @@ static void acpi_thermal_check(void *data) } /* sys I/F for generic thermal sysfs support */ +#define KELVIN_TO_MILLICELSIUS(t) (t * 100 - 273200) + static int thermal_get_temp(struct thermal_zone_device *thermal, char *buf) { struct acpi_thermal *tz = thermal->devdata; @@ -886,7 +888,7 @@ static int thermal_get_temp(struct thermal_zone_device *thermal, char *buf) if (!tz) return -EINVAL; - return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS(tz->temperature)); + return sprintf(buf, "%ld\n", KELVIN_TO_MILLICELSIUS(tz->temperature)); } static const char enabled[] = "kernel"; @@ -980,21 +982,21 @@ static int thermal_get_trip_temp(struct thermal_zone_device *thermal, if (tz->trips.critical.flags.valid) { if (!trip) - return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS( + return sprintf(buf, "%ld\n", KELVIN_TO_MILLICELSIUS( tz->trips.critical.temperature)); trip--; } if (tz->trips.hot.flags.valid) { if (!trip) - return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS( + return sprintf(buf, "%ld\n", KELVIN_TO_MILLICELSIUS( tz->trips.hot.temperature)); trip--; } if (tz->trips.passive.flags.valid) { if (!trip) - return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS( + return sprintf(buf, "%ld\n", KELVIN_TO_MILLICELSIUS( tz->trips.passive.temperature)); trip--; } @@ -1002,7 +1004,7 @@ static int thermal_get_trip_temp(struct thermal_zone_device *thermal, for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE && tz->trips.active[i].flags.valid; i++) { if (!trip) - return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS( + return sprintf(buf, "%ld\n", KELVIN_TO_MILLICELSIUS( tz->trips.active[i].temperature)); trip--; } diff --git a/drivers/acpi/toshiba_acpi.c b/drivers/acpi/toshiba_acpi.c index 9e8c20c6a0b7..0a43c8e0eff3 100644 --- a/drivers/acpi/toshiba_acpi.c +++ b/drivers/acpi/toshiba_acpi.c @@ -99,6 +99,13 @@ MODULE_LICENSE("GPL"); #define HCI_VIDEO_OUT_CRT 0x2 #define HCI_VIDEO_OUT_TV 0x4 +static const struct acpi_device_id toshiba_device_ids[] = { + {"TOS6200", 0}, + {"TOS1900", 0}, + {"", 0}, +}; +MODULE_DEVICE_TABLE(acpi, toshiba_device_ids); + /* utility */ diff --git a/drivers/acpi/utilities/utdebug.c b/drivers/acpi/utilities/utdebug.c index c7e128e5369b..7361204b1eef 100644 --- a/drivers/acpi/utilities/utdebug.c +++ b/drivers/acpi/utilities/utdebug.c @@ -109,7 +109,7 @@ void acpi_ut_track_stack_ptr(void) * RETURN: Updated pointer to the function name * * DESCRIPTION: Remove the "Acpi" prefix from the function name, if present. - * This allows compiler macros such as __FUNCTION__ to be used + * This allows compiler macros such as __func__ to be used * with no change to the debug output. * ******************************************************************************/ diff --git a/drivers/acpi/utilities/utobject.c b/drivers/acpi/utilities/utobject.c index 76ee766c84f9..e08b3fa6639f 100644 --- a/drivers/acpi/utilities/utobject.c +++ b/drivers/acpi/utilities/utobject.c @@ -432,7 +432,7 @@ acpi_ut_get_simple_object_size(union acpi_operand_object *internal_object, * element -- which is legal) */ if (!internal_object) { - *obj_length = 0; + *obj_length = sizeof(union acpi_object); return_ACPI_STATUS(AE_OK); } diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index eba55b7d6c95..44ea60cf21c0 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -407,6 +407,12 @@ acpi_evaluate_reference(acpi_handle handle, break; } + if (!element->reference.handle) { + printk(KERN_WARNING PREFIX "Invalid reference in" + " package %s\n", pathname); + status = AE_NULL_ENTRY; + break; + } /* Get the acpi_handle. */ list->handles[i] = element->reference.handle; diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 12cce69b5441..12fb44f16766 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -713,7 +713,7 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) kfree(obj); - if (device->cap._BCL && device->cap._BCM && device->cap._BQC && max_level > 0){ + if (device->cap._BCL && device->cap._BCM && max_level > 0) { int result; static int count = 0; char *name; @@ -807,40 +807,11 @@ static void acpi_video_bus_find_cap(struct acpi_video_bus *video) static int acpi_video_bus_check(struct acpi_video_bus *video) { acpi_status status = -ENOENT; - long device_id; - struct device *dev; - struct acpi_device *device; + if (!video) return -EINVAL; - device = video->device; - - status = - acpi_evaluate_integer(device->handle, "_ADR", NULL, &device_id); - - if (!ACPI_SUCCESS(status)) - return -ENODEV; - - /* We need to attempt to determine whether the _ADR refers to a - PCI device or not. There's no terribly good way to do this, - so the best we can hope for is to assume that there'll never - be a video device in the host bridge */ - if (device_id >= 0x10000) { - /* It looks like a PCI device. Does it exist? */ - dev = acpi_get_physical_device(device->handle); - } else { - /* It doesn't look like a PCI device. Does its parent - exist? */ - acpi_handle phandle; - if (acpi_get_parent(device->handle, &phandle)) - return -ENODEV; - dev = acpi_get_physical_device(phandle); - } - if (!dev) - return -ENODEV; - put_device(dev); - /* Since there is no HID, CID and so on for VGA driver, we have * to check well known required nodes. */ @@ -1201,7 +1172,7 @@ static int acpi_video_bus_ROM_seq_show(struct seq_file *seq, void *offset) if (!video) goto end; - printk(KERN_INFO PREFIX "Please implement %s\n", __FUNCTION__); + printk(KERN_INFO PREFIX "Please implement %s\n", __func__); seq_printf(seq, "<TODO>\n"); end: @@ -1366,37 +1337,8 @@ acpi_video_bus_write_DOS(struct file *file, static int acpi_video_bus_add_fs(struct acpi_device *device) { - long device_id; - int status; struct proc_dir_entry *entry = NULL; struct acpi_video_bus *video; - struct device *dev; - - status = - acpi_evaluate_integer(device->handle, "_ADR", NULL, &device_id); - - if (!ACPI_SUCCESS(status)) - return -ENODEV; - - /* We need to attempt to determine whether the _ADR refers to a - PCI device or not. There's no terribly good way to do this, - so the best we can hope for is to assume that there'll never - be a video device in the host bridge */ - if (device_id >= 0x10000) { - /* It looks like a PCI device. Does it exist? */ - dev = acpi_get_physical_device(device->handle); - } else { - /* It doesn't look like a PCI device. Does its parent - exist? */ - acpi_handle phandle; - if (acpi_get_parent(device->handle, &phandle)) - return -ENODEV; - dev = acpi_get_physical_device(phandle); - } - if (!dev) - return -ENODEV; - put_device(dev); - video = acpi_driver_data(device); diff --git a/drivers/acpi/wmi.c b/drivers/acpi/wmi.c index efacc9f8bfe3..c33b1c6e93b1 100644 --- a/drivers/acpi/wmi.c +++ b/drivers/acpi/wmi.c @@ -293,7 +293,7 @@ struct acpi_buffer *out) { struct guid_block *block = NULL; struct wmi_block *wblock = NULL; - acpi_handle handle; + acpi_handle handle, wc_handle; acpi_status status, wc_status = AE_ERROR; struct acpi_object_list input, wc_input; union acpi_object wc_params[1], wq_params[1]; @@ -338,8 +338,10 @@ struct acpi_buffer *out) * expensive, but have no corresponding WCxx method. So we * should not fail if this happens. */ - wc_status = acpi_evaluate_object(handle, wc_method, - &wc_input, NULL); + wc_status = acpi_get_handle(handle, wc_method, &wc_handle); + if (ACPI_SUCCESS(wc_status)) + wc_status = acpi_evaluate_object(handle, wc_method, + &wc_input, NULL); } strcpy(method, "WQ"); @@ -351,7 +353,7 @@ struct acpi_buffer *out) * If ACPI_WMI_EXPENSIVE, call the relevant WCxx method, even if * the WQxx method failed - we should disable collection anyway. */ - if ((block->flags & ACPI_WMI_EXPENSIVE) && wc_status) { + if ((block->flags & ACPI_WMI_EXPENSIVE) && ACPI_SUCCESS(wc_status)) { wc_params[0].integer.value = 0; status = acpi_evaluate_object(handle, wc_method, &wc_input, NULL); diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index ba8f7f4dfa11..25aba69b59b4 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -30,6 +30,7 @@ config ATA_NONSTANDARD config ATA_ACPI bool depends on ACPI && PCI + select ACPI_DOCK default y help This option adds support for ATA-related ACPI objects. @@ -538,6 +539,15 @@ config PATA_RADISYS If unsure, say N. +config PATA_RB500 + tristate "RouterBoard 500 PATA CompactFlash support" + depends on MIKROTIK_RB500 + help + This option enables support for the RouterBoard 500 + PATA CompactFlash controller. + + If unsure, say N. + config PATA_RZ1000 tristate "PC Tech RZ1000 PATA support" depends on PCI diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index 701651e37c89..0511e6f0bb58 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -55,6 +55,7 @@ obj-$(CONFIG_PATA_PDC2027X) += pata_pdc2027x.o obj-$(CONFIG_PATA_PDC_OLD) += pata_pdc202xx_old.o obj-$(CONFIG_PATA_QDI) += pata_qdi.o obj-$(CONFIG_PATA_RADISYS) += pata_radisys.o +obj-$(CONFIG_PATA_RB500) += pata_rb500_cf.o obj-$(CONFIG_PATA_RZ1000) += pata_rz1000.o obj-$(CONFIG_PATA_SC1200) += pata_sc1200.o obj-$(CONFIG_PATA_SERVERWORKS) += pata_serverworks.o diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 8a49835bd0f8..17ee6ed985d9 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -49,6 +49,10 @@ #define DRV_NAME "ahci" #define DRV_VERSION "3.0" +static int ahci_skip_host_reset; +module_param_named(skip_host_reset, ahci_skip_host_reset, int, 0444); +MODULE_PARM_DESC(skip_host_reset, "skip global host reset (0=don't skip, 1=skip)"); + static int ahci_enable_alpm(struct ata_port *ap, enum link_pm policy); static void ahci_disable_alpm(struct ata_port *ap); @@ -567,6 +571,18 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(NVIDIA, 0x0abd), board_ahci }, /* MCP79 */ { PCI_VDEVICE(NVIDIA, 0x0abe), board_ahci }, /* MCP79 */ { PCI_VDEVICE(NVIDIA, 0x0abf), board_ahci }, /* MCP79 */ + { PCI_VDEVICE(NVIDIA, 0x0bc8), board_ahci }, /* MCP7B */ + { PCI_VDEVICE(NVIDIA, 0x0bc9), board_ahci }, /* MCP7B */ + { PCI_VDEVICE(NVIDIA, 0x0bca), board_ahci }, /* MCP7B */ + { PCI_VDEVICE(NVIDIA, 0x0bcb), board_ahci }, /* MCP7B */ + { PCI_VDEVICE(NVIDIA, 0x0bcc), board_ahci }, /* MCP7B */ + { PCI_VDEVICE(NVIDIA, 0x0bcd), board_ahci }, /* MCP7B */ + { PCI_VDEVICE(NVIDIA, 0x0bce), board_ahci }, /* MCP7B */ + { PCI_VDEVICE(NVIDIA, 0x0bcf), board_ahci }, /* MCP7B */ + { PCI_VDEVICE(NVIDIA, 0x0bd0), board_ahci }, /* MCP7B */ + { PCI_VDEVICE(NVIDIA, 0x0bd1), board_ahci }, /* MCP7B */ + { PCI_VDEVICE(NVIDIA, 0x0bd2), board_ahci }, /* MCP7B */ + { PCI_VDEVICE(NVIDIA, 0x0bd3), board_ahci }, /* MCP7B */ /* SiS */ { PCI_VDEVICE(SI, 0x1184), board_ahci }, /* SiS 966 */ @@ -575,6 +591,7 @@ static const struct pci_device_id ahci_pci_tbl[] = { /* Marvell */ { PCI_VDEVICE(MARVELL, 0x6145), board_ahci_mv }, /* 6145 */ + { PCI_VDEVICE(MARVELL, 0x6121), board_ahci_mv }, /* 6121 */ /* Generic, PCI class code for AHCI */ { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, @@ -649,6 +666,7 @@ static void ahci_save_initial_config(struct pci_dev *pdev, void __iomem *mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR]; u32 cap, port_map; int i; + int mv; /* make sure AHCI mode is enabled before accessing CAP */ ahci_enable_ahci(mmio); @@ -672,7 +690,7 @@ static void ahci_save_initial_config(struct pci_dev *pdev, cap &= ~HOST_CAP_NCQ; } - if ((cap && HOST_CAP_PMP) && (hpriv->flags & AHCI_HFLAG_NO_PMP)) { + if ((cap & HOST_CAP_PMP) && (hpriv->flags & AHCI_HFLAG_NO_PMP)) { dev_printk(KERN_INFO, &pdev->dev, "controller can't do PMP, turning off CAP_PMP\n"); cap &= ~HOST_CAP_PMP; @@ -684,12 +702,16 @@ static void ahci_save_initial_config(struct pci_dev *pdev, * presence register, as bit 4 (counting from 0) */ if (hpriv->flags & AHCI_HFLAG_MV_PATA) { + if (pdev->device == 0x6121) + mv = 0x3; + else + mv = 0xf; dev_printk(KERN_ERR, &pdev->dev, "MV_AHCI HACK: port_map %x -> %x\n", - hpriv->port_map, - hpriv->port_map & 0xf); + port_map, + port_map & mv); - port_map &= 0xf; + port_map &= mv; } /* cross check port_map and cap.n_ports */ @@ -1076,29 +1098,35 @@ static int ahci_reset_controller(struct ata_host *host) ahci_enable_ahci(mmio); /* global controller reset */ - tmp = readl(mmio + HOST_CTL); - if ((tmp & HOST_RESET) == 0) { - writel(tmp | HOST_RESET, mmio + HOST_CTL); - readl(mmio + HOST_CTL); /* flush */ - } + if (!ahci_skip_host_reset) { + tmp = readl(mmio + HOST_CTL); + if ((tmp & HOST_RESET) == 0) { + writel(tmp | HOST_RESET, mmio + HOST_CTL); + readl(mmio + HOST_CTL); /* flush */ + } - /* reset must complete within 1 second, or - * the hardware should be considered fried. - */ - ssleep(1); + /* reset must complete within 1 second, or + * the hardware should be considered fried. + */ + ssleep(1); - tmp = readl(mmio + HOST_CTL); - if (tmp & HOST_RESET) { - dev_printk(KERN_ERR, host->dev, - "controller reset failed (0x%x)\n", tmp); - return -EIO; - } + tmp = readl(mmio + HOST_CTL); + if (tmp & HOST_RESET) { + dev_printk(KERN_ERR, host->dev, + "controller reset failed (0x%x)\n", tmp); + return -EIO; + } - /* turn on AHCI mode */ - ahci_enable_ahci(mmio); + /* turn on AHCI mode */ + ahci_enable_ahci(mmio); - /* some registers might be cleared on reset. restore initial values */ - ahci_restore_initial_config(host); + /* Some registers might be cleared on reset. Restore + * initial values. + */ + ahci_restore_initial_config(host); + } else + dev_printk(KERN_INFO, host->dev, + "skipping global host reset\n"); if (pdev->vendor == PCI_VENDOR_ID_INTEL) { u16 tmp16; @@ -1150,9 +1178,14 @@ static void ahci_init_controller(struct ata_host *host) int i; void __iomem *port_mmio; u32 tmp; + int mv; if (hpriv->flags & AHCI_HFLAG_MV_PATA) { - port_mmio = __ahci_port_base(host, 4); + if (pdev->device == 0x6121) + mv = 2; + else + mv = 4; + port_mmio = __ahci_port_base(host, mv); writel(0, port_mmio + PORT_IRQ_MASK); @@ -2229,7 +2262,10 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) return rc; - rc = pcim_iomap_regions(pdev, 1 << AHCI_PCI_BAR, DRV_NAME); + /* AHCI controllers often implement SFF compatible interface. + * Grab all PCI BARs just in case. + */ + rc = pcim_iomap_regions_request_all(pdev, 1 << AHCI_PCI_BAR, DRV_NAME); if (rc == -EBUSY) pcim_pin_device(pdev); if (rc) diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index 9e8ec19260af..bf98a566adac 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c @@ -118,45 +118,77 @@ static void ata_acpi_associate_ide_port(struct ata_port *ap) ap->pflags |= ATA_PFLAG_INIT_GTM_VALID; } -static void ata_acpi_handle_hotplug(struct ata_port *ap, struct kobject *kobj, +static void ata_acpi_handle_hotplug(struct ata_port *ap, struct ata_device *dev, u32 event) { char event_string[12]; char *envp[] = { event_string, NULL }; - struct ata_eh_info *ehi = &ap->link.eh_info; - - if (event == 0 || event == 1) { - unsigned long flags; - spin_lock_irqsave(ap->lock, flags); - ata_ehi_clear_desc(ehi); - ata_ehi_push_desc(ehi, "ACPI event"); - ata_ehi_hotplugged(ehi); - ata_port_freeze(ap); - spin_unlock_irqrestore(ap->lock, flags); + struct ata_eh_info *ehi; + struct kobject *kobj = NULL; + int wait = 0; + unsigned long flags; + + if (!ap) + ap = dev->link->ap; + ehi = &ap->link.eh_info; + + spin_lock_irqsave(ap->lock, flags); + + switch (event) { + case ACPI_NOTIFY_BUS_CHECK: + case ACPI_NOTIFY_DEVICE_CHECK: + ata_ehi_push_desc(ehi, "ACPI event"); + ata_ehi_hotplugged(ehi); + ata_port_freeze(ap); + break; + + case ACPI_NOTIFY_EJECT_REQUEST: + ata_ehi_push_desc(ehi, "ACPI event"); + if (dev) + dev->flags |= ATA_DFLAG_DETACH; + else { + struct ata_link *tlink; + struct ata_device *tdev; + + ata_port_for_each_link(tlink, ap) + ata_link_for_each_dev(tdev, tlink) + tdev->flags |= ATA_DFLAG_DETACH; + } + + ata_port_schedule_eh(ap); + wait = 1; + break; } + if (dev) { + if (dev->sdev) + kobj = &dev->sdev->sdev_gendev.kobj; + } else + kobj = &ap->dev->kobj; + if (kobj) { sprintf(event_string, "BAY_EVENT=%d", event); kobject_uevent_env(kobj, KOBJ_CHANGE, envp); } + + spin_unlock_irqrestore(ap->lock, flags); + + if (wait) + ata_port_wait_eh(ap); } static void ata_acpi_dev_notify(acpi_handle handle, u32 event, void *data) { struct ata_device *dev = data; - struct kobject *kobj = NULL; - if (dev->sdev) - kobj = &dev->sdev->sdev_gendev.kobj; - - ata_acpi_handle_hotplug(dev->link->ap, kobj, event); + ata_acpi_handle_hotplug(NULL, dev, event); } static void ata_acpi_ap_notify(acpi_handle handle, u32 event, void *data) { struct ata_port *ap = data; - ata_acpi_handle_hotplug(ap, &ap->dev->kobj, event); + ata_acpi_handle_hotplug(ap, NULL, event); } /** @@ -191,20 +223,30 @@ void ata_acpi_associate(struct ata_host *host) else ata_acpi_associate_ide_port(ap); - if (ap->acpi_handle) - acpi_install_notify_handler (ap->acpi_handle, - ACPI_SYSTEM_NOTIFY, - ata_acpi_ap_notify, - ap); + if (ap->acpi_handle) { + acpi_install_notify_handler(ap->acpi_handle, + ACPI_SYSTEM_NOTIFY, + ata_acpi_ap_notify, ap); +#if defined(CONFIG_ACPI_DOCK) || defined(CONFIG_ACPI_DOCK_MODULE) + /* we might be on a docking station */ + register_hotplug_dock_device(ap->acpi_handle, + ata_acpi_ap_notify, ap); +#endif + } for (j = 0; j < ata_link_max_devices(&ap->link); j++) { struct ata_device *dev = &ap->link.device[j]; - if (dev->acpi_handle) - acpi_install_notify_handler (dev->acpi_handle, - ACPI_SYSTEM_NOTIFY, - ata_acpi_dev_notify, - dev); + if (dev->acpi_handle) { + acpi_install_notify_handler(dev->acpi_handle, + ACPI_SYSTEM_NOTIFY, + ata_acpi_dev_notify, dev); +#if defined(CONFIG_ACPI_DOCK) || defined(CONFIG_ACPI_DOCK_MODULE) + /* we might be on a docking station */ + register_hotplug_dock_device(dev->acpi_handle, + ata_acpi_dev_notify, dev); +#endif + } } } } @@ -382,7 +424,7 @@ static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf) if (ata_msg_probe(ap)) ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER: port#: %d\n", - __FUNCTION__, ap->port_no); + __func__, ap->port_no); /* _GTF has no input parameters */ status = acpi_evaluate_object(dev->acpi_handle, "_GTF", NULL, &output); @@ -402,7 +444,7 @@ static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf) if (ata_msg_probe(ap)) ata_dev_printk(dev, KERN_DEBUG, "%s: Run _GTF: " "length or ptr is NULL (0x%llx, 0x%p)\n", - __FUNCTION__, + __func__, (unsigned long long)output.length, output.pointer); rc = -EINVAL; @@ -432,7 +474,7 @@ static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf) if (ata_msg_probe(ap)) ata_dev_printk(dev, KERN_DEBUG, "%s: returning gtf=%p, gtf_count=%d\n", - __FUNCTION__, *gtf, rc); + __func__, *gtf, rc); } return rc; @@ -725,7 +767,7 @@ static int ata_acpi_push_id(struct ata_device *dev) if (ata_msg_probe(ap)) ata_dev_printk(dev, KERN_DEBUG, "%s: ix = %d, port#: %d\n", - __FUNCTION__, dev->devno, ap->port_no); + __func__, dev->devno, ap->port_no); /* Give the drive Identify data to the drive via the _SDD method */ /* _SDD: set up input parameters */ diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 4fbcce758b04..4bbe31f98ef8 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -106,7 +106,8 @@ static struct ata_force_ent *ata_force_tbl; static int ata_force_tbl_size; static char ata_force_param_buf[PAGE_SIZE] __initdata; -module_param_string(force, ata_force_param_buf, sizeof(ata_force_param_buf), 0444); +/* param_buf is thrown away after initialization, disallow read */ +module_param_string(force, ata_force_param_buf, sizeof(ata_force_param_buf), 0); MODULE_PARM_DESC(force, "Force ATA configurations including cable type, link speed and transfer mode (see Documentation/kernel-parameters.txt for details)"); int atapi_enabled = 1; @@ -1719,7 +1720,7 @@ void ata_port_flush_task(struct ata_port *ap) cancel_rearming_delayed_work(&ap->port_task); if (ata_msg_ctl(ap)) - ata_port_printk(ap, KERN_DEBUG, "%s: EXIT\n", __FUNCTION__); + ata_port_printk(ap, KERN_DEBUG, "%s: EXIT\n", __func__); } static void ata_qc_complete_internal(struct ata_queued_cmd *qc) @@ -2056,7 +2057,7 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, int rc; if (ata_msg_ctl(ap)) - ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER\n", __FUNCTION__); + ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER\n", __func__); ata_dev_select(ap, dev->devno, 1, 1); /* select device 0/1 */ retry: @@ -2253,12 +2254,12 @@ int ata_dev_configure(struct ata_device *dev) if (!ata_dev_enabled(dev) && ata_msg_info(ap)) { ata_dev_printk(dev, KERN_INFO, "%s: ENTER/EXIT -- nodev\n", - __FUNCTION__); + __func__); return 0; } if (ata_msg_probe(ap)) - ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER\n", __FUNCTION__); + ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER\n", __func__); /* set horkage */ dev->horkage |= ata_dev_blacklisted(dev); @@ -2279,7 +2280,7 @@ int ata_dev_configure(struct ata_device *dev) ata_dev_printk(dev, KERN_DEBUG, "%s: cfg 49:%04x 82:%04x 83:%04x 84:%04x " "85:%04x 86:%04x 87:%04x 88:%04x\n", - __FUNCTION__, + __func__, id[49], id[82], id[83], id[84], id[85], id[86], id[87], id[88]); @@ -2511,13 +2512,13 @@ int ata_dev_configure(struct ata_device *dev) if (ata_msg_probe(ap)) ata_dev_printk(dev, KERN_DEBUG, "%s: EXIT, drv_stat = 0x%x\n", - __FUNCTION__, ata_chk_status(ap)); + __func__, ata_chk_status(ap)); return 0; err_out_nosup: if (ata_msg_probe(ap)) ata_dev_printk(dev, KERN_DEBUG, - "%s: EXIT, err\n", __FUNCTION__); + "%s: EXIT, err\n", __func__); return rc; } diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 698ce2cea52c..681252fd8143 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -2150,6 +2150,15 @@ int ata_eh_reset(struct ata_link *link, int classify, ap->ops->set_piomode(ap, dev); } + if (!softreset && !hardreset) { + if (verbose) + ata_link_printk(link, KERN_INFO, "no reset method " + "available, skipping reset\n"); + if (!(lflags & ATA_LFLAG_ASSUME_CLASS)) + lflags |= ATA_LFLAG_ASSUME_ATA; + goto done; + } + /* Determine which reset to use and record in ehc->i.action. * prereset() may examine and modify it. */ @@ -2254,6 +2263,7 @@ int ata_eh_reset(struct ata_link *link, int classify, lflags |= ATA_LFLAG_ASSUME_ATA; } + done: ata_link_for_each_dev(dev, link) { /* After the reset, the device state is PIO 0 and the * controller state is undefined. Reset also wakes up diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 60cd4b179766..20dc572fb45a 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -56,7 +56,8 @@ u8 ata_irq_on(struct ata_port *ap) ap->ctl &= ~ATA_NIEN; ap->last_ctl = ap->ctl; - iowrite8(ap->ctl, ioaddr->ctl_addr); + if (ioaddr->ctl_addr) + iowrite8(ap->ctl, ioaddr->ctl_addr); tmp = ata_wait_idle(ap); ap->ops->irq_clear(ap); @@ -81,12 +82,14 @@ void ata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; if (tf->ctl != ap->last_ctl) { - iowrite8(tf->ctl, ioaddr->ctl_addr); + if (ioaddr->ctl_addr) + iowrite8(tf->ctl, ioaddr->ctl_addr); ap->last_ctl = tf->ctl; ata_wait_idle(ap); } if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) { + WARN_ON(!ioaddr->ctl_addr); iowrite8(tf->hob_feature, ioaddr->feature_addr); iowrite8(tf->hob_nsect, ioaddr->nsect_addr); iowrite8(tf->hob_lbal, ioaddr->lbal_addr); @@ -167,14 +170,17 @@ void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf) tf->device = ioread8(ioaddr->device_addr); if (tf->flags & ATA_TFLAG_LBA48) { - iowrite8(tf->ctl | ATA_HOB, ioaddr->ctl_addr); - tf->hob_feature = ioread8(ioaddr->error_addr); - tf->hob_nsect = ioread8(ioaddr->nsect_addr); - tf->hob_lbal = ioread8(ioaddr->lbal_addr); - tf->hob_lbam = ioread8(ioaddr->lbam_addr); - tf->hob_lbah = ioread8(ioaddr->lbah_addr); - iowrite8(tf->ctl, ioaddr->ctl_addr); - ap->last_ctl = tf->ctl; + if (likely(ioaddr->ctl_addr)) { + iowrite8(tf->ctl | ATA_HOB, ioaddr->ctl_addr); + tf->hob_feature = ioread8(ioaddr->error_addr); + tf->hob_nsect = ioread8(ioaddr->nsect_addr); + tf->hob_lbal = ioread8(ioaddr->lbal_addr); + tf->hob_lbam = ioread8(ioaddr->lbam_addr); + tf->hob_lbah = ioread8(ioaddr->lbah_addr); + iowrite8(tf->ctl, ioaddr->ctl_addr); + ap->last_ctl = tf->ctl; + } else + WARN_ON(1); } } @@ -352,7 +358,8 @@ void ata_bmdma_freeze(struct ata_port *ap) ap->ctl |= ATA_NIEN; ap->last_ctl = ap->ctl; - iowrite8(ap->ctl, ioaddr->ctl_addr); + if (ioaddr->ctl_addr) + iowrite8(ap->ctl, ioaddr->ctl_addr); /* Under certain circumstances, some controllers raise IRQ on * ATA_NIEN manipulation. Also, many controllers fail to mask @@ -459,13 +466,14 @@ void ata_bmdma_drive_eh(struct ata_port *ap, ata_prereset_fn_t prereset, */ void ata_bmdma_error_handler(struct ata_port *ap) { - ata_reset_fn_t hardreset; + ata_reset_fn_t softreset = NULL, hardreset = NULL; - hardreset = NULL; + if (ap->ioaddr.ctl_addr) + softreset = ata_std_softreset; if (sata_scr_valid(&ap->link)) hardreset = sata_std_hardreset; - ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset, hardreset, + ata_bmdma_drive_eh(ap, ata_std_prereset, softreset, hardreset, ata_std_postreset); } diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c index 7e68edf3c0f3..8786455c901d 100644 --- a/drivers/ata/pata_ali.c +++ b/drivers/ata/pata_ali.c @@ -295,7 +295,7 @@ static void ali_lock_sectors(struct ata_device *adev) static int ali_check_atapi_dma(struct ata_queued_cmd *qc) { /* If its not a media command, its not worth it */ - if (qc->nbytes < 2048) + if (atapi_cmd_type(qc->cdb[0]) == ATAPI_MISC) return -EOPNOTSUPP; return 0; } diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c index 028af5dbeed6..511c89b9bae8 100644 --- a/drivers/ata/pata_pdc2027x.c +++ b/drivers/ata/pata_pdc2027x.c @@ -39,7 +39,7 @@ #undef PDC_DEBUG #ifdef PDC_DEBUG -#define PDPRINTK(fmt, args...) printk(KERN_ERR "%s: " fmt, __FUNCTION__, ## args) +#define PDPRINTK(fmt, args...) printk(KERN_ERR "%s: " fmt, __func__, ## args) #else #define PDPRINTK(fmt, args...) #endif diff --git a/drivers/ata/pata_rb500_cf.c b/drivers/ata/pata_rb500_cf.c new file mode 100644 index 000000000000..4ce9b03fe6c8 --- /dev/null +++ b/drivers/ata/pata_rb500_cf.c @@ -0,0 +1,314 @@ +/* + * A low-level PATA driver to handle a Compact Flash connected on the + * Mikrotik's RouterBoard 532 board. + * + * Copyright (C) 2007 Gabor Juhos <juhosg at openwrt.org> + * Copyright (C) 2008 Florian Fainelli <florian@openwrt.org> + * + * This file was based on: drivers/ata/pata_ixp4xx_cf.c + * Copyright (C) 2006-07 Tower Technologies + * Author: Alessandro Zummo <a.zummo@towertech.it> + * + * Also was based on the driver for Linux 2.4.xx published by Mikrotik for + * their RouterBoard 1xx and 5xx series devices. The original Mikrotik code + * seems not to have a license. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> + +#include <linux/io.h> +#include <linux/interrupt.h> +#include <linux/irq.h> + +#include <linux/libata.h> +#include <scsi/scsi_host.h> + +#include <asm/gpio.h> + +#define DRV_NAME "pata-rb500-cf" +#define DRV_VERSION "0.1.0" +#define DRV_DESC "PATA driver for RouterBOARD 532 Compact Flash" + +#define RB500_CF_MAXPORTS 1 +#define RB500_CF_IO_DELAY 400 + +#define RB500_CF_REG_CMD 0x0800 +#define RB500_CF_REG_CTRL 0x080E +#define RB500_CF_REG_DATA 0x0C00 + +struct rb500_cf_info { + void __iomem *iobase; + unsigned int gpio_line; + int frozen; + unsigned int irq; +}; + +/* ------------------------------------------------------------------------ */ + +static inline void rb500_pata_finish_io(struct ata_port *ap) +{ + struct ata_host *ah = ap->host; + struct rb500_cf_info *info = ah->private_data; + + ata_altstatus(ap); + ndelay(RB500_CF_IO_DELAY); + + set_irq_type(info->irq, IRQ_TYPE_LEVEL_HIGH); +} + +static void rb500_pata_exec_command(struct ata_port *ap, + const struct ata_taskfile *tf) +{ + writeb(tf->command, ap->ioaddr.command_addr); + rb500_pata_finish_io(ap); +} + +static void rb500_pata_data_xfer(struct ata_device *adev, unsigned char *buf, + unsigned int buflen, int write_data) +{ + struct ata_port *ap = adev->link->ap; + void __iomem *ioaddr = ap->ioaddr.data_addr; + + if (write_data) { + for (; buflen > 0; buflen--, buf++) + writeb(*buf, ioaddr); + } else { + for (; buflen > 0; buflen--, buf++) + *buf = readb(ioaddr); + } + + rb500_pata_finish_io(adev->link->ap); +} + +static void rb500_pata_freeze(struct ata_port *ap) +{ + struct rb500_cf_info *info = ap->host->private_data; + + info->frozen = 1; +} + +static void rb500_pata_thaw(struct ata_port *ap) +{ + struct rb500_cf_info *info = ap->host->private_data; + + info->frozen = 0; +} + +static irqreturn_t rb500_pata_irq_handler(int irq, void *dev_instance) +{ + struct ata_host *ah = dev_instance; + struct rb500_cf_info *info = ah->private_data; + + if (gpio_get_value(info->gpio_line)) { + set_irq_type(info->irq, IRQ_TYPE_LEVEL_LOW); + if (!info->frozen) + ata_interrupt(info->irq, dev_instance); + } else { + set_irq_type(info->irq, IRQ_TYPE_LEVEL_HIGH); + } + + return IRQ_HANDLED; +} + +static void rb500_pata_irq_clear(struct ata_port *ap) +{ +} + +static int rb500_pata_port_start(struct ata_port *ap) +{ + return 0; +} + +static struct ata_port_operations rb500_pata_port_ops = { + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + + .exec_command = rb500_pata_exec_command, + .check_status = ata_check_status, + .dev_select = ata_std_dev_select, + + .data_xfer = rb500_pata_data_xfer, + + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, + + .freeze = rb500_pata_freeze, + .thaw = rb500_pata_thaw, + .error_handler = ata_bmdma_error_handler, + + .irq_handler = rb500_pata_irq_handler, + .irq_clear = rb500_pata_irq_clear, + .irq_on = ata_irq_on, + + .port_start = rb500_pata_port_start, +}; + +/* ------------------------------------------------------------------------ */ + +static struct scsi_host_template rb500_pata_sht = { + .module = THIS_MODULE, + .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, + .queuecommand = ata_scsi_queuecmd, + .slave_configure = ata_scsi_slave_config, + .slave_destroy = ata_scsi_slave_destroy, + .bios_param = ata_std_bios_param, + .proc_name = DRV_NAME, + + .can_queue = ATA_DEF_QUEUE, + .this_id = ATA_SHT_THIS_ID, + .sg_tablesize = LIBATA_MAX_PRD, + .dma_boundary = ATA_DMA_BOUNDARY, + .cmd_per_lun = ATA_SHT_CMD_PER_LUN, + .emulated = ATA_SHT_EMULATED, + .use_clustering = ATA_SHT_USE_CLUSTERING, +}; + +/* ------------------------------------------------------------------------ */ + +static void rb500_pata_setup_ports(struct ata_host *ah) +{ + struct rb500_cf_info *info = ah->private_data; + struct ata_port *ap; + + ap = ah->ports[0]; + + ap->ops = &rb500_pata_port_ops; + ap->pio_mask = 0x1f; /* PIO4 */ + ap->flags = ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO; + + ap->ioaddr.cmd_addr = info->iobase + RB500_CF_REG_CMD; + ap->ioaddr.ctl_addr = info->iobase + RB500_CF_REG_CTRL; + ap->ioaddr.altstatus_addr = info->iobase + RB500_CF_REG_CTRL; + + ata_std_ports(&ap->ioaddr); + + ap->ioaddr.data_addr = info->iobase + RB500_CF_REG_DATA; +} + +static __devinit int rb500_pata_driver_probe(struct platform_device *pdev) +{ + unsigned int irq; + int gpio; + struct resource *res; + struct ata_host *ah; + struct rb500_cf_info *info; + int ret; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "no IOMEM resource found\n"); + return -EINVAL; + } + + irq = platform_get_irq(pdev, 0); + if (irq <= 0) { + dev_err(&pdev->dev, "no IRQ resource found\n"); + return -ENOENT; + } + + gpio = irq_to_gpio(irq); + if (gpio < 0) { + dev_err(&pdev->dev, "no GPIO found for irq%d\n", irq); + return -ENOENT; + } + + ret = gpio_request(gpio, DRV_NAME); + if (ret) { + dev_err(&pdev->dev, "GPIO request failed\n"); + return ret; + } + + /* allocate host */ + ah = ata_host_alloc(&pdev->dev, RB500_CF_MAXPORTS); + if (!ah) + return -ENOMEM; + + platform_set_drvdata(pdev, ah); + + info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + ah->private_data = info; + info->gpio_line = gpio; + info->irq = irq; + + info->iobase = devm_ioremap_nocache(&pdev->dev, res->start, + res->end - res->start + 1); + if (!info->iobase) + return -ENOMEM; + + ret = gpio_direction_input(gpio); + if (ret) { + dev_err(&pdev->dev, "unable to set GPIO direction, err=%d\n", + ret); + goto err_free_gpio; + } + + rb500_pata_setup_ports(ah); + + ret = ata_host_activate(ah, irq, rb500_pata_irq_handler, + IRQF_TRIGGER_LOW, &rb500_pata_sht); + if (ret) + goto err_free_gpio; + + return 0; + +err_free_gpio: + gpio_free(gpio); + + return ret; +} + +static __devexit int rb500_pata_driver_remove(struct platform_device *pdev) +{ + struct ata_host *ah = platform_get_drvdata(pdev); + struct rb500_cf_info *info = ah->private_data; + + ata_host_detach(ah); + gpio_free(info->gpio_line); + + return 0; +} + +static struct platform_driver rb500_pata_platform_driver = { + .probe = rb500_pata_driver_probe, + .remove = __devexit_p(rb500_pata_driver_remove), + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, +}; + +/* ------------------------------------------------------------------------ */ + +#define DRV_INFO DRV_DESC " version " DRV_VERSION + +static int __init rb500_pata_module_init(void) +{ + printk(KERN_INFO DRV_INFO "\n"); + + return platform_driver_register(&rb500_pata_platform_driver); +} + +static void __exit rb500_pata_module_exit(void) +{ + platform_driver_unregister(&rb500_pata_platform_driver); +} + +MODULE_AUTHOR("Gabor Juhos <juhosg at openwrt.org>"); +MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>"); +MODULE_DESCRIPTION(DRV_DESC); +MODULE_VERSION(DRV_VERSION); +MODULE_LICENSE("GPL"); + +module_init(rb500_pata_module_init); +module_exit(rb500_pata_module_exit); diff --git a/drivers/atm/firestream.c b/drivers/atm/firestream.c index c662d686154a..47c57a4294b7 100644 --- a/drivers/atm/firestream.c +++ b/drivers/atm/firestream.c @@ -331,8 +331,8 @@ module_param(fs_keystream, int, 0); #define FS_DEBUG_QSIZE 0x00001000 -#define func_enter() fs_dprintk (FS_DEBUG_FLOW, "fs: enter %s\n", __FUNCTION__) -#define func_exit() fs_dprintk (FS_DEBUG_FLOW, "fs: exit %s\n", __FUNCTION__) +#define func_enter() fs_dprintk(FS_DEBUG_FLOW, "fs: enter %s\n", __func__) +#define func_exit() fs_dprintk(FS_DEBUG_FLOW, "fs: exit %s\n", __func__) static struct fs_dev *fs_boards = NULL; diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c index f97e050338f0..9427a61f62b0 100644 --- a/drivers/atm/fore200e.c +++ b/drivers/atm/fore200e.c @@ -95,8 +95,8 @@ #if 1 #define ASSERT(expr) if (!(expr)) { \ printk(FORE200E "assertion failed! %s[%d]: %s\n", \ - __FUNCTION__, __LINE__, #expr); \ - panic(FORE200E "%s", __FUNCTION__); \ + __func__, __LINE__, #expr); \ + panic(FORE200E "%s", __func__); \ } #else #define ASSERT(expr) do {} while (0) diff --git a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c index eee54c0cde68..b967919fb7e2 100644 --- a/drivers/atm/idt77252.c +++ b/drivers/atm/idt77252.c @@ -555,7 +555,7 @@ idt77252_tx_dump(struct idt77252_dev *card) struct vc_map *vc; int i; - printk("%s\n", __FUNCTION__); + printk("%s\n", __func__); for (i = 0; i < card->tct_size; i++) { vc = card->vcs[i]; if (!vc) @@ -1035,7 +1035,7 @@ dequeue_rx(struct idt77252_dev *card, struct rsq_entry *rsqe) skb = sb_pool_skb(card, le32_to_cpu(rsqe->word_2)); if (skb == NULL) { printk("%s: NULL skb in %s, rsqe: %08x %08x %08x %08x\n", - card->name, __FUNCTION__, + card->name, __func__, le32_to_cpu(rsqe->word_1), le32_to_cpu(rsqe->word_2), le32_to_cpu(rsqe->word_3), le32_to_cpu(rsqe->word_4)); return; @@ -1873,7 +1873,7 @@ add_rx_skb(struct idt77252_dev *card, int queue, return; if (sb_pool_add(card, skb, queue)) { - printk("%s: SB POOL full\n", __FUNCTION__); + printk("%s: SB POOL full\n", __func__); goto outfree; } @@ -1883,7 +1883,7 @@ add_rx_skb(struct idt77252_dev *card, int queue, IDT77252_PRV_PADDR(skb) = paddr; if (push_rx_skb(card, skb, queue)) { - printk("%s: FB QUEUE full\n", __FUNCTION__); + printk("%s: FB QUEUE full\n", __func__); goto outunmap; } } @@ -3821,12 +3821,12 @@ static int __init idt77252_init(void) { struct sk_buff *skb; - printk("%s: at %p\n", __FUNCTION__, idt77252_init); + printk("%s: at %p\n", __func__, idt77252_init); if (sizeof(skb->cb) < sizeof(struct atm_skb_data) + sizeof(struct idt77252_skb_prv)) { printk(KERN_ERR "%s: skb->cb is too small (%lu < %lu)\n", - __FUNCTION__, (unsigned long) sizeof(skb->cb), + __func__, (unsigned long) sizeof(skb->cb), (unsigned long) sizeof(struct atm_skb_data) + sizeof(struct idt77252_skb_prv)); return -EIO; diff --git a/drivers/base/platform.c b/drivers/base/platform.c index efaf282c438c..911ec600fe71 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -648,7 +648,7 @@ u64 dma_get_required_mask(struct device *dev) high_totalram += high_totalram - 1; mask = (((u64)high_totalram) << 32) + 0xffffffff; } - return mask & *dev->dma_mask; + return mask; } EXPORT_SYMBOL_GPL(dma_get_required_mask); #endif diff --git a/drivers/base/sys.c b/drivers/base/sys.c index 2f79c55acdcc..8e13fd942163 100644 --- a/drivers/base/sys.c +++ b/drivers/base/sys.c @@ -133,6 +133,7 @@ int sysdev_class_register(struct sysdev_class * cls) pr_debug("Registering sysdev class '%s'\n", kobject_name(&cls->kset.kobj)); INIT_LIST_HEAD(&cls->drivers); + memset(&cls->kset.kobj, 0x00, sizeof(struct kobject)); cls->kset.kobj.parent = &system_kset->kobj; cls->kset.kobj.ktype = &ktype_sysdev_class; cls->kset.kobj.kset = system_kset; @@ -227,6 +228,9 @@ int sysdev_register(struct sys_device * sysdev) pr_debug("Registering sys device '%s'\n", kobject_name(&sysdev->kobj)); + /* initialize the kobject to 0, in case it had previously been used */ + memset(&sysdev->kobj, 0x00, sizeof(struct kobject)); + /* Make sure the kset is set */ sysdev->kobj.kset = &cls->kset; diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index b6d230b3209f..0d1d2133d9bc 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -44,16 +44,6 @@ config MAC_FLOPPY If you have a SWIM-3 (Super Woz Integrated Machine 3; from Apple) floppy controller, say Y here. Most commonly found in PowerMacs. -config BLK_DEV_PS2 - tristate "PS/2 ESDI hard disk support" - depends on MCA && MCA_LEGACY && BROKEN - help - Say Y here if you have a PS/2 machine with a MCA bus and an ESDI - hard disk. - - To compile this driver as a module, choose M here: the - module will be called ps2esdi. - config AMIGA_Z2RAM tristate "Amiga Zorro II ramdisk support" depends on ZORRO diff --git a/drivers/block/Makefile b/drivers/block/Makefile index 01c972415cb2..5e584306be99 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -13,7 +13,6 @@ obj-$(CONFIG_ATARI_FLOPPY) += ataflop.o obj-$(CONFIG_AMIGA_Z2RAM) += z2ram.o obj-$(CONFIG_BLK_DEV_RAM) += brd.o obj-$(CONFIG_BLK_DEV_LOOP) += loop.o -obj-$(CONFIG_BLK_DEV_PS2) += ps2esdi.o obj-$(CONFIG_BLK_DEV_XD) += xd.o obj-$(CONFIG_BLK_CPQ_DA) += cpqarray.o obj-$(CONFIG_BLK_CPQ_CISS_DA) += cciss.o diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 32c79a55511b..7652e87d60c5 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -217,7 +217,6 @@ static int use_virtual_dma; */ static DEFINE_SPINLOCK(floppy_lock); -static struct completion device_release; static unsigned short virtual_dma_port = 0x3f0; irqreturn_t floppy_interrupt(int irq, void *dev_id); @@ -4144,7 +4143,6 @@ DEVICE_ATTR(cmos,S_IRUGO,floppy_cmos_show,NULL); static void floppy_device_release(struct device *dev) { - complete(&device_release); } static struct platform_device floppy_device[N_DRIVE]; @@ -4539,7 +4537,6 @@ void cleanup_module(void) { int drive; - init_completion(&device_release); blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256); unregister_blkdev(FLOPPY_MAJOR, "fd"); @@ -4564,8 +4561,6 @@ void cleanup_module(void) /* eject disk, if any */ fd_eject(0); - - wait_for_completion(&device_release); } module_param(floppy, charp, 0); diff --git a/drivers/block/ps2esdi.c b/drivers/block/ps2esdi.c deleted file mode 100644 index 3c796e236253..000000000000 --- a/drivers/block/ps2esdi.c +++ /dev/null @@ -1,1079 +0,0 @@ -/* ps2esdi driver based on assembler code by Arindam Banerji, - written by Peter De Schrijver */ -/* Reassuring note to IBM : This driver was NOT developed by vice-versa - engineering the PS/2's BIOS */ -/* Dedicated to Wannes, Tofke, Ykke, Godot, Killroy and all those - other lovely fish out there... */ -/* This code was written during the long and boring WINA - elections 1994 */ -/* Thanks to Arindam Banerij for giving me the source of his driver */ -/* This code may be freely distributed and modified in any way, - as long as these notes remain intact */ - -/* Revised: 05/07/94 by Arindam Banerji (axb@cse.nd.edu) */ -/* Revised: 09/08/94 by Peter De Schrijver (stud11@cc4.kuleuven.ac.be) - Thanks to Arindam Banerij for sending me the docs of the adapter */ - -/* BA Modified for ThinkPad 720 by Boris Ashkinazi */ -/* (bash@vnet.ibm.com) 08/08/95 */ - -/* Modified further for ThinkPad-720C by Uri Blumenthal */ -/* (uri@watson.ibm.com) Sep 11, 1995 */ - -/* TODO : - + Timeouts - + Get disk parameters - + DMA above 16MB - + reset after read/write error - */ - -#define DEVICE_NAME "PS/2 ESDI" - -#include <linux/major.h> -#include <linux/errno.h> -#include <linux/wait.h> -#include <linux/interrupt.h> -#include <linux/fs.h> -#include <linux/kernel.h> -#include <linux/genhd.h> -#include <linux/ps2esdi.h> -#include <linux/blkdev.h> -#include <linux/mca-legacy.h> -#include <linux/init.h> -#include <linux/ioport.h> -#include <linux/module.h> -#include <linux/hdreg.h> - -#include <asm/system.h> -#include <asm/io.h> -#include <asm/dma.h> -#include <asm/mca_dma.h> -#include <asm/uaccess.h> - -#define PS2ESDI_IRQ 14 -#define MAX_HD 2 -#define MAX_RETRIES 5 -#define MAX_16BIT 65536 -#define ESDI_TIMEOUT 0xf000 -#define ESDI_STAT_TIMEOUT 4 - -#define TYPE_0_CMD_BLK_LENGTH 2 -#define TYPE_1_CMD_BLK_LENGTH 4 - -static void reset_ctrl(void); - -static int ps2esdi_geninit(void); - -static void do_ps2esdi_request(struct request_queue * q); - -static void ps2esdi_readwrite(int cmd, struct request *req); - -static void ps2esdi_fill_cmd_block(u_short * cmd_blk, u_short cmd, -u_short cyl, u_short head, u_short sector, u_short length, u_char drive); - -static int ps2esdi_out_cmd_blk(u_short * cmd_blk); - -static void ps2esdi_prep_dma(char *buffer, u_short length, u_char dma_xmode); - -static irqreturn_t ps2esdi_interrupt_handler(int irq, void *dev_id); -static void (*current_int_handler) (u_int) = NULL; -static void ps2esdi_normal_interrupt_handler(u_int); -static void ps2esdi_initial_reset_int_handler(u_int); -static void ps2esdi_geometry_int_handler(u_int); -static int ps2esdi_getgeo(struct block_device *bdev, struct hd_geometry *geo); - -static int ps2esdi_read_status_words(int num_words, int max_words, u_short * buffer); - -static void dump_cmd_complete_status(u_int int_ret_code); - -static void ps2esdi_get_device_cfg(void); - -static void ps2esdi_reset_timer(unsigned long unused); - -static u_int dma_arb_level; /* DMA arbitration level */ - -static DECLARE_WAIT_QUEUE_HEAD(ps2esdi_int); - -static int no_int_yet; -static int ps2esdi_drives; -static u_short io_base; -static DEFINE_TIMER(esdi_timer, ps2esdi_reset_timer, 0, 0); -static int reset_status; -static int ps2esdi_slot = -1; -static int tp720esdi = 0; /* Is it Integrated ESDI of ThinkPad-720? */ -static int intg_esdi = 0; /* If integrated adapter */ -struct ps2esdi_i_struct { - unsigned int head, sect, cyl, wpcom, lzone, ctl; -}; -static DEFINE_SPINLOCK(ps2esdi_lock); -static struct request_queue *ps2esdi_queue; -static struct request *current_req; - -#if 0 -#if 0 /* try both - I don't know which one is better... UB */ -static struct ps2esdi_i_struct ps2esdi_info[MAX_HD] = -{ - {4, 48, 1553, 0, 0, 0}, - {0, 0, 0, 0, 0, 0}}; -#else -static struct ps2esdi_i_struct ps2esdi_info[MAX_HD] = -{ - {64, 32, 161, 0, 0, 0}, - {0, 0, 0, 0, 0, 0}}; -#endif -#endif -static struct ps2esdi_i_struct ps2esdi_info[MAX_HD] = -{ - {0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0}}; - -static struct block_device_operations ps2esdi_fops = -{ - .owner = THIS_MODULE, - .getgeo = ps2esdi_getgeo, -}; - -static struct gendisk *ps2esdi_gendisk[2]; - -/* initialization routine called by ll_rw_blk.c */ -static int __init ps2esdi_init(void) -{ - - int error = 0; - - /* register the device - pass the name and major number */ - if (register_blkdev(PS2ESDI_MAJOR, "ed")) - return -EBUSY; - - /* set up some global information - indicating device specific info */ - ps2esdi_queue = blk_init_queue(do_ps2esdi_request, &ps2esdi_lock); - if (!ps2esdi_queue) { - unregister_blkdev(PS2ESDI_MAJOR, "ed"); - return -ENOMEM; - } - - /* some minor housekeeping - setup the global gendisk structure */ - error = ps2esdi_geninit(); - if (error) { - printk(KERN_WARNING "PS2ESDI: error initialising" - " device, releasing resources\n"); - unregister_blkdev(PS2ESDI_MAJOR, "ed"); - blk_cleanup_queue(ps2esdi_queue); - return error; - } - return 0; -} /* ps2esdi_init */ - -#ifndef MODULE - -module_init(ps2esdi_init); - -#else - -static int cyl[MAX_HD] = {-1,-1}; -static int head[MAX_HD] = {-1, -1}; -static int sect[MAX_HD] = {-1, -1}; - -module_param(tp720esdi, bool, 0); -module_param_array(cyl, int, NULL, 0); -module_param_array(head, int, NULL, 0); -module_param_array(sect, int, NULL, 0); -MODULE_LICENSE("GPL"); - -int init_module(void) { - int drive; - - for(drive = 0; drive < MAX_HD; drive++) { - struct ps2esdi_i_struct *info = &ps2esdi_info[drive]; - - if (cyl[drive] != -1) { - info->cyl = info->lzone = cyl[drive]; - info->wpcom = 0; - } - if (head[drive] != -1) { - info->head = head[drive]; - info->ctl = (head[drive] > 8 ? 8 : 0); - } - if (sect[drive] != -1) info->sect = sect[drive]; - } - return ps2esdi_init(); -} - -void -cleanup_module(void) { - int i; - if(ps2esdi_slot) { - mca_mark_as_unused(ps2esdi_slot); - mca_set_adapter_procfn(ps2esdi_slot, NULL, NULL); - } - release_region(io_base, 4); - free_dma(dma_arb_level); - free_irq(PS2ESDI_IRQ, &ps2esdi_gendisk); - unregister_blkdev(PS2ESDI_MAJOR, "ed"); - blk_cleanup_queue(ps2esdi_queue); - for (i = 0; i < ps2esdi_drives; i++) { - del_gendisk(ps2esdi_gendisk[i]); - put_disk(ps2esdi_gendisk[i]); - } -} -#endif /* MODULE */ - -/* handles boot time command line parameters */ -void __init tp720_setup(char *str, int *ints) -{ - /* no params, just sets the tp720esdi flag if it exists */ - - printk("%s: TP 720 ESDI flag set\n", DEVICE_NAME); - tp720esdi = 1; -} - -void __init ed_setup(char *str, int *ints) -{ - int hdind = 0; - - /* handles 3 parameters only - corresponding to - 1. Number of cylinders - 2. Number of heads - 3. Sectors/track - */ - - if (ints[0] != 3) - return; - - /* print out the information - seen at boot time */ - printk("%s: ints[0]=%d ints[1]=%d ints[2]=%d ints[3]=%d\n", - DEVICE_NAME, ints[0], ints[1], ints[2], ints[3]); - - /* set the index into device specific information table */ - if (ps2esdi_info[0].head != 0) - hdind = 1; - - /* set up all the device information */ - ps2esdi_info[hdind].head = ints[2]; - ps2esdi_info[hdind].sect = ints[3]; - ps2esdi_info[hdind].cyl = ints[1]; - ps2esdi_info[hdind].wpcom = 0; - ps2esdi_info[hdind].lzone = ints[1]; - ps2esdi_info[hdind].ctl = (ints[2] > 8 ? 8 : 0); -#if 0 /* this may be needed for PS2/Mod.80, but it hurts ThinkPad! */ - ps2esdi_drives = hdind + 1; /* increment index for the next time */ -#endif -} /* ed_setup */ - -static int ps2esdi_getinfo(char *buf, int slot, void *d) -{ - int len = 0; - - len += sprintf(buf + len, "DMA Arbitration Level: %d\n", - dma_arb_level); - len += sprintf(buf + len, "IO Port: %x\n", io_base); - len += sprintf(buf + len, "IRQ: 14\n"); - len += sprintf(buf + len, "Drives: %d\n", ps2esdi_drives); - - return len; -} - -/* ps2 esdi specific initialization - called thru the gendisk chain */ -static int __init ps2esdi_geninit(void) -{ - /* - The first part contains the initialization code - for the ESDI disk subsystem. All we really do - is search for the POS registers of the controller - to do some simple setup operations. First, we - must ensure that the controller is installed, - enabled, and configured as PRIMARY. Then we must - determine the DMA arbitration level being used by - the controller so we can handle data transfer - operations properly. If all of this works, then - we will set the INIT_FLAG to a non-zero value. - */ - - int slot = 0, i, reset_start, reset_end; - u_char status; - unsigned short adapterID; - int error = 0; - - if ((slot = mca_find_adapter(INTG_ESDI_ID, 0)) != MCA_NOTFOUND) { - adapterID = INTG_ESDI_ID; - printk("%s: integrated ESDI adapter found in slot %d\n", - DEVICE_NAME, slot+1); -#ifndef MODULE - mca_set_adapter_name(slot, "PS/2 Integrated ESDI"); -#endif - } else if ((slot = mca_find_adapter(NRML_ESDI_ID, 0)) != -1) { - adapterID = NRML_ESDI_ID; - printk("%s: normal ESDI adapter found in slot %d\n", - DEVICE_NAME, slot+1); - mca_set_adapter_name(slot, "PS/2 ESDI"); - } else { - return -ENODEV; - } - - ps2esdi_slot = slot; - mca_mark_as_used(slot); - mca_set_adapter_procfn(slot, (MCA_ProcFn) ps2esdi_getinfo, NULL); - - /* Found the slot - read the POS register 2 to get the necessary - configuration and status information. POS register 2 has the - following information : - Bit Function - 7 reserved = 0 - 6 arbitration method - 0 - fairness enabled - 1 - fairness disabled, linear priority assignment - 5-2 arbitration level - 1 alternate address - 1 alternate address - 0 - use addresses 0x3510 - 0x3517 - 0 adapter enable - */ - - status = mca_read_stored_pos(slot, 2); - /* is it enabled ? */ - if (!(status & STATUS_ENABLED)) { - printk("%s: ESDI adapter disabled\n", DEVICE_NAME); - error = -ENODEV; - goto err_out1; - } - /* try to grab IRQ, and try to grab a slow IRQ if it fails, so we can - share with the SCSI driver */ - if (request_irq(PS2ESDI_IRQ, ps2esdi_interrupt_handler, - IRQF_DISABLED | IRQF_SHARED, "PS/2 ESDI", &ps2esdi_gendisk) - && request_irq(PS2ESDI_IRQ, ps2esdi_interrupt_handler, - IRQF_SHARED, "PS/2 ESDI", &ps2esdi_gendisk) - ) { - printk("%s: Unable to get IRQ %d\n", DEVICE_NAME, PS2ESDI_IRQ); - error = -EBUSY; - goto err_out1; - } - if (status & STATUS_ALTERNATE) - io_base = ALT_IO_BASE; - else - io_base = PRIMARY_IO_BASE; - - if (!request_region(io_base, 4, "ed")) { - printk(KERN_WARNING"Unable to request region 0x%x\n", io_base); - error = -EBUSY; - goto err_out2; - } - /* get the dma arbitration level */ - dma_arb_level = (status >> 2) & 0xf; - - /* BA */ - printk("%s: DMA arbitration level : %d\n", - DEVICE_NAME, dma_arb_level); - - LITE_ON; - current_int_handler = ps2esdi_initial_reset_int_handler; - reset_ctrl(); - reset_status = 0; - reset_start = jiffies; - while (!reset_status) { - init_timer(&esdi_timer); - esdi_timer.expires = jiffies + HZ; - esdi_timer.data = 0; - add_timer(&esdi_timer); - sleep_on(&ps2esdi_int); - } - reset_end = jiffies; - LITE_OFF; - printk("%s: reset interrupt after %d jiffies, %u.%02u secs\n", - DEVICE_NAME, reset_end - reset_start, (reset_end - reset_start) / HZ, - (reset_end - reset_start) % HZ); - - - /* Integrated ESDI Disk and Controller has only one drive! */ - if (adapterID == INTG_ESDI_ID) {/* if not "normal" PS2 ESDI adapter */ - ps2esdi_drives = 1; /* then we have only one physical disk! */ intg_esdi = 1; - } - - - - /* finally this part sets up some global data structures etc. */ - - ps2esdi_get_device_cfg(); - - /* some annoyance in the above routine returns TWO drives? - Is something else happining in the background? - Regaurdless we fix the # of drives again. AJK */ - /* Integrated ESDI Disk and Controller has only one drive! */ - if (adapterID == INTG_ESDI_ID) /* if not "normal" PS2 ESDI adapter */ - ps2esdi_drives = 1; /* Not three or two, ONE DAMNIT! */ - - current_int_handler = ps2esdi_normal_interrupt_handler; - - if (request_dma(dma_arb_level, "ed") !=0) { - printk(KERN_WARNING "PS2ESDI: Can't request dma-channel %d\n" - ,(int) dma_arb_level); - error = -EBUSY; - goto err_out3; - } - blk_queue_max_sectors(ps2esdi_queue, 128); - - error = -ENOMEM; - for (i = 0; i < ps2esdi_drives; i++) { - struct gendisk *disk = alloc_disk(64); - if (!disk) - goto err_out4; - disk->major = PS2ESDI_MAJOR; - disk->first_minor = i<<6; - sprintf(disk->disk_name, "ed%c", 'a'+i); - disk->fops = &ps2esdi_fops; - ps2esdi_gendisk[i] = disk; - } - - for (i = 0; i < ps2esdi_drives; i++) { - struct gendisk *disk = ps2esdi_gendisk[i]; - set_capacity(disk, ps2esdi_info[i].head * ps2esdi_info[i].sect * - ps2esdi_info[i].cyl); - disk->queue = ps2esdi_queue; - disk->private_data = &ps2esdi_info[i]; - add_disk(disk); - } - return 0; -err_out4: - while (i--) - put_disk(ps2esdi_gendisk[i]); -err_out3: - release_region(io_base, 4); -err_out2: - free_irq(PS2ESDI_IRQ, &ps2esdi_gendisk); -err_out1: - if(ps2esdi_slot) { - mca_mark_as_unused(ps2esdi_slot); - mca_set_adapter_procfn(ps2esdi_slot, NULL, NULL); - } - return error; -} - -static void __init ps2esdi_get_device_cfg(void) -{ - u_short cmd_blk[TYPE_0_CMD_BLK_LENGTH]; - - /*BA */ printk("%s: Drive 0\n", DEVICE_NAME); - current_int_handler = ps2esdi_geometry_int_handler; - cmd_blk[0] = CMD_GET_DEV_CONFIG | 0x600; - cmd_blk[1] = 0; - no_int_yet = TRUE; - ps2esdi_out_cmd_blk(cmd_blk); - if (no_int_yet) - sleep_on(&ps2esdi_int); - - if (ps2esdi_drives > 1) { - printk("%s: Drive 1\n", DEVICE_NAME); /*BA */ - cmd_blk[0] = CMD_GET_DEV_CONFIG | (1 << 5) | 0x600; - cmd_blk[1] = 0; - no_int_yet = TRUE; - ps2esdi_out_cmd_blk(cmd_blk); - if (no_int_yet) - sleep_on(&ps2esdi_int); - } /* if second physical drive is present */ - return; -} - -/* strategy routine that handles most of the IO requests */ -static void do_ps2esdi_request(struct request_queue * q) -{ - struct request *req; - /* since, this routine is called with interrupts cleared - they - must be before it finishes */ - - req = elv_next_request(q); - if (!req) - return; - -#if 0 - printk("%s:got request. device : %s command : %d sector : %ld count : %ld, buffer: %p\n", - DEVICE_NAME, - req->rq_disk->disk_name, - req->cmd, req->sector, - req->current_nr_sectors, req->buffer); -#endif - - /* check for above 16Mb dmas */ - if (isa_virt_to_bus(req->buffer + req->current_nr_sectors * 512) > 16 * MB) { - printk("%s: DMA above 16MB not supported\n", DEVICE_NAME); - end_request(req, FAIL); - return; - } - - if (req->sector+req->current_nr_sectors > get_capacity(req->rq_disk)) { - printk("Grrr. error. ps2esdi_drives: %d, %llu %llu\n", - ps2esdi_drives, req->sector, - (unsigned long long)get_capacity(req->rq_disk)); - end_request(req, FAIL); - return; - } - - switch (rq_data_dir(req)) { - case READ: - ps2esdi_readwrite(READ, req); - break; - case WRITE: - ps2esdi_readwrite(WRITE, req); - break; - default: - printk("%s: Unknown command\n", req->rq_disk->disk_name); - end_request(req, FAIL); - break; - } /* handle different commands */ -} /* main strategy routine */ - -/* resets the ESDI adapter */ -static void reset_ctrl(void) -{ - - u_long expire; - u_short status; - - /* enable interrupts on the controller */ - status = inb(ESDI_INTRPT); - outb((status & 0xe0) | ATT_EOI, ESDI_ATTN); /* to be sure we don't have - any interrupt pending... */ - outb_p(CTRL_ENABLE_INTR, ESDI_CONTROL); - - /* read the ESDI status port - if the controller is not busy, - simply do a soft reset (fast) - otherwise we'll have to do a - hard (slow) reset. */ - if (!(inb_p(ESDI_STATUS) & STATUS_BUSY)) { - /*BA */ printk("%s: soft reset...\n", DEVICE_NAME); - outb_p(CTRL_SOFT_RESET, ESDI_ATTN); - } - /* soft reset */ - else { - /*BA */ - printk("%s: hard reset...\n", DEVICE_NAME); - outb_p(CTRL_HARD_RESET, ESDI_CONTROL); - expire = jiffies + 2*HZ; - while (time_before(jiffies, expire)); - outb_p(1, ESDI_CONTROL); - } /* hard reset */ - - -} /* reset the controller */ - -/* called by the strategy routine to handle read and write requests */ -static void ps2esdi_readwrite(int cmd, struct request *req) -{ - struct ps2esdi_i_struct *p = req->rq_disk->private_data; - unsigned block = req->sector; - unsigned count = req->current_nr_sectors; - int drive = p - ps2esdi_info; - u_short track, head, cylinder, sector; - u_short cmd_blk[TYPE_1_CMD_BLK_LENGTH]; - - /* do some relevant arithmatic */ - track = block / p->sect; - head = track % p->head; - cylinder = track / p->head; - sector = block % p->sect; - -#if 0 - printk("%s: cyl=%d head=%d sect=%d\n", DEVICE_NAME, cylinder, head, sector); -#endif - /* call the routine that actually fills out a command block */ - ps2esdi_fill_cmd_block - (cmd_blk, - (cmd == READ) ? CMD_READ : CMD_WRITE, - cylinder, head, sector, count, drive); - - /* send the command block to the controller */ - current_req = req; - spin_unlock_irq(&ps2esdi_lock); - if (ps2esdi_out_cmd_blk(cmd_blk)) { - spin_lock_irq(&ps2esdi_lock); - printk("%s: Controller failed\n", DEVICE_NAME); - if ((++req->errors) >= MAX_RETRIES) - end_request(req, FAIL); - } - /* check for failure to put out the command block */ - else { - spin_lock_irq(&ps2esdi_lock); -#if 0 - printk("%s: waiting for xfer\n", DEVICE_NAME); -#endif - /* turn disk lights on */ - LITE_ON; - } - -} /* ps2esdi_readwrite */ - -/* fill out the command block */ -static void ps2esdi_fill_cmd_block(u_short * cmd_blk, u_short cmd, - u_short cyl, u_short head, u_short sector, u_short length, u_char drive) -{ - - cmd_blk[0] = (drive << 5) | cmd; - cmd_blk[1] = length; - cmd_blk[2] = ((cyl & 0x1f) << 11) | (head << 5) | sector; - cmd_blk[3] = (cyl & 0x3E0) >> 5; - -} /* fill out the command block */ - -/* write a command block to the controller */ -static int ps2esdi_out_cmd_blk(u_short * cmd_blk) -{ - - int i; - unsigned long jif; - u_char status; - - /* enable interrupts */ - outb(CTRL_ENABLE_INTR, ESDI_CONTROL); - - /* do not write to the controller, if it is busy */ - for (jif = jiffies + ESDI_STAT_TIMEOUT; - time_after(jif, jiffies) && - (inb(ESDI_STATUS) & STATUS_BUSY); ) - ; - -#if 0 - printk("%s: i(1)=%ld\n", DEVICE_NAME, jif); -#endif - - /* if device is still busy - then just time out */ - if (inb(ESDI_STATUS) & STATUS_BUSY) { - printk("%s: ps2esdi_out_cmd timed out (1)\n", DEVICE_NAME); - return ERROR; - } /* timeout ??? */ - /* Set up the attention register in the controller */ - outb(((*cmd_blk) & 0xE0) | 1, ESDI_ATTN); - -#if 0 - printk("%s: sending %d words to controller\n", DEVICE_NAME, (((*cmd_blk) >> 14) + 1) << 1); -#endif - - /* one by one send each word out */ - for (i = (((*cmd_blk) >> 14) + 1) << 1; i; i--) { - status = inb(ESDI_STATUS); - for (jif = jiffies + ESDI_STAT_TIMEOUT; - time_after(jif, jiffies) && (status & STATUS_BUSY) && - (status & STATUS_CMD_INF); status = inb(ESDI_STATUS)); - if ((status & (STATUS_BUSY | STATUS_CMD_INF)) == STATUS_BUSY) { -#if 0 - printk("%s: sending %04X\n", DEVICE_NAME, *cmd_blk); -#endif - outw(*cmd_blk++, ESDI_CMD_INT); - } else { - printk("%s: ps2esdi_out_cmd timed out while sending command (status=%02X)\n", - DEVICE_NAME, status); - return ERROR; - } - } /* send all words out */ - return OK; -} /* send out the commands */ - - -/* prepare for dma - do all the necessary setup */ -static void ps2esdi_prep_dma(char *buffer, u_short length, u_char dma_xmode) -{ - unsigned long flags = claim_dma_lock(); - - mca_disable_dma(dma_arb_level); - - mca_set_dma_addr(dma_arb_level, isa_virt_to_bus(buffer)); - - mca_set_dma_count(dma_arb_level, length * 512 / 2); - - mca_set_dma_mode(dma_arb_level, dma_xmode); - - mca_enable_dma(dma_arb_level); - - release_dma_lock(flags); - -} /* prepare for dma */ - - - -static irqreturn_t ps2esdi_interrupt_handler(int irq, void *dev_id) -{ - u_int int_ret_code; - - if (inb(ESDI_STATUS) & STATUS_INTR) { - int_ret_code = inb(ESDI_INTRPT); - if (current_int_handler) { - /* Disable adapter interrupts till processing is finished */ - outb(CTRL_DISABLE_INTR, ESDI_CONTROL); - current_int_handler(int_ret_code); - } else - printk("%s: help ! No interrupt handler.\n", DEVICE_NAME); - } else { - return IRQ_NONE; - } - return IRQ_HANDLED; -} - -static void ps2esdi_initial_reset_int_handler(u_int int_ret_code) -{ - - switch (int_ret_code & 0xf) { - case INT_RESET: - /*BA */ - printk("%s: initial reset completed.\n", DEVICE_NAME); - outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN); - wake_up(&ps2esdi_int); - break; - case INT_ATTN_ERROR: - printk("%s: Attention error. interrupt status : %02X\n", DEVICE_NAME, - int_ret_code); - printk("%s: status: %02x\n", DEVICE_NAME, inb(ESDI_STATUS)); - break; - default: - printk("%s: initial reset handler received interrupt: %02X\n", - DEVICE_NAME, int_ret_code); - outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN); - break; - } - outb(CTRL_ENABLE_INTR, ESDI_CONTROL); -} - - -static void ps2esdi_geometry_int_handler(u_int int_ret_code) -{ - u_int status, drive_num; - unsigned long rba; - int i; - - drive_num = int_ret_code >> 5; - switch (int_ret_code & 0xf) { - case INT_CMD_COMPLETE: - for (i = ESDI_TIMEOUT; i && !(inb(ESDI_STATUS) & STATUS_STAT_AVAIL); i--); - if (!(inb(ESDI_STATUS) & STATUS_STAT_AVAIL)) { - printk("%s: timeout reading status word\n", DEVICE_NAME); - outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN); - break; - } - status = inw(ESDI_STT_INT); - if ((status & 0x1F) == CMD_GET_DEV_CONFIG) { -#define REPLY_WORDS 5 /* we already read word 0 */ - u_short reply[REPLY_WORDS]; - - if (ps2esdi_read_status_words((status >> 8) - 1, REPLY_WORDS, reply)) { - /*BA */ - printk("%s: Device Configuration Status for drive %u\n", - DEVICE_NAME, drive_num); - - printk("%s: Spares/cyls: %u", DEVICE_NAME, reply[0] >> 8); - - printk - ("Config bits: %s%s%s%s%s\n", - (reply[0] & CONFIG_IS) ? "Invalid Secondary, " : "", - ((reply[0] & CONFIG_ZD) && !(reply[0] & CONFIG_IS)) - ? "Zero Defect, " : "Defects Present, ", - (reply[0] & CONFIG_SF) ? "Skewed Format, " : "", - (reply[0] & CONFIG_FR) ? "Removable, " : "Non-Removable, ", - (reply[0] & CONFIG_RT) ? "No Retries" : "Retries"); - - rba = reply[1] | ((unsigned long) reply[2] << 16); - printk("%s: Number of RBA's: %lu\n", DEVICE_NAME, rba); - - printk("%s: Physical number of cylinders: %u, Sectors/Track: %u, Heads: %u\n", - DEVICE_NAME, reply[3], reply[4] >> 8, reply[4] & 0xff); - - if (!ps2esdi_info[drive_num].head) { - ps2esdi_info[drive_num].head = 64; - ps2esdi_info[drive_num].sect = 32; - ps2esdi_info[drive_num].cyl = rba / (64 * 32); - ps2esdi_info[drive_num].wpcom = 0; - ps2esdi_info[drive_num].lzone = ps2esdi_info[drive_num].cyl; - ps2esdi_info[drive_num].ctl = 8; - if (tp720esdi) { /* store the retrieved parameters */ - ps2esdi_info[0].head = reply[4] & 0Xff; - ps2esdi_info[0].sect = reply[4] >> 8; - ps2esdi_info[0].cyl = reply[3]; - ps2esdi_info[0].wpcom = 0; - ps2esdi_info[0].lzone = reply[3]; - } else { - if (!intg_esdi) - ps2esdi_drives++; - } - } -#ifdef OBSOLETE - if (!ps2esdi_info[drive_num].head) { - ps2esdi_info[drive_num].head = reply[4] & 0Xff; - ps2esdi_info[drive_num].sect = reply[4] >> 8; - ps2esdi_info[drive_num].cyl = reply[3]; - ps2esdi_info[drive_num].wpcom = 0; - ps2esdi_info[drive_num].lzone = reply[3]; - if (tp720esdi) { /* store the retrieved parameters */ - ps2esdi_info[0].head = reply[4] & 0Xff; - ps2esdi_info[0].sect = reply[4] >> 8; - ps2esdi_info[0].cyl = reply[3]; - ps2esdi_info[0].wpcom = 0; - ps2esdi_info[0].lzone = reply[3]; - } else { - ps2esdi_drives++; - } - } -#endif - - } else - printk("%s: failed while getting device config\n", DEVICE_NAME); -#undef REPLY_WORDS - } else - printk("%s: command %02X unknown by geometry handler\n", - DEVICE_NAME, status & 0x1f); - - outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN); - break; - - case INT_ATTN_ERROR: - printk("%s: Attention error. interrupt status : %02X\n", DEVICE_NAME, - int_ret_code); - printk("%s: Device not available\n", DEVICE_NAME); - break; - case INT_CMD_ECC: - case INT_CMD_RETRY: - case INT_CMD_ECC_RETRY: - case INT_CMD_WARNING: - case INT_CMD_ABORT: - case INT_CMD_FAILED: - case INT_DMA_ERR: - case INT_CMD_BLK_ERR: - /*BA */ printk("%s: Whaa. Error occurred...\n", DEVICE_NAME); - dump_cmd_complete_status(int_ret_code); - outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN); - break; - default: - printk("%s: Unknown interrupt reason: %02X\n", - DEVICE_NAME, int_ret_code & 0xf); - outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN); - break; - } - - wake_up(&ps2esdi_int); - no_int_yet = FALSE; - outb(CTRL_ENABLE_INTR, ESDI_CONTROL); - -} - -static void ps2esdi_normal_interrupt_handler(u_int int_ret_code) -{ - unsigned long flags; - u_int status; - u_int ending; - int i; - - switch (int_ret_code & 0x0f) { - case INT_TRANSFER_REQ: - ps2esdi_prep_dma(current_req->buffer, - current_req->current_nr_sectors, - (rq_data_dir(current_req) == READ) - ? MCA_DMA_MODE_16 | MCA_DMA_MODE_WRITE | MCA_DMA_MODE_XFER - : MCA_DMA_MODE_16 | MCA_DMA_MODE_READ); - outb(CTRL_ENABLE_DMA | CTRL_ENABLE_INTR, ESDI_CONTROL); - ending = -1; - break; - - case INT_ATTN_ERROR: - printk("%s: Attention error. interrupt status : %02X\n", DEVICE_NAME, - int_ret_code); - outb(CTRL_ENABLE_INTR, ESDI_CONTROL); - ending = FAIL; - break; - - case INT_CMD_COMPLETE: - for (i = ESDI_TIMEOUT; i && !(inb(ESDI_STATUS) & STATUS_STAT_AVAIL); i--); - if (!(inb(ESDI_STATUS) & STATUS_STAT_AVAIL)) { - printk("%s: timeout reading status word\n", DEVICE_NAME); - outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN); - outb(CTRL_ENABLE_INTR, ESDI_CONTROL); - if ((++current_req->errors) >= MAX_RETRIES) - ending = FAIL; - else - ending = -1; - break; - } - status = inw(ESDI_STT_INT); - switch (status & 0x1F) { - case (CMD_READ & 0xff): - case (CMD_WRITE & 0xff): - LITE_OFF; - outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN); - outb(CTRL_ENABLE_INTR, ESDI_CONTROL); - ending = SUCCES; - break; - default: - printk("%s: interrupt for unknown command %02X\n", - DEVICE_NAME, status & 0x1f); - outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN); - outb(CTRL_ENABLE_INTR, ESDI_CONTROL); - ending = -1; - break; - } - break; - case INT_CMD_ECC: - case INT_CMD_RETRY: - case INT_CMD_ECC_RETRY: - LITE_OFF; - dump_cmd_complete_status(int_ret_code); - outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN); - outb(CTRL_ENABLE_INTR, ESDI_CONTROL); - ending = SUCCES; - break; - case INT_CMD_WARNING: - case INT_CMD_ABORT: - case INT_CMD_FAILED: - case INT_DMA_ERR: - LITE_OFF; - dump_cmd_complete_status(int_ret_code); - outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN); - outb(CTRL_ENABLE_INTR, ESDI_CONTROL); - if ((++current_req->errors) >= MAX_RETRIES) - ending = FAIL; - else - ending = -1; - break; - - case INT_CMD_BLK_ERR: - dump_cmd_complete_status(int_ret_code); - outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN); - outb(CTRL_ENABLE_INTR, ESDI_CONTROL); - ending = FAIL; - break; - - case INT_CMD_FORMAT: - printk("%s: huh ? Who issued this format command ?\n" - ,DEVICE_NAME); - outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN); - outb(CTRL_ENABLE_INTR, ESDI_CONTROL); - ending = -1; - break; - - case INT_RESET: - /* BA printk("%s: reset completed.\n", DEVICE_NAME) */ ; - outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN); - outb(CTRL_ENABLE_INTR, ESDI_CONTROL); - ending = -1; - break; - - default: - printk("%s: Unknown interrupt reason: %02X\n", - DEVICE_NAME, int_ret_code & 0xf); - outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN); - outb(CTRL_ENABLE_INTR, ESDI_CONTROL); - ending = -1; - break; - } - if(ending != -1) { - spin_lock_irqsave(&ps2esdi_lock, flags); - end_request(current_req, ending); - current_req = NULL; - do_ps2esdi_request(ps2esdi_queue); - spin_unlock_irqrestore(&ps2esdi_lock, flags); - } -} /* handle interrupts */ - - - -static int ps2esdi_read_status_words(int num_words, - int max_words, - u_short * buffer) -{ - int i; - - for (; max_words && num_words; max_words--, num_words--, buffer++) { - for (i = ESDI_TIMEOUT; i && !(inb(ESDI_STATUS) & STATUS_STAT_AVAIL); i--); - if (!(inb(ESDI_STATUS) & STATUS_STAT_AVAIL)) { - printk("%s: timeout reading status word\n", DEVICE_NAME); - return FAIL; - } - *buffer = inw(ESDI_STT_INT); - } - return SUCCES; -} - - - - -static void dump_cmd_complete_status(u_int int_ret_code) -{ -#define WAIT_FOR_STATUS \ - for(i=ESDI_TIMEOUT;i && !(inb(ESDI_STATUS) & STATUS_STAT_AVAIL);i--); \ - if(!(inb(ESDI_STATUS) & STATUS_STAT_AVAIL)) { \ - printk("%s: timeout reading status word\n",DEVICE_NAME); \ - return; \ - } - - int i, word_count; - u_short stat_word; - u_long rba; - - printk("%s: Device: %u, interrupt ID: %02X\n", - DEVICE_NAME, int_ret_code >> 5, - int_ret_code & 0xf); - - WAIT_FOR_STATUS; - stat_word = inw(ESDI_STT_INT); - word_count = (stat_word >> 8) - 1; - printk("%s: %u status words, command: %02X\n", DEVICE_NAME, word_count, - stat_word & 0xff); - - if (word_count--) { - WAIT_FOR_STATUS; - stat_word = inw(ESDI_STT_INT); - printk("%s: command status code: %02X, command error code: %02X\n", - DEVICE_NAME, stat_word >> 8, stat_word & 0xff); - } - if (word_count--) { - WAIT_FOR_STATUS; - stat_word = inw(ESDI_STT_INT); - printk("%s: device error code: %s%s%s%s%s,%02X\n", DEVICE_NAME, - (stat_word & 0x1000) ? "Ready, " : "Not Ready, ", - (stat_word & 0x0800) ? "Selected, " : "Not Selected, ", - (stat_word & 0x0400) ? "Write Fault, " : "", - (stat_word & 0x0200) ? "Track 0, " : "", - (stat_word & 0x0100) ? "Seek or command complete, " : "", - stat_word >> 8); - } - if (word_count--) { - WAIT_FOR_STATUS; - stat_word = inw(ESDI_STT_INT); - printk("%s: Blocks to do: %u", DEVICE_NAME, stat_word); - } - if (word_count -= 2) { - WAIT_FOR_STATUS; - rba = inw(ESDI_STT_INT); - WAIT_FOR_STATUS; - rba |= inw(ESDI_STT_INT) << 16; - printk(", Last Cyl: %u Head: %u Sector: %u\n", - (u_short) ((rba & 0x1ff80000) >> 11), - (u_short) ((rba & 0x7E0) >> 5), (u_short) (rba & 0x1f)); - } else - printk("\n"); - - if (word_count--) { - WAIT_FOR_STATUS; - stat_word = inw(ESDI_STT_INT); - printk("%s: Blocks required ECC: %u", DEVICE_NAME, stat_word); - } - printk("\n"); - -#undef WAIT_FOR_STATUS - -} - -static int ps2esdi_getgeo(struct block_device *bdev, struct hd_geometry *geo) -{ - struct ps2esdi_i_struct *p = bdev->bd_disk->private_data; - - geo->heads = p->head; - geo->sectors = p->sect; - geo->cylinders = p->cyl; - return 0; -} - -static void ps2esdi_reset_timer(unsigned long unused) -{ - - int status; - - status = inb(ESDI_INTRPT); - if ((status & 0xf) == INT_RESET) { - outb((status & 0xe0) | ATT_EOI, ESDI_ATTN); - outb(CTRL_ENABLE_INTR, ESDI_CONTROL); - reset_status = 1; - } - wake_up(&ps2esdi_int); -} diff --git a/drivers/block/viodasd.c b/drivers/block/viodasd.c index 9e61fca46117..41ca721d2523 100644 --- a/drivers/block/viodasd.c +++ b/drivers/block/viodasd.c @@ -528,8 +528,7 @@ static int block_event_to_scatterlist(const struct vioblocklpevent *bevent, numsg = VIOMAXBLOCKDMA; *total_len = 0; - memset(sg, 0, sizeof(sg[0]) * VIOMAXBLOCKDMA); - + sg_init_table(sg, VIOMAXBLOCKDMA); for (i = 0; (i < numsg) && (rw_data->dma_info[i].len > 0); ++i) { sg_dma_address(&sg[i]) = rw_data->dma_info[i].token; sg_dma_len(&sg[i]) = rw_data->dma_info[i].len; diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index 3b1a68d6eddb..0cfbe8c594a5 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c @@ -238,6 +238,7 @@ static int virtblk_probe(struct virtio_device *vdev) vblk->disk->first_minor = index_to_minor(index); vblk->disk->private_data = vblk; vblk->disk->fops = &virtblk_fops; + vblk->disk->driverfs_dev = &vdev->dev; index++; /* If barriers are supported, tell block layer that queue is ordered */ diff --git a/drivers/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c index f16c94cbf488..8b884f87d8b7 100644 --- a/drivers/bluetooth/hci_usb.c +++ b/drivers/bluetooth/hci_usb.c @@ -149,6 +149,9 @@ static struct usb_device_id blacklist_ids[] = { { USB_DEVICE(0x0400, 0x0807), .driver_info = HCI_BROKEN_ISOC }, { USB_DEVICE(0x0400, 0x080a), .driver_info = HCI_BROKEN_ISOC }, + /* CONWISE Technology based adapters with buggy SCO support */ + { USB_DEVICE(0x0e5e, 0x6622), .driver_info = HCI_BROKEN_ISOC }, + /* Belkin F8T012 and F8T013 devices */ { USB_DEVICE(0x050d, 0x0012), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU }, { USB_DEVICE(0x050d, 0x0013), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU }, diff --git a/drivers/char/drm/ati_pcigart.c b/drivers/char/drm/ati_pcigart.c index d352dbb4ccf7..e5a0e97cfdda 100644 --- a/drivers/char/drm/ati_pcigart.c +++ b/drivers/char/drm/ati_pcigart.c @@ -35,42 +35,23 @@ # define ATI_PCIGART_PAGE_SIZE 4096 /**< PCI GART page size */ -static void *drm_ati_alloc_pcigart_table(int order) +static int drm_ati_alloc_pcigart_table(struct drm_device *dev, + struct drm_ati_pcigart_info *gart_info) { - unsigned long address; - struct page *page; - int i; - - DRM_DEBUG("%d order\n", order); - - address = __get_free_pages(GFP_KERNEL | __GFP_COMP, - order); - if (address == 0UL) { - return NULL; - } - - page = virt_to_page(address); + gart_info->table_handle = drm_pci_alloc(dev, gart_info->table_size, + PAGE_SIZE, + gart_info->table_mask); + if (gart_info->table_handle == NULL) + return -ENOMEM; - for (i = 0; i < order; i++, page++) - SetPageReserved(page); - - DRM_DEBUG("returning 0x%08lx\n", address); - return (void *)address; + return 0; } -static void drm_ati_free_pcigart_table(void *address, int order) +static void drm_ati_free_pcigart_table(struct drm_device *dev, + struct drm_ati_pcigart_info *gart_info) { - struct page *page; - int i; - int num_pages = 1 << order; - DRM_DEBUG("\n"); - - page = virt_to_page((unsigned long)address); - - for (i = 0; i < num_pages; i++, page++) - ClearPageReserved(page); - - free_pages((unsigned long)address, order); + drm_pci_free(dev, gart_info->table_handle); + gart_info->table_handle = NULL; } int drm_ati_pcigart_cleanup(struct drm_device *dev, struct drm_ati_pcigart_info *gart_info) @@ -78,8 +59,7 @@ int drm_ati_pcigart_cleanup(struct drm_device *dev, struct drm_ati_pcigart_info struct drm_sg_mem *entry = dev->sg; unsigned long pages; int i; - int order; - int num_pages, max_pages; + int max_pages; /* we need to support large memory configurations */ if (!entry) { @@ -87,15 +67,7 @@ int drm_ati_pcigart_cleanup(struct drm_device *dev, struct drm_ati_pcigart_info return 0; } - order = drm_order((gart_info->table_size + (PAGE_SIZE-1)) / PAGE_SIZE); - num_pages = 1 << order; - if (gart_info->bus_addr) { - if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) { - pci_unmap_single(dev->pdev, gart_info->bus_addr, - num_pages * PAGE_SIZE, - PCI_DMA_TODEVICE); - } max_pages = (gart_info->table_size / sizeof(u32)); pages = (entry->pages <= max_pages) @@ -112,10 +84,9 @@ int drm_ati_pcigart_cleanup(struct drm_device *dev, struct drm_ati_pcigart_info gart_info->bus_addr = 0; } - if (gart_info->gart_table_location == DRM_ATI_GART_MAIN - && gart_info->addr) { - drm_ati_free_pcigart_table(gart_info->addr, order); - gart_info->addr = NULL; + if (gart_info->gart_table_location == DRM_ATI_GART_MAIN && + gart_info->table_handle) { + drm_ati_free_pcigart_table(dev, gart_info); } return 1; @@ -127,11 +98,10 @@ int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *ga struct drm_sg_mem *entry = dev->sg; void *address = NULL; unsigned long pages; - u32 *pci_gart, page_base, bus_address = 0; + u32 *pci_gart, page_base; + dma_addr_t bus_address = 0; int i, j, ret = 0; - int order; int max_pages; - int num_pages; if (!entry) { DRM_ERROR("no scatter/gather memory!\n"); @@ -141,31 +111,14 @@ int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *ga if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) { DRM_DEBUG("PCI: no table in VRAM: using normal RAM\n"); - order = drm_order((gart_info->table_size + - (PAGE_SIZE-1)) / PAGE_SIZE); - num_pages = 1 << order; - address = drm_ati_alloc_pcigart_table(order); - if (!address) { + ret = drm_ati_alloc_pcigart_table(dev, gart_info); + if (ret) { DRM_ERROR("cannot allocate PCI GART page!\n"); goto done; } - if (!dev->pdev) { - DRM_ERROR("PCI device unknown!\n"); - goto done; - } - - bus_address = pci_map_single(dev->pdev, address, - num_pages * PAGE_SIZE, - PCI_DMA_TODEVICE); - if (bus_address == 0) { - DRM_ERROR("unable to map PCIGART pages!\n"); - order = drm_order((gart_info->table_size + - (PAGE_SIZE-1)) / PAGE_SIZE); - drm_ati_free_pcigart_table(address, order); - address = NULL; - goto done; - } + address = gart_info->table_handle->vaddr; + bus_address = gart_info->table_handle->busaddr; } else { address = gart_info->addr; bus_address = gart_info->bus_addr; diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h index a6789f25009b..8ea9dd1717a9 100644 --- a/drivers/char/drm/drmP.h +++ b/drivers/char/drm/drmP.h @@ -54,6 +54,7 @@ #include <linux/pci.h> #include <linux/jiffies.h> #include <linux/smp_lock.h> /* For (un)lock_kernel */ +#include <linux/dma-mapping.h> #include <linux/mm.h> #include <linux/cdev.h> #include <linux/mutex.h> @@ -551,6 +552,8 @@ struct drm_ati_pcigart_info { int gart_reg_if; void *addr; dma_addr_t bus_addr; + dma_addr_t table_mask; + struct drm_dma_handle *table_handle; drm_local_map_t mapping; int table_size; }; diff --git a/drivers/char/drm/drm_fops.c b/drivers/char/drm/drm_fops.c index 3992f73299cc..f09d4b5002b0 100644 --- a/drivers/char/drm/drm_fops.c +++ b/drivers/char/drm/drm_fops.c @@ -326,6 +326,7 @@ int drm_release(struct inode *inode, struct file *filp) struct drm_file *file_priv = filp->private_data; struct drm_device *dev = file_priv->head->dev; int retcode = 0; + unsigned long irqflags; lock_kernel(); @@ -357,9 +358,11 @@ int drm_release(struct inode *inode, struct file *filp) */ do{ - spin_lock(&dev->lock.spinlock); + spin_lock_irqsave(&dev->lock.spinlock, + irqflags); locked = dev->lock.idle_has_lock; - spin_unlock(&dev->lock.spinlock); + spin_unlock_irqrestore(&dev->lock.spinlock, + irqflags); if (locked) break; schedule(); diff --git a/drivers/char/drm/drm_lock.c b/drivers/char/drm/drm_lock.c index bea2a7d5b2b2..12dcdd1832f0 100644 --- a/drivers/char/drm/drm_lock.c +++ b/drivers/char/drm/drm_lock.c @@ -53,6 +53,7 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv) DECLARE_WAITQUEUE(entry, current); struct drm_lock *lock = data; int ret = 0; + unsigned long irqflags; ++file_priv->lock_count; @@ -71,9 +72,9 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv) return -EINVAL; add_wait_queue(&dev->lock.lock_queue, &entry); - spin_lock(&dev->lock.spinlock); + spin_lock_irqsave(&dev->lock.spinlock, irqflags); dev->lock.user_waiters++; - spin_unlock(&dev->lock.spinlock); + spin_unlock_irqrestore(&dev->lock.spinlock, irqflags); for (;;) { __set_current_state(TASK_INTERRUPTIBLE); if (!dev->lock.hw_lock) { @@ -95,9 +96,9 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv) break; } } - spin_lock(&dev->lock.spinlock); + spin_lock_irqsave(&dev->lock.spinlock, irqflags); dev->lock.user_waiters--; - spin_unlock(&dev->lock.spinlock); + spin_unlock_irqrestore(&dev->lock.spinlock, irqflags); __set_current_state(TASK_RUNNING); remove_wait_queue(&dev->lock.lock_queue, &entry); @@ -198,8 +199,9 @@ int drm_lock_take(struct drm_lock_data *lock_data, { unsigned int old, new, prev; volatile unsigned int *lock = &lock_data->hw_lock->lock; + unsigned long irqflags; - spin_lock(&lock_data->spinlock); + spin_lock_irqsave(&lock_data->spinlock, irqflags); do { old = *lock; if (old & _DRM_LOCK_HELD) @@ -211,7 +213,7 @@ int drm_lock_take(struct drm_lock_data *lock_data, } prev = cmpxchg(lock, old, new); } while (prev != old); - spin_unlock(&lock_data->spinlock); + spin_unlock_irqrestore(&lock_data->spinlock, irqflags); if (_DRM_LOCKING_CONTEXT(old) == context) { if (old & _DRM_LOCK_HELD) { @@ -272,15 +274,16 @@ int drm_lock_free(struct drm_lock_data *lock_data, unsigned int context) { unsigned int old, new, prev; volatile unsigned int *lock = &lock_data->hw_lock->lock; + unsigned long irqflags; - spin_lock(&lock_data->spinlock); + spin_lock_irqsave(&lock_data->spinlock, irqflags); if (lock_data->kernel_waiters != 0) { drm_lock_transfer(lock_data, 0); lock_data->idle_has_lock = 1; - spin_unlock(&lock_data->spinlock); + spin_unlock_irqrestore(&lock_data->spinlock, irqflags); return 1; } - spin_unlock(&lock_data->spinlock); + spin_unlock_irqrestore(&lock_data->spinlock, irqflags); do { old = *lock; @@ -344,19 +347,20 @@ static int drm_notifier(void *priv) void drm_idlelock_take(struct drm_lock_data *lock_data) { int ret = 0; + unsigned long irqflags; - spin_lock(&lock_data->spinlock); + spin_lock_irqsave(&lock_data->spinlock, irqflags); lock_data->kernel_waiters++; if (!lock_data->idle_has_lock) { - spin_unlock(&lock_data->spinlock); + spin_unlock_irqrestore(&lock_data->spinlock, irqflags); ret = drm_lock_take(lock_data, DRM_KERNEL_CONTEXT); - spin_lock(&lock_data->spinlock); + spin_lock_irqsave(&lock_data->spinlock, irqflags); if (ret == 1) lock_data->idle_has_lock = 1; } - spin_unlock(&lock_data->spinlock); + spin_unlock_irqrestore(&lock_data->spinlock, irqflags); } EXPORT_SYMBOL(drm_idlelock_take); @@ -364,8 +368,9 @@ void drm_idlelock_release(struct drm_lock_data *lock_data) { unsigned int old, prev; volatile unsigned int *lock = &lock_data->hw_lock->lock; + unsigned long irqflags; - spin_lock(&lock_data->spinlock); + spin_lock_irqsave(&lock_data->spinlock, irqflags); if (--lock_data->kernel_waiters == 0) { if (lock_data->idle_has_lock) { do { @@ -376,7 +381,7 @@ void drm_idlelock_release(struct drm_lock_data *lock_data) lock_data->idle_has_lock = 0; } } - spin_unlock(&lock_data->spinlock); + spin_unlock_irqrestore(&lock_data->spinlock, irqflags); } EXPORT_SYMBOL(drm_idlelock_release); diff --git a/drivers/char/drm/drm_pciids.h b/drivers/char/drm/drm_pciids.h index 715b361f0c2b..a6a499f97e22 100644 --- a/drivers/char/drm/drm_pciids.h +++ b/drivers/char/drm/drm_pciids.h @@ -205,9 +205,9 @@ {0x1002, 0x71D6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x71DA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_NEW_MEMMAP}, \ {0x1002, 0x71DE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ - {0x1002, 0x7200, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_NEW_MEMMAP}, \ - {0x1002, 0x7210, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ - {0x1002, 0x7211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x7200, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x7210, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x7211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x7240, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \ {0x1002, 0x7243, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \ {0x1002, 0x7244, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \ @@ -238,6 +238,7 @@ {0x1002, 0x7834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP|RADEON_NEW_MEMMAP}, \ {0x1002, 0x7835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x791e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS690|RADEON_IS_IGP|RADEON_NEW_MEMMAP|RADEON_IS_IGPGART}, \ + {0x1002, 0x791f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS690|RADEON_IS_IGP|RADEON_NEW_MEMMAP|RADEON_IS_IGPGART}, \ {0, 0, 0} #define r128_PCI_IDS \ diff --git a/drivers/char/drm/r128_cce.c b/drivers/char/drm/r128_cce.c index 892e0a589846..f36adbd3aaf5 100644 --- a/drivers/char/drm/r128_cce.c +++ b/drivers/char/drm/r128_cce.c @@ -558,6 +558,7 @@ static int r128_do_init_cce(struct drm_device * dev, drm_r128_init_t * init) #if __OS_HAS_AGP if (dev_priv->is_pci) { #endif + dev_priv->gart_info.table_mask = DMA_BIT_MASK(32); dev_priv->gart_info.gart_table_location = DRM_ATI_GART_MAIN; dev_priv->gart_info.table_size = R128_PCIGART_TABLE_SIZE; dev_priv->gart_info.addr = NULL; diff --git a/drivers/char/drm/radeon_cp.c b/drivers/char/drm/radeon_cp.c index 833abc7e55fb..9072e4a1894e 100644 --- a/drivers/char/drm/radeon_cp.c +++ b/drivers/char/drm/radeon_cp.c @@ -1807,6 +1807,7 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init) } else #endif { + dev_priv->gart_info.table_mask = DMA_BIT_MASK(32); /* if we have an offset set from userspace */ if (dev_priv->pcigart_offset_set) { dev_priv->gart_info.bus_addr = diff --git a/drivers/char/drm/via_dma.c b/drivers/char/drm/via_dma.c index 94baec692b57..7a339dba6a69 100644 --- a/drivers/char/drm/via_dma.c +++ b/drivers/char/drm/via_dma.c @@ -126,6 +126,8 @@ via_cmdbuf_wait(drm_via_private_t * dev_priv, unsigned int size) hw_addr, cur_addr, next_addr); return -1; } + if ((cur_addr < hw_addr) && (next_addr >= hw_addr)) + msleep(1); } while ((cur_addr < hw_addr) && (next_addr >= hw_addr)); return 0; } @@ -416,27 +418,50 @@ static int via_hook_segment(drm_via_private_t * dev_priv, int paused, count; volatile uint32_t *paused_at = dev_priv->last_pause_ptr; uint32_t reader,ptr; + uint32_t diff; paused = 0; via_flush_write_combine(); (void) *(volatile uint32_t *)(via_get_dma(dev_priv) -1); + *paused_at = pause_addr_lo; via_flush_write_combine(); (void) *paused_at; + reader = *(dev_priv->hw_addr_ptr); ptr = ((volatile char *)paused_at - dev_priv->dma_ptr) + dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr + 4; + dev_priv->last_pause_ptr = via_get_dma(dev_priv) - 1; - if ((ptr - reader) <= dev_priv->dma_diff ) { - count = 10000000; - while (!(paused = (VIA_READ(0x41c) & 0x80000000)) && count--); + /* + * If there is a possibility that the command reader will + * miss the new pause address and pause on the old one, + * In that case we need to program the new start address + * using PCI. + */ + + diff = (uint32_t) (ptr - reader) - dev_priv->dma_diff; + count = 10000000; + while(diff == 0 && count--) { + paused = (VIA_READ(0x41c) & 0x80000000); + if (paused) + break; + reader = *(dev_priv->hw_addr_ptr); + diff = (uint32_t) (ptr - reader) - dev_priv->dma_diff; } + paused = VIA_READ(0x41c) & 0x80000000; + if (paused && !no_pci_fire) { reader = *(dev_priv->hw_addr_ptr); - if ((ptr - reader) == dev_priv->dma_diff) { - + diff = (uint32_t) (ptr - reader) - dev_priv->dma_diff; + diff &= (dev_priv->dma_high - 1); + if (diff != 0 && diff < (dev_priv->dma_high >> 1)) { + DRM_ERROR("Paused at incorrect address. " + "0x%08x, 0x%08x 0x%08x\n", + ptr, reader, dev_priv->dma_diff); + } else if (diff == 0) { /* * There is a concern that these writes may stall the PCI bus * if the GPU is not idle. However, idling the GPU first @@ -577,6 +602,7 @@ static void via_cmdbuf_jump(drm_via_private_t * dev_priv) uint32_t pause_addr_lo, pause_addr_hi; uint32_t jump_addr_lo, jump_addr_hi; volatile uint32_t *last_pause_ptr; + uint32_t dma_low_save1, dma_low_save2; agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr; via_align_cmd(dev_priv, HC_HAGPBpID_JUMP, 0, &jump_addr_hi, @@ -603,8 +629,29 @@ static void via_cmdbuf_jump(drm_via_private_t * dev_priv) &pause_addr_lo, 0); *last_pause_ptr = pause_addr_lo; + dma_low_save1 = dev_priv->dma_low; - via_hook_segment( dev_priv, jump_addr_hi, jump_addr_lo, 0); + /* + * Now, set a trap that will pause the regulator if it tries to rerun the old + * command buffer. (Which may happen if via_hook_segment detecs a command regulator pause + * and reissues the jump command over PCI, while the regulator has already taken the jump + * and actually paused at the current buffer end). + * There appears to be no other way to detect this condition, since the hw_addr_pointer + * does not seem to get updated immediately when a jump occurs. + */ + + last_pause_ptr = + via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi, + &pause_addr_lo, 0) - 1; + via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi, + &pause_addr_lo, 0); + *last_pause_ptr = pause_addr_lo; + + dma_low_save2 = dev_priv->dma_low; + dev_priv->dma_low = dma_low_save1; + via_hook_segment(dev_priv, jump_addr_hi, jump_addr_lo, 0); + dev_priv->dma_low = dma_low_save2; + via_hook_segment(dev_priv, pause_addr_hi, pause_addr_lo, 0); } diff --git a/drivers/char/drm/via_dmablit.c b/drivers/char/drm/via_dmablit.c index 33c5197b73c4..409e00afdd07 100644 --- a/drivers/char/drm/via_dmablit.c +++ b/drivers/char/drm/via_dmablit.c @@ -603,7 +603,7 @@ via_build_sg_info(struct drm_device *dev, drm_via_sg_info_t *vsg, drm_via_dmabli * (Not a big limitation anyway.) */ - if ((xfer->mem_stride - xfer->line_length) >= PAGE_SIZE) { + if ((xfer->mem_stride - xfer->line_length) > 2*PAGE_SIZE) { DRM_ERROR("Too large system memory stride. Stride: %d, " "Length: %d\n", xfer->mem_stride, xfer->line_length); return -EINVAL; diff --git a/drivers/char/nozomi.c b/drivers/char/nozomi.c index dfaab2322de3..6d0dc5f9b6bb 100644 --- a/drivers/char/nozomi.c +++ b/drivers/char/nozomi.c @@ -190,6 +190,14 @@ enum card_type { F32_8 = 8192, /* 3072 bytes downl. + 1024 bytes uplink * 2 -> 8192 */ }; +/* Initialization states a card can be in */ +enum card_state { + NOZOMI_STATE_UKNOWN = 0, + NOZOMI_STATE_ENABLED = 1, /* pci device enabled */ + NOZOMI_STATE_ALLOCATED = 2, /* config setup done */ + NOZOMI_STATE_READY = 3, /* flowcontrols received */ +}; + /* Two different toggle channels exist */ enum channel_type { CH_A = 0, @@ -385,6 +393,7 @@ struct nozomi { spinlock_t spin_mutex; /* secures access to registers and tty */ unsigned int index_start; + enum card_state state; u32 open_ttys; }; @@ -686,6 +695,7 @@ static int nozomi_read_config_table(struct nozomi *dc) dc->last_ier = dc->last_ier | CTRL_DL; writew(dc->last_ier, dc->reg_ier); + dc->state = NOZOMI_STATE_ALLOCATED; dev_info(&dc->pdev->dev, "Initialization OK!\n"); return 1; } @@ -944,6 +954,14 @@ static int receive_flow_control(struct nozomi *dc) case CTRL_APP2: port = PORT_APP2; enable_ier = APP2_DL; + if (dc->state == NOZOMI_STATE_ALLOCATED) { + /* + * After card initialization the flow control + * received for APP2 is always the last + */ + dc->state = NOZOMI_STATE_READY; + dev_info(&dc->pdev->dev, "Device READY!\n"); + } break; default: dev_err(&dc->pdev->dev, @@ -1366,22 +1384,12 @@ static int __devinit nozomi_card_init(struct pci_dev *pdev, dc->pdev = pdev; - /* Find out what card type it is */ - nozomi_get_card_type(dc); - ret = pci_enable_device(dc->pdev); if (ret) { dev_err(&pdev->dev, "Failed to enable PCI Device\n"); goto err_free; } - start = pci_resource_start(dc->pdev, 0); - if (start == 0) { - dev_err(&pdev->dev, "No I/O address for card detected\n"); - ret = -ENODEV; - goto err_disable_device; - } - ret = pci_request_regions(dc->pdev, NOZOMI_NAME); if (ret) { dev_err(&pdev->dev, "I/O address 0x%04x already in use\n", @@ -1389,6 +1397,16 @@ static int __devinit nozomi_card_init(struct pci_dev *pdev, goto err_disable_device; } + start = pci_resource_start(dc->pdev, 0); + if (start == 0) { + dev_err(&pdev->dev, "No I/O address for card detected\n"); + ret = -ENODEV; + goto err_rel_regs; + } + + /* Find out what card type it is */ + nozomi_get_card_type(dc); + dc->base_addr = ioremap(start, dc->card_type); if (!dc->base_addr) { dev_err(&pdev->dev, "Unable to map card MMIO\n"); @@ -1425,6 +1443,14 @@ static int __devinit nozomi_card_init(struct pci_dev *pdev, dc->index_start = ndev_idx * MAX_PORT; ndevs[ndev_idx] = dc; + pci_set_drvdata(pdev, dc); + + /* Enable RESET interrupt */ + dc->last_ier = RESET; + iowrite16(dc->last_ier, dc->reg_ier); + + dc->state = NOZOMI_STATE_ENABLED; + for (i = 0; i < MAX_PORT; i++) { mutex_init(&dc->port[i].tty_sem); dc->port[i].tty_open_count = 0; @@ -1433,12 +1459,6 @@ static int __devinit nozomi_card_init(struct pci_dev *pdev, &pdev->dev); } - /* Enable RESET interrupt. */ - dc->last_ier = RESET; - writew(dc->last_ier, dc->reg_ier); - - pci_set_drvdata(pdev, dc); - return 0; err_free_sbuf: @@ -1553,7 +1573,7 @@ static int ntty_open(struct tty_struct *tty, struct file *file) struct nozomi *dc = get_dc_by_tty(tty); unsigned long flags; - if (!port || !dc) + if (!port || !dc || dc->state != NOZOMI_STATE_READY) return -ENODEV; if (mutex_lock_interruptible(&port->tty_sem)) @@ -1716,6 +1736,10 @@ static int ntty_tiocmget(struct tty_struct *tty, struct file *file) static int ntty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear) { + struct nozomi *dc = get_dc_by_tty(tty); + unsigned long flags; + + spin_lock_irqsave(&dc->spin_mutex, flags); if (set & TIOCM_RTS) set_rts(tty, 1); else if (clear & TIOCM_RTS) @@ -1725,6 +1749,7 @@ static int ntty_tiocmset(struct tty_struct *tty, struct file *file, set_dtr(tty, 1); else if (clear & TIOCM_DTR) set_dtr(tty, 0); + spin_unlock_irqrestore(&dc->spin_mutex, flags); return 0; } @@ -1762,7 +1787,7 @@ static int ntty_ioctl_tiocgicount(struct port *port, void __user *argp) icount.brk = cnow.brk; icount.buf_overrun = cnow.buf_overrun; - return copy_to_user(argp, &icount, sizeof(icount)); + return copy_to_user(argp, &icount, sizeof(icount)) ? -EFAULT : 0; } static int ntty_ioctl(struct tty_struct *tty, struct file *file, diff --git a/drivers/char/riscom8.c b/drivers/char/riscom8.c index 8fc4fe4e38f1..3f9d0a9ac36d 100644 --- a/drivers/char/riscom8.c +++ b/drivers/char/riscom8.c @@ -1620,14 +1620,8 @@ static int __init rc_init_drivers(void) static void rc_release_drivers(void) { - unsigned long flags; - - spin_lock_irqsave(&riscom_lock, flags); - tty_unregister_driver(riscom_driver); put_tty_driver(riscom_driver); - - spin_unlock_irqrestore(&riscom_lock, flags); } #ifndef MODULE @@ -1715,7 +1709,7 @@ static int __init riscom8_init_module (void) if (iobase || iobase1 || iobase2 || iobase3) { for(i = 0; i < RC_NBOARD; i++) - rc_board[0].base = 0; + rc_board[i].base = 0; } if (iobase) diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c index 29965231b912..8db0e7f9d3f4 100644 --- a/drivers/dma/dmaengine.c +++ b/drivers/dma/dmaengine.c @@ -357,7 +357,7 @@ int dma_async_device_register(struct dma_device *device) !device->device_prep_dma_zero_sum); BUG_ON(dma_has_cap(DMA_MEMSET, device->cap_mask) && !device->device_prep_dma_memset); - BUG_ON(dma_has_cap(DMA_ZERO_SUM, device->cap_mask) && + BUG_ON(dma_has_cap(DMA_INTERRUPT, device->cap_mask) && !device->device_prep_dma_interrupt); BUG_ON(!device->device_alloc_chan_resources); diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c index cc9a68158d99..72692309398a 100644 --- a/drivers/dma/fsldma.c +++ b/drivers/dma/fsldma.c @@ -57,12 +57,12 @@ static void dma_init(struct fsl_dma_chan *fsl_chan) } -static void set_sr(struct fsl_dma_chan *fsl_chan, dma_addr_t val) +static void set_sr(struct fsl_dma_chan *fsl_chan, u32 val) { DMA_OUT(fsl_chan, &fsl_chan->reg_base->sr, val, 32); } -static dma_addr_t get_sr(struct fsl_dma_chan *fsl_chan) +static u32 get_sr(struct fsl_dma_chan *fsl_chan) { return DMA_IN(fsl_chan, &fsl_chan->reg_base->sr, 32); } @@ -123,6 +123,11 @@ static dma_addr_t get_ndar(struct fsl_dma_chan *fsl_chan) return DMA_IN(fsl_chan, &fsl_chan->reg_base->ndar, 64); } +static u32 get_bcr(struct fsl_dma_chan *fsl_chan) +{ + return DMA_IN(fsl_chan, &fsl_chan->reg_base->bcr, 32); +} + static int dma_is_idle(struct fsl_dma_chan *fsl_chan) { u32 sr = get_sr(fsl_chan); @@ -406,6 +411,35 @@ static void fsl_dma_free_chan_resources(struct dma_chan *chan) dma_pool_destroy(fsl_chan->desc_pool); } +static struct dma_async_tx_descriptor * +fsl_dma_prep_interrupt(struct dma_chan *chan) +{ + struct fsl_dma_chan *fsl_chan; + struct fsl_desc_sw *new; + + if (!chan) + return NULL; + + fsl_chan = to_fsl_chan(chan); + + new = fsl_dma_alloc_descriptor(fsl_chan); + if (!new) { + dev_err(fsl_chan->dev, "No free memory for link descriptor\n"); + return NULL; + } + + new->async_tx.cookie = -EBUSY; + new->async_tx.ack = 0; + + /* Insert the link descriptor to the LD ring */ + list_add_tail(&new->node, &new->async_tx.tx_list); + + /* Set End-of-link to the last link descriptor of new list*/ + set_ld_eol(fsl_chan, new); + + return &new->async_tx; +} + static struct dma_async_tx_descriptor *fsl_dma_prep_memcpy( struct dma_chan *chan, dma_addr_t dma_dest, dma_addr_t dma_src, size_t len, unsigned long flags) @@ -436,7 +470,7 @@ static struct dma_async_tx_descriptor *fsl_dma_prep_memcpy( dev_dbg(fsl_chan->dev, "new link desc alloc %p\n", new); #endif - copy = min(len, FSL_DMA_BCR_MAX_CNT); + copy = min(len, (size_t)FSL_DMA_BCR_MAX_CNT); set_desc_cnt(fsl_chan, &new->hw, copy); set_desc_src(fsl_chan, &new->hw, dma_src); @@ -513,7 +547,6 @@ static void fsl_chan_ld_cleanup(struct fsl_dma_chan *fsl_chan) spin_lock_irqsave(&fsl_chan->desc_lock, flags); - fsl_dma_update_completed_cookie(fsl_chan); dev_dbg(fsl_chan->dev, "chan completed_cookie = %d\n", fsl_chan->completed_cookie); list_for_each_entry_safe(desc, _desc, &fsl_chan->ld_queue, node) { @@ -581,8 +614,8 @@ static void fsl_chan_xfer_ld_queue(struct fsl_dma_chan *fsl_chan) if (ld_node != &fsl_chan->ld_queue) { /* Get the ld start address from ld_queue */ next_dest_addr = to_fsl_desc(ld_node)->async_tx.phys; - dev_dbg(fsl_chan->dev, "xfer LDs staring from 0x%016llx\n", - (u64)next_dest_addr); + dev_dbg(fsl_chan->dev, "xfer LDs staring from %p\n", + (void *)next_dest_addr); set_cdar(fsl_chan, next_dest_addr); dma_start(fsl_chan); } else { @@ -662,7 +695,7 @@ static enum dma_status fsl_dma_is_complete(struct dma_chan *chan, static irqreturn_t fsl_dma_chan_do_interrupt(int irq, void *data) { struct fsl_dma_chan *fsl_chan = (struct fsl_dma_chan *)data; - dma_addr_t stat; + u32 stat; stat = get_sr(fsl_chan); dev_dbg(fsl_chan->dev, "event: channel %d, stat = 0x%x\n", @@ -676,15 +709,32 @@ static irqreturn_t fsl_dma_chan_do_interrupt(int irq, void *data) if (stat & FSL_DMA_SR_TE) dev_err(fsl_chan->dev, "Transfer Error!\n"); + /* Programming Error + * The DMA_INTERRUPT async_tx is a NULL transfer, which will + * triger a PE interrupt. + */ + if (stat & FSL_DMA_SR_PE) { + dev_dbg(fsl_chan->dev, "event: Programming Error INT\n"); + if (get_bcr(fsl_chan) == 0) { + /* BCR register is 0, this is a DMA_INTERRUPT async_tx. + * Now, update the completed cookie, and continue the + * next uncompleted transfer. + */ + fsl_dma_update_completed_cookie(fsl_chan); + fsl_chan_xfer_ld_queue(fsl_chan); + } + stat &= ~FSL_DMA_SR_PE; + } + /* If the link descriptor segment transfer finishes, * we will recycle the used descriptor. */ if (stat & FSL_DMA_SR_EOSI) { dev_dbg(fsl_chan->dev, "event: End-of-segments INT\n"); - dev_dbg(fsl_chan->dev, "event: clndar 0x%016llx, " - "nlndar 0x%016llx\n", (u64)get_cdar(fsl_chan), - (u64)get_ndar(fsl_chan)); + dev_dbg(fsl_chan->dev, "event: clndar %p, nlndar %p\n", + (void *)get_cdar(fsl_chan), (void *)get_ndar(fsl_chan)); stat &= ~FSL_DMA_SR_EOSI; + fsl_dma_update_completed_cookie(fsl_chan); } /* If it current transfer is the end-of-transfer, @@ -726,12 +776,15 @@ static void dma_do_tasklet(unsigned long data) fsl_chan_ld_cleanup(fsl_chan); } +#ifdef FSL_DMA_CALLBACKTEST static void fsl_dma_callback_test(struct fsl_dma_chan *fsl_chan) { if (fsl_chan) dev_info(fsl_chan->dev, "selftest: callback is ok!\n"); } +#endif +#ifdef CONFIG_FSL_DMA_SELFTEST static int fsl_dma_self_test(struct fsl_dma_chan *fsl_chan) { struct dma_chan *chan; @@ -813,6 +866,11 @@ static int fsl_dma_self_test(struct fsl_dma_chan *fsl_chan) tx3 = fsl_dma_prep_memcpy(chan, dma_dest, dma_src, test_size / 4, 0); async_tx_ack(tx3); + /* Interrupt tx test */ + tx1 = fsl_dma_prep_interrupt(chan); + async_tx_ack(tx1); + cookie = fsl_dma_tx_submit(tx1); + /* Test exchanging the prepared tx sort */ cookie = fsl_dma_tx_submit(tx3); cookie = fsl_dma_tx_submit(tx2); @@ -837,9 +895,9 @@ static int fsl_dma_self_test(struct fsl_dma_chan *fsl_chan) if (err) { for (i = 0; (*(src + i) == *(dest + i)) && (i < test_size); i++); - dev_err(fsl_chan->dev, "selftest: Test failed, data %d/%d is " + dev_err(fsl_chan->dev, "selftest: Test failed, data %d/%ld is " "error! src 0x%x, dest 0x%x\n", - i, test_size, *(src + i), *(dest + i)); + i, (long)test_size, *(src + i), *(dest + i)); } free_resources: @@ -848,6 +906,7 @@ out: kfree(src); return err; } +#endif static int __devinit of_fsl_dma_chan_probe(struct of_device *dev, const struct of_device_id *match) @@ -1008,8 +1067,8 @@ static int __devinit of_fsl_dma_probe(struct of_device *dev, } dev_info(&dev->dev, "Probe the Freescale DMA driver for %s " - "controller at 0x%08x...\n", - match->compatible, fdev->reg.start); + "controller at %p...\n", + match->compatible, (void *)fdev->reg.start); fdev->reg_base = ioremap(fdev->reg.start, fdev->reg.end - fdev->reg.start + 1); @@ -1017,6 +1076,7 @@ static int __devinit of_fsl_dma_probe(struct of_device *dev, dma_cap_set(DMA_INTERRUPT, fdev->common.cap_mask); fdev->common.device_alloc_chan_resources = fsl_dma_alloc_chan_resources; fdev->common.device_free_chan_resources = fsl_dma_free_chan_resources; + fdev->common.device_prep_dma_interrupt = fsl_dma_prep_interrupt; fdev->common.device_prep_dma_memcpy = fsl_dma_prep_memcpy; fdev->common.device_is_tx_complete = fsl_dma_is_complete; fdev->common.device_issue_pending = fsl_dma_memcpy_issue_pending; diff --git a/drivers/dma/fsldma.h b/drivers/dma/fsldma.h index ba78c42121ba..fddd6aee2a63 100644 --- a/drivers/dma/fsldma.h +++ b/drivers/dma/fsldma.h @@ -40,6 +40,7 @@ #define FSL_DMA_MR_EOTIE 0x00000080 #define FSL_DMA_SR_CH 0x00000020 +#define FSL_DMA_SR_PE 0x00000010 #define FSL_DMA_SR_CB 0x00000004 #define FSL_DMA_SR_TE 0x00000080 #define FSL_DMA_SR_EOSI 0x00000002 diff --git a/drivers/dma/iop-adma.c b/drivers/dma/iop-adma.c index 3986d54492bd..f82b0906d466 100644 --- a/drivers/dma/iop-adma.c +++ b/drivers/dma/iop-adma.c @@ -140,7 +140,7 @@ static void __iop_adma_slot_cleanup(struct iop_adma_chan *iop_chan) int busy = iop_chan_is_busy(iop_chan); int seen_current = 0, slot_cnt = 0, slots_per_op = 0; - dev_dbg(iop_chan->device->common.dev, "%s\n", __FUNCTION__); + dev_dbg(iop_chan->device->common.dev, "%s\n", __func__); /* free completed slots from the chain starting with * the oldest descriptor */ @@ -438,7 +438,7 @@ iop_adma_tx_submit(struct dma_async_tx_descriptor *tx) spin_unlock_bh(&iop_chan->lock); dev_dbg(iop_chan->device->common.dev, "%s cookie: %d slot: %d\n", - __FUNCTION__, sw_desc->async_tx.cookie, sw_desc->idx); + __func__, sw_desc->async_tx.cookie, sw_desc->idx); return cookie; } @@ -520,7 +520,7 @@ iop_adma_prep_dma_interrupt(struct dma_chan *chan) struct iop_adma_desc_slot *sw_desc, *grp_start; int slot_cnt, slots_per_op; - dev_dbg(iop_chan->device->common.dev, "%s\n", __FUNCTION__); + dev_dbg(iop_chan->device->common.dev, "%s\n", __func__); spin_lock_bh(&iop_chan->lock); slot_cnt = iop_chan_interrupt_slot_count(&slots_per_op, iop_chan); @@ -548,7 +548,7 @@ iop_adma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dma_dest, BUG_ON(unlikely(len > IOP_ADMA_MAX_BYTE_COUNT)); dev_dbg(iop_chan->device->common.dev, "%s len: %u\n", - __FUNCTION__, len); + __func__, len); spin_lock_bh(&iop_chan->lock); slot_cnt = iop_chan_memcpy_slot_count(len, &slots_per_op); @@ -580,7 +580,7 @@ iop_adma_prep_dma_memset(struct dma_chan *chan, dma_addr_t dma_dest, BUG_ON(unlikely(len > IOP_ADMA_MAX_BYTE_COUNT)); dev_dbg(iop_chan->device->common.dev, "%s len: %u\n", - __FUNCTION__, len); + __func__, len); spin_lock_bh(&iop_chan->lock); slot_cnt = iop_chan_memset_slot_count(len, &slots_per_op); @@ -614,7 +614,7 @@ iop_adma_prep_dma_xor(struct dma_chan *chan, dma_addr_t dma_dest, dev_dbg(iop_chan->device->common.dev, "%s src_cnt: %d len: %u flags: %lx\n", - __FUNCTION__, src_cnt, len, flags); + __func__, src_cnt, len, flags); spin_lock_bh(&iop_chan->lock); slot_cnt = iop_chan_xor_slot_count(len, src_cnt, &slots_per_op); @@ -648,7 +648,7 @@ iop_adma_prep_dma_zero_sum(struct dma_chan *chan, dma_addr_t *dma_src, return NULL; dev_dbg(iop_chan->device->common.dev, "%s src_cnt: %d len: %u\n", - __FUNCTION__, src_cnt, len); + __func__, src_cnt, len); spin_lock_bh(&iop_chan->lock); slot_cnt = iop_chan_zero_sum_slot_count(len, src_cnt, &slots_per_op); @@ -659,7 +659,7 @@ iop_adma_prep_dma_zero_sum(struct dma_chan *chan, dma_addr_t *dma_src, iop_desc_set_zero_sum_byte_count(grp_start, len); grp_start->xor_check_result = result; pr_debug("\t%s: grp_start->xor_check_result: %p\n", - __FUNCTION__, grp_start->xor_check_result); + __func__, grp_start->xor_check_result); sw_desc->unmap_src_cnt = src_cnt; sw_desc->unmap_len = len; while (src_cnt--) @@ -700,7 +700,7 @@ static void iop_adma_free_chan_resources(struct dma_chan *chan) iop_chan->last_used = NULL; dev_dbg(iop_chan->device->common.dev, "%s slots_allocated %d\n", - __FUNCTION__, iop_chan->slots_allocated); + __func__, iop_chan->slots_allocated); spin_unlock_bh(&iop_chan->lock); /* one is ok since we left it on there on purpose */ @@ -753,7 +753,7 @@ static irqreturn_t iop_adma_eot_handler(int irq, void *data) { struct iop_adma_chan *chan = data; - dev_dbg(chan->device->common.dev, "%s\n", __FUNCTION__); + dev_dbg(chan->device->common.dev, "%s\n", __func__); tasklet_schedule(&chan->irq_tasklet); @@ -766,7 +766,7 @@ static irqreturn_t iop_adma_eoc_handler(int irq, void *data) { struct iop_adma_chan *chan = data; - dev_dbg(chan->device->common.dev, "%s\n", __FUNCTION__); + dev_dbg(chan->device->common.dev, "%s\n", __func__); tasklet_schedule(&chan->irq_tasklet); @@ -823,7 +823,7 @@ static int __devinit iop_adma_memcpy_self_test(struct iop_adma_device *device) int err = 0; struct iop_adma_chan *iop_chan; - dev_dbg(device->common.dev, "%s\n", __FUNCTION__); + dev_dbg(device->common.dev, "%s\n", __func__); src = kzalloc(sizeof(u8) * IOP_ADMA_TEST_SIZE, GFP_KERNEL); if (!src) @@ -906,7 +906,7 @@ iop_adma_xor_zero_sum_self_test(struct iop_adma_device *device) int err = 0; struct iop_adma_chan *iop_chan; - dev_dbg(device->common.dev, "%s\n", __FUNCTION__); + dev_dbg(device->common.dev, "%s\n", __func__); for (src_idx = 0; src_idx < IOP_ADMA_NUM_SRC_TEST; src_idx++) { xor_srcs[src_idx] = alloc_page(GFP_KERNEL); @@ -1159,7 +1159,7 @@ static int __devinit iop_adma_probe(struct platform_device *pdev) } dev_dbg(&pdev->dev, "%s: allocted descriptor pool virt %p phys %p\n", - __FUNCTION__, adev->dma_desc_pool_virt, + __func__, adev->dma_desc_pool_virt, (void *) adev->dma_desc_pool); adev->id = plat_data->hw_id; @@ -1289,7 +1289,7 @@ static void iop_chan_start_null_memcpy(struct iop_adma_chan *iop_chan) dma_cookie_t cookie; int slot_cnt, slots_per_op; - dev_dbg(iop_chan->device->common.dev, "%s\n", __FUNCTION__); + dev_dbg(iop_chan->device->common.dev, "%s\n", __func__); spin_lock_bh(&iop_chan->lock); slot_cnt = iop_chan_memcpy_slot_count(0, &slots_per_op); @@ -1346,7 +1346,7 @@ static void iop_chan_start_null_xor(struct iop_adma_chan *iop_chan) dma_cookie_t cookie; int slot_cnt, slots_per_op; - dev_dbg(iop_chan->device->common.dev, "%s\n", __FUNCTION__); + dev_dbg(iop_chan->device->common.dev, "%s\n", __func__); spin_lock_bh(&iop_chan->lock); slot_cnt = iop_chan_xor_slot_count(0, 2, &slots_per_op); diff --git a/drivers/firewire/Kconfig b/drivers/firewire/Kconfig index fe9e768cfbc4..25bdc2dd9ce1 100644 --- a/drivers/firewire/Kconfig +++ b/drivers/firewire/Kconfig @@ -1,5 +1,3 @@ -# -*- shell-script -*- - comment "An alternative FireWire stack is available with EXPERIMENTAL=y" depends on EXPERIMENTAL=n @@ -21,27 +19,7 @@ config FIREWIRE NOTE: You should only build ONE of the stacks, unless you REALLY know what - you are doing. If you install both, you should configure them only as - modules rather than link them statically, and you should blacklist one - of the concurrent low-level drivers in /etc/modprobe.conf. Add either - - blacklist firewire-ohci - or - blacklist ohci1394 - - there depending on which driver you DON'T want to have auto-loaded. - You can optionally do the same with the other IEEE 1394/ FireWire - drivers. - - If you have an old modprobe which doesn't implement the blacklist - directive, use either - - install firewire-ohci /bin/true - or - install ohci1394 /bin/true - - and so on, depending on which modules you DON't want to have - auto-loaded. + you are doing. config FIREWIRE_OHCI tristate "Support for OHCI FireWire host controllers" @@ -57,8 +35,24 @@ config FIREWIRE_OHCI NOTE: - If you also build ohci1394 of the classic stack, blacklist either - ohci1394 or firewire-ohci to let hotplug load only the desired driver. + You should only build ohci1394 or firewire-ohci, but not both. + If you nevertheless want to install both, you should configure them + only as modules and blacklist the driver(s) which you don't want to + have auto-loaded. Add either + + blacklist firewire-ohci + or + blacklist ohci1394 + blacklist video1394 + blacklist dv1394 + + to /etc/modprobe.conf or /etc/modprobe.d/* and update modprobe.conf + depending on your distribution. The latter two modules should be + blacklisted together with ohci1394 because they depend on ohci1394. + + If you have an old modprobe which doesn't implement the blacklist + directive, use "install modulename /bin/true" for the modules to be + blacklisted. config FIREWIRE_SBP2 tristate "Support for storage devices (SBP-2 protocol driver)" @@ -75,9 +69,3 @@ config FIREWIRE_SBP2 You should also enable support for disks, CD-ROMs, etc. in the SCSI configuration section. - - NOTE: - - If you also build sbp2 of the classic stack, blacklist either sbp2 - or firewire-sbp2 to let hotplug load only the desired driver. - diff --git a/drivers/firewire/fw-ohci.c b/drivers/firewire/fw-ohci.c index 7ebad3c14cb8..996d61f0d460 100644 --- a/drivers/firewire/fw-ohci.c +++ b/drivers/firewire/fw-ohci.c @@ -33,6 +33,10 @@ #include <asm/page.h> #include <asm/system.h> +#ifdef CONFIG_PPC_PMAC +#include <asm/pmac_feature.h> +#endif + #include "fw-ohci.h" #include "fw-transaction.h" @@ -175,6 +179,7 @@ struct fw_ohci { int generation; int request_generation; u32 bus_seconds; + bool old_uninorth; /* * Spinlock for accessing fw_ohci data. Never call out of @@ -276,19 +281,13 @@ static int ar_context_add_page(struct ar_context *ctx) { struct device *dev = ctx->ohci->card.device; struct ar_buffer *ab; - dma_addr_t ab_bus; + dma_addr_t uninitialized_var(ab_bus); size_t offset; - ab = (struct ar_buffer *) __get_free_page(GFP_ATOMIC); + ab = dma_alloc_coherent(dev, PAGE_SIZE, &ab_bus, GFP_ATOMIC); if (ab == NULL) return -ENOMEM; - ab_bus = dma_map_single(dev, ab, PAGE_SIZE, DMA_BIDIRECTIONAL); - if (dma_mapping_error(ab_bus)) { - free_page((unsigned long) ab); - return -ENOMEM; - } - memset(&ab->descriptor, 0, sizeof(ab->descriptor)); ab->descriptor.control = cpu_to_le16(DESCRIPTOR_INPUT_MORE | DESCRIPTOR_STATUS | @@ -299,8 +298,6 @@ static int ar_context_add_page(struct ar_context *ctx) ab->descriptor.res_count = cpu_to_le16(PAGE_SIZE - offset); ab->descriptor.branch_address = 0; - dma_sync_single_for_device(dev, ab_bus, PAGE_SIZE, DMA_BIDIRECTIONAL); - ctx->last_buffer->descriptor.branch_address = cpu_to_le32(ab_bus | 1); ctx->last_buffer->next = ab; ctx->last_buffer = ab; @@ -311,15 +308,22 @@ static int ar_context_add_page(struct ar_context *ctx) return 0; } +#if defined(CONFIG_PPC_PMAC) && defined(CONFIG_PPC32) +#define cond_le32_to_cpu(v) \ + (ohci->old_uninorth ? (__force __u32)(v) : le32_to_cpu(v)) +#else +#define cond_le32_to_cpu(v) le32_to_cpu(v) +#endif + static __le32 *handle_ar_packet(struct ar_context *ctx, __le32 *buffer) { struct fw_ohci *ohci = ctx->ohci; struct fw_packet p; u32 status, length, tcode; - p.header[0] = le32_to_cpu(buffer[0]); - p.header[1] = le32_to_cpu(buffer[1]); - p.header[2] = le32_to_cpu(buffer[2]); + p.header[0] = cond_le32_to_cpu(buffer[0]); + p.header[1] = cond_le32_to_cpu(buffer[1]); + p.header[2] = cond_le32_to_cpu(buffer[2]); tcode = (p.header[0] >> 4) & 0x0f; switch (tcode) { @@ -331,7 +335,7 @@ static __le32 *handle_ar_packet(struct ar_context *ctx, __le32 *buffer) break; case TCODE_READ_BLOCK_REQUEST : - p.header[3] = le32_to_cpu(buffer[3]); + p.header[3] = cond_le32_to_cpu(buffer[3]); p.header_length = 16; p.payload_length = 0; break; @@ -340,7 +344,7 @@ static __le32 *handle_ar_packet(struct ar_context *ctx, __le32 *buffer) case TCODE_READ_BLOCK_RESPONSE: case TCODE_LOCK_REQUEST: case TCODE_LOCK_RESPONSE: - p.header[3] = le32_to_cpu(buffer[3]); + p.header[3] = cond_le32_to_cpu(buffer[3]); p.header_length = 16; p.payload_length = p.header[3] >> 16; break; @@ -357,7 +361,7 @@ static __le32 *handle_ar_packet(struct ar_context *ctx, __le32 *buffer) /* FIXME: What to do about evt_* errors? */ length = (p.header_length + p.payload_length + 3) / 4; - status = le32_to_cpu(buffer[length]); + status = cond_le32_to_cpu(buffer[length]); p.ack = ((status >> 16) & 0x1f) - 16; p.speed = (status >> 21) & 0x7; @@ -375,7 +379,7 @@ static __le32 *handle_ar_packet(struct ar_context *ctx, __le32 *buffer) */ if (p.ack + 16 == 0x09) - ohci->request_generation = (buffer[2] >> 16) & 0xff; + ohci->request_generation = (p.header[2] >> 16) & 0xff; else if (ctx == &ohci->ar_request_ctx) fw_core_handle_request(&ohci->card, &p); else @@ -397,6 +401,7 @@ static void ar_context_tasklet(unsigned long data) if (d->res_count == 0) { size_t size, rest, offset; + dma_addr_t buffer_bus; /* * This descriptor is finished and we may have a @@ -405,9 +410,7 @@ static void ar_context_tasklet(unsigned long data) */ offset = offsetof(struct ar_buffer, data); - dma_unmap_single(ohci->card.device, - le32_to_cpu(ab->descriptor.data_address) - offset, - PAGE_SIZE, DMA_BIDIRECTIONAL); + buffer_bus = le32_to_cpu(ab->descriptor.data_address) - offset; buffer = ab; ab = ab->next; @@ -423,7 +426,8 @@ static void ar_context_tasklet(unsigned long data) while (buffer < end) buffer = handle_ar_packet(ctx, buffer); - free_page((unsigned long)buffer); + dma_free_coherent(ohci->card.device, PAGE_SIZE, + buffer, buffer_bus); ar_context_add_page(ctx); } else { buffer = ctx->pointer; @@ -532,7 +536,7 @@ static int context_add_buffer(struct context *ctx) { struct descriptor_buffer *desc; - dma_addr_t bus_addr; + dma_addr_t uninitialized_var(bus_addr); int offset; /* @@ -1022,13 +1026,14 @@ static void bus_reset_tasklet(unsigned long data) */ self_id_count = (reg_read(ohci, OHCI1394_SelfIDCount) >> 3) & 0x3ff; - generation = (le32_to_cpu(ohci->self_id_cpu[0]) >> 16) & 0xff; + generation = (cond_le32_to_cpu(ohci->self_id_cpu[0]) >> 16) & 0xff; rmb(); for (i = 1, j = 0; j < self_id_count; i += 2, j++) { if (ohci->self_id_cpu[i] != ~ohci->self_id_cpu[i + 1]) fw_error("inconsistent self IDs\n"); - ohci->self_id_buffer[j] = le32_to_cpu(ohci->self_id_cpu[i]); + ohci->self_id_buffer[j] = + cond_le32_to_cpu(ohci->self_id_cpu[i]); } rmb(); @@ -1316,7 +1321,7 @@ ohci_set_config_rom(struct fw_card *card, u32 *config_rom, size_t length) unsigned long flags; int retval = -EBUSY; __be32 *next_config_rom; - dma_addr_t next_config_rom_bus; + dma_addr_t uninitialized_var(next_config_rom_bus); ohci = fw_ohci(card); @@ -1487,7 +1492,7 @@ static int handle_ir_dualbuffer_packet(struct context *context, void *p, *end; int i; - if (db->first_res_count > 0 && db->second_res_count > 0) { + if (db->first_res_count != 0 && db->second_res_count != 0) { if (ctx->excess_bytes <= le16_to_cpu(db->second_req_count)) { /* This descriptor isn't done yet, stop iteration. */ return 0; @@ -1513,7 +1518,7 @@ static int handle_ir_dualbuffer_packet(struct context *context, memcpy(ctx->header + i + 4, p + 8, ctx->base.header_size - 4); i += ctx->base.header_size; ctx->excess_bytes += - (le32_to_cpu(*(u32 *)(p + 4)) >> 16) & 0xffff; + (le32_to_cpu(*(__le32 *)(p + 4)) >> 16) & 0xffff; p += ctx->base.header_size + 4; } ctx->header_length = i; @@ -2048,6 +2053,18 @@ pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) int err; size_t size; +#ifdef CONFIG_PPC_PMAC + /* Necessary on some machines if fw-ohci was loaded/ unloaded before */ + if (machine_is(powermac)) { + struct device_node *ofn = pci_device_to_OF_node(dev); + + if (ofn) { + pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, ofn, 0, 1); + pmac_call_feature(PMAC_FTR_1394_ENABLE, ofn, 0, 1); + } + } +#endif /* CONFIG_PPC_PMAC */ + ohci = kzalloc(sizeof(*ohci), GFP_KERNEL); if (ohci == NULL) { fw_error("Could not malloc fw_ohci data.\n"); @@ -2066,6 +2083,10 @@ pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) pci_write_config_dword(dev, OHCI1394_PCI_HCI_Control, 0); pci_set_drvdata(dev, ohci); +#if defined(CONFIG_PPC_PMAC) && defined(CONFIG_PPC32) + ohci->old_uninorth = dev->vendor == PCI_VENDOR_ID_APPLE && + dev->device == PCI_DEVICE_ID_APPLE_UNI_N_FW; +#endif spin_lock_init(&ohci->lock); tasklet_init(&ohci->bus_reset_tasklet, @@ -2182,6 +2203,19 @@ static void pci_remove(struct pci_dev *dev) pci_disable_device(dev); fw_card_put(&ohci->card); +#ifdef CONFIG_PPC_PMAC + /* On UniNorth, power down the cable and turn off the chip clock + * to save power on laptops */ + if (machine_is(powermac)) { + struct device_node *ofn = pci_device_to_OF_node(dev); + + if (ofn) { + pmac_call_feature(PMAC_FTR_1394_ENABLE, ofn, 0, 0); + pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, ofn, 0, 0); + } + } +#endif /* CONFIG_PPC_PMAC */ + fw_notify("Removed fw-ohci device.\n"); } @@ -2202,6 +2236,16 @@ static int pci_suspend(struct pci_dev *pdev, pm_message_t state) if (err) fw_error("pci_set_power_state failed with %d\n", err); +/* PowerMac suspend code comes last */ +#ifdef CONFIG_PPC_PMAC + if (machine_is(powermac)) { + struct device_node *ofn = pci_device_to_OF_node(pdev); + + if (ofn) + pmac_call_feature(PMAC_FTR_1394_ENABLE, ofn, 0, 0); + } +#endif /* CONFIG_PPC_PMAC */ + return 0; } @@ -2210,6 +2254,16 @@ static int pci_resume(struct pci_dev *pdev) struct fw_ohci *ohci = pci_get_drvdata(pdev); int err; +/* PowerMac resume code comes first */ +#ifdef CONFIG_PPC_PMAC + if (machine_is(powermac)) { + struct device_node *ofn = pci_device_to_OF_node(pdev); + + if (ofn) + pmac_call_feature(PMAC_FTR_1394_ENABLE, ofn, 0, 1); + } +#endif /* CONFIG_PPC_PMAC */ + pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); err = pci_enable_device(pdev); diff --git a/drivers/firewire/fw-sbp2.c b/drivers/firewire/fw-sbp2.c index 03069a454c07..62b4e47d0cc0 100644 --- a/drivers/firewire/fw-sbp2.c +++ b/drivers/firewire/fw-sbp2.c @@ -173,6 +173,7 @@ struct sbp2_target { #define SBP2_ORB_TIMEOUT 2000U /* Timeout in ms */ #define SBP2_ORB_NULL 0x80000000 #define SBP2_MAX_SG_ELEMENT_LENGTH 0xf000 +#define SBP2_RETRY_LIMIT 0xf /* 15 retries */ #define SBP2_DIRECTION_TO_MEDIA 0x0 #define SBP2_DIRECTION_FROM_MEDIA 0x1 @@ -330,6 +331,11 @@ static const struct { .model = ~0, .workarounds = SBP2_WORKAROUND_128K_MAX_TRANS, }, + /* Datafab MD2-FW2 with Symbios/LSILogic SYM13FW500 bridge */ { + .firmware_revision = 0x002600, + .model = ~0, + .workarounds = SBP2_WORKAROUND_128K_MAX_TRANS, + }, /* * There are iPods (2nd gen, 3rd gen) with model_id == 0, but @@ -812,6 +818,30 @@ static void sbp2_target_put(struct sbp2_target *tgt) kref_put(&tgt->kref, sbp2_release_target); } +static void +complete_set_busy_timeout(struct fw_card *card, int rcode, + void *payload, size_t length, void *done) +{ + complete(done); +} + +static void sbp2_set_busy_timeout(struct sbp2_logical_unit *lu) +{ + struct fw_device *device = fw_device(lu->tgt->unit->device.parent); + DECLARE_COMPLETION_ONSTACK(done); + struct fw_transaction t; + static __be32 busy_timeout; + + /* FIXME: we should try to set dual-phase cycle_limit too */ + busy_timeout = cpu_to_be32(SBP2_RETRY_LIMIT); + + fw_send_request(device->card, &t, TCODE_WRITE_QUADLET_REQUEST, + lu->tgt->node_id, lu->generation, device->max_speed, + CSR_REGISTER_BASE + CSR_BUSY_TIMEOUT, &busy_timeout, + sizeof(busy_timeout), complete_set_busy_timeout, &done); + wait_for_completion(&done); +} + static void sbp2_reconnect(struct work_struct *work); static void sbp2_login(struct work_struct *work) @@ -864,10 +894,8 @@ static void sbp2_login(struct work_struct *work) fw_notify("%s: logged in to LUN %04x (%d retries)\n", tgt->bus_id, lu->lun, lu->retries); -#if 0 - /* FIXME: The linux1394 sbp2 does this last step. */ - sbp2_set_busy_timeout(scsi_id); -#endif + /* set appropriate retry limit(s) in BUSY_TIMEOUT register */ + sbp2_set_busy_timeout(lu); PREPARE_DELAYED_WORK(&lu->work, sbp2_reconnect); sbp2_agent_reset(lu); diff --git a/drivers/firewire/fw-topology.c b/drivers/firewire/fw-topology.c index e47bb040197a..d2c7a3d7e1cb 100644 --- a/drivers/firewire/fw-topology.c +++ b/drivers/firewire/fw-topology.c @@ -21,6 +21,7 @@ #include <linux/module.h> #include <linux/wait.h> #include <linux/errno.h> +#include <asm/bug.h> #include <asm/system.h> #include "fw-transaction.h" #include "fw-topology.h" @@ -424,8 +425,8 @@ update_tree(struct fw_card *card, struct fw_node *root) node1 = fw_node(list1.next); while (&node0->link != &list0) { + WARN_ON(node0->port_count != node1->port_count); - /* assert(node0->port_count == node1->port_count); */ if (node0->link_on && !node1->link_on) event = FW_NODE_LINK_OFF; else if (!node0->link_on && node1->link_on) diff --git a/drivers/firewire/fw-transaction.c b/drivers/firewire/fw-transaction.c index 7fcc59dedf08..99529e59a0b1 100644 --- a/drivers/firewire/fw-transaction.c +++ b/drivers/firewire/fw-transaction.c @@ -751,7 +751,7 @@ handle_topology_map(struct fw_card *card, struct fw_request *request, void *payload, size_t length, void *callback_data) { int i, start, end; - u32 *map; + __be32 *map; if (!TCODE_IS_READ_REQUEST(tcode)) { fw_send_response(card, request, RCODE_TYPE_ERROR); diff --git a/drivers/firewire/fw-transaction.h b/drivers/firewire/fw-transaction.h index 09cb72870454..a43bb22912f9 100644 --- a/drivers/firewire/fw-transaction.h +++ b/drivers/firewire/fw-transaction.h @@ -86,12 +86,12 @@ static inline void fw_memcpy_from_be32(void *_dst, void *_src, size_t size) { - u32 *dst = _dst; - u32 *src = _src; + u32 *dst = _dst; + __be32 *src = _src; int i; for (i = 0; i < size / 4; i++) - dst[i] = cpu_to_be32(src[i]); + dst[i] = be32_to_cpu(src[i]); } static inline void diff --git a/drivers/gpio/pca953x.c b/drivers/gpio/pca953x.c index 92583cd4bffd..6e72fd31184d 100644 --- a/drivers/gpio/pca953x.c +++ b/drivers/gpio/pca953x.c @@ -184,6 +184,7 @@ static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios) gc->direction_output = pca953x_gpio_direction_output; gc->get = pca953x_gpio_get_value; gc->set = pca953x_gpio_set_value; + gc->can_sleep = 1; gc->base = chip->gpio_start; gc->ngpio = gpios; diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index d73a768e176e..f0b00ec1e47e 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -968,7 +968,7 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i size--; } - /* dump the report descriptor */ + /* dump the report */ dbg_hid("report %d (size %u) = ", n, size); for (i = 0; i < size; i++) dbg_hid_line(" %02x", data[i]); diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 5a38fb27d69f..c3eb3f13e2ca 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -98,18 +98,16 @@ struct hidinput_key_translation { static struct hidinput_key_translation apple_fn_keys[] = { { KEY_BACKSPACE, KEY_DELETE }, - { KEY_F1, KEY_BRIGHTNESSDOWN, APPLE_FLAG_FKEY }, - { KEY_F2, KEY_BRIGHTNESSUP, APPLE_FLAG_FKEY }, - { KEY_F3, KEY_CYCLEWINDOWS, APPLE_FLAG_FKEY }, /* Exposé */ - { KEY_F4, KEY_FN_F4, APPLE_FLAG_FKEY }, /* Dashboard */ - { KEY_F5, KEY_FN_F5 }, - { KEY_F6, KEY_FN_F6 }, - { KEY_F7, KEY_BACK, APPLE_FLAG_FKEY }, - { KEY_F8, KEY_PLAYPAUSE, APPLE_FLAG_FKEY }, - { KEY_F9, KEY_FORWARD, APPLE_FLAG_FKEY }, - { KEY_F10, KEY_MUTE, APPLE_FLAG_FKEY }, - { KEY_F11, KEY_VOLUMEDOWN, APPLE_FLAG_FKEY }, - { KEY_F12, KEY_VOLUMEUP, APPLE_FLAG_FKEY }, + { KEY_F1, KEY_BRIGHTNESSDOWN, APPLE_FLAG_FKEY }, + { KEY_F2, KEY_BRIGHTNESSUP, APPLE_FLAG_FKEY }, + { KEY_F3, KEY_FN_F5, APPLE_FLAG_FKEY }, /* Exposé */ + { KEY_F4, KEY_FN_F4, APPLE_FLAG_FKEY }, /* Dashboard */ + { KEY_F7, KEY_PREVIOUSSONG, APPLE_FLAG_FKEY }, + { KEY_F8, KEY_PLAYPAUSE, APPLE_FLAG_FKEY }, + { KEY_F9, KEY_NEXTSONG, APPLE_FLAG_FKEY }, + { KEY_F10, KEY_MUTE, APPLE_FLAG_FKEY }, + { KEY_F11, KEY_VOLUMEDOWN, APPLE_FLAG_FKEY }, + { KEY_F12, KEY_VOLUMEUP, APPLE_FLAG_FKEY }, { KEY_UP, KEY_PAGEUP }, { KEY_DOWN, KEY_PAGEDOWN }, { KEY_LEFT, KEY_HOME }, diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index b38e559b7a46..d95979f0e028 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -278,7 +278,7 @@ static int hid_submit_ctrl(struct hid_device *hid) usbhid->urbctrl->pipe = usb_rcvctrlpipe(hid_to_usb_dev(hid), 0); maxpacket = usb_maxpacket(hid_to_usb_dev(hid), usbhid->urbctrl->pipe, 0); if (maxpacket > 0) { - padlen = (len + maxpacket - 1) / maxpacket; + padlen = DIV_ROUND_UP(len, maxpacket); padlen *= maxpacket; if (padlen > usbhid->bufsize) padlen = usbhid->bufsize; diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index e6d05f6b1c1c..e29a057cbea2 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -345,6 +345,9 @@ #define USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR 0x0400 #define USB_DEVICE_ID_N_S_HARMONY 0xc359 +#define USB_VENDOR_ID_NATSU 0x08b7 +#define USB_DEVICE_ID_NATSU_GAMEPAD 0x0001 + #define USB_VENDOR_ID_NEC 0x073e #define USB_DEVICE_ID_NEC_USB_GAME_PAD 0x0301 @@ -426,6 +429,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_DRIVING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FLYING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FIGHTING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT }, + { USB_VENDOR_ID_NATSU, USB_DEVICE_ID_NATSU_GAMEPAD, HID_QUIRK_BADPAD }, { USB_VENDOR_ID_NEC, USB_DEVICE_ID_NEC_USB_GAME_PAD, HID_QUIRK_BADPAD }, { USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RUMBLEPAD, HID_QUIRK_BADPAD }, { USB_VENDOR_ID_TOPMAX, USB_DEVICE_ID_TOPMAX_COBRAPAD, HID_QUIRK_BADPAD }, @@ -624,7 +628,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_ISO, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_APPLE_ISO_KEYBOARD }, { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_JIS, HID_QUIRK_APPLE_HAS_FN }, { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ANSI, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ISO, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_APPLE_ISO_KEYBOARD }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ISO, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_JIS, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI, HID_QUIRK_APPLE_HAS_FN }, { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_APPLE_ISO_KEYBOARD }, diff --git a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c index 573abe440842..2fa43183d375 100644 --- a/drivers/i2c/busses/i2c-amd756.c +++ b/drivers/i2c/busses/i2c-amd756.c @@ -335,7 +335,7 @@ static int __devinit amd756_probe(struct pci_dev *pdev, u8 temp; /* driver_data might come from user-space, so check it */ - if (id->driver_data > ARRAY_SIZE(chipname)) + if (id->driver_data >= ARRAY_SIZE(chipname)) return -EINVAL; if (amd756_ioport) { diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile index 501f00cea782..e47aca0ca5ae 100644 --- a/drivers/i2c/chips/Makefile +++ b/drivers/i2c/chips/Makefile @@ -1,6 +1,13 @@ # # Makefile for miscellaneous I2C chip drivers. # +# Think twice before you add a new driver to this directory. +# Device drivers are better grouped according to the functionality they +# implement rather than to the bus they are connected to. In particular: +# * Hardware monitoring chip drivers go to drivers/hwmon +# * RTC chip drivers go to drivers/rtc +# * I/O expander drivers go to drivers/gpio +# obj-$(CONFIG_DS1682) += ds1682.o obj-$(CONFIG_SENSORS_EEPROM) += eeprom.o diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 96da22e9a5a4..fd84b2a36338 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -90,12 +90,16 @@ static int i2c_device_probe(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct i2c_driver *driver = to_i2c_driver(dev->driver); + int status; if (!driver->probe) return -ENODEV; client->driver = driver; dev_dbg(dev, "probe\n"); - return driver->probe(client); + status = driver->probe(client); + if (status) + client->driver = NULL; + return status; } static int i2c_device_remove(struct device *dev) diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c index 0518a2e948cf..4c86a8d84b4c 100644 --- a/drivers/ide/ide-taskfile.c +++ b/drivers/ide/ide-taskfile.c @@ -423,6 +423,25 @@ void task_end_request(ide_drive_t *drive, struct request *rq, u8 stat) } /* + * We got an interrupt on a task_in case, but no errors and no DRQ. + * + * It might be a spurious irq (shared irq), but it might be a + * command that had no output. + */ +static ide_startstop_t task_in_unexpected(ide_drive_t *drive, struct request *rq, u8 stat) +{ + /* Command all done? */ + if (OK_STAT(stat, READY_STAT, BUSY_STAT)) { + task_end_request(drive, rq, stat); + return ide_stopped; + } + + /* Assume it was a spurious irq */ + ide_set_handler(drive, &task_in_intr, WAIT_WORSTCASE, NULL); + return ide_started; +} + +/* * Handler for command with PIO data-in phase (Read/Read Multiple). */ static ide_startstop_t task_in_intr(ide_drive_t *drive) @@ -431,18 +450,17 @@ static ide_startstop_t task_in_intr(ide_drive_t *drive) struct request *rq = HWGROUP(drive)->rq; u8 stat = ide_read_status(drive); - /* new way for dealing with premature shared PCI interrupts */ - if (!OK_STAT(stat, DRQ_STAT, BAD_R_STAT)) { - if (stat & (ERR_STAT | DRQ_STAT)) - return task_error(drive, rq, __FUNCTION__, stat); - /* No data yet, so wait for another IRQ. */ - ide_set_handler(drive, &task_in_intr, WAIT_WORSTCASE, NULL); - return ide_started; - } + /* Error? */ + if (stat & ERR_STAT) + return task_error(drive, rq, __FUNCTION__, stat); + + /* Didn't want any data? Odd. */ + if (!(stat & DRQ_STAT)) + return task_in_unexpected(drive, rq, stat); ide_pio_datablock(drive, rq, 0); - /* If it was the last datablock check status and finish transfer. */ + /* Are we done? Check status and finish transfer. */ if (!hwif->nleft) { stat = wait_drive_not_busy(drive); if (!OK_STAT(stat, 0, BAD_STAT)) diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c index 9e2b1964d71a..f53f72daae34 100644 --- a/drivers/ieee1394/sbp2.c +++ b/drivers/ieee1394/sbp2.c @@ -376,6 +376,11 @@ static const struct { .model_id = SBP2_ROM_VALUE_WILDCARD, .workarounds = SBP2_WORKAROUND_128K_MAX_TRANS, }, + /* Datafab MD2-FW2 with Symbios/LSILogic SYM13FW500 bridge */ { + .firmware_revision = 0x002600, + .model_id = SBP2_ROM_VALUE_WILDCARD, + .workarounds = SBP2_WORKAROUND_128K_MAX_TRANS, + }, /* iPod 4th generation */ { .firmware_revision = 0x0a2700, .model_id = 0x000021, diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c index b10ade92efed..4df405157086 100644 --- a/drivers/infiniband/core/cm.c +++ b/drivers/infiniband/core/cm.c @@ -3759,6 +3759,7 @@ static void cm_remove_one(struct ib_device *device) port = cm_dev->port[i-1]; ib_modify_port(device, port->port_num, 0, &port_modify); ib_unregister_mad_agent(port->mad_agent); + flush_workqueue(cm.wq); cm_remove_port_fs(port); } kobject_put(&cm_dev->dev_obj); @@ -3813,6 +3814,7 @@ static void __exit ib_cm_cleanup(void) cancel_delayed_work(&timewait_info->work.work); spin_unlock_irq(&cm.lock); + ib_unregister_client(&cm_client); destroy_workqueue(cm.wq); list_for_each_entry_safe(timewait_info, tmp, &cm.timewait_list, list) { @@ -3820,7 +3822,6 @@ static void __exit ib_cm_cleanup(void) kfree(timewait_info); } - ib_unregister_client(&cm_client); class_unregister(&cm_class); idr_destroy(&cm.local_id_table); } diff --git a/drivers/infiniband/core/fmr_pool.c b/drivers/infiniband/core/fmr_pool.c index 7f00347364f7..06d502c06a4d 100644 --- a/drivers/infiniband/core/fmr_pool.c +++ b/drivers/infiniband/core/fmr_pool.c @@ -139,7 +139,7 @@ static inline struct ib_pool_fmr *ib_fmr_cache_lookup(struct ib_fmr_pool *pool, static void ib_fmr_batch_release(struct ib_fmr_pool *pool) { int ret; - struct ib_pool_fmr *fmr, *next; + struct ib_pool_fmr *fmr; LIST_HEAD(unmap_list); LIST_HEAD(fmr_list); @@ -158,20 +158,6 @@ static void ib_fmr_batch_release(struct ib_fmr_pool *pool) #endif } - /* - * The free_list may hold FMRs that have been put there - * because they haven't reached the max_remap count. - * Invalidate their mapping as well. - */ - list_for_each_entry_safe(fmr, next, &pool->free_list, list) { - if (fmr->remap_count == 0) - continue; - hlist_del_init(&fmr->cache_node); - fmr->remap_count = 0; - list_add_tail(&fmr->fmr->list, &fmr_list); - list_move(&fmr->list, &unmap_list); - } - list_splice(&pool->dirty_list, &unmap_list); INIT_LIST_HEAD(&pool->dirty_list); pool->dirty_len = 0; @@ -384,6 +370,11 @@ void ib_destroy_fmr_pool(struct ib_fmr_pool *pool) i = 0; list_for_each_entry_safe(fmr, tmp, &pool->free_list, list) { + if (fmr->remap_count) { + INIT_LIST_HEAD(&fmr_list); + list_add_tail(&fmr->fmr->list, &fmr_list); + ib_unmap_fmr(&fmr_list); + } ib_dealloc_fmr(fmr->fmr); list_del(&fmr->list); kfree(fmr); @@ -407,8 +398,23 @@ EXPORT_SYMBOL(ib_destroy_fmr_pool); */ int ib_flush_fmr_pool(struct ib_fmr_pool *pool) { - int serial = atomic_inc_return(&pool->req_ser); + int serial; + struct ib_pool_fmr *fmr, *next; + + /* + * The free_list holds FMRs that may have been used + * but have not been remapped enough times to be dirty. + * Put them on the dirty list now so that the cleanup + * thread will reap them too. + */ + spin_lock_irq(&pool->pool_lock); + list_for_each_entry_safe(fmr, next, &pool->free_list, list) { + if (fmr->remap_count > 0) + list_move(&fmr->list, &pool->dirty_list); + } + spin_unlock_irq(&pool->pool_lock); + serial = atomic_inc_return(&pool->req_ser); wake_up_process(pool->thread); if (wait_event_interruptible(pool->force_wait, diff --git a/drivers/infiniband/core/iwcm.c b/drivers/infiniband/core/iwcm.c index 223b1aa7d92b..81c9195b512a 100644 --- a/drivers/infiniband/core/iwcm.c +++ b/drivers/infiniband/core/iwcm.c @@ -839,6 +839,7 @@ static void cm_work_handler(struct work_struct *_work) unsigned long flags; int empty; int ret = 0; + int destroy_id; spin_lock_irqsave(&cm_id_priv->lock, flags); empty = list_empty(&cm_id_priv->work_list); @@ -857,9 +858,9 @@ 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); + destroy_id = test_bit(IWCM_F_CALLBACK_DESTROY, &cm_id_priv->flags); if (iwcm_deref_id(cm_id_priv)) { - if (test_bit(IWCM_F_CALLBACK_DESTROY, - &cm_id_priv->flags)) { + if (destroy_id) { BUG_ON(!list_empty(&cm_id_priv->work_list)); free_cm_id(cm_id_priv); } diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.c b/drivers/infiniband/hw/cxgb3/iwch_provider.c index df1838f8f94d..b2ea9210467f 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_provider.c +++ b/drivers/infiniband/hw/cxgb3/iwch_provider.c @@ -189,7 +189,7 @@ static struct ib_cq *iwch_create_cq(struct ib_device *ibdev, int entries, int ve return ERR_PTR(-ENOMEM); } chp->rhp = rhp; - chp->ibcq.cqe = (1 << chp->cq.size_log2) - 1; + chp->ibcq.cqe = 1 << chp->cq.size_log2; spin_lock_init(&chp->lock); atomic_set(&chp->refcnt, 1); init_waitqueue_head(&chp->wait); @@ -819,8 +819,11 @@ static struct ib_qp *iwch_create_qp(struct ib_pd *pd, kfree(qhp); return ERR_PTR(-ENOMEM); } + attrs->cap.max_recv_wr = rqsize - 1; attrs->cap.max_send_wr = sqsize; + attrs->cap.max_inline_data = T3_MAX_INLINE; + qhp->rhp = rhp; qhp->attr.pd = php->pdid; qhp->attr.scq = ((struct iwch_cq *) attrs->send_cq)->cq.cqid; diff --git a/drivers/infiniband/hw/ipath/ipath_common.h b/drivers/infiniband/hw/ipath/ipath_common.h index 414621095540..591901aab6b7 100644 --- a/drivers/infiniband/hw/ipath/ipath_common.h +++ b/drivers/infiniband/hw/ipath/ipath_common.h @@ -75,7 +75,7 @@ #define IPATH_IB_LINKDOWN 0 #define IPATH_IB_LINKARM 1 #define IPATH_IB_LINKACTIVE 2 -#define IPATH_IB_LINKINIT 3 +#define IPATH_IB_LINKDOWN_ONLY 3 #define IPATH_IB_LINKDOWN_SLEEP 4 #define IPATH_IB_LINKDOWN_DISABLE 5 #define IPATH_IB_LINK_LOOPBACK 6 /* enable local loopback */ diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c index d5ff6ca2db30..ca4d0acc6786 100644 --- a/drivers/infiniband/hw/ipath/ipath_driver.c +++ b/drivers/infiniband/hw/ipath/ipath_driver.c @@ -851,8 +851,7 @@ void ipath_disarm_piobufs(struct ipath_devdata *dd, unsigned first, * -ETIMEDOUT state can have multiple states set, for any of several * transitions. */ -static int ipath_wait_linkstate(struct ipath_devdata *dd, u32 state, - int msecs) +int ipath_wait_linkstate(struct ipath_devdata *dd, u32 state, int msecs) { dd->ipath_state_wanted = state; wait_event_interruptible_timeout(ipath_state_wait, @@ -1656,8 +1655,8 @@ void ipath_cancel_sends(struct ipath_devdata *dd, int restore_sendctrl) static void ipath_set_ib_lstate(struct ipath_devdata *dd, int which) { static const char *what[4] = { - [0] = "DOWN", - [INFINIPATH_IBCC_LINKCMD_INIT] = "INIT", + [0] = "NOP", + [INFINIPATH_IBCC_LINKCMD_DOWN] = "DOWN", [INFINIPATH_IBCC_LINKCMD_ARMED] = "ARMED", [INFINIPATH_IBCC_LINKCMD_ACTIVE] = "ACTIVE" }; @@ -1672,9 +1671,9 @@ static void ipath_set_ib_lstate(struct ipath_devdata *dd, int which) (dd, dd->ipath_kregs->kr_ibcstatus) >> INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) & INFINIPATH_IBCS_LINKTRAININGSTATE_MASK]); - /* flush all queued sends when going to DOWN or INIT, to be sure that + /* flush all queued sends when going to DOWN to be sure that * they don't block MAD packets */ - if (!linkcmd || linkcmd == INFINIPATH_IBCC_LINKCMD_INIT) + if (linkcmd == INFINIPATH_IBCC_LINKCMD_DOWN) ipath_cancel_sends(dd, 1); ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl, @@ -1687,6 +1686,13 @@ int ipath_set_linkstate(struct ipath_devdata *dd, u8 newstate) int ret; switch (newstate) { + case IPATH_IB_LINKDOWN_ONLY: + ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKCMD_DOWN << + INFINIPATH_IBCC_LINKCMD_SHIFT); + /* don't wait */ + ret = 0; + goto bail; + case IPATH_IB_LINKDOWN: ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKINITCMD_POLL << INFINIPATH_IBCC_LINKINITCMD_SHIFT); @@ -1709,16 +1715,6 @@ int ipath_set_linkstate(struct ipath_devdata *dd, u8 newstate) ret = 0; goto bail; - case IPATH_IB_LINKINIT: - if (dd->ipath_flags & IPATH_LINKINIT) { - ret = 0; - goto bail; - } - ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKCMD_INIT << - INFINIPATH_IBCC_LINKCMD_SHIFT); - lstate = IPATH_LINKINIT; - break; - case IPATH_IB_LINKARM: if (dd->ipath_flags & IPATH_LINKARMED) { ret = 0; diff --git a/drivers/infiniband/hw/ipath/ipath_kernel.h b/drivers/infiniband/hw/ipath/ipath_kernel.h index 4cc0f95ea877..ecf3f7ff7717 100644 --- a/drivers/infiniband/hw/ipath/ipath_kernel.h +++ b/drivers/infiniband/hw/ipath/ipath_kernel.h @@ -767,6 +767,7 @@ void ipath_kreceive(struct ipath_portdata *); int ipath_setrcvhdrsize(struct ipath_devdata *, unsigned); int ipath_reset_device(int); void ipath_get_faststats(unsigned long); +int ipath_wait_linkstate(struct ipath_devdata *, u32, int); int ipath_set_linkstate(struct ipath_devdata *, u8); int ipath_set_mtu(struct ipath_devdata *, u16); int ipath_set_lid(struct ipath_devdata *, u32, u8); diff --git a/drivers/infiniband/hw/ipath/ipath_mad.c b/drivers/infiniband/hw/ipath/ipath_mad.c index d98d5f103700..b34b91d3723a 100644 --- a/drivers/infiniband/hw/ipath/ipath_mad.c +++ b/drivers/infiniband/hw/ipath/ipath_mad.c @@ -555,10 +555,7 @@ static int recv_subn_set_portinfo(struct ib_smp *smp, /* FALLTHROUGH */ case IB_PORT_DOWN: if (lstate == 0) - if (get_linkdowndefaultstate(dd)) - lstate = IPATH_IB_LINKDOWN_SLEEP; - else - lstate = IPATH_IB_LINKDOWN; + lstate = IPATH_IB_LINKDOWN_ONLY; else if (lstate == 1) lstate = IPATH_IB_LINKDOWN_SLEEP; else if (lstate == 2) @@ -568,6 +565,8 @@ static int recv_subn_set_portinfo(struct ib_smp *smp, else goto err; ipath_set_linkstate(dd, lstate); + ipath_wait_linkstate(dd, IPATH_LINKINIT | IPATH_LINKARMED | + IPATH_LINKACTIVE, 1000); break; case IB_PORT_ARMED: ipath_set_linkstate(dd, IPATH_IB_LINKARM); diff --git a/drivers/infiniband/hw/ipath/ipath_qp.c b/drivers/infiniband/hw/ipath/ipath_qp.c index 80dc623cee40..087ed3166479 100644 --- a/drivers/infiniband/hw/ipath/ipath_qp.c +++ b/drivers/infiniband/hw/ipath/ipath_qp.c @@ -329,8 +329,9 @@ struct ipath_qp *ipath_lookup_qpn(struct ipath_qp_table *qpt, u32 qpn) /** * ipath_reset_qp - initialize the QP state to the reset state * @qp: the QP to reset + * @type: the QP type */ -static void ipath_reset_qp(struct ipath_qp *qp) +static void ipath_reset_qp(struct ipath_qp *qp, enum ib_qp_type type) { qp->remote_qpn = 0; qp->qkey = 0; @@ -342,7 +343,7 @@ static void ipath_reset_qp(struct ipath_qp *qp) qp->s_psn = 0; qp->r_psn = 0; qp->r_msn = 0; - if (qp->ibqp.qp_type == IB_QPT_RC) { + if (type == IB_QPT_RC) { qp->s_state = IB_OPCODE_RC_SEND_LAST; qp->r_state = IB_OPCODE_RC_SEND_LAST; } else { @@ -414,7 +415,7 @@ int ipath_error_qp(struct ipath_qp *qp, enum ib_wc_status err) wc.wr_id = qp->r_wr_id; wc.opcode = IB_WC_RECV; wc.status = err; - ipath_cq_enter(to_icq(qp->ibqp.send_cq), &wc, 1); + ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc, 1); } wc.status = IB_WC_WR_FLUSH_ERR; @@ -534,7 +535,7 @@ int ipath_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, switch (new_state) { case IB_QPS_RESET: - ipath_reset_qp(qp); + ipath_reset_qp(qp, ibqp->qp_type); break; case IB_QPS_ERR: @@ -647,7 +648,7 @@ int ipath_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, attr->port_num = 1; attr->timeout = qp->timeout; attr->retry_cnt = qp->s_retry_cnt; - attr->rnr_retry = qp->s_rnr_retry; + attr->rnr_retry = qp->s_rnr_retry_cnt; attr->alt_port_num = 0; attr->alt_timeout = 0; @@ -839,7 +840,7 @@ struct ib_qp *ipath_create_qp(struct ib_pd *ibpd, goto bail_qp; } qp->ip = NULL; - ipath_reset_qp(qp); + ipath_reset_qp(qp, init_attr->qp_type); break; default: diff --git a/drivers/infiniband/hw/ipath/ipath_rc.c b/drivers/infiniband/hw/ipath/ipath_rc.c index 459e46e2c016..40f3e37d7adc 100644 --- a/drivers/infiniband/hw/ipath/ipath_rc.c +++ b/drivers/infiniband/hw/ipath/ipath_rc.c @@ -1196,6 +1196,10 @@ static inline void ipath_rc_rcv_resp(struct ipath_ibdev *dev, list_move_tail(&qp->timerwait, &dev->pending[dev->pending_index]); spin_unlock(&dev->pending_lock); + + if (opcode == OP(RDMA_READ_RESPONSE_MIDDLE)) + qp->s_retry = qp->s_retry_cnt; + /* * Update the RDMA receive state but do the copy w/o * holding the locks and blocking interrupts. diff --git a/drivers/infiniband/hw/ipath/ipath_registers.h b/drivers/infiniband/hw/ipath/ipath_registers.h index 6d2a17f9c1da..92ad73a7fff0 100644 --- a/drivers/infiniband/hw/ipath/ipath_registers.h +++ b/drivers/infiniband/hw/ipath/ipath_registers.h @@ -185,7 +185,7 @@ #define INFINIPATH_IBCC_LINKINITCMD_SLEEP 3 #define INFINIPATH_IBCC_LINKINITCMD_SHIFT 16 #define INFINIPATH_IBCC_LINKCMD_MASK 0x3ULL -#define INFINIPATH_IBCC_LINKCMD_INIT 1 /* move to 0x11 */ +#define INFINIPATH_IBCC_LINKCMD_DOWN 1 /* move to 0x11 */ #define INFINIPATH_IBCC_LINKCMD_ARMED 2 /* move to 0x21 */ #define INFINIPATH_IBCC_LINKCMD_ACTIVE 3 /* move to 0x31 */ #define INFINIPATH_IBCC_LINKCMD_SHIFT 18 diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c index 52b1bebfa744..2490b2d79dbb 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c @@ -38,6 +38,7 @@ #include <net/icmp.h> #include <linux/icmpv6.h> #include <linux/delay.h> +#include <linux/vmalloc.h> #include "ipoib.h" @@ -637,6 +638,7 @@ static inline int post_send(struct ipoib_dev_priv *priv, priv->tx_sge[0].addr = addr; priv->tx_sge[0].length = len; + priv->tx_wr.num_sge = 1; priv->tx_wr.wr_id = wr_id | IPOIB_OP_CM; return ib_post_send(tx->qp, &priv->tx_wr, &bad_wr); @@ -1030,13 +1032,13 @@ static int ipoib_cm_tx_init(struct ipoib_cm_tx *p, u32 qpn, struct ipoib_dev_priv *priv = netdev_priv(p->dev); int ret; - p->tx_ring = kzalloc(ipoib_sendq_size * sizeof *p->tx_ring, - GFP_KERNEL); + p->tx_ring = vmalloc(ipoib_sendq_size * sizeof *p->tx_ring); if (!p->tx_ring) { ipoib_warn(priv, "failed to allocate tx ring\n"); ret = -ENOMEM; goto err_tx; } + memset(p->tx_ring, 0, ipoib_sendq_size * sizeof *p->tx_ring); p->qp = ipoib_cm_create_tx_qp(p->dev, p); if (IS_ERR(p->qp)) { @@ -1077,6 +1079,7 @@ err_id: ib_destroy_qp(p->qp); err_qp: p->qp = NULL; + vfree(p->tx_ring); err_tx: return ret; } @@ -1127,7 +1130,7 @@ timeout: if (p->qp) ib_destroy_qp(p->qp); - kfree(p->tx_ring); + vfree(p->tx_ring); kfree(p); } diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index f96477a8ca5a..57282048865c 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -41,6 +41,7 @@ #include <linux/init.h> #include <linux/slab.h> #include <linux/kernel.h> +#include <linux/vmalloc.h> #include <linux/if_arp.h> /* For ARPHRD_xxx */ @@ -887,13 +888,13 @@ int ipoib_dev_init(struct net_device *dev, struct ib_device *ca, int port) goto out; } - priv->tx_ring = kzalloc(ipoib_sendq_size * sizeof *priv->tx_ring, - GFP_KERNEL); + priv->tx_ring = vmalloc(ipoib_sendq_size * sizeof *priv->tx_ring); if (!priv->tx_ring) { printk(KERN_WARNING "%s: failed to allocate TX ring (%d entries)\n", ca->name, ipoib_sendq_size); goto out_rx_ring_cleanup; } + memset(priv->tx_ring, 0, ipoib_sendq_size * sizeof *priv->tx_ring); /* priv->tx_head, tx_tail & tx_outstanding are already 0 */ @@ -903,7 +904,7 @@ int ipoib_dev_init(struct net_device *dev, struct ib_device *ca, int port) return 0; out_tx_ring_cleanup: - kfree(priv->tx_ring); + vfree(priv->tx_ring); out_rx_ring_cleanup: kfree(priv->rx_ring); @@ -928,7 +929,7 @@ void ipoib_dev_cleanup(struct net_device *dev) ipoib_ib_dev_cleanup(dev); kfree(priv->rx_ring); - kfree(priv->tx_ring); + vfree(priv->tx_ring); priv->rx_ring = NULL; priv->tx_ring = NULL; diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index 2628339e3a99..31a53c5bcb13 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c @@ -650,7 +650,7 @@ void ipoib_mcast_send(struct net_device *dev, void *mgid, struct sk_buff *skb) */ spin_lock(&priv->lock); - if (!test_bit(IPOIB_MCAST_STARTED, &priv->flags) || + if (!test_bit(IPOIB_FLAG_OPER_UP, &priv->flags) || !priv->broadcast || !test_bit(IPOIB_MCAST_FLAG_ATTACHED, &priv->broadcast->flags)) { ++dev->stats.tx_dropped; diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c index 714b8db02b29..993f0a8ff28f 100644 --- a/drivers/infiniband/ulp/iser/iser_verbs.c +++ b/drivers/infiniband/ulp/iser/iser_verbs.c @@ -237,36 +237,32 @@ static int iser_free_ib_conn_res(struct iser_conn *ib_conn) static struct iser_device *iser_device_find_by_ib_device(struct rdma_cm_id *cma_id) { - struct list_head *p_list; - struct iser_device *device = NULL; + struct iser_device *device; mutex_lock(&ig.device_list_mutex); - p_list = ig.device_list.next; - while (p_list != &ig.device_list) { - device = list_entry(p_list, struct iser_device, ig_list); + list_for_each_entry(device, &ig.device_list, ig_list) /* find if there's a match using the node GUID */ if (device->ib_device->node_guid == cma_id->device->node_guid) - break; - } + goto inc_refcnt; - if (device == NULL) { - device = kzalloc(sizeof *device, GFP_KERNEL); - if (device == NULL) - goto out; - /* assign this device to the device */ - device->ib_device = cma_id->device; - /* init the device and link it into ig device list */ - if (iser_create_device_ib_res(device)) { - kfree(device); - device = NULL; - goto out; - } - list_add(&device->ig_list, &ig.device_list); + device = kzalloc(sizeof *device, GFP_KERNEL); + if (device == NULL) + goto out; + + /* assign this device to the device */ + device->ib_device = cma_id->device; + /* init the device and link it into ig device list */ + if (iser_create_device_ib_res(device)) { + kfree(device); + device = NULL; + goto out; } -out: - BUG_ON(device == NULL); + list_add(&device->ig_list, &ig.device_list); + +inc_refcnt: device->refcount++; +out: mutex_unlock(&ig.device_list_mutex); return device; } @@ -372,6 +368,12 @@ static void iser_addr_handler(struct rdma_cm_id *cma_id) int ret; device = iser_device_find_by_ib_device(cma_id); + if (!device) { + iser_err("device lookup/creation failed\n"); + iser_connect_error(cma_id); + return; + } + ib_conn = (struct iser_conn *)cma_id->context; ib_conn->device = device; @@ -380,7 +382,6 @@ static void iser_addr_handler(struct rdma_cm_id *cma_id) iser_err("resolve route failed: %d\n", ret); iser_connect_error(cma_id); } - return; } static void iser_route_handler(struct rdma_cm_id *cma_id) diff --git a/drivers/input/misc/cobalt_btns.c b/drivers/input/misc/cobalt_btns.c index 4833b1a82623..5511ef006a66 100644 --- a/drivers/input/misc/cobalt_btns.c +++ b/drivers/input/misc/cobalt_btns.c @@ -1,7 +1,7 @@ /* * Cobalt button interface driver. * - * Copyright (C) 2007 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp> + * Copyright (C) 2007-2008 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -15,7 +15,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include <linux/init.h> #include <linux/input-polldev.h> @@ -55,7 +55,7 @@ static void handle_buttons(struct input_polled_dev *dev) status = ~readl(bdev->reg) >> 24; for (i = 0; i < ARRAY_SIZE(bdev->keymap); i++) { - if (status & (1UL << i)) { + if (status & (1U << i)) { if (++bdev->count[i] == BUTTONS_COUNT_THRESHOLD) { input_event(input, EV_MSC, MSC_SCAN, i); input_report_key(input, bdev->keymap[i], 1); @@ -97,16 +97,16 @@ static int __devinit cobalt_buttons_probe(struct platform_device *pdev) input->name = "Cobalt buttons"; input->phys = "cobalt/input0"; input->id.bustype = BUS_HOST; - input->cdev.dev = &pdev->dev; + input->dev.parent = &pdev->dev; - input->keycode = pdev->keymap; - input->keycodemax = ARRAY_SIZE(pdev->keymap); + input->keycode = bdev->keymap; + input->keycodemax = ARRAY_SIZE(bdev->keymap); input->keycodesize = sizeof(unsigned short); input_set_capability(input, EV_MSC, MSC_SCAN); __set_bit(EV_KEY, input->evbit); - for (i = 0; i < ARRAY_SIZE(buttons_map); i++) - __set_bit(input->keycode[i], input->keybit); + for (i = 0; i < ARRAY_SIZE(cobalt_map); i++) + __set_bit(bdev->keymap[i], input->keybit); __clear_bit(KEY_RESERVED, input->keybit); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index b346a3b418ea..385e32bcf6a6 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -116,8 +116,8 @@ static void alps_process_packet(struct psmouse *psmouse) } if (priv->i->flags & ALPS_FW_BK_1) { - back = packet[2] & 4; - forward = packet[0] & 0x10; + back = packet[0] & 0x10; + forward = packet[2] & 4; } if (priv->i->flags & ALPS_FW_BK_2) { @@ -483,6 +483,7 @@ int alps_init(struct psmouse *psmouse) dev2->id.vendor = 0x0002; dev2->id.product = PSMOUSE_ALPS; dev2->id.version = 0x0000; + dev2->dev.parent = &psmouse->ps2dev.serio->dev; dev2->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); dev2->relbit[BIT_WORD(REL_X)] |= BIT_MASK(REL_X) | BIT_MASK(REL_Y); diff --git a/drivers/input/serio/i8042-snirm.h b/drivers/input/serio/i8042-snirm.h new file mode 100644 index 000000000000..409a9341143d --- /dev/null +++ b/drivers/input/serio/i8042-snirm.h @@ -0,0 +1,75 @@ +#ifndef _I8042_SNIRM_H +#define _I8042_SNIRM_H + +#include <asm/sni.h> + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + +/* + * Names. + */ + +#define I8042_KBD_PHYS_DESC "onboard/serio0" +#define I8042_AUX_PHYS_DESC "onboard/serio1" +#define I8042_MUX_PHYS_DESC "onboard/serio%d" + +/* + * IRQs. + */ +static int i8042_kbd_irq; +static int i8042_aux_irq; +#define I8042_KBD_IRQ i8042_kbd_irq +#define I8042_AUX_IRQ i8042_aux_irq + +static void __iomem *kbd_iobase; + +#define I8042_COMMAND_REG (kbd_iobase + 0x64UL) +#define I8042_DATA_REG (kbd_iobase + 0x60UL) + +static inline int i8042_read_data(void) +{ + return readb(kbd_iobase + 0x60UL); +} + +static inline int i8042_read_status(void) +{ + return readb(kbd_iobase + 0x64UL); +} + +static inline void i8042_write_data(int val) +{ + writeb(val, kbd_iobase + 0x60UL); +} + +static inline void i8042_write_command(int val) +{ + writeb(val, kbd_iobase + 0x64UL); +} +static inline int i8042_platform_init(void) +{ + /* RM200 is strange ... */ + if (sni_brd_type == SNI_BRD_RM200) { + kbd_iobase = ioremap(0x16000000, 4); + i8042_kbd_irq = 33; + i8042_aux_irq = 44; + } else { + kbd_iobase = ioremap(0x14000000, 4); + i8042_kbd_irq = 1; + i8042_aux_irq = 12; + } + if (!kbd_iobase) + return -ENOMEM; + + return 0; +} + +static inline void i8042_platform_exit(void) +{ + +} + +#endif /* _I8042_SNIRM_H */ diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index 662e84482c26..60931aceb828 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -277,6 +277,13 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "M636/A737 platform"), }, }, + { + .ident = "Lenovo 3000 n100", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "3000 N100"), + }, + }, { } }; diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index 2763394869d2..65a74cfc187b 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -1151,7 +1151,6 @@ static int __devinit i8042_setup_kbd(void) static int __devinit i8042_probe(struct platform_device *dev) { int error; - char param; error = i8042_controller_selftest(); if (error) @@ -1174,7 +1173,7 @@ static int __devinit i8042_probe(struct platform_device *dev) } #ifdef CONFIG_X86 if (i8042_dritek) { - param = 0x90; + char param = 0x90; error = i8042_command(¶m, 0x1059); if (error) goto out_fail; diff --git a/drivers/input/serio/i8042.h b/drivers/input/serio/i8042.h index dd22d91f8b39..cbc1beb66574 100644 --- a/drivers/input/serio/i8042.h +++ b/drivers/input/serio/i8042.h @@ -16,8 +16,10 @@ #if defined(CONFIG_MACH_JAZZ) #include "i8042-jazzio.h" -#elif defined(CONFIG_SGI_IP22) +#elif defined(CONFIG_SGI_HAS_I8042) #include "i8042-ip22io.h" +#elif defined(CONFIG_SNI_RM) +#include "i8042-snirm.h" #elif defined(CONFIG_PPC) #include "i8042-ppcio.h" #elif defined(CONFIG_SPARC) diff --git a/drivers/input/tablet/wacom.h b/drivers/input/tablet/wacom.h index 6542edb6f76e..acf9830698cb 100644 --- a/drivers/input/tablet/wacom.h +++ b/drivers/input/tablet/wacom.h @@ -11,7 +11,7 @@ * Copyright (c) 2000 Daniel Egger <egger@suse.de> * Copyright (c) 2001 Frederic Lepied <flepied@mandrakesoft.com> * Copyright (c) 2004 Panagiotis Issaris <panagiotis.issaris@mech.kuleuven.ac.be> - * Copyright (c) 2002-2007 Ping Cheng <pingc@wacom.com> + * Copyright (c) 2002-2008 Ping Cheng <pingc@wacom.com> * * ChangeLog: * v0.1 (vp) - Initial release @@ -65,6 +65,7 @@ * - and wacom_wac.c deals with Wacom specific code * - Support Intuos3 4x6 * v1.47 (pc) - Added support for Bamboo + * v1.48 (pc) - Added support for Bamboo1, BambooFun, and Cintiq 12WX */ /* @@ -85,7 +86,7 @@ /* * Version Information */ -#define DRIVER_VERSION "v1.47" +#define DRIVER_VERSION "v1.48" #define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>" #define DRIVER_DESC "USB Wacom Graphire and Wacom Intuos tablet driver" #define DRIVER_LICENSE "GPL" @@ -125,6 +126,7 @@ extern void input_dev_i(struct input_dev *input_dev, struct wacom_wac *wacom_wac extern void input_dev_pl(struct input_dev *input_dev, struct wacom_wac *wacom_wac); extern void input_dev_pt(struct input_dev *input_dev, struct wacom_wac *wacom_wac); extern void input_dev_mo(struct input_dev *input_dev, struct wacom_wac *wacom_wac); +extern void input_dev_bee(struct input_dev *input_dev, struct wacom_wac *wacom_wac); extern __u16 wacom_le16_to_cpu(unsigned char *data); extern __u16 wacom_be16_to_cpu(unsigned char *data); extern struct wacom_features * get_wacom_feature(const struct usb_device_id *id); diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c index d64b1ea136b3..41caaef8e2d7 100644 --- a/drivers/input/tablet/wacom_sys.c +++ b/drivers/input/tablet/wacom_sys.c @@ -171,6 +171,7 @@ void input_dev_i3s(struct input_dev *input_dev, struct wacom_wac *wacom_wac) input_dev->keybit[BIT_WORD(BTN_LEFT)] |= BIT_MASK(BTN_0) | BIT_MASK(BTN_1) | BIT_MASK(BTN_2) | BIT_MASK(BTN_3); input_set_abs_params(input_dev, ABS_RX, 0, 4096, 0, 0); + input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0); } void input_dev_i3(struct input_dev *input_dev, struct wacom_wac *wacom_wac) @@ -180,6 +181,11 @@ void input_dev_i3(struct input_dev *input_dev, struct wacom_wac *wacom_wac) input_set_abs_params(input_dev, ABS_RY, 0, 4096, 0, 0); } +void input_dev_bee(struct input_dev *input_dev, struct wacom_wac *wacom_wac) +{ + input_dev->keybit[BIT_WORD(BTN_LEFT)] |= BIT_MASK(BTN_8) | BIT_MASK(BTN_9); +} + void input_dev_i(struct input_dev *input_dev, struct wacom_wac *wacom_wac) { input_dev->evbit[0] |= BIT_MASK(EV_MSC) | BIT_MASK(EV_REL); diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c index fc03ba256f4c..ffe33842143f 100644 --- a/drivers/input/tablet/wacom_wac.c +++ b/drivers/input/tablet/wacom_wac.c @@ -163,7 +163,9 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo) } id = STYLUS_DEVICE_ID; - if (data[1] & 0x80) { /* in prox */ + if ((data[1] & 0x80) && ((data[1] & 0x07) || data[2] || data[3] || data[4] + || data[5] || data[6] || (data[7] & 0x07))) { + /* in prox and not a pad data */ switch ((data[1] >> 5) & 3) { @@ -233,7 +235,6 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo) if (data[7] & 0xf8) { wacom_input_sync(wcombo); /* sync last event */ wacom->id[1] = 1; - wacom->serial[1] = (data[7] & 0xf8); wacom_report_key(wcombo, BTN_0, (data[7] & 0x40)); wacom_report_key(wcombo, BTN_4, (data[7] & 0x80)); rw = ((data[7] & 0x18) >> 3) - ((data[7] & 0x20) >> 3); @@ -252,10 +253,9 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo) } break; case WACOM_MO: - if ((data[7] & 0xf8) || (data[8] & 0x80)) { + if ((data[7] & 0xf8) || (data[8] & 0xff)) { wacom_input_sync(wcombo); /* sync last event */ wacom->id[1] = 1; - wacom->serial[1] = (data[7] & 0xf8); wacom_report_key(wcombo, BTN_0, (data[7] & 0x08)); wacom_report_key(wcombo, BTN_1, (data[7] & 0x20)); wacom_report_key(wcombo, BTN_4, (data[7] & 0x10)); @@ -434,10 +434,12 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo) wacom_report_key(wcombo, BTN_5, (data[6] & 0x02)); wacom_report_key(wcombo, BTN_6, (data[6] & 0x04)); wacom_report_key(wcombo, BTN_7, (data[6] & 0x08)); + wacom_report_key(wcombo, BTN_8, (data[5] & 0x10)); + wacom_report_key(wcombo, BTN_9, (data[6] & 0x10)); wacom_report_abs(wcombo, ABS_RX, ((data[1] & 0x1f) << 8) | data[2]); wacom_report_abs(wcombo, ABS_RY, ((data[3] & 0x1f) << 8) | data[4]); - if((data[5] & 0x0f) | (data[6] & 0x0f) | (data[1] & 0x1f) | + if ((data[5] & 0x1f) | (data[6] & 0x1f) | (data[1] & 0x1f) | data[2] | (data[3] & 0x1f) | data[4]) wacom_report_key(wcombo, wacom->tool[1], 1); else @@ -481,13 +483,11 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo) if (data[1] & 0x02) { /* Rotation packet */ if (wacom->features->type >= INTUOS3S) { - /* I3 marker pen rotation reported as wheel - * due to valuator limitation - */ + /* I3 marker pen rotation */ t = (data[6] << 3) | ((data[7] >> 5) & 7); t = (data[7] & 0x20) ? ((t > 900) ? ((t-1) / 2 - 1350) : ((t-1) / 2 + 450)) : (450 - t / 2) ; - wacom_report_abs(wcombo, ABS_WHEEL, t); + wacom_report_abs(wcombo, ABS_Z, t); } else { /* 4D mouse rotation packet */ t = (data[6] << 3) | ((data[7] >> 5) & 7); @@ -558,6 +558,7 @@ int wacom_wac_irq(struct wacom_wac *wacom_wac, void *wcombo) case INTUOS3: case INTUOS3L: case CINTIQ: + case WACOM_BEE: return (wacom_intuos_irq(wacom_wac, wcombo)); break; default: @@ -577,6 +578,8 @@ void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_w case GRAPHIRE: input_dev_g(input_dev, wacom_wac); break; + case WACOM_BEE: + input_dev_bee(input_dev, wacom_wac); case INTUOS3: case INTUOS3L: case CINTIQ: @@ -607,12 +610,15 @@ static struct wacom_features wacom_features[] = { { "Wacom Graphire3 6x8", 8, 16704, 12064, 511, 63, GRAPHIRE }, { "Wacom Graphire4 4x5", 8, 10208, 7424, 511, 63, WACOM_G4 }, { "Wacom Graphire4 6x8", 8, 16704, 12064, 511, 63, WACOM_G4 }, + { "Wacom BambooFun 4x5", 9, 14760, 9225, 511, 63, WACOM_MO }, + { "Wacom BambooFun 6x8", 9, 21648, 13530, 511, 63, WACOM_MO }, { "Wacom Volito", 8, 5104, 3712, 511, 63, GRAPHIRE }, { "Wacom PenStation2", 8, 3250, 2320, 255, 63, GRAPHIRE }, { "Wacom Volito2 4x5", 8, 5104, 3712, 511, 63, GRAPHIRE }, { "Wacom Volito2 2x3", 8, 3248, 2320, 511, 63, GRAPHIRE }, - { "Wacom PenPartner2", 8, 3250, 2320, 255, 63, GRAPHIRE }, + { "Wacom PenPartner2", 8, 3250, 2320, 511, 63, GRAPHIRE }, { "Wacom Bamboo", 9, 14760, 9225, 511, 63, WACOM_MO }, + { "Wacom Bamboo1", 8, 5104, 3712, 511, 63, GRAPHIRE }, { "Wacom Intuos 4x5", 10, 12700, 10600, 1023, 31, INTUOS }, { "Wacom Intuos 6x8", 10, 20320, 16240, 1023, 31, INTUOS }, { "Wacom Intuos 9x12", 10, 30480, 24060, 1023, 31, INTUOS }, @@ -643,6 +649,7 @@ static struct wacom_features wacom_features[] = { { "Wacom Intuos3 6x11", 10, 54204, 31750, 1023, 63, INTUOS3 }, { "Wacom Intuos3 4x6", 10, 31496, 19685, 1023, 63, INTUOS3S }, { "Wacom Cintiq 21UX", 10, 87200, 65600, 1023, 63, CINTIQ }, + { "Wacom Cintiq 12WX", 10, 53020, 33440, 1023, 63, WACOM_BEE }, { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 31, INTUOS }, { } }; @@ -656,12 +663,15 @@ static struct usb_device_id wacom_ids[] = { { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x14) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x15) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x16) }, + { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x17) }, + { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x18) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x60) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x61) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x62) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x63) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x64) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x65) }, + { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x69) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x20) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x21) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x22) }, @@ -692,6 +702,7 @@ static struct usb_device_id wacom_ids[] = { { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB5) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB7) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x3F) }, + { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC6) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x47) }, { } }; diff --git a/drivers/input/tablet/wacom_wac.h b/drivers/input/tablet/wacom_wac.h index a302e229bb8a..3342bc05847d 100644 --- a/drivers/input/tablet/wacom_wac.h +++ b/drivers/input/tablet/wacom_wac.h @@ -25,6 +25,7 @@ enum { INTUOS3, INTUOS3L, CINTIQ, + WACOM_BEE, WACOM_MO, MAX_TYPE }; diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index 58934a40f5ce..57a1c28bf122 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -213,7 +213,7 @@ static int ads7846_read12_ser(struct device *dev, unsigned command) struct ads7846 *ts = dev_get_drvdata(dev); struct ser_req *req = kzalloc(sizeof *req, GFP_KERNEL); int status; - int sample; + int uninitialized_var(sample); int use_internal; if (!req) diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c index 9cef6fcf587b..d4ad6992f776 100644 --- a/drivers/isdn/i4l/isdn_common.c +++ b/drivers/isdn/i4l/isdn_common.c @@ -981,13 +981,13 @@ isdn_readbchan_tty(int di, int channel, struct tty_struct *tty, int cisco_hack) } -static __inline int +static inline int isdn_minor2drv(int minor) { return (dev->drvmap[minor]); } -static __inline int +static inline int isdn_minor2chan(int minor) { return (dev->chanmap[minor]); diff --git a/drivers/isdn/i4l/isdn_v110.c b/drivers/isdn/i4l/isdn_v110.c index 5484d3c38a57..c5d02b6aafab 100644 --- a/drivers/isdn/i4l/isdn_v110.c +++ b/drivers/isdn/i4l/isdn_v110.c @@ -62,7 +62,7 @@ static unsigned char V110_OffMatrix_38400[] = * and to 67452301 when keylen = 2. This is necessary because ordering on * the isdn line is the other way. */ -static __inline unsigned char +static inline unsigned char FlipBits(unsigned char c, int keylen) { unsigned char b = c; diff --git a/drivers/lguest/core.c b/drivers/lguest/core.c index 7743d73768df..c632c08cbbdc 100644 --- a/drivers/lguest/core.c +++ b/drivers/lguest/core.c @@ -69,11 +69,22 @@ static __init int map_switcher(void) switcher_page[i] = virt_to_page(addr); } + /* First we check that the Switcher won't overlap the fixmap area at + * the top of memory. It's currently nowhere near, but it could have + * very strange effects if it ever happened. */ + if (SWITCHER_ADDR + (TOTAL_SWITCHER_PAGES+1)*PAGE_SIZE > FIXADDR_START){ + err = -ENOMEM; + printk("lguest: mapping switcher would thwack fixmap\n"); + goto free_pages; + } + /* Now we reserve the "virtual memory area" we want: 0xFFC00000 * (SWITCHER_ADDR). We might not get it in theory, but in practice - * it's worked so far. */ + * it's worked so far. The end address needs +1 because __get_vm_area + * allocates an extra guard page, so we need space for that. */ switcher_vma = __get_vm_area(TOTAL_SWITCHER_PAGES * PAGE_SIZE, - VM_ALLOC, SWITCHER_ADDR, VMALLOC_END); + VM_ALLOC, SWITCHER_ADDR, SWITCHER_ADDR + + (TOTAL_SWITCHER_PAGES+1) * PAGE_SIZE); if (!switcher_vma) { err = -ENOMEM; printk("lguest: could not map switcher pages high\n"); diff --git a/drivers/lguest/lguest_user.c b/drivers/lguest/lguest_user.c index 85d42d3d01a9..2221485b0773 100644 --- a/drivers/lguest/lguest_user.c +++ b/drivers/lguest/lguest_user.c @@ -241,15 +241,16 @@ static ssize_t write(struct file *file, const char __user *in, cpu = &lg->cpus[cpu_id]; if (!cpu) return -EINVAL; - } - /* Once the Guest is dead, all you can do is read() why it died. */ - if (lg && lg->dead) - return -ENOENT; + /* Once the Guest is dead, you can only read() why it died. */ + if (lg->dead) + return -ENOENT; - /* If you're not the task which owns the Guest, you can only break */ - if (lg && current != cpu->tsk && req != LHREQ_BREAK) - return -EPERM; + /* If you're not the task which owns the Guest, all you can do + * is break the Launcher out of running the Guest. */ + if (current != cpu->tsk && req != LHREQ_BREAK) + return -EPERM; + } switch (req) { case LHREQ_INITIALIZE: diff --git a/drivers/lguest/page_tables.c b/drivers/lguest/page_tables.c index 275f23c2deb4..a7f64a9d67e0 100644 --- a/drivers/lguest/page_tables.c +++ b/drivers/lguest/page_tables.c @@ -391,7 +391,7 @@ static unsigned int find_pgdir(struct lguest *lg, unsigned long pgtable) { unsigned int i; for (i = 0; i < ARRAY_SIZE(lg->pgdirs); i++) - if (lg->pgdirs[i].gpgdir == pgtable) + if (lg->pgdirs[i].pgdir && lg->pgdirs[i].gpgdir == pgtable) break; return i; } diff --git a/drivers/macintosh/via-pmu-backlight.c b/drivers/macintosh/via-pmu-backlight.c index 741a2e3f4fc6..a348bb0791d3 100644 --- a/drivers/macintosh/via-pmu-backlight.c +++ b/drivers/macintosh/via-pmu-backlight.c @@ -17,7 +17,7 @@ static struct backlight_ops pmu_backlight_data; static DEFINE_SPINLOCK(pmu_backlight_lock); -static int sleeping; +static int sleeping, uses_pmu_bl; static u8 bl_curve[FB_BACKLIGHT_LEVELS]; static void pmu_backlight_init_curve(u8 off, u8 min, u8 max) @@ -128,7 +128,7 @@ void pmu_backlight_set_sleep(int sleep) spin_lock_irqsave(&pmu_backlight_lock, flags); sleeping = sleep; - if (pmac_backlight) { + if (pmac_backlight && uses_pmu_bl) { if (sleep) { struct adb_request req; @@ -166,6 +166,7 @@ void __init pmu_backlight_init() printk(KERN_ERR "PMU Backlight registration failed\n"); return; } + uses_pmu_bl = 1; bd->props.max_brightness = FB_BACKLIGHT_LEVELS - 1; pmu_backlight_init_curve(0x7F, 0x46, 0x0E); diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index ebec663d5d37..d6365a9f0637 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -2528,7 +2528,7 @@ EXPORT_SYMBOL(pmu_wait_complete); EXPORT_SYMBOL(pmu_suspend); EXPORT_SYMBOL(pmu_resume); EXPORT_SYMBOL(pmu_unlock); -#if defined(CONFIG_SUSPEND) && defined(CONFIG_PPC32) +#if defined(CONFIG_PPC32) EXPORT_SYMBOL(pmu_enable_irled); EXPORT_SYMBOL(pmu_battery_count); EXPORT_SYMBOL(pmu_batteries); diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 831aed9c56ff..c14dacdacfac 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -1045,7 +1045,8 @@ void bitmap_daemon_work(struct bitmap *bitmap) if (bitmap == NULL) return; if (time_before(jiffies, bitmap->daemon_lastrun + bitmap->daemon_sleep*HZ)) - return; + goto done; + bitmap->daemon_lastrun = jiffies; if (bitmap->allclean) { bitmap->mddev->thread->timeout = MAX_SCHEDULE_TIMEOUT; @@ -1142,6 +1143,7 @@ void bitmap_daemon_work(struct bitmap *bitmap) } } + done: if (bitmap->allclean == 0) bitmap->mddev->thread->timeout = bitmap->daemon_sleep * HZ; } diff --git a/drivers/md/md.c b/drivers/md/md.c index 827824a9f3e9..ccbbf63727cc 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -5149,7 +5149,7 @@ static int md_seq_show(struct seq_file *seq, void *v) if (mddev->ro==1) seq_printf(seq, " (read-only)"); if (mddev->ro==2) - seq_printf(seq, "(auto-read-only)"); + seq_printf(seq, " (auto-read-only)"); seq_printf(seq, " %s", mddev->pers->name); } diff --git a/drivers/memstick/Kconfig b/drivers/memstick/Kconfig index 1093fdb07297..f0ca41c20323 100644 --- a/drivers/memstick/Kconfig +++ b/drivers/memstick/Kconfig @@ -8,7 +8,7 @@ menuconfig MEMSTICK Sony MemoryStick is a proprietary storage/extension card protocol. If you want MemoryStick support, you should say Y here and also - to the specific driver for your MMC interface. + to the specific driver for your MemoryStick interface. if MEMSTICK diff --git a/drivers/memstick/core/memstick.c b/drivers/memstick/core/memstick.c index bba467fe4bce..de80dba12f9b 100644 --- a/drivers/memstick/core/memstick.c +++ b/drivers/memstick/core/memstick.c @@ -18,7 +18,6 @@ #include <linux/delay.h> #define DRIVER_NAME "memstick" -#define DRIVER_VERSION "0.2" static unsigned int cmd_retries = 3; module_param(cmd_retries, uint, 0644); @@ -236,7 +235,7 @@ int memstick_next_req(struct memstick_host *host, struct memstick_request **mrq) rc = host->card->next_request(host->card, mrq); if (!rc) - host->retries = cmd_retries; + host->retries = cmd_retries > 1 ? cmd_retries - 1 : 1; else *mrq = NULL; @@ -271,7 +270,7 @@ void memstick_init_req_sg(struct memstick_request *mrq, unsigned char tpc, mrq->data_dir = READ; mrq->sg = *sg; - mrq->io_type = MEMSTICK_IO_SG; + mrq->long_data = 1; if (tpc == MS_TPC_SET_CMD || tpc == MS_TPC_EX_SET_CMD) mrq->need_card_int = 1; @@ -306,7 +305,7 @@ void memstick_init_req(struct memstick_request *mrq, unsigned char tpc, if (mrq->data_dir == WRITE) memcpy(mrq->data, buf, mrq->data_len); - mrq->io_type = MEMSTICK_IO_VAL; + mrq->long_data = 0; if (tpc == MS_TPC_SET_CMD || tpc == MS_TPC_EX_SET_CMD) mrq->need_card_int = 1; @@ -561,6 +560,31 @@ void memstick_free_host(struct memstick_host *host) } EXPORT_SYMBOL(memstick_free_host); +/** + * memstick_suspend_host - notify bus driver of host suspension + * @host - host to use + */ +void memstick_suspend_host(struct memstick_host *host) +{ + mutex_lock(&host->lock); + host->set_param(host, MEMSTICK_POWER, MEMSTICK_POWER_OFF); + mutex_unlock(&host->lock); +} +EXPORT_SYMBOL(memstick_suspend_host); + +/** + * memstick_resume_host - notify bus driver of host resumption + * @host - host to use + */ +void memstick_resume_host(struct memstick_host *host) +{ + mutex_lock(&host->lock); + host->set_param(host, MEMSTICK_POWER, MEMSTICK_POWER_ON); + mutex_unlock(&host->lock); + memstick_detect_change(host); +} +EXPORT_SYMBOL(memstick_resume_host); + int memstick_register_driver(struct memstick_driver *drv) { drv->driver.bus = &memstick_bus_type; @@ -611,4 +635,3 @@ module_exit(memstick_exit); MODULE_AUTHOR("Alex Dubov"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Sony MemoryStick core driver"); -MODULE_VERSION(DRIVER_VERSION); diff --git a/drivers/memstick/core/mspro_block.c b/drivers/memstick/core/mspro_block.c index 423ad8cf4bb9..1d637e4561d3 100644 --- a/drivers/memstick/core/mspro_block.c +++ b/drivers/memstick/core/mspro_block.c @@ -16,10 +16,10 @@ #include <linux/idr.h> #include <linux/hdreg.h> #include <linux/kthread.h> +#include <linux/delay.h> #include <linux/memstick.h> #define DRIVER_NAME "mspro_block" -#define DRIVER_VERSION "0.2" static int major; module_param(major, int, 0644); @@ -110,6 +110,17 @@ struct mspro_mbr { unsigned int sectors_per_partition; } __attribute__((packed)); +struct mspro_specfile { + char name[8]; + char ext[3]; + unsigned char attr; + unsigned char reserved[10]; + unsigned short time; + unsigned short date; + unsigned short cluster; + unsigned int size; +} __attribute__((packed)); + struct mspro_devinfo { unsigned short cylinders; unsigned short heads; @@ -293,6 +304,20 @@ static ssize_t mspro_block_attr_show_sysinfo(struct device *dev, dev_attr); struct mspro_sys_info *x_sys = x_attr->data; ssize_t rc = 0; + int date_tz = 0, date_tz_f = 0; + + if (x_sys->assembly_date[0] > 0x80U) { + date_tz = (~x_sys->assembly_date[0]) + 1; + date_tz_f = date_tz & 3; + date_tz >>= 2; + date_tz = -date_tz; + date_tz_f *= 15; + } else if (x_sys->assembly_date[0] < 0x80U) { + date_tz = x_sys->assembly_date[0]; + date_tz_f = date_tz & 3; + date_tz >>= 2; + date_tz_f *= 15; + } rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "class: %x\n", x_sys->class); @@ -305,8 +330,8 @@ static ssize_t mspro_block_attr_show_sysinfo(struct device *dev, rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "page size: %x\n", be16_to_cpu(x_sys->page_size)); rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "assembly date: " - "%d %04u-%02u-%02u %02u:%02u:%02u\n", - x_sys->assembly_date[0], + "GMT%+d:%d %04u-%02u-%02u %02u:%02u:%02u\n", + date_tz, date_tz_f, be16_to_cpu(*(unsigned short *) &x_sys->assembly_date[1]), x_sys->assembly_date[3], x_sys->assembly_date[4], @@ -398,6 +423,41 @@ static ssize_t mspro_block_attr_show_mbr(struct device *dev, return rc; } +static ssize_t mspro_block_attr_show_specfile(struct device *dev, + struct device_attribute *attr, + char *buffer) +{ + struct mspro_sys_attr *x_attr = container_of(attr, + struct mspro_sys_attr, + dev_attr); + struct mspro_specfile *x_spfile = x_attr->data; + char name[9], ext[4]; + ssize_t rc = 0; + + memcpy(name, x_spfile->name, 8); + name[8] = 0; + memcpy(ext, x_spfile->ext, 3); + ext[3] = 0; + + rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "name: %s\n", name); + rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "ext: %s\n", ext); + rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "attribute: %x\n", + x_spfile->attr); + rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "time: %d:%d:%d\n", + x_spfile->time >> 11, + (x_spfile->time >> 5) & 0x3f, + (x_spfile->time & 0x1f) * 2); + rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "date: %d-%d-%d\n", + (x_spfile->date >> 9) + 1980, + (x_spfile->date >> 5) & 0xf, + x_spfile->date & 0x1f); + rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "start cluster: %x\n", + x_spfile->cluster); + rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "size: %x\n", + x_spfile->size); + return rc; +} + static ssize_t mspro_block_attr_show_devinfo(struct device *dev, struct device_attribute *attr, char *buffer) @@ -430,6 +490,9 @@ static sysfs_show_t mspro_block_attr_show(unsigned char tag) return mspro_block_attr_show_modelname; case MSPRO_BLOCK_ID_MBR: return mspro_block_attr_show_mbr; + case MSPRO_BLOCK_ID_SPECFILEVALUES1: + case MSPRO_BLOCK_ID_SPECFILEVALUES2: + return mspro_block_attr_show_specfile; case MSPRO_BLOCK_ID_DEVINFO: return mspro_block_attr_show_devinfo; default: @@ -629,7 +692,7 @@ static void mspro_block_process_request(struct memstick_dev *card, param.system = msb->system; param.data_count = cpu_to_be16(page_count); param.data_address = cpu_to_be32((uint32_t)t_sec); - param.cmd_param = 0; + param.tpc_param = 0; msb->data_dir = rq_data_dir(req); msb->transfer_cmd = msb->data_dir == READ @@ -758,10 +821,10 @@ static int mspro_block_switch_to_parallel(struct memstick_dev *card) struct memstick_host *host = card->host; struct mspro_block_data *msb = memstick_get_drvdata(card); struct mspro_param_register param = { - .system = 0, + .system = MEMSTICK_SYS_PAR4, .data_count = 0, .data_address = 0, - .cmd_param = 0 + .tpc_param = 0 }; card->next_request = h_mspro_block_req_init; @@ -773,8 +836,8 @@ static int mspro_block_switch_to_parallel(struct memstick_dev *card) if (card->current_mrq.error) return card->current_mrq.error; - msb->system = 0; - host->set_param(host, MEMSTICK_INTERFACE, MEMSTICK_PARALLEL); + msb->system = MEMSTICK_SYS_PAR4; + host->set_param(host, MEMSTICK_INTERFACE, MEMSTICK_PAR4); card->next_request = h_mspro_block_req_init; msb->mrq_handler = h_mspro_block_default; @@ -783,8 +846,24 @@ static int mspro_block_switch_to_parallel(struct memstick_dev *card) wait_for_completion(&card->mrq_complete); if (card->current_mrq.error) { - msb->system = 0x80; + msb->system = MEMSTICK_SYS_SERIAL; + host->set_param(host, MEMSTICK_POWER, MEMSTICK_POWER_OFF); + msleep(1000); + host->set_param(host, MEMSTICK_POWER, MEMSTICK_POWER_ON); host->set_param(host, MEMSTICK_INTERFACE, MEMSTICK_SERIAL); + + if (memstick_set_rw_addr(card)) + return card->current_mrq.error; + + param.system = msb->system; + + card->next_request = h_mspro_block_req_init; + msb->mrq_handler = h_mspro_block_default; + memstick_init_req(&card->current_mrq, MS_TPC_WRITE_REG, ¶m, + sizeof(param)); + memstick_new_req(host); + wait_for_completion(&card->mrq_complete); + return -EFAULT; } @@ -802,7 +881,7 @@ static int mspro_block_read_attributes(struct memstick_dev *card) .system = msb->system, .data_count = cpu_to_be16(1), .data_address = 0, - .cmd_param = 0 + .tpc_param = 0 }; struct mspro_attribute *attr = NULL; struct mspro_sys_attr *s_attr = NULL; @@ -922,7 +1001,7 @@ static int mspro_block_read_attributes(struct memstick_dev *card) param.system = msb->system; param.data_count = cpu_to_be16((rc / msb->page_size) + 1); param.data_address = cpu_to_be32(addr / msb->page_size); - param.cmd_param = 0; + param.tpc_param = 0; sg_init_one(&msb->req_sg[0], buffer, be16_to_cpu(param.data_count) * msb->page_size); @@ -964,7 +1043,7 @@ static int mspro_block_init_card(struct memstick_dev *card) struct memstick_host *host = card->host; int rc = 0; - msb->system = 0x80; + msb->system = MEMSTICK_SYS_SERIAL; card->reg_addr.r_offset = offsetof(struct mspro_register, status); card->reg_addr.r_length = sizeof(struct ms_status_register); card->reg_addr.w_offset = offsetof(struct mspro_register, param); @@ -973,7 +1052,7 @@ static int mspro_block_init_card(struct memstick_dev *card) if (memstick_set_rw_addr(card)) return -EIO; - if (host->caps & MEMSTICK_CAP_PARALLEL) { + if (host->caps & MEMSTICK_CAP_PAR4) { if (mspro_block_switch_to_parallel(card)) printk(KERN_WARNING "%s: could not switch to " "parallel interface\n", card->dev.bus_id); @@ -1348,4 +1427,3 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Alex Dubov"); MODULE_DESCRIPTION("Sony MemoryStickPro block device driver"); MODULE_DEVICE_TABLE(memstick, mspro_block_id_tbl); -MODULE_VERSION(DRIVER_VERSION); diff --git a/drivers/memstick/host/Kconfig b/drivers/memstick/host/Kconfig index c002fcc3c879..4ce5c8dffb68 100644 --- a/drivers/memstick/host/Kconfig +++ b/drivers/memstick/host/Kconfig @@ -20,3 +20,13 @@ config MEMSTICK_TIFM_MS To compile this driver as a module, choose M here: the module will be called tifm_ms. +config MEMSTICK_JMICRON_38X + tristate "JMicron JMB38X MemoryStick interface support (EXPERIMENTAL)" + depends on EXPERIMENTAL && PCI + + help + Say Y here if you want to be able to access MemoryStick cards with + the JMicron(R) JMB38X MemoryStick card reader. + + To compile this driver as a module, choose M here: the + module will be called jmb38x_ms. diff --git a/drivers/memstick/host/Makefile b/drivers/memstick/host/Makefile index ee666380efa1..12530e4311d3 100644 --- a/drivers/memstick/host/Makefile +++ b/drivers/memstick/host/Makefile @@ -3,8 +3,8 @@ # ifeq ($(CONFIG_MEMSTICK_DEBUG),y) - EXTRA_CFLAGS += -DDEBUG + EXTRA_CFLAGS += -DDEBUG endif -obj-$(CONFIG_MEMSTICK_TIFM_MS) += tifm_ms.o - +obj-$(CONFIG_MEMSTICK_TIFM_MS) += tifm_ms.o +obj-$(CONFIG_MEMSTICK_JMICRON_38X) += jmb38x_ms.o diff --git a/drivers/memstick/host/jmb38x_ms.c b/drivers/memstick/host/jmb38x_ms.c new file mode 100644 index 000000000000..03fe8783b1ee --- /dev/null +++ b/drivers/memstick/host/jmb38x_ms.c @@ -0,0 +1,945 @@ +/* + * jmb38x_ms.c - JMicron jmb38x MemoryStick card reader + * + * Copyright (C) 2008 Alex Dubov <oakad@yahoo.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include <linux/spinlock.h> +#include <linux/interrupt.h> +#include <linux/pci.h> +#include <linux/delay.h> +#include <linux/highmem.h> +#include <linux/memstick.h> + +#define DRIVER_NAME "jmb38x_ms" + +static int no_dma; +module_param(no_dma, bool, 0644); + +enum { + DMA_ADDRESS = 0x00, + BLOCK = 0x04, + DMA_CONTROL = 0x08, + TPC_P0 = 0x0c, + TPC_P1 = 0x10, + TPC = 0x14, + HOST_CONTROL = 0x18, + DATA = 0x1c, + STATUS = 0x20, + INT_STATUS = 0x24, + INT_STATUS_ENABLE = 0x28, + INT_SIGNAL_ENABLE = 0x2c, + TIMER = 0x30, + TIMER_CONTROL = 0x34, + PAD_OUTPUT_ENABLE = 0x38, + PAD_PU_PD = 0x3c, + CLOCK_DELAY = 0x40, + ADMA_ADDRESS = 0x44, + CLOCK_CONTROL = 0x48, + LED_CONTROL = 0x4c, + VERSION = 0x50 +}; + +struct jmb38x_ms_host { + struct jmb38x_ms *chip; + void __iomem *addr; + spinlock_t lock; + int id; + char host_id[DEVICE_ID_SIZE]; + int irq; + unsigned int block_pos; + unsigned long timeout_jiffies; + struct timer_list timer; + struct memstick_request *req; + unsigned char eject:1, + use_dma:1; + unsigned char cmd_flags; + unsigned char io_pos; + unsigned int io_word[2]; +}; + +struct jmb38x_ms { + struct pci_dev *pdev; + int host_cnt; + struct memstick_host *hosts[]; +}; + +#define BLOCK_COUNT_MASK 0xffff0000 +#define BLOCK_SIZE_MASK 0x00000fff + +#define DMA_CONTROL_ENABLE 0x00000001 + +#define TPC_DATA_SEL 0x00008000 +#define TPC_DIR 0x00004000 +#define TPC_WAIT_INT 0x00002000 +#define TPC_GET_INT 0x00000800 +#define TPC_CODE_SZ_MASK 0x00000700 +#define TPC_DATA_SZ_MASK 0x00000007 + +#define HOST_CONTROL_RESET_REQ 0x00008000 +#define HOST_CONTROL_REI 0x00004000 +#define HOST_CONTROL_LED 0x00000400 +#define HOST_CONTROL_FAST_CLK 0x00000200 +#define HOST_CONTROL_RESET 0x00000100 +#define HOST_CONTROL_POWER_EN 0x00000080 +#define HOST_CONTROL_CLOCK_EN 0x00000040 +#define HOST_CONTROL_IF_SHIFT 4 + +#define HOST_CONTROL_IF_SERIAL 0x0 +#define HOST_CONTROL_IF_PAR4 0x1 +#define HOST_CONTROL_IF_PAR8 0x3 + +#define STATUS_HAS_MEDIA 0x00000400 +#define STATUS_FIFO_EMPTY 0x00000200 +#define STATUS_FIFO_FULL 0x00000100 + +#define INT_STATUS_TPC_ERR 0x00080000 +#define INT_STATUS_CRC_ERR 0x00040000 +#define INT_STATUS_TIMER_TO 0x00020000 +#define INT_STATUS_HSK_TO 0x00010000 +#define INT_STATUS_ANY_ERR 0x00008000 +#define INT_STATUS_FIFO_WRDY 0x00000080 +#define INT_STATUS_FIFO_RRDY 0x00000040 +#define INT_STATUS_MEDIA_OUT 0x00000010 +#define INT_STATUS_MEDIA_IN 0x00000008 +#define INT_STATUS_DMA_BOUNDARY 0x00000004 +#define INT_STATUS_EOTRAN 0x00000002 +#define INT_STATUS_EOTPC 0x00000001 + +#define INT_STATUS_ALL 0x000f801f + +#define PAD_OUTPUT_ENABLE_MS 0x0F3F + +#define PAD_PU_PD_OFF 0x7FFF0000 +#define PAD_PU_PD_ON_MS_SOCK0 0x5f8f0000 +#define PAD_PU_PD_ON_MS_SOCK1 0x0f0f0000 + +enum { + CMD_READY = 0x01, + FIFO_READY = 0x02, + REG_DATA = 0x04, + AUTO_GET_INT = 0x08 +}; + +static unsigned int jmb38x_ms_read_data(struct jmb38x_ms_host *host, + unsigned char *buf, unsigned int length) +{ + unsigned int off = 0; + + while (host->io_pos && length) { + buf[off++] = host->io_word[0] & 0xff; + host->io_word[0] >>= 8; + length--; + host->io_pos--; + } + + if (!length) + return off; + + while (!(STATUS_FIFO_EMPTY & readl(host->addr + STATUS))) { + if (length < 4) + break; + *(unsigned int *)(buf + off) = __raw_readl(host->addr + DATA); + length -= 4; + off += 4; + } + + if (length + && !(STATUS_FIFO_EMPTY & readl(host->addr + STATUS))) { + host->io_word[0] = readl(host->addr + DATA); + for (host->io_pos = 4; host->io_pos; --host->io_pos) { + buf[off++] = host->io_word[0] & 0xff; + host->io_word[0] >>= 8; + length--; + if (!length) + break; + } + } + + return off; +} + +static unsigned int jmb38x_ms_read_reg_data(struct jmb38x_ms_host *host, + unsigned char *buf, + unsigned int length) +{ + unsigned int off = 0; + + while (host->io_pos > 4 && length) { + buf[off++] = host->io_word[0] & 0xff; + host->io_word[0] >>= 8; + length--; + host->io_pos--; + } + + if (!length) + return off; + + while (host->io_pos && length) { + buf[off++] = host->io_word[1] & 0xff; + host->io_word[1] >>= 8; + length--; + host->io_pos--; + } + + return off; +} + +static unsigned int jmb38x_ms_write_data(struct jmb38x_ms_host *host, + unsigned char *buf, + unsigned int length) +{ + unsigned int off = 0; + + if (host->io_pos) { + while (host->io_pos < 4 && length) { + host->io_word[0] |= buf[off++] << (host->io_pos * 8); + host->io_pos++; + length--; + } + } + + if (host->io_pos == 4 + && !(STATUS_FIFO_FULL & readl(host->addr + STATUS))) { + writel(host->io_word[0], host->addr + DATA); + host->io_pos = 0; + host->io_word[0] = 0; + } else if (host->io_pos) { + return off; + } + + if (!length) + return off; + + while (!(STATUS_FIFO_FULL & readl(host->addr + STATUS))) { + if (length < 4) + break; + + __raw_writel(*(unsigned int *)(buf + off), + host->addr + DATA); + length -= 4; + off += 4; + } + + switch (length) { + case 3: + host->io_word[0] |= buf[off + 2] << 16; + host->io_pos++; + case 2: + host->io_word[0] |= buf[off + 1] << 8; + host->io_pos++; + case 1: + host->io_word[0] |= buf[off]; + host->io_pos++; + } + + off += host->io_pos; + + return off; +} + +static unsigned int jmb38x_ms_write_reg_data(struct jmb38x_ms_host *host, + unsigned char *buf, + unsigned int length) +{ + unsigned int off = 0; + + while (host->io_pos < 4 && length) { + host->io_word[0] &= ~(0xff << (host->io_pos * 8)); + host->io_word[0] |= buf[off++] << (host->io_pos * 8); + host->io_pos++; + length--; + } + + if (!length) + return off; + + while (host->io_pos < 8 && length) { + host->io_word[1] &= ~(0xff << (host->io_pos * 8)); + host->io_word[1] |= buf[off++] << (host->io_pos * 8); + host->io_pos++; + length--; + } + + return off; +} + +static int jmb38x_ms_transfer_data(struct jmb38x_ms_host *host) +{ + unsigned int length; + unsigned int off; + unsigned int t_size, p_off, p_cnt; + unsigned char *buf; + struct page *pg; + unsigned long flags = 0; + + if (host->req->long_data) { + length = host->req->sg.length - host->block_pos; + off = host->req->sg.offset + host->block_pos; + } else { + length = host->req->data_len - host->block_pos; + off = 0; + } + + while (length) { + if (host->req->long_data) { + pg = nth_page(sg_page(&host->req->sg), + off >> PAGE_SHIFT); + p_off = offset_in_page(off); + p_cnt = PAGE_SIZE - p_off; + p_cnt = min(p_cnt, length); + + local_irq_save(flags); + buf = kmap_atomic(pg, KM_BIO_SRC_IRQ) + p_off; + } else { + buf = host->req->data + host->block_pos; + p_cnt = host->req->data_len - host->block_pos; + } + + if (host->req->data_dir == WRITE) + t_size = !(host->cmd_flags & REG_DATA) + ? jmb38x_ms_write_data(host, buf, p_cnt) + : jmb38x_ms_write_reg_data(host, buf, p_cnt); + else + t_size = !(host->cmd_flags & REG_DATA) + ? jmb38x_ms_read_data(host, buf, p_cnt) + : jmb38x_ms_read_reg_data(host, buf, p_cnt); + + if (host->req->long_data) { + kunmap_atomic(buf - p_off, KM_BIO_SRC_IRQ); + local_irq_restore(flags); + } + + if (!t_size) + break; + host->block_pos += t_size; + length -= t_size; + off += t_size; + } + + if (!length && host->req->data_dir == WRITE) { + if (host->cmd_flags & REG_DATA) { + writel(host->io_word[0], host->addr + TPC_P0); + writel(host->io_word[1], host->addr + TPC_P1); + } else if (host->io_pos) { + writel(host->io_word[0], host->addr + DATA); + } + } + + return length; +} + +static int jmb38x_ms_issue_cmd(struct memstick_host *msh) +{ + struct jmb38x_ms_host *host = memstick_priv(msh); + unsigned char *data; + unsigned int data_len, cmd, t_val; + + if (!(STATUS_HAS_MEDIA & readl(host->addr + STATUS))) { + dev_dbg(msh->cdev.dev, "no media status\n"); + host->req->error = -ETIME; + return host->req->error; + } + + dev_dbg(msh->cdev.dev, "control %08x\n", + readl(host->addr + HOST_CONTROL)); + dev_dbg(msh->cdev.dev, "status %08x\n", readl(host->addr + INT_STATUS)); + dev_dbg(msh->cdev.dev, "hstatus %08x\n", readl(host->addr + STATUS)); + + host->cmd_flags = 0; + host->block_pos = 0; + host->io_pos = 0; + host->io_word[0] = 0; + host->io_word[1] = 0; + + cmd = host->req->tpc << 16; + cmd |= TPC_DATA_SEL; + + if (host->req->data_dir == READ) + cmd |= TPC_DIR; + if (host->req->need_card_int) + cmd |= TPC_WAIT_INT; + if (host->req->get_int_reg) + cmd |= TPC_GET_INT; + + data = host->req->data; + + host->use_dma = !no_dma; + + if (host->req->long_data) { + data_len = host->req->sg.length; + } else { + data_len = host->req->data_len; + host->use_dma = 0; + } + + if (data_len <= 8) { + cmd &= ~(TPC_DATA_SEL | 0xf); + host->cmd_flags |= REG_DATA; + cmd |= data_len & 0xf; + host->use_dma = 0; + } + + if (host->use_dma) { + if (1 != pci_map_sg(host->chip->pdev, &host->req->sg, 1, + host->req->data_dir == READ + ? PCI_DMA_FROMDEVICE + : PCI_DMA_TODEVICE)) { + host->req->error = -ENOMEM; + return host->req->error; + } + data_len = sg_dma_len(&host->req->sg); + writel(sg_dma_address(&host->req->sg), + host->addr + DMA_ADDRESS); + writel(((1 << 16) & BLOCK_COUNT_MASK) + | (data_len & BLOCK_SIZE_MASK), + host->addr + BLOCK); + writel(DMA_CONTROL_ENABLE, host->addr + DMA_CONTROL); + } else if (!(host->cmd_flags & REG_DATA)) { + writel(((1 << 16) & BLOCK_COUNT_MASK) + | (data_len & BLOCK_SIZE_MASK), + host->addr + BLOCK); + t_val = readl(host->addr + INT_STATUS_ENABLE); + t_val |= host->req->data_dir == READ + ? INT_STATUS_FIFO_RRDY + : INT_STATUS_FIFO_WRDY; + + writel(t_val, host->addr + INT_STATUS_ENABLE); + writel(t_val, host->addr + INT_SIGNAL_ENABLE); + } else { + cmd &= ~(TPC_DATA_SEL | 0xf); + host->cmd_flags |= REG_DATA; + cmd |= data_len & 0xf; + + if (host->req->data_dir == WRITE) { + jmb38x_ms_transfer_data(host); + writel(host->io_word[0], host->addr + TPC_P0); + writel(host->io_word[1], host->addr + TPC_P1); + } + } + + mod_timer(&host->timer, jiffies + host->timeout_jiffies); + writel(HOST_CONTROL_LED | readl(host->addr + HOST_CONTROL), + host->addr + HOST_CONTROL); + host->req->error = 0; + + writel(cmd, host->addr + TPC); + dev_dbg(msh->cdev.dev, "executing TPC %08x, len %x\n", cmd, data_len); + + return 0; +} + +static void jmb38x_ms_complete_cmd(struct memstick_host *msh, int last) +{ + struct jmb38x_ms_host *host = memstick_priv(msh); + unsigned int t_val = 0; + int rc; + + del_timer(&host->timer); + + dev_dbg(msh->cdev.dev, "c control %08x\n", + readl(host->addr + HOST_CONTROL)); + dev_dbg(msh->cdev.dev, "c status %08x\n", + readl(host->addr + INT_STATUS)); + dev_dbg(msh->cdev.dev, "c hstatus %08x\n", readl(host->addr + STATUS)); + + if (host->req->get_int_reg) { + t_val = readl(host->addr + TPC_P0); + host->req->int_reg = (t_val & 0xff); + } + + if (host->use_dma) { + writel(0, host->addr + DMA_CONTROL); + pci_unmap_sg(host->chip->pdev, &host->req->sg, 1, + host->req->data_dir == READ + ? PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE); + } else { + t_val = readl(host->addr + INT_STATUS_ENABLE); + if (host->req->data_dir == READ) + t_val &= ~INT_STATUS_FIFO_RRDY; + else + t_val &= ~INT_STATUS_FIFO_WRDY; + + writel(t_val, host->addr + INT_STATUS_ENABLE); + writel(t_val, host->addr + INT_SIGNAL_ENABLE); + } + + writel((~HOST_CONTROL_LED) & readl(host->addr + HOST_CONTROL), + host->addr + HOST_CONTROL); + + if (!last) { + do { + rc = memstick_next_req(msh, &host->req); + } while (!rc && jmb38x_ms_issue_cmd(msh)); + } else { + do { + rc = memstick_next_req(msh, &host->req); + if (!rc) + host->req->error = -ETIME; + } while (!rc); + } +} + +static irqreturn_t jmb38x_ms_isr(int irq, void *dev_id) +{ + struct memstick_host *msh = dev_id; + struct jmb38x_ms_host *host = memstick_priv(msh); + unsigned int irq_status; + + spin_lock(&host->lock); + irq_status = readl(host->addr + INT_STATUS); + dev_dbg(&host->chip->pdev->dev, "irq_status = %08x\n", irq_status); + if (irq_status == 0 || irq_status == (~0)) { + spin_unlock(&host->lock); + return IRQ_NONE; + } + + if (host->req) { + if (irq_status & INT_STATUS_ANY_ERR) { + if (irq_status & INT_STATUS_CRC_ERR) + host->req->error = -EILSEQ; + else + host->req->error = -ETIME; + } else { + if (host->use_dma) { + if (irq_status & INT_STATUS_EOTRAN) + host->cmd_flags |= FIFO_READY; + } else { + if (irq_status & (INT_STATUS_FIFO_RRDY + | INT_STATUS_FIFO_WRDY)) + jmb38x_ms_transfer_data(host); + + if (irq_status & INT_STATUS_EOTRAN) { + jmb38x_ms_transfer_data(host); + host->cmd_flags |= FIFO_READY; + } + } + + if (irq_status & INT_STATUS_EOTPC) { + host->cmd_flags |= CMD_READY; + if (host->cmd_flags & REG_DATA) { + if (host->req->data_dir == READ) { + host->io_word[0] + = readl(host->addr + + TPC_P0); + host->io_word[1] + = readl(host->addr + + TPC_P1); + host->io_pos = 8; + + jmb38x_ms_transfer_data(host); + } + host->cmd_flags |= FIFO_READY; + } + } + } + } + + if (irq_status & (INT_STATUS_MEDIA_IN | INT_STATUS_MEDIA_OUT)) { + dev_dbg(&host->chip->pdev->dev, "media changed\n"); + memstick_detect_change(msh); + } + + writel(irq_status, host->addr + INT_STATUS); + + if (host->req + && (((host->cmd_flags & CMD_READY) + && (host->cmd_flags & FIFO_READY)) + || host->req->error)) + jmb38x_ms_complete_cmd(msh, 0); + + spin_unlock(&host->lock); + return IRQ_HANDLED; +} + +static void jmb38x_ms_abort(unsigned long data) +{ + struct memstick_host *msh = (struct memstick_host *)data; + struct jmb38x_ms_host *host = memstick_priv(msh); + unsigned long flags; + + dev_dbg(&host->chip->pdev->dev, "abort\n"); + spin_lock_irqsave(&host->lock, flags); + if (host->req) { + host->req->error = -ETIME; + jmb38x_ms_complete_cmd(msh, 0); + } + spin_unlock_irqrestore(&host->lock, flags); +} + +static void jmb38x_ms_request(struct memstick_host *msh) +{ + struct jmb38x_ms_host *host = memstick_priv(msh); + unsigned long flags; + int rc; + + spin_lock_irqsave(&host->lock, flags); + if (host->req) { + spin_unlock_irqrestore(&host->lock, flags); + BUG(); + return; + } + + do { + rc = memstick_next_req(msh, &host->req); + } while (!rc && jmb38x_ms_issue_cmd(msh)); + spin_unlock_irqrestore(&host->lock, flags); +} + +static void jmb38x_ms_reset(struct jmb38x_ms_host *host) +{ + unsigned int host_ctl = readl(host->addr + HOST_CONTROL); + + writel(host_ctl | HOST_CONTROL_RESET_REQ | HOST_CONTROL_RESET, + host->addr + HOST_CONTROL); + + while (HOST_CONTROL_RESET_REQ + & (host_ctl = readl(host->addr + HOST_CONTROL))) { + ndelay(100); + dev_dbg(&host->chip->pdev->dev, "reset\n"); + } + + writel(INT_STATUS_ALL, host->addr + INT_STATUS_ENABLE); + writel(INT_STATUS_ALL, host->addr + INT_SIGNAL_ENABLE); + + dev_dbg(&host->chip->pdev->dev, "reset\n"); +} + +static void jmb38x_ms_set_param(struct memstick_host *msh, + enum memstick_param param, + int value) +{ + struct jmb38x_ms_host *host = memstick_priv(msh); + unsigned int host_ctl; + unsigned long flags; + + spin_lock_irqsave(&host->lock, flags); + + switch (param) { + case MEMSTICK_POWER: + if (value == MEMSTICK_POWER_ON) { + jmb38x_ms_reset(host); + + writel(host->id ? PAD_PU_PD_ON_MS_SOCK1 + : PAD_PU_PD_ON_MS_SOCK0, + host->addr + PAD_PU_PD); + + writel(PAD_OUTPUT_ENABLE_MS, + host->addr + PAD_OUTPUT_ENABLE); + + host_ctl = readl(host->addr + HOST_CONTROL); + host_ctl |= 7; + writel(host_ctl | (HOST_CONTROL_POWER_EN + | HOST_CONTROL_CLOCK_EN), + host->addr + HOST_CONTROL); + + dev_dbg(&host->chip->pdev->dev, "power on\n"); + } else if (value == MEMSTICK_POWER_OFF) { + writel(readl(host->addr + HOST_CONTROL) + & ~(HOST_CONTROL_POWER_EN + | HOST_CONTROL_CLOCK_EN), + host->addr + HOST_CONTROL); + writel(0, host->addr + PAD_OUTPUT_ENABLE); + writel(PAD_PU_PD_OFF, host->addr + PAD_PU_PD); + dev_dbg(&host->chip->pdev->dev, "power off\n"); + } + break; + case MEMSTICK_INTERFACE: + /* jmb38x_ms_reset(host); */ + + host_ctl = readl(host->addr + HOST_CONTROL); + host_ctl &= ~(3 << HOST_CONTROL_IF_SHIFT); + /* host_ctl |= 7; */ + + if (value == MEMSTICK_SERIAL) { + host_ctl &= ~HOST_CONTROL_FAST_CLK; + host_ctl |= HOST_CONTROL_IF_SERIAL + << HOST_CONTROL_IF_SHIFT; + host_ctl |= HOST_CONTROL_REI; + writel(0, host->addr + CLOCK_DELAY); + } else if (value == MEMSTICK_PAR4) { + host_ctl |= HOST_CONTROL_FAST_CLK; + host_ctl |= HOST_CONTROL_IF_PAR4 + << HOST_CONTROL_IF_SHIFT; + host_ctl &= ~HOST_CONTROL_REI; + writel(4, host->addr + CLOCK_DELAY); + } else if (value == MEMSTICK_PAR8) { + host_ctl |= HOST_CONTROL_FAST_CLK; + host_ctl |= HOST_CONTROL_IF_PAR8 + << HOST_CONTROL_IF_SHIFT; + host_ctl &= ~HOST_CONTROL_REI; + writel(4, host->addr + CLOCK_DELAY); + } + writel(host_ctl, host->addr + HOST_CONTROL); + break; + }; + + spin_unlock_irqrestore(&host->lock, flags); +} + +#ifdef CONFIG_PM + +static int jmb38x_ms_suspend(struct pci_dev *dev, pm_message_t state) +{ + struct jmb38x_ms *jm = pci_get_drvdata(dev); + int cnt; + + for (cnt = 0; cnt < jm->host_cnt; ++cnt) { + if (!jm->hosts[cnt]) + break; + memstick_suspend_host(jm->hosts[cnt]); + } + + pci_save_state(dev); + pci_enable_wake(dev, pci_choose_state(dev, state), 0); + pci_disable_device(dev); + pci_set_power_state(dev, pci_choose_state(dev, state)); + return 0; +} + +static int jmb38x_ms_resume(struct pci_dev *dev) +{ + struct jmb38x_ms *jm = pci_get_drvdata(dev); + int rc; + + pci_set_power_state(dev, PCI_D0); + pci_restore_state(dev); + rc = pci_enable_device(dev); + if (rc) + return rc; + pci_set_master(dev); + + pci_read_config_dword(dev, 0xac, &rc); + pci_write_config_dword(dev, 0xac, rc | 0x00470000); + + for (rc = 0; rc < jm->host_cnt; ++rc) { + if (!jm->hosts[rc]) + break; + memstick_resume_host(jm->hosts[rc]); + memstick_detect_change(jm->hosts[rc]); + } + + return 0; +} + +#else + +#define jmb38x_ms_suspend NULL +#define jmb38x_ms_resume NULL + +#endif /* CONFIG_PM */ + +static int jmb38x_ms_count_slots(struct pci_dev *pdev) +{ + int cnt, rc = 0; + + for (cnt = 0; cnt < PCI_ROM_RESOURCE; ++cnt) { + if (!(IORESOURCE_MEM & pci_resource_flags(pdev, cnt))) + break; + + if (256 != pci_resource_len(pdev, cnt)) + break; + + ++rc; + } + return rc; +} + +static struct memstick_host *jmb38x_ms_alloc_host(struct jmb38x_ms *jm, int cnt) +{ + struct memstick_host *msh; + struct jmb38x_ms_host *host; + + msh = memstick_alloc_host(sizeof(struct jmb38x_ms_host), + &jm->pdev->dev); + if (!msh) + return NULL; + + host = memstick_priv(msh); + host->chip = jm; + host->addr = ioremap(pci_resource_start(jm->pdev, cnt), + pci_resource_len(jm->pdev, cnt)); + if (!host->addr) + goto err_out_free; + + spin_lock_init(&host->lock); + host->id = cnt; + snprintf(host->host_id, DEVICE_ID_SIZE, DRIVER_NAME ":slot%d", + host->id); + host->irq = jm->pdev->irq; + host->timeout_jiffies = msecs_to_jiffies(4000); + msh->request = jmb38x_ms_request; + msh->set_param = jmb38x_ms_set_param; + /* + msh->caps = MEMSTICK_CAP_AUTO_GET_INT | MEMSTICK_CAP_PAR4 + | MEMSTICK_CAP_PAR8; + */ + msh->caps = MEMSTICK_CAP_PAR4 | MEMSTICK_CAP_PAR8; + + setup_timer(&host->timer, jmb38x_ms_abort, (unsigned long)msh); + + if (!request_irq(host->irq, jmb38x_ms_isr, IRQF_SHARED, host->host_id, + msh)) + return msh; + + iounmap(host->addr); +err_out_free: + kfree(msh); + return NULL; +} + +static void jmb38x_ms_free_host(struct memstick_host *msh) +{ + struct jmb38x_ms_host *host = memstick_priv(msh); + + free_irq(host->irq, msh); + iounmap(host->addr); + memstick_free_host(msh); +} + +static int jmb38x_ms_probe(struct pci_dev *pdev, + const struct pci_device_id *dev_id) +{ + struct jmb38x_ms *jm; + int pci_dev_busy = 0; + int rc, cnt; + + rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + if (rc) + return rc; + + rc = pci_enable_device(pdev); + if (rc) + return rc; + + pci_set_master(pdev); + + rc = pci_request_regions(pdev, DRIVER_NAME); + if (rc) { + pci_dev_busy = 1; + goto err_out; + } + + pci_read_config_dword(pdev, 0xac, &rc); + pci_write_config_dword(pdev, 0xac, rc | 0x00470000); + + cnt = jmb38x_ms_count_slots(pdev); + if (!cnt) { + rc = -ENODEV; + pci_dev_busy = 1; + goto err_out; + } + + jm = kzalloc(sizeof(struct jmb38x_ms) + + cnt * sizeof(struct memstick_host *), GFP_KERNEL); + if (!jm) { + rc = -ENOMEM; + goto err_out_int; + } + + jm->pdev = pdev; + jm->host_cnt = cnt; + pci_set_drvdata(pdev, jm); + + for (cnt = 0; cnt < jm->host_cnt; ++cnt) { + jm->hosts[cnt] = jmb38x_ms_alloc_host(jm, cnt); + if (!jm->hosts[cnt]) + break; + + rc = memstick_add_host(jm->hosts[cnt]); + + if (rc) { + jmb38x_ms_free_host(jm->hosts[cnt]); + jm->hosts[cnt] = NULL; + break; + } + } + + if (cnt) + return 0; + + rc = -ENODEV; + + pci_set_drvdata(pdev, NULL); + kfree(jm); +err_out_int: + pci_release_regions(pdev); +err_out: + if (!pci_dev_busy) + pci_disable_device(pdev); + return rc; +} + +static void jmb38x_ms_remove(struct pci_dev *dev) +{ + struct jmb38x_ms *jm = pci_get_drvdata(dev); + struct jmb38x_ms_host *host; + int cnt; + unsigned long flags; + + for (cnt = 0; cnt < jm->host_cnt; ++cnt) { + if (!jm->hosts[cnt]) + break; + + host = memstick_priv(jm->hosts[cnt]); + + writel(0, host->addr + INT_SIGNAL_ENABLE); + writel(0, host->addr + INT_STATUS_ENABLE); + mmiowb(); + dev_dbg(&jm->pdev->dev, "interrupts off\n"); + spin_lock_irqsave(&host->lock, flags); + if (host->req) { + host->req->error = -ETIME; + jmb38x_ms_complete_cmd(jm->hosts[cnt], 1); + } + spin_unlock_irqrestore(&host->lock, flags); + + memstick_remove_host(jm->hosts[cnt]); + dev_dbg(&jm->pdev->dev, "host removed\n"); + + jmb38x_ms_free_host(jm->hosts[cnt]); + } + + pci_set_drvdata(dev, NULL); + pci_release_regions(dev); + pci_disable_device(dev); + kfree(jm); +} + +static struct pci_device_id jmb38x_ms_id_tbl [] = { + { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB38X_MS, PCI_ANY_ID, + PCI_ANY_ID, 0, 0, 0 }, + { } +}; + +static struct pci_driver jmb38x_ms_driver = { + .name = DRIVER_NAME, + .id_table = jmb38x_ms_id_tbl, + .probe = jmb38x_ms_probe, + .remove = jmb38x_ms_remove, + .suspend = jmb38x_ms_suspend, + .resume = jmb38x_ms_resume +}; + +static int __init jmb38x_ms_init(void) +{ + return pci_register_driver(&jmb38x_ms_driver); +} + +static void __exit jmb38x_ms_exit(void) +{ + pci_unregister_driver(&jmb38x_ms_driver); +} + +MODULE_AUTHOR("Alex Dubov"); +MODULE_DESCRIPTION("JMicron jmb38x MemoryStick driver"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, jmb38x_ms_id_tbl); + +module_init(jmb38x_ms_init); +module_exit(jmb38x_ms_exit); diff --git a/drivers/memstick/host/tifm_ms.c b/drivers/memstick/host/tifm_ms.c index 4fb24215bd95..2b5bf52a8302 100644 --- a/drivers/memstick/host/tifm_ms.c +++ b/drivers/memstick/host/tifm_ms.c @@ -20,293 +20,315 @@ #include <asm/io.h> #define DRIVER_NAME "tifm_ms" -#define DRIVER_VERSION "0.1" static int no_dma; module_param(no_dma, bool, 0644); -#define TIFM_MS_TIMEOUT 0x00100 -#define TIFM_MS_BADCRC 0x00200 -#define TIFM_MS_EOTPC 0x01000 -#define TIFM_MS_INT 0x02000 - -/* The meaning of the bit majority in this constant is unknown. */ -#define TIFM_MS_SERIAL 0x04010 +/* + * Some control bits of TIFM appear to conform to Sony's reference design, + * so I'm just assuming they all are. + */ -#define TIFM_MS_SYS_LATCH 0x00100 -#define TIFM_MS_SYS_NOT_RDY 0x00800 -#define TIFM_MS_SYS_DATA 0x10000 +#define TIFM_MS_STAT_DRQ 0x04000 +#define TIFM_MS_STAT_MSINT 0x02000 +#define TIFM_MS_STAT_RDY 0x01000 +#define TIFM_MS_STAT_CRC 0x00200 +#define TIFM_MS_STAT_TOE 0x00100 +#define TIFM_MS_STAT_EMP 0x00020 +#define TIFM_MS_STAT_FUL 0x00010 +#define TIFM_MS_STAT_CED 0x00008 +#define TIFM_MS_STAT_ERR 0x00004 +#define TIFM_MS_STAT_BRQ 0x00002 +#define TIFM_MS_STAT_CNK 0x00001 + +#define TIFM_MS_SYS_DMA 0x10000 +#define TIFM_MS_SYS_RESET 0x08000 +#define TIFM_MS_SYS_SRAC 0x04000 +#define TIFM_MS_SYS_INTEN 0x02000 +#define TIFM_MS_SYS_NOCRC 0x01000 +#define TIFM_MS_SYS_INTCLR 0x00800 +#define TIFM_MS_SYS_MSIEN 0x00400 +#define TIFM_MS_SYS_FCLR 0x00200 +#define TIFM_MS_SYS_FDIR 0x00100 +#define TIFM_MS_SYS_DAM 0x00080 +#define TIFM_MS_SYS_DRM 0x00040 +#define TIFM_MS_SYS_DRQSL 0x00020 +#define TIFM_MS_SYS_REI 0x00010 +#define TIFM_MS_SYS_REO 0x00008 +#define TIFM_MS_SYS_BSY_MASK 0x00007 + +#define TIFM_MS_SYS_FIFO (TIFM_MS_SYS_INTEN | TIFM_MS_SYS_MSIEN \ + | TIFM_MS_SYS_FCLR | TIFM_MS_SYS_BSY_MASK) /* Hardware flags */ enum { - CMD_READY = 0x0001, - FIFO_READY = 0x0002, - CARD_READY = 0x0004, - DATA_CARRY = 0x0008 + CMD_READY = 0x01, + FIFO_READY = 0x02, + CARD_INT = 0x04 }; struct tifm_ms { struct tifm_dev *dev; - unsigned short eject:1, - no_dma:1; - unsigned short cmd_flags; + struct timer_list timer; + struct memstick_request *req; unsigned int mode_mask; unsigned int block_pos; unsigned long timeout_jiffies; - - struct timer_list timer; - struct memstick_request *req; + unsigned char eject:1, + use_dma:1; + unsigned char cmd_flags; + unsigned char io_pos; unsigned int io_word; }; -static void tifm_ms_read_fifo(struct tifm_ms *host, unsigned int fifo_offset, - struct page *pg, unsigned int page_off, - unsigned int length) +static unsigned int tifm_ms_read_data(struct tifm_ms *host, + unsigned char *buf, unsigned int length) { struct tifm_dev *sock = host->dev; - unsigned int cnt = 0, off = 0; - unsigned char *buf = kmap_atomic(pg, KM_BIO_DST_IRQ) + page_off; + unsigned int off = 0; + + while (host->io_pos && length) { + buf[off++] = host->io_word & 0xff; + host->io_word >>= 8; + length--; + host->io_pos--; + } - if (host->cmd_flags & DATA_CARRY) { - while ((fifo_offset & 3) && length) { + if (!length) + return off; + + while (!(TIFM_MS_STAT_EMP & readl(sock->addr + SOCK_MS_STATUS))) { + if (length < 4) + break; + *(unsigned int *)(buf + off) = __raw_readl(sock->addr + + SOCK_MS_DATA); + length -= 4; + off += 4; + } + + if (length + && !(TIFM_MS_STAT_EMP & readl(sock->addr + SOCK_MS_STATUS))) { + host->io_word = readl(sock->addr + SOCK_MS_DATA); + for (host->io_pos = 4; host->io_pos; --host->io_pos) { buf[off++] = host->io_word & 0xff; host->io_word >>= 8; length--; - fifo_offset++; + if (!length) + break; } - if (!(fifo_offset & 3)) - host->cmd_flags &= ~DATA_CARRY; - if (!length) - return; } - do { - host->io_word = readl(sock->addr + SOCK_FIFO_ACCESS - + fifo_offset); - cnt = 4; - while (length && cnt) { - buf[off++] = (host->io_word >> 8) & 0xff; - cnt--; - length--; - } - fifo_offset += 4 - cnt; - } while (length); - - if (cnt) - host->cmd_flags |= DATA_CARRY; - - kunmap_atomic(buf - page_off, KM_BIO_DST_IRQ); + return off; } -static void tifm_ms_write_fifo(struct tifm_ms *host, unsigned int fifo_offset, - struct page *pg, unsigned int page_off, - unsigned int length) +static unsigned int tifm_ms_write_data(struct tifm_ms *host, + unsigned char *buf, unsigned int length) { struct tifm_dev *sock = host->dev; - unsigned int cnt = 0, off = 0; - unsigned char *buf = kmap_atomic(pg, KM_BIO_SRC_IRQ) + page_off; + unsigned int off = 0; - if (host->cmd_flags & DATA_CARRY) { - while (fifo_offset & 3) { - host->io_word |= buf[off++] << (8 * (fifo_offset & 3)); + if (host->io_pos) { + while (host->io_pos < 4 && length) { + host->io_word |= buf[off++] << (host->io_pos * 8); + host->io_pos++; length--; - fifo_offset++; } - if (!(fifo_offset & 3)) { - writel(host->io_word, sock->addr + SOCK_FIFO_ACCESS - + fifo_offset - 4); - - host->cmd_flags &= ~DATA_CARRY; - } - if (!length) - return; } - do { - cnt = 4; + if (host->io_pos == 4 + && !(TIFM_MS_STAT_FUL & readl(sock->addr + SOCK_MS_STATUS))) { + writel(TIFM_MS_SYS_FDIR | readl(sock->addr + SOCK_MS_SYSTEM), + sock->addr + SOCK_MS_SYSTEM); + writel(host->io_word, sock->addr + SOCK_MS_DATA); + host->io_pos = 0; host->io_word = 0; - while (length && cnt) { - host->io_word |= buf[off++] << (4 - cnt); - cnt--; - length--; - } - fifo_offset += 4 - cnt; - if (!cnt) - writel(host->io_word, sock->addr + SOCK_FIFO_ACCESS - + fifo_offset - 4); - - } while (length); - - if (cnt) - host->cmd_flags |= DATA_CARRY; + } else if (host->io_pos) { + return off; + } - kunmap_atomic(buf - page_off, KM_BIO_SRC_IRQ); -} + if (!length) + return off; -static void tifm_ms_move_block(struct tifm_ms *host, unsigned int length) -{ - unsigned int t_size; - unsigned int off = host->req->sg.offset + host->block_pos; - unsigned int p_off, p_cnt; - struct page *pg; - unsigned long flags; + while (!(TIFM_MS_STAT_FUL & readl(sock->addr + SOCK_MS_STATUS))) { + if (length < 4) + break; + writel(TIFM_MS_SYS_FDIR | readl(sock->addr + SOCK_MS_SYSTEM), + sock->addr + SOCK_MS_SYSTEM); + __raw_writel(*(unsigned int *)(buf + off), + sock->addr + SOCK_MS_DATA); + length -= 4; + off += 4; + } - dev_dbg(&host->dev->dev, "moving block\n"); - local_irq_save(flags); - t_size = length; - while (t_size) { - pg = nth_page(sg_page(&host->req->sg), off >> PAGE_SHIFT); - p_off = offset_in_page(off); - p_cnt = PAGE_SIZE - p_off; - p_cnt = min(p_cnt, t_size); + switch (length) { + case 3: + host->io_word |= buf[off + 2] << 16; + host->io_pos++; + case 2: + host->io_word |= buf[off + 1] << 8; + host->io_pos++; + case 1: + host->io_word |= buf[off]; + host->io_pos++; + } - if (host->req->data_dir == WRITE) - tifm_ms_write_fifo(host, length - t_size, - pg, p_off, p_cnt); - else - tifm_ms_read_fifo(host, length - t_size, - pg, p_off, p_cnt); + off += host->io_pos; - t_size -= p_cnt; - } - local_irq_restore(flags); + return off; } -static int tifm_ms_transfer_data(struct tifm_ms *host, int skip) +static unsigned int tifm_ms_transfer_data(struct tifm_ms *host) { struct tifm_dev *sock = host->dev; - unsigned int length = host->req->sg.length - host->block_pos; + unsigned int length; + unsigned int off; + unsigned int t_size, p_off, p_cnt; + unsigned char *buf; + struct page *pg; + unsigned long flags = 0; + + if (host->req->long_data) { + length = host->req->sg.length - host->block_pos; + off = host->req->sg.offset + host->block_pos; + } else { + length = host->req->data_len - host->block_pos; + off = 0; + } + dev_dbg(&sock->dev, "fifo data transfer, %d, %d\n", length, + host->block_pos); + + while (length) { + if (host->req->long_data) { + pg = nth_page(sg_page(&host->req->sg), + off >> PAGE_SHIFT); + p_off = offset_in_page(off); + p_cnt = PAGE_SIZE - p_off; + p_cnt = min(p_cnt, length); + + local_irq_save(flags); + buf = kmap_atomic(pg, KM_BIO_SRC_IRQ) + p_off; + } else { + buf = host->req->data + host->block_pos; + p_cnt = host->req->data_len - host->block_pos; + } - if (!length) - return 1; + t_size = host->req->data_dir == WRITE + ? tifm_ms_write_data(host, buf, p_cnt) + : tifm_ms_read_data(host, buf, p_cnt); - if (length > TIFM_FIFO_SIZE) - length = TIFM_FIFO_SIZE; + if (host->req->long_data) { + kunmap_atomic(buf - p_off, KM_BIO_SRC_IRQ); + local_irq_restore(flags); + } - if (!skip) { - tifm_ms_move_block(host, length); - host->block_pos += length; + if (!t_size) + break; + host->block_pos += t_size; + length -= t_size; + off += t_size; } - if ((host->req->data_dir == READ) - && (host->block_pos == host->req->sg.length)) - return 1; - - writel(ilog2(length) - 2, sock->addr + SOCK_FIFO_PAGE_SIZE); - if (host->req->data_dir == WRITE) - writel((1 << 8) | TIFM_DMA_TX, sock->addr + SOCK_DMA_CONTROL); - else - writel((1 << 8), sock->addr + SOCK_DMA_CONTROL); + dev_dbg(&sock->dev, "fifo data transfer, %d remaining\n", length); + if (!length && (host->req->data_dir == WRITE)) { + if (host->io_pos) { + writel(TIFM_MS_SYS_FDIR + | readl(sock->addr + SOCK_MS_SYSTEM), + sock->addr + SOCK_MS_SYSTEM); + writel(host->io_word, sock->addr + SOCK_MS_DATA); + } + writel(TIFM_MS_SYS_FDIR + | readl(sock->addr + SOCK_MS_SYSTEM), + sock->addr + SOCK_MS_SYSTEM); + writel(0, sock->addr + SOCK_MS_DATA); + } else { + readl(sock->addr + SOCK_MS_DATA); + } - return 0; + return length; } static int tifm_ms_issue_cmd(struct tifm_ms *host) { struct tifm_dev *sock = host->dev; unsigned char *data; - unsigned int data_len = 0, cmd = 0, cmd_mask = 0, cnt, tval = 0; + unsigned int data_len, cmd, sys_param; host->cmd_flags = 0; + host->block_pos = 0; + host->io_pos = 0; + host->io_word = 0; + host->cmd_flags = 0; - if (host->req->io_type == MEMSTICK_IO_SG) { - if (!host->no_dma) { - if (1 != tifm_map_sg(sock, &host->req->sg, 1, - host->req->data_dir == READ - ? PCI_DMA_FROMDEVICE - : PCI_DMA_TODEVICE)) { - host->req->error = -ENOMEM; - return host->req->error; - } - data_len = sg_dma_len(&host->req->sg); - } else - data_len = host->req->sg.length; - - writel(TIFM_FIFO_INT_SETALL, - sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR); - writel(TIFM_FIFO_ENABLE, - sock->addr + SOCK_FIFO_CONTROL); - writel(TIFM_FIFO_INTMASK, - sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET); + data = host->req->data; - if (!host->no_dma) { - writel(ilog2(data_len) - 2, - sock->addr + SOCK_FIFO_PAGE_SIZE); - writel(sg_dma_address(&host->req->sg), - sock->addr + SOCK_DMA_ADDRESS); - if (host->req->data_dir == WRITE) - writel((1 << 8) | TIFM_DMA_TX | TIFM_DMA_EN, - sock->addr + SOCK_DMA_CONTROL); - else - writel((1 << 8) | TIFM_DMA_EN, - sock->addr + SOCK_DMA_CONTROL); - } else { - tifm_ms_transfer_data(host, - host->req->data_dir == READ); - } + host->use_dma = !no_dma; - cmd_mask = readl(sock->addr + SOCK_MS_SYSTEM); - cmd_mask |= TIFM_MS_SYS_DATA | TIFM_MS_SYS_NOT_RDY; - writel(cmd_mask, sock->addr + SOCK_MS_SYSTEM); - } else if (host->req->io_type == MEMSTICK_IO_VAL) { - data = host->req->data; + if (host->req->long_data) { + data_len = host->req->sg.length; + if (!is_power_of_2(data_len)) + host->use_dma = 0; + } else { data_len = host->req->data_len; + host->use_dma = 0; + } - cmd_mask = host->mode_mask | 0x2607; /* unknown constant */ - - if (host->req->data_dir == WRITE) { - cmd_mask |= TIFM_MS_SYS_LATCH; - writel(cmd_mask, sock->addr + SOCK_MS_SYSTEM); - for (cnt = 0; (data_len - cnt) >= 4; cnt += 4) { - writel(TIFM_MS_SYS_LATCH - | readl(sock->addr + SOCK_MS_SYSTEM), - sock->addr + SOCK_MS_SYSTEM); - __raw_writel(*(unsigned int *)(data + cnt), - sock->addr + SOCK_MS_DATA); - dev_dbg(&sock->dev, "writing %x\n", - *(int *)(data + cnt)); - } - switch (data_len - cnt) { - case 3: - tval |= data[cnt + 2] << 16; - case 2: - tval |= data[cnt + 1] << 8; - case 1: - tval |= data[cnt]; - writel(TIFM_MS_SYS_LATCH - | readl(sock->addr + SOCK_MS_SYSTEM), - sock->addr + SOCK_MS_SYSTEM); - writel(tval, sock->addr + SOCK_MS_DATA); - dev_dbg(&sock->dev, "writing %x\n", tval); - } + writel(TIFM_FIFO_INT_SETALL, + sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR); + writel(TIFM_FIFO_ENABLE, + sock->addr + SOCK_FIFO_CONTROL); + + if (host->use_dma) { + if (1 != tifm_map_sg(sock, &host->req->sg, 1, + host->req->data_dir == READ + ? PCI_DMA_FROMDEVICE + : PCI_DMA_TODEVICE)) { + host->req->error = -ENOMEM; + return host->req->error; + } + data_len = sg_dma_len(&host->req->sg); - writel(TIFM_MS_SYS_LATCH - | readl(sock->addr + SOCK_MS_SYSTEM), - sock->addr + SOCK_MS_SYSTEM); - writel(0, sock->addr + SOCK_MS_DATA); - dev_dbg(&sock->dev, "writing %x\n", 0); + writel(ilog2(data_len) - 2, + sock->addr + SOCK_FIFO_PAGE_SIZE); + writel(TIFM_FIFO_INTMASK, + sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET); + sys_param = TIFM_DMA_EN | (1 << 8); + if (host->req->data_dir == WRITE) + sys_param |= TIFM_DMA_TX; + + writel(TIFM_FIFO_INTMASK, + sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET); - } else - writel(cmd_mask, sock->addr + SOCK_MS_SYSTEM); + writel(sg_dma_address(&host->req->sg), + sock->addr + SOCK_DMA_ADDRESS); + writel(sys_param, sock->addr + SOCK_DMA_CONTROL); + } else { + writel(host->mode_mask | TIFM_MS_SYS_FIFO, + sock->addr + SOCK_MS_SYSTEM); - cmd_mask = readl(sock->addr + SOCK_MS_SYSTEM); - cmd_mask &= ~TIFM_MS_SYS_DATA; - cmd_mask |= TIFM_MS_SYS_NOT_RDY; - dev_dbg(&sock->dev, "mask %x\n", cmd_mask); - writel(cmd_mask, sock->addr + SOCK_MS_SYSTEM); - } else - BUG(); + writel(TIFM_FIFO_MORE, + sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET); + } mod_timer(&host->timer, jiffies + host->timeout_jiffies); writel(TIFM_CTRL_LED | readl(sock->addr + SOCK_CONTROL), sock->addr + SOCK_CONTROL); host->req->error = 0; + sys_param = readl(sock->addr + SOCK_MS_SYSTEM); + sys_param |= TIFM_MS_SYS_INTCLR; + + if (host->use_dma) + sys_param |= TIFM_MS_SYS_DMA; + else + sys_param &= ~TIFM_MS_SYS_DMA; + + writel(sys_param, sock->addr + SOCK_MS_SYSTEM); + cmd = (host->req->tpc & 0xf) << 12; cmd |= data_len; writel(cmd, sock->addr + SOCK_MS_COMMAND); - dev_dbg(&sock->dev, "executing TPC %x, %x\n", cmd, cmd_mask); + dev_dbg(&sock->dev, "executing TPC %x, %x\n", cmd, sys_param); return 0; } @@ -314,47 +336,20 @@ static void tifm_ms_complete_cmd(struct tifm_ms *host) { struct tifm_dev *sock = host->dev; struct memstick_host *msh = tifm_get_drvdata(sock); - unsigned int tval = 0, data_len; - unsigned char *data; int rc; del_timer(&host->timer); - if (host->req->io_type == MEMSTICK_IO_SG) { - if (!host->no_dma) - tifm_unmap_sg(sock, &host->req->sg, 1, - host->req->data_dir == READ - ? PCI_DMA_FROMDEVICE - : PCI_DMA_TODEVICE); - } else if (host->req->io_type == MEMSTICK_IO_VAL) { - writel(~TIFM_MS_SYS_DATA & readl(sock->addr + SOCK_MS_SYSTEM), - sock->addr + SOCK_MS_SYSTEM); - - data = host->req->data; - data_len = host->req->data_len; - if (host->req->data_dir == READ) { - for (rc = 0; (data_len - rc) >= 4; rc += 4) - *(int *)(data + rc) - = __raw_readl(sock->addr - + SOCK_MS_DATA); - - if (data_len - rc) - tval = readl(sock->addr + SOCK_MS_DATA); - switch (data_len - rc) { - case 3: - data[rc + 2] = (tval >> 16) & 0xff; - case 2: - data[rc + 1] = (tval >> 8) & 0xff; - case 1: - data[rc] = tval & 0xff; - } - readl(sock->addr + SOCK_MS_DATA); - } - } + if (host->use_dma) + tifm_unmap_sg(sock, &host->req->sg, 1, + host->req->data_dir == READ + ? PCI_DMA_FROMDEVICE + : PCI_DMA_TODEVICE); writel((~TIFM_CTRL_LED) & readl(sock->addr + SOCK_CONTROL), sock->addr + SOCK_CONTROL); + dev_dbg(&sock->dev, "TPC complete\n"); do { rc = memstick_next_req(msh, &host->req); } while (!rc && tifm_ms_issue_cmd(host)); @@ -365,11 +360,10 @@ static int tifm_ms_check_status(struct tifm_ms *host) if (!host->req->error) { if (!(host->cmd_flags & CMD_READY)) return 1; - if ((host->req->io_type == MEMSTICK_IO_SG) - && !(host->cmd_flags & FIFO_READY)) + if (!(host->cmd_flags & FIFO_READY)) return 1; if (host->req->need_card_int - && !(host->cmd_flags & CARD_READY)) + && !(host->cmd_flags & CARD_INT)) return 1; } return 0; @@ -379,18 +373,24 @@ static int tifm_ms_check_status(struct tifm_ms *host) static void tifm_ms_data_event(struct tifm_dev *sock) { struct tifm_ms *host; - unsigned int fifo_status = 0; + unsigned int fifo_status = 0, host_status = 0; int rc = 1; spin_lock(&sock->lock); host = memstick_priv((struct memstick_host *)tifm_get_drvdata(sock)); fifo_status = readl(sock->addr + SOCK_DMA_FIFO_STATUS); - dev_dbg(&sock->dev, "data event: fifo_status %x, flags %x\n", - fifo_status, host->cmd_flags); + host_status = readl(sock->addr + SOCK_MS_STATUS); + dev_dbg(&sock->dev, + "data event: fifo_status %x, host_status %x, flags %x\n", + fifo_status, host_status, host->cmd_flags); if (host->req) { - if (fifo_status & TIFM_FIFO_READY) { - if (!host->no_dma || tifm_ms_transfer_data(host, 0)) { + if (host->use_dma && (fifo_status & 1)) { + host->cmd_flags |= FIFO_READY; + rc = tifm_ms_check_status(host); + } + if (!host->use_dma && (fifo_status & TIFM_FIFO_MORE)) { + if (!tifm_ms_transfer_data(host)) { host->cmd_flags |= FIFO_READY; rc = tifm_ms_check_status(host); } @@ -419,9 +419,9 @@ static void tifm_ms_card_event(struct tifm_dev *sock) host_status, host->cmd_flags); if (host->req) { - if (host_status & TIFM_MS_TIMEOUT) + if (host_status & TIFM_MS_STAT_TOE) host->req->error = -ETIME; - else if (host_status & TIFM_MS_BADCRC) + else if (host_status & TIFM_MS_STAT_CRC) host->req->error = -EILSEQ; if (host->req->error) { @@ -430,18 +430,17 @@ static void tifm_ms_card_event(struct tifm_dev *sock) writel(TIFM_DMA_RESET, sock->addr + SOCK_DMA_CONTROL); } - if (host_status & TIFM_MS_EOTPC) + if (host_status & TIFM_MS_STAT_RDY) host->cmd_flags |= CMD_READY; - if (host_status & TIFM_MS_INT) - host->cmd_flags |= CARD_READY; + + if (host_status & TIFM_MS_STAT_MSINT) + host->cmd_flags |= CARD_INT; rc = tifm_ms_check_status(host); } - writel(TIFM_MS_SYS_NOT_RDY | readl(sock->addr + SOCK_MS_SYSTEM), - sock->addr + SOCK_MS_SYSTEM); - writel((~TIFM_MS_SYS_DATA) & readl(sock->addr + SOCK_MS_SYSTEM), + writel(TIFM_MS_SYS_INTCLR | readl(sock->addr + SOCK_MS_SYSTEM), sock->addr + SOCK_MS_SYSTEM); if (!rc) @@ -497,15 +496,26 @@ static void tifm_ms_set_param(struct memstick_host *msh, switch (param) { case MEMSTICK_POWER: - /* this is set by card detection mechanism */ + /* also affected by media detection mechanism */ + if (value == MEMSTICK_POWER_ON) { + host->mode_mask = TIFM_MS_SYS_SRAC | TIFM_MS_SYS_REI; + writel(TIFM_MS_SYS_RESET, sock->addr + SOCK_MS_SYSTEM); + writel(TIFM_MS_SYS_FCLR | TIFM_MS_SYS_INTCLR, + sock->addr + SOCK_MS_SYSTEM); + writel(0xffffffff, sock->addr + SOCK_MS_STATUS); + } else if (value == MEMSTICK_POWER_OFF) { + writel(TIFM_MS_SYS_FCLR | TIFM_MS_SYS_INTCLR, + sock->addr + SOCK_MS_SYSTEM); + writel(0xffffffff, sock->addr + SOCK_MS_STATUS); + } break; case MEMSTICK_INTERFACE: if (value == MEMSTICK_SERIAL) { - host->mode_mask = TIFM_MS_SERIAL; + host->mode_mask = TIFM_MS_SYS_SRAC | TIFM_MS_SYS_REI; writel((~TIFM_CTRL_FAST_CLK) & readl(sock->addr + SOCK_CONTROL), sock->addr + SOCK_CONTROL); - } else if (value == MEMSTICK_PARALLEL) { + } else if (value == MEMSTICK_PAR4) { host->mode_mask = 0; writel(TIFM_CTRL_FAST_CLK | readl(sock->addr + SOCK_CONTROL), @@ -532,21 +542,6 @@ static void tifm_ms_abort(unsigned long data) tifm_eject(host->dev); } -static int tifm_ms_initialize_host(struct tifm_ms *host) -{ - struct tifm_dev *sock = host->dev; - struct memstick_host *msh = tifm_get_drvdata(sock); - - host->mode_mask = TIFM_MS_SERIAL; - writel(0x8000, sock->addr + SOCK_MS_SYSTEM); - writel(0x0200 | TIFM_MS_SYS_NOT_RDY, sock->addr + SOCK_MS_SYSTEM); - writel(0xffffffff, sock->addr + SOCK_MS_STATUS); - if (tifm_has_ms_pif(sock)) - msh->caps |= MEMSTICK_CAP_PARALLEL; - - return 0; -} - static int tifm_ms_probe(struct tifm_dev *sock) { struct memstick_host *msh; @@ -568,7 +563,6 @@ static int tifm_ms_probe(struct tifm_dev *sock) tifm_set_drvdata(sock, msh); host->dev = sock; host->timeout_jiffies = msecs_to_jiffies(1000); - host->no_dma = no_dma; setup_timer(&host->timer, tifm_ms_abort, (unsigned long)host); @@ -576,10 +570,10 @@ static int tifm_ms_probe(struct tifm_dev *sock) msh->set_param = tifm_ms_set_param; sock->card_event = tifm_ms_card_event; sock->data_event = tifm_ms_data_event; - rc = tifm_ms_initialize_host(host); + if (tifm_has_ms_pif(sock)) + msh->caps |= MEMSTICK_CAP_PAR4; - if (!rc) - rc = memstick_add_host(msh); + rc = memstick_add_host(msh); if (!rc) return 0; @@ -601,7 +595,7 @@ static void tifm_ms_remove(struct tifm_dev *sock) writel(TIFM_FIFO_INT_SETALL, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR); writel(TIFM_DMA_RESET, sock->addr + SOCK_DMA_CONTROL); - if ((host->req->io_type == MEMSTICK_IO_SG) && !host->no_dma) + if (host->use_dma) tifm_unmap_sg(sock, &host->req->sg, 1, host->req->data_dir == READ ? PCI_DMA_TODEVICE @@ -617,10 +611,6 @@ static void tifm_ms_remove(struct tifm_dev *sock) spin_unlock_irqrestore(&sock->lock, flags); memstick_remove_host(msh); - - writel(0x0200 | TIFM_MS_SYS_NOT_RDY, sock->addr + SOCK_MS_SYSTEM); - writel(0xffffffff, sock->addr + SOCK_MS_STATUS); - memstick_free_host(msh); } @@ -628,17 +618,17 @@ static void tifm_ms_remove(struct tifm_dev *sock) static int tifm_ms_suspend(struct tifm_dev *sock, pm_message_t state) { + struct memstick_host *msh = tifm_get_drvdata(sock); + + memstick_suspend_host(msh); return 0; } static int tifm_ms_resume(struct tifm_dev *sock) { struct memstick_host *msh = tifm_get_drvdata(sock); - struct tifm_ms *host = memstick_priv(msh); - - tifm_ms_initialize_host(host); - memstick_detect_change(msh); + memstick_resume_host(msh); return 0; } @@ -679,7 +669,6 @@ MODULE_AUTHOR("Alex Dubov"); MODULE_DESCRIPTION("TI FlashMedia MemoryStick driver"); MODULE_LICENSE("GPL"); MODULE_DEVICE_TABLE(tifm, tifm_ms_id_tbl); -MODULE_VERSION(DRIVER_VERSION); module_init(tifm_ms_init); module_exit(tifm_ms_exit); diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 982e27b86d10..962817e49fba 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -108,6 +108,7 @@ config ACER_WMI depends on ACPI depends on LEDS_CLASS depends on BACKLIGHT_CLASS_DEVICE + depends on SERIO_I8042 select ACPI_WMI ---help--- This is a driver for newer Acer (and Wistron) laptops. It adds diff --git a/drivers/misc/acer-wmi.c b/drivers/misc/acer-wmi.c index 74d12b4a3abd..dd13a3749927 100644 --- a/drivers/misc/acer-wmi.c +++ b/drivers/misc/acer-wmi.c @@ -219,6 +219,15 @@ static struct dmi_system_id acer_quirks[] = { }, { .callback = dmi_matched, + .ident = "Acer Aspire 3610", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3610"), + }, + .driver_data = &quirk_acer_travelmate_2490, + }, + { + .callback = dmi_matched, .ident = "Acer Aspire 5100", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), @@ -228,6 +237,15 @@ static struct dmi_system_id acer_quirks[] = { }, { .callback = dmi_matched, + .ident = "Acer Aspire 5610", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5610"), + }, + .driver_data = &quirk_acer_travelmate_2490, + }, + { + .callback = dmi_matched, .ident = "Acer Aspire 5630", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), @@ -761,11 +779,11 @@ enum led_brightness value) } static struct led_classdev mail_led = { - .name = "acer-mail:green", + .name = "acer-wmi::mail", .brightness_set = mail_led_set, }; -static int __init acer_led_init(struct device *dev) +static int __devinit acer_led_init(struct device *dev) { return led_classdev_register(dev, &mail_led); } @@ -798,7 +816,7 @@ static struct backlight_ops acer_bl_ops = { .update_status = update_bl_status, }; -static int __init acer_backlight_init(struct device *dev) +static int __devinit acer_backlight_init(struct device *dev) { struct backlight_device *bd; @@ -817,7 +835,7 @@ static int __init acer_backlight_init(struct device *dev) return 0; } -static void __exit acer_backlight_exit(void) +static void acer_backlight_exit(void) { backlight_device_unregister(acer_backlight_device); } @@ -1052,11 +1070,12 @@ static int __init acer_wmi_init(void) if (wmi_has_guid(WMID_GUID2) && interface) { if (ACPI_FAILURE(WMID_set_capabilities())) { - printk(ACER_ERR "Unable to detect available devices\n"); + printk(ACER_ERR "Unable to detect available WMID " + "devices\n"); return -ENODEV; } } else if (!wmi_has_guid(WMID_GUID2) && interface) { - printk(ACER_ERR "Unable to detect available devices\n"); + printk(ACER_ERR "No WMID device detection method found\n"); return -ENODEV; } @@ -1064,21 +1083,20 @@ static int __init acer_wmi_init(void) interface = &AMW0_interface; if (ACPI_FAILURE(AMW0_set_capabilities())) { - printk(ACER_ERR "Unable to detect available devices\n"); + printk(ACER_ERR "Unable to detect available AMW0 " + "devices\n"); return -ENODEV; } } - if (wmi_has_guid(AMW0_GUID1)) { - if (ACPI_FAILURE(AMW0_find_mailled())) - printk(ACER_ERR "Unable to detect mail LED\n"); - } + if (wmi_has_guid(AMW0_GUID1)) + AMW0_find_mailled(); find_quirks(); if (!interface) { - printk(ACER_ERR "No or unsupported WMI interface, unable to "); - printk(KERN_CONT "load.\n"); + printk(ACER_ERR "No or unsupported WMI interface, unable to " + "load\n"); return -ENODEV; } diff --git a/drivers/misc/sony-laptop.c b/drivers/misc/sony-laptop.c index 899e3f75f288..02ff3d19b1cc 100644 --- a/drivers/misc/sony-laptop.c +++ b/drivers/misc/sony-laptop.c @@ -315,7 +315,7 @@ static void sony_laptop_report_input_event(u8 event) break; default: - if (event > ARRAY_SIZE(sony_laptop_input_index)) { + if (event >= ARRAY_SIZE(sony_laptop_input_index)) { dprintk("sony_laptop_report_input_event, event not known: %d\n", event); break; } diff --git a/drivers/misc/tifm_7xx1.c b/drivers/misc/tifm_7xx1.c index 63a089b29545..67503ea71d21 100644 --- a/drivers/misc/tifm_7xx1.c +++ b/drivers/misc/tifm_7xx1.c @@ -368,6 +368,8 @@ static int tifm_7xx1_probe(struct pci_dev *dev, goto err_out_irq; writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1), + fm->addr + FM_CLEAR_INTERRUPT_ENABLE); + writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1), fm->addr + FM_SET_INTERRUPT_ENABLE); return 0; diff --git a/drivers/mmc/host/tifm_sd.c b/drivers/mmc/host/tifm_sd.c index 20d5c7bd940a..1c14a186f000 100644 --- a/drivers/mmc/host/tifm_sd.c +++ b/drivers/mmc/host/tifm_sd.c @@ -180,7 +180,7 @@ static void tifm_sd_transfer_data(struct tifm_sd *host) host->sg_pos++; if (host->sg_pos == host->sg_len) { if ((r_data->flags & MMC_DATA_WRITE) - && DATA_CARRY) + && (host->cmd_flags & DATA_CARRY)) writel(host->bounce_buf_data[0], host->dev->addr + SOCK_MMCSD_DATA); diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index a0f0e605d630..fe7b5ec09708 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2366,15 +2366,15 @@ config GELIC_NET module will be called ps3_gelic. config GELIC_WIRELESS - bool "PS3 Wireless support" - depends on GELIC_NET - select WIRELESS_EXT - help - This option adds the support for the wireless feature of PS3. - If you have the wireless-less model of PS3 or have no plan to - use wireless feature, disabling this option saves memory. As - the driver automatically distinguishes the models, you can - safely enable this option even if you have a wireless-less model. + bool "PS3 Wireless support" + depends on GELIC_NET + select WIRELESS_EXT + help + This option adds the support for the wireless feature of PS3. + If you have the wireless-less model of PS3 or have no plan to + use wireless feature, disabling this option saves memory. As + the driver automatically distinguishes the models, you can + safely enable this option even if you have a wireless-less model. config GIANFAR tristate "Gianfar Ethernet" @@ -2519,7 +2519,7 @@ config CHELSIO_T3 config EHEA tristate "eHEA Ethernet support" - depends on IBMEBUS && INET + depends on IBMEBUS && INET && SPARSEMEM select INET_LRO ---help--- This driver supports the IBM pSeries eHEA ethernet adapter. diff --git a/drivers/net/ac3200.c b/drivers/net/ac3200.c index 5136d94923aa..b1448637107f 100644 --- a/drivers/net/ac3200.c +++ b/drivers/net/ac3200.c @@ -369,7 +369,7 @@ MODULE_PARM_DESC(mem, "Memory base address(es)"); MODULE_DESCRIPTION("Ansel AC3200 EISA ethernet driver"); MODULE_LICENSE("GPL"); -int __init init_module(void) +static int __init ac3200_module_init(void) { struct net_device *dev; int this_dev, found = 0; @@ -404,8 +404,7 @@ static void cleanup_card(struct net_device *dev) iounmap(ei_status.mem); } -void __exit -cleanup_module(void) +static void __exit ac3200_module_exit(void) { int this_dev; @@ -418,4 +417,6 @@ cleanup_module(void) } } } +module_init(ac3200_module_init); +module_exit(ac3200_module_exit); #endif /* MODULE */ diff --git a/drivers/net/apne.c b/drivers/net/apne.c index c12cbdf368b1..47a8275d3962 100644 --- a/drivers/net/apne.c +++ b/drivers/net/apne.c @@ -569,7 +569,7 @@ static irqreturn_t apne_interrupt(int irq, void *dev_id) #ifdef MODULE static struct net_device *apne_dev; -int __init init_module(void) +static int __init apne_module_init(void) { apne_dev = apne_probe(-1); if (IS_ERR(apne_dev)) @@ -577,7 +577,7 @@ int __init init_module(void) return 0; } -void __exit cleanup_module(void) +static void __exit apne_module_exit(void) { unregister_netdev(apne_dev); @@ -591,7 +591,8 @@ void __exit cleanup_module(void) free_netdev(apne_dev); } - +module_init(apne_module_init); +module_exit(apne_module_exit); #endif static int init_pcmcia(void) diff --git a/drivers/net/appletalk/ltpc.c b/drivers/net/appletalk/ltpc.c index 6ab2c2d4d673..fef5560bc7a2 100644 --- a/drivers/net/appletalk/ltpc.c +++ b/drivers/net/appletalk/ltpc.c @@ -1252,7 +1252,7 @@ module_param(irq, int, 0); module_param(dma, int, 0); -int __init init_module(void) +static int __init ltpc_module_init(void) { if(io == 0) printk(KERN_NOTICE @@ -1263,6 +1263,7 @@ int __init init_module(void) return PTR_ERR(dev_ltpc); return 0; } +module_init(ltpc_module_init); #endif static void __exit ltpc_cleanup(void) diff --git a/drivers/net/arcnet/capmode.c b/drivers/net/arcnet/capmode.c index cc4610db6395..02cb8f1c1148 100644 --- a/drivers/net/arcnet/capmode.c +++ b/drivers/net/arcnet/capmode.c @@ -80,17 +80,19 @@ void arcnet_cap_init(void) #ifdef MODULE -int __init init_module(void) +static int __init capmode_module_init(void) { printk(VERSION); arcnet_cap_init(); return 0; } -void cleanup_module(void) +static void __exit capmode_module_exit(void) { arcnet_unregister_proto(&capmode_proto); } +module_init(capmode_module_init); +module_exit(capmode_module_exit); MODULE_LICENSE("GPL"); #endif /* MODULE */ diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c index b74dbeef8050..13c293b286de 100644 --- a/drivers/net/atarilance.c +++ b/drivers/net/atarilance.c @@ -336,8 +336,6 @@ struct lance_addr { /***************************** Prototypes *****************************/ -static int addr_accessible( volatile void *regp, int wordflag, int - writeflag ); static unsigned long lance_probe1( struct net_device *dev, struct lance_addr *init_rec ); static int lance_open( struct net_device *dev ); @@ -406,7 +404,8 @@ struct net_device * __init atarilance_probe(int unit) /* Derived from hwreg_present() in atari/config.c: */ -static int __init addr_accessible( volatile void *regp, int wordflag, int writeflag ) +static noinline int __init addr_accessible(volatile void *regp, int wordflag, + int writeflag) { int ret; long flags; diff --git a/drivers/net/e100.c b/drivers/net/e100.c index 36ba6dc96acc..cdf3090a1885 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -2782,16 +2782,13 @@ static void __devexit e100_remove(struct pci_dev *pdev) } } -#ifdef CONFIG_PM static int e100_suspend(struct pci_dev *pdev, pm_message_t state) { struct net_device *netdev = pci_get_drvdata(pdev); struct nic *nic = netdev_priv(netdev); if (netif_running(netdev)) - napi_disable(&nic->napi); - del_timer_sync(&nic->watchdog); - netif_carrier_off(nic->netdev); + e100_down(nic); netif_device_detach(netdev); pci_save_state(pdev); @@ -2804,14 +2801,13 @@ static int e100_suspend(struct pci_dev *pdev, pm_message_t state) pci_enable_wake(pdev, PCI_D3cold, 0); } - free_irq(pdev->irq, netdev); - pci_disable_device(pdev); pci_set_power_state(pdev, PCI_D3hot); return 0; } +#ifdef CONFIG_PM static int e100_resume(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); @@ -2832,26 +2828,7 @@ static int e100_resume(struct pci_dev *pdev) static void e100_shutdown(struct pci_dev *pdev) { - struct net_device *netdev = pci_get_drvdata(pdev); - struct nic *nic = netdev_priv(netdev); - - if (netif_running(netdev)) - napi_disable(&nic->napi); - del_timer_sync(&nic->watchdog); - netif_carrier_off(nic->netdev); - - if ((nic->flags & wol_magic) | e100_asf(nic)) { - pci_enable_wake(pdev, PCI_D3hot, 1); - pci_enable_wake(pdev, PCI_D3cold, 1); - } else { - pci_enable_wake(pdev, PCI_D3hot, 0); - pci_enable_wake(pdev, PCI_D3cold, 0); - } - - free_irq(pdev->irq, netdev); - - pci_disable_device(pdev); - pci_set_power_state(pdev, PCI_D3hot); + e100_suspend(pdev, PMSG_SUSPEND); } /* ------------------ PCI Error Recovery infrastructure -------------- */ diff --git a/drivers/net/enc28j60.c b/drivers/net/enc28j60.c index 0809a6a5a286..46a90e9ec563 100644 --- a/drivers/net/enc28j60.c +++ b/drivers/net/enc28j60.c @@ -900,7 +900,7 @@ static void enc28j60_hw_rx(struct net_device *ndev) if (RSV_GETBIT(rxstat, RSV_LENCHECKERR)) ndev->stats.rx_frame_errors++; } else { - skb = dev_alloc_skb(len); + skb = dev_alloc_skb(len + NET_IP_ALIGN); if (!skb) { if (netif_msg_rx_err(priv)) dev_err(&ndev->dev, @@ -908,6 +908,7 @@ static void enc28j60_hw_rx(struct net_device *ndev) ndev->stats.rx_dropped++; } else { skb->dev = ndev; + skb_reserve(skb, NET_IP_ALIGN); /* copy the packet from the receive buffer */ enc28j60_mem_read(priv, priv->next_pk_ptr + sizeof(rsv), len, skb_put(skb, len)); diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 23d0a4afe0e1..c2095ce531c9 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -2133,7 +2133,7 @@ static void ixgbe_watchdog(unsigned long data) (link_speed == IXGBE_LINK_SPEED_10GB_FULL ? "10 Gbps" : (link_speed == IXGBE_LINK_SPEED_1GB_FULL ? - "1 Gpbs" : "unknown speed")), + "1 Gbps" : "unknown speed")), ((FLOW_RX && FLOW_TX) ? "RX/TX" : (FLOW_RX ? "RX" : (FLOW_TX ? "TX" : "None")))); diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index b528ce77c406..771139e283af 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -2104,6 +2104,7 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR( "Rabeeh Khoury, Assaf Hoffman, Matthew Dharm, Manish Lachwani" " and Dale Farnsworth"); MODULE_DESCRIPTION("Ethernet driver for Marvell MV643XX"); +MODULE_ALIAS("platform:mv643xx_eth"); /* * The second part is the low level driver of the gigE ethernet ports. diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index e8a63e483a2b..ce95c5d168fe 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c @@ -1268,7 +1268,7 @@ static irqreturn_t ax_interrupt(int irq, void *dev_id) } } - if (interrupts && ei_debug) + if (interrupts && ei_debug > 3) { handled = 1; if (nr_serviced >= MAX_SERVICE) diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index f4ca0591231d..3ac8529bb92c 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -67,6 +67,7 @@ config REALTEK_PHY config FIXED_PHY bool "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs" + depends on PHYLIB=y ---help--- Adds the platform "fixed" MDIO Bus to cover the boards that use PHYs that are not connected to the real MDIO bus. diff --git a/drivers/net/phy/davicom.c b/drivers/net/phy/davicom.c index 7ed632db00d7..d926168bc780 100644 --- a/drivers/net/phy/davicom.c +++ b/drivers/net/phy/davicom.c @@ -37,6 +37,7 @@ #define MII_DM9161_SCR 0x10 #define MII_DM9161_SCR_INIT 0x0610 +#define MII_DM9161_SCR_RMII 0x0100 /* DM9161 Interrupt Register */ #define MII_DM9161_INTR 0x15 @@ -103,7 +104,7 @@ static int dm9161_config_aneg(struct phy_device *phydev) static int dm9161_config_init(struct phy_device *phydev) { - int err; + int err, temp; /* Isolate the PHY */ err = phy_write(phydev, MII_BMCR, BMCR_ISOLATE); @@ -111,9 +112,19 @@ static int dm9161_config_init(struct phy_device *phydev) if (err < 0) return err; - /* Do not bypass the scrambler/descrambler */ - err = phy_write(phydev, MII_DM9161_SCR, MII_DM9161_SCR_INIT); + switch (phydev->interface) { + case PHY_INTERFACE_MODE_MII: + temp = MII_DM9161_SCR_INIT; + break; + case PHY_INTERFACE_MODE_RMII: + temp = MII_DM9161_SCR_INIT | MII_DM9161_SCR_RMII; + break; + default: + return -EINVAL; + } + /* Do not bypass the scrambler/descrambler */ + err = phy_write(phydev, MII_DM9161_SCR, temp); if (err < 0) return err; diff --git a/drivers/net/pppol2tp.c b/drivers/net/pppol2tp.c index 86e5dba079fe..3d10ca050b79 100644 --- a/drivers/net/pppol2tp.c +++ b/drivers/net/pppol2tp.c @@ -302,14 +302,14 @@ pppol2tp_session_find(struct pppol2tp_tunnel *tunnel, u16 session_id) struct pppol2tp_session *session; struct hlist_node *walk; - read_lock(&tunnel->hlist_lock); + read_lock_bh(&tunnel->hlist_lock); hlist_for_each_entry(session, walk, session_list, hlist) { if (session->tunnel_addr.s_session == session_id) { - read_unlock(&tunnel->hlist_lock); + read_unlock_bh(&tunnel->hlist_lock); return session; } } - read_unlock(&tunnel->hlist_lock); + read_unlock_bh(&tunnel->hlist_lock); return NULL; } @@ -320,14 +320,14 @@ static struct pppol2tp_tunnel *pppol2tp_tunnel_find(u16 tunnel_id) { struct pppol2tp_tunnel *tunnel = NULL; - read_lock(&pppol2tp_tunnel_list_lock); + read_lock_bh(&pppol2tp_tunnel_list_lock); list_for_each_entry(tunnel, &pppol2tp_tunnel_list, list) { if (tunnel->stats.tunnel_id == tunnel_id) { - read_unlock(&pppol2tp_tunnel_list_lock); + read_unlock_bh(&pppol2tp_tunnel_list_lock); return tunnel; } } - read_unlock(&pppol2tp_tunnel_list_lock); + read_unlock_bh(&pppol2tp_tunnel_list_lock); return NULL; } @@ -342,10 +342,11 @@ static struct pppol2tp_tunnel *pppol2tp_tunnel_find(u16 tunnel_id) static void pppol2tp_recv_queue_skb(struct pppol2tp_session *session, struct sk_buff *skb) { struct sk_buff *skbp; + struct sk_buff *tmp; u16 ns = PPPOL2TP_SKB_CB(skb)->ns; - spin_lock(&session->reorder_q.lock); - skb_queue_walk(&session->reorder_q, skbp) { + spin_lock_bh(&session->reorder_q.lock); + skb_queue_walk_safe(&session->reorder_q, skbp, tmp) { if (PPPOL2TP_SKB_CB(skbp)->ns > ns) { __skb_insert(skb, skbp->prev, skbp, &session->reorder_q); PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_DEBUG, @@ -360,7 +361,7 @@ static void pppol2tp_recv_queue_skb(struct pppol2tp_session *session, struct sk_ __skb_queue_tail(&session->reorder_q, skb); out: - spin_unlock(&session->reorder_q.lock); + spin_unlock_bh(&session->reorder_q.lock); } /* Dequeue a single skb. @@ -371,10 +372,9 @@ static void pppol2tp_recv_dequeue_skb(struct pppol2tp_session *session, struct s int length = PPPOL2TP_SKB_CB(skb)->length; struct sock *session_sock = NULL; - /* We're about to requeue the skb, so unlink it and return resources + /* We're about to requeue the skb, so return resources * to its current owner (a socket receive buffer). */ - skb_unlink(skb, &session->reorder_q); skb_orphan(skb); tunnel->stats.rx_packets++; @@ -442,7 +442,7 @@ static void pppol2tp_recv_dequeue(struct pppol2tp_session *session) * expect to send up next, dequeue it and any other * in-sequence packets behind it. */ - spin_lock(&session->reorder_q.lock); + spin_lock_bh(&session->reorder_q.lock); skb_queue_walk_safe(&session->reorder_q, skb, tmp) { if (time_after(jiffies, PPPOL2TP_SKB_CB(skb)->expires)) { session->stats.rx_seq_discards++; @@ -470,13 +470,18 @@ static void pppol2tp_recv_dequeue(struct pppol2tp_session *session) goto out; } } - spin_unlock(&session->reorder_q.lock); + __skb_unlink(skb, &session->reorder_q); + + /* Process the skb. We release the queue lock while we + * do so to let other contexts process the queue. + */ + spin_unlock_bh(&session->reorder_q.lock); pppol2tp_recv_dequeue_skb(session, skb); - spin_lock(&session->reorder_q.lock); + spin_lock_bh(&session->reorder_q.lock); } out: - spin_unlock(&session->reorder_q.lock); + spin_unlock_bh(&session->reorder_q.lock); } /* Internal receive frame. Do the real work of receiving an L2TP data frame @@ -1059,7 +1064,7 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) /* Get routing info from the tunnel socket */ dst_release(skb->dst); - skb->dst = sk_dst_get(sk_tun); + skb->dst = dst_clone(__sk_dst_get(sk_tun)); skb_orphan(skb); skb->sk = sk_tun; @@ -1107,7 +1112,7 @@ static void pppol2tp_tunnel_closeall(struct pppol2tp_tunnel *tunnel) PRINTK(tunnel->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO, "%s: closing all sessions...\n", tunnel->name); - write_lock(&tunnel->hlist_lock); + write_lock_bh(&tunnel->hlist_lock); for (hash = 0; hash < PPPOL2TP_HASH_SIZE; hash++) { again: hlist_for_each_safe(walk, tmp, &tunnel->session_hlist[hash]) { @@ -1129,7 +1134,7 @@ again: * disappear as we're jumping between locks. */ sock_hold(sk); - write_unlock(&tunnel->hlist_lock); + write_unlock_bh(&tunnel->hlist_lock); lock_sock(sk); if (sk->sk_state & (PPPOX_CONNECTED | PPPOX_BOUND)) { @@ -1154,11 +1159,11 @@ again: * list so we are guaranteed to make forward * progress. */ - write_lock(&tunnel->hlist_lock); + write_lock_bh(&tunnel->hlist_lock); goto again; } } - write_unlock(&tunnel->hlist_lock); + write_unlock_bh(&tunnel->hlist_lock); } /* Really kill the tunnel. @@ -1167,9 +1172,9 @@ again: static void pppol2tp_tunnel_free(struct pppol2tp_tunnel *tunnel) { /* Remove from socket list */ - write_lock(&pppol2tp_tunnel_list_lock); + write_lock_bh(&pppol2tp_tunnel_list_lock); list_del_init(&tunnel->list); - write_unlock(&pppol2tp_tunnel_list_lock); + write_unlock_bh(&pppol2tp_tunnel_list_lock); atomic_dec(&pppol2tp_tunnel_count); kfree(tunnel); @@ -1245,9 +1250,9 @@ static void pppol2tp_session_destruct(struct sock *sk) /* Delete the session socket from the * hash */ - write_lock(&tunnel->hlist_lock); + write_lock_bh(&tunnel->hlist_lock); hlist_del_init(&session->hlist); - write_unlock(&tunnel->hlist_lock); + write_unlock_bh(&tunnel->hlist_lock); atomic_dec(&pppol2tp_session_count); } @@ -1392,9 +1397,9 @@ static struct sock *pppol2tp_prepare_tunnel_socket(int fd, u16 tunnel_id, /* Add tunnel to our list */ INIT_LIST_HEAD(&tunnel->list); - write_lock(&pppol2tp_tunnel_list_lock); + write_lock_bh(&pppol2tp_tunnel_list_lock); list_add(&tunnel->list, &pppol2tp_tunnel_list); - write_unlock(&pppol2tp_tunnel_list_lock); + write_unlock_bh(&pppol2tp_tunnel_list_lock); atomic_inc(&pppol2tp_tunnel_count); /* Bump the reference count. The tunnel context is deleted @@ -1599,11 +1604,11 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr, sk->sk_user_data = session; /* Add session to the tunnel's hash list */ - write_lock(&tunnel->hlist_lock); + write_lock_bh(&tunnel->hlist_lock); hlist_add_head(&session->hlist, pppol2tp_session_id_hash(tunnel, session->tunnel_addr.s_session)); - write_unlock(&tunnel->hlist_lock); + write_unlock_bh(&tunnel->hlist_lock); atomic_inc(&pppol2tp_session_count); @@ -2205,7 +2210,7 @@ static struct pppol2tp_session *next_session(struct pppol2tp_tunnel *tunnel, str int next = 0; int i; - read_lock(&tunnel->hlist_lock); + read_lock_bh(&tunnel->hlist_lock); for (i = 0; i < PPPOL2TP_HASH_SIZE; i++) { hlist_for_each_entry(session, walk, &tunnel->session_hlist[i], hlist) { if (curr == NULL) { @@ -2223,7 +2228,7 @@ static struct pppol2tp_session *next_session(struct pppol2tp_tunnel *tunnel, str } } out: - read_unlock(&tunnel->hlist_lock); + read_unlock_bh(&tunnel->hlist_lock); if (!found) session = NULL; @@ -2234,13 +2239,13 @@ static struct pppol2tp_tunnel *next_tunnel(struct pppol2tp_tunnel *curr) { struct pppol2tp_tunnel *tunnel = NULL; - read_lock(&pppol2tp_tunnel_list_lock); + read_lock_bh(&pppol2tp_tunnel_list_lock); if (list_is_last(&curr->list, &pppol2tp_tunnel_list)) { goto out; } tunnel = list_entry(curr->list.next, struct pppol2tp_tunnel, list); out: - read_unlock(&pppol2tp_tunnel_list_lock); + read_unlock_bh(&pppol2tp_tunnel_list_lock); return tunnel; } diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 6179a0a2032c..c72787adeba3 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -1088,7 +1088,7 @@ static int s2io_print_pci_mode(struct s2io_nic *nic) * '-1' on failure */ -int init_tti(struct s2io_nic *nic, int link) +static int init_tti(struct s2io_nic *nic, int link) { struct XENA_dev_config __iomem *bar0 = nic->bar0; register u64 val64 = 0; diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c index 77d9dd7ea34f..567c62757e9d 100644 --- a/drivers/net/tulip/de2104x.c +++ b/drivers/net/tulip/de2104x.c @@ -910,7 +910,8 @@ static void de_set_media (struct de_private *de) unsigned media = de->media_type; u32 macmode = dr32(MacMode); - BUG_ON(de_is_running(de)); + if (de_is_running(de)) + printk(KERN_WARNING "%s: chip is running while changing media!\n", de->dev->name); if (de->de21040) dw32(CSR11, FULL_DUPLEX_MAGIC); diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 19fd4cb0ddf8..b58472cf76f8 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -203,8 +203,11 @@ again: if (received < budget) { netif_rx_complete(vi->dev, napi); if (unlikely(!vi->rvq->vq_ops->enable_cb(vi->rvq)) - && netif_rx_reschedule(vi->dev, napi)) + && napi_schedule_prep(napi)) { + vi->rvq->vq_ops->disable_cb(vi->rvq); + __netif_rx_schedule(vi->dev, napi); goto again; + } } return received; @@ -278,10 +281,11 @@ again: pr_debug("%s: virtio not prepared to send\n", dev->name); netif_stop_queue(dev); - /* Activate callback for using skbs: if this fails it + /* Activate callback for using skbs: if this returns false it * means some were used in the meantime. */ if (unlikely(!vi->svq->vq_ops->enable_cb(vi->svq))) { - printk("Unlikely: restart svq failed\n"); + printk("Unlikely: restart svq race\n"); + vi->svq->vq_ops->disable_cb(vi->svq); netif_start_queue(dev); goto again; } @@ -294,6 +298,15 @@ again: return 0; } +#ifdef CONFIG_NET_POLL_CONTROLLER +static void virtnet_netpoll(struct net_device *dev) +{ + struct virtnet_info *vi = netdev_priv(dev); + + napi_schedule(&vi->napi); +} +#endif + static int virtnet_open(struct net_device *dev) { struct virtnet_info *vi = netdev_priv(dev); @@ -336,6 +349,9 @@ static int virtnet_probe(struct virtio_device *vdev) dev->stop = virtnet_close; dev->hard_start_xmit = start_xmit; dev->features = NETIF_F_HIGHDMA; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = virtnet_netpoll; +#endif SET_NETDEV_DEV(dev, &vdev->dev); /* Do we support "hardware" checksums? */ diff --git a/drivers/net/wan/sbni.c b/drivers/net/wan/sbni.c index 15d5c58e57bc..e59255a155a9 100644 --- a/drivers/net/wan/sbni.c +++ b/drivers/net/wan/sbni.c @@ -751,7 +751,7 @@ upload_data( struct net_device *dev, unsigned framelen, unsigned frameno, } -static __inline void +static inline void send_complete( struct net_local *nl ) { #ifdef CONFIG_SBNI_MULTILINE diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index bdc6a1cc2103..f0ef7081bdeb 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -578,7 +578,7 @@ int lbs_process_rx_command(struct lbs_private *priv) goto done; } if (respcmd != CMD_RET(curcmd) && - respcmd != CMD_802_11_ASSOCIATE && curcmd != CMD_RET_802_11_ASSOCIATE) { + respcmd != CMD_RET_802_11_ASSOCIATE && curcmd != CMD_802_11_ASSOCIATE) { lbs_pr_info("Invalid CMD_RESP %x to command %x!\n", respcmd, curcmd); spin_unlock_irqrestore(&priv->driver_lock, flags); ret = -1; diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index e808db98f2f5..93ea212fedd5 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2302,9 +2302,9 @@ static void rt61pci_configure_filter(struct ieee80211_hw *hw, * Apply some rules to the filters: * - Some filters imply different filters to be set. * - Some things we can't filter out at all. + * - Multicast filter seems to kill broadcast traffic so never use it. */ - if (mc_count) - *total_flags |= FIF_ALLMULTI; + *total_flags |= FIF_ALLMULTI; if (*total_flags & FIF_OTHER_BSS || *total_flags & FIF_PROMISC_IN_BSS) *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS; diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 4fac2d414d84..8103d41a1543 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1869,9 +1869,9 @@ static void rt73usb_configure_filter(struct ieee80211_hw *hw, * Apply some rules to the filters: * - Some filters imply different filters to be set. * - Some things we can't filter out at all. + * - Multicast filter seems to kill broadcast traffic so never use it. */ - if (mc_count) - *total_flags |= FIF_ALLMULTI; + *total_flags |= FIF_ALLMULTI; if (*total_flags & FIF_OTHER_BSS || *total_flags & FIF_PROMISC_IN_BSS) *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS; @@ -2098,6 +2098,7 @@ static struct usb_device_id rt73usb_device_table[] = { /* D-Link */ { USB_DEVICE(0x07d1, 0x3c03), USB_DEVICE_DATA(&rt73usb_ops) }, { USB_DEVICE(0x07d1, 0x3c04), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x07d1, 0x3c07), USB_DEVICE_DATA(&rt73usb_ops) }, /* Gemtek */ { USB_DEVICE(0x15a9, 0x0004), USB_DEVICE_DATA(&rt73usb_ops) }, /* Gigabyte */ diff --git a/drivers/parisc/pdc_stable.c b/drivers/parisc/pdc_stable.c index de34aa9d3136..f9f9a5f1bbd0 100644 --- a/drivers/parisc/pdc_stable.c +++ b/drivers/parisc/pdc_stable.c @@ -829,7 +829,7 @@ static ssize_t pdcs_autoboot_write(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) { - return pdcs_auto_write(kset, attr, buf, count, PF_AUTOBOOT); + return pdcs_auto_write(kobj, attr, buf, count, PF_AUTOBOOT); } /** @@ -845,7 +845,7 @@ static ssize_t pdcs_autosearch_write(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) { - return pdcs_auto_write(kset, attr, buf, count, PF_AUTOSEARCH); + return pdcs_auto_write(kobj, attr, buf, count, PF_AUTOSEARCH); } /** @@ -1066,7 +1066,7 @@ pdc_stable_init(void) } /* Don't forget the root entries */ - error = sysfs_create_group(stable_kobj, pdcs_attr_group); + error = sysfs_create_group(stable_kobj, &pdcs_attr_group); /* register the paths kset as a child of the stable kset */ paths_kset = kset_create_and_add("paths", NULL, stable_kobj); diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c index bdbe780e21c5..8c4d2c13d5f2 100644 --- a/drivers/parisc/sba_iommu.c +++ b/drivers/parisc/sba_iommu.c @@ -314,8 +314,8 @@ sba_dump_sg( struct ioc *ioc, struct scatterlist *startsg, int nents) #define RESMAP_MASK(n) (~0UL << (BITS_PER_LONG - (n))) #define RESMAP_IDX_MASK (sizeof(unsigned long) - 1) -unsigned long ptr_to_pide(struct ioc *ioc, unsigned long *res_ptr, - unsigned int bitshiftcnt) +static unsigned long ptr_to_pide(struct ioc *ioc, unsigned long *res_ptr, + unsigned int bitshiftcnt) { return (((unsigned long)res_ptr - (unsigned long)ioc->res_map) << 3) + bitshiftcnt; diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index 6a9403d79e0c..d708358326e5 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c @@ -143,14 +143,18 @@ void pci_bus_add_devices(struct pci_bus *bus) /* register the bus with sysfs as the parent is now * properly registered. */ child_bus = dev->subordinate; + if (child_bus->is_added) + continue; child_bus->dev.parent = child_bus->bridge; retval = device_register(&child_bus->dev); if (retval) dev_err(&dev->dev, "Error registering pci_bus," " continuing...\n"); - else + else { + child_bus->is_added = 1; retval = device_create_file(&child_bus->dev, &dev_attr_cpuaffinity); + } if (retval) dev_err(&dev->dev, "Error creating cpuaffinity" " file, continuing...\n"); diff --git a/drivers/pci/hotplug/ibmphp_ebda.c b/drivers/pci/hotplug/ibmphp_ebda.c index 600ed7b67ae7..bbccde9f228f 100644 --- a/drivers/pci/hotplug/ibmphp_ebda.c +++ b/drivers/pci/hotplug/ibmphp_ebda.c @@ -963,6 +963,7 @@ static int __init ebda_rsrc_controller (void) bus_info_ptr1 = ibmphp_find_same_bus_num (hpc_ptr->slots[index].slot_bus_num); if (!bus_info_ptr1) { + kfree(tmp_slot); rc = -ENODEV; goto error; } diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index 7f4836b8e71e..5fa4ba0d9934 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c @@ -467,7 +467,7 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_ t_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset); t_slot->hpc_ops->get_adapter_status(t_slot, &value); /* Check if slot is occupied */ - if (value) { + if (value && pciehp_force) { rc = pciehp_enable_slot(t_slot); if (rc) /* -ENODEV: shouldn't happen, but deal with it */ value = 0; diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index 4a23654184fc..72f7476930c8 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -272,21 +272,29 @@ static int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state) { acpi_handle handle = DEVICE_ACPI_HANDLE(&dev->dev); acpi_handle tmp; - static int state_conv[] = { - [0] = 0, - [1] = 1, - [2] = 2, - [3] = 3, - [4] = 3 + static const u8 state_conv[] = { + [PCI_D0] = ACPI_STATE_D0, + [PCI_D1] = ACPI_STATE_D1, + [PCI_D2] = ACPI_STATE_D2, + [PCI_D3hot] = ACPI_STATE_D3, + [PCI_D3cold] = ACPI_STATE_D3 }; - int acpi_state = state_conv[(int __force) state]; if (!handle) return -ENODEV; /* If the ACPI device has _EJ0, ignore the device */ if (ACPI_SUCCESS(acpi_get_handle(handle, "_EJ0", &tmp))) return 0; - return acpi_bus_set_power(handle, acpi_state); + + switch (state) { + case PCI_D0: + case PCI_D1: + case PCI_D2: + case PCI_D3hot: + case PCI_D3cold: + return acpi_bus_set_power(handle, state_conv[state]); + } + return -EINVAL; } diff --git a/drivers/pnp/quirks.c b/drivers/pnp/quirks.c index 4065139753b6..37993206ae5d 100644 --- a/drivers/pnp/quirks.c +++ b/drivers/pnp/quirks.c @@ -17,7 +17,6 @@ #include <linux/slab.h> #include <linux/pnp.h> #include <linux/io.h> -#include <linux/dmi.h> #include <linux/kallsyms.h> #include "base.h" @@ -109,42 +108,73 @@ static void quirk_sb16audio_resources(struct pnp_dev *dev) "pnp: SB audio device quirk - increasing port range\n"); } -static void quirk_supermicro_h8dce_system(struct pnp_dev *dev) + +#include <linux/pci.h> + +static void quirk_system_pci_resources(struct pnp_dev *dev) { - int i; - static struct dmi_system_id supermicro_h8dce[] = { - { - .ident = "Supermicro H8DCE", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Supermicro"), - DMI_MATCH(DMI_PRODUCT_NAME, "H8DCE"), - }, - }, - { } - }; - - if (!dmi_check_system(supermicro_h8dce)) - return; + struct pci_dev *pdev = NULL; + resource_size_t pnp_start, pnp_end, pci_start, pci_end; + int i, j; /* - * On the Supermicro H8DCE, there's a system device with resources - * that overlap BAR 6 of the built-in SATA PCI adapter. If the PNP - * system device claims them, the sata_nv driver won't be able to. - * More details at: - * https://bugzilla.redhat.com/show_bug.cgi?id=280641 - * https://bugzilla.redhat.com/show_bug.cgi?id=313491 - * http://lkml.org/lkml/2008/1/9/449 - * http://thread.gmane.org/gmane.linux.acpi.devel/27312 + * Some BIOSes have PNP motherboard devices with resources that + * partially overlap PCI BARs. The PNP system driver claims these + * motherboard resources, which prevents the normal PCI driver from + * requesting them later. + * + * This patch disables the PNP resources that conflict with PCI BARs + * so they won't be claimed by the PNP system driver. */ - for (i = 0; i < PNP_MAX_MEM; i++) { - if (pnp_mem_valid(dev, i) && pnp_mem_len(dev, i) && - (pnp_mem_start(dev, i) & 0xdfef0000) == 0xdfef0000) { - dev_warn(&dev->dev, "disabling 0x%llx-0x%llx to prevent" - " conflict with sata_nv PCI device\n", - (unsigned long long) pnp_mem_start(dev, i), - (unsigned long long) (pnp_mem_start(dev, i) + - pnp_mem_len(dev, i) - 1)); - pnp_mem_flags(dev, i) = 0; + for_each_pci_dev(pdev) { + for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { + if (!(pci_resource_flags(pdev, i) & IORESOURCE_MEM) || + pci_resource_len(pdev, i) == 0) + continue; + + pci_start = pci_resource_start(pdev, i); + pci_end = pci_resource_end(pdev, i); + for (j = 0; j < PNP_MAX_MEM; j++) { + if (!pnp_mem_valid(dev, j) || + pnp_mem_len(dev, j) == 0) + continue; + + pnp_start = pnp_mem_start(dev, j); + pnp_end = pnp_mem_end(dev, j); + + /* + * If the PNP region doesn't overlap the PCI + * region at all, there's no problem. + */ + if (pnp_end < pci_start || pnp_start > pci_end) + continue; + + /* + * If the PNP region completely encloses (or is + * at least as large as) the PCI region, that's + * also OK. For example, this happens when the + * PNP device describes a bridge with PCI + * behind it. + */ + if (pnp_start <= pci_start && + pnp_end >= pci_end) + continue; + + /* + * Otherwise, the PNP region overlaps *part* of + * the PCI region, and that might prevent a PCI + * driver from requesting its resources. + */ + dev_warn(&dev->dev, "mem resource " + "(0x%llx-0x%llx) overlaps %s BAR %d " + "(0x%llx-0x%llx), disabling\n", + (unsigned long long) pnp_start, + (unsigned long long) pnp_end, + pci_name(pdev), i, + (unsigned long long) pci_start, + (unsigned long long) pci_end); + pnp_mem_flags(dev, j) = 0; + } } } } @@ -169,8 +199,8 @@ static struct pnp_fixup pnp_fixups[] = { {"CTL0043", quirk_sb16audio_resources}, {"CTL0044", quirk_sb16audio_resources}, {"CTL0045", quirk_sb16audio_resources}, - {"PNP0c01", quirk_supermicro_h8dce_system}, - {"PNP0c02", quirk_supermicro_h8dce_system}, + {"PNP0c01", quirk_system_pci_resources}, + {"PNP0c02", quirk_system_pci_resources}, {""} }; diff --git a/drivers/serial/of_serial.c b/drivers/serial/of_serial.c index a64d85821996..c0e50a461055 100644 --- a/drivers/serial/of_serial.c +++ b/drivers/serial/of_serial.c @@ -138,7 +138,7 @@ static struct of_device_id __devinitdata of_platform_serial_table[] = { { /* end of list */ }, }; -static struct of_platform_driver __devinitdata of_platform_serial_driver = { +static struct of_platform_driver of_platform_serial_driver = { .owner = THIS_MODULE, .name = "of_serial", .probe = of_platform_serial_probe, diff --git a/drivers/spi/au1550_spi.c b/drivers/spi/au1550_spi.c index c47a650183a1..41a3d00c4515 100644 --- a/drivers/spi/au1550_spi.c +++ b/drivers/spi/au1550_spi.c @@ -99,7 +99,7 @@ static dbdev_tab_t au1550_spi_mem_dbdev = static void au1550_spi_bits_handlers_set(struct au1550_spi *hw, int bpw); -/** +/* * compute BRG and DIV bits to setup spi clock based on main input clock rate * that was specified in platform data structure * according to au1550 datasheet: @@ -650,7 +650,7 @@ static int au1550_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) return hw->txrx_bufs(spi, t); } -static irqreturn_t au1550_spi_irq(int irq, void *dev, struct pt_regs *regs) +static irqreturn_t au1550_spi_irq(int irq, void *dev) { struct au1550_spi *hw = dev; return hw->irq_callback(hw); diff --git a/drivers/spi/spi_bitbang.c b/drivers/spi/spi_bitbang.c index f7f8580edad8..71e881419cdd 100644 --- a/drivers/spi/spi_bitbang.c +++ b/drivers/spi/spi_bitbang.c @@ -344,12 +344,14 @@ static void bitbang_work(struct work_struct *work) t->rx_dma = t->tx_dma = 0; status = bitbang->txrx_bufs(spi, t); } + if (status > 0) + m->actual_length += status; if (status != t->len) { - if (status > 0) - status = -EMSGSIZE; + /* always report some kind of error */ + if (status >= 0) + status = -EREMOTEIO; break; } - m->actual_length += status; status = 0; /* protocol tweaks before next transfer */ diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index 69f19f224875..17e71d56f31e 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -4,7 +4,6 @@ menuconfig THERMAL bool "Generic Thermal sysfs driver" - default y help Generic Thermal Sysfs driver offers a generic mechanism for thermal management. Usually it's made up of one or more thermal diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index c13955164686..6f45dd669b33 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -131,7 +131,7 @@ config USB_ATMEL_USBA config USB_GADGET_FSL_USB2 boolean "Freescale Highspeed USB DR Peripheral Controller" - depends on MPC834x || PPC_MPC831x + depends on FSL_SOC select USB_GADGET_DUALSPEED help Some of Freescale PowerPC processors have a High Speed diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index b8ad55aff842..46ee7f4c0912 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -281,23 +281,44 @@ static void ehci_iaa_watchdog(unsigned long param) { struct ehci_hcd *ehci = (struct ehci_hcd *) param; unsigned long flags; - u32 status, cmd; spin_lock_irqsave (&ehci->lock, flags); - WARN_ON(!ehci->reclaim); - status = ehci_readl(ehci, &ehci->regs->status); - cmd = ehci_readl(ehci, &ehci->regs->command); - ehci_dbg(ehci, "IAA watchdog: status %x cmd %x\n", status, cmd); - - /* lost IAA irqs wedge things badly; seen first with a vt8235 */ - if (ehci->reclaim) { - if (status & STS_IAA) { - ehci_vdbg (ehci, "lost IAA\n"); + /* Lost IAA irqs wedge things badly; seen first with a vt8235. + * So we need this watchdog, but must protect it against both + * (a) SMP races against real IAA firing and retriggering, and + * (b) clean HC shutdown, when IAA watchdog was pending. + */ + if (ehci->reclaim + && !timer_pending(&ehci->iaa_watchdog) + && HC_IS_RUNNING(ehci_to_hcd(ehci)->state)) { + u32 cmd, status; + + /* If we get here, IAA is *REALLY* late. It's barely + * conceivable that the system is so busy that CMD_IAAD + * is still legitimately set, so let's be sure it's + * clear before we read STS_IAA. (The HC should clear + * CMD_IAAD when it sets STS_IAA.) + */ + cmd = ehci_readl(ehci, &ehci->regs->command); + if (cmd & CMD_IAAD) + ehci_writel(ehci, cmd & ~CMD_IAAD, + &ehci->regs->command); + + /* If IAA is set here it either legitimately triggered + * before we cleared IAAD above (but _way_ late, so we'll + * still count it as lost) ... or a silicon erratum: + * - VIA seems to set IAA without triggering the IRQ; + * - IAAD potentially cleared without setting IAA. + */ + status = ehci_readl(ehci, &ehci->regs->status); + if ((status & STS_IAA) || !(cmd & CMD_IAAD)) { COUNT (ehci->stats.lost_iaa); ehci_writel(ehci, STS_IAA, &ehci->regs->status); } - ehci_writel(ehci, cmd & ~CMD_IAAD, &ehci->regs->command); + + ehci_vdbg(ehci, "IAA watchdog: status %x cmd %x\n", + status, cmd); end_unlink_async(ehci); } @@ -631,7 +652,7 @@ static int ehci_run (struct usb_hcd *hcd) static irqreturn_t ehci_irq (struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); - u32 status, pcd_status = 0; + u32 status, pcd_status = 0, cmd; int bh; spin_lock (&ehci->lock); @@ -652,7 +673,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) /* clear (just) interrupts */ ehci_writel(ehci, status, &ehci->regs->status); - ehci_readl(ehci, &ehci->regs->command); /* unblock posted write */ + cmd = ehci_readl(ehci, &ehci->regs->command); bh = 0; #ifdef EHCI_VERBOSE_DEBUG @@ -673,8 +694,17 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) /* complete the unlinking of some qh [4.15.2.3] */ if (status & STS_IAA) { - COUNT (ehci->stats.reclaim); - end_unlink_async(ehci); + /* guard against (alleged) silicon errata */ + if (cmd & CMD_IAAD) { + ehci_writel(ehci, cmd & ~CMD_IAAD, + &ehci->regs->command); + ehci_dbg(ehci, "IAA with IAAD still set?\n"); + } + if (ehci->reclaim) { + COUNT(ehci->stats.reclaim); + end_unlink_async(ehci); + } else + ehci_dbg(ehci, "IAA with nothing to reclaim?\n"); } /* remote wakeup [4.3.1] */ @@ -781,7 +811,7 @@ static int ehci_urb_enqueue ( static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) { /* failfast */ - if (!HC_IS_RUNNING(ehci_to_hcd(ehci)->state)) + if (!HC_IS_RUNNING(ehci_to_hcd(ehci)->state) && ehci->reclaim) end_unlink_async(ehci); /* if it's not linked then there's nothing to do */ diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index 08c65c1a3771..779d07851a4d 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@ -94,6 +94,7 @@ static struct usb_device_id id_table_earthmate [] = { static struct usb_device_id id_table_cyphidcomrs232 [] = { { USB_DEVICE(VENDOR_ID_CYPRESS, PRODUCT_ID_CYPHIDCOM) }, + { USB_DEVICE(VENDOR_ID_POWERCOM, PRODUCT_ID_UPS) }, { } /* Terminating entry */ }; @@ -106,6 +107,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB) }, { USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB_LT20) }, { USB_DEVICE(VENDOR_ID_CYPRESS, PRODUCT_ID_CYPHIDCOM) }, + { USB_DEVICE(VENDOR_ID_POWERCOM, PRODUCT_ID_UPS) }, { USB_DEVICE(VENDOR_ID_DAZZLE, PRODUCT_ID_CA42) }, { } /* Terminating entry */ }; diff --git a/drivers/usb/serial/cypress_m8.h b/drivers/usb/serial/cypress_m8.h index e1c7c27e18b7..0388065bb794 100644 --- a/drivers/usb/serial/cypress_m8.h +++ b/drivers/usb/serial/cypress_m8.h @@ -19,6 +19,10 @@ #define VENDOR_ID_CYPRESS 0x04b4 #define PRODUCT_ID_CYPHIDCOM 0x5500 +/* Powercom UPS, chip CY7C63723 */ +#define VENDOR_ID_POWERCOM 0x0d9f +#define PRODUCT_ID_UPS 0x0002 + /* Nokia CA-42 USB to serial cable */ #define VENDOR_ID_DAZZLE 0x07d0 #define PRODUCT_ID_CA42 0x4101 diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 91dc433dbcf1..3abb3c863647 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -359,6 +359,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_MAXSTREAM_PID) }, { USB_DEVICE(TML_VID, TML_USB_SERIAL_PID) }, { USB_DEVICE(FTDI_VID, FTDI_ELSTER_UNICOM_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_PROPOX_JTAGCABLEII_PID) }, { USB_DEVICE(OLIMEX_VID, OLIMEX_ARM_USB_OCD_PID), .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, { USB_DEVICE(FIC_VID, FIC_NEO1973_DEBUG_PID), diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index e1eb742abcd5..6da539ede0ee 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h @@ -557,6 +557,9 @@ #define TML_VID 0x1B91 /* Vendor ID */ #define TML_USB_SERIAL_PID 0x0064 /* USB - Serial Converter */ +/* Propox devices */ +#define FTDI_PROPOX_JTAGCABLEII_PID 0xD738 + /* Commands */ #define FTDI_SIO_RESET 0 /* Reset the port */ #define FTDI_SIO_MODEM_CTRL 1 /* Set the modem control register */ diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index 97fa3c428435..7cfce9dabb90 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c @@ -323,7 +323,7 @@ static void flush_and_resubmit_read_urb (struct usb_serial_port *port) room = tty_buffer_request_room(tty, urb->actual_length); if (room) { tty_insert_flip_string(tty, urb->transfer_buffer, room); - tty_flip_buffer_push(tty); /* is this allowed from an URB callback ? */ + tty_flip_buffer_push(tty); } } @@ -349,10 +349,12 @@ void usb_serial_generic_read_bulk_callback (struct urb *urb) /* Throttle the device if requested by tty */ spin_lock_irqsave(&port->lock, flags); - if (!(port->throttled = port->throttle_req)) - /* Handle data and continue reading from device */ + if (!(port->throttled = port->throttle_req)) { + spin_unlock_irqrestore(&port->lock, flags); flush_and_resubmit_read_urb(port); - spin_unlock_irqrestore(&port->lock, flags); + } else { + spin_unlock_irqrestore(&port->lock, flags); + } } EXPORT_SYMBOL_GPL(usb_serial_generic_read_bulk_callback); diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 828a4377ec6a..a396fbbdc9c2 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -111,6 +111,42 @@ static int option_send_setup(struct usb_serial_port *port); #define HUAWEI_PRODUCT_E220BIS 0x1004 #define NOVATELWIRELESS_VENDOR_ID 0x1410 + +/* MERLIN EVDO PRODUCTS */ +#define NOVATELWIRELESS_PRODUCT_V640 0x1100 +#define NOVATELWIRELESS_PRODUCT_V620 0x1110 +#define NOVATELWIRELESS_PRODUCT_V740 0x1120 +#define NOVATELWIRELESS_PRODUCT_V720 0x1130 + +/* MERLIN HSDPA/HSPA PRODUCTS */ +#define NOVATELWIRELESS_PRODUCT_U730 0x1400 +#define NOVATELWIRELESS_PRODUCT_U740 0x1410 +#define NOVATELWIRELESS_PRODUCT_U870 0x1420 +#define NOVATELWIRELESS_PRODUCT_XU870 0x1430 +#define NOVATELWIRELESS_PRODUCT_X950D 0x1450 + +/* EXPEDITE PRODUCTS */ +#define NOVATELWIRELESS_PRODUCT_EV620 0x2100 +#define NOVATELWIRELESS_PRODUCT_ES720 0x2110 +#define NOVATELWIRELESS_PRODUCT_E725 0x2120 +#define NOVATELWIRELESS_PRODUCT_EU730 0x2400 +#define NOVATELWIRELESS_PRODUCT_EU740 0x2410 +#define NOVATELWIRELESS_PRODUCT_EU870D 0x2420 + +/* OVATION PRODUCTS */ +#define NOVATELWIRELESS_PRODUCT_MC727 0x4100 +#define NOVATELWIRELESS_PRODUCT_MC950D 0x4400 + +/* FUTURE NOVATEL PRODUCTS */ +#define NOVATELWIRELESS_PRODUCT_EVDO_1 0x6000 +#define NOVATELWIRELESS_PRODUCT_HSPA_1 0x7000 +#define NOVATELWIRELESS_PRODUCT_EMBEDDED_1 0x8000 +#define NOVATELWIRELESS_PRODUCT_GLOBAL_1 0x9000 +#define NOVATELWIRELESS_PRODUCT_EVDO_2 0x6001 +#define NOVATELWIRELESS_PRODUCT_HSPA_2 0x7001 +#define NOVATELWIRELESS_PRODUCT_EMBEDDED_2 0x8001 +#define NOVATELWIRELESS_PRODUCT_GLOBAL_2 0x9001 + #define DELL_VENDOR_ID 0x413C #define KYOCERA_VENDOR_ID 0x0c88 @@ -168,21 +204,34 @@ static struct usb_device_id option_ids[] = { { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220BIS, 0xff, 0xff, 0xff) }, - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x1100) }, /* Novatel Merlin XS620/S640 */ - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x1110) }, /* Novatel Merlin S620 */ - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x1120) }, /* Novatel Merlin EX720 */ - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x1130) }, /* Novatel Merlin S720 */ - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x1400) }, /* Novatel U730 */ - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x1410) }, /* Novatel U740 */ - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x1420) }, /* Novatel EU870 */ - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x1430) }, /* Novatel Merlin XU870 HSDPA/3G */ - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x2100) }, /* Novatel EV620 CDMA/EV-DO */ - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x2110) }, /* Novatel Merlin ES620 / Merlin ES720 / Ovation U720 */ + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V640) }, /* Novatel Merlin V640/XV620 */ + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V620) }, /* Novatel Merlin V620/S620 */ + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V740) }, /* Novatel Merlin EX720/V740/X720 */ + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V720) }, /* Novatel Merlin V720/S720/PC720 */ + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_U730) }, /* Novatel U730/U740 (VF version) */ + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_U740) }, /* Novatel U740 */ + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_U870) }, /* Novatel U870 */ + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_XU870) }, /* Novatel Merlin XU870 HSDPA/3G */ + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_X950D) }, /* Novatel X950D */ + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EV620) }, /* Novatel EV620/ES620 CDMA/EV-DO */ + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_ES720) }, /* Novatel ES620/ES720/U720/USB720 */ + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_E725) }, /* Novatel E725/E726 */ { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x2130) }, /* Novatel Merlin ES620 SM Bus */ - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x2410) }, /* Novatel EU740 */ - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x4100) }, /* Novatel U727 */ - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x4400) }, /* Novatel MC950 */ + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EU730) }, /* Novatel EU730 and Vodafone EU740 */ + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EU740) }, /* Novatel non-Vodafone EU740 */ + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EU870D) }, /* Novatel EU850D/EU860D/EU870D */ + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC950D) }, /* Novatel MC930D/MC950D */ + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC727) }, /* Novatel MC727/U727/USB727 */ { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x5010) }, /* Novatel U727 */ + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EVDO_1) }, /* Novatel EVDO product */ + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_1) }, /* Novatel HSPA product */ + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EMBEDDED_1) }, /* Novatel Embedded product */ + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_GLOBAL_1) }, /* Novatel Global product */ + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EVDO_2) }, /* Novatel EVDO product */ + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_2) }, /* Novatel HSPA product */ + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EMBEDDED_2) }, /* Novatel Embedded product */ + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_GLOBAL_2) }, /* Novatel Global product */ + { USB_DEVICE(DELL_VENDOR_ID, 0x8114) }, /* Dell Wireless 5700 Mobile Broadband CDMA/EVDO Mini-Card == Novatel Expedite EV620 CDMA/EV-DO */ { USB_DEVICE(DELL_VENDOR_ID, 0x8115) }, /* Dell Wireless 5500 Mobile Broadband HSDPA Mini-Card == Novatel Expedite EU740 HSDPA/3G */ { USB_DEVICE(DELL_VENDOR_ID, 0x8116) }, /* Dell Wireless 5505 Mobile Broadband HSDPA Mini-Card == Novatel Expedite EU740 HSDPA/3G */ diff --git a/drivers/usb/storage/sddr55.c b/drivers/usb/storage/sddr55.c index d43a3415e12f..6d14327c921d 100644 --- a/drivers/usb/storage/sddr55.c +++ b/drivers/usb/storage/sddr55.c @@ -522,8 +522,8 @@ int sddr55_reset(struct us_data *us) { static unsigned long sddr55_get_capacity(struct us_data *us) { - unsigned char manufacturerID; - unsigned char deviceID; + unsigned char uninitialized_var(manufacturerID); + unsigned char uninitialized_var(deviceID); int result; struct sddr55_card_info *info = (struct sddr55_card_info *)us->extra; diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 758435f8a6f8..e0b0580705e4 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -553,6 +553,19 @@ config FB_BF54X_LQ043 help This is the framebuffer device driver for a SHARP LQ043T1DG01 TFT LCD +config FB_BFIN_T350MCQB + tristate "Varitronix COG-T350MCQB TFT LCD display (BF527 EZKIT)" + depends on FB && BLACKFIN + select BFIN_GPTIMERS + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + help + This is the framebuffer device driver for a Varitronix VL-PS-COG-T350MCQB-01 display TFT LCD + This display is a QVGA 320x240 24-bit RGB display interfaced by an 8-bit wide PPI + It uses PPI[0..7] PPI_FS1, PPI_FS2 and PPI_CLK. + + config FB_STI tristate "HP STI frame buffer device support" depends on FB && PARISC diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 83e02b3429b6..03371c789039 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -122,6 +122,7 @@ obj-$(CONFIG_FB_EFI) += efifb.o obj-$(CONFIG_FB_VGA16) += vga16fb.o obj-$(CONFIG_FB_OF) += offb.o obj-$(CONFIG_FB_BF54X_LQ043) += bf54x-lq043fb.o +obj-$(CONFIG_FB_BFIN_T350MCQB) += bfin-t350mcqb-fb.o # the test framebuffer is last obj-$(CONFIG_FB_VIRTUAL) += vfb.o diff --git a/drivers/video/bf54x-lq043fb.c b/drivers/video/bf54x-lq043fb.c index 0ce791e6f79c..986a550c0439 100644 --- a/drivers/video/bf54x-lq043fb.c +++ b/drivers/video/bf54x-lq043fb.c @@ -8,7 +8,7 @@ * * * Modified: - * Copyright 2004-2007 Analog Devices Inc. + * Copyright 2007-2008 Analog Devices Inc. * * Bugs: Enter bugs at http://blackfin.uclinux.org/ * @@ -241,7 +241,7 @@ static int request_ports(struct bfin_bf54xfb_info *fbi) u16 eppi_req_18[] = EPPI0_18; u16 disp = fbi->mach_info->disp; - if (gpio_request(disp, NULL)) { + if (gpio_request(disp, DRIVER_NAME)) { printk(KERN_ERR "Requesting GPIO %d faild\n", disp); return -EFAULT; } @@ -672,7 +672,7 @@ static int __init bfin_bf54x_probe(struct platform_device *pdev) &bfin_lq043fb_bl_ops); bl_dev->props.max_brightness = 255; - lcd_dev = lcd_device_register(DRIVER_NAME, NULL, &bfin_lcd_ops); + lcd_dev = lcd_device_register(DRIVER_NAME, &pdev->dev, NULL, &bfin_lcd_ops); lcd_dev->props.max_contrast = 255, printk(KERN_INFO "Done.\n"); #endif diff --git a/drivers/video/bfin-t350mcqb-fb.c b/drivers/video/bfin-t350mcqb-fb.c new file mode 100644 index 000000000000..a2bb2de9e020 --- /dev/null +++ b/drivers/video/bfin-t350mcqb-fb.c @@ -0,0 +1,685 @@ +/* + * File: drivers/video/bfin-t350mcqb-fb.c + * Based on: + * Author: Michael Hennerich <hennerich@blackfin.uclinux.org> + * + * Created: + * Description: Blackfin LCD Framebufer driver + * + * + * Modified: + * Copyright 2004-2007 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/interrupt.h> +#include <linux/device.h> +#include <linux/backlight.h> +#include <linux/lcd.h> +#include <linux/dma-mapping.h> +#include <linux/platform_device.h> + +#include <asm/blackfin.h> +#include <asm/irq.h> +#include <asm/dma-mapping.h> +#include <asm/dma.h> +#include <asm/portmux.h> +#include <asm/gptimers.h> + +#define NO_BL_SUPPORT + +#define LCD_X_RES 320 /* Horizontal Resolution */ +#define LCD_Y_RES 240 /* Vertical Resolution */ +#define LCD_BPP 24 /* Bit Per Pixel */ + +#define DMA_BUS_SIZE 16 +#define LCD_CLK (12*1000*1000) /* 12MHz */ + +#define CLOCKS_PER_PIX 3 + + /* + * HS and VS timing parameters (all in number of PPI clk ticks) + */ + +#define U_LINE 1 /* Blanking Lines */ + +#define H_ACTPIX (LCD_X_RES * CLOCKS_PER_PIX) /* active horizontal pixel */ +#define H_PERIOD (408 * CLOCKS_PER_PIX) /* HS period */ +#define H_PULSE 90 /* HS pulse width */ +#define H_START 204 /* first valid pixel */ + +#define V_LINES (LCD_Y_RES + U_LINE) /* total vertical lines */ +#define V_PULSE (3 * H_PERIOD) /* VS pulse width (1-5 H_PERIODs) */ +#define V_PERIOD (H_PERIOD * V_LINES) /* VS period */ + +#define ACTIVE_VIDEO_MEM_OFFSET (U_LINE * H_ACTPIX) + +#define BFIN_LCD_NBR_PALETTE_ENTRIES 256 + +#define DRIVER_NAME "bfin-t350mcqb" +static char driver_name[] = DRIVER_NAME; + +struct bfin_t350mcqbfb_info { + struct fb_info *fb; + struct device *dev; + unsigned char *fb_buffer; /* RGB Buffer */ + dma_addr_t dma_handle; + int lq043_mmap; + int lq043_open_cnt; + int irq; + spinlock_t lock; /* lock */ +}; + +static int nocursor; +module_param(nocursor, int, 0644); +MODULE_PARM_DESC(nocursor, "cursor enable/disable"); + +#define PPI_TX_MODE 0x2 +#define PPI_XFER_TYPE_11 0xC +#define PPI_PORT_CFG_01 0x10 +#define PPI_PACK_EN 0x80 +#define PPI_POLS_1 0x8000 + +static void bfin_t350mcqb_config_ppi(struct bfin_t350mcqbfb_info *fbi) +{ + bfin_write_PPI_DELAY(H_START); + bfin_write_PPI_COUNT(H_ACTPIX-1); + bfin_write_PPI_FRAME(V_LINES); + + bfin_write_PPI_CONTROL(PPI_TX_MODE | /* output mode , PORT_DIR */ + PPI_XFER_TYPE_11 | /* sync mode XFR_TYPE */ + PPI_PORT_CFG_01 | /* two frame sync PORT_CFG */ + PPI_PACK_EN | /* packing enabled PACK_EN */ + PPI_POLS_1); /* faling edge syncs POLS */ +} + +static inline void bfin_t350mcqb_disable_ppi(void) +{ + bfin_write_PPI_CONTROL(bfin_read_PPI_CONTROL() & ~PORT_EN); +} + +static inline void bfin_t350mcqb_enable_ppi(void) +{ + bfin_write_PPI_CONTROL(bfin_read_PPI_CONTROL() | PORT_EN); +} + +static void bfin_t350mcqb_start_timers(void) +{ + unsigned long flags; + + local_irq_save(flags); + enable_gptimers(TIMER1bit); + enable_gptimers(TIMER0bit); + local_irq_restore(flags); +} + +static void bfin_t350mcqb_stop_timers(void) +{ + disable_gptimers(TIMER0bit | TIMER1bit); + + set_gptimer_status(0, TIMER_STATUS_TRUN0 | TIMER_STATUS_TRUN1 | + TIMER_STATUS_TIMIL0 | TIMER_STATUS_TIMIL1 | + TIMER_STATUS_TOVF0 | TIMER_STATUS_TOVF1); + +} + +static void bfin_t350mcqb_init_timers(void) +{ + + bfin_t350mcqb_stop_timers(); + + set_gptimer_period(TIMER0_id, H_PERIOD); + set_gptimer_pwidth(TIMER0_id, H_PULSE); + set_gptimer_config(TIMER0_id, TIMER_MODE_PWM | TIMER_PERIOD_CNT | + TIMER_TIN_SEL | TIMER_CLK_SEL| + TIMER_EMU_RUN); + + set_gptimer_period(TIMER1_id, V_PERIOD); + set_gptimer_pwidth(TIMER1_id, V_PULSE); + set_gptimer_config(TIMER1_id, TIMER_MODE_PWM | TIMER_PERIOD_CNT | + TIMER_TIN_SEL | TIMER_CLK_SEL | + TIMER_EMU_RUN); + +} + +static void bfin_t350mcqb_config_dma(struct bfin_t350mcqbfb_info *fbi) +{ + + set_dma_config(CH_PPI, + set_bfin_dma_config(DIR_READ, DMA_FLOW_AUTO, + INTR_DISABLE, DIMENSION_2D, + DATA_SIZE_16, + DMA_NOSYNC_KEEP_DMA_BUF)); + set_dma_x_count(CH_PPI, (LCD_X_RES * LCD_BPP) / DMA_BUS_SIZE); + set_dma_x_modify(CH_PPI, DMA_BUS_SIZE / 8); + set_dma_y_count(CH_PPI, V_LINES); + + set_dma_y_modify(CH_PPI, DMA_BUS_SIZE / 8); + set_dma_start_addr(CH_PPI, (unsigned long)fbi->fb_buffer); + +} + +static int bfin_t350mcqb_request_ports(int action) +{ + u16 ppi0_req_8[] = {P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2, + P_PPI0_D0, P_PPI0_D1, P_PPI0_D2, + P_PPI0_D3, P_PPI0_D4, P_PPI0_D5, + P_PPI0_D6, P_PPI0_D7, 0}; + + if (action) { + if (peripheral_request_list(ppi0_req_8, DRIVER_NAME)) { + printk(KERN_ERR "Requesting Peripherals faild\n"); + return -EFAULT; + } + } else + peripheral_free_list(ppi0_req_8); + + return 0; +} + +static int bfin_t350mcqb_fb_open(struct fb_info *info, int user) +{ + struct bfin_t350mcqbfb_info *fbi = info->par; + + spin_lock(&fbi->lock); + fbi->lq043_open_cnt++; + + if (fbi->lq043_open_cnt <= 1) { + + bfin_t350mcqb_disable_ppi(); + SSYNC(); + + bfin_t350mcqb_config_dma(fbi); + bfin_t350mcqb_config_ppi(fbi); + bfin_t350mcqb_init_timers(); + + /* start dma */ + enable_dma(CH_PPI); + bfin_t350mcqb_enable_ppi(); + bfin_t350mcqb_start_timers(); + } + + spin_unlock(&fbi->lock); + + return 0; +} + +static int bfin_t350mcqb_fb_release(struct fb_info *info, int user) +{ + struct bfin_t350mcqbfb_info *fbi = info->par; + + spin_lock(&fbi->lock); + + fbi->lq043_open_cnt--; + fbi->lq043_mmap = 0; + + if (fbi->lq043_open_cnt <= 0) { + bfin_t350mcqb_disable_ppi(); + SSYNC(); + disable_dma(CH_PPI); + bfin_t350mcqb_stop_timers(); + memset(fbi->fb_buffer, 0, info->fix.smem_len); + } + + spin_unlock(&fbi->lock); + + return 0; +} + +static int bfin_t350mcqb_fb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + + if (var->bits_per_pixel != LCD_BPP) { + pr_debug("%s: depth not supported: %u BPP\n", __FUNCTION__, + var->bits_per_pixel); + return -EINVAL; + } + + if (info->var.xres != var->xres || info->var.yres != var->yres || + info->var.xres_virtual != var->xres_virtual || + info->var.yres_virtual != var->yres_virtual) { + pr_debug("%s: Resolution not supported: X%u x Y%u \n", + __FUNCTION__, var->xres, var->yres); + return -EINVAL; + } + + /* + * Memory limit + */ + + if ((info->fix.line_length * var->yres_virtual) > info->fix.smem_len) { + pr_debug("%s: Memory Limit requested yres_virtual = %u\n", + __FUNCTION__, var->yres_virtual); + return -ENOMEM; + } + + return 0; +} + +static int bfin_t350mcqb_fb_mmap(struct fb_info *info, struct vm_area_struct *vma) +{ + struct bfin_t350mcqbfb_info *fbi = info->par; + + if (fbi->lq043_mmap) + return -1; + + spin_lock(&fbi->lock); + fbi->lq043_mmap = 1; + spin_unlock(&fbi->lock); + + vma->vm_start = (unsigned long)(fbi->fb_buffer + ACTIVE_VIDEO_MEM_OFFSET); + + vma->vm_end = vma->vm_start + info->fix.smem_len; + /* For those who don't understand how mmap works, go read + * Documentation/nommu-mmap.txt. + * For those that do, you will know that the VM_MAYSHARE flag + * must be set in the vma->vm_flags structure on noMMU + * Other flags can be set, and are documented in + * include/linux/mm.h + */ + vma->vm_flags |= VM_MAYSHARE; + + return 0; +} + +int bfin_t350mcqb_fb_cursor(struct fb_info *info, struct fb_cursor *cursor) +{ + if (nocursor) + return 0; + else + return -EINVAL; /* just to force soft_cursor() call */ +} + +static int bfin_t350mcqb_fb_setcolreg(u_int regno, u_int red, u_int green, + u_int blue, u_int transp, + struct fb_info *info) +{ + if (regno >= BFIN_LCD_NBR_PALETTE_ENTRIES) + return -EINVAL; + + if (info->var.grayscale) { + /* grayscale = 0.30*R + 0.59*G + 0.11*B */ + red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8; + } + + if (info->fix.visual == FB_VISUAL_TRUECOLOR) { + + u32 value; + /* Place color in the pseudopalette */ + if (regno > 16) + return -EINVAL; + + red >>= (16 - info->var.red.length); + green >>= (16 - info->var.green.length); + blue >>= (16 - info->var.blue.length); + + value = (red << info->var.red.offset) | + (green << info->var.green.offset) | + (blue << info->var.blue.offset); + value &= 0xFFFFFF; + + ((u32 *) (info->pseudo_palette))[regno] = value; + + } + + return 0; +} + +static struct fb_ops bfin_t350mcqb_fb_ops = { + .owner = THIS_MODULE, + .fb_open = bfin_t350mcqb_fb_open, + .fb_release = bfin_t350mcqb_fb_release, + .fb_check_var = bfin_t350mcqb_fb_check_var, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_mmap = bfin_t350mcqb_fb_mmap, + .fb_cursor = bfin_t350mcqb_fb_cursor, + .fb_setcolreg = bfin_t350mcqb_fb_setcolreg, +}; + +#ifndef NO_BL_SUPPORT +static int bl_get_brightness(struct backlight_device *bd) +{ + return 0; +} + +static struct backlight_ops bfin_lq043fb_bl_ops = { + .get_brightness = bl_get_brightness, +}; + +static struct backlight_device *bl_dev; + +static int bfin_lcd_get_power(struct lcd_device *dev) +{ + return 0; +} + +static int bfin_lcd_set_power(struct lcd_device *dev, int power) +{ + return 0; +} + +static int bfin_lcd_get_contrast(struct lcd_device *dev) +{ + return 0; +} + +static int bfin_lcd_set_contrast(struct lcd_device *dev, int contrast) +{ + + return 0; +} + +static int bfin_lcd_check_fb(struct fb_info *fi) +{ + if (!fi || (fi == &bfin_t350mcqb_fb)) + return 1; + return 0; +} + +static struct lcd_ops bfin_lcd_ops = { + .get_power = bfin_lcd_get_power, + .set_power = bfin_lcd_set_power, + .get_contrast = bfin_lcd_get_contrast, + .set_contrast = bfin_lcd_set_contrast, + .check_fb = bfin_lcd_check_fb, +}; + +static struct lcd_device *lcd_dev; +#endif + +static irqreturn_t bfin_t350mcqb_irq_error(int irq, void *dev_id) +{ + /*struct bfin_t350mcqbfb_info *info = (struct bfin_t350mcqbfb_info *)dev_id;*/ + + u16 status = bfin_read_PPI_STATUS(); + bfin_write_PPI_STATUS(0xFFFF); + + if (status) { + bfin_t350mcqb_disable_ppi(); + disable_dma(CH_PPI); + + /* start dma */ + enable_dma(CH_PPI); + bfin_t350mcqb_enable_ppi(); + bfin_write_PPI_STATUS(0xFFFF); + } + + return IRQ_HANDLED; +} + +static int __init bfin_t350mcqb_probe(struct platform_device *pdev) +{ + struct bfin_t350mcqbfb_info *info; + struct fb_info *fbinfo; + int ret; + + printk(KERN_INFO DRIVER_NAME ": %dx%d %d-bit RGB FrameBuffer initializing...\n", + LCD_X_RES, LCD_Y_RES, LCD_BPP); + + if (request_dma(CH_PPI, "CH_PPI") < 0) { + printk(KERN_ERR DRIVER_NAME + ": couldn't request CH_PPI DMA\n"); + ret = -EFAULT; + goto out1; + } + + fbinfo = + framebuffer_alloc(sizeof(struct bfin_t350mcqbfb_info), &pdev->dev); + if (!fbinfo) { + ret = -ENOMEM; + goto out2; + } + + info = fbinfo->par; + info->fb = fbinfo; + info->dev = &pdev->dev; + + platform_set_drvdata(pdev, fbinfo); + + strcpy(fbinfo->fix.id, driver_name); + + fbinfo->fix.type = FB_TYPE_PACKED_PIXELS; + fbinfo->fix.type_aux = 0; + fbinfo->fix.xpanstep = 0; + fbinfo->fix.ypanstep = 0; + fbinfo->fix.ywrapstep = 0; + fbinfo->fix.accel = FB_ACCEL_NONE; + fbinfo->fix.visual = FB_VISUAL_TRUECOLOR; + + fbinfo->var.nonstd = 0; + fbinfo->var.activate = FB_ACTIVATE_NOW; + fbinfo->var.height = -1; + fbinfo->var.width = -1; + fbinfo->var.accel_flags = 0; + fbinfo->var.vmode = FB_VMODE_NONINTERLACED; + + fbinfo->var.xres = LCD_X_RES; + fbinfo->var.xres_virtual = LCD_X_RES; + fbinfo->var.yres = LCD_Y_RES; + fbinfo->var.yres_virtual = LCD_Y_RES; + fbinfo->var.bits_per_pixel = LCD_BPP; + + fbinfo->var.red.offset = 0; + fbinfo->var.green.offset = 8; + fbinfo->var.blue.offset = 16; + fbinfo->var.transp.offset = 0; + fbinfo->var.red.length = 8; + fbinfo->var.green.length = 8; + fbinfo->var.blue.length = 8; + fbinfo->var.transp.length = 0; + fbinfo->fix.smem_len = LCD_X_RES * LCD_Y_RES * LCD_BPP / 8; + + fbinfo->fix.line_length = fbinfo->var.xres_virtual * + fbinfo->var.bits_per_pixel / 8; + + + fbinfo->fbops = &bfin_t350mcqb_fb_ops; + fbinfo->flags = FBINFO_FLAG_DEFAULT; + + info->fb_buffer = + dma_alloc_coherent(NULL, fbinfo->fix.smem_len, &info->dma_handle, + GFP_KERNEL); + + if (NULL == info->fb_buffer) { + printk(KERN_ERR DRIVER_NAME + ": couldn't allocate dma buffer.\n"); + ret = -ENOMEM; + goto out3; + } + + memset(info->fb_buffer, 0, fbinfo->fix.smem_len); + + fbinfo->screen_base = (void *)info->fb_buffer + ACTIVE_VIDEO_MEM_OFFSET; + fbinfo->fix.smem_start = (int)info->fb_buffer + ACTIVE_VIDEO_MEM_OFFSET; + + fbinfo->fbops = &bfin_t350mcqb_fb_ops; + + fbinfo->pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL); + if (!fbinfo->pseudo_palette) { + printk(KERN_ERR DRIVER_NAME + "Fail to allocate pseudo_palette\n"); + + ret = -ENOMEM; + goto out4; + } + + memset(fbinfo->pseudo_palette, 0, sizeof(u32) * 16); + + if (fb_alloc_cmap(&fbinfo->cmap, BFIN_LCD_NBR_PALETTE_ENTRIES, 0) + < 0) { + printk(KERN_ERR DRIVER_NAME + "Fail to allocate colormap (%d entries)\n", + BFIN_LCD_NBR_PALETTE_ENTRIES); + ret = -EFAULT; + goto out5; + } + + if (bfin_t350mcqb_request_ports(1)) { + printk(KERN_ERR DRIVER_NAME ": couldn't request gpio port.\n"); + ret = -EFAULT; + goto out6; + } + + info->irq = platform_get_irq(pdev, 0); + if (info->irq < 0) { + ret = -EINVAL; + goto out7; + } + + if (request_irq(info->irq, (void *)bfin_t350mcqb_irq_error, IRQF_DISABLED, + "PPI ERROR", info) < 0) { + printk(KERN_ERR DRIVER_NAME + ": unable to request PPI ERROR IRQ\n"); + ret = -EFAULT; + goto out7; + } + + if (register_framebuffer(fbinfo) < 0) { + printk(KERN_ERR DRIVER_NAME + ": unable to register framebuffer.\n"); + ret = -EINVAL; + goto out8; + } +#ifndef NO_BL_SUPPORT + bl_dev = + backlight_device_register("bf52x-bl", NULL, NULL, + &bfin_lq043fb_bl_ops); + bl_dev->props.max_brightness = 255; + + lcd_dev = lcd_device_register(DRIVER_NAME, NULL, &bfin_lcd_ops); + lcd_dev->props.max_contrast = 255, printk(KERN_INFO "Done.\n"); +#endif + + return 0; + +out8: + free_irq(info->irq, info); +out7: + bfin_t350mcqb_request_ports(0); +out6: + fb_dealloc_cmap(&fbinfo->cmap); +out5: + kfree(fbinfo->pseudo_palette); +out4: + dma_free_coherent(NULL, fbinfo->fix.smem_len, info->fb_buffer, + info->dma_handle); +out3: + framebuffer_release(fbinfo); +out2: + free_dma(CH_PPI); +out1: + platform_set_drvdata(pdev, NULL); + + return ret; +} + +static int bfin_t350mcqb_remove(struct platform_device *pdev) +{ + + struct fb_info *fbinfo = platform_get_drvdata(pdev); + struct bfin_t350mcqbfb_info *info = fbinfo->par; + + free_dma(CH_PPI); + free_irq(info->irq, info); + + if (info->fb_buffer != NULL) + dma_free_coherent(NULL, fbinfo->fix.smem_len, info->fb_buffer, + info->dma_handle); + + kfree(fbinfo->pseudo_palette); + fb_dealloc_cmap(&fbinfo->cmap); + +#ifndef NO_BL_SUPPORT + lcd_device_unregister(lcd_dev); + backlight_device_unregister(bl_dev); +#endif + + unregister_framebuffer(fbinfo); + + bfin_t350mcqb_request_ports(0); + + printk(KERN_INFO DRIVER_NAME ": Unregister LCD driver.\n"); + + return 0; +} + +#ifdef CONFIG_PM +static int bfin_t350mcqb_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct fb_info *fbinfo = platform_get_drvdata(pdev); + struct bfin_t350mcqbfb_info *info = fbinfo->par; + + bfin_t350mcqb_disable_ppi(); + disable_dma(CH_PPI); + bfin_write_PPI_STATUS(0xFFFF); + + return 0; +} + +static int bfin_t350mcqb_resume(struct platform_device *pdev) +{ + struct fb_info *fbinfo = platform_get_drvdata(pdev); + struct bfin_t350mcqbfb_info *info = fbinfo->par; + + enable_dma(CH_PPI); + bfin_t350mcqb_enable_ppi(); + + return 0; +} +#else +#define bfin_t350mcqb_suspend NULL +#define bfin_t350mcqb_resume NULL +#endif + +static struct platform_driver bfin_t350mcqb_driver = { + .probe = bfin_t350mcqb_probe, + .remove = bfin_t350mcqb_remove, + .suspend = bfin_t350mcqb_suspend, + .resume = bfin_t350mcqb_resume, + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __devinit bfin_t350mcqb_driver_init(void) +{ + return platform_driver_register(&bfin_t350mcqb_driver); +} + +static void __exit bfin_t350mcqb_driver_cleanup(void) +{ + platform_driver_unregister(&bfin_t350mcqb_driver); +} + +MODULE_DESCRIPTION("Blackfin TFT LCD Driver"); +MODULE_LICENSE("GPL"); + +module_init(bfin_t350mcqb_driver_init); +module_exit(bfin_t350mcqb_driver_cleanup); diff --git a/drivers/video/mbx/mbxfb.c b/drivers/video/mbx/mbxfb.c index 80cd117ca65c..01f77bcc68f9 100644 --- a/drivers/video/mbx/mbxfb.c +++ b/drivers/video/mbx/mbxfb.c @@ -889,7 +889,7 @@ static int __devinit mbxfb_probe(struct platform_device *dev) struct mbxfb_info *mfbi; struct mbxfb_platform_data *pdata; - dev_dbg(dev, "mbxfb_probe\n"); + dev_dbg(&dev->dev, "mbxfb_probe\n"); pdata = dev->dev.platform_data; if (!pdata) { diff --git a/drivers/video/stifb.c b/drivers/video/stifb.c index e7c8db2eb49b..f98be301140c 100644 --- a/drivers/video/stifb.c +++ b/drivers/video/stifb.c @@ -505,16 +505,24 @@ ngleSetupAttrPlanes(struct stifb_info *fb, int BufferNumber) static void rattlerSetupPlanes(struct stifb_info *fb) { + int saved_id, y; + + /* Write RAMDAC pixel read mask register so all overlay + * planes are display-enabled. (CRX24 uses Bt462 pixel + * read mask register for overlay planes, not image planes). + */ CRX24_SETUP_RAMDAC(fb); - /* replacement for: SETUP_FB(fb, CRX24_OVERLAY_PLANES); */ - WRITE_WORD(0x83000300, fb, REG_14); - SETUP_HW(fb); - WRITE_BYTE(1, fb, REG_16b1); + /* change fb->id temporarily to fool SETUP_FB() */ + saved_id = fb->id; + fb->id = CRX24_OVERLAY_PLANES; + SETUP_FB(fb); + fb->id = saved_id; + + for (y = 0; y < fb->info.var.yres; ++y) + memset(fb->info.screen_base + y * fb->info.fix.line_length, + 0xff, fb->info.var.xres * fb->info.var.bits_per_pixel/8); - fb_memset((void*)fb->info.fix.smem_start, 0xff, - fb->info.var.yres*fb->info.fix.line_length); - CRX24_SET_OVLY_MASK(fb); SETUP_FB(fb); } diff --git a/drivers/video/tridentfb.c b/drivers/video/tridentfb.c index 919ce75db9e2..0a4e07d43d2d 100644 --- a/drivers/video/tridentfb.c +++ b/drivers/video/tridentfb.c @@ -566,44 +566,32 @@ static inline void write3CE(int reg, unsigned char val) static void enable_mmio(void) { - unsigned char tmp; - /* Goto New Mode */ outb(0x0B, 0x3C4); inb(0x3C5); /* Unprotect registers */ outb(NewMode1, 0x3C4); - tmp = inb(0x3C5); outb(0x80, 0x3C5); /* Enable MMIO */ outb(PCIReg, 0x3D4); outb(inb(0x3D5) | 0x01, 0x3D5); - - t_outb(NewMode1, 0x3C4); - t_outb(tmp, 0x3C5); } static void disable_mmio(void) { - unsigned char tmp; - /* Goto New Mode */ t_outb(0x0B, 0x3C4); t_inb(0x3C5); /* Unprotect registers */ t_outb(NewMode1, 0x3C4); - tmp = t_inb(0x3C5); t_outb(0x80, 0x3C5); /* Disable MMIO */ t_outb(PCIReg, 0x3D4); t_outb(t_inb(0x3D5) & ~0x01, 0x3D5); - - outb(NewMode1, 0x3C4); - outb(tmp, 0x3C5); } #define crtc_unlock() write3X4(CRTVSyncEnd, read3X4(CRTVSyncEnd) & 0x7F) @@ -757,7 +745,7 @@ static unsigned int __devinit get_memsize(void) switch (tmp) { case 0x01: - k = 512; + k = 512 * Kb; break; case 0x02: k = 6 * Mb; /* XP */ diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c index c8a4332d1132..0b3efc31ee6d 100644 --- a/drivers/virtio/virtio_balloon.c +++ b/drivers/virtio/virtio_balloon.c @@ -152,7 +152,7 @@ static void virtballoon_changed(struct virtio_device *vdev) wake_up(&vb->config_change); } -static inline int towards_target(struct virtio_balloon *vb) +static inline s64 towards_target(struct virtio_balloon *vb) { u32 v; __virtio_config_val(vb->vdev, @@ -176,7 +176,7 @@ static int balloon(void *_vballoon) set_freezable(); while (!kthread_should_stop()) { - int diff; + s64 diff; try_to_freeze(); wait_event_interruptible(vb->config_change, diff --git a/drivers/virtio/virtio_pci.c b/drivers/virtio/virtio_pci.c index 26f787ddd5ff..59a8f73dec73 100644 --- a/drivers/virtio/virtio_pci.c +++ b/drivers/virtio/virtio_pci.c @@ -177,6 +177,7 @@ static irqreturn_t vp_interrupt(int irq, void *opaque) struct virtio_pci_device *vp_dev = opaque; struct virtio_pci_vq_info *info; irqreturn_t ret = IRQ_NONE; + unsigned long flags; u8 isr; /* reading the ISR has the effect of also clearing it so it's very @@ -197,12 +198,12 @@ static irqreturn_t vp_interrupt(int irq, void *opaque) drv->config_changed(&vp_dev->vdev); } - spin_lock(&vp_dev->lock); + spin_lock_irqsave(&vp_dev->lock, flags); list_for_each_entry(info, &vp_dev->virtqueues, node) { if (vring_interrupt(irq, info->vq) == IRQ_HANDLED) ret = IRQ_HANDLED; } - spin_unlock(&vp_dev->lock); + spin_unlock_irqrestore(&vp_dev->lock, flags); return ret; } @@ -214,6 +215,7 @@ static struct virtqueue *vp_find_vq(struct virtio_device *vdev, unsigned index, struct virtio_pci_device *vp_dev = to_vp_device(vdev); struct virtio_pci_vq_info *info; struct virtqueue *vq; + unsigned long flags; u16 num; int err; @@ -255,9 +257,9 @@ static struct virtqueue *vp_find_vq(struct virtio_device *vdev, unsigned index, vq->priv = info; info->vq = vq; - spin_lock(&vp_dev->lock); + spin_lock_irqsave(&vp_dev->lock, flags); list_add(&info->node, &vp_dev->virtqueues); - spin_unlock(&vp_dev->lock); + spin_unlock_irqrestore(&vp_dev->lock, flags); return vq; @@ -274,10 +276,11 @@ static void vp_del_vq(struct virtqueue *vq) { struct virtio_pci_device *vp_dev = to_vp_device(vq->vdev); struct virtio_pci_vq_info *info = vq->priv; + unsigned long flags; - spin_lock(&vp_dev->lock); + spin_lock_irqsave(&vp_dev->lock, flags); list_del(&info->node); - spin_unlock(&vp_dev->lock); + spin_unlock_irqrestore(&vp_dev->lock, flags); vring_del_virtqueue(vq); diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c index 3a28c1382131..aa714028641e 100644 --- a/drivers/virtio/virtio_ring.c +++ b/drivers/virtio/virtio_ring.c @@ -232,7 +232,6 @@ static bool vring_enable_cb(struct virtqueue *_vq) vq->vring.avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT; mb(); if (unlikely(more_used(vq))) { - vq->vring.avail->flags |= VRING_AVAIL_F_NO_INTERRUPT; END_USE(vq); return false; } diff --git a/drivers/watchdog/cpu5wdt.c b/drivers/watchdog/cpu5wdt.c index 5941ca601a3a..df72f90123df 100644 --- a/drivers/watchdog/cpu5wdt.c +++ b/drivers/watchdog/cpu5wdt.c @@ -59,9 +59,9 @@ static int ticks = 10000; static struct { struct completion stop; - volatile int running; + int running; struct timer_list timer; - volatile int queue; + int queue; int default_ticks; unsigned long inuse; } cpu5wdt_device; diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c index a2e174b09fe7..6483d1066b95 100644 --- a/drivers/watchdog/hpwdt.c +++ b/drivers/watchdog/hpwdt.c @@ -58,41 +58,6 @@ struct bios32_service_dir { u8 reserved[5]; }; -/* - * smbios_entry_point - defines SMBIOS entry point structure - * - * anchor[4] - anchor string (_SM_) - * checksum - checksum of the entry point structure - * length - length of the entry point structure - * major_ver - major version (02h for revision 2.1) - * minor_ver - minor version (01h for revision 2.1) - * max_struct_size - size of the largest SMBIOS structure - * revision - entry point structure revision implemented - * formatted_area[5] - reserved - * intermediate_anchor[5] - intermediate anchor string (_DMI_) - * intermediate_checksum - intermediate checksum - * table_length - structure table length - * table_address - structure table address - * table_num_structs - number of SMBIOS structures present - * bcd_revision - BCD revision - */ -struct smbios_entry_point { - u8 anchor[4]; - u8 checksum; - u8 length; - u8 major_ver; - u8 minor_ver; - u16 max_struct_size; - u8 revision; - u8 formatted_area[5]; - u8 intermediate_anchor[5]; - u8 intermediate_checksum; - u16 table_length; - u64 table_address; - u16 table_num_structs; - u8 bcd_revision; -}; - /* type 212 */ struct smbios_cru64_info { u8 type; @@ -175,31 +140,13 @@ static struct pci_device_id hpwdt_devices[] = { }; MODULE_DEVICE_TABLE(pci, hpwdt_devices); -/* - * bios_checksum - */ -static int __devinit bios_checksum(const char __iomem *ptr, int len) -{ - char sum = 0; - int i; - - /* - * calculate checksum of size bytes. This should add up - * to zero if we have a valid header. - */ - for (i = 0; i < len; i++) - sum += ptr[i]; - - return ((sum == 0) && (len > 0)); -} - #ifndef CONFIG_X86_64 /* --32 Bit Bios------------------------------------------------------------ */ #define HPWDT_ARCH 32 -asmlinkage void asminline_call(struct cmn_registers *pi86Regs, - unsigned long *pRomEntry) +static void asminline_call(struct cmn_registers *pi86Regs, + unsigned long *pRomEntry) { asm("pushl %ebp \n\t" "movl %esp, %ebp \n\t" @@ -303,6 +250,24 @@ static int __devinit cru_detect(unsigned long map_entry, } /* + * bios_checksum + */ +static int __devinit bios_checksum(const char __iomem *ptr, int len) +{ + char sum = 0; + int i; + + /* + * calculate checksum of size bytes. This should add up + * to zero if we have a valid header. + */ + for (i = 0; i < len; i++) + sum += ptr[i]; + + return ((sum == 0) && (len > 0)); +} + +/* * bios32_present * * Routine Description: @@ -368,8 +333,8 @@ static int __devinit detect_cru_service(void) #define HPWDT_ARCH 64 -asmlinkage void asminline_call(struct cmn_registers *pi86Regs, - unsigned long *pRomEntry) +static void asminline_call(struct cmn_registers *pi86Regs, + unsigned long *pRomEntry) { asm("pushq %rbp \n\t" "movq %rsp, %rbp \n\t" @@ -410,12 +375,8 @@ asmlinkage void asminline_call(struct cmn_registers *pi86Regs, * dmi_find_cru * * Routine Description: - * This function checks wether or not a SMBIOS/DMI record is + * This function checks whether or not a SMBIOS/DMI record is * the 64bit CRU info or not - * - * Return Value: - * 0 : SUCCESS - if record found - * <0 : FAILURE - if record not found */ static void __devinit dmi_find_cru(const struct dmi_header *dm) { @@ -434,138 +395,11 @@ static void __devinit dmi_find_cru(const struct dmi_header *dm) } } -/* - * dmi_table - * - * Routine Description: - * Decode the SMBIOS/DMI table and check if we have a 64bit CRU record - * or not. - * - * We have to be cautious here. We have seen BIOSes with DMI pointers - * pointing to completely the wrong place for example - */ -static void __devinit dmi_table(u8 *buf, int len, int num, - void (*decode)(const struct dmi_header *)) -{ - u8 *data = buf; - int i = 0; - - /* - * Stop when we see all the items the table claimed to have - * OR we run off the end of the table (also happens) - */ - while ((i < num) && (data - buf + sizeof(struct dmi_header)) <= len) { - const struct dmi_header *dm = (const struct dmi_header *)data; - - /* - * We want to know the total length (formated area and strings) - * before decoding to make sure we won't run off the table in - * dmi_decode or dmi_string - */ - data += dm->length; - while ((data - buf < len - 1) && (data[0] || data[1])) - data++; - if (data - buf < len - 1) - decode(dm); - data += 2; - i++; - } -} - -/* - * smbios_present - * - * Routine Description: - * This function parses the SMBIOS entry point table to retrieve - * the 64 bit CRU Service. - * - * Return Value: - * 0 : SUCCESS - * <0 : FAILURE - */ -static int __devinit smbios_present(const char __iomem *p) -{ - struct smbios_entry_point *eps = - (struct smbios_entry_point *) p; - int length; - u8 *buf; - - /* check if we have indeed the SMBIOS table entry point */ - if ((strncmp((char *)eps->anchor, "_SM_", - sizeof(eps->anchor))) == 0) { - length = eps->length; - - /* SMBIOS v2.1 implementation might use 0x1e */ - if ((length == 0x1e) && - (eps->major_ver == 2) && - (eps->minor_ver == 1)) - length = 0x1f; - - /* - * Now we will check: - * - SMBIOS checksum must be 0 - * - intermediate anchor should be _DMI_ - * - intermediate checksum should be 0 - */ - if ((bios_checksum(p, length)) && - (strncmp((char *)eps->intermediate_anchor, "_DMI_", - sizeof(eps->intermediate_anchor)) == 0) && - (bios_checksum(p+0x10, 15))) { - buf = ioremap(eps->table_address, eps->table_length); - if (buf == NULL) - return -ENODEV; - - - /* Scan the DMI table for the 64 bit CRU service */ - dmi_table(buf, eps->table_length, - eps->table_num_structs, dmi_find_cru); - - iounmap(buf); - return 0; - } - } - - return -ENODEV; -} - -static int __devinit smbios_scan_machine(void) -{ - char __iomem *p, *q; - int rc; - - if (efi_enabled) { - if (efi.smbios == EFI_INVALID_TABLE_ADDR) - return -ENODEV; - - p = ioremap(efi.smbios, 32); - if (p == NULL) - return -ENOMEM; - - rc = smbios_present(p); - iounmap(p); - } else { - /* - * Search from 0x0f0000 through 0x0fffff, inclusive. - */ - p = ioremap(PCI_ROM_BASE1, ROM_SIZE); - if (p == NULL) - return -ENOMEM; - - for (q = p; q < p + ROM_SIZE; q += 16) { - rc = smbios_present(q); - if (!rc) { - break; - } - } - iounmap(p); - } -} - static int __devinit detect_cru_service(void) { cru_rom_addr = NULL; - smbios_scan_machine(); /* will become dmi_walk(dmi_find_cru); */ + dmi_walk(dmi_find_cru); /* if cru_rom_addr has been set then we found a CRU service */ return ((cru_rom_addr != NULL)? 0: -ENODEV); diff --git a/drivers/watchdog/it8712f_wdt.c b/drivers/watchdog/it8712f_wdt.c index 1b6d7d1b715d..1efcad3b6fca 100644 --- a/drivers/watchdog/it8712f_wdt.c +++ b/drivers/watchdog/it8712f_wdt.c @@ -7,7 +7,8 @@ * * drivers/char/watchdog/scx200_wdt.c * drivers/hwmon/it87.c - * IT8712F EC-LPC I/O Preliminary Specification 0.9.2.pdf + * IT8712F EC-LPC I/O Preliminary Specification 0.8.2 + * IT8712F EC-LPC I/O Preliminary Specification 0.9.3 * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -40,6 +41,7 @@ MODULE_DESCRIPTION("IT8712F Watchdog Driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); +static int max_units = 255; static int margin = 60; /* in seconds */ module_param(margin, int, 0); MODULE_PARM_DESC(margin, "Watchdog margin in seconds"); @@ -51,6 +53,7 @@ MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close"); static struct semaphore it8712f_wdt_sem; static unsigned expect_close; static spinlock_t io_lock; +static unsigned char revision; /* Dog Food address - We use the game port address */ static unsigned short address; @@ -108,6 +111,15 @@ superio_inw(int reg) return val; } +static void +superio_outw(int val, int reg) +{ + outb(reg++, REG); + outb((val >> 8) & 0xff, VAL); + outb(reg, REG); + outb(val & 0xff, VAL); +} + static inline void superio_select(int ldn) { @@ -143,15 +155,33 @@ static void it8712f_wdt_update_margin(void) { int config = WDT_OUT_KRST | WDT_OUT_PWROK; - - printk(KERN_INFO NAME ": timer margin %d seconds\n", margin); - - /* The timeout register only has 8bits wide */ - if (margin < 256) - config |= WDT_UNIT_SEC; /* else UNIT are MINUTES */ + int units = margin; + + /* Switch to minutes precision if the configured margin + * value does not fit within the register width. + */ + if (units <= max_units) { + config |= WDT_UNIT_SEC; /* else UNIT is MINUTES */ + printk(KERN_INFO NAME ": timer margin %d seconds\n", units); + } else { + units /= 60; + printk(KERN_INFO NAME ": timer margin %d minutes\n", units); + } superio_outb(config, WDT_CONFIG); - superio_outb((margin > 255) ? (margin / 60) : margin, WDT_TIMEOUT); + if (revision >= 0x08) + superio_outw(units, WDT_TIMEOUT); + else + superio_outb(units, WDT_TIMEOUT); +} + +static int +it8712f_wdt_get_status(void) +{ + if (superio_inb(WDT_CONTROL) & 0x01) + return WDIOF_CARDRESET; + else + return 0; } static void @@ -234,7 +264,7 @@ it8712f_wdt_ioctl(struct inode *inode, struct file *file, .firmware_version = 1, .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, }; - int new_margin; + int value; switch (cmd) { default: @@ -244,17 +274,27 @@ it8712f_wdt_ioctl(struct inode *inode, struct file *file, return -EFAULT; return 0; case WDIOC_GETSTATUS: + superio_enter(); + superio_select(LDN_GPIO); + + value = it8712f_wdt_get_status(); + + superio_exit(); + + return put_user(value, p); case WDIOC_GETBOOTSTATUS: return put_user(0, p); case WDIOC_KEEPALIVE: it8712f_wdt_ping(); return 0; case WDIOC_SETTIMEOUT: - if (get_user(new_margin, p)) + if (get_user(value, p)) return -EFAULT; - if (new_margin < 1) + if (value < 1) + return -EINVAL; + if (value > (max_units * 60)) return -EINVAL; - margin = new_margin; + margin = value; superio_enter(); superio_select(LDN_GPIO); @@ -262,6 +302,7 @@ it8712f_wdt_ioctl(struct inode *inode, struct file *file, superio_exit(); it8712f_wdt_ping(); + /* Fall through */ case WDIOC_GETTIMEOUT: if (put_user(margin, p)) return -EFAULT; @@ -336,9 +377,18 @@ it8712f_wdt_find(unsigned short *address) } err = 0; - printk(KERN_DEBUG NAME ": Found IT%04xF chip revision %d - " + revision = superio_inb(DEVREV) & 0x0f; + + /* Later revisions have 16-bit values per datasheet 0.9.1 */ + if (revision >= 0x08) + max_units = 65535; + + if (margin > (max_units * 60)) + margin = (max_units * 60); + + printk(KERN_INFO NAME ": Found IT%04xF chip revision %d - " "using DogFood address 0x%x\n", - chip_type, superio_inb(DEVREV) & 0x0f, *address); + chip_type, revision, *address); exit: superio_exit(); diff --git a/drivers/watchdog/machzwd.c b/drivers/watchdog/machzwd.c index e6e07b4575eb..6905135a776c 100644 --- a/drivers/watchdog/machzwd.c +++ b/drivers/watchdog/machzwd.c @@ -141,7 +141,7 @@ static unsigned long next_heartbeat = 0; #ifndef ZF_DEBUG # define dprintk(format, args...) #else -# define dprintk(format, args...) printk(KERN_DEBUG PFX ":%s:%d: " format, __FUNCTION__, __LINE__ , ## args) +# define dprintk(format, args...) printk(KERN_DEBUG PFX ":%s:%d: " format, __func__, __LINE__ , ## args) #endif diff --git a/drivers/watchdog/mtx-1_wdt.c b/drivers/watchdog/mtx-1_wdt.c index 789831b3fa00..10b89f2703bd 100644 --- a/drivers/watchdog/mtx-1_wdt.c +++ b/drivers/watchdog/mtx-1_wdt.c @@ -59,9 +59,9 @@ static int ticks = 100 * HZ; static struct { struct completion stop; - volatile int running; + int running; struct timer_list timer; - volatile int queue; + int queue; int default_ticks; unsigned long inuse; unsigned gpio; diff --git a/drivers/watchdog/pcwd_usb.c b/drivers/watchdog/pcwd_usb.c index 0f3fd6c9c354..bf443d077a1e 100644 --- a/drivers/watchdog/pcwd_usb.c +++ b/drivers/watchdog/pcwd_usb.c @@ -179,11 +179,11 @@ static void usb_pcwd_intr_done(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status); + dbg("%s - urb shutting down with status: %d", __func__, urb->status); return; /* -EPIPE: should clear the halt */ default: /* error */ - dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status); + dbg("%s - nonzero urb status received: %d", __func__, urb->status); goto resubmit; } diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c index 5d1c15f83d23..7645e8812156 100644 --- a/drivers/watchdog/s3c2410_wdt.c +++ b/drivers/watchdog/s3c2410_wdt.c @@ -144,7 +144,7 @@ static int s3c2410wdt_start(void) } DBG("%s: wdt_count=0x%08x, wtcon=%08lx\n", - __FUNCTION__, wdt_count, wtcon); + __func__, wdt_count, wtcon); writel(wdt_count, wdt_base + S3C2410_WTDAT); writel(wdt_count, wdt_base + S3C2410_WTCNT); @@ -167,7 +167,7 @@ static int s3c2410wdt_set_heartbeat(int timeout) count = timeout * freq; DBG("%s: count=%d, timeout=%d, freq=%d\n", - __FUNCTION__, count, timeout, freq); + __func__, count, timeout, freq); /* if the count is bigger than the watchdog register, then work out what we need to do (and if) we can @@ -189,7 +189,7 @@ static int s3c2410wdt_set_heartbeat(int timeout) tmr_margin = timeout; DBG("%s: timeout=%d, divisor=%d, count=%d (%08x)\n", - __FUNCTION__, timeout, divisor, count, count/divisor); + __func__, timeout, divisor, count, count/divisor); count /= divisor; wdt_count = count; @@ -355,7 +355,7 @@ static int s3c2410wdt_probe(struct platform_device *pdev) int ret; int size; - DBG("%s: probe=%p\n", __FUNCTION__, pdev); + DBG("%s: probe=%p\n", __func__, pdev); dev = &pdev->dev; wdt_dev = &pdev->dev; diff --git a/drivers/watchdog/shwdt.c b/drivers/watchdog/shwdt.c index 61dde863bd40..1277f7e9cc54 100644 --- a/drivers/watchdog/shwdt.c +++ b/drivers/watchdog/shwdt.c @@ -298,7 +298,7 @@ static int sh_wdt_mmap(struct file *file, struct vm_area_struct *vma) if (io_remap_pfn_range(vma, vma->vm_start, addr >> PAGE_SHIFT, PAGE_SIZE, vma->vm_page_prot)) { printk(KERN_ERR PFX "%s: io_remap_pfn_range failed\n", - __FUNCTION__); + __func__); return -EAGAIN; } |