diff options
Diffstat (limited to 'drivers')
434 files changed, 10055 insertions, 5366 deletions
diff --git a/drivers/acorn/char/defkeymap-l7200.c b/drivers/acorn/char/defkeymap-l7200.c index 28a5fbc6aa1..93d80a1c36f 100644 --- a/drivers/acorn/char/defkeymap-l7200.c +++ b/drivers/acorn/char/defkeymap-l7200.c @@ -347,40 +347,40 @@ char *func_table[MAX_NR_FUNC] = { }; struct kbdiacruc accent_table[MAX_DIACR] = { - {'`', 'A', '\300'}, {'`', 'a', '\340'}, - {'\'', 'A', '\301'}, {'\'', 'a', '\341'}, - {'^', 'A', '\302'}, {'^', 'a', '\342'}, - {'~', 'A', '\303'}, {'~', 'a', '\343'}, - {'"', 'A', '\304'}, {'"', 'a', '\344'}, - {'O', 'A', '\305'}, {'o', 'a', '\345'}, - {'0', 'A', '\305'}, {'0', 'a', '\345'}, - {'A', 'A', '\305'}, {'a', 'a', '\345'}, - {'A', 'E', '\306'}, {'a', 'e', '\346'}, - {',', 'C', '\307'}, {',', 'c', '\347'}, - {'`', 'E', '\310'}, {'`', 'e', '\350'}, - {'\'', 'E', '\311'}, {'\'', 'e', '\351'}, - {'^', 'E', '\312'}, {'^', 'e', '\352'}, - {'"', 'E', '\313'}, {'"', 'e', '\353'}, - {'`', 'I', '\314'}, {'`', 'i', '\354'}, - {'\'', 'I', '\315'}, {'\'', 'i', '\355'}, - {'^', 'I', '\316'}, {'^', 'i', '\356'}, - {'"', 'I', '\317'}, {'"', 'i', '\357'}, - {'-', 'D', '\320'}, {'-', 'd', '\360'}, - {'~', 'N', '\321'}, {'~', 'n', '\361'}, - {'`', 'O', '\322'}, {'`', 'o', '\362'}, - {'\'', 'O', '\323'}, {'\'', 'o', '\363'}, - {'^', 'O', '\324'}, {'^', 'o', '\364'}, - {'~', 'O', '\325'}, {'~', 'o', '\365'}, - {'"', 'O', '\326'}, {'"', 'o', '\366'}, - {'/', 'O', '\330'}, {'/', 'o', '\370'}, - {'`', 'U', '\331'}, {'`', 'u', '\371'}, - {'\'', 'U', '\332'}, {'\'', 'u', '\372'}, - {'^', 'U', '\333'}, {'^', 'u', '\373'}, - {'"', 'U', '\334'}, {'"', 'u', '\374'}, - {'\'', 'Y', '\335'}, {'\'', 'y', '\375'}, - {'T', 'H', '\336'}, {'t', 'h', '\376'}, - {'s', 's', '\337'}, {'"', 'y', '\377'}, - {'s', 'z', '\337'}, {'i', 'j', '\377'}, + {'`', 'A', 0300}, {'`', 'a', 0340}, + {'\'', 'A', 0301}, {'\'', 'a', 0341}, + {'^', 'A', 0302}, {'^', 'a', 0342}, + {'~', 'A', 0303}, {'~', 'a', 0343}, + {'"', 'A', 0304}, {'"', 'a', 0344}, + {'O', 'A', 0305}, {'o', 'a', 0345}, + {'0', 'A', 0305}, {'0', 'a', 0345}, + {'A', 'A', 0305}, {'a', 'a', 0345}, + {'A', 'E', 0306}, {'a', 'e', 0346}, + {',', 'C', 0307}, {',', 'c', 0347}, + {'`', 'E', 0310}, {'`', 'e', 0350}, + {'\'', 'E', 0311}, {'\'', 'e', 0351}, + {'^', 'E', 0312}, {'^', 'e', 0352}, + {'"', 'E', 0313}, {'"', 'e', 0353}, + {'`', 'I', 0314}, {'`', 'i', 0354}, + {'\'', 'I', 0315}, {'\'', 'i', 0355}, + {'^', 'I', 0316}, {'^', 'i', 0356}, + {'"', 'I', 0317}, {'"', 'i', 0357}, + {'-', 'D', 0320}, {'-', 'd', 0360}, + {'~', 'N', 0321}, {'~', 'n', 0361}, + {'`', 'O', 0322}, {'`', 'o', 0362}, + {'\'', 'O', 0323}, {'\'', 'o', 0363}, + {'^', 'O', 0324}, {'^', 'o', 0364}, + {'~', 'O', 0325}, {'~', 'o', 0365}, + {'"', 'O', 0326}, {'"', 'o', 0366}, + {'/', 'O', 0330}, {'/', 'o', 0370}, + {'`', 'U', 0331}, {'`', 'u', 0371}, + {'\'', 'U', 0332}, {'\'', 'u', 0372}, + {'^', 'U', 0333}, {'^', 'u', 0373}, + {'"', 'U', 0334}, {'"', 'u', 0374}, + {'\'', 'Y', 0335}, {'\'', 'y', 0375}, + {'T', 'H', 0336}, {'t', 'h', 0376}, + {'s', 's', 0337}, {'"', 'y', 0377}, + {'s', 'z', 0337}, {'i', 'j', 0377}, }; unsigned int accent_table_size = 68; diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index f688c214be0..b4f5e854282 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 d25ef961415..44ad90c03c2 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 f6215e80980..d5729d5dc19 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 ce3c0a2cbac..5b6760e0f95 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 24a7865a57c..6c5da83cdb6 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 307cef65c24..fa44fb96fc3 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 caf873c14bf..7222a18a031 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/fan.c b/drivers/acpi/fan.c index c8e3cba423e..4d535c50d82 100644 --- a/drivers/acpi/fan.c +++ b/drivers/acpi/fan.c @@ -260,24 +260,22 @@ static int acpi_fan_add(struct acpi_device *device) result = PTR_ERR(cdev); goto end; } - if (cdev) { - printk(KERN_INFO PREFIX - "%s is registered as cooling_device%d\n", - device->dev.bus_id, cdev->id); - - acpi_driver_data(device) = cdev; - result = sysfs_create_link(&device->dev.kobj, - &cdev->device.kobj, - "thermal_cooling"); - if (result) - return result; - - result = sysfs_create_link(&cdev->device.kobj, - &device->dev.kobj, - "device"); - if (result) - return result; - } + printk(KERN_INFO PREFIX + "%s is registered as cooling_device%d\n", + device->dev.bus_id, cdev->id); + + acpi_driver_data(device) = cdev; + result = sysfs_create_link(&device->dev.kobj, + &cdev->device.kobj, + "thermal_cooling"); + if (result) + return result; + + result = sysfs_create_link(&cdev->device.kobj, + &device->dev.kobj, + "device"); + if (result) + return result; result = acpi_fan_add_fs(device); if (result) diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 8edba7b678e..a697fb6cf05 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 7f19859580c..89022a74fae 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 f14ff1ffab2..c3fed31166b 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 a3cc8a98255..3a136f6c66a 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -674,22 +674,20 @@ static int __cpuinit acpi_processor_start(struct acpi_device *device) result = PTR_ERR(pr->cdev); goto end; } - if (pr->cdev) { - printk(KERN_INFO PREFIX - "%s is registered as cooling_device%d\n", - device->dev.bus_id, pr->cdev->id); - - result = sysfs_create_link(&device->dev.kobj, - &pr->cdev->device.kobj, - "thermal_cooling"); - if (result) - return result; - result = sysfs_create_link(&pr->cdev->device.kobj, - &device->dev.kobj, - "device"); - if (result) - return result; - } + printk(KERN_INFO PREFIX + "%s is registered as cooling_device%d\n", + device->dev.bus_id, pr->cdev->id); + + result = sysfs_create_link(&device->dev.kobj, + &pr->cdev->device.kobj, + "thermal_cooling"); + if (result) + return result; + result = sysfs_create_link(&pr->cdev->device.kobj, + &device->dev.kobj, + "device"); + if (result) + return result; if (pr->flags.throttling) { printk(KERN_INFO PREFIX "%s [%s] (supports", @@ -840,17 +838,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 +886,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 +897,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 6f3b217699e..788da9781f8 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: @@ -1481,7 +1487,6 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev, return 0; } - acpi_unlazy_tlb(smp_processor_id()); /* * Must be done before busmaster disable as we might need to * access HPET ! @@ -1571,6 +1576,8 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, return 0; } + acpi_unlazy_tlb(smp_processor_id()); + /* Tell the scheduler that we are going deep-idle: */ sched_clock_idle_sleep_event(); /* @@ -1686,7 +1693,9 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr) switch (cx->type) { case ACPI_STATE_C1: state->flags |= CPUIDLE_FLAG_SHALLOW; - state->flags |= CPUIDLE_FLAG_TIME_VALID; + if (cx->entry_method == ACPI_CSTATE_FFH) + state->flags |= CPUIDLE_FLAG_TIME_VALID; + state->enter = acpi_idle_enter_c1; dev->safe_state = state; break; diff --git a/drivers/acpi/sbshc.c b/drivers/acpi/sbshc.c index a2cf3008ce6..bcf2c70fca8 100644 --- a/drivers/acpi/sbshc.c +++ b/drivers/acpi/sbshc.c @@ -130,7 +130,6 @@ static int acpi_smbus_transaction(struct acpi_smb_hc *hc, u8 protocol, goto end; } smb_hc_write(hc, ACPI_SMB_COMMAND, command); - smb_hc_write(hc, ACPI_SMB_COMMAND, command); if (!(protocol & 0x01)) { smb_hc_write(hc, ACPI_SMB_BLOCK_COUNT, length); for (i = 0; i < length; ++i) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 3fac011f9cf..e6ce262b5d4 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -39,20 +39,26 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias, int size) { int len; + int count; - if (!acpi_dev->flags.hardware_id) + if (!acpi_dev->flags.hardware_id && !acpi_dev->flags.compatible_ids) return -ENODEV; - len = snprintf(modalias, size, "acpi:%s:", - acpi_dev->pnp.hardware_id); - if (len < 0 || len >= size) - return -EINVAL; + len = snprintf(modalias, size, "acpi:"); size -= len; + if (acpi_dev->flags.hardware_id) { + count = snprintf(&modalias[len], size, "%s:", + acpi_dev->pnp.hardware_id); + if (count < 0 || count >= size) + return -EINVAL; + len += count; + size -= count; + } + if (acpi_dev->flags.compatible_ids) { struct acpi_compatible_id_list *cid_list; int i; - int count; cid_list = acpi_dev->pnp.cid_list; for (i = 0; i < cid_list->count; i++) { @@ -609,7 +615,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 +973,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 293a1cbb47c..d2f71a54726 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 55cf4c05bb7..4749f379a91 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 8d4b79b4f93..c4e00ac8ea8 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 9e8c20c6a0b..0a43c8e0eff 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 c7e128e5369..7361204b1ee 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 76ee766c84f..e08b3fa6639 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 eba55b7d6c9..44ea60cf21c 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 12cce69b544..fe09b57de61 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; @@ -734,21 +734,19 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) if (IS_ERR(device->cdev)) return; - if (device->cdev) { - printk(KERN_INFO PREFIX - "%s is registered as cooling_device%d\n", - device->dev->dev.bus_id, device->cdev->id); - result = sysfs_create_link(&device->dev->dev.kobj, - &device->cdev->device.kobj, - "thermal_cooling"); - if (result) - printk(KERN_ERR PREFIX "Create sysfs link\n"); - result = sysfs_create_link(&device->cdev->device.kobj, - &device->dev->dev.kobj, - "device"); - if (result) - printk(KERN_ERR PREFIX "Create sysfs link\n"); - } + printk(KERN_INFO PREFIX + "%s is registered as cooling_device%d\n", + device->dev->dev.bus_id, device->cdev->id); + result = sysfs_create_link(&device->dev->dev.kobj, + &device->cdev->device.kobj, + "thermal_cooling"); + if (result) + printk(KERN_ERR PREFIX "Create sysfs link\n"); + result = sysfs_create_link(&device->cdev->device.kobj, + &device->dev->dev.kobj, + "device"); + if (result) + printk(KERN_ERR PREFIX "Create sysfs link\n"); } if (device->cap._DCS && device->cap._DSS){ static int count = 0; @@ -807,40 +805,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 +1170,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 +1335,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 efacc9f8bfe..c33b1c6e93b 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 ba8f7f4dfa1..25aba69b59b 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 701651e37c8..0511e6f0bb5 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 1db93b61907..b1eb4e24c86 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); @@ -186,6 +190,7 @@ enum { AHCI_HFLAG_NO_MSI = (1 << 5), /* no PCI MSI */ AHCI_HFLAG_NO_PMP = (1 << 6), /* no PMP */ AHCI_HFLAG_NO_HOTPLUG = (1 << 7), /* ignore PxSERR.DIAG.N */ + AHCI_HFLAG_SECT255 = (1 << 8), /* max 255 sectors */ /* ap->flags bits */ @@ -255,6 +260,7 @@ static void ahci_vt8251_error_handler(struct ata_port *ap); static void ahci_p5wdh_error_handler(struct ata_port *ap); static void ahci_post_internal_cmd(struct ata_queued_cmd *qc); static int ahci_port_resume(struct ata_port *ap); +static void ahci_dev_config(struct ata_device *dev); static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl); static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag, u32 opts); @@ -294,6 +300,8 @@ static const struct ata_port_operations ahci_ops = { .check_altstatus = ahci_check_status, .dev_select = ata_noop_dev_select, + .dev_config = ahci_dev_config, + .tf_read = ahci_tf_read, .qc_defer = sata_pmp_qc_defer_cmd_switch, @@ -425,7 +433,8 @@ static const struct ata_port_info ahci_port_info[] = { /* board_ahci_sb600 */ { AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL | - AHCI_HFLAG_32BIT_ONLY | AHCI_HFLAG_NO_PMP), + AHCI_HFLAG_32BIT_ONLY | + AHCI_HFLAG_SECT255 | AHCI_HFLAG_NO_PMP), .flags = AHCI_FLAG_COMMON, .link_flags = AHCI_LFLAG_COMMON, .pio_mask = 0x1f, /* pio0-4 */ @@ -563,6 +572,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 */ @@ -571,6 +592,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, @@ -645,6 +667,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); @@ -668,7 +691,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; @@ -680,12 +703,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 */ @@ -1072,29 +1099,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; @@ -1146,9 +1179,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); @@ -1176,6 +1214,17 @@ static void ahci_init_controller(struct ata_host *host) VPRINTK("HOST_CTL 0x%x\n", tmp); } +static void ahci_dev_config(struct ata_device *dev) +{ + struct ahci_host_priv *hpriv = dev->link->ap->host->private_data; + + if (hpriv->flags & AHCI_HFLAG_SECT255) { + dev->max_sectors = 255; + ata_dev_printk(dev, KERN_INFO, + "SB600 AHCI: limiting to 255 sectors per cmd\n"); + } +} + static unsigned int ahci_dev_classify(struct ata_port *ap) { void __iomem *port_mmio = ahci_port_base(ap); @@ -2217,7 +2266,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 9e8ec19260a..bf98a566ada 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 4fbcce758b0..c4248b37ff6 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; @@ -1415,12 +1416,12 @@ static int ata_hpa_resize(struct ata_device *dev) /* read native max address */ rc = ata_read_native_max_address(dev, &native_sectors); if (rc) { - /* If HPA isn't going to be unlocked, skip HPA - * resizing from the next try. + /* If device aborted the command or HPA isn't going to + * be unlocked, skip HPA resizing. */ - if (!ata_ignore_hpa) { + if (rc == -EACCES || !ata_ignore_hpa) { ata_dev_printk(dev, KERN_WARNING, "HPA support seems " - "broken, will skip HPA handling\n"); + "broken, skipping HPA handling\n"); dev->horkage |= ATA_HORKAGE_BROKEN_HPA; /* we can continue if device aborted the command */ @@ -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: @@ -2091,24 +2092,34 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, id, sizeof(id[0]) * ATA_ID_WORDS, 0); if (err_mask) { if (err_mask & AC_ERR_NODEV_HINT) { - DPRINTK("ata%u.%d: NODEV after polling detection\n", - ap->print_id, dev->devno); + ata_dev_printk(dev, KERN_DEBUG, + "NODEV after polling detection\n"); return -ENOENT; } - /* Device or controller might have reported the wrong - * device class. Give a shot at the other IDENTIFY if - * the current one is aborted by the device. - */ - if (may_fallback && - (err_mask == AC_ERR_DEV) && (tf.feature & ATA_ABORTED)) { - may_fallback = 0; + if ((err_mask == AC_ERR_DEV) && (tf.feature & ATA_ABORTED)) { + /* Device or controller might have reported + * the wrong device class. Give a shot at the + * other IDENTIFY if the current one is + * aborted by the device. + */ + if (may_fallback) { + may_fallback = 0; - if (class == ATA_DEV_ATA) - class = ATA_DEV_ATAPI; - else - class = ATA_DEV_ATA; - goto retry; + if (class == ATA_DEV_ATA) + class = ATA_DEV_ATAPI; + else + class = ATA_DEV_ATA; + goto retry; + } + + /* Control reaches here iff the device aborted + * both flavors of IDENTIFYs which happens + * sometimes with phantom devices. + */ + ata_dev_printk(dev, KERN_DEBUG, + "both IDENTIFYs aborted, assuming NODEV\n"); + return -ENOENT; } rc = -EIO; @@ -2253,12 +2264,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 +2290,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 +2522,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 698ce2cea52..681252fd814 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-scsi.c b/drivers/ata/libata-scsi.c index 7b1f1ee8131..15795394b0a 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -527,6 +527,14 @@ static struct ata_queued_cmd *ata_scsi_qc_new(struct ata_device *dev, return qc; } +static void ata_qc_set_pc_nbytes(struct ata_queued_cmd *qc) +{ + struct scsi_cmnd *scmd = qc->scsicmd; + + qc->extrabytes = scmd->request->extra_len; + qc->nbytes = scsi_bufflen(scmd) + qc->extrabytes; +} + /** * ata_dump_status - user friendly display of error info * @id: id of the port in question @@ -862,9 +870,10 @@ static int ata_scsi_dev_config(struct scsi_device *sdev, struct request_queue *q = sdev->request_queue; void *buf; - /* set the min alignment */ + /* set the min alignment and padding */ blk_queue_update_dma_alignment(sdev->request_queue, ATA_DMA_PAD_SZ - 1); + blk_queue_dma_pad(sdev->request_queue, ATA_DMA_PAD_SZ - 1); /* configure draining */ buf = kmalloc(ATAPI_MAX_DRAIN, q->bounce_gfp | GFP_KERNEL); @@ -2538,7 +2547,7 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc) } qc->tf.command = ATA_CMD_PACKET; - qc->nbytes = scsi_bufflen(scmd); + ata_qc_set_pc_nbytes(qc); /* check whether ATAPI DMA is safe */ if (!using_pio && ata_check_atapi_dma(qc)) @@ -2549,7 +2558,7 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc) * want to set it properly, and for DMA where it is * effectively meaningless. */ - nbytes = min(scmd->request->raw_data_len, (unsigned int)63 * 1024); + nbytes = min(ata_qc_raw_nbytes(qc), (unsigned int)63 * 1024); /* Most ATAPI devices which honor transfer chunk size don't * behave according to the spec when odd chunk size which @@ -2875,7 +2884,7 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc) * TODO: find out if we need to do more here to * cover scatter/gather case. */ - qc->nbytes = scsi_bufflen(scmd); + ata_qc_set_pc_nbytes(qc); /* request result TF and be quiet about device error */ qc->flags |= ATA_QCFLAG_RESULT_TF | ATA_QCFLAG_QUIET; diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 60cd4b17976..20dc572fb45 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 7e68edf3c0f..8786455c901 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_hpt366.c b/drivers/ata/pata_hpt366.c index 0713872cf65..a742efa0da2 100644 --- a/drivers/ata/pata_hpt366.c +++ b/drivers/ata/pata_hpt366.c @@ -27,7 +27,7 @@ #include <linux/libata.h> #define DRV_NAME "pata_hpt366" -#define DRV_VERSION "0.6.1" +#define DRV_VERSION "0.6.2" struct hpt_clock { u8 xfer_speed; @@ -180,9 +180,9 @@ static unsigned long hpt366_filter(struct ata_device *adev, unsigned long mask) if (hpt_dma_blacklisted(adev, "UDMA", bad_ata33)) mask &= ~ATA_MASK_UDMA; if (hpt_dma_blacklisted(adev, "UDMA3", bad_ata66_3)) - mask &= ~(0x07 << ATA_SHIFT_UDMA); + mask &= ~(0xF8 << ATA_SHIFT_UDMA); if (hpt_dma_blacklisted(adev, "UDMA4", bad_ata66_4)) - mask &= ~(0x0F << ATA_SHIFT_UDMA); + mask &= ~(0xF0 << ATA_SHIFT_UDMA); } return ata_pci_default_filter(adev, mask); } diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c index 68eb34929ce..9a10878b2ad 100644 --- a/drivers/ata/pata_hpt37x.c +++ b/drivers/ata/pata_hpt37x.c @@ -24,7 +24,7 @@ #include <linux/libata.h> #define DRV_NAME "pata_hpt37x" -#define DRV_VERSION "0.6.9" +#define DRV_VERSION "0.6.11" struct hpt_clock { u8 xfer_speed; @@ -281,7 +281,7 @@ static unsigned long hpt370_filter(struct ata_device *adev, unsigned long mask) if (hpt_dma_blacklisted(adev, "UDMA", bad_ata33)) mask &= ~ATA_MASK_UDMA; if (hpt_dma_blacklisted(adev, "UDMA100", bad_ata100_5)) - mask &= ~(0x1F << ATA_SHIFT_UDMA); + mask &= ~(0xE0 << ATA_SHIFT_UDMA); } return ata_pci_default_filter(adev, mask); } @@ -297,7 +297,7 @@ static unsigned long hpt370a_filter(struct ata_device *adev, unsigned long mask) { if (adev->class == ATA_DEV_ATA) { if (hpt_dma_blacklisted(adev, "UDMA100", bad_ata100_5)) - mask &= ~ (0x1F << ATA_SHIFT_UDMA); + mask &= ~(0xE0 << ATA_SHIFT_UDMA); } return ata_pci_default_filter(adev, mask); } diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c index 109ddd42c26..257951d03db 100644 --- a/drivers/ata/pata_it821x.c +++ b/drivers/ata/pata_it821x.c @@ -564,7 +564,7 @@ static int it821x_check_atapi_dma(struct ata_queued_cmd *qc) struct it821x_dev *itdev = ap->private_data; /* Only use dma for transfers to/from the media. */ - if (qc->nbytes < 2048) + if (ata_qc_raw_nbytes(qc) < 2048) return -EOPNOTSUPP; /* No ATAPI DMA in smart mode */ diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c index 028af5dbeed..511c89b9bae 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 00000000000..4ce9b03fe6c --- /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/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c index 9c523fbf529..a589c0fa0db 100644 --- a/drivers/ata/pata_serverworks.c +++ b/drivers/ata/pata_serverworks.c @@ -226,7 +226,7 @@ static unsigned long serverworks_csb_filter(struct ata_device *adev, unsigned lo for (i = 0; (p = csb_bad_ata100[i]) != NULL; i++) { if (!strcmp(p, model_num)) - mask &= ~(0x1F << ATA_SHIFT_UDMA); + mask &= ~(0xE0 << ATA_SHIFT_UDMA); } return ata_pci_default_filter(adev, mask); } diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c index f251a5f569d..11c1afea2db 100644 --- a/drivers/ata/sata_promise.c +++ b/drivers/ata/sata_promise.c @@ -46,7 +46,7 @@ #include "sata_promise.h" #define DRV_NAME "sata_promise" -#define DRV_VERSION "2.11" +#define DRV_VERSION "2.12" enum { PDC_MAX_PORTS = 4, @@ -145,7 +145,9 @@ static int pdc_old_sata_check_atapi_dma(struct ata_queued_cmd *qc); static void pdc_irq_clear(struct ata_port *ap); static unsigned int pdc_qc_issue_prot(struct ata_queued_cmd *qc); static void pdc_freeze(struct ata_port *ap); +static void pdc_sata_freeze(struct ata_port *ap); static void pdc_thaw(struct ata_port *ap); +static void pdc_sata_thaw(struct ata_port *ap); static void pdc_pata_error_handler(struct ata_port *ap); static void pdc_sata_error_handler(struct ata_port *ap); static void pdc_post_internal_cmd(struct ata_queued_cmd *qc); @@ -180,8 +182,8 @@ static const struct ata_port_operations pdc_sata_ops = { .qc_prep = pdc_qc_prep, .qc_issue = pdc_qc_issue_prot, - .freeze = pdc_freeze, - .thaw = pdc_thaw, + .freeze = pdc_sata_freeze, + .thaw = pdc_sata_thaw, .error_handler = pdc_sata_error_handler, .post_internal_cmd = pdc_post_internal_cmd, .cable_detect = pdc_sata_cable_detect, @@ -205,8 +207,8 @@ static const struct ata_port_operations pdc_old_sata_ops = { .qc_prep = pdc_qc_prep, .qc_issue = pdc_qc_issue_prot, - .freeze = pdc_freeze, - .thaw = pdc_thaw, + .freeze = pdc_sata_freeze, + .thaw = pdc_sata_thaw, .error_handler = pdc_sata_error_handler, .post_internal_cmd = pdc_post_internal_cmd, .cable_detect = pdc_sata_cable_detect, @@ -631,6 +633,41 @@ static void pdc_qc_prep(struct ata_queued_cmd *qc) } } +static int pdc_is_sataii_tx4(unsigned long flags) +{ + const unsigned long mask = PDC_FLAG_GEN_II | PDC_FLAG_4_PORTS; + return (flags & mask) == mask; +} + +static unsigned int pdc_port_no_to_ata_no(unsigned int port_no, + int is_sataii_tx4) +{ + static const unsigned char sataii_tx4_port_remap[4] = { 3, 1, 0, 2}; + return is_sataii_tx4 ? sataii_tx4_port_remap[port_no] : port_no; +} + +static unsigned int pdc_sata_nr_ports(const struct ata_port *ap) +{ + return (ap->flags & PDC_FLAG_4_PORTS) ? 4 : 2; +} + +static unsigned int pdc_sata_ata_port_to_ata_no(const struct ata_port *ap) +{ + const struct ata_host *host = ap->host; + unsigned int nr_ports = pdc_sata_nr_ports(ap); + unsigned int i; + + for(i = 0; i < nr_ports && host->ports[i] != ap; ++i) + ; + BUG_ON(i >= nr_ports); + return pdc_port_no_to_ata_no(i, pdc_is_sataii_tx4(ap->flags)); +} + +static unsigned int pdc_sata_hotplug_offset(const struct ata_port *ap) +{ + return (ap->flags & PDC_FLAG_GEN_II) ? PDC2_SATA_PLUG_CSR : PDC_SATA_PLUG_CSR; +} + static void pdc_freeze(struct ata_port *ap) { void __iomem *mmio = ap->ioaddr.cmd_addr; @@ -643,6 +680,29 @@ static void pdc_freeze(struct ata_port *ap) readl(mmio + PDC_CTLSTAT); /* flush */ } +static void pdc_sata_freeze(struct ata_port *ap) +{ + struct ata_host *host = ap->host; + void __iomem *host_mmio = host->iomap[PDC_MMIO_BAR]; + unsigned int hotplug_offset = pdc_sata_hotplug_offset(ap); + unsigned int ata_no = pdc_sata_ata_port_to_ata_no(ap); + u32 hotplug_status; + + /* Disable hotplug events on this port. + * + * Locking: + * 1) hotplug register accesses must be serialised via host->lock + * 2) ap->lock == &ap->host->lock + * 3) ->freeze() and ->thaw() are called with ap->lock held + */ + hotplug_status = readl(host_mmio + hotplug_offset); + hotplug_status |= 0x11 << (ata_no + 16); + writel(hotplug_status, host_mmio + hotplug_offset); + readl(host_mmio + hotplug_offset); /* flush */ + + pdc_freeze(ap); +} + static void pdc_thaw(struct ata_port *ap) { void __iomem *mmio = ap->ioaddr.cmd_addr; @@ -658,6 +718,26 @@ static void pdc_thaw(struct ata_port *ap) readl(mmio + PDC_CTLSTAT); /* flush */ } +static void pdc_sata_thaw(struct ata_port *ap) +{ + struct ata_host *host = ap->host; + void __iomem *host_mmio = host->iomap[PDC_MMIO_BAR]; + unsigned int hotplug_offset = pdc_sata_hotplug_offset(ap); + unsigned int ata_no = pdc_sata_ata_port_to_ata_no(ap); + u32 hotplug_status; + + pdc_thaw(ap); + + /* Enable hotplug events on this port. + * Locking: see pdc_sata_freeze(). + */ + hotplug_status = readl(host_mmio + hotplug_offset); + hotplug_status |= 0x11 << ata_no; + hotplug_status &= ~(0x11 << (ata_no + 16)); + writel(hotplug_status, host_mmio + hotplug_offset); + readl(host_mmio + hotplug_offset); /* flush */ +} + static void pdc_common_error_handler(struct ata_port *ap, ata_reset_fn_t hardreset) { if (!(ap->pflags & ATA_PFLAG_FROZEN)) @@ -765,19 +845,6 @@ static void pdc_irq_clear(struct ata_port *ap) readl(mmio + PDC_INT_SEQMASK); } -static int pdc_is_sataii_tx4(unsigned long flags) -{ - const unsigned long mask = PDC_FLAG_GEN_II | PDC_FLAG_4_PORTS; - return (flags & mask) == mask; -} - -static unsigned int pdc_port_no_to_ata_no(unsigned int port_no, - int is_sataii_tx4) -{ - static const unsigned char sataii_tx4_port_remap[4] = { 3, 1, 0, 2}; - return is_sataii_tx4 ? sataii_tx4_port_remap[port_no] : port_no; -} - static irqreturn_t pdc_interrupt(int irq, void *dev_instance) { struct ata_host *host = dev_instance; @@ -799,6 +866,8 @@ static irqreturn_t pdc_interrupt(int irq, void *dev_instance) mmio_base = host->iomap[PDC_MMIO_BAR]; + spin_lock(&host->lock); + /* read and clear hotplug flags for all ports */ if (host->ports[0]->flags & PDC_FLAG_GEN_II) hotplug_offset = PDC2_SATA_PLUG_CSR; @@ -814,11 +883,9 @@ static irqreturn_t pdc_interrupt(int irq, void *dev_instance) if (mask == 0xffffffff && hotplug_status == 0) { VPRINTK("QUICK EXIT 2\n"); - return IRQ_NONE; + goto done_irq; } - spin_lock(&host->lock); - mask &= 0xffff; /* only 16 tags possible */ if (mask == 0 && hotplug_status == 0) { VPRINTK("QUICK EXIT 3\n"); diff --git a/drivers/atm/firestream.c b/drivers/atm/firestream.c index c662d686154..47c57a4294b 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 f97e050338f..432181ed7bb 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) @@ -1988,19 +1988,19 @@ fore200e_fetch_stats(struct fore200e* fore200e, struct sonet_stats __user *arg) if (fore200e_getstats(fore200e) < 0) return -EIO; - tmp.section_bip = cpu_to_be32(fore200e->stats->oc3.section_bip8_errors); - tmp.line_bip = cpu_to_be32(fore200e->stats->oc3.line_bip24_errors); - tmp.path_bip = cpu_to_be32(fore200e->stats->oc3.path_bip8_errors); - tmp.line_febe = cpu_to_be32(fore200e->stats->oc3.line_febe_errors); - tmp.path_febe = cpu_to_be32(fore200e->stats->oc3.path_febe_errors); - tmp.corr_hcs = cpu_to_be32(fore200e->stats->oc3.corr_hcs_errors); - tmp.uncorr_hcs = cpu_to_be32(fore200e->stats->oc3.ucorr_hcs_errors); - tmp.tx_cells = cpu_to_be32(fore200e->stats->aal0.cells_transmitted) + - cpu_to_be32(fore200e->stats->aal34.cells_transmitted) + - cpu_to_be32(fore200e->stats->aal5.cells_transmitted); - tmp.rx_cells = cpu_to_be32(fore200e->stats->aal0.cells_received) + - cpu_to_be32(fore200e->stats->aal34.cells_received) + - cpu_to_be32(fore200e->stats->aal5.cells_received); + tmp.section_bip = be32_to_cpu(fore200e->stats->oc3.section_bip8_errors); + tmp.line_bip = be32_to_cpu(fore200e->stats->oc3.line_bip24_errors); + tmp.path_bip = be32_to_cpu(fore200e->stats->oc3.path_bip8_errors); + tmp.line_febe = be32_to_cpu(fore200e->stats->oc3.line_febe_errors); + tmp.path_febe = be32_to_cpu(fore200e->stats->oc3.path_febe_errors); + tmp.corr_hcs = be32_to_cpu(fore200e->stats->oc3.corr_hcs_errors); + tmp.uncorr_hcs = be32_to_cpu(fore200e->stats->oc3.ucorr_hcs_errors); + tmp.tx_cells = be32_to_cpu(fore200e->stats->aal0.cells_transmitted) + + be32_to_cpu(fore200e->stats->aal34.cells_transmitted) + + be32_to_cpu(fore200e->stats->aal5.cells_transmitted); + tmp.rx_cells = be32_to_cpu(fore200e->stats->aal0.cells_received) + + be32_to_cpu(fore200e->stats->aal34.cells_received) + + be32_to_cpu(fore200e->stats->aal5.cells_received); if (arg) return copy_to_user(arg, &tmp, sizeof(struct sonet_stats)) ? -EFAULT : 0; @@ -2587,7 +2587,7 @@ fore200e_start_fw(struct fore200e* fore200e) static int __devinit fore200e_load_fw(struct fore200e* fore200e) { - u32* fw_data = (u32*) fore200e->bus->fw_data; + __le32* fw_data = (__le32*) fore200e->bus->fw_data; u32 fw_size = (u32) *fore200e->bus->fw_size / sizeof(u32); struct fw_header* fw_header = (struct fw_header*) fw_data; @@ -2965,8 +2965,8 @@ fore200e_proc_read(struct atm_dev *dev, loff_t* pos, char* page) " 4b5b:\n" " crc_header_errors:\t\t%10u\n" " framing_errors:\t\t%10u\n", - cpu_to_be32(fore200e->stats->phy.crc_header_errors), - cpu_to_be32(fore200e->stats->phy.framing_errors)); + be32_to_cpu(fore200e->stats->phy.crc_header_errors), + be32_to_cpu(fore200e->stats->phy.framing_errors)); if (!left--) return sprintf(page, "\n" @@ -2978,13 +2978,13 @@ fore200e_proc_read(struct atm_dev *dev, loff_t* pos, char* page) " path_febe_errors:\t\t%10u\n" " corr_hcs_errors:\t\t%10u\n" " ucorr_hcs_errors:\t\t%10u\n", - cpu_to_be32(fore200e->stats->oc3.section_bip8_errors), - cpu_to_be32(fore200e->stats->oc3.path_bip8_errors), - cpu_to_be32(fore200e->stats->oc3.line_bip24_errors), - cpu_to_be32(fore200e->stats->oc3.line_febe_errors), - cpu_to_be32(fore200e->stats->oc3.path_febe_errors), - cpu_to_be32(fore200e->stats->oc3.corr_hcs_errors), - cpu_to_be32(fore200e->stats->oc3.ucorr_hcs_errors)); + be32_to_cpu(fore200e->stats->oc3.section_bip8_errors), + be32_to_cpu(fore200e->stats->oc3.path_bip8_errors), + be32_to_cpu(fore200e->stats->oc3.line_bip24_errors), + be32_to_cpu(fore200e->stats->oc3.line_febe_errors), + be32_to_cpu(fore200e->stats->oc3.path_febe_errors), + be32_to_cpu(fore200e->stats->oc3.corr_hcs_errors), + be32_to_cpu(fore200e->stats->oc3.ucorr_hcs_errors)); if (!left--) return sprintf(page,"\n" @@ -2995,12 +2995,12 @@ fore200e_proc_read(struct atm_dev *dev, loff_t* pos, char* page) " vpi no conn:\t\t%10u\n" " vci out of range:\t\t%10u\n" " vci no conn:\t\t%10u\n", - cpu_to_be32(fore200e->stats->atm.cells_transmitted), - cpu_to_be32(fore200e->stats->atm.cells_received), - cpu_to_be32(fore200e->stats->atm.vpi_bad_range), - cpu_to_be32(fore200e->stats->atm.vpi_no_conn), - cpu_to_be32(fore200e->stats->atm.vci_bad_range), - cpu_to_be32(fore200e->stats->atm.vci_no_conn)); + be32_to_cpu(fore200e->stats->atm.cells_transmitted), + be32_to_cpu(fore200e->stats->atm.cells_received), + be32_to_cpu(fore200e->stats->atm.vpi_bad_range), + be32_to_cpu(fore200e->stats->atm.vpi_no_conn), + be32_to_cpu(fore200e->stats->atm.vci_bad_range), + be32_to_cpu(fore200e->stats->atm.vci_no_conn)); if (!left--) return sprintf(page,"\n" @@ -3008,9 +3008,9 @@ fore200e_proc_read(struct atm_dev *dev, loff_t* pos, char* page) " TX:\t\t\t%10u\n" " RX:\t\t\t%10u\n" " dropped:\t\t\t%10u\n", - cpu_to_be32(fore200e->stats->aal0.cells_transmitted), - cpu_to_be32(fore200e->stats->aal0.cells_received), - cpu_to_be32(fore200e->stats->aal0.cells_dropped)); + be32_to_cpu(fore200e->stats->aal0.cells_transmitted), + be32_to_cpu(fore200e->stats->aal0.cells_received), + be32_to_cpu(fore200e->stats->aal0.cells_dropped)); if (!left--) return sprintf(page,"\n" @@ -3026,15 +3026,15 @@ fore200e_proc_read(struct atm_dev *dev, loff_t* pos, char* page) " RX:\t\t\t%10u\n" " dropped:\t\t\t%10u\n" " protocol errors:\t\t%10u\n", - cpu_to_be32(fore200e->stats->aal34.cells_transmitted), - cpu_to_be32(fore200e->stats->aal34.cells_received), - cpu_to_be32(fore200e->stats->aal34.cells_dropped), - cpu_to_be32(fore200e->stats->aal34.cells_crc_errors), - cpu_to_be32(fore200e->stats->aal34.cells_protocol_errors), - cpu_to_be32(fore200e->stats->aal34.cspdus_transmitted), - cpu_to_be32(fore200e->stats->aal34.cspdus_received), - cpu_to_be32(fore200e->stats->aal34.cspdus_dropped), - cpu_to_be32(fore200e->stats->aal34.cspdus_protocol_errors)); + be32_to_cpu(fore200e->stats->aal34.cells_transmitted), + be32_to_cpu(fore200e->stats->aal34.cells_received), + be32_to_cpu(fore200e->stats->aal34.cells_dropped), + be32_to_cpu(fore200e->stats->aal34.cells_crc_errors), + be32_to_cpu(fore200e->stats->aal34.cells_protocol_errors), + be32_to_cpu(fore200e->stats->aal34.cspdus_transmitted), + be32_to_cpu(fore200e->stats->aal34.cspdus_received), + be32_to_cpu(fore200e->stats->aal34.cspdus_dropped), + be32_to_cpu(fore200e->stats->aal34.cspdus_protocol_errors)); if (!left--) return sprintf(page,"\n" @@ -3050,15 +3050,15 @@ fore200e_proc_read(struct atm_dev *dev, loff_t* pos, char* page) " dropped:\t\t\t%10u\n" " CRC errors:\t\t%10u\n" " protocol errors:\t\t%10u\n", - cpu_to_be32(fore200e->stats->aal5.cells_transmitted), - cpu_to_be32(fore200e->stats->aal5.cells_received), - cpu_to_be32(fore200e->stats->aal5.cells_dropped), - cpu_to_be32(fore200e->stats->aal5.congestion_experienced), - cpu_to_be32(fore200e->stats->aal5.cspdus_transmitted), - cpu_to_be32(fore200e->stats->aal5.cspdus_received), - cpu_to_be32(fore200e->stats->aal5.cspdus_dropped), - cpu_to_be32(fore200e->stats->aal5.cspdus_crc_errors), - cpu_to_be32(fore200e->stats->aal5.cspdus_protocol_errors)); + be32_to_cpu(fore200e->stats->aal5.cells_transmitted), + be32_to_cpu(fore200e->stats->aal5.cells_received), + be32_to_cpu(fore200e->stats->aal5.cells_dropped), + be32_to_cpu(fore200e->stats->aal5.congestion_experienced), + be32_to_cpu(fore200e->stats->aal5.cspdus_transmitted), + be32_to_cpu(fore200e->stats->aal5.cspdus_received), + be32_to_cpu(fore200e->stats->aal5.cspdus_dropped), + be32_to_cpu(fore200e->stats->aal5.cspdus_crc_errors), + be32_to_cpu(fore200e->stats->aal5.cspdus_protocol_errors)); if (!left--) return sprintf(page,"\n" @@ -3069,11 +3069,11 @@ fore200e_proc_read(struct atm_dev *dev, loff_t* pos, char* page) " large b2:\t\t\t%10u\n" " RX PDUs:\t\t\t%10u\n" " TX PDUs:\t\t\t%10lu\n", - cpu_to_be32(fore200e->stats->aux.small_b1_failed), - cpu_to_be32(fore200e->stats->aux.large_b1_failed), - cpu_to_be32(fore200e->stats->aux.small_b2_failed), - cpu_to_be32(fore200e->stats->aux.large_b2_failed), - cpu_to_be32(fore200e->stats->aux.rpd_alloc_failed), + be32_to_cpu(fore200e->stats->aux.small_b1_failed), + be32_to_cpu(fore200e->stats->aux.large_b1_failed), + be32_to_cpu(fore200e->stats->aux.small_b2_failed), + be32_to_cpu(fore200e->stats->aux.large_b2_failed), + be32_to_cpu(fore200e->stats->aux.rpd_alloc_failed), fore200e->tx_sat); if (!left--) diff --git a/drivers/atm/fore200e.h b/drivers/atm/fore200e.h index b85a54613de..183841cc8fd 100644 --- a/drivers/atm/fore200e.h +++ b/drivers/atm/fore200e.h @@ -349,90 +349,90 @@ typedef struct oc3_block { /* physical encoding statistics */ typedef struct stats_phy { - u32 crc_header_errors; /* cells received with bad header CRC */ - u32 framing_errors; /* cells received with bad framing */ - u32 pad[ 2 ]; /* i960 padding */ + __be32 crc_header_errors; /* cells received with bad header CRC */ + __be32 framing_errors; /* cells received with bad framing */ + __be32 pad[ 2 ]; /* i960 padding */ } stats_phy_t; /* OC-3 statistics */ typedef struct stats_oc3 { - u32 section_bip8_errors; /* section 8 bit interleaved parity */ - u32 path_bip8_errors; /* path 8 bit interleaved parity */ - u32 line_bip24_errors; /* line 24 bit interleaved parity */ - u32 line_febe_errors; /* line far end block errors */ - u32 path_febe_errors; /* path far end block errors */ - u32 corr_hcs_errors; /* correctable header check sequence */ - u32 ucorr_hcs_errors; /* uncorrectable header check sequence */ - u32 pad[ 1 ]; /* i960 padding */ + __be32 section_bip8_errors; /* section 8 bit interleaved parity */ + __be32 path_bip8_errors; /* path 8 bit interleaved parity */ + __be32 line_bip24_errors; /* line 24 bit interleaved parity */ + __be32 line_febe_errors; /* line far end block errors */ + __be32 path_febe_errors; /* path far end block errors */ + __be32 corr_hcs_errors; /* correctable header check sequence */ + __be32 ucorr_hcs_errors; /* uncorrectable header check sequence */ + __be32 pad[ 1 ]; /* i960 padding */ } stats_oc3_t; /* ATM statistics */ typedef struct stats_atm { - u32 cells_transmitted; /* cells transmitted */ - u32 cells_received; /* cells received */ - u32 vpi_bad_range; /* cell drops: VPI out of range */ - u32 vpi_no_conn; /* cell drops: no connection for VPI */ - u32 vci_bad_range; /* cell drops: VCI out of range */ - u32 vci_no_conn; /* cell drops: no connection for VCI */ - u32 pad[ 2 ]; /* i960 padding */ + __be32 cells_transmitted; /* cells transmitted */ + __be32 cells_received; /* cells received */ + __be32 vpi_bad_range; /* cell drops: VPI out of range */ + __be32 vpi_no_conn; /* cell drops: no connection for VPI */ + __be32 vci_bad_range; /* cell drops: VCI out of range */ + __be32 vci_no_conn; /* cell drops: no connection for VCI */ + __be32 pad[ 2 ]; /* i960 padding */ } stats_atm_t; /* AAL0 statistics */ typedef struct stats_aal0 { - u32 cells_transmitted; /* cells transmitted */ - u32 cells_received; /* cells received */ - u32 cells_dropped; /* cells dropped */ - u32 pad[ 1 ]; /* i960 padding */ + __be32 cells_transmitted; /* cells transmitted */ + __be32 cells_received; /* cells received */ + __be32 cells_dropped; /* cells dropped */ + __be32 pad[ 1 ]; /* i960 padding */ } stats_aal0_t; /* AAL3/4 statistics */ typedef struct stats_aal34 { - u32 cells_transmitted; /* cells transmitted from segmented PDUs */ - u32 cells_received; /* cells reassembled into PDUs */ - u32 cells_crc_errors; /* payload CRC error count */ - u32 cells_protocol_errors; /* SAR or CS layer protocol errors */ - u32 cells_dropped; /* cells dropped: partial reassembly */ - u32 cspdus_transmitted; /* CS PDUs transmitted */ - u32 cspdus_received; /* CS PDUs received */ - u32 cspdus_protocol_errors; /* CS layer protocol errors */ - u32 cspdus_dropped; /* reassembled PDUs drop'd (in cells) */ - u32 pad[ 3 ]; /* i960 padding */ + __be32 cells_transmitted; /* cells transmitted from segmented PDUs */ + __be32 cells_received; /* cells reassembled into PDUs */ + __be32 cells_crc_errors; /* payload CRC error count */ + __be32 cells_protocol_errors; /* SAR or CS layer protocol errors */ + __be32 cells_dropped; /* cells dropped: partial reassembly */ + __be32 cspdus_transmitted; /* CS PDUs transmitted */ + __be32 cspdus_received; /* CS PDUs received */ + __be32 cspdus_protocol_errors; /* CS layer protocol errors */ + __be32 cspdus_dropped; /* reassembled PDUs drop'd (in cells) */ + __be32 pad[ 3 ]; /* i960 padding */ } stats_aal34_t; /* AAL5 statistics */ typedef struct stats_aal5 { - u32 cells_transmitted; /* cells transmitted from segmented SDUs */ - u32 cells_received; /* cells reassembled into SDUs */ - u32 cells_dropped; /* reassembled PDUs dropped (in cells) */ - u32 congestion_experienced; /* CRC error and length wrong */ - u32 cspdus_transmitted; /* CS PDUs transmitted */ - u32 cspdus_received; /* CS PDUs received */ - u32 cspdus_crc_errors; /* CS PDUs CRC errors */ - u32 cspdus_protocol_errors; /* CS layer protocol errors */ - u32 cspdus_dropped; /* reassembled PDUs dropped */ - u32 pad[ 3 ]; /* i960 padding */ + __be32 cells_transmitted; /* cells transmitted from segmented SDUs */ + __be32 cells_received; /* cells reassembled into SDUs */ + __be32 cells_dropped; /* reassembled PDUs dropped (in cells) */ + __be32 congestion_experienced; /* CRC error and length wrong */ + __be32 cspdus_transmitted; /* CS PDUs transmitted */ + __be32 cspdus_received; /* CS PDUs received */ + __be32 cspdus_crc_errors; /* CS PDUs CRC errors */ + __be32 cspdus_protocol_errors; /* CS layer protocol errors */ + __be32 cspdus_dropped; /* reassembled PDUs dropped */ + __be32 pad[ 3 ]; /* i960 padding */ } stats_aal5_t; /* auxiliary statistics */ typedef struct stats_aux { - u32 small_b1_failed; /* receive BD allocation failures */ - u32 large_b1_failed; /* receive BD allocation failures */ - u32 small_b2_failed; /* receive BD allocation failures */ - u32 large_b2_failed; /* receive BD allocation failures */ - u32 rpd_alloc_failed; /* receive PDU allocation failures */ - u32 receive_carrier; /* no carrier = 0, carrier = 1 */ - u32 pad[ 2 ]; /* i960 padding */ + __be32 small_b1_failed; /* receive BD allocation failures */ + __be32 large_b1_failed; /* receive BD allocation failures */ + __be32 small_b2_failed; /* receive BD allocation failures */ + __be32 large_b2_failed; /* receive BD allocation failures */ + __be32 rpd_alloc_failed; /* receive PDU allocation failures */ + __be32 receive_carrier; /* no carrier = 0, carrier = 1 */ + __be32 pad[ 2 ]; /* i960 padding */ } stats_aux_t; @@ -643,10 +643,10 @@ typedef struct host_bsq { /* header of the firmware image */ typedef struct fw_header { - u32 magic; /* magic number */ - u32 version; /* firmware version id */ - u32 load_offset; /* fw load offset in board memory */ - u32 start_offset; /* fw execution start address in board memory */ + __le32 magic; /* magic number */ + __le32 version; /* firmware version id */ + __le32 load_offset; /* fw load offset in board memory */ + __le32 start_offset; /* fw execution start address in board memory */ } fw_header_t; #define FW_HEADER_MAGIC 0x65726f66 /* 'fore' */ diff --git a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c index eee54c0cde6..b967919fb7e 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/core.c b/drivers/base/core.c index 9c0070b5bd3..24198ad0197 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -19,6 +19,7 @@ #include <linux/kdev_t.h> #include <linux/notifier.h> #include <linux/genhd.h> +#include <linux/kallsyms.h> #include <asm/semaphore.h> #include "base.h" @@ -68,6 +69,10 @@ static ssize_t dev_attr_show(struct kobject *kobj, struct attribute *attr, if (dev_attr->show) ret = dev_attr->show(dev, dev_attr, buf); + if (ret >= (ssize_t)PAGE_SIZE) { + print_symbol("dev_attr_show: %s returned bad count\n", + (unsigned long)dev_attr->show); + } return ret; } @@ -621,7 +626,8 @@ static struct kobject *get_device_parent(struct device *dev, static void cleanup_glue_dir(struct device *dev, struct kobject *glue_dir) { /* see if we live in a "glue" directory */ - if (!dev->class || glue_dir->kset != &dev->class->class_dirs) + if (!glue_dir || !dev->class || + glue_dir->kset != &dev->class->class_dirs) return; kobject_put(glue_dir); @@ -770,17 +776,10 @@ int device_add(struct device *dev) struct class_interface *class_intf; int error; - error = pm_sleep_lock(); - if (error) { - dev_warn(dev, "Suspicious %s during suspend\n", __FUNCTION__); - dump_stack(); - return error; - } - dev = get_device(dev); if (!dev || !strlen(dev->bus_id)) { error = -EINVAL; - goto Error; + goto Done; } pr_debug("device: '%s': %s\n", dev->bus_id, __FUNCTION__); @@ -843,11 +842,9 @@ int device_add(struct device *dev) } Done: put_device(dev); - pm_sleep_unlock(); return error; BusError: device_pm_remove(dev); - dpm_sysfs_remove(dev); PMError: if (dev->bus) blocking_notifier_call_chain(&dev->bus->p->bus_notifier, diff --git a/drivers/base/platform.c b/drivers/base/platform.c index efaf282c438..911ec600fe7 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/power/main.c b/drivers/base/power/main.c index ee9d1c8db0d..d887d5cb5be 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -48,7 +48,6 @@ */ LIST_HEAD(dpm_active); -static LIST_HEAD(dpm_locked); static LIST_HEAD(dpm_off); static LIST_HEAD(dpm_off_irq); static LIST_HEAD(dpm_destroy); @@ -81,28 +80,6 @@ void device_pm_add(struct device *dev) */ void device_pm_remove(struct device *dev) { - /* - * If this function is called during a suspend, it will be blocked, - * because we're holding the device's semaphore at that time, which may - * lead to a deadlock. In that case we want to print a warning. - * However, it may also be called by unregister_dropped_devices() with - * the device's semaphore released, in which case the warning should - * not be printed. - */ - if (down_trylock(&dev->sem)) { - if (down_read_trylock(&pm_sleep_rwsem)) { - /* No suspend in progress, wait on dev->sem */ - down(&dev->sem); - up_read(&pm_sleep_rwsem); - } else { - /* Suspend in progress, we may deadlock */ - dev_warn(dev, "Suspicious %s during suspend\n", - __FUNCTION__); - dump_stack(); - /* The user has been warned ... */ - down(&dev->sem); - } - } pr_debug("PM: Removing info for %s:%s\n", dev->bus ? dev->bus->name : "No Bus", kobject_name(&dev->kobj)); @@ -110,7 +87,6 @@ void device_pm_remove(struct device *dev) dpm_sysfs_remove(dev); list_del_init(&dev->power.entry); mutex_unlock(&dpm_list_mtx); - up(&dev->sem); } /** @@ -230,6 +206,8 @@ static int resume_device(struct device *dev) TRACE_DEVICE(dev); TRACE_RESUME(0); + down(&dev->sem); + if (dev->bus && dev->bus->resume) { dev_dbg(dev,"resuming\n"); error = dev->bus->resume(dev); @@ -245,6 +223,8 @@ static int resume_device(struct device *dev) error = dev->class->resume(dev); } + up(&dev->sem); + TRACE_RESUME(error); return error; } @@ -266,7 +246,7 @@ static void dpm_resume(void) struct list_head *entry = dpm_off.next; struct device *dev = to_device(entry); - list_move_tail(entry, &dpm_locked); + list_move_tail(entry, &dpm_active); mutex_unlock(&dpm_list_mtx); resume_device(dev); mutex_lock(&dpm_list_mtx); @@ -275,25 +255,6 @@ static void dpm_resume(void) } /** - * unlock_all_devices - Release each device's semaphore - * - * Go through the dpm_off list. Put each device on the dpm_active - * list and unlock it. - */ -static void unlock_all_devices(void) -{ - mutex_lock(&dpm_list_mtx); - while (!list_empty(&dpm_locked)) { - struct list_head *entry = dpm_locked.prev; - struct device *dev = to_device(entry); - - list_move(entry, &dpm_active); - up(&dev->sem); - } - mutex_unlock(&dpm_list_mtx); -} - -/** * unregister_dropped_devices - Unregister devices scheduled for removal * * Unregister all devices on the dpm_destroy list. @@ -305,7 +266,6 @@ static void unregister_dropped_devices(void) struct list_head *entry = dpm_destroy.next; struct device *dev = to_device(entry); - up(&dev->sem); mutex_unlock(&dpm_list_mtx); /* This also removes the device from the list */ device_unregister(dev); @@ -324,7 +284,6 @@ void device_resume(void) { might_sleep(); dpm_resume(); - unlock_all_devices(); unregister_dropped_devices(); up_write(&pm_sleep_rwsem); } @@ -388,18 +347,15 @@ int device_power_down(pm_message_t state) struct list_head *entry = dpm_off.prev; struct device *dev = to_device(entry); - list_del_init(&dev->power.entry); error = suspend_device_late(dev, state); if (error) { printk(KERN_ERR "Could not power down device %s: " "error %d\n", kobject_name(&dev->kobj), error); - if (list_empty(&dev->power.entry)) - list_add(&dev->power.entry, &dpm_off); break; } - if (list_empty(&dev->power.entry)) - list_add(&dev->power.entry, &dpm_off_irq); + if (!list_empty(&dev->power.entry)) + list_move(&dev->power.entry, &dpm_off_irq); } if (!error) @@ -419,6 +375,8 @@ static int suspend_device(struct device *dev, pm_message_t state) { int error = 0; + down(&dev->sem); + if (dev->power.power_state.event) { dev_dbg(dev, "PM: suspend %d-->%d\n", dev->power.power_state.event, state.event); @@ -441,6 +399,9 @@ static int suspend_device(struct device *dev, pm_message_t state) error = dev->bus->suspend(dev, state); suspend_report_result(dev->bus->suspend, error); } + + up(&dev->sem); + return error; } @@ -461,13 +422,13 @@ static int dpm_suspend(pm_message_t state) int error = 0; mutex_lock(&dpm_list_mtx); - while (!list_empty(&dpm_locked)) { - struct list_head *entry = dpm_locked.prev; + while (!list_empty(&dpm_active)) { + struct list_head *entry = dpm_active.prev; struct device *dev = to_device(entry); - list_del_init(&dev->power.entry); mutex_unlock(&dpm_list_mtx); error = suspend_device(dev, state); + mutex_lock(&dpm_list_mtx); if (error) { printk(KERN_ERR "Could not suspend device %s: " "error %d%s\n", @@ -476,14 +437,10 @@ static int dpm_suspend(pm_message_t state) (error == -EAGAIN ? " (please convert to suspend_late)" : "")); - mutex_lock(&dpm_list_mtx); - if (list_empty(&dev->power.entry)) - list_add(&dev->power.entry, &dpm_locked); break; } - mutex_lock(&dpm_list_mtx); - if (list_empty(&dev->power.entry)) - list_add(&dev->power.entry, &dpm_off); + if (!list_empty(&dev->power.entry)) + list_move(&dev->power.entry, &dpm_off); } mutex_unlock(&dpm_list_mtx); @@ -491,36 +448,6 @@ static int dpm_suspend(pm_message_t state) } /** - * lock_all_devices - Acquire every device's semaphore - * - * Go through the dpm_active list. Carefully lock each device's - * semaphore and put it in on the dpm_locked list. - */ -static void lock_all_devices(void) -{ - mutex_lock(&dpm_list_mtx); - while (!list_empty(&dpm_active)) { - struct list_head *entry = dpm_active.next; - struct device *dev = to_device(entry); - - /* Required locking order is dev->sem first, - * then dpm_list_mutex. Hence this awkward code. - */ - get_device(dev); - mutex_unlock(&dpm_list_mtx); - down(&dev->sem); - mutex_lock(&dpm_list_mtx); - - if (list_empty(entry)) - up(&dev->sem); /* Device was removed */ - else - list_move_tail(entry, &dpm_locked); - put_device(dev); - } - mutex_unlock(&dpm_list_mtx); -} - -/** * device_suspend - Save state and stop all devices in system. * @state: new power management state * @@ -533,7 +460,6 @@ int device_suspend(pm_message_t state) might_sleep(); down_write(&pm_sleep_rwsem); - lock_all_devices(); error = dpm_suspend(state); if (error) device_resume(); diff --git a/drivers/base/sys.c b/drivers/base/sys.c index 2f79c55acdc..8e13fd94216 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/base/transport_class.c b/drivers/base/transport_class.c index f25e7c6b2d2..40bca48abc1 100644 --- a/drivers/base/transport_class.c +++ b/drivers/base/transport_class.c @@ -126,9 +126,7 @@ static int transport_setup_classdev(struct attribute_container *cont, } /** - * transport_setup_device - declare a new dev for transport class association - * but don't make it visible yet. - * + * transport_setup_device - declare a new dev for transport class association but don't make it visible yet. * @dev: the generic device representing the entity being added * * Usually, dev represents some component in the HBA system (either diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index b6d230b3209..0d1d2133d9b 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 01c972415cb..5e584306be9 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/cciss.c b/drivers/block/cciss.c index 9715be3f248..55bd35c0f08 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -33,6 +33,7 @@ #include <linux/blkpg.h> #include <linux/timer.h> #include <linux/proc_fs.h> +#include <linux/seq_file.h> #include <linux/init.h> #include <linux/hdreg.h> #include <linux/spinlock.h> @@ -131,7 +132,6 @@ static struct board_type products[] = { /*define how many times we will try a command because of bus resets */ #define MAX_CMD_RETRIES 3 -#define READ_AHEAD 1024 #define MAX_CTLR 32 /* Originally cciss driver only supports 8 major numbers */ @@ -174,8 +174,6 @@ static int sendcmd_withirq(__u8 cmd, int ctlr, void *buff, size_t size, static void fail_all_cmds(unsigned long ctlr); #ifdef CONFIG_PROC_FS -static int cciss_proc_get_info(char *buffer, char **start, off_t offset, - int length, int *eof, void *data); static void cciss_procinit(int i); #else static void cciss_procinit(int i) @@ -240,24 +238,46 @@ static inline CommandList_struct *removeQ(CommandList_struct **Qptr, */ #define ENG_GIG 1000000000 #define ENG_GIG_FACTOR (ENG_GIG/512) +#define ENGAGE_SCSI "engage scsi" static const char *raid_label[] = { "0", "4", "1(1+0)", "5", "5+1", "ADG", "UNKNOWN" }; static struct proc_dir_entry *proc_cciss; -static int cciss_proc_get_info(char *buffer, char **start, off_t offset, - int length, int *eof, void *data) +static void cciss_seq_show_header(struct seq_file *seq) { - off_t pos = 0; - off_t len = 0; - int size, i, ctlr; - ctlr_info_t *h = (ctlr_info_t *) data; - drive_info_struct *drv; - unsigned long flags; - sector_t vol_sz, vol_sz_frac; + ctlr_info_t *h = seq->private; + + seq_printf(seq, "%s: HP %s Controller\n" + "Board ID: 0x%08lx\n" + "Firmware Version: %c%c%c%c\n" + "IRQ: %d\n" + "Logical drives: %d\n" + "Current Q depth: %d\n" + "Current # commands on controller: %d\n" + "Max Q depth since init: %d\n" + "Max # commands on controller since init: %d\n" + "Max SG entries since init: %d\n", + h->devname, + h->product_name, + (unsigned long)h->board_id, + h->firm_ver[0], h->firm_ver[1], h->firm_ver[2], + h->firm_ver[3], (unsigned int)h->intr[SIMPLE_MODE_INT], + h->num_luns, + h->Qdepth, h->commands_outstanding, + h->maxQsinceinit, h->max_outstanding, h->maxSG); - ctlr = h->ctlr; +#ifdef CONFIG_CISS_SCSI_TAPE + cciss_seq_tape_report(seq, h->ctlr); +#endif /* CONFIG_CISS_SCSI_TAPE */ +} + +static void *cciss_seq_start(struct seq_file *seq, loff_t *pos) +{ + ctlr_info_t *h = seq->private; + unsigned ctlr = h->ctlr; + unsigned long flags; /* prevent displaying bogus info during configuration * or deconfiguration of a logical volume @@ -265,115 +285,155 @@ static int cciss_proc_get_info(char *buffer, char **start, off_t offset, spin_lock_irqsave(CCISS_LOCK(ctlr), flags); if (h->busy_configuring) { spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags); - return -EBUSY; + return ERR_PTR(-EBUSY); } h->busy_configuring = 1; spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags); - size = sprintf(buffer, "%s: HP %s Controller\n" - "Board ID: 0x%08lx\n" - "Firmware Version: %c%c%c%c\n" - "IRQ: %d\n" - "Logical drives: %d\n" - "Max sectors: %d\n" - "Current Q depth: %d\n" - "Current # commands on controller: %d\n" - "Max Q depth since init: %d\n" - "Max # commands on controller since init: %d\n" - "Max SG entries since init: %d\n\n", - h->devname, - h->product_name, - (unsigned long)h->board_id, - h->firm_ver[0], h->firm_ver[1], h->firm_ver[2], - h->firm_ver[3], (unsigned int)h->intr[SIMPLE_MODE_INT], - h->num_luns, - h->cciss_max_sectors, - h->Qdepth, h->commands_outstanding, - h->maxQsinceinit, h->max_outstanding, h->maxSG); - - pos += size; - len += size; - cciss_proc_tape_report(ctlr, buffer, &pos, &len); - for (i = 0; i <= h->highest_lun; i++) { - - drv = &h->drv[i]; - if (drv->heads == 0) - continue; + if (*pos == 0) + cciss_seq_show_header(seq); - vol_sz = drv->nr_blocks; - vol_sz_frac = sector_div(vol_sz, ENG_GIG_FACTOR); - vol_sz_frac *= 100; - sector_div(vol_sz_frac, ENG_GIG_FACTOR); + return pos; +} + +static int cciss_seq_show(struct seq_file *seq, void *v) +{ + sector_t vol_sz, vol_sz_frac; + ctlr_info_t *h = seq->private; + unsigned ctlr = h->ctlr; + loff_t *pos = v; + drive_info_struct *drv = &h->drv[*pos]; + + if (*pos > h->highest_lun) + return 0; + + if (drv->heads == 0) + return 0; + + vol_sz = drv->nr_blocks; + vol_sz_frac = sector_div(vol_sz, ENG_GIG_FACTOR); + vol_sz_frac *= 100; + sector_div(vol_sz_frac, ENG_GIG_FACTOR); + + if (drv->raid_level > 5) + drv->raid_level = RAID_UNKNOWN; + seq_printf(seq, "cciss/c%dd%d:" + "\t%4u.%02uGB\tRAID %s\n", + ctlr, (int) *pos, (int)vol_sz, (int)vol_sz_frac, + raid_label[drv->raid_level]); + return 0; +} + +static void *cciss_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + ctlr_info_t *h = seq->private; + + if (*pos > h->highest_lun) + return NULL; + *pos += 1; + + return pos; +} + +static void cciss_seq_stop(struct seq_file *seq, void *v) +{ + ctlr_info_t *h = seq->private; + + /* Only reset h->busy_configuring if we succeeded in setting + * it during cciss_seq_start. */ + if (v == ERR_PTR(-EBUSY)) + return; - if (drv->raid_level > 5) - drv->raid_level = RAID_UNKNOWN; - size = sprintf(buffer + len, "cciss/c%dd%d:" - "\t%4u.%02uGB\tRAID %s\n", - ctlr, i, (int)vol_sz, (int)vol_sz_frac, - raid_label[drv->raid_level]); - pos += size; - len += size; - } - - *eof = 1; - *start = buffer + offset; - len -= offset; - if (len > length) - len = length; h->busy_configuring = 0; - return len; } -static int -cciss_proc_write(struct file *file, const char __user *buffer, - unsigned long count, void *data) +static struct seq_operations cciss_seq_ops = { + .start = cciss_seq_start, + .show = cciss_seq_show, + .next = cciss_seq_next, + .stop = cciss_seq_stop, +}; + +static int cciss_seq_open(struct inode *inode, struct file *file) { - unsigned char cmd[80]; - int len; -#ifdef CONFIG_CISS_SCSI_TAPE - ctlr_info_t *h = (ctlr_info_t *) data; - int rc; + int ret = seq_open(file, &cciss_seq_ops); + struct seq_file *seq = file->private_data; + + if (!ret) + seq->private = PDE(inode)->data; + + return ret; +} + +static ssize_t +cciss_proc_write(struct file *file, const char __user *buf, + size_t length, loff_t *ppos) +{ + int err; + char *buffer; + +#ifndef CONFIG_CISS_SCSI_TAPE + return -EINVAL; #endif - if (count > sizeof(cmd) - 1) + if (!buf || length > PAGE_SIZE - 1) return -EINVAL; - if (copy_from_user(cmd, buffer, count)) - return -EFAULT; - cmd[count] = '\0'; - len = strlen(cmd); // above 3 lines ensure safety - if (len && cmd[len - 1] == '\n') - cmd[--len] = '\0'; -# ifdef CONFIG_CISS_SCSI_TAPE - if (strcmp("engage scsi", cmd) == 0) { + + buffer = (char *)__get_free_page(GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + err = -EFAULT; + if (copy_from_user(buffer, buf, length)) + goto out; + buffer[length] = '\0'; + +#ifdef CONFIG_CISS_SCSI_TAPE + if (strncmp(ENGAGE_SCSI, buffer, sizeof ENGAGE_SCSI - 1) == 0) { + struct seq_file *seq = file->private_data; + ctlr_info_t *h = seq->private; + int rc; + rc = cciss_engage_scsi(h->ctlr); if (rc != 0) - return -rc; - return count; - } + err = -rc; + else + err = length; + } else +#endif /* CONFIG_CISS_SCSI_TAPE */ + err = -EINVAL; /* might be nice to have "disengage" too, but it's not safely possible. (only 1 module use count, lock issues.) */ -# endif - return -EINVAL; + +out: + free_page((unsigned long)buffer); + return err; } -/* - * Get us a file in /proc/cciss that says something about each controller. - * Create /proc/cciss if it doesn't exist yet. - */ +static struct file_operations cciss_proc_fops = { + .owner = THIS_MODULE, + .open = cciss_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, + .write = cciss_proc_write, +}; + static void __devinit cciss_procinit(int i) { struct proc_dir_entry *pde; - if (proc_cciss == NULL) { + if (proc_cciss == NULL) proc_cciss = proc_mkdir("cciss", proc_root_driver); - if (!proc_cciss) - return; - } + if (!proc_cciss) + return; + pde = proc_create(hba[i]->devname, S_IWUSR | S_IRUSR | S_IRGRP | + S_IROTH, proc_cciss, + &cciss_proc_fops); + if (!pde) + return; - pde = create_proc_read_entry(hba[i]->devname, - S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH, - proc_cciss, cciss_proc_get_info, hba[i]); - pde->write_proc = cciss_proc_write; + pde->data = hba[i]; } #endif /* CONFIG_PROC_FS */ @@ -1341,7 +1401,6 @@ geo_inq: disk->private_data = &h->drv[drv_index]; /* Set up queue information */ - disk->queue->backing_dev_info.ra_pages = READ_AHEAD; blk_queue_bounce_limit(disk->queue, hba[ctlr]->pdev->dma_mask); /* This is a hardware imposed limit. */ @@ -3434,7 +3493,6 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, } drv->queue = q; - q->backing_dev_info.ra_pages = READ_AHEAD; blk_queue_bounce_limit(q, hba[i]->pdev->dma_mask); /* This is a hardware imposed limit. */ diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c index 55178e9973a..45ac09300eb 100644 --- a/drivers/block/cciss_scsi.c +++ b/drivers/block/cciss_scsi.c @@ -1404,21 +1404,18 @@ cciss_engage_scsi(int ctlr) } static void -cciss_proc_tape_report(int ctlr, unsigned char *buffer, off_t *pos, off_t *len) +cciss_seq_tape_report(struct seq_file *seq, int ctlr) { unsigned long flags; - int size; - - *pos = *pos -1; *len = *len - 1; // cut off the last trailing newline CPQ_TAPE_LOCK(ctlr, flags); - size = sprintf(buffer + *len, + seq_printf(seq, "Sequential access devices: %d\n\n", ccissscsi[ctlr].ndevices); CPQ_TAPE_UNLOCK(ctlr, flags); - *pos += size; *len += size; } + /* Need at least one of these error handlers to keep ../scsi/hosts.c from * complaining. Doing a host- or bus-reset can't do anything good here. * Despite what it might say in scsi_error.c, there may well be commands @@ -1498,6 +1495,5 @@ static int cciss_eh_abort_handler(struct scsi_cmnd *scsicmd) #define cciss_scsi_setup(cntl_num) #define cciss_unregister_scsi(ctlr) #define cciss_register_scsi(ctlr) -#define cciss_proc_tape_report(ctlr, buffer, pos, len) #endif /* CONFIG_CISS_SCSI_TAPE */ diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 32c79a55511..7652e87d60c 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/pktcdvd.c b/drivers/block/pktcdvd.c index 674cd66dcab..18feb1c7c33 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -849,7 +849,8 @@ static int pkt_flush_cache(struct pktcdvd_device *pd) /* * speed is given as the normal factor, e.g. 4 for 4x */ -static int pkt_set_speed(struct pktcdvd_device *pd, unsigned write_speed, unsigned read_speed) +static noinline_for_stack int pkt_set_speed(struct pktcdvd_device *pd, + unsigned write_speed, unsigned read_speed) { struct packet_command cgc; struct request_sense sense; @@ -1776,7 +1777,8 @@ static int pkt_get_track_info(struct pktcdvd_device *pd, __u16 track, __u8 type, return pkt_generic_packet(pd, &cgc); } -static int pkt_get_last_written(struct pktcdvd_device *pd, long *last_written) +static noinline_for_stack int pkt_get_last_written(struct pktcdvd_device *pd, + long *last_written) { disc_information di; track_information ti; @@ -1813,7 +1815,7 @@ static int pkt_get_last_written(struct pktcdvd_device *pd, long *last_written) /* * write mode select package based on pd->settings */ -static int pkt_set_write_settings(struct pktcdvd_device *pd) +static noinline_for_stack int pkt_set_write_settings(struct pktcdvd_device *pd) { struct packet_command cgc; struct request_sense sense; @@ -1972,7 +1974,7 @@ static int pkt_writable_disc(struct pktcdvd_device *pd, disc_information *di) return 1; } -static int pkt_probe_settings(struct pktcdvd_device *pd) +static noinline_for_stack int pkt_probe_settings(struct pktcdvd_device *pd) { struct packet_command cgc; unsigned char buf[12]; @@ -2071,7 +2073,8 @@ static int pkt_probe_settings(struct pktcdvd_device *pd) /* * enable/disable write caching on drive */ -static int pkt_write_caching(struct pktcdvd_device *pd, int set) +static noinline_for_stack int pkt_write_caching(struct pktcdvd_device *pd, + int set) { struct packet_command cgc; struct request_sense sense; @@ -2116,7 +2119,8 @@ static int pkt_lock_door(struct pktcdvd_device *pd, int lockflag) /* * Returns drive maximum write speed */ -static int pkt_get_max_speed(struct pktcdvd_device *pd, unsigned *write_speed) +static noinline_for_stack int pkt_get_max_speed(struct pktcdvd_device *pd, + unsigned *write_speed) { struct packet_command cgc; struct request_sense sense; @@ -2177,7 +2181,8 @@ static char us_clv_to_speed[16] = { /* * reads the maximum media speed from ATIP */ -static int pkt_media_speed(struct pktcdvd_device *pd, unsigned *speed) +static noinline_for_stack int pkt_media_speed(struct pktcdvd_device *pd, + unsigned *speed) { struct packet_command cgc; struct request_sense sense; @@ -2249,7 +2254,7 @@ static int pkt_media_speed(struct pktcdvd_device *pd, unsigned *speed) } } -static int pkt_perform_opc(struct pktcdvd_device *pd) +static noinline_for_stack int pkt_perform_opc(struct pktcdvd_device *pd) { struct packet_command cgc; struct request_sense sense; diff --git a/drivers/block/ps2esdi.c b/drivers/block/ps2esdi.c deleted file mode 100644 index 3c796e23625..00000000000 --- 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 9e61fca4611..41ca721d252 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 3b1a68d6edd..0cfbe8c594a 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 372c7ef633d..8b884f87d8b 100644 --- a/drivers/bluetooth/hci_usb.c +++ b/drivers/bluetooth/hci_usb.c @@ -116,6 +116,7 @@ static struct usb_device_id blacklist_ids[] = { { USB_DEVICE(0x0a5c, 0x2009), .driver_info = HCI_BCM92035 }, /* Broadcom BCM2045 */ + { USB_DEVICE(0x0a5c, 0x2039), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU }, { USB_DEVICE(0x0a5c, 0x2101), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU }, /* IBM/Lenovo ThinkPad with Broadcom chip */ @@ -148,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/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index db259e60289..12f5baea439 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -1152,8 +1152,8 @@ clean_up_and_return: /* This code is similar to that in open_for_data. The routine is called whenever an audio play operation is requested. */ -int check_for_audio_disc(struct cdrom_device_info * cdi, - struct cdrom_device_ops * cdo) +static int check_for_audio_disc(struct cdrom_device_info * cdi, + struct cdrom_device_ops * cdo) { int ret; tracktype tracks; diff --git a/drivers/char/defkeymap.c_shipped b/drivers/char/defkeymap.c_shipped index 0aa419a6176..d2208dfe3f6 100644 --- a/drivers/char/defkeymap.c_shipped +++ b/drivers/char/defkeymap.c_shipped @@ -223,40 +223,40 @@ char *func_table[MAX_NR_FUNC] = { }; struct kbdiacruc accent_table[MAX_DIACR] = { - {'`', 'A', '\300'}, {'`', 'a', '\340'}, - {'\'', 'A', '\301'}, {'\'', 'a', '\341'}, - {'^', 'A', '\302'}, {'^', 'a', '\342'}, - {'~', 'A', '\303'}, {'~', 'a', '\343'}, - {'"', 'A', '\304'}, {'"', 'a', '\344'}, - {'O', 'A', '\305'}, {'o', 'a', '\345'}, - {'0', 'A', '\305'}, {'0', 'a', '\345'}, - {'A', 'A', '\305'}, {'a', 'a', '\345'}, - {'A', 'E', '\306'}, {'a', 'e', '\346'}, - {',', 'C', '\307'}, {',', 'c', '\347'}, - {'`', 'E', '\310'}, {'`', 'e', '\350'}, - {'\'', 'E', '\311'}, {'\'', 'e', '\351'}, - {'^', 'E', '\312'}, {'^', 'e', '\352'}, - {'"', 'E', '\313'}, {'"', 'e', '\353'}, - {'`', 'I', '\314'}, {'`', 'i', '\354'}, - {'\'', 'I', '\315'}, {'\'', 'i', '\355'}, - {'^', 'I', '\316'}, {'^', 'i', '\356'}, - {'"', 'I', '\317'}, {'"', 'i', '\357'}, - {'-', 'D', '\320'}, {'-', 'd', '\360'}, - {'~', 'N', '\321'}, {'~', 'n', '\361'}, - {'`', 'O', '\322'}, {'`', 'o', '\362'}, - {'\'', 'O', '\323'}, {'\'', 'o', '\363'}, - {'^', 'O', '\324'}, {'^', 'o', '\364'}, - {'~', 'O', '\325'}, {'~', 'o', '\365'}, - {'"', 'O', '\326'}, {'"', 'o', '\366'}, - {'/', 'O', '\330'}, {'/', 'o', '\370'}, - {'`', 'U', '\331'}, {'`', 'u', '\371'}, - {'\'', 'U', '\332'}, {'\'', 'u', '\372'}, - {'^', 'U', '\333'}, {'^', 'u', '\373'}, - {'"', 'U', '\334'}, {'"', 'u', '\374'}, - {'\'', 'Y', '\335'}, {'\'', 'y', '\375'}, - {'T', 'H', '\336'}, {'t', 'h', '\376'}, - {'s', 's', '\337'}, {'"', 'y', '\377'}, - {'s', 'z', '\337'}, {'i', 'j', '\377'}, + {'`', 'A', 0300}, {'`', 'a', 0340}, + {'\'', 'A', 0301}, {'\'', 'a', 0341}, + {'^', 'A', 0302}, {'^', 'a', 0342}, + {'~', 'A', 0303}, {'~', 'a', 0343}, + {'"', 'A', 0304}, {'"', 'a', 0344}, + {'O', 'A', 0305}, {'o', 'a', 0345}, + {'0', 'A', 0305}, {'0', 'a', 0345}, + {'A', 'A', 0305}, {'a', 'a', 0345}, + {'A', 'E', 0306}, {'a', 'e', 0346}, + {',', 'C', 0307}, {',', 'c', 0347}, + {'`', 'E', 0310}, {'`', 'e', 0350}, + {'\'', 'E', 0311}, {'\'', 'e', 0351}, + {'^', 'E', 0312}, {'^', 'e', 0352}, + {'"', 'E', 0313}, {'"', 'e', 0353}, + {'`', 'I', 0314}, {'`', 'i', 0354}, + {'\'', 'I', 0315}, {'\'', 'i', 0355}, + {'^', 'I', 0316}, {'^', 'i', 0356}, + {'"', 'I', 0317}, {'"', 'i', 0357}, + {'-', 'D', 0320}, {'-', 'd', 0360}, + {'~', 'N', 0321}, {'~', 'n', 0361}, + {'`', 'O', 0322}, {'`', 'o', 0362}, + {'\'', 'O', 0323}, {'\'', 'o', 0363}, + {'^', 'O', 0324}, {'^', 'o', 0364}, + {'~', 'O', 0325}, {'~', 'o', 0365}, + {'"', 'O', 0326}, {'"', 'o', 0366}, + {'/', 'O', 0330}, {'/', 'o', 0370}, + {'`', 'U', 0331}, {'`', 'u', 0371}, + {'\'', 'U', 0332}, {'\'', 'u', 0372}, + {'^', 'U', 0333}, {'^', 'u', 0373}, + {'"', 'U', 0334}, {'"', 'u', 0374}, + {'\'', 'Y', 0335}, {'\'', 'y', 0375}, + {'T', 'H', 0336}, {'t', 'h', 0376}, + {'s', 's', 0337}, {'"', 'y', 0377}, + {'s', 'z', 0337}, {'i', 'j', 0377}, }; unsigned int accent_table_size = 68; diff --git a/drivers/char/drm/ati_pcigart.c b/drivers/char/drm/ati_pcigart.c index d352dbb4ccf..e5a0e97cfdd 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 a6789f25009..8ea9dd1717a 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 3992f73299c..f09d4b5002b 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 bea2a7d5b2b..12dcdd1832f 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 715b361f0c2..a6a499f97e2 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 892e0a58984..f36adbd3aaf 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 833abc7e55f..9072e4a1894 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 94baec692b5..7a339dba6a6 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 33c5197b73c..409e00afdd0 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/esp.c b/drivers/char/esp.c index c01e26d9ee5..f3fe6206734 100644 --- a/drivers/char/esp.c +++ b/drivers/char/esp.c @@ -2484,6 +2484,7 @@ static int __init espserial_init(void) return 0; } + spin_lock_init(&info->lock); /* rx_trigger, tx_trigger are needed by autoconfig */ info->config.rx_trigger = rx_trigger; info->config.tx_trigger = tx_trigger; diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index 6bbd4fa50f3..8d6c2089d2a 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig @@ -9,7 +9,14 @@ config HW_RANDOM Hardware Random Number Generator Core infrastructure. To compile this driver as a module, choose M here: the - module will be called rng-core. + module will be called rng-core. This provides a device + that's usually called /dev/hw_random, and which exposes one + of possibly several hardware random number generators. + + These hardware random number generators do not feed directly + into the kernel's random number generator. That is usually + handled by the "rngd" daemon. Documentation/hw_random.txt + has more information. If unsure, say Y. diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c index 85d596a3c18..eba2883b630 100644 --- a/drivers/char/isicom.c +++ b/drivers/char/isicom.c @@ -1527,7 +1527,7 @@ static int __devinit reset_card(struct pci_dev *pdev, msleep(10); portcount = inw(base + 0x2); - if (!inw(base + 0xe) & 0x1 || (portcount != 0 && portcount != 4 && + if (!(inw(base + 0xe) & 0x1) || (portcount != 0 && portcount != 4 && portcount != 8 && portcount != 16)) { dev_err(&pdev->dev, "ISILoad:PCI Card%d reset failure.\n", card + 1); diff --git a/drivers/char/nozomi.c b/drivers/char/nozomi.c index dfaab2322de..6d0dc5f9b6b 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/pcmcia/ipwireless/network.c b/drivers/char/pcmcia/ipwireless/network.c index ff35230058d..d793e68b3e0 100644 --- a/drivers/char/pcmcia/ipwireless/network.c +++ b/drivers/char/pcmcia/ipwireless/network.c @@ -377,13 +377,16 @@ void ipwireless_network_packet_received(struct ipw_network *network, for (i = 0; i < MAX_ASSOCIATED_TTYS; i++) { struct ipw_tty *tty = network->associated_ttys[channel_idx][i]; + if (!tty) + continue; + /* * If it's associated with a tty (other than the RAS channel * when we're online), then send the data to that tty. The RAS * channel's data is handled above - it always goes through * ppp_generic. */ - if (tty && channel_idx == IPW_CHANNEL_RAS + if (channel_idx == IPW_CHANNEL_RAS && (network->ras_control_lines & IPW_CONTROL_LINE_DCD) != 0 && ipwireless_tty_is_modem(tty)) { diff --git a/drivers/char/riscom8.c b/drivers/char/riscom8.c index 8fc4fe4e38f..3f9d0a9ac36 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/char/rocket.c b/drivers/char/rocket.c index 72f289279d8..f585bc8579e 100644 --- a/drivers/char/rocket.c +++ b/drivers/char/rocket.c @@ -83,6 +83,7 @@ #include <linux/pci.h> #include <asm/uaccess.h> #include <asm/atomic.h> +#include <asm/unaligned.h> #include <linux/bitops.h> #include <linux/spinlock.h> #include <linux/init.h> @@ -1312,7 +1313,7 @@ static int rp_tiocmset(struct tty_struct *tty, struct file *file, if (clear & TIOCM_DTR) info->channel.TxControl[3] &= ~SET_DTR; - sOutDW(info->channel.IndexAddr, *(DWord_t *) & (info->channel.TxControl[0])); + out32(info->channel.IndexAddr, info->channel.TxControl); return 0; } @@ -1748,7 +1749,7 @@ static int rp_write(struct tty_struct *tty, /* Write remaining data into the port's xmit_buf */ while (1) { - if (info->tty == 0) /* Seemingly obligatory check... */ + if (!info->tty) /* Seemingly obligatory check... */ goto end; c = min(count, min(XMIT_BUF_SIZE - info->xmit_cnt - 1, XMIT_BUF_SIZE - info->xmit_head)); @@ -2798,7 +2799,7 @@ static int sReadAiopNumChan(WordIO_t io) static Byte_t R[4] = { 0x00, 0x00, 0x34, 0x12 }; /* write to chan 0 SRAM */ - sOutDW((DWordIO_t) io + _INDX_ADDR, *((DWord_t *) & R[0])); + out32((DWordIO_t) io + _INDX_ADDR, R); sOutW(io + _INDX_ADDR, 0); /* read from SRAM, chan 0 */ x = sInW(io + _INDX_DATA); sOutW(io + _INDX_ADDR, 0x4000); /* read from SRAM, chan 4 */ @@ -2864,7 +2865,7 @@ static int sInitChan(CONTROLLER_T * CtlP, CHANNEL_T * ChP, int AiopNum, R[1] = RData[i + 1] + 0x10 * ChanNum; R[2] = RData[i + 2]; R[3] = RData[i + 3]; - sOutDW(ChP->IndexAddr, *((DWord_t *) & R[0])); + out32(ChP->IndexAddr, R); } ChR = ChP->R; @@ -2887,43 +2888,43 @@ static int sInitChan(CONTROLLER_T * CtlP, CHANNEL_T * ChP, int AiopNum, ChP->BaudDiv[1] = (Byte_t) ((ChOff + _BAUD) >> 8); ChP->BaudDiv[2] = (Byte_t) brd9600; ChP->BaudDiv[3] = (Byte_t) (brd9600 >> 8); - sOutDW(ChP->IndexAddr, *(DWord_t *) & ChP->BaudDiv[0]); + out32(ChP->IndexAddr, ChP->BaudDiv); ChP->TxControl[0] = (Byte_t) (ChOff + _TX_CTRL); ChP->TxControl[1] = (Byte_t) ((ChOff + _TX_CTRL) >> 8); ChP->TxControl[2] = 0; ChP->TxControl[3] = 0; - sOutDW(ChP->IndexAddr, *(DWord_t *) & ChP->TxControl[0]); + out32(ChP->IndexAddr, ChP->TxControl); ChP->RxControl[0] = (Byte_t) (ChOff + _RX_CTRL); ChP->RxControl[1] = (Byte_t) ((ChOff + _RX_CTRL) >> 8); ChP->RxControl[2] = 0; ChP->RxControl[3] = 0; - sOutDW(ChP->IndexAddr, *(DWord_t *) & ChP->RxControl[0]); + out32(ChP->IndexAddr, ChP->RxControl); ChP->TxEnables[0] = (Byte_t) (ChOff + _TX_ENBLS); ChP->TxEnables[1] = (Byte_t) ((ChOff + _TX_ENBLS) >> 8); ChP->TxEnables[2] = 0; ChP->TxEnables[3] = 0; - sOutDW(ChP->IndexAddr, *(DWord_t *) & ChP->TxEnables[0]); + out32(ChP->IndexAddr, ChP->TxEnables); ChP->TxCompare[0] = (Byte_t) (ChOff + _TXCMP1); ChP->TxCompare[1] = (Byte_t) ((ChOff + _TXCMP1) >> 8); ChP->TxCompare[2] = 0; ChP->TxCompare[3] = 0; - sOutDW(ChP->IndexAddr, *(DWord_t *) & ChP->TxCompare[0]); + out32(ChP->IndexAddr, ChP->TxCompare); ChP->TxReplace1[0] = (Byte_t) (ChOff + _TXREP1B1); ChP->TxReplace1[1] = (Byte_t) ((ChOff + _TXREP1B1) >> 8); ChP->TxReplace1[2] = 0; ChP->TxReplace1[3] = 0; - sOutDW(ChP->IndexAddr, *(DWord_t *) & ChP->TxReplace1[0]); + out32(ChP->IndexAddr, ChP->TxReplace1); ChP->TxReplace2[0] = (Byte_t) (ChOff + _TXREP2); ChP->TxReplace2[1] = (Byte_t) ((ChOff + _TXREP2) >> 8); ChP->TxReplace2[2] = 0; ChP->TxReplace2[3] = 0; - sOutDW(ChP->IndexAddr, *(DWord_t *) & ChP->TxReplace2[0]); + out32(ChP->IndexAddr, ChP->TxReplace2); ChP->TxFIFOPtrs = ChOff + _TXF_OUTP; ChP->TxFIFO = ChOff + _TX_FIFO; @@ -2979,7 +2980,7 @@ static void sStopRxProcessor(CHANNEL_T * ChP) R[1] = ChP->R[1]; R[2] = 0x0a; R[3] = ChP->R[3]; - sOutDW(ChP->IndexAddr, *(DWord_t *) & R[0]); + out32(ChP->IndexAddr, R); } /*************************************************************************** @@ -3094,13 +3095,13 @@ static int sWriteTxPrioByte(CHANNEL_T * ChP, Byte_t Data) *WordPtr = ChP->TxPrioBuf; /* data byte address */ DWBuf[2] = Data; /* data byte value */ - sOutDW(IndexAddr, *((DWord_t *) (&DWBuf[0]))); /* write it out */ + out32(IndexAddr, DWBuf); /* write it out */ *WordPtr = ChP->TxPrioCnt; /* Tx priority count address */ DWBuf[2] = PRI_PEND + 1; /* indicate 1 byte pending */ DWBuf[3] = 0; /* priority buffer pointer */ - sOutDW(IndexAddr, *((DWord_t *) (&DWBuf[0]))); /* write it out */ + out32(IndexAddr, DWBuf); /* write it out */ } else { /* write it to Tx FIFO */ sWriteTxByte(sGetTxRxDataIO(ChP), Data); @@ -3147,11 +3148,11 @@ static void sEnInterrupts(CHANNEL_T * ChP, Word_t Flags) ChP->RxControl[2] |= ((Byte_t) Flags & (RXINT_EN | SRCINT_EN | MCINT_EN)); - sOutDW(ChP->IndexAddr, *(DWord_t *) & ChP->RxControl[0]); + out32(ChP->IndexAddr, ChP->RxControl); ChP->TxControl[2] |= ((Byte_t) Flags & TXINT_EN); - sOutDW(ChP->IndexAddr, *(DWord_t *) & ChP->TxControl[0]); + out32(ChP->IndexAddr, ChP->TxControl); if (Flags & CHANINT_EN) { Mask = sInB(ChP->IntMask) | sBitMapSetTbl[ChP->ChanNum]; @@ -3190,9 +3191,9 @@ static void sDisInterrupts(CHANNEL_T * ChP, Word_t Flags) ChP->RxControl[2] &= ~((Byte_t) Flags & (RXINT_EN | SRCINT_EN | MCINT_EN)); - sOutDW(ChP->IndexAddr, *(DWord_t *) & ChP->RxControl[0]); + out32(ChP->IndexAddr, ChP->RxControl); ChP->TxControl[2] &= ~((Byte_t) Flags & TXINT_EN); - sOutDW(ChP->IndexAddr, *(DWord_t *) & ChP->TxControl[0]); + out32(ChP->IndexAddr, ChP->TxControl); if (Flags & CHANINT_EN) { Mask = sInB(ChP->IntMask) & sBitMapClrTbl[ChP->ChanNum]; diff --git a/drivers/char/rocket_int.h b/drivers/char/rocket_int.h index f3a75791b81..b01d38125a8 100644 --- a/drivers/char/rocket_int.h +++ b/drivers/char/rocket_int.h @@ -26,7 +26,6 @@ typedef unsigned int ByteIO_t; typedef unsigned int Word_t; typedef unsigned int WordIO_t; -typedef unsigned long DWord_t; typedef unsigned int DWordIO_t; /* @@ -38,7 +37,6 @@ typedef unsigned int DWordIO_t; * instruction. */ -#ifdef ROCKET_DEBUG_IO static inline void sOutB(unsigned short port, unsigned char value) { #ifdef ROCKET_DEBUG_IO @@ -55,12 +53,13 @@ static inline void sOutW(unsigned short port, unsigned short value) outw_p(value, port); } -static inline void sOutDW(unsigned short port, unsigned long value) +static inline void out32(unsigned short port, Byte_t *p) { + u32 value = le32_to_cpu(get_unaligned((__le32 *)p)); #ifdef ROCKET_DEBUG_IO - printk(KERN_DEBUG "sOutDW(%x, %lx)...\n", port, value); + printk(KERN_DEBUG "out32(%x, %lx)...\n", port, value); #endif - outl_p(cpu_to_le32(value), port); + outl_p(value, port); } static inline unsigned char sInB(unsigned short port) @@ -73,14 +72,6 @@ static inline unsigned short sInW(unsigned short port) return inw_p(port); } -#else /* !ROCKET_DEBUG_IO */ -#define sOutB(a, b) outb_p(b, a) -#define sOutW(a, b) outw_p(b, a) -#define sOutDW(port, value) outl_p(cpu_to_le32(value), port) -#define sInB(a) (inb_p(a)) -#define sInW(a) (inw_p(a)) -#endif /* ROCKET_DEBUG_IO */ - /* This is used to move arrays of bytes so byte swapping isn't appropriate. */ #define sOutStrW(port, addr, count) if (count) outsw(port, addr, count) #define sInStrW(port, addr, count) if (count) insw(port, addr, count) @@ -390,7 +381,7 @@ Call: sClrBreak(ChP) #define sClrBreak(ChP) \ do { \ (ChP)->TxControl[3] &= ~SETBREAK; \ - sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->TxControl[0]); \ + out32((ChP)->IndexAddr,(ChP)->TxControl); \ } while (0) /*************************************************************************** @@ -402,7 +393,7 @@ Call: sClrDTR(ChP) #define sClrDTR(ChP) \ do { \ (ChP)->TxControl[3] &= ~SET_DTR; \ - sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->TxControl[0]); \ + out32((ChP)->IndexAddr,(ChP)->TxControl); \ } while (0) /*************************************************************************** @@ -415,7 +406,7 @@ Call: sClrRTS(ChP) do { \ if ((ChP)->rtsToggle) break; \ (ChP)->TxControl[3] &= ~SET_RTS; \ - sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->TxControl[0]); \ + out32((ChP)->IndexAddr,(ChP)->TxControl); \ } while (0) /*************************************************************************** @@ -489,7 +480,7 @@ Call: sDisCTSFlowCtl(ChP) #define sDisCTSFlowCtl(ChP) \ do { \ (ChP)->TxControl[2] &= ~CTSFC_EN; \ - sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->TxControl[0]); \ + out32((ChP)->IndexAddr,(ChP)->TxControl); \ } while (0) /*************************************************************************** @@ -501,7 +492,7 @@ Call: sDisIXANY(ChP) #define sDisIXANY(ChP) \ do { \ (ChP)->R[0x0e] = 0x86; \ - sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->R[0x0c]); \ + out32((ChP)->IndexAddr,&(ChP)->R[0x0c]); \ } while (0) /*************************************************************************** @@ -515,7 +506,7 @@ Comments: Function sSetParity() can be used in place of functions sEnParity(), #define sDisParity(ChP) \ do { \ (ChP)->TxControl[2] &= ~PARITY_EN; \ - sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->TxControl[0]); \ + out32((ChP)->IndexAddr,(ChP)->TxControl); \ } while (0) /*************************************************************************** @@ -527,7 +518,7 @@ Call: sDisRTSToggle(ChP) #define sDisRTSToggle(ChP) \ do { \ (ChP)->TxControl[2] &= ~RTSTOG_EN; \ - sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->TxControl[0]); \ + out32((ChP)->IndexAddr,(ChP)->TxControl); \ (ChP)->rtsToggle = 0; \ } while (0) @@ -540,7 +531,7 @@ Call: sDisRxFIFO(ChP) #define sDisRxFIFO(ChP) \ do { \ (ChP)->R[0x32] = 0x0a; \ - sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->R[0x30]); \ + out32((ChP)->IndexAddr,&(ChP)->R[0x30]); \ } while (0) /*************************************************************************** @@ -567,7 +558,7 @@ Call: sDisTransmit(ChP) #define sDisTransmit(ChP) \ do { \ (ChP)->TxControl[3] &= ~TX_ENABLE; \ - sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->TxControl[0]); \ + out32((ChP)->IndexAddr,(ChP)->TxControl); \ } while (0) /*************************************************************************** @@ -579,7 +570,7 @@ Call: sDisTxSoftFlowCtl(ChP) #define sDisTxSoftFlowCtl(ChP) \ do { \ (ChP)->R[0x06] = 0x8a; \ - sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->R[0x04]); \ + out32((ChP)->IndexAddr,&(ChP)->R[0x04]); \ } while (0) /*************************************************************************** @@ -604,7 +595,7 @@ Call: sEnCTSFlowCtl(ChP) #define sEnCTSFlowCtl(ChP) \ do { \ (ChP)->TxControl[2] |= CTSFC_EN; \ - sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->TxControl[0]); \ + out32((ChP)->IndexAddr,(ChP)->TxControl); \ } while (0) /*************************************************************************** @@ -616,7 +607,7 @@ Call: sEnIXANY(ChP) #define sEnIXANY(ChP) \ do { \ (ChP)->R[0x0e] = 0x21; \ - sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->R[0x0c]); \ + out32((ChP)->IndexAddr,&(ChP)->R[0x0c]); \ } while (0) /*************************************************************************** @@ -633,7 +624,7 @@ Warnings: Before enabling parity odd or even parity should be chosen using #define sEnParity(ChP) \ do { \ (ChP)->TxControl[2] |= PARITY_EN; \ - sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->TxControl[0]); \ + out32((ChP)->IndexAddr,(ChP)->TxControl); \ } while (0) /*************************************************************************** @@ -647,10 +638,10 @@ Comments: This function will disable RTS flow control and clear the RTS #define sEnRTSToggle(ChP) \ do { \ (ChP)->RxControl[2] &= ~RTSFC_EN; \ - sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->RxControl[0]); \ + out32((ChP)->IndexAddr,(ChP)->RxControl); \ (ChP)->TxControl[2] |= RTSTOG_EN; \ (ChP)->TxControl[3] &= ~SET_RTS; \ - sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->TxControl[0]); \ + out32((ChP)->IndexAddr,(ChP)->TxControl); \ (ChP)->rtsToggle = 1; \ } while (0) @@ -663,7 +654,7 @@ Call: sEnRxFIFO(ChP) #define sEnRxFIFO(ChP) \ do { \ (ChP)->R[0x32] = 0x08; \ - sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->R[0x30]); \ + out32((ChP)->IndexAddr,&(ChP)->R[0x30]); \ } while (0) /*************************************************************************** @@ -684,7 +675,7 @@ Warnings: This function must be called after valid microcode has been #define sEnRxProcessor(ChP) \ do { \ (ChP)->RxControl[2] |= RXPROC_EN; \ - sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->RxControl[0]); \ + out32((ChP)->IndexAddr,(ChP)->RxControl); \ } while (0) /*************************************************************************** @@ -708,7 +699,7 @@ Call: sEnTransmit(ChP) #define sEnTransmit(ChP) \ do { \ (ChP)->TxControl[3] |= TX_ENABLE; \ - sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->TxControl[0]); \ + out32((ChP)->IndexAddr,(ChP)->TxControl); \ } while (0) /*************************************************************************** @@ -720,7 +711,7 @@ Call: sEnTxSoftFlowCtl(ChP) #define sEnTxSoftFlowCtl(ChP) \ do { \ (ChP)->R[0x06] = 0xc5; \ - sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->R[0x04]); \ + out32((ChP)->IndexAddr,&(ChP)->R[0x04]); \ } while (0) /*************************************************************************** @@ -927,7 +918,7 @@ Call: sSendBreak(ChP) #define sSendBreak(ChP) \ do { \ (ChP)->TxControl[3] |= SETBREAK; \ - sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->TxControl[0]); \ + out32((ChP)->IndexAddr,(ChP)->TxControl); \ } while (0) /*************************************************************************** @@ -941,7 +932,7 @@ Call: sSetBaud(ChP,Divisor) do { \ (ChP)->BaudDiv[2] = (Byte_t)(DIVISOR); \ (ChP)->BaudDiv[3] = (Byte_t)((DIVISOR) >> 8); \ - sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->BaudDiv[0]); \ + out32((ChP)->IndexAddr,(ChP)->BaudDiv); \ } while (0) /*************************************************************************** @@ -953,7 +944,7 @@ Call: sSetData7(ChP) #define sSetData7(ChP) \ do { \ (ChP)->TxControl[2] &= ~DATA8BIT; \ - sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->TxControl[0]); \ + out32((ChP)->IndexAddr,(ChP)->TxControl); \ } while (0) /*************************************************************************** @@ -965,7 +956,7 @@ Call: sSetData8(ChP) #define sSetData8(ChP) \ do { \ (ChP)->TxControl[2] |= DATA8BIT; \ - sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->TxControl[0]); \ + out32((ChP)->IndexAddr,(ChP)->TxControl); \ } while (0) /*************************************************************************** @@ -977,7 +968,7 @@ Call: sSetDTR(ChP) #define sSetDTR(ChP) \ do { \ (ChP)->TxControl[3] |= SET_DTR; \ - sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->TxControl[0]); \ + out32((ChP)->IndexAddr,(ChP)->TxControl); \ } while (0) /*************************************************************************** @@ -994,7 +985,7 @@ Warnings: This function has no effect unless parity is enabled with function #define sSetEvenParity(ChP) \ do { \ (ChP)->TxControl[2] |= EVEN_PAR; \ - sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->TxControl[0]); \ + out32((ChP)->IndexAddr,(ChP)->TxControl); \ } while (0) /*************************************************************************** @@ -1011,7 +1002,7 @@ Warnings: This function has no effect unless parity is enabled with function #define sSetOddParity(ChP) \ do { \ (ChP)->TxControl[2] &= ~EVEN_PAR; \ - sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->TxControl[0]); \ + out32((ChP)->IndexAddr,(ChP)->TxControl); \ } while (0) /*************************************************************************** @@ -1024,7 +1015,7 @@ Call: sSetRTS(ChP) do { \ if ((ChP)->rtsToggle) break; \ (ChP)->TxControl[3] |= SET_RTS; \ - sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->TxControl[0]); \ + out32((ChP)->IndexAddr,(ChP)->TxControl); \ } while (0) /*************************************************************************** @@ -1050,7 +1041,7 @@ Comments: An interrupt will be generated when the trigger level is reached do { \ (ChP)->RxControl[2] &= ~TRIG_MASK; \ (ChP)->RxControl[2] |= LEVEL; \ - sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->RxControl[0]); \ + out32((ChP)->IndexAddr,(ChP)->RxControl); \ } while (0) /*************************************************************************** @@ -1062,7 +1053,7 @@ Call: sSetStop1(ChP) #define sSetStop1(ChP) \ do { \ (ChP)->TxControl[2] &= ~STOP2; \ - sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->TxControl[0]); \ + out32((ChP)->IndexAddr,(ChP)->TxControl); \ } while (0) /*************************************************************************** @@ -1074,7 +1065,7 @@ Call: sSetStop2(ChP) #define sSetStop2(ChP) \ do { \ (ChP)->TxControl[2] |= STOP2; \ - sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->TxControl[0]); \ + out32((ChP)->IndexAddr,(ChP)->TxControl); \ } while (0) /*************************************************************************** @@ -1087,7 +1078,7 @@ Call: sSetTxXOFFChar(ChP,Ch) #define sSetTxXOFFChar(ChP,CH) \ do { \ (ChP)->R[0x07] = (CH); \ - sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->R[0x04]); \ + out32((ChP)->IndexAddr,&(ChP)->R[0x04]); \ } while (0) /*************************************************************************** @@ -1100,7 +1091,7 @@ Call: sSetTxXONChar(ChP,Ch) #define sSetTxXONChar(ChP,CH) \ do { \ (ChP)->R[0x0b] = (CH); \ - sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->R[0x08]); \ + out32((ChP)->IndexAddr,&(ChP)->R[0x08]); \ } while (0) /*************************************************************************** @@ -1113,7 +1104,7 @@ Comments: This function is used to start a Rx processor after it was will restart both the Rx processor and software input flow control. */ -#define sStartRxProcessor(ChP) sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->R[0]) +#define sStartRxProcessor(ChP) out32((ChP)->IndexAddr,&(ChP)->R[0]) /*************************************************************************** Function: sWriteTxByte diff --git a/drivers/char/specialix.c b/drivers/char/specialix.c index c0e08c7bca2..5ff83df67b4 100644 --- a/drivers/char/specialix.c +++ b/drivers/char/specialix.c @@ -2109,7 +2109,6 @@ static void sx_throttle(struct tty_struct * tty) sx_out(bp, CD186x_CAR, port_No(port)); spin_unlock_irqrestore(&bp->lock, flags); if (I_IXOFF(tty)) { - spin_unlock_irqrestore(&bp->lock, flags); sx_wait_CCR(bp); spin_lock_irqsave(&bp->lock, flags); sx_out(bp, CD186x_CCR, CCR_SSCH2); diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 367be917506..9b58b894f82 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -702,6 +702,7 @@ void redraw_screen(struct vc_data *vc, int is_switch) if (is_switch) { set_leds(); compute_shiftstate(); + notify_update(vc); } } diff --git a/drivers/char/xilinx_hwicap/buffer_icap.c b/drivers/char/xilinx_hwicap/buffer_icap.c index dfea2bde162..f577daedb63 100644 --- a/drivers/char/xilinx_hwicap/buffer_icap.c +++ b/drivers/char/xilinx_hwicap/buffer_icap.c @@ -73,8 +73,8 @@ #define XHI_BUFFER_START 0 /** - * buffer_icap_get_status: Get the contents of the status register. - * @parameter base_address: is the base address of the device + * buffer_icap_get_status - Get the contents of the status register. + * @base_address: is the base address of the device * * The status register contains the ICAP status and the done bit. * @@ -94,9 +94,9 @@ static inline u32 buffer_icap_get_status(void __iomem *base_address) } /** - * buffer_icap_get_bram: Reads data from the storage buffer bram. - * @parameter base_address: contains the base address of the component. - * @parameter offset: The word offset from which the data should be read. + * buffer_icap_get_bram - Reads data from the storage buffer bram. + * @base_address: contains the base address of the component. + * @offset: The word offset from which the data should be read. * * A bram is used as a configuration memory cache. One frame of data can * be stored in this "storage buffer". @@ -108,8 +108,8 @@ static inline u32 buffer_icap_get_bram(void __iomem *base_address, } /** - * buffer_icap_busy: Return true if the icap device is busy - * @parameter base_address: is the base address of the device + * buffer_icap_busy - Return true if the icap device is busy + * @base_address: is the base address of the device * * The queries the low order bit of the status register, which * indicates whether the current configuration or readback operation @@ -121,8 +121,8 @@ static inline bool buffer_icap_busy(void __iomem *base_address) } /** - * buffer_icap_busy: Return true if the icap device is not busy - * @parameter base_address: is the base address of the device + * buffer_icap_busy - Return true if the icap device is not busy + * @base_address: is the base address of the device * * The queries the low order bit of the status register, which * indicates whether the current configuration or readback operation @@ -134,9 +134,9 @@ static inline bool buffer_icap_done(void __iomem *base_address) } /** - * buffer_icap_set_size: Set the size register. - * @parameter base_address: is the base address of the device - * @parameter data: The size in bytes. + * buffer_icap_set_size - Set the size register. + * @base_address: is the base address of the device + * @data: The size in bytes. * * The size register holds the number of 8 bit bytes to transfer between * bram and the icap (or icap to bram). @@ -148,9 +148,9 @@ static inline void buffer_icap_set_size(void __iomem *base_address, } /** - * buffer_icap_mSetoffsetReg: Set the bram offset register. - * @parameter base_address: contains the base address of the device. - * @parameter data: is the value to be written to the data register. + * buffer_icap_set_offset - Set the bram offset register. + * @base_address: contains the base address of the device. + * @data: is the value to be written to the data register. * * The bram offset register holds the starting bram address to transfer * data from during configuration or write data to during readback. @@ -162,9 +162,9 @@ static inline void buffer_icap_set_offset(void __iomem *base_address, } /** - * buffer_icap_set_rnc: Set the RNC (Readback not Configure) register. - * @parameter base_address: contains the base address of the device. - * @parameter data: is the value to be written to the data register. + * buffer_icap_set_rnc - Set the RNC (Readback not Configure) register. + * @base_address: contains the base address of the device. + * @data: is the value to be written to the data register. * * The RNC register determines the direction of the data transfer. It * controls whether a configuration or readback take place. Writing to @@ -178,10 +178,10 @@ static inline void buffer_icap_set_rnc(void __iomem *base_address, } /** - * buffer_icap_set_bram: Write data to the storage buffer bram. - * @parameter base_address: contains the base address of the component. - * @parameter offset: The word offset at which the data should be written. - * @parameter data: The value to be written to the bram offset. + * buffer_icap_set_bram - Write data to the storage buffer bram. + * @base_address: contains the base address of the component. + * @offset: The word offset at which the data should be written. + * @data: The value to be written to the bram offset. * * A bram is used as a configuration memory cache. One frame of data can * be stored in this "storage buffer". @@ -193,10 +193,10 @@ static inline void buffer_icap_set_bram(void __iomem *base_address, } /** - * buffer_icap_device_read: Transfer bytes from ICAP to the storage buffer. - * @parameter drvdata: a pointer to the drvdata. - * @parameter offset: The storage buffer start address. - * @parameter count: The number of words (32 bit) to read from the + * buffer_icap_device_read - Transfer bytes from ICAP to the storage buffer. + * @drvdata: a pointer to the drvdata. + * @offset: The storage buffer start address. + * @count: The number of words (32 bit) to read from the * device (ICAP). **/ static int buffer_icap_device_read(struct hwicap_drvdata *drvdata, @@ -227,10 +227,10 @@ static int buffer_icap_device_read(struct hwicap_drvdata *drvdata, }; /** - * buffer_icap_device_write: Transfer bytes from ICAP to the storage buffer. - * @parameter drvdata: a pointer to the drvdata. - * @parameter offset: The storage buffer start address. - * @parameter count: The number of words (32 bit) to read from the + * buffer_icap_device_write - Transfer bytes from ICAP to the storage buffer. + * @drvdata: a pointer to the drvdata. + * @offset: The storage buffer start address. + * @count: The number of words (32 bit) to read from the * device (ICAP). **/ static int buffer_icap_device_write(struct hwicap_drvdata *drvdata, @@ -261,8 +261,8 @@ static int buffer_icap_device_write(struct hwicap_drvdata *drvdata, }; /** - * buffer_icap_reset: Reset the logic of the icap device. - * @parameter drvdata: a pointer to the drvdata. + * buffer_icap_reset - Reset the logic of the icap device. + * @drvdata: a pointer to the drvdata. * * Writing to the status register resets the ICAP logic in an internal * version of the core. For the version of the core published in EDK, @@ -274,10 +274,10 @@ void buffer_icap_reset(struct hwicap_drvdata *drvdata) } /** - * buffer_icap_set_configuration: Load a partial bitstream from system memory. - * @parameter drvdata: a pointer to the drvdata. - * @parameter data: Kernel address of the partial bitstream. - * @parameter size: the size of the partial bitstream in 32 bit words. + * buffer_icap_set_configuration - Load a partial bitstream from system memory. + * @drvdata: a pointer to the drvdata. + * @data: Kernel address of the partial bitstream. + * @size: the size of the partial bitstream in 32 bit words. **/ int buffer_icap_set_configuration(struct hwicap_drvdata *drvdata, u32 *data, u32 size) @@ -333,10 +333,10 @@ int buffer_icap_set_configuration(struct hwicap_drvdata *drvdata, u32 *data, }; /** - * buffer_icap_get_configuration: Read configuration data from the device. - * @parameter drvdata: a pointer to the drvdata. - * @parameter data: Address of the data representing the partial bitstream - * @parameter size: the size of the partial bitstream in 32 bit words. + * buffer_icap_get_configuration - Read configuration data from the device. + * @drvdata: a pointer to the drvdata. + * @data: Address of the data representing the partial bitstream + * @size: the size of the partial bitstream in 32 bit words. **/ int buffer_icap_get_configuration(struct hwicap_drvdata *drvdata, u32 *data, u32 size) diff --git a/drivers/char/xilinx_hwicap/fifo_icap.c b/drivers/char/xilinx_hwicap/fifo_icap.c index 0988314694a..6f45dbd4712 100644 --- a/drivers/char/xilinx_hwicap/fifo_icap.c +++ b/drivers/char/xilinx_hwicap/fifo_icap.c @@ -94,9 +94,9 @@ /** - * fifo_icap_fifo_write: Write data to the write FIFO. - * @parameter drvdata: a pointer to the drvdata. - * @parameter data: the 32-bit value to be written to the FIFO. + * fifo_icap_fifo_write - Write data to the write FIFO. + * @drvdata: a pointer to the drvdata. + * @data: the 32-bit value to be written to the FIFO. * * This function will silently fail if the fifo is full. **/ @@ -108,8 +108,8 @@ static inline void fifo_icap_fifo_write(struct hwicap_drvdata *drvdata, } /** - * fifo_icap_fifo_read: Read data from the Read FIFO. - * @parameter drvdata: a pointer to the drvdata. + * fifo_icap_fifo_read - Read data from the Read FIFO. + * @drvdata: a pointer to the drvdata. * * This function will silently fail if the fifo is empty. **/ @@ -121,9 +121,9 @@ static inline u32 fifo_icap_fifo_read(struct hwicap_drvdata *drvdata) } /** - * fifo_icap_set_read_size: Set the the size register. - * @parameter drvdata: a pointer to the drvdata. - * @parameter data: the size of the following read transaction, in words. + * fifo_icap_set_read_size - Set the the size register. + * @drvdata: a pointer to the drvdata. + * @data: the size of the following read transaction, in words. **/ static inline void fifo_icap_set_read_size(struct hwicap_drvdata *drvdata, u32 data) @@ -132,8 +132,8 @@ static inline void fifo_icap_set_read_size(struct hwicap_drvdata *drvdata, } /** - * fifo_icap_start_config: Initiate a configuration (write) to the device. - * @parameter drvdata: a pointer to the drvdata. + * fifo_icap_start_config - Initiate a configuration (write) to the device. + * @drvdata: a pointer to the drvdata. **/ static inline void fifo_icap_start_config(struct hwicap_drvdata *drvdata) { @@ -142,8 +142,8 @@ static inline void fifo_icap_start_config(struct hwicap_drvdata *drvdata) } /** - * fifo_icap_start_readback: Initiate a readback from the device. - * @parameter drvdata: a pointer to the drvdata. + * fifo_icap_start_readback - Initiate a readback from the device. + * @drvdata: a pointer to the drvdata. **/ static inline void fifo_icap_start_readback(struct hwicap_drvdata *drvdata) { @@ -152,8 +152,8 @@ static inline void fifo_icap_start_readback(struct hwicap_drvdata *drvdata) } /** - * fifo_icap_busy: Return true if the ICAP is still processing a transaction. - * @parameter drvdata: a pointer to the drvdata. + * fifo_icap_busy - Return true if the ICAP is still processing a transaction. + * @drvdata: a pointer to the drvdata. **/ static inline u32 fifo_icap_busy(struct hwicap_drvdata *drvdata) { @@ -163,8 +163,8 @@ static inline u32 fifo_icap_busy(struct hwicap_drvdata *drvdata) } /** - * fifo_icap_write_fifo_vacancy: Query the write fifo available space. - * @parameter drvdata: a pointer to the drvdata. + * fifo_icap_write_fifo_vacancy - Query the write fifo available space. + * @drvdata: a pointer to the drvdata. * * Return the number of words that can be safely pushed into the write fifo. **/ @@ -175,8 +175,8 @@ static inline u32 fifo_icap_write_fifo_vacancy( } /** - * fifo_icap_read_fifo_occupancy: Query the read fifo available data. - * @parameter drvdata: a pointer to the drvdata. + * fifo_icap_read_fifo_occupancy - Query the read fifo available data. + * @drvdata: a pointer to the drvdata. * * Return the number of words that can be safely read from the read fifo. **/ @@ -187,11 +187,11 @@ static inline u32 fifo_icap_read_fifo_occupancy( } /** - * fifo_icap_set_configuration: Send configuration data to the ICAP. - * @parameter drvdata: a pointer to the drvdata. - * @parameter frame_buffer: a pointer to the data to be written to the + * fifo_icap_set_configuration - Send configuration data to the ICAP. + * @drvdata: a pointer to the drvdata. + * @frame_buffer: a pointer to the data to be written to the * ICAP device. - * @parameter num_words: the number of words (32 bit) to write to the ICAP + * @num_words: the number of words (32 bit) to write to the ICAP * device. * This function writes the given user data to the Write FIFO in @@ -266,10 +266,10 @@ int fifo_icap_set_configuration(struct hwicap_drvdata *drvdata, } /** - * fifo_icap_get_configuration: Read configuration data from the device. - * @parameter drvdata: a pointer to the drvdata. - * @parameter data: Address of the data representing the partial bitstream - * @parameter size: the size of the partial bitstream in 32 bit words. + * fifo_icap_get_configuration - Read configuration data from the device. + * @drvdata: a pointer to the drvdata. + * @data: Address of the data representing the partial bitstream + * @size: the size of the partial bitstream in 32 bit words. * * This function reads the specified number of words from the ICAP device in * the polled mode. @@ -335,8 +335,8 @@ int fifo_icap_get_configuration(struct hwicap_drvdata *drvdata, } /** - * buffer_icap_reset: Reset the logic of the icap device. - * @parameter drvdata: a pointer to the drvdata. + * buffer_icap_reset - Reset the logic of the icap device. + * @drvdata: a pointer to the drvdata. * * This function forces the software reset of the complete HWICAP device. * All the registers will return to the default value and the FIFO is also @@ -360,8 +360,8 @@ void fifo_icap_reset(struct hwicap_drvdata *drvdata) } /** - * fifo_icap_flush_fifo: This function flushes the FIFOs in the device. - * @parameter drvdata: a pointer to the drvdata. + * fifo_icap_flush_fifo - This function flushes the FIFOs in the device. + * @drvdata: a pointer to the drvdata. */ void fifo_icap_flush_fifo(struct hwicap_drvdata *drvdata) { diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.c b/drivers/char/xilinx_hwicap/xilinx_hwicap.c index 24f6aef0fd3..2284fa2a5a5 100644 --- a/drivers/char/xilinx_hwicap/xilinx_hwicap.c +++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.c @@ -84,7 +84,7 @@ #include <linux/init.h> #include <linux/poll.h> #include <linux/proc_fs.h> -#include <asm/semaphore.h> +#include <linux/mutex.h> #include <linux/sysctl.h> #include <linux/version.h> #include <linux/fs.h> @@ -119,6 +119,7 @@ module_param(xhwicap_minor, int, S_IRUGO); /* An array, which is set to true when the device is registered. */ static bool probed_devices[HWICAP_DEVICES]; +static struct mutex icap_sem; static struct class *icap_class; @@ -199,14 +200,14 @@ static const struct config_registers v5_config_registers = { }; /** - * hwicap_command_desync: Send a DESYNC command to the ICAP port. - * @parameter drvdata: a pointer to the drvdata. + * hwicap_command_desync - Send a DESYNC command to the ICAP port. + * @drvdata: a pointer to the drvdata. * * This command desynchronizes the ICAP After this command, a * bitstream containing a NULL packet, followed by a SYNCH packet is * required before the ICAP will recognize commands. */ -int hwicap_command_desync(struct hwicap_drvdata *drvdata) +static int hwicap_command_desync(struct hwicap_drvdata *drvdata) { u32 buffer[4]; u32 index = 0; @@ -228,51 +229,18 @@ int hwicap_command_desync(struct hwicap_drvdata *drvdata) } /** - * hwicap_command_capture: Send a CAPTURE command to the ICAP port. - * @parameter drvdata: a pointer to the drvdata. - * - * This command captures all of the flip flop states so they will be - * available during readback. One can use this command instead of - * enabling the CAPTURE block in the design. - */ -int hwicap_command_capture(struct hwicap_drvdata *drvdata) -{ - u32 buffer[7]; - u32 index = 0; - - /* - * Create the data to be written to the ICAP. - */ - buffer[index++] = XHI_DUMMY_PACKET; - buffer[index++] = XHI_SYNC_PACKET; - buffer[index++] = XHI_NOOP_PACKET; - buffer[index++] = hwicap_type_1_write(drvdata->config_regs->CMD) | 1; - buffer[index++] = XHI_CMD_GCAPTURE; - buffer[index++] = XHI_DUMMY_PACKET; - buffer[index++] = XHI_DUMMY_PACKET; - - /* - * Write the data to the FIFO and intiate the transfer of data - * present in the FIFO to the ICAP device. - */ - return drvdata->config->set_configuration(drvdata, - &buffer[0], index); - -} - -/** - * hwicap_get_configuration_register: Query a configuration register. - * @parameter drvdata: a pointer to the drvdata. - * @parameter reg: a constant which represents the configuration + * hwicap_get_configuration_register - Query a configuration register. + * @drvdata: a pointer to the drvdata. + * @reg: a constant which represents the configuration * register value to be returned. * Examples: XHI_IDCODE, XHI_FLR. - * @parameter RegData: returns the value of the register. + * @reg_data: returns the value of the register. * * Sends a query packet to the ICAP and then receives the response. * The icap is left in Synched state. */ -int hwicap_get_configuration_register(struct hwicap_drvdata *drvdata, - u32 reg, u32 *RegData) +static int hwicap_get_configuration_register(struct hwicap_drvdata *drvdata, + u32 reg, u32 *reg_data) { int status; u32 buffer[6]; @@ -300,14 +268,14 @@ int hwicap_get_configuration_register(struct hwicap_drvdata *drvdata, /* * Read the configuration register */ - status = drvdata->config->get_configuration(drvdata, RegData, 1); + status = drvdata->config->get_configuration(drvdata, reg_data, 1); if (status) return status; return 0; } -int hwicap_initialize_hwicap(struct hwicap_drvdata *drvdata) +static int hwicap_initialize_hwicap(struct hwicap_drvdata *drvdata) { int status; u32 idcode; @@ -344,7 +312,7 @@ int hwicap_initialize_hwicap(struct hwicap_drvdata *drvdata) } static ssize_t -hwicap_read(struct file *file, char *buf, size_t count, loff_t *ppos) +hwicap_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { struct hwicap_drvdata *drvdata = file->private_data; ssize_t bytes_to_read = 0; @@ -353,8 +321,9 @@ hwicap_read(struct file *file, char *buf, size_t count, loff_t *ppos) u32 bytes_remaining; int status; - if (down_interruptible(&drvdata->sem)) - return -ERESTARTSYS; + status = mutex_lock_interruptible(&drvdata->sem); + if (status) + return status; if (drvdata->read_buffer_in_use) { /* If there are leftover bytes in the buffer, just */ @@ -370,8 +339,9 @@ hwicap_read(struct file *file, char *buf, size_t count, loff_t *ppos) goto error; } drvdata->read_buffer_in_use -= bytes_to_read; - memcpy(drvdata->read_buffer + bytes_to_read, - drvdata->read_buffer, 4 - bytes_to_read); + memmove(drvdata->read_buffer, + drvdata->read_buffer + bytes_to_read, + 4 - bytes_to_read); } else { /* Get new data from the ICAP, and return was was requested. */ kbuf = (u32 *) get_zeroed_page(GFP_KERNEL); @@ -414,18 +384,20 @@ hwicap_read(struct file *file, char *buf, size_t count, loff_t *ppos) status = -EFAULT; goto error; } - memcpy(kbuf, drvdata->read_buffer, bytes_remaining); + memcpy(drvdata->read_buffer, + kbuf, + bytes_remaining); drvdata->read_buffer_in_use = bytes_remaining; free_page((unsigned long)kbuf); } status = bytes_to_read; error: - up(&drvdata->sem); + mutex_unlock(&drvdata->sem); return status; } static ssize_t -hwicap_write(struct file *file, const char *buf, +hwicap_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { struct hwicap_drvdata *drvdata = file->private_data; @@ -435,8 +407,9 @@ hwicap_write(struct file *file, const char *buf, ssize_t len; ssize_t status; - if (down_interruptible(&drvdata->sem)) - return -ERESTARTSYS; + status = mutex_lock_interruptible(&drvdata->sem); + if (status) + return status; left += drvdata->write_buffer_in_use; @@ -465,7 +438,7 @@ hwicap_write(struct file *file, const char *buf, memcpy(kbuf, drvdata->write_buffer, drvdata->write_buffer_in_use); if (copy_from_user( - (((char *)kbuf) + (drvdata->write_buffer_in_use)), + (((char *)kbuf) + drvdata->write_buffer_in_use), buf + written, len - (drvdata->write_buffer_in_use))) { free_page((unsigned long)kbuf); @@ -508,7 +481,7 @@ hwicap_write(struct file *file, const char *buf, free_page((unsigned long)kbuf); status = written; error: - up(&drvdata->sem); + mutex_unlock(&drvdata->sem); return status; } @@ -519,8 +492,9 @@ static int hwicap_open(struct inode *inode, struct file *file) drvdata = container_of(inode->i_cdev, struct hwicap_drvdata, cdev); - if (down_interruptible(&drvdata->sem)) - return -ERESTARTSYS; + status = mutex_lock_interruptible(&drvdata->sem); + if (status) + return status; if (drvdata->is_open) { status = -EBUSY; @@ -539,7 +513,7 @@ static int hwicap_open(struct inode *inode, struct file *file) drvdata->is_open = 1; error: - up(&drvdata->sem); + mutex_unlock(&drvdata->sem); return status; } @@ -549,8 +523,7 @@ static int hwicap_release(struct inode *inode, struct file *file) int i; int status = 0; - if (down_interruptible(&drvdata->sem)) - return -ERESTARTSYS; + mutex_lock(&drvdata->sem); if (drvdata->write_buffer_in_use) { /* Flush write buffer. */ @@ -569,7 +542,7 @@ static int hwicap_release(struct inode *inode, struct file *file) error: drvdata->is_open = 0; - up(&drvdata->sem); + mutex_unlock(&drvdata->sem); return status; } @@ -592,31 +565,36 @@ static int __devinit hwicap_setup(struct device *dev, int id, dev_info(dev, "Xilinx icap port driver\n"); + mutex_lock(&icap_sem); + if (id < 0) { for (id = 0; id < HWICAP_DEVICES; id++) if (!probed_devices[id]) break; } if (id < 0 || id >= HWICAP_DEVICES) { + mutex_unlock(&icap_sem); dev_err(dev, "%s%i too large\n", DRIVER_NAME, id); return -EINVAL; } if (probed_devices[id]) { + mutex_unlock(&icap_sem); dev_err(dev, "cannot assign to %s%i; it is already in use\n", DRIVER_NAME, id); return -EBUSY; } probed_devices[id] = 1; + mutex_unlock(&icap_sem); devt = MKDEV(xhwicap_major, xhwicap_minor + id); - drvdata = kmalloc(sizeof(struct hwicap_drvdata), GFP_KERNEL); + drvdata = kzalloc(sizeof(struct hwicap_drvdata), GFP_KERNEL); if (!drvdata) { dev_err(dev, "Couldn't allocate device private record\n"); - return -ENOMEM; + retval = -ENOMEM; + goto failed0; } - memset((void *)drvdata, 0, sizeof(struct hwicap_drvdata)); dev_set_drvdata(dev, (void *)drvdata); if (!regs_res) { @@ -648,7 +626,7 @@ static int __devinit hwicap_setup(struct device *dev, int id, drvdata->config = config; drvdata->config_regs = config_regs; - init_MUTEX(&drvdata->sem); + mutex_init(&drvdata->sem); drvdata->is_open = 0; dev_info(dev, "ioremap %lx to %p with size %x\n", @@ -663,7 +641,7 @@ static int __devinit hwicap_setup(struct device *dev, int id, goto failed3; } /* devfs_mk_cdev(devt, S_IFCHR|S_IRUGO|S_IWUGO, DRIVER_NAME); */ - class_device_create(icap_class, NULL, devt, NULL, DRIVER_NAME); + device_create(icap_class, dev, devt, "%s%d", DRIVER_NAME, id); return 0; /* success */ failed3: @@ -675,6 +653,11 @@ static int __devinit hwicap_setup(struct device *dev, int id, failed1: kfree(drvdata); + failed0: + mutex_lock(&icap_sem); + probed_devices[id] = 0; + mutex_unlock(&icap_sem); + return retval; } @@ -699,14 +682,16 @@ static int __devexit hwicap_remove(struct device *dev) if (!drvdata) return 0; - class_device_destroy(icap_class, drvdata->devt); + device_destroy(icap_class, drvdata->devt); cdev_del(&drvdata->cdev); iounmap(drvdata->base_address); release_mem_region(drvdata->mem_start, drvdata->mem_size); kfree(drvdata); dev_set_drvdata(dev, NULL); - probed_devices[MINOR(dev->devt)-xhwicap_minor] = 0; + mutex_lock(&icap_sem); + probed_devices[MINOR(dev->devt)-xhwicap_minor] = 0; + mutex_unlock(&icap_sem); return 0; /* success */ } @@ -821,28 +806,29 @@ static struct of_platform_driver hwicap_of_driver = { }; /* Registration helpers to keep the number of #ifdefs to a minimum */ -static inline int __devinit hwicap_of_register(void) +static inline int __init hwicap_of_register(void) { pr_debug("hwicap: calling of_register_platform_driver()\n"); return of_register_platform_driver(&hwicap_of_driver); } -static inline void __devexit hwicap_of_unregister(void) +static inline void __exit hwicap_of_unregister(void) { of_unregister_platform_driver(&hwicap_of_driver); } #else /* CONFIG_OF */ /* CONFIG_OF not enabled; do nothing helpers */ -static inline int __devinit hwicap_of_register(void) { return 0; } -static inline void __devexit hwicap_of_unregister(void) { } +static inline int __init hwicap_of_register(void) { return 0; } +static inline void __exit hwicap_of_unregister(void) { } #endif /* CONFIG_OF */ -static int __devinit hwicap_module_init(void) +static int __init hwicap_module_init(void) { dev_t devt; int retval; icap_class = class_create(THIS_MODULE, "xilinx_config"); + mutex_init(&icap_sem); if (xhwicap_major) { devt = MKDEV(xhwicap_major, xhwicap_minor); @@ -883,7 +869,7 @@ static int __devinit hwicap_module_init(void) return retval; } -static void __devexit hwicap_module_cleanup(void) +static void __exit hwicap_module_cleanup(void) { dev_t devt = MKDEV(xhwicap_major, xhwicap_minor); diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.h b/drivers/char/xilinx_hwicap/xilinx_hwicap.h index ae771cac162..405fee7e189 100644 --- a/drivers/char/xilinx_hwicap/xilinx_hwicap.h +++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.h @@ -48,9 +48,9 @@ struct hwicap_drvdata { u8 write_buffer[4]; u32 read_buffer_in_use; /* Always in [0,3] */ u8 read_buffer[4]; - u32 mem_start; /* phys. address of the control registers */ - u32 mem_end; /* phys. address of the control registers */ - u32 mem_size; + resource_size_t mem_start;/* phys. address of the control registers */ + resource_size_t mem_end; /* phys. address of the control registers */ + resource_size_t mem_size; void __iomem *base_address;/* virt. address of the control registers */ struct device *dev; @@ -61,7 +61,7 @@ struct hwicap_drvdata { const struct config_registers *config_regs; void *private_data; bool is_open; - struct semaphore sem; + struct mutex sem; }; struct hwicap_driver_config { @@ -164,29 +164,29 @@ struct config_registers { #define XHI_DISABLED_AUTO_CRC 0x0000DEFCUL /** - * hwicap_type_1_read: Generates a Type 1 read packet header. - * @parameter: Register is the address of the register to be read back. + * hwicap_type_1_read - Generates a Type 1 read packet header. + * @reg: is the address of the register to be read back. * * Generates a Type 1 read packet header, which is used to indirectly * read registers in the configuration logic. This packet must then * be sent through the icap device, and a return packet received with * the information. **/ -static inline u32 hwicap_type_1_read(u32 Register) +static inline u32 hwicap_type_1_read(u32 reg) { return (XHI_TYPE_1 << XHI_TYPE_SHIFT) | - (Register << XHI_REGISTER_SHIFT) | + (reg << XHI_REGISTER_SHIFT) | (XHI_OP_READ << XHI_OP_SHIFT); } /** - * hwicap_type_1_write: Generates a Type 1 write packet header - * @parameter: Register is the address of the register to be read back. + * hwicap_type_1_write - Generates a Type 1 write packet header + * @reg: is the address of the register to be read back. **/ -static inline u32 hwicap_type_1_write(u32 Register) +static inline u32 hwicap_type_1_write(u32 reg) { return (XHI_TYPE_1 << XHI_TYPE_SHIFT) | - (Register << XHI_REGISTER_SHIFT) | + (reg << XHI_REGISTER_SHIFT) | (XHI_OP_WRITE << XHI_OP_SHIFT); } diff --git a/drivers/connector/cn_queue.c b/drivers/connector/cn_queue.c index 5732ca3259f..b6fe7e7a2c2 100644 --- a/drivers/connector/cn_queue.c +++ b/drivers/connector/cn_queue.c @@ -146,7 +146,7 @@ struct cn_queue_dev *cn_queue_alloc_dev(char *name, struct sock *nls) dev->nls = nls; - dev->cn_queue = create_workqueue(dev->name); + dev->cn_queue = create_singlethread_workqueue(dev->name); if (!dev->cn_queue) { kfree(dev); return NULL; diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 89a29cd9378..35a26a3e5f6 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -671,13 +671,13 @@ static ssize_t show(struct kobject * kobj, struct attribute * attr ,char * buf) { struct cpufreq_policy * policy = to_policy(kobj); struct freq_attr * fattr = to_attr(attr); - ssize_t ret; + ssize_t ret = -EINVAL; policy = cpufreq_cpu_get(policy->cpu); if (!policy) - return -EINVAL; + goto no_policy; if (lock_policy_rwsem_read(policy->cpu) < 0) - return -EINVAL; + goto fail; if (fattr->show) ret = fattr->show(policy, buf); @@ -685,8 +685,9 @@ static ssize_t show(struct kobject * kobj, struct attribute * attr ,char * buf) ret = -EIO; unlock_policy_rwsem_read(policy->cpu); - +fail: cpufreq_cpu_put(policy); +no_policy: return ret; } @@ -695,13 +696,13 @@ static ssize_t store(struct kobject * kobj, struct attribute * attr, { struct cpufreq_policy * policy = to_policy(kobj); struct freq_attr * fattr = to_attr(attr); - ssize_t ret; + ssize_t ret = -EINVAL; policy = cpufreq_cpu_get(policy->cpu); if (!policy) - return -EINVAL; + goto no_policy; if (lock_policy_rwsem_write(policy->cpu) < 0) - return -EINVAL; + goto fail; if (fattr->store) ret = fattr->store(policy, buf, count); @@ -709,8 +710,9 @@ static ssize_t store(struct kobject * kobj, struct attribute * attr, ret = -EIO; unlock_policy_rwsem_write(policy->cpu); - +fail: cpufreq_cpu_put(policy); +no_policy: return ret; } @@ -1775,7 +1777,7 @@ static int __cpuinit cpufreq_cpu_callback(struct notifier_block *nfb, return NOTIFY_OK; } -static struct notifier_block __cpuinitdata cpufreq_cpu_notifier = +static struct notifier_block __refdata cpufreq_cpu_notifier = { .notifier_call = cpufreq_cpu_callback, }; diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index 1b8312b0200..070421a5480 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -323,7 +323,7 @@ static int __cpuinit cpufreq_stat_cpu_callback(struct notifier_block *nfb, return NOTIFY_OK; } -static struct notifier_block cpufreq_stat_cpu_notifier __cpuinitdata = +static struct notifier_block cpufreq_stat_cpu_notifier __refdata = { .notifier_call = cpufreq_stat_cpu_callback, }; diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index d73663a5232..fc555a90bb2 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -67,7 +67,7 @@ static void cpuidle_idle_call(void) /* enter the state and update stats */ dev->last_residency = target_state->enter(dev, target_state); dev->last_state = target_state; - target_state->time += dev->last_residency; + target_state->time += (unsigned long long)dev->last_residency; target_state->usage++; /* give the governor an opportunity to reflect on the outcome */ @@ -224,7 +224,7 @@ static void poll_idle_init(struct cpuidle_device *dev) state->exit_latency = 0; state->target_residency = 0; state->power_usage = -1; - state->flags = CPUIDLE_FLAG_POLL | CPUIDLE_FLAG_TIME_VALID; + state->flags = CPUIDLE_FLAG_POLL; state->enter = poll_idle; } #else diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c index 69102ca0568..e949618b9be 100644 --- a/drivers/cpuidle/sysfs.c +++ b/drivers/cpuidle/sysfs.c @@ -218,6 +218,12 @@ static ssize_t show_state_##_name(struct cpuidle_state *state, char *buf) \ return sprintf(buf, "%u\n", state->_name);\ } +#define define_show_state_ull_function(_name) \ +static ssize_t show_state_##_name(struct cpuidle_state *state, char *buf) \ +{ \ + return sprintf(buf, "%llu\n", state->_name);\ +} + #define define_show_state_str_function(_name) \ static ssize_t show_state_##_name(struct cpuidle_state *state, char *buf) \ { \ @@ -228,8 +234,8 @@ static ssize_t show_state_##_name(struct cpuidle_state *state, char *buf) \ define_show_state_function(exit_latency) define_show_state_function(power_usage) -define_show_state_function(usage) -define_show_state_function(time) +define_show_state_ull_function(usage) +define_show_state_ull_function(time) define_show_state_str_function(name) define_show_state_str_function(desc) diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index a703deffb79..27340a7b19d 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -4,7 +4,7 @@ menuconfig DMADEVICES bool "DMA Engine support" - depends on (PCI && X86) || ARCH_IOP32X || ARCH_IOP33X || ARCH_IOP13XX + depends on (PCI && X86) || ARCH_IOP32X || ARCH_IOP33X || ARCH_IOP13XX || PPC depends on !HIGHMEM64G help DMA engines can do asynchronous data transfers without @@ -37,6 +37,23 @@ config INTEL_IOP_ADMA help Enable support for the Intel(R) IOP Series RAID engines. +config FSL_DMA + bool "Freescale MPC85xx/MPC83xx DMA support" + depends on PPC + select DMA_ENGINE + ---help--- + Enable support for the Freescale DMA engine. Now, it support + MPC8560/40, MPC8555, MPC8548 and MPC8641 processors. + The MPC8349, MPC8360 is also supported. + +config FSL_DMA_SELFTEST + bool "Enable the self test for each DMA channel" + depends on FSL_DMA + default y + ---help--- + Enable the self test for each DMA channel. A self test will be + performed after the channel probed to ensure the DMA works well. + config DMA_ENGINE bool diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index b152cd84e12..c8036d94590 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -3,3 +3,4 @@ obj-$(CONFIG_NET_DMA) += iovlock.o obj-$(CONFIG_INTEL_IOATDMA) += ioatdma.o ioatdma-objs := ioat.o ioat_dma.o ioat_dca.o obj-$(CONFIG_INTEL_IOP_ADMA) += iop-adma.o +obj-$(CONFIG_FSL_DMA) += fsldma.o diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c index 29965231b91..8db0e7f9d3f 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 new file mode 100644 index 00000000000..72692309398 --- /dev/null +++ b/drivers/dma/fsldma.c @@ -0,0 +1,1127 @@ +/* + * Freescale MPC85xx, MPC83xx DMA Engine support + * + * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved. + * + * Author: + * Zhang Wei <wei.zhang@freescale.com>, Jul 2007 + * Ebony Zhu <ebony.zhu@freescale.com>, May 2007 + * + * Description: + * DMA engine driver for Freescale MPC8540 DMA controller, which is + * also fit for MPC8560, MPC8555, MPC8548, MPC8641, and etc. + * The support for MPC8349 DMA contorller is also added. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/interrupt.h> +#include <linux/dmaengine.h> +#include <linux/delay.h> +#include <linux/dma-mapping.h> +#include <linux/dmapool.h> +#include <linux/of_platform.h> + +#include "fsldma.h" + +static void dma_init(struct fsl_dma_chan *fsl_chan) +{ + /* Reset the channel */ + DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr, 0, 32); + + switch (fsl_chan->feature & FSL_DMA_IP_MASK) { + case FSL_DMA_IP_85XX: + /* Set the channel to below modes: + * EIE - Error interrupt enable + * EOSIE - End of segments interrupt enable (basic mode) + * EOLNIE - End of links interrupt enable + */ + DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr, FSL_DMA_MR_EIE + | FSL_DMA_MR_EOLNIE | FSL_DMA_MR_EOSIE, 32); + break; + case FSL_DMA_IP_83XX: + /* Set the channel to below modes: + * EOTIE - End-of-transfer interrupt enable + */ + DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr, FSL_DMA_MR_EOTIE, + 32); + break; + } + +} + +static void set_sr(struct fsl_dma_chan *fsl_chan, u32 val) +{ + DMA_OUT(fsl_chan, &fsl_chan->reg_base->sr, val, 32); +} + +static u32 get_sr(struct fsl_dma_chan *fsl_chan) +{ + return DMA_IN(fsl_chan, &fsl_chan->reg_base->sr, 32); +} + +static void set_desc_cnt(struct fsl_dma_chan *fsl_chan, + struct fsl_dma_ld_hw *hw, u32 count) +{ + hw->count = CPU_TO_DMA(fsl_chan, count, 32); +} + +static void set_desc_src(struct fsl_dma_chan *fsl_chan, + struct fsl_dma_ld_hw *hw, dma_addr_t src) +{ + u64 snoop_bits; + + snoop_bits = ((fsl_chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_85XX) + ? ((u64)FSL_DMA_SATR_SREADTYPE_SNOOP_READ << 32) : 0; + hw->src_addr = CPU_TO_DMA(fsl_chan, snoop_bits | src, 64); +} + +static void set_desc_dest(struct fsl_dma_chan *fsl_chan, + struct fsl_dma_ld_hw *hw, dma_addr_t dest) +{ + u64 snoop_bits; + + snoop_bits = ((fsl_chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_85XX) + ? ((u64)FSL_DMA_DATR_DWRITETYPE_SNOOP_WRITE << 32) : 0; + hw->dst_addr = CPU_TO_DMA(fsl_chan, snoop_bits | dest, 64); +} + +static void set_desc_next(struct fsl_dma_chan *fsl_chan, + struct fsl_dma_ld_hw *hw, dma_addr_t next) +{ + u64 snoop_bits; + + snoop_bits = ((fsl_chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_83XX) + ? FSL_DMA_SNEN : 0; + hw->next_ln_addr = CPU_TO_DMA(fsl_chan, snoop_bits | next, 64); +} + +static void set_cdar(struct fsl_dma_chan *fsl_chan, dma_addr_t addr) +{ + DMA_OUT(fsl_chan, &fsl_chan->reg_base->cdar, addr | FSL_DMA_SNEN, 64); +} + +static dma_addr_t get_cdar(struct fsl_dma_chan *fsl_chan) +{ + return DMA_IN(fsl_chan, &fsl_chan->reg_base->cdar, 64) & ~FSL_DMA_SNEN; +} + +static void set_ndar(struct fsl_dma_chan *fsl_chan, dma_addr_t addr) +{ + DMA_OUT(fsl_chan, &fsl_chan->reg_base->ndar, addr, 64); +} + +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); + return (!(sr & FSL_DMA_SR_CB)) || (sr & FSL_DMA_SR_CH); +} + +static void dma_start(struct fsl_dma_chan *fsl_chan) +{ + u32 mr_set = 0;; + + if (fsl_chan->feature & FSL_DMA_CHAN_PAUSE_EXT) { + DMA_OUT(fsl_chan, &fsl_chan->reg_base->bcr, 0, 32); + mr_set |= FSL_DMA_MR_EMP_EN; + } else + DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr, + DMA_IN(fsl_chan, &fsl_chan->reg_base->mr, 32) + & ~FSL_DMA_MR_EMP_EN, 32); + + if (fsl_chan->feature & FSL_DMA_CHAN_START_EXT) + mr_set |= FSL_DMA_MR_EMS_EN; + else + mr_set |= FSL_DMA_MR_CS; + + DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr, + DMA_IN(fsl_chan, &fsl_chan->reg_base->mr, 32) + | mr_set, 32); +} + +static void dma_halt(struct fsl_dma_chan *fsl_chan) +{ + int i = 0; + DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr, + DMA_IN(fsl_chan, &fsl_chan->reg_base->mr, 32) | FSL_DMA_MR_CA, + 32); + DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr, + DMA_IN(fsl_chan, &fsl_chan->reg_base->mr, 32) & ~(FSL_DMA_MR_CS + | FSL_DMA_MR_EMS_EN | FSL_DMA_MR_CA), 32); + + while (!dma_is_idle(fsl_chan) && (i++ < 100)) + udelay(10); + if (i >= 100 && !dma_is_idle(fsl_chan)) + dev_err(fsl_chan->dev, "DMA halt timeout!\n"); +} + +static void set_ld_eol(struct fsl_dma_chan *fsl_chan, + struct fsl_desc_sw *desc) +{ + desc->hw.next_ln_addr = CPU_TO_DMA(fsl_chan, + DMA_TO_CPU(fsl_chan, desc->hw.next_ln_addr, 64) | FSL_DMA_EOL, + 64); +} + +static void append_ld_queue(struct fsl_dma_chan *fsl_chan, + struct fsl_desc_sw *new_desc) +{ + struct fsl_desc_sw *queue_tail = to_fsl_desc(fsl_chan->ld_queue.prev); + + if (list_empty(&fsl_chan->ld_queue)) + return; + + /* Link to the new descriptor physical address and + * Enable End-of-segment interrupt for + * the last link descriptor. + * (the previous node's next link descriptor) + * + * For FSL_DMA_IP_83xx, the snoop enable bit need be set. + */ + queue_tail->hw.next_ln_addr = CPU_TO_DMA(fsl_chan, + new_desc->async_tx.phys | FSL_DMA_EOSIE | + (((fsl_chan->feature & FSL_DMA_IP_MASK) + == FSL_DMA_IP_83XX) ? FSL_DMA_SNEN : 0), 64); +} + +/** + * fsl_chan_set_src_loop_size - Set source address hold transfer size + * @fsl_chan : Freescale DMA channel + * @size : Address loop size, 0 for disable loop + * + * The set source address hold transfer size. The source + * address hold or loop transfer size is when the DMA transfer + * data from source address (SA), if the loop size is 4, the DMA will + * read data from SA, SA + 1, SA + 2, SA + 3, then loop back to SA, + * SA + 1 ... and so on. + */ +static void fsl_chan_set_src_loop_size(struct fsl_dma_chan *fsl_chan, int size) +{ + switch (size) { + case 0: + DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr, + DMA_IN(fsl_chan, &fsl_chan->reg_base->mr, 32) & + (~FSL_DMA_MR_SAHE), 32); + break; + case 1: + case 2: + case 4: + case 8: + DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr, + DMA_IN(fsl_chan, &fsl_chan->reg_base->mr, 32) | + FSL_DMA_MR_SAHE | (__ilog2(size) << 14), + 32); + break; + } +} + +/** + * fsl_chan_set_dest_loop_size - Set destination address hold transfer size + * @fsl_chan : Freescale DMA channel + * @size : Address loop size, 0 for disable loop + * + * The set destination address hold transfer size. The destination + * address hold or loop transfer size is when the DMA transfer + * data to destination address (TA), if the loop size is 4, the DMA will + * write data to TA, TA + 1, TA + 2, TA + 3, then loop back to TA, + * TA + 1 ... and so on. + */ +static void fsl_chan_set_dest_loop_size(struct fsl_dma_chan *fsl_chan, int size) +{ + switch (size) { + case 0: + DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr, + DMA_IN(fsl_chan, &fsl_chan->reg_base->mr, 32) & + (~FSL_DMA_MR_DAHE), 32); + break; + case 1: + case 2: + case 4: + case 8: + DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr, + DMA_IN(fsl_chan, &fsl_chan->reg_base->mr, 32) | + FSL_DMA_MR_DAHE | (__ilog2(size) << 16), + 32); + break; + } +} + +/** + * fsl_chan_toggle_ext_pause - Toggle channel external pause status + * @fsl_chan : Freescale DMA channel + * @size : Pause control size, 0 for disable external pause control. + * The maximum is 1024. + * + * The Freescale DMA channel can be controlled by the external + * signal DREQ#. The pause control size is how many bytes are allowed + * to transfer before pausing the channel, after which a new assertion + * of DREQ# resumes channel operation. + */ +static void fsl_chan_toggle_ext_pause(struct fsl_dma_chan *fsl_chan, int size) +{ + if (size > 1024) + return; + + if (size) { + DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr, + DMA_IN(fsl_chan, &fsl_chan->reg_base->mr, 32) + | ((__ilog2(size) << 24) & 0x0f000000), + 32); + fsl_chan->feature |= FSL_DMA_CHAN_PAUSE_EXT; + } else + fsl_chan->feature &= ~FSL_DMA_CHAN_PAUSE_EXT; +} + +/** + * fsl_chan_toggle_ext_start - Toggle channel external start status + * @fsl_chan : Freescale DMA channel + * @enable : 0 is disabled, 1 is enabled. + * + * If enable the external start, the channel can be started by an + * external DMA start pin. So the dma_start() does not start the + * transfer immediately. The DMA channel will wait for the + * control pin asserted. + */ +static void fsl_chan_toggle_ext_start(struct fsl_dma_chan *fsl_chan, int enable) +{ + if (enable) + fsl_chan->feature |= FSL_DMA_CHAN_START_EXT; + else + fsl_chan->feature &= ~FSL_DMA_CHAN_START_EXT; +} + +static dma_cookie_t fsl_dma_tx_submit(struct dma_async_tx_descriptor *tx) +{ + struct fsl_desc_sw *desc = tx_to_fsl_desc(tx); + struct fsl_dma_chan *fsl_chan = to_fsl_chan(tx->chan); + unsigned long flags; + dma_cookie_t cookie; + + /* cookie increment and adding to ld_queue must be atomic */ + spin_lock_irqsave(&fsl_chan->desc_lock, flags); + + cookie = fsl_chan->common.cookie; + cookie++; + if (cookie < 0) + cookie = 1; + desc->async_tx.cookie = cookie; + fsl_chan->common.cookie = desc->async_tx.cookie; + + append_ld_queue(fsl_chan, desc); + list_splice_init(&desc->async_tx.tx_list, fsl_chan->ld_queue.prev); + + spin_unlock_irqrestore(&fsl_chan->desc_lock, flags); + + return cookie; +} + +/** + * fsl_dma_alloc_descriptor - Allocate descriptor from channel's DMA pool. + * @fsl_chan : Freescale DMA channel + * + * Return - The descriptor allocated. NULL for failed. + */ +static struct fsl_desc_sw *fsl_dma_alloc_descriptor( + struct fsl_dma_chan *fsl_chan) +{ + dma_addr_t pdesc; + struct fsl_desc_sw *desc_sw; + + desc_sw = dma_pool_alloc(fsl_chan->desc_pool, GFP_ATOMIC, &pdesc); + if (desc_sw) { + memset(desc_sw, 0, sizeof(struct fsl_desc_sw)); + dma_async_tx_descriptor_init(&desc_sw->async_tx, + &fsl_chan->common); + desc_sw->async_tx.tx_submit = fsl_dma_tx_submit; + INIT_LIST_HEAD(&desc_sw->async_tx.tx_list); + desc_sw->async_tx.phys = pdesc; + } + + return desc_sw; +} + + +/** + * fsl_dma_alloc_chan_resources - Allocate resources for DMA channel. + * @fsl_chan : Freescale DMA channel + * + * This function will create a dma pool for descriptor allocation. + * + * Return - The number of descriptors allocated. + */ +static int fsl_dma_alloc_chan_resources(struct dma_chan *chan) +{ + struct fsl_dma_chan *fsl_chan = to_fsl_chan(chan); + LIST_HEAD(tmp_list); + + /* We need the descriptor to be aligned to 32bytes + * for meeting FSL DMA specification requirement. + */ + fsl_chan->desc_pool = dma_pool_create("fsl_dma_engine_desc_pool", + fsl_chan->dev, sizeof(struct fsl_desc_sw), + 32, 0); + if (!fsl_chan->desc_pool) { + dev_err(fsl_chan->dev, "No memory for channel %d " + "descriptor dma pool.\n", fsl_chan->id); + return 0; + } + + return 1; +} + +/** + * fsl_dma_free_chan_resources - Free all resources of the channel. + * @fsl_chan : Freescale DMA channel + */ +static void fsl_dma_free_chan_resources(struct dma_chan *chan) +{ + struct fsl_dma_chan *fsl_chan = to_fsl_chan(chan); + struct fsl_desc_sw *desc, *_desc; + unsigned long flags; + + dev_dbg(fsl_chan->dev, "Free all channel resources.\n"); + spin_lock_irqsave(&fsl_chan->desc_lock, flags); + list_for_each_entry_safe(desc, _desc, &fsl_chan->ld_queue, node) { +#ifdef FSL_DMA_LD_DEBUG + dev_dbg(fsl_chan->dev, + "LD %p will be released.\n", desc); +#endif + list_del(&desc->node); + /* free link descriptor */ + dma_pool_free(fsl_chan->desc_pool, desc, desc->async_tx.phys); + } + spin_unlock_irqrestore(&fsl_chan->desc_lock, flags); + 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) +{ + struct fsl_dma_chan *fsl_chan; + struct fsl_desc_sw *first = NULL, *prev = NULL, *new; + size_t copy; + LIST_HEAD(link_chain); + + if (!chan) + return NULL; + + if (!len) + return NULL; + + fsl_chan = to_fsl_chan(chan); + + do { + + /* Allocate the link descriptor from DMA pool */ + new = fsl_dma_alloc_descriptor(fsl_chan); + if (!new) { + dev_err(fsl_chan->dev, + "No free memory for link descriptor\n"); + return NULL; + } +#ifdef FSL_DMA_LD_DEBUG + dev_dbg(fsl_chan->dev, "new link desc alloc %p\n", new); +#endif + + 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); + set_desc_dest(fsl_chan, &new->hw, dma_dest); + + if (!first) + first = new; + else + set_desc_next(fsl_chan, &prev->hw, new->async_tx.phys); + + new->async_tx.cookie = 0; + new->async_tx.ack = 1; + + prev = new; + len -= copy; + dma_src += copy; + dma_dest += copy; + + /* Insert the link descriptor to the LD ring */ + list_add_tail(&new->node, &first->async_tx.tx_list); + } while (len); + + new->async_tx.ack = 0; /* client is in control of this ack */ + new->async_tx.cookie = -EBUSY; + + /* Set End-of-link to the last link descriptor of new list*/ + set_ld_eol(fsl_chan, new); + + return first ? &first->async_tx : NULL; +} + +/** + * fsl_dma_update_completed_cookie - Update the completed cookie. + * @fsl_chan : Freescale DMA channel + */ +static void fsl_dma_update_completed_cookie(struct fsl_dma_chan *fsl_chan) +{ + struct fsl_desc_sw *cur_desc, *desc; + dma_addr_t ld_phy; + + ld_phy = get_cdar(fsl_chan) & FSL_DMA_NLDA_MASK; + + if (ld_phy) { + cur_desc = NULL; + list_for_each_entry(desc, &fsl_chan->ld_queue, node) + if (desc->async_tx.phys == ld_phy) { + cur_desc = desc; + break; + } + + if (cur_desc && cur_desc->async_tx.cookie) { + if (dma_is_idle(fsl_chan)) + fsl_chan->completed_cookie = + cur_desc->async_tx.cookie; + else + fsl_chan->completed_cookie = + cur_desc->async_tx.cookie - 1; + } + } +} + +/** + * fsl_chan_ld_cleanup - Clean up link descriptors + * @fsl_chan : Freescale DMA channel + * + * This function clean up the ld_queue of DMA channel. + * If 'in_intr' is set, the function will move the link descriptor to + * the recycle list. Otherwise, free it directly. + */ +static void fsl_chan_ld_cleanup(struct fsl_dma_chan *fsl_chan) +{ + struct fsl_desc_sw *desc, *_desc; + unsigned long flags; + + spin_lock_irqsave(&fsl_chan->desc_lock, flags); + + 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) { + dma_async_tx_callback callback; + void *callback_param; + + if (dma_async_is_complete(desc->async_tx.cookie, + fsl_chan->completed_cookie, fsl_chan->common.cookie) + == DMA_IN_PROGRESS) + break; + + callback = desc->async_tx.callback; + callback_param = desc->async_tx.callback_param; + + /* Remove from ld_queue list */ + list_del(&desc->node); + + dev_dbg(fsl_chan->dev, "link descriptor %p will be recycle.\n", + desc); + dma_pool_free(fsl_chan->desc_pool, desc, desc->async_tx.phys); + + /* Run the link descriptor callback function */ + if (callback) { + spin_unlock_irqrestore(&fsl_chan->desc_lock, flags); + dev_dbg(fsl_chan->dev, "link descriptor %p callback\n", + desc); + callback(callback_param); + spin_lock_irqsave(&fsl_chan->desc_lock, flags); + } + } + spin_unlock_irqrestore(&fsl_chan->desc_lock, flags); +} + +/** + * fsl_chan_xfer_ld_queue - Transfer link descriptors in channel ld_queue. + * @fsl_chan : Freescale DMA channel + */ +static void fsl_chan_xfer_ld_queue(struct fsl_dma_chan *fsl_chan) +{ + struct list_head *ld_node; + dma_addr_t next_dest_addr; + unsigned long flags; + + if (!dma_is_idle(fsl_chan)) + return; + + dma_halt(fsl_chan); + + /* If there are some link descriptors + * not transfered in queue. We need to start it. + */ + spin_lock_irqsave(&fsl_chan->desc_lock, flags); + + /* Find the first un-transfer desciptor */ + for (ld_node = fsl_chan->ld_queue.next; + (ld_node != &fsl_chan->ld_queue) + && (dma_async_is_complete( + to_fsl_desc(ld_node)->async_tx.cookie, + fsl_chan->completed_cookie, + fsl_chan->common.cookie) == DMA_SUCCESS); + ld_node = ld_node->next); + + spin_unlock_irqrestore(&fsl_chan->desc_lock, flags); + + 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 %p\n", + (void *)next_dest_addr); + set_cdar(fsl_chan, next_dest_addr); + dma_start(fsl_chan); + } else { + set_cdar(fsl_chan, 0); + set_ndar(fsl_chan, 0); + } +} + +/** + * fsl_dma_memcpy_issue_pending - Issue the DMA start command + * @fsl_chan : Freescale DMA channel + */ +static void fsl_dma_memcpy_issue_pending(struct dma_chan *chan) +{ + struct fsl_dma_chan *fsl_chan = to_fsl_chan(chan); + +#ifdef FSL_DMA_LD_DEBUG + struct fsl_desc_sw *ld; + unsigned long flags; + + spin_lock_irqsave(&fsl_chan->desc_lock, flags); + if (list_empty(&fsl_chan->ld_queue)) { + spin_unlock_irqrestore(&fsl_chan->desc_lock, flags); + return; + } + + dev_dbg(fsl_chan->dev, "--memcpy issue--\n"); + list_for_each_entry(ld, &fsl_chan->ld_queue, node) { + int i; + dev_dbg(fsl_chan->dev, "Ch %d, LD %08x\n", + fsl_chan->id, ld->async_tx.phys); + for (i = 0; i < 8; i++) + dev_dbg(fsl_chan->dev, "LD offset %d: %08x\n", + i, *(((u32 *)&ld->hw) + i)); + } + dev_dbg(fsl_chan->dev, "----------------\n"); + spin_unlock_irqrestore(&fsl_chan->desc_lock, flags); +#endif + + fsl_chan_xfer_ld_queue(fsl_chan); +} + +static void fsl_dma_dependency_added(struct dma_chan *chan) +{ + struct fsl_dma_chan *fsl_chan = to_fsl_chan(chan); + + fsl_chan_ld_cleanup(fsl_chan); +} + +/** + * fsl_dma_is_complete - Determine the DMA status + * @fsl_chan : Freescale DMA channel + */ +static enum dma_status fsl_dma_is_complete(struct dma_chan *chan, + dma_cookie_t cookie, + dma_cookie_t *done, + dma_cookie_t *used) +{ + struct fsl_dma_chan *fsl_chan = to_fsl_chan(chan); + dma_cookie_t last_used; + dma_cookie_t last_complete; + + fsl_chan_ld_cleanup(fsl_chan); + + last_used = chan->cookie; + last_complete = fsl_chan->completed_cookie; + + if (done) + *done = last_complete; + + if (used) + *used = last_used; + + return dma_async_is_complete(cookie, last_complete, last_used); +} + +static irqreturn_t fsl_dma_chan_do_interrupt(int irq, void *data) +{ + struct fsl_dma_chan *fsl_chan = (struct fsl_dma_chan *)data; + u32 stat; + + stat = get_sr(fsl_chan); + dev_dbg(fsl_chan->dev, "event: channel %d, stat = 0x%x\n", + fsl_chan->id, stat); + set_sr(fsl_chan, stat); /* Clear the event register */ + + stat &= ~(FSL_DMA_SR_CB | FSL_DMA_SR_CH); + if (!stat) + return IRQ_NONE; + + 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 %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, + * we should clear the Channel Start bit for + * prepare next transfer. + */ + if (stat & (FSL_DMA_SR_EOLNI | FSL_DMA_SR_EOCDI)) { + dev_dbg(fsl_chan->dev, "event: End-of-link INT\n"); + stat &= ~FSL_DMA_SR_EOLNI; + fsl_chan_xfer_ld_queue(fsl_chan); + } + + if (stat) + dev_dbg(fsl_chan->dev, "event: unhandled sr 0x%02x\n", + stat); + + dev_dbg(fsl_chan->dev, "event: Exit\n"); + tasklet_schedule(&fsl_chan->tasklet); + return IRQ_HANDLED; +} + +static irqreturn_t fsl_dma_do_interrupt(int irq, void *data) +{ + struct fsl_dma_device *fdev = (struct fsl_dma_device *)data; + u32 gsr; + int ch_nr; + + gsr = (fdev->feature & FSL_DMA_BIG_ENDIAN) ? in_be32(fdev->reg_base) + : in_le32(fdev->reg_base); + ch_nr = (32 - ffs(gsr)) / 8; + + return fdev->chan[ch_nr] ? fsl_dma_chan_do_interrupt(irq, + fdev->chan[ch_nr]) : IRQ_NONE; +} + +static void dma_do_tasklet(unsigned long data) +{ + struct fsl_dma_chan *fsl_chan = (struct fsl_dma_chan *)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; + int err = 0; + dma_addr_t dma_dest, dma_src; + dma_cookie_t cookie; + u8 *src, *dest; + int i; + size_t test_size; + struct dma_async_tx_descriptor *tx1, *tx2, *tx3; + + test_size = 4096; + + src = kmalloc(test_size * 2, GFP_KERNEL); + if (!src) { + dev_err(fsl_chan->dev, + "selftest: Cannot alloc memory for test!\n"); + err = -ENOMEM; + goto out; + } + + dest = src + test_size; + + for (i = 0; i < test_size; i++) + src[i] = (u8) i; + + chan = &fsl_chan->common; + + if (fsl_dma_alloc_chan_resources(chan) < 1) { + dev_err(fsl_chan->dev, + "selftest: Cannot alloc resources for DMA\n"); + err = -ENODEV; + goto out; + } + + /* TX 1 */ + dma_src = dma_map_single(fsl_chan->dev, src, test_size / 2, + DMA_TO_DEVICE); + dma_dest = dma_map_single(fsl_chan->dev, dest, test_size / 2, + DMA_FROM_DEVICE); + tx1 = fsl_dma_prep_memcpy(chan, dma_dest, dma_src, test_size / 2, 0); + async_tx_ack(tx1); + + cookie = fsl_dma_tx_submit(tx1); + fsl_dma_memcpy_issue_pending(chan); + msleep(2); + + if (fsl_dma_is_complete(chan, cookie, NULL, NULL) != DMA_SUCCESS) { + dev_err(fsl_chan->dev, "selftest: Time out!\n"); + err = -ENODEV; + goto out; + } + + /* Test free and re-alloc channel resources */ + fsl_dma_free_chan_resources(chan); + + if (fsl_dma_alloc_chan_resources(chan) < 1) { + dev_err(fsl_chan->dev, + "selftest: Cannot alloc resources for DMA\n"); + err = -ENODEV; + goto free_resources; + } + + /* Continue to test + * TX 2 + */ + dma_src = dma_map_single(fsl_chan->dev, src + test_size / 2, + test_size / 4, DMA_TO_DEVICE); + dma_dest = dma_map_single(fsl_chan->dev, dest + test_size / 2, + test_size / 4, DMA_FROM_DEVICE); + tx2 = fsl_dma_prep_memcpy(chan, dma_dest, dma_src, test_size / 4, 0); + async_tx_ack(tx2); + + /* TX 3 */ + dma_src = dma_map_single(fsl_chan->dev, src + test_size * 3 / 4, + test_size / 4, DMA_TO_DEVICE); + dma_dest = dma_map_single(fsl_chan->dev, dest + test_size * 3 / 4, + test_size / 4, DMA_FROM_DEVICE); + 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); + +#ifdef FSL_DMA_CALLBACKTEST + if (dma_has_cap(DMA_INTERRUPT, ((struct fsl_dma_device *) + dev_get_drvdata(fsl_chan->dev->parent))->common.cap_mask)) { + tx3->callback = fsl_dma_callback_test; + tx3->callback_param = fsl_chan; + } +#endif + fsl_dma_memcpy_issue_pending(chan); + msleep(2); + + if (fsl_dma_is_complete(chan, cookie, NULL, NULL) != DMA_SUCCESS) { + dev_err(fsl_chan->dev, "selftest: Time out!\n"); + err = -ENODEV; + goto free_resources; + } + + err = memcmp(src, dest, test_size); + if (err) { + for (i = 0; (*(src + i) == *(dest + i)) && (i < test_size); + i++); + dev_err(fsl_chan->dev, "selftest: Test failed, data %d/%ld is " + "error! src 0x%x, dest 0x%x\n", + i, (long)test_size, *(src + i), *(dest + i)); + } + +free_resources: + fsl_dma_free_chan_resources(chan); +out: + kfree(src); + return err; +} +#endif + +static int __devinit of_fsl_dma_chan_probe(struct of_device *dev, + const struct of_device_id *match) +{ + struct fsl_dma_device *fdev; + struct fsl_dma_chan *new_fsl_chan; + int err; + + fdev = dev_get_drvdata(dev->dev.parent); + BUG_ON(!fdev); + + /* alloc channel */ + new_fsl_chan = kzalloc(sizeof(struct fsl_dma_chan), GFP_KERNEL); + if (!new_fsl_chan) { + dev_err(&dev->dev, "No free memory for allocating " + "dma channels!\n"); + err = -ENOMEM; + goto err; + } + + /* get dma channel register base */ + err = of_address_to_resource(dev->node, 0, &new_fsl_chan->reg); + if (err) { + dev_err(&dev->dev, "Can't get %s property 'reg'\n", + dev->node->full_name); + goto err; + } + + new_fsl_chan->feature = *(u32 *)match->data; + + if (!fdev->feature) + fdev->feature = new_fsl_chan->feature; + + /* If the DMA device's feature is different than its channels', + * report the bug. + */ + WARN_ON(fdev->feature != new_fsl_chan->feature); + + new_fsl_chan->dev = &dev->dev; + new_fsl_chan->reg_base = ioremap(new_fsl_chan->reg.start, + new_fsl_chan->reg.end - new_fsl_chan->reg.start + 1); + + new_fsl_chan->id = ((new_fsl_chan->reg.start - 0x100) & 0xfff) >> 7; + if (new_fsl_chan->id > FSL_DMA_MAX_CHANS_PER_DEVICE) { + dev_err(&dev->dev, "There is no %d channel!\n", + new_fsl_chan->id); + err = -EINVAL; + goto err; + } + fdev->chan[new_fsl_chan->id] = new_fsl_chan; + tasklet_init(&new_fsl_chan->tasklet, dma_do_tasklet, + (unsigned long)new_fsl_chan); + + /* Init the channel */ + dma_init(new_fsl_chan); + + /* Clear cdar registers */ + set_cdar(new_fsl_chan, 0); + + switch (new_fsl_chan->feature & FSL_DMA_IP_MASK) { + case FSL_DMA_IP_85XX: + new_fsl_chan->toggle_ext_start = fsl_chan_toggle_ext_start; + new_fsl_chan->toggle_ext_pause = fsl_chan_toggle_ext_pause; + case FSL_DMA_IP_83XX: + new_fsl_chan->set_src_loop_size = fsl_chan_set_src_loop_size; + new_fsl_chan->set_dest_loop_size = fsl_chan_set_dest_loop_size; + } + + spin_lock_init(&new_fsl_chan->desc_lock); + INIT_LIST_HEAD(&new_fsl_chan->ld_queue); + + new_fsl_chan->common.device = &fdev->common; + + /* Add the channel to DMA device channel list */ + list_add_tail(&new_fsl_chan->common.device_node, + &fdev->common.channels); + fdev->common.chancnt++; + + new_fsl_chan->irq = irq_of_parse_and_map(dev->node, 0); + if (new_fsl_chan->irq != NO_IRQ) { + err = request_irq(new_fsl_chan->irq, + &fsl_dma_chan_do_interrupt, IRQF_SHARED, + "fsldma-channel", new_fsl_chan); + if (err) { + dev_err(&dev->dev, "DMA channel %s request_irq error " + "with return %d\n", dev->node->full_name, err); + goto err; + } + } + +#ifdef CONFIG_FSL_DMA_SELFTEST + err = fsl_dma_self_test(new_fsl_chan); + if (err) + goto err; +#endif + + dev_info(&dev->dev, "#%d (%s), irq %d\n", new_fsl_chan->id, + match->compatible, new_fsl_chan->irq); + + return 0; +err: + dma_halt(new_fsl_chan); + iounmap(new_fsl_chan->reg_base); + free_irq(new_fsl_chan->irq, new_fsl_chan); + list_del(&new_fsl_chan->common.device_node); + kfree(new_fsl_chan); + return err; +} + +const u32 mpc8540_dma_ip_feature = FSL_DMA_IP_85XX | FSL_DMA_BIG_ENDIAN; +const u32 mpc8349_dma_ip_feature = FSL_DMA_IP_83XX | FSL_DMA_LITTLE_ENDIAN; + +static struct of_device_id of_fsl_dma_chan_ids[] = { + { + .compatible = "fsl,mpc8540-dma-channel", + .data = (void *)&mpc8540_dma_ip_feature, + }, + { + .compatible = "fsl,mpc8349-dma-channel", + .data = (void *)&mpc8349_dma_ip_feature, + }, + {} +}; + +static struct of_platform_driver of_fsl_dma_chan_driver = { + .name = "of-fsl-dma-channel", + .match_table = of_fsl_dma_chan_ids, + .probe = of_fsl_dma_chan_probe, +}; + +static __init int of_fsl_dma_chan_init(void) +{ + return of_register_platform_driver(&of_fsl_dma_chan_driver); +} + +static int __devinit of_fsl_dma_probe(struct of_device *dev, + const struct of_device_id *match) +{ + int err; + unsigned int irq; + struct fsl_dma_device *fdev; + + fdev = kzalloc(sizeof(struct fsl_dma_device), GFP_KERNEL); + if (!fdev) { + dev_err(&dev->dev, "No enough memory for 'priv'\n"); + err = -ENOMEM; + goto err; + } + fdev->dev = &dev->dev; + INIT_LIST_HEAD(&fdev->common.channels); + + /* get DMA controller register base */ + err = of_address_to_resource(dev->node, 0, &fdev->reg); + if (err) { + dev_err(&dev->dev, "Can't get %s property 'reg'\n", + dev->node->full_name); + goto err; + } + + dev_info(&dev->dev, "Probe the Freescale DMA driver for %s " + "controller at %p...\n", + match->compatible, (void *)fdev->reg.start); + fdev->reg_base = ioremap(fdev->reg.start, fdev->reg.end + - fdev->reg.start + 1); + + dma_cap_set(DMA_MEMCPY, fdev->common.cap_mask); + 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; + fdev->common.device_dependency_added = fsl_dma_dependency_added; + fdev->common.dev = &dev->dev; + + irq = irq_of_parse_and_map(dev->node, 0); + if (irq != NO_IRQ) { + err = request_irq(irq, &fsl_dma_do_interrupt, IRQF_SHARED, + "fsldma-device", fdev); + if (err) { + dev_err(&dev->dev, "DMA device request_irq error " + "with return %d\n", err); + goto err; + } + } + + dev_set_drvdata(&(dev->dev), fdev); + of_platform_bus_probe(dev->node, of_fsl_dma_chan_ids, &dev->dev); + + dma_async_device_register(&fdev->common); + return 0; + +err: + iounmap(fdev->reg_base); + kfree(fdev); + return err; +} + +static struct of_device_id of_fsl_dma_ids[] = { + { .compatible = "fsl,mpc8540-dma", }, + { .compatible = "fsl,mpc8349-dma", }, + {} +}; + +static struct of_platform_driver of_fsl_dma_driver = { + .name = "of-fsl-dma", + .match_table = of_fsl_dma_ids, + .probe = of_fsl_dma_probe, +}; + +static __init int of_fsl_dma_init(void) +{ + return of_register_platform_driver(&of_fsl_dma_driver); +} + +subsys_initcall(of_fsl_dma_chan_init); +subsys_initcall(of_fsl_dma_init); diff --git a/drivers/dma/fsldma.h b/drivers/dma/fsldma.h new file mode 100644 index 00000000000..fddd6aee2a6 --- /dev/null +++ b/drivers/dma/fsldma.h @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved. + * + * Author: + * Zhang Wei <wei.zhang@freescale.com>, Jul 2007 + * Ebony Zhu <ebony.zhu@freescale.com>, May 2007 + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ +#ifndef __DMA_FSLDMA_H +#define __DMA_FSLDMA_H + +#include <linux/device.h> +#include <linux/dmapool.h> +#include <linux/dmaengine.h> + +/* Define data structures needed by Freescale + * MPC8540 and MPC8349 DMA controller. + */ +#define FSL_DMA_MR_CS 0x00000001 +#define FSL_DMA_MR_CC 0x00000002 +#define FSL_DMA_MR_CA 0x00000008 +#define FSL_DMA_MR_EIE 0x00000040 +#define FSL_DMA_MR_XFE 0x00000020 +#define FSL_DMA_MR_EOLNIE 0x00000100 +#define FSL_DMA_MR_EOLSIE 0x00000080 +#define FSL_DMA_MR_EOSIE 0x00000200 +#define FSL_DMA_MR_CDSM 0x00000010 +#define FSL_DMA_MR_CTM 0x00000004 +#define FSL_DMA_MR_EMP_EN 0x00200000 +#define FSL_DMA_MR_EMS_EN 0x00040000 +#define FSL_DMA_MR_DAHE 0x00002000 +#define FSL_DMA_MR_SAHE 0x00001000 + +/* Special MR definition for MPC8349 */ +#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 +#define FSL_DMA_SR_EOLSI 0x00000001 +#define FSL_DMA_SR_EOCDI 0x00000001 +#define FSL_DMA_SR_EOLNI 0x00000008 + +#define FSL_DMA_SATR_SBPATMU 0x20000000 +#define FSL_DMA_SATR_STRANSINT_RIO 0x00c00000 +#define FSL_DMA_SATR_SREADTYPE_SNOOP_READ 0x00050000 +#define FSL_DMA_SATR_SREADTYPE_BP_IORH 0x00020000 +#define FSL_DMA_SATR_SREADTYPE_BP_NREAD 0x00040000 +#define FSL_DMA_SATR_SREADTYPE_BP_MREAD 0x00070000 + +#define FSL_DMA_DATR_DBPATMU 0x20000000 +#define FSL_DMA_DATR_DTRANSINT_RIO 0x00c00000 +#define FSL_DMA_DATR_DWRITETYPE_SNOOP_WRITE 0x00050000 +#define FSL_DMA_DATR_DWRITETYPE_BP_FLUSH 0x00010000 + +#define FSL_DMA_EOL ((u64)0x1) +#define FSL_DMA_SNEN ((u64)0x10) +#define FSL_DMA_EOSIE 0x8 +#define FSL_DMA_NLDA_MASK (~(u64)0x1f) + +#define FSL_DMA_BCR_MAX_CNT 0x03ffffffu + +#define FSL_DMA_DGSR_TE 0x80 +#define FSL_DMA_DGSR_CH 0x20 +#define FSL_DMA_DGSR_PE 0x10 +#define FSL_DMA_DGSR_EOLNI 0x08 +#define FSL_DMA_DGSR_CB 0x04 +#define FSL_DMA_DGSR_EOSI 0x02 +#define FSL_DMA_DGSR_EOLSI 0x01 + +struct fsl_dma_ld_hw { + u64 __bitwise src_addr; + u64 __bitwise dst_addr; + u64 __bitwise next_ln_addr; + u32 __bitwise count; + u32 __bitwise reserve; +} __attribute__((aligned(32))); + +struct fsl_desc_sw { + struct fsl_dma_ld_hw hw; + struct list_head node; + struct dma_async_tx_descriptor async_tx; + struct list_head *ld; + void *priv; +} __attribute__((aligned(32))); + +struct fsl_dma_chan_regs { + u32 __bitwise mr; /* 0x00 - Mode Register */ + u32 __bitwise sr; /* 0x04 - Status Register */ + u64 __bitwise cdar; /* 0x08 - Current descriptor address register */ + u64 __bitwise sar; /* 0x10 - Source Address Register */ + u64 __bitwise dar; /* 0x18 - Destination Address Register */ + u32 __bitwise bcr; /* 0x20 - Byte Count Register */ + u64 __bitwise ndar; /* 0x24 - Next Descriptor Address Register */ +}; + +struct fsl_dma_chan; +#define FSL_DMA_MAX_CHANS_PER_DEVICE 4 + +struct fsl_dma_device { + void __iomem *reg_base; /* DGSR register base */ + struct resource reg; /* Resource for register */ + struct device *dev; + struct dma_device common; + struct fsl_dma_chan *chan[FSL_DMA_MAX_CHANS_PER_DEVICE]; + u32 feature; /* The same as DMA channels */ +}; + +/* Define macros for fsl_dma_chan->feature property */ +#define FSL_DMA_LITTLE_ENDIAN 0x00000000 +#define FSL_DMA_BIG_ENDIAN 0x00000001 + +#define FSL_DMA_IP_MASK 0x00000ff0 +#define FSL_DMA_IP_85XX 0x00000010 +#define FSL_DMA_IP_83XX 0x00000020 + +#define FSL_DMA_CHAN_PAUSE_EXT 0x00001000 +#define FSL_DMA_CHAN_START_EXT 0x00002000 + +struct fsl_dma_chan { + struct fsl_dma_chan_regs __iomem *reg_base; + dma_cookie_t completed_cookie; /* The maximum cookie completed */ + spinlock_t desc_lock; /* Descriptor operation lock */ + struct list_head ld_queue; /* Link descriptors queue */ + struct dma_chan common; /* DMA common channel */ + struct dma_pool *desc_pool; /* Descriptors pool */ + struct device *dev; /* Channel device */ + struct resource reg; /* Resource for register */ + int irq; /* Channel IRQ */ + int id; /* Raw id of this channel */ + struct tasklet_struct tasklet; + u32 feature; + + void (*toggle_ext_pause)(struct fsl_dma_chan *fsl_chan, int size); + void (*toggle_ext_start)(struct fsl_dma_chan *fsl_chan, int enable); + void (*set_src_loop_size)(struct fsl_dma_chan *fsl_chan, int size); + void (*set_dest_loop_size)(struct fsl_dma_chan *fsl_chan, int size); +}; + +#define to_fsl_chan(chan) container_of(chan, struct fsl_dma_chan, common) +#define to_fsl_desc(lh) container_of(lh, struct fsl_desc_sw, node) +#define tx_to_fsl_desc(tx) container_of(tx, struct fsl_desc_sw, async_tx) + +#ifndef __powerpc64__ +static u64 in_be64(const u64 __iomem *addr) +{ + return ((u64)in_be32((u32 *)addr) << 32) | (in_be32((u32 *)addr + 1)); +} + +static void out_be64(u64 __iomem *addr, u64 val) +{ + out_be32((u32 *)addr, val >> 32); + out_be32((u32 *)addr + 1, (u32)val); +} + +/* There is no asm instructions for 64 bits reverse loads and stores */ +static u64 in_le64(const u64 __iomem *addr) +{ + return ((u64)in_le32((u32 *)addr + 1) << 32) | (in_le32((u32 *)addr)); +} + +static void out_le64(u64 __iomem *addr, u64 val) +{ + out_le32((u32 *)addr + 1, val >> 32); + out_le32((u32 *)addr, (u32)val); +} +#endif + +#define DMA_IN(fsl_chan, addr, width) \ + (((fsl_chan)->feature & FSL_DMA_BIG_ENDIAN) ? \ + in_be##width(addr) : in_le##width(addr)) +#define DMA_OUT(fsl_chan, addr, val, width) \ + (((fsl_chan)->feature & FSL_DMA_BIG_ENDIAN) ? \ + out_be##width(addr, val) : out_le##width(addr, val)) + +#define DMA_TO_CPU(fsl_chan, d, width) \ + (((fsl_chan)->feature & FSL_DMA_BIG_ENDIAN) ? \ + be##width##_to_cpu(d) : le##width##_to_cpu(d)) +#define CPU_TO_DMA(fsl_chan, c, width) \ + (((fsl_chan)->feature & FSL_DMA_BIG_ENDIAN) ? \ + cpu_to_be##width(c) : cpu_to_le##width(c)) + +#endif /* __DMA_FSLDMA_H */ diff --git a/drivers/dma/ioat_dma.c b/drivers/dma/ioat_dma.c index dff38accc5c..4017d9e7acd 100644 --- a/drivers/dma/ioat_dma.c +++ b/drivers/dma/ioat_dma.c @@ -714,6 +714,7 @@ static struct dma_async_tx_descriptor *ioat1_dma_prep_memcpy( new->len = len; new->dst = dma_dest; new->src = dma_src; + new->async_tx.ack = 0; return &new->async_tx; } else return NULL; @@ -741,6 +742,7 @@ static struct dma_async_tx_descriptor *ioat2_dma_prep_memcpy( new->len = len; new->dst = dma_dest; new->src = dma_src; + new->async_tx.ack = 0; return &new->async_tx; } else return NULL; diff --git a/drivers/dma/iop-adma.c b/drivers/dma/iop-adma.c index 3986d54492b..f82b0906d46 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 fe9e768cfbc..25bdc2dd9ce 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-card.c b/drivers/firewire/fw-card.c index 3e9719948a8..a03462750b9 100644 --- a/drivers/firewire/fw-card.c +++ b/drivers/firewire/fw-card.c @@ -18,6 +18,7 @@ #include <linux/module.h> #include <linux/errno.h> +#include <linux/delay.h> #include <linux/device.h> #include <linux/mutex.h> #include <linux/crc-itu-t.h> @@ -214,17 +215,29 @@ static void fw_card_bm_work(struct work_struct *work) { struct fw_card *card = container_of(work, struct fw_card, work.work); - struct fw_device *root; + struct fw_device *root_device; + struct fw_node *root_node, *local_node; struct bm_data bmd; unsigned long flags; int root_id, new_root_id, irm_id, gap_count, generation, grace; int do_reset = 0; spin_lock_irqsave(&card->lock, flags); + local_node = card->local_node; + root_node = card->root_node; + + if (local_node == NULL) { + spin_unlock_irqrestore(&card->lock, flags); + return; + } + fw_node_get(local_node); + fw_node_get(root_node); generation = card->generation; - root = card->root_node->data; - root_id = card->root_node->node_id; + root_device = root_node->data; + if (root_device) + fw_device_get(root_device); + root_id = root_node->node_id; grace = time_after(jiffies, card->reset_jiffies + DIV_ROUND_UP(HZ, 10)); if (card->bm_generation + 1 == generation || @@ -243,14 +256,14 @@ fw_card_bm_work(struct work_struct *work) irm_id = card->irm_node->node_id; if (!card->irm_node->link_on) { - new_root_id = card->local_node->node_id; + new_root_id = local_node->node_id; fw_notify("IRM has link off, making local node (%02x) root.\n", new_root_id); goto pick_me; } bmd.lock.arg = cpu_to_be32(0x3f); - bmd.lock.data = cpu_to_be32(card->local_node->node_id); + bmd.lock.data = cpu_to_be32(local_node->node_id); spin_unlock_irqrestore(&card->lock, flags); @@ -267,12 +280,12 @@ fw_card_bm_work(struct work_struct *work) * Another bus reset happened. Just return, * the BM work has been rescheduled. */ - return; + goto out; } if (bmd.rcode == RCODE_COMPLETE && bmd.old != 0x3f) /* Somebody else is BM, let them do the work. */ - return; + goto out; spin_lock_irqsave(&card->lock, flags); if (bmd.rcode != RCODE_COMPLETE) { @@ -282,7 +295,7 @@ fw_card_bm_work(struct work_struct *work) * do a bus reset and pick the local node as * root, and thus, IRM. */ - new_root_id = card->local_node->node_id; + new_root_id = local_node->node_id; fw_notify("BM lock failed, making local node (%02x) root.\n", new_root_id); goto pick_me; @@ -295,7 +308,7 @@ fw_card_bm_work(struct work_struct *work) */ spin_unlock_irqrestore(&card->lock, flags); schedule_delayed_work(&card->work, DIV_ROUND_UP(HZ, 10)); - return; + goto out; } /* @@ -305,20 +318,20 @@ fw_card_bm_work(struct work_struct *work) */ card->bm_generation = generation; - if (root == NULL) { + if (root_device == NULL) { /* * Either link_on is false, or we failed to read the * config rom. In either case, pick another root. */ - new_root_id = card->local_node->node_id; - } else if (atomic_read(&root->state) != FW_DEVICE_RUNNING) { + new_root_id = local_node->node_id; + } else if (atomic_read(&root_device->state) != FW_DEVICE_RUNNING) { /* * If we haven't probed this device yet, bail out now * and let's try again once that's done. */ spin_unlock_irqrestore(&card->lock, flags); - return; - } else if (root->config_rom[2] & BIB_CMC) { + goto out; + } else if (root_device->config_rom[2] & BIB_CMC) { /* * FIXME: I suppose we should set the cmstr bit in the * STATE_CLEAR register of this node, as described in @@ -332,7 +345,7 @@ fw_card_bm_work(struct work_struct *work) * successfully read the config rom, but it's not * cycle master capable. */ - new_root_id = card->local_node->node_id; + new_root_id = local_node->node_id; } pick_me: @@ -341,8 +354,8 @@ fw_card_bm_work(struct work_struct *work) * the typically much larger 1394b beta repeater delays though. */ if (!card->beta_repeaters_present && - card->root_node->max_hops < ARRAY_SIZE(gap_count_table)) - gap_count = gap_count_table[card->root_node->max_hops]; + root_node->max_hops < ARRAY_SIZE(gap_count_table)) + gap_count = gap_count_table[root_node->max_hops]; else gap_count = 63; @@ -364,6 +377,11 @@ fw_card_bm_work(struct work_struct *work) fw_send_phy_config(card, new_root_id, generation, gap_count); fw_core_initiate_bus_reset(card, 1); } + out: + if (root_device) + fw_device_put(root_device); + fw_node_put(root_node); + fw_node_put(local_node); } static void @@ -381,6 +399,7 @@ fw_card_initialize(struct fw_card *card, const struct fw_card_driver *driver, static atomic_t index = ATOMIC_INIT(-1); kref_init(&card->kref); + atomic_set(&card->device_count, 0); card->index = atomic_inc_return(&index); card->driver = driver; card->device = device; @@ -511,8 +530,14 @@ fw_core_remove_card(struct fw_card *card) card->driver = &dummy_driver; fw_destroy_nodes(card); - flush_scheduled_work(); + /* + * Wait for all device workqueue jobs to finish. Otherwise the + * firewire-core module could be unloaded before the jobs ran. + */ + while (atomic_read(&card->device_count) > 0) + msleep(100); + cancel_delayed_work_sync(&card->work); fw_flush_transactions(card); del_timer_sync(&card->flush_timer); diff --git a/drivers/firewire/fw-device.c b/drivers/firewire/fw-device.c index 2ab13e0f346..870125a3638 100644 --- a/drivers/firewire/fw-device.c +++ b/drivers/firewire/fw-device.c @@ -150,21 +150,10 @@ struct bus_type fw_bus_type = { }; EXPORT_SYMBOL(fw_bus_type); -struct fw_device *fw_device_get(struct fw_device *device) -{ - get_device(&device->device); - - return device; -} - -void fw_device_put(struct fw_device *device) -{ - put_device(&device->device); -} - static void fw_device_release(struct device *dev) { struct fw_device *device = fw_device(dev); + struct fw_card *card = device->card; unsigned long flags; /* @@ -176,9 +165,9 @@ static void fw_device_release(struct device *dev) spin_unlock_irqrestore(&device->card->lock, flags); fw_node_put(device->node); - fw_card_put(device->card); kfree(device->config_rom); kfree(device); + atomic_dec(&card->device_count); } int fw_device_enable_phys_dma(struct fw_device *device) @@ -668,7 +657,8 @@ static void fw_device_init(struct work_struct *work) */ if (read_bus_info_block(device, device->generation) < 0) { - if (device->config_rom_retries < MAX_RETRIES) { + if (device->config_rom_retries < MAX_RETRIES && + atomic_read(&device->state) == FW_DEVICE_INITIALIZING) { device->config_rom_retries++; schedule_delayed_work(&device->work, RETRY_DELAY); } else { @@ -805,7 +795,8 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event) */ device_initialize(&device->device); atomic_set(&device->state, FW_DEVICE_INITIALIZING); - device->card = fw_card_get(card); + atomic_inc(&card->device_count); + device->card = card; device->node = fw_node_get(node); device->node_id = node->node_id; device->generation = card->generation; diff --git a/drivers/firewire/fw-device.h b/drivers/firewire/fw-device.h index 43808c02793..78ecd3991b7 100644 --- a/drivers/firewire/fw-device.h +++ b/drivers/firewire/fw-device.h @@ -76,9 +76,21 @@ fw_device_is_shutdown(struct fw_device *device) return atomic_read(&device->state) == FW_DEVICE_SHUTDOWN; } -struct fw_device *fw_device_get(struct fw_device *device); +static inline struct fw_device * +fw_device_get(struct fw_device *device) +{ + get_device(&device->device); + + return device; +} + +static inline void +fw_device_put(struct fw_device *device) +{ + put_device(&device->device); +} + struct fw_device *fw_device_get_by_devt(dev_t devt); -void fw_device_put(struct fw_device *device); int fw_device_enable_phys_dma(struct fw_device *device); void fw_device_cdev_update(struct fw_device *device); diff --git a/drivers/firewire/fw-ohci.c b/drivers/firewire/fw-ohci.c index 7ebad3c14cb..996d61f0d46 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 5259491580f..62b4e47d0cc 100644 --- a/drivers/firewire/fw-sbp2.c +++ b/drivers/firewire/fw-sbp2.c @@ -122,7 +122,6 @@ static const char sbp2_driver_name[] = "sbp2"; struct sbp2_logical_unit { struct sbp2_target *tgt; struct list_head link; - struct scsi_device *sdev; struct fw_address_handler address_handler; struct list_head orb_list; @@ -139,6 +138,7 @@ struct sbp2_logical_unit { int generation; int retries; struct delayed_work work; + bool has_sdev; bool blocked; }; @@ -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 @@ -751,20 +757,34 @@ static void sbp2_unblock(struct sbp2_target *tgt) scsi_unblock_requests(shost); } +static int sbp2_lun2int(u16 lun) +{ + struct scsi_lun eight_bytes_lun; + + memset(&eight_bytes_lun, 0, sizeof(eight_bytes_lun)); + eight_bytes_lun.scsi_lun[0] = (lun >> 8) & 0xff; + eight_bytes_lun.scsi_lun[1] = lun & 0xff; + + return scsilun_to_int(&eight_bytes_lun); +} + static void sbp2_release_target(struct kref *kref) { struct sbp2_target *tgt = container_of(kref, struct sbp2_target, kref); struct sbp2_logical_unit *lu, *next; struct Scsi_Host *shost = container_of((void *)tgt, struct Scsi_Host, hostdata[0]); + struct scsi_device *sdev; + struct fw_device *device = fw_device(tgt->unit->device.parent); /* prevent deadlocks */ sbp2_unblock(tgt); list_for_each_entry_safe(lu, next, &tgt->lu_list, link) { - if (lu->sdev) { - scsi_remove_device(lu->sdev); - scsi_device_put(lu->sdev); + sdev = scsi_device_lookup(shost, 0, 0, sbp2_lun2int(lu->lun)); + if (sdev) { + scsi_remove_device(sdev); + scsi_device_put(sdev); } sbp2_send_management_orb(lu, tgt->node_id, lu->generation, SBP2_LOGOUT_REQUEST, lu->login_id, NULL); @@ -778,6 +798,7 @@ static void sbp2_release_target(struct kref *kref) put_device(&tgt->unit->device); scsi_host_put(shost); + fw_device_put(device); } static struct workqueue_struct *sbp2_wq; @@ -797,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) @@ -807,7 +852,6 @@ static void sbp2_login(struct work_struct *work) struct fw_device *device = fw_device(tgt->unit->device.parent); struct Scsi_Host *shost; struct scsi_device *sdev; - struct scsi_lun eight_bytes_lun; struct sbp2_login_response response; int generation, node_id, local_node_id; @@ -820,7 +864,7 @@ static void sbp2_login(struct work_struct *work) local_node_id = device->card->node_id; /* If this is a re-login attempt, log out, or we might be rejected. */ - if (lu->sdev) + if (lu->has_sdev) sbp2_send_management_orb(lu, device->node_id, generation, SBP2_LOGOUT_REQUEST, lu->login_id, NULL); @@ -850,16 +894,14 @@ 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); /* This was a re-login. */ - if (lu->sdev) { + if (lu->has_sdev) { sbp2_cancel_orbs(lu); sbp2_conditionally_unblock(lu); goto out; @@ -868,13 +910,8 @@ static void sbp2_login(struct work_struct *work) if (lu->tgt->workarounds & SBP2_WORKAROUND_DELAY_INQUIRY) ssleep(SBP2_INQUIRY_DELAY); - memset(&eight_bytes_lun, 0, sizeof(eight_bytes_lun)); - eight_bytes_lun.scsi_lun[0] = (lu->lun >> 8) & 0xff; - eight_bytes_lun.scsi_lun[1] = lu->lun & 0xff; shost = container_of((void *)tgt, struct Scsi_Host, hostdata[0]); - - sdev = __scsi_add_device(shost, 0, 0, - scsilun_to_int(&eight_bytes_lun), lu); + sdev = __scsi_add_device(shost, 0, 0, sbp2_lun2int(lu->lun), lu); /* * FIXME: We are unable to perform reconnects while in sbp2_login(). * Therefore __scsi_add_device() will get into trouble if a bus reset @@ -896,7 +933,8 @@ static void sbp2_login(struct work_struct *work) } /* No error during __scsi_add_device() */ - lu->sdev = sdev; + lu->has_sdev = true; + scsi_device_put(sdev); sbp2_allow_block(lu); goto out; @@ -934,11 +972,11 @@ static int sbp2_add_logical_unit(struct sbp2_target *tgt, int lun_entry) return -ENOMEM; } - lu->tgt = tgt; - lu->sdev = NULL; - lu->lun = lun_entry & 0xffff; - lu->retries = 0; - lu->blocked = false; + lu->tgt = tgt; + lu->lun = lun_entry & 0xffff; + lu->retries = 0; + lu->has_sdev = false; + lu->blocked = false; ++tgt->dont_block; INIT_LIST_HEAD(&lu->orb_list); INIT_DELAYED_WORK(&lu->work, sbp2_login); @@ -1080,6 +1118,8 @@ static int sbp2_probe(struct device *dev) if (scsi_add_host(shost, &unit->device) < 0) goto fail_shost_put; + fw_device_get(device); + /* Initialize to values that won't match anything in our table. */ firmware_revision = 0xff000000; model = 0xff000000; diff --git a/drivers/firewire/fw-topology.c b/drivers/firewire/fw-topology.c index 172c1867e9a..d2c7a3d7e1c 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" @@ -383,6 +384,7 @@ void fw_destroy_nodes(struct fw_card *card) card->color++; if (card->local_node != NULL) for_each_fw_node(card, card->local_node, report_lost_node); + card->local_node = NULL; spin_unlock_irqrestore(&card->lock, flags); } @@ -423,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 7fcc59dedf0..e6f1bda3894 100644 --- a/drivers/firewire/fw-transaction.c +++ b/drivers/firewire/fw-transaction.c @@ -736,6 +736,12 @@ fw_core_handle_response(struct fw_card *card, struct fw_packet *p) break; } + /* + * The response handler may be executed while the request handler + * is still pending. Cancel the request handler. + */ + card->driver->cancel_packet(card, &t->packet); + t->callback(card, rcode, data, data_length, t->callback_data); } EXPORT_SYMBOL(fw_core_handle_response); @@ -751,7 +757,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 fa7967b5740..a43bb22912f 100644 --- a/drivers/firewire/fw-transaction.h +++ b/drivers/firewire/fw-transaction.h @@ -26,6 +26,7 @@ #include <linux/fs.h> #include <linux/dma-mapping.h> #include <linux/firewire-constants.h> +#include <asm/atomic.h> #define TCODE_IS_READ_REQUEST(tcode) (((tcode) & ~1) == 4) #define TCODE_IS_BLOCK_PACKET(tcode) (((tcode) & 1) != 0) @@ -85,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 @@ -219,6 +220,7 @@ extern struct bus_type fw_bus_type; struct fw_card { const struct fw_card_driver *driver; struct device *device; + atomic_t device_count; struct kref kref; int node_id; diff --git a/drivers/gpio/pca953x.c b/drivers/gpio/pca953x.c index 92583cd4bff..6e72fd31184 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 d73a768e176..f0b00ec1e47 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 5a38fb27d69..c3eb3f13e2c 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 b38e559b7a4..d95979f0e02 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 e6d05f6b1c1..e29a057cbea 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/hwmon/Kconfig b/drivers/hwmon/Kconfig index 368879ff5d8..4dc76bc45c9 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -337,8 +337,9 @@ config SENSORS_IBMPEX help If you say yes here you get support for the temperature and power sensors in various IBM System X servers that support - PowerExecutive. So far this includes the x3550, x3650, x3655, - x3755, and certain HS20 blades. + PowerExecutive. So far this includes the x3350, x3550, x3650, + x3655, and x3755; the x3800, x3850, and x3950 models that have + PCI Express; and some of the HS2x, LS2x, and QS2x blades. This driver can also be built as a module. If so, the module will be called ibmpex. diff --git a/drivers/hwmon/ibmpex.c b/drivers/hwmon/ibmpex.c index 9c9cdb0685e..4e9b19c6732 100644 --- a/drivers/hwmon/ibmpex.c +++ b/drivers/hwmon/ibmpex.c @@ -327,10 +327,14 @@ static int is_temp_sensor(const char *sensor_id, int len) return 0; } -static int power_sensor_multiplier(const char *sensor_id, int len) +static int power_sensor_multiplier(struct ibmpex_bmc_data *data, + const char *sensor_id, int len) { int i; + if (data->sensor_major == 2) + return 1000000; + for (i = PEX_SENSOR_TYPE_LEN; i < len - 1; i++) if (!memcmp(&sensor_id[i], watt_sensor_sig, PEX_MULT_LEN)) return 1000000; @@ -398,14 +402,15 @@ static int ibmpex_find_sensors(struct ibmpex_bmc_data *data) num_power++; sensor_counter = num_power; data->sensors[i].multiplier = - power_sensor_multiplier(data->rx_msg_data, - data->rx_msg_len); + power_sensor_multiplier(data, + data->rx_msg_data, + data->rx_msg_len); } else if (is_temp_sensor(data->rx_msg_data, data->rx_msg_len)) { sensor_type = TEMP_SENSOR; num_temp++; sensor_counter = num_temp; - data->sensors[i].multiplier = 1; + data->sensors[i].multiplier = 1000; } else continue; diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 476b0bb72d6..5fa9c3c67e0 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -100,7 +100,7 @@ config I2C_AU1550 config I2C_BLACKFIN_TWI tristate "Blackfin TWI I2C support" - depends on BF534 || BF536 || BF537 || BF54x + depends on BF534 || BF536 || BF537 help This is the TWI I2C device driver for Blackfin 534/536/537/54x. This driver can also be built as a module. If so, the module diff --git a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c index 573abe44084..2fa43183d37 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/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index da6639707ea..7ba31770d77 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -128,6 +128,8 @@ struct omap_i2c_dev { size_t buf_len; struct i2c_adapter adapter; unsigned rev1:1; + unsigned idle:1; + u16 iestate; /* Saved interrupt register */ }; static inline void omap_i2c_write_reg(struct omap_i2c_dev *i2c_dev, @@ -174,18 +176,30 @@ static void omap_i2c_put_clocks(struct omap_i2c_dev *dev) } } -static void omap_i2c_enable_clocks(struct omap_i2c_dev *dev) +static void omap_i2c_unidle(struct omap_i2c_dev *dev) { if (dev->iclk != NULL) clk_enable(dev->iclk); clk_enable(dev->fclk); + if (dev->iestate) + omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, dev->iestate); + dev->idle = 0; } -static void omap_i2c_disable_clocks(struct omap_i2c_dev *dev) +static void omap_i2c_idle(struct omap_i2c_dev *dev) { + u16 iv; + + dev->idle = 1; + dev->iestate = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG); + omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, 0); + if (dev->rev1) + iv = omap_i2c_read_reg(dev, OMAP_I2C_IV_REG); /* Read clears */ + else + omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, dev->iestate); + clk_disable(dev->fclk); if (dev->iclk != NULL) clk_disable(dev->iclk); - clk_disable(dev->fclk); } static int omap_i2c_init(struct omap_i2c_dev *dev) @@ -360,7 +374,7 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) int i; int r; - omap_i2c_enable_clocks(dev); + omap_i2c_unidle(dev); if ((r = omap_i2c_wait_for_bb(dev)) < 0) goto out; @@ -374,7 +388,7 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) if (r == 0) r = num; out: - omap_i2c_disable_clocks(dev); + omap_i2c_idle(dev); return r; } @@ -403,6 +417,9 @@ omap_i2c_rev1_isr(int this_irq, void *dev_id) struct omap_i2c_dev *dev = dev_id; u16 iv, w; + if (dev->idle) + return IRQ_NONE; + iv = omap_i2c_read_reg(dev, OMAP_I2C_IV_REG); switch (iv) { case 0x00: /* None */ @@ -457,6 +474,9 @@ omap_i2c_isr(int this_irq, void *dev_id) u16 stat, w; int count = 0; + if (dev->idle) + return IRQ_NONE; + bits = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG); while ((stat = (omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG))) & bits) { dev_dbg(dev->dev, "IRQ (ISR = 0x%04x)\n", stat); @@ -575,7 +595,7 @@ omap_i2c_probe(struct platform_device *pdev) if ((r = omap_i2c_get_clocks(dev)) != 0) goto err_free_mem; - omap_i2c_enable_clocks(dev); + omap_i2c_unidle(dev); if (cpu_is_omap15xx()) dev->rev1 = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) < 0x20; @@ -610,7 +630,7 @@ omap_i2c_probe(struct platform_device *pdev) goto err_free_irq; } - omap_i2c_disable_clocks(dev); + omap_i2c_idle(dev); return 0; @@ -618,7 +638,7 @@ err_free_irq: free_irq(dev->irq, dev); err_unuse_clocks: omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0); - omap_i2c_disable_clocks(dev); + omap_i2c_idle(dev); omap_i2c_put_clocks(dev); err_free_mem: platform_set_drvdata(pdev, NULL); diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile index 501f00cea78..e47aca0ca5a 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 96da22e9a5a..8b645c6b2cb 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) @@ -485,8 +489,8 @@ EXPORT_SYMBOL(i2c_add_adapter); * Context: can sleep * * This routine is used to declare an I2C adapter when its bus number - * matters. Example: for I2C adapters from system-on-chip CPUs, or - * otherwise built in to the system's mainboard, and where i2c_board_info + * matters. For example, use it for I2C adapters from system-on-chip CPUs, + * or otherwise built in to the system's mainboard, and where i2c_board_info * is used to properly configure I2C devices. * * If no devices have pre-been declared for this bus, then be sure to diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig index df752e690e4..eed6d8e1b5c 100644 --- a/drivers/ide/Kconfig +++ b/drivers/ide/Kconfig @@ -50,7 +50,7 @@ menuconfig IDE To compile this driver as a module, choose M here: the module will be called ide. - For further information, please read <file:Documentation/ide.txt>. + For further information, please read <file:Documentation/ide/ide.txt>. If unsure, say Y. @@ -77,7 +77,7 @@ config BLK_DEV_IDE Useful information about large (>540 MB) IDE disks, multiple interfaces, what to do if ATA/IDE devices are not automatically detected, sound card ATA/IDE ports, module support, and other - topics, is contained in <file:Documentation/ide.txt>. For detailed + topics, is contained in <file:Documentation/ide/ide.txt>. For detailed information about hard drives, consult the Disk-HOWTO and the Multi-Disk-HOWTO, available from <http://www.tldp.org/docs.html#howto>. @@ -87,7 +87,7 @@ config BLK_DEV_IDE <ftp://ibiblio.org/pub/Linux/system/hardware/>. To compile this driver as a module, choose M here and read - <file:Documentation/ide.txt>. The module will be called ide-mod. + <file:Documentation/ide/ide.txt>. The module will be called ide-mod. Do not compile this driver as a module if your root file system (the one containing the directory /) is located on an IDE device. @@ -98,7 +98,7 @@ config BLK_DEV_IDE if BLK_DEV_IDE -comment "Please see Documentation/ide.txt for help/info on IDE drives" +comment "Please see Documentation/ide/ide.txt for help/info on IDE drives" config BLK_DEV_IDE_SATA bool "Support for SATA (deprecated; conflicts with libata SATA driver)" @@ -235,8 +235,8 @@ config BLK_DEV_IDETAPE along with other IDE devices, as "hdb" or "hdc", or something similar, and will be mapped to a character device such as "ht0" (check the boot messages with dmesg). Be sure to consult the - <file:drivers/ide/ide-tape.c> and <file:Documentation/ide.txt> files - for usage information. + <file:drivers/ide/ide-tape.c> and <file:Documentation/ide/ide.txt> + files for usage information. To compile this driver as a module, choose M here: the module will be called ide-tape. @@ -358,7 +358,7 @@ config BLK_DEV_CMD640 The CMD640 chip is also used on add-in cards by Acculogic, and on the "CSA-6400E PCI to IDE controller" that some people have. For - details, read <file:Documentation/ide.txt>. + details, read <file:Documentation/ide/ide.txt>. config BLK_DEV_CMD640_ENHANCED bool "CMD640 enhanced support" @@ -366,7 +366,7 @@ config BLK_DEV_CMD640_ENHANCED help This option includes support for setting/autotuning PIO modes and prefetch on CMD640 IDE interfaces. For details, read - <file:Documentation/ide.txt>. If you have a CMD640 IDE interface + <file:Documentation/ide/ide.txt>. If you have a CMD640 IDE interface and your BIOS does not already do this for you, then say Y here. Otherwise say N. @@ -1069,9 +1069,9 @@ config BLK_DEV_ALI14XX This driver is enabled at runtime using the "ali14xx.probe" kernel boot parameter. It enables support for the secondary IDE interface of the ALI M1439/1443/1445/1487/1489 chipsets, and permits faster - I/O speeds to be set as well. See the files - <file:Documentation/ide.txt> and <file:drivers/ide/legacy/ali14xx.c> - for more info. + I/O speeds to be set as well. + See the files <file:Documentation/ide/ide.txt> and + <file:drivers/ide/legacy/ali14xx.c> for more info. config BLK_DEV_DTC2278 tristate "DTC-2278 support" @@ -1079,7 +1079,7 @@ config BLK_DEV_DTC2278 This driver is enabled at runtime using the "dtc2278.probe" kernel boot parameter. It enables support for the secondary IDE interface of the DTC-2278 card, and permits faster I/O speeds to be set as - well. See the <file:Documentation/ide.txt> and + well. See the <file:Documentation/ide/ide.txt> and <file:drivers/ide/legacy/dtc2278.c> files for more info. config BLK_DEV_HT6560B @@ -1088,7 +1088,7 @@ config BLK_DEV_HT6560B This driver is enabled at runtime using the "ht6560b.probe" kernel boot parameter. It enables support for the secondary IDE interface of the Holtek card, and permits faster I/O speeds to be set as well. - See the <file:Documentation/ide.txt> and + See the <file:Documentation/ide/ide.txt> and <file:drivers/ide/legacy/ht6560b.c> files for more info. config BLK_DEV_QD65XX @@ -1096,7 +1096,7 @@ config BLK_DEV_QD65XX help This driver is enabled at runtime using the "qd65xx.probe" kernel boot parameter. It permits faster I/O speeds to be set. See the - <file:Documentation/ide.txt> and <file:drivers/ide/legacy/qd65xx.c> + <file:Documentation/ide/ide.txt> and <file:drivers/ide/legacy/qd65xx.c> for more info. config BLK_DEV_UMC8672 @@ -1105,7 +1105,7 @@ config BLK_DEV_UMC8672 This driver is enabled at runtime using the "umc8672.probe" kernel boot parameter. It enables support for the secondary IDE interface of the UMC-8672, and permits faster I/O speeds to be set as well. - See the files <file:Documentation/ide.txt> and + See the files <file:Documentation/ide/ide.txt> and <file:drivers/ide/legacy/umc8672.c> for more info. endif diff --git a/drivers/ide/ide-cd_ioctl.c b/drivers/ide/ide-cd_ioctl.c index b68284de4e8..6d147ce6782 100644 --- a/drivers/ide/ide-cd_ioctl.c +++ b/drivers/ide/ide-cd_ioctl.c @@ -457,6 +457,10 @@ int ide_cdrom_packet(struct cdrom_device_info *cdi, layer. the packet must be complete, as we do not touch it at all. */ ide_cd_init_rq(drive, &req); + + if (cgc->data_direction == CGC_DATA_WRITE) + req.cmd_flags |= REQ_RW; + memcpy(req.cmd, cgc->cmd, CDROM_PACKET_SIZE); if (cgc->sense) memset(cgc->sense, 0, sizeof(struct request_sense)); diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c index 2de99e4be5c..d61e5788d31 100644 --- a/drivers/ide/ide-dma.c +++ b/drivers/ide/ide-dma.c @@ -713,7 +713,7 @@ static int ide_tune_dma(ide_drive_t *drive) } if (hwif->host_flags & IDE_HFLAG_NO_SET_MODE) - return 0; + return 1; if (ide_set_dma_mode(drive, speed)) return 0; diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c index 29e2c9719c3..7031a8dcf69 100644 --- a/drivers/ide/ide-lib.c +++ b/drivers/ide/ide-lib.c @@ -122,7 +122,6 @@ static struct ide_pio_info { const char *name; int pio; } ide_pio_blacklist [] = { -/* { "Conner Peripherals 1275MB - CFS1275A", 4 }, */ { "Conner Peripherals 540MB - CFS540A", 3 }, { "WDC AC2700", 3 }, @@ -138,10 +137,8 @@ static struct ide_pio_info { { "WDC AC1170", 1 }, { "WDC AC1210", 1 }, { "WDC AC280", 0 }, -/* { "WDC AC21000", 4 }, */ { "WDC AC31000", 3 }, { "WDC AC31200", 3 }, -/* { "WDC AC31600", 4 }, */ { "Maxtor 7131 AT", 1 }, { "Maxtor 7171 AT", 1 }, @@ -155,13 +152,6 @@ static struct ide_pio_info { { "SAMSUNG SHD-3122A", 1 }, { "SAMSUNG SHD-3172A", 1 }, -/* { "ST51080A", 4 }, - * { "ST51270A", 4 }, - * { "ST31220A", 4 }, - * { "ST31640A", 4 }, - * { "ST32140A", 4 }, - * { "ST3780A", 4 }, - */ { "ST5660A", 3 }, { "ST3660A", 3 }, { "ST3630A", 3 }, diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index 43e0e055777..0598ecfd5f3 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -3765,11 +3765,6 @@ static int ide_tape_probe(ide_drive_t *drive) g->fops = &idetape_block_ops; ide_register_region(g); - printk(KERN_WARNING "It is possible that this driver does not have any" - " users anymore and, as a result, it will be REMOVED soon." - " Please notify Bart <bzolnier@gmail.com> or Boris" - " <petkovbb@gmail.com> in case you still need it.\n"); - return 0; out_free_tape: diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c index 0518a2e948c..4c86a8d84b4 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/ide/ide.c b/drivers/ide/ide.c index fa16bc30bbc..fc69fe2e3ec 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -667,7 +667,6 @@ int ide_register_hw(hw_regs_t *hw, void (*quirkproc)(ide_drive_t *), do { hwif = ide_deprecated_find_port(hw->io_ports[IDE_DATA_OFFSET]); - index = hwif->index; if (hwif) goto found; for (index = 0; index < MAX_HWIFS; index++) @@ -675,6 +674,7 @@ int ide_register_hw(hw_regs_t *hw, void (*quirkproc)(ide_drive_t *), } while (retry--); return -1; found: + index = hwif->index; if (hwif->present) ide_unregister(index, 0, 1); else if (!hwif->hold) @@ -1180,7 +1180,7 @@ static int __initdata is_chipset_set[MAX_HWIFS]; * ide_setup() gets called VERY EARLY during initialization, * to handle kernel "command line" strings beginning with "hdx=" or "ide". * - * Remember to update Documentation/ide.txt if you change something here. + * Remember to update Documentation/ide/ide.txt if you change something here. */ static int __init ide_setup(char *s) { @@ -1258,7 +1258,7 @@ static int __init ide_setup(char *s) drive = &hwif->drives[unit]; if (strncmp(s + 4, "ide-", 4) == 0) { strlcpy(drive->driver_req, s + 4, sizeof(drive->driver_req)); - goto done; + goto obsolete_option; } switch (match_parm(&s[3], hd_words, vals, 3)) { case -1: /* "none" */ @@ -1290,13 +1290,13 @@ static int __init ide_setup(char *s) goto done; case -12: /* "remap" */ drive->remap_0_to_1 = 1; - goto done; + goto obsolete_option; case -13: /* "remap63" */ drive->sect0 = 63; - goto done; + goto obsolete_option; case -14: /* "scsi" */ drive->scsi = 1; - goto done; + goto obsolete_option; case 3: /* cyl,head,sect */ drive->media = ide_disk; drive->ready_stat = READY_STAT; @@ -1370,32 +1370,32 @@ static int __init ide_setup(char *s) #ifdef CONFIG_BLK_DEV_ALI14XX case -17: /* "ali14xx" */ probe_ali14xx = 1; - goto done; + goto obsolete_option; #endif #ifdef CONFIG_BLK_DEV_UMC8672 case -16: /* "umc8672" */ probe_umc8672 = 1; - goto done; + goto obsolete_option; #endif #ifdef CONFIG_BLK_DEV_DTC2278 case -15: /* "dtc2278" */ probe_dtc2278 = 1; - goto done; + goto obsolete_option; #endif #ifdef CONFIG_BLK_DEV_CMD640 case -14: /* "cmd640_vlb" */ cmd640_vlb = 1; - goto done; + goto obsolete_option; #endif #ifdef CONFIG_BLK_DEV_HT6560B case -13: /* "ht6560b" */ probe_ht6560b = 1; - goto done; + goto obsolete_option; #endif #ifdef CONFIG_BLK_DEV_QD65XX case -12: /* "qd65xx" */ probe_qd65xx = 1; - goto done; + goto obsolete_option; #endif #ifdef CONFIG_BLK_DEV_4DRIVES case -11: /* "four" drives on one set of ports */ diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c index 9e2b1964d71..f53f72daae3 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 b10ade92efe..4df40515708 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 7f00347364f..06d502c06a4 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 223b1aa7d92..81c9195b512 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 df1838f8f94..b2ea9210467 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 41462109554..591901aab6b 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 d5ff6ca2db3..ca4d0acc678 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 4cc0f95ea87..ecf3f7ff771 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 d98d5f10370..b34b91d3723 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 80dc623cee4..087ed316647 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 459e46e2c01..40f3e37d7ad 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 6d2a17f9c1d..92ad73a7fff 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/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c index 39adb267fb1..0bef878e0f6 100644 --- a/drivers/infiniband/hw/nes/nes_cm.c +++ b/drivers/infiniband/hw/nes/nes_cm.c @@ -40,6 +40,7 @@ #include <linux/tcp.h> #include <linux/init.h> #include <linux/if_arp.h> +#include <linux/if_vlan.h> #include <linux/notifier.h> #include <linux/net.h> #include <linux/types.h> @@ -1072,7 +1073,7 @@ static struct nes_cm_node *make_cm_node(struct nes_cm_core *cm_core, ts = current_kernel_time(); cm_node->tcp_cntxt.loc_seq_num = htonl(ts.tv_nsec); cm_node->tcp_cntxt.mss = nesvnic->max_frame_size - sizeof(struct iphdr) - - sizeof(struct tcphdr) - ETH_HLEN; + sizeof(struct tcphdr) - ETH_HLEN - VLAN_HLEN; cm_node->tcp_cntxt.rcv_nxt = 0; /* get a unique session ID , add thread_id to an upcounter to handle race */ atomic_inc(&cm_core->node_cnt); diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c index 52b1bebfa74..2490b2d79db 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 f96477a8ca5..57282048865 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 2628339e3a9..31a53c5bcb1 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 714b8db02b2..993f0a8ff28 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/Kconfig b/drivers/input/misc/Kconfig index 8b10d9f23be..c5263d63aca 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -42,14 +42,14 @@ config INPUT_M68K_BEEP config INPUT_APANEL tristate "Fujitsu Lifebook Application Panel buttons" - depends on X86 - select I2C_I801 + depends on X86 && I2C && LEDS_CLASS select INPUT_POLLDEV select CHECK_SIGNATURE help Say Y here for support of the Application Panel buttons, used on Fujitsu Lifebook. These are attached to the mainboard through - an SMBus interface managed by the I2C Intel ICH (i801) driver. + an SMBus interface managed by the I2C Intel ICH (i801) driver, + which you should also build for this kernel. To compile this driver as a module, choose M here: the module will be called apanel. diff --git a/drivers/input/misc/cobalt_btns.c b/drivers/input/misc/cobalt_btns.c index 4833b1a8262..5511ef006a6 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 b346a3b418e..385e32bcf6a 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 00000000000..409a9341143 --- /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 662e84482c2..60931aceb82 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 2763394869d..65a74cfc187 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 dd22d91f8b3..cbc1beb6657 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 6542edb6f76..acf9830698c 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 d64b1ea136b..41caaef8e2d 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 fc03ba256f4..ffe33842143 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 a302e229bb8..3342bc05847 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 58934a40f5c..57a1c28bf12 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/gigaset/common.c b/drivers/isdn/gigaset/common.c index aacedec4986..827c32c1679 100644 --- a/drivers/isdn/gigaset/common.c +++ b/drivers/isdn/gigaset/common.c @@ -637,7 +637,6 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels, err("maximum number of devices exceeded"); return NULL; } - mutex_init(&cs->mutex); gig_dbg(DEBUG_INIT, "allocating bcs[0..%d]", channels - 1); cs->bcs = kmalloc(channels * sizeof(struct bc_state), GFP_KERNEL); @@ -898,8 +897,10 @@ int gigaset_shutdown(struct cardstate *cs) { mutex_lock(&cs->mutex); - if (!(cs->flags & VALID_MINOR)) + if (!(cs->flags & VALID_MINOR)) { + mutex_unlock(&cs->mutex); return -1; + } cs->waiting = 1; @@ -1086,6 +1087,7 @@ struct gigaset_driver *gigaset_initdriver(unsigned minor, unsigned minors, drv->cs[i].driver = drv; drv->cs[i].ops = drv->ops; drv->cs[i].minor_index = i; + mutex_init(&drv->cs[i].mutex); } gigaset_if_initdriver(drv, procname, devname); diff --git a/drivers/isdn/hisax/hisax_fcpcipnp.c b/drivers/isdn/hisax/hisax_fcpcipnp.c index 7993e01f9fc..76043dedba5 100644 --- a/drivers/isdn/hisax/hisax_fcpcipnp.c +++ b/drivers/isdn/hisax/hisax_fcpcipnp.c @@ -725,23 +725,6 @@ static int __devinit fcpcipnp_setup(struct fritz_adapter *adapter) switch (adapter->type) { case AVM_FRITZ_PCIV2: - retval = request_irq(adapter->irq, fcpci2_irq, IRQF_SHARED, - "fcpcipnp", adapter); - break; - case AVM_FRITZ_PCI: - retval = request_irq(adapter->irq, fcpci_irq, IRQF_SHARED, - "fcpcipnp", adapter); - break; - case AVM_FRITZ_PNP: - retval = request_irq(adapter->irq, fcpci_irq, 0, - "fcpcipnp", adapter); - break; - } - if (retval) - goto err_region; - - switch (adapter->type) { - case AVM_FRITZ_PCIV2: case AVM_FRITZ_PCI: val = inl(adapter->io); break; @@ -796,6 +779,23 @@ static int __devinit fcpcipnp_setup(struct fritz_adapter *adapter) switch (adapter->type) { case AVM_FRITZ_PCIV2: + retval = request_irq(adapter->irq, fcpci2_irq, IRQF_SHARED, + "fcpcipnp", adapter); + break; + case AVM_FRITZ_PCI: + retval = request_irq(adapter->irq, fcpci_irq, IRQF_SHARED, + "fcpcipnp", adapter); + break; + case AVM_FRITZ_PNP: + retval = request_irq(adapter->irq, fcpci_irq, 0, + "fcpcipnp", adapter); + break; + } + if (retval) + goto err_region; + + switch (adapter->type) { + case AVM_FRITZ_PCIV2: fcpci2_init(adapter); isacsx_setup(&adapter->isac); break; diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c index 9cef6fcf587..d4ad6992f77 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_ttyfax.c b/drivers/isdn/i4l/isdn_ttyfax.c index f93de4a3035..78f7660c1d0 100644 --- a/drivers/isdn/i4l/isdn_ttyfax.c +++ b/drivers/isdn/i4l/isdn_ttyfax.c @@ -906,7 +906,8 @@ isdn_tty_cmd_FCLASS2(char **p, modem_info * info) sprintf(rs, "\r\n0-2"); isdn_tty_at_cout(rs, info); } else { - if ((f->phase != ISDN_FAX_PHASE_D) || (!info->faxonline & 1)) + if ((f->phase != ISDN_FAX_PHASE_D) || + (!(info->faxonline & 1))) PARSE_ERROR1; par = isdn_getnum(p); if ((par < 0) || (par > 2)) diff --git a/drivers/isdn/i4l/isdn_v110.c b/drivers/isdn/i4l/isdn_v110.c index 5484d3c38a5..c5d02b6aafa 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/isdn/isdnloop/isdnloop.c b/drivers/isdn/isdnloop/isdnloop.c index 655ef9a3f4d..a335c85a736 100644 --- a/drivers/isdn/isdnloop/isdnloop.c +++ b/drivers/isdn/isdnloop/isdnloop.c @@ -1289,7 +1289,7 @@ isdnloop_command(isdn_ctrl * c, isdnloop_card * card) } break; case ISDN_CMD_CLREAZ: - if (!card->flags & ISDNLOOP_FLAGS_RUNNING) + if (!(card->flags & ISDNLOOP_FLAGS_RUNNING)) return -ENODEV; if (card->leased) break; @@ -1333,7 +1333,7 @@ isdnloop_command(isdn_ctrl * c, isdnloop_card * card) } break; case ISDN_CMD_SETL3: - if (!card->flags & ISDNLOOP_FLAGS_RUNNING) + if (!(card->flags & ISDNLOOP_FLAGS_RUNNING)) return -ENODEV; return 0; default: @@ -1380,7 +1380,7 @@ if_writecmd(const u_char __user *buf, int len, int id, int channel) isdnloop_card *card = isdnloop_findcard(id); if (card) { - if (!card->flags & ISDNLOOP_FLAGS_RUNNING) + if (!(card->flags & ISDNLOOP_FLAGS_RUNNING)) return -ENODEV; return (isdnloop_writecmd(buf, len, 1, card)); } diff --git a/drivers/lguest/core.c b/drivers/lguest/core.c index 7743d73768d..c632c08cbbd 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 85d42d3d01a..2221485b077 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 275f23c2deb..a7f64a9d67e 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 741a2e3f4fc..a348bb0791d 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 ebec663d5d3..d6365a9f063 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 7aeceedcf7d..c14dacdacfa 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -1045,8 +1045,14 @@ 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; + return; + } + bitmap->allclean = 1; for (j = 0; j < bitmap->chunks; j++) { bitmap_counter_t *bmc; @@ -1068,8 +1074,10 @@ void bitmap_daemon_work(struct bitmap *bitmap) clear_page_attr(bitmap, page, BITMAP_PAGE_NEEDWRITE); spin_unlock_irqrestore(&bitmap->lock, flags); - if (need_write) + if (need_write) { write_page(bitmap, page, 0); + bitmap->allclean = 0; + } continue; } @@ -1098,6 +1106,9 @@ void bitmap_daemon_work(struct bitmap *bitmap) /* if (j < 100) printk("bitmap: j=%lu, *bmc = 0x%x\n", j, *bmc); */ + if (*bmc) + bitmap->allclean = 0; + if (*bmc == 2) { *bmc=1; /* maybe clear the bit next time */ set_page_attr(bitmap, page, BITMAP_PAGE_CLEAN); @@ -1132,6 +1143,9 @@ void bitmap_daemon_work(struct bitmap *bitmap) } } + done: + if (bitmap->allclean == 0) + bitmap->mddev->thread->timeout = bitmap->daemon_sleep * HZ; } static bitmap_counter_t *bitmap_get_counter(struct bitmap *bitmap, @@ -1226,6 +1240,7 @@ int bitmap_startwrite(struct bitmap *bitmap, sector_t offset, unsigned long sect sectors -= blocks; else sectors = 0; } + bitmap->allclean = 0; return 0; } @@ -1296,6 +1311,7 @@ int bitmap_start_sync(struct bitmap *bitmap, sector_t offset, int *blocks, } } spin_unlock_irq(&bitmap->lock); + bitmap->allclean = 0; return rv; } @@ -1332,6 +1348,7 @@ void bitmap_end_sync(struct bitmap *bitmap, sector_t offset, int *blocks, int ab } unlock: spin_unlock_irqrestore(&bitmap->lock, flags); + bitmap->allclean = 0; } void bitmap_close_sync(struct bitmap *bitmap) @@ -1399,7 +1416,7 @@ static void bitmap_set_memory_bits(struct bitmap *bitmap, sector_t offset, int n set_page_attr(bitmap, page, BITMAP_PAGE_CLEAN); } spin_unlock_irq(&bitmap->lock); - + bitmap->allclean = 0; } /* dirty the memory and file bits for bitmap chunks "s" to "e" */ diff --git a/drivers/md/md.c b/drivers/md/md.c index 7da6ec244e1..61ccbd2683f 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -1105,7 +1105,11 @@ static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version) rdev->sb_size = le32_to_cpu(sb->max_dev) * 2 + 256; bmask = queue_hardsect_size(rdev->bdev->bd_disk->queue)-1; if (rdev->sb_size & bmask) - rdev-> sb_size = (rdev->sb_size | bmask)+1; + rdev->sb_size = (rdev->sb_size | bmask) + 1; + + if (minor_version + && rdev->data_offset < sb_offset + (rdev->sb_size/512)) + return -EINVAL; if (sb->level == cpu_to_le32(LEVEL_MULTIPATH)) rdev->desc_nr = -1; @@ -1137,7 +1141,7 @@ static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version) else ret = 0; } - if (minor_version) + if (minor_version) rdev->size = ((rdev->bdev->bd_inode->i_size>>9) - le64_to_cpu(sb->data_offset)) / 2; else rdev->size = rdev->sb_offset; @@ -1499,7 +1503,8 @@ static void export_rdev(mdk_rdev_t * rdev) free_disk_sb(rdev); list_del_init(&rdev->same_set); #ifndef MODULE - md_autodetect_dev(rdev->bdev->bd_dev); + if (test_bit(AutoDetected, &rdev->flags)) + md_autodetect_dev(rdev->bdev->bd_dev); #endif unlock_rdev(rdev); kobject_put(&rdev->kobj); @@ -1859,17 +1864,6 @@ static struct rdev_sysfs_entry rdev_state = __ATTR(state, S_IRUGO|S_IWUSR, state_show, state_store); static ssize_t -super_show(mdk_rdev_t *rdev, char *page) -{ - if (rdev->sb_loaded && rdev->sb_size) { - memcpy(page, page_address(rdev->sb_page), rdev->sb_size); - return rdev->sb_size; - } else - return 0; -} -static struct rdev_sysfs_entry rdev_super = __ATTR_RO(super); - -static ssize_t errors_show(mdk_rdev_t *rdev, char *page) { return sprintf(page, "%d\n", atomic_read(&rdev->corrected_errors)); @@ -1996,9 +1990,11 @@ rdev_size_store(mdk_rdev_t *rdev, const char *buf, size_t len) char *e; unsigned long long size = simple_strtoull(buf, &e, 10); unsigned long long oldsize = rdev->size; + mddev_t *my_mddev = rdev->mddev; + if (e==buf || (*e && *e != '\n')) return -EINVAL; - if (rdev->mddev->pers) + if (my_mddev->pers) return -EBUSY; rdev->size = size; if (size > oldsize && rdev->mddev->external) { @@ -2011,7 +2007,7 @@ rdev_size_store(mdk_rdev_t *rdev, const char *buf, size_t len) int overlap = 0; struct list_head *tmp, *tmp2; - mddev_unlock(rdev->mddev); + mddev_unlock(my_mddev); for_each_mddev(mddev, tmp) { mdk_rdev_t *rdev2; @@ -2031,7 +2027,7 @@ rdev_size_store(mdk_rdev_t *rdev, const char *buf, size_t len) break; } } - mddev_lock(rdev->mddev); + mddev_lock(my_mddev); if (overlap) { /* Someone else could have slipped in a size * change here, but doing so is just silly. @@ -2043,8 +2039,8 @@ rdev_size_store(mdk_rdev_t *rdev, const char *buf, size_t len) return -EBUSY; } } - if (size < rdev->mddev->size || rdev->mddev->size == 0) - rdev->mddev->size = size; + if (size < my_mddev->size || my_mddev->size == 0) + my_mddev->size = size; return len; } @@ -2053,7 +2049,6 @@ __ATTR(size, S_IRUGO|S_IWUSR, rdev_size_show, rdev_size_store); static struct attribute *rdev_default_attrs[] = { &rdev_state.attr, - &rdev_super.attr, &rdev_errors.attr, &rdev_slot.attr, &rdev_offset.attr, @@ -2065,10 +2060,21 @@ rdev_attr_show(struct kobject *kobj, struct attribute *attr, char *page) { struct rdev_sysfs_entry *entry = container_of(attr, struct rdev_sysfs_entry, attr); mdk_rdev_t *rdev = container_of(kobj, mdk_rdev_t, kobj); + mddev_t *mddev = rdev->mddev; + ssize_t rv; if (!entry->show) return -EIO; - return entry->show(rdev, page); + + rv = mddev ? mddev_lock(mddev) : -EBUSY; + if (!rv) { + if (rdev->mddev == NULL) + rv = -EBUSY; + else + rv = entry->show(rdev, page); + mddev_unlock(mddev); + } + return rv; } static ssize_t @@ -2077,15 +2083,19 @@ rdev_attr_store(struct kobject *kobj, struct attribute *attr, { struct rdev_sysfs_entry *entry = container_of(attr, struct rdev_sysfs_entry, attr); mdk_rdev_t *rdev = container_of(kobj, mdk_rdev_t, kobj); - int rv; + ssize_t rv; + mddev_t *mddev = rdev->mddev; if (!entry->store) return -EIO; if (!capable(CAP_SYS_ADMIN)) return -EACCES; - rv = mddev_lock(rdev->mddev); + rv = mddev ? mddev_lock(mddev): -EBUSY; if (!rv) { - rv = entry->store(rdev, page, length); + if (rdev->mddev == NULL) + rv = -EBUSY; + else + rv = entry->store(rdev, page, length); mddev_unlock(rdev->mddev); } return rv; @@ -5127,7 +5137,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); } @@ -5351,6 +5361,7 @@ void md_write_start(mddev_t *mddev, struct bio *bi) mddev->ro = 0; set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); md_wakeup_thread(mddev->thread); + md_wakeup_thread(mddev->sync_thread); } atomic_inc(&mddev->writes_pending); if (mddev->in_sync) { @@ -6021,6 +6032,7 @@ static void autostart_arrays(int part) MD_BUG(); continue; } + set_bit(AutoDetected, &rdev->flags); list_add(&rdev->same_set, &pending_raid_disks); i_passed++; } diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 5c7fef091ce..ff61b309129 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -592,6 +592,37 @@ static int raid1_congested(void *data, int bits) } +static int flush_pending_writes(conf_t *conf) +{ + /* Any writes that have been queued but are awaiting + * bitmap updates get flushed here. + * We return 1 if any requests were actually submitted. + */ + int rv = 0; + + spin_lock_irq(&conf->device_lock); + + if (conf->pending_bio_list.head) { + struct bio *bio; + bio = bio_list_get(&conf->pending_bio_list); + blk_remove_plug(conf->mddev->queue); + spin_unlock_irq(&conf->device_lock); + /* flush any pending bitmap writes to + * disk before proceeding w/ I/O */ + bitmap_unplug(conf->mddev->bitmap); + + while (bio) { /* submit pending writes */ + struct bio *next = bio->bi_next; + bio->bi_next = NULL; + generic_make_request(bio); + bio = next; + } + rv = 1; + } else + spin_unlock_irq(&conf->device_lock); + return rv; +} + /* Barriers.... * Sometimes we need to suspend IO while we do something else, * either some resync/recovery, or reconfigure the array. @@ -673,15 +704,23 @@ static void freeze_array(conf_t *conf) /* stop syncio and normal IO and wait for everything to * go quite. * We increment barrier and nr_waiting, and then - * wait until barrier+nr_pending match nr_queued+2 + * wait until nr_pending match nr_queued+1 + * This is called in the context of one normal IO request + * that has failed. Thus any sync request that might be pending + * will be blocked by nr_pending, and we need to wait for + * pending IO requests to complete or be queued for re-try. + * Thus the number queued (nr_queued) plus this request (1) + * must match the number of pending IOs (nr_pending) before + * we continue. */ spin_lock_irq(&conf->resync_lock); conf->barrier++; conf->nr_waiting++; wait_event_lock_irq(conf->wait_barrier, - conf->barrier+conf->nr_pending == conf->nr_queued+2, + conf->nr_pending == conf->nr_queued+1, conf->resync_lock, - raid1_unplug(conf->mddev->queue)); + ({ flush_pending_writes(conf); + raid1_unplug(conf->mddev->queue); })); spin_unlock_irq(&conf->resync_lock); } static void unfreeze_array(conf_t *conf) @@ -907,6 +946,9 @@ static int make_request(struct request_queue *q, struct bio * bio) blk_plug_device(mddev->queue); spin_unlock_irqrestore(&conf->device_lock, flags); + /* In case raid1d snuck into freeze_array */ + wake_up(&conf->wait_barrier); + if (do_sync) md_wakeup_thread(mddev->thread); #if 0 @@ -1473,28 +1515,14 @@ static void raid1d(mddev_t *mddev) for (;;) { char b[BDEVNAME_SIZE]; - spin_lock_irqsave(&conf->device_lock, flags); - - if (conf->pending_bio_list.head) { - bio = bio_list_get(&conf->pending_bio_list); - blk_remove_plug(mddev->queue); - spin_unlock_irqrestore(&conf->device_lock, flags); - /* flush any pending bitmap writes to disk before proceeding w/ I/O */ - bitmap_unplug(mddev->bitmap); - while (bio) { /* submit pending writes */ - struct bio *next = bio->bi_next; - bio->bi_next = NULL; - generic_make_request(bio); - bio = next; - } - unplug = 1; + unplug += flush_pending_writes(conf); - continue; - } - - if (list_empty(head)) + spin_lock_irqsave(&conf->device_lock, flags); + if (list_empty(head)) { + spin_unlock_irqrestore(&conf->device_lock, flags); break; + } r1_bio = list_entry(head->prev, r1bio_t, retry_list); list_del(head->prev); conf->nr_queued--; @@ -1590,7 +1618,6 @@ static void raid1d(mddev_t *mddev) } } } - spin_unlock_irqrestore(&conf->device_lock, flags); if (unplug) unplug_slaves(mddev); } diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 017f58113c3..32389d2f18f 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -537,7 +537,8 @@ static int read_balance(conf_t *conf, r10bio_t *r10_bio) current_distance = abs(r10_bio->devs[slot].addr - conf->mirrors[disk].head_position); - /* Find the disk whose head is closest */ + /* Find the disk whose head is closest, + * or - for far > 1 - find the closest to partition beginning */ for (nslot = slot; nslot < conf->copies; nslot++) { int ndisk = r10_bio->devs[nslot].devnum; @@ -557,8 +558,13 @@ static int read_balance(conf_t *conf, r10bio_t *r10_bio) slot = nslot; break; } - new_distance = abs(r10_bio->devs[nslot].addr - - conf->mirrors[ndisk].head_position); + + /* for far > 1 always use the lowest address */ + if (conf->far_copies > 1) + new_distance = r10_bio->devs[nslot].addr; + else + new_distance = abs(r10_bio->devs[nslot].addr - + conf->mirrors[ndisk].head_position); if (new_distance < current_distance) { current_distance = new_distance; disk = ndisk; @@ -629,7 +635,36 @@ static int raid10_congested(void *data, int bits) return ret; } - +static int flush_pending_writes(conf_t *conf) +{ + /* Any writes that have been queued but are awaiting + * bitmap updates get flushed here. + * We return 1 if any requests were actually submitted. + */ + int rv = 0; + + spin_lock_irq(&conf->device_lock); + + if (conf->pending_bio_list.head) { + struct bio *bio; + bio = bio_list_get(&conf->pending_bio_list); + blk_remove_plug(conf->mddev->queue); + spin_unlock_irq(&conf->device_lock); + /* flush any pending bitmap writes to disk + * before proceeding w/ I/O */ + bitmap_unplug(conf->mddev->bitmap); + + while (bio) { /* submit pending writes */ + struct bio *next = bio->bi_next; + bio->bi_next = NULL; + generic_make_request(bio); + bio = next; + } + rv = 1; + } else + spin_unlock_irq(&conf->device_lock); + return rv; +} /* Barriers.... * Sometimes we need to suspend IO while we do something else, * either some resync/recovery, or reconfigure the array. @@ -712,15 +747,23 @@ static void freeze_array(conf_t *conf) /* stop syncio and normal IO and wait for everything to * go quiet. * We increment barrier and nr_waiting, and then - * wait until barrier+nr_pending match nr_queued+2 + * wait until nr_pending match nr_queued+1 + * This is called in the context of one normal IO request + * that has failed. Thus any sync request that might be pending + * will be blocked by nr_pending, and we need to wait for + * pending IO requests to complete or be queued for re-try. + * Thus the number queued (nr_queued) plus this request (1) + * must match the number of pending IOs (nr_pending) before + * we continue. */ spin_lock_irq(&conf->resync_lock); conf->barrier++; conf->nr_waiting++; wait_event_lock_irq(conf->wait_barrier, - conf->barrier+conf->nr_pending == conf->nr_queued+2, + conf->nr_pending == conf->nr_queued+1, conf->resync_lock, - raid10_unplug(conf->mddev->queue)); + ({ flush_pending_writes(conf); + raid10_unplug(conf->mddev->queue); })); spin_unlock_irq(&conf->resync_lock); } @@ -892,6 +935,9 @@ static int make_request(struct request_queue *q, struct bio * bio) blk_plug_device(mddev->queue); spin_unlock_irqrestore(&conf->device_lock, flags); + /* In case raid10d snuck in to freeze_array */ + wake_up(&conf->wait_barrier); + if (do_sync) md_wakeup_thread(mddev->thread); @@ -1464,28 +1510,14 @@ static void raid10d(mddev_t *mddev) for (;;) { char b[BDEVNAME_SIZE]; - spin_lock_irqsave(&conf->device_lock, flags); - if (conf->pending_bio_list.head) { - bio = bio_list_get(&conf->pending_bio_list); - blk_remove_plug(mddev->queue); - spin_unlock_irqrestore(&conf->device_lock, flags); - /* flush any pending bitmap writes to disk before proceeding w/ I/O */ - bitmap_unplug(mddev->bitmap); - - while (bio) { /* submit pending writes */ - struct bio *next = bio->bi_next; - bio->bi_next = NULL; - generic_make_request(bio); - bio = next; - } - unplug = 1; - - continue; - } + unplug += flush_pending_writes(conf); - if (list_empty(head)) + spin_lock_irqsave(&conf->device_lock, flags); + if (list_empty(head)) { + spin_unlock_irqrestore(&conf->device_lock, flags); break; + } r10_bio = list_entry(head->prev, r10bio_t, retry_list); list_del(head->prev); conf->nr_queued--; @@ -1548,7 +1580,6 @@ static void raid10d(mddev_t *mddev) } } } - spin_unlock_irqrestore(&conf->device_lock, flags); if (unplug) unplug_slaves(mddev); } @@ -1787,6 +1818,8 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i if (j == conf->copies) { /* Cannot recover, so abort the recovery */ put_buf(r10_bio); + if (rb2) + atomic_dec(&rb2->remaining); r10_bio = rb2; if (!test_and_set_bit(MD_RECOVERY_ERR, &mddev->recovery)) printk(KERN_INFO "raid10: %s: insufficient working devices for recovery.\n", diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 2d6f1a51359..c574cf5efb5 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -1143,7 +1143,7 @@ static void raid5_end_read_request(struct bio * bi, int error) rdev = conf->disks[i].rdev; printk(KERN_INFO "raid5:%s: read error corrected (%lu sectors at %llu on %s)\n", mdname(conf->mddev), STRIPE_SECTORS, - (unsigned long long)sh->sector + rdev->data_offset, + (unsigned long long)(sh->sector + rdev->data_offset), bdevname(rdev->bdev, b)); clear_bit(R5_ReadError, &sh->dev[i].flags); clear_bit(R5_ReWrite, &sh->dev[i].flags); @@ -1160,13 +1160,13 @@ static void raid5_end_read_request(struct bio * bi, int error) if (conf->mddev->degraded) printk(KERN_WARNING "raid5:%s: read error not correctable (sector %llu on %s).\n", mdname(conf->mddev), - (unsigned long long)sh->sector + rdev->data_offset, + (unsigned long long)(sh->sector + rdev->data_offset), bdn); else if (test_bit(R5_ReWrite, &sh->dev[i].flags)) /* Oh, no!!! */ printk(KERN_WARNING "raid5:%s: read error NOT corrected!! (sector %llu on %s).\n", mdname(conf->mddev), - (unsigned long long)sh->sector + rdev->data_offset, + (unsigned long long)(sh->sector + rdev->data_offset), bdn); else if (atomic_read(&rdev->read_errors) > conf->max_nr_stripes) diff --git a/drivers/media/dvb/dvb-usb/opera1.c b/drivers/media/dvb/dvb-usb/opera1.c index 21935bf7059..302cc67407c 100644 --- a/drivers/media/dvb/dvb-usb/opera1.c +++ b/drivers/media/dvb/dvb-usb/opera1.c @@ -478,9 +478,9 @@ static int opera1_xilinx_load_firmware(struct usb_device *dev, err("could not restart the USB controller CPU."); ret = -EINVAL; } - kfree(p); } } + kfree(p); if (fw) { release_firmware(fw); } diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 37072a21d8c..1832966f53f 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -305,7 +305,7 @@ comment "MPEG video encoders" config VIDEO_CX2341X tristate "Conexant CX2341x MPEG encoders" - depends on VIDEO_V4L2 && EXPERIMENTAL + depends on VIDEO_V4L2 && EXPERIMENTAL && VIDEO_V4L2_COMMON ---help--- Support for the Conexant CX23416 MPEG encoders and CX23415 MPEG encoder/decoders. @@ -382,7 +382,7 @@ endmenu # encoder / decoder chips config VIDEO_VIVI tristate "Virtual Video Driver" - depends on VIDEO_V4L2 && !SPARC32 && !SPARC64 + depends on VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64 select VIDEOBUF_VMALLOC default n ---help--- diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index 5404fcc5276..a080c149cc6 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -3389,7 +3389,6 @@ static struct video_device bttv_video_template = .vidiocgmbuf = vidiocgmbuf, #endif .vidioc_g_crop = bttv_g_crop, - .vidioc_g_crop = bttv_g_crop, .vidioc_s_crop = bttv_s_crop, .vidioc_g_fbuf = bttv_g_fbuf, .vidioc_s_fbuf = bttv_s_fbuf, diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index e6b7f518c56..8c9a8adf52d 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -2196,6 +2196,11 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr) cx88_reset(core); cx88_card_setup_pre_i2c(core); cx88_i2c_init(core, pci); + + /* load tuner module, if needed */ + if (TUNER_ABSENT != core->board.tuner_type) + request_module("tuner"); + cx88_call_i2c_clients (core, TUNER_SET_STANDBY, NULL); cx88_card_setup(core); cx88_ir_init(core, pci); diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index 7f1931aed20..227179620d1 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -1826,8 +1826,6 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, cx_set(MO_PCI_INTMSK, core->pci_irqmask); /* load and configure helper modules */ - if (TUNER_ABSENT != core->board.tuner_type) - request_module("tuner"); if (core->board.audio_chip == AUDIO_CHIP_WM8775) request_module("wm8775"); diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c index 7d1537cab86..c1caaa855b9 100644 --- a/drivers/media/video/em28xx/em28xx-core.c +++ b/drivers/media/video/em28xx/em28xx-core.c @@ -267,7 +267,7 @@ static int em28xx_write_ac97(struct em28xx *dev, u8 reg, u8 *val) for (i = 0; i < 10; i++) { if ((ret = em28xx_read_reg(dev, AC97BUSY_REG)) < 0) return ret; - if (!((u8) ret) & 0x01) + if (!(ret & 0x01)) return 0; msleep(5); } diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index d42f120354e..948ca35e7ee 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -54,7 +54,6 @@ #include "ivtv-vbi.h" #include "ivtv-routing.h" #include "ivtv-gpio.h" -#include "ivtv-yuv.h" #include <media/tveeprom.h> #include <media/saa7115.h> @@ -700,6 +699,9 @@ static int __devinit ivtv_init_struct1(struct ivtv *itv) itv->vbi.in.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE; itv->vbi.sliced_in = &itv->vbi.in.fmt.sliced; + /* Init the sg table for osd/yuv output */ + sg_init_table(itv->udma.SGlist, IVTV_DMA_SG_OSD_ENT); + /* OSD */ itv->osd_global_alpha_state = 1; itv->osd_global_alpha = 255; @@ -1053,9 +1055,6 @@ static int __devinit ivtv_probe(struct pci_dev *dev, goto free_io; } - /* Check yuv output filter table */ - if (itv->has_cx23415) ivtv_yuv_filter_check(itv); - ivtv_gpio_init(itv); /* active i2c */ diff --git a/drivers/media/video/ivtv/ivtv-firmware.c b/drivers/media/video/ivtv/ivtv-firmware.c index 425eb106390..6dba55b7e25 100644 --- a/drivers/media/video/ivtv/ivtv-firmware.c +++ b/drivers/media/video/ivtv/ivtv-firmware.c @@ -22,6 +22,7 @@ #include "ivtv-driver.h" #include "ivtv-mailbox.h" #include "ivtv-firmware.h" +#include "ivtv-yuv.h" #include <linux/firmware.h> #define IVTV_MASK_SPU_ENABLE 0xFFFFFFFE @@ -225,11 +226,14 @@ int ivtv_firmware_init(struct ivtv *itv) return 0; itv->dec_mbox.mbox = ivtv_search_mailbox(itv->dec_mem, IVTV_DECODER_SIZE); - if (itv->dec_mbox.mbox == NULL) + if (itv->dec_mbox.mbox == NULL) { IVTV_ERR("Decoder mailbox not found\n"); - else if (itv->has_cx23415 && ivtv_vapi(itv, CX2341X_DEC_PING_FW, 0)) { + } else if (itv->has_cx23415 && ivtv_vapi(itv, CX2341X_DEC_PING_FW, 0)) { IVTV_ERR("Decoder firmware dead!\n"); itv->dec_mbox.mbox = NULL; + } else { + /* Firmware okay, so check yuv output filter table */ + ivtv_yuv_filter_check(itv); } return itv->dec_mbox.mbox ? 0 : -ENODEV; } diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 262830da08c..6f5744286e8 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -2484,27 +2484,28 @@ struct saa7134_board saa7134_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .gpiomask = 0x080200000, - .inputs = {{ - .name = name_tv, - .vmux = 4, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 1, - .amux = LINE2, - },{ - .name = name_comp2, - .vmux = 0, - .amux = LINE2, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE2, - }}, + .inputs = { { + .name = name_tv, + .vmux = 4, + .amux = TV, + .tv = 1, + }, { + .name = name_comp1, + .vmux = 1, + .amux = LINE2, + }, { + .name = name_comp2, + .vmux = 0, + .amux = LINE2, + }, { + .name = name_svideo, + .vmux = 8, + .amux = LINE2, + } }, .radio = { - .name = name_radio, - .amux = LINE1, + .name = name_radio, + .amux = TV, + .gpio = 0x0200000, }, }, [SAA7134_BOARD_ASUSTeK_P7131_DUAL] = { diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index 52baa4f7f7d..58ab163fdbd 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -1022,12 +1022,13 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, saa7134_i2c_register(dev); /* initialize hardware #2 */ + if (TUNER_ABSENT != dev->tuner_type) + request_module("tuner"); saa7134_board_init2(dev); + saa7134_hwinit2(dev); /* load i2c helpers */ - if (TUNER_ABSENT != dev->tuner_type) - request_module("tuner"); if (card_is_empress(dev)) { request_module("saa6752hs"); } diff --git a/drivers/media/video/tvp5150.c b/drivers/media/video/tvp5150.c index 445eba4174d..d28318cb2b8 100644 --- a/drivers/media/video/tvp5150.c +++ b/drivers/media/video/tvp5150.c @@ -672,7 +672,7 @@ static int tvp5150_set_vbi(struct i2c_client *c, if (std == V4L2_STD_ALL) { tvp5150_err("VBI can't be configured without knowing number of lines\n"); return 0; - } else if (std && V4L2_STD_625_50) { + } else if (std & V4L2_STD_625_50) { /* Don't follow NTSC Line number convension */ line += 3; } @@ -719,7 +719,7 @@ static int tvp5150_get_vbi(struct i2c_client *c, if (std == V4L2_STD_ALL) { tvp5150_err("VBI can't be configured without knowing number of lines\n"); return 0; - } else if (std && V4L2_STD_625_50) { + } else if (std & V4L2_STD_625_50) { /* Don't follow NTSC Line number convension */ line += 3; } diff --git a/drivers/media/video/usbvideo/usbvideo.c b/drivers/media/video/usbvideo/usbvideo.c index fb434b5602a..5d363be7bc7 100644 --- a/drivers/media/video/usbvideo/usbvideo.c +++ b/drivers/media/video/usbvideo/usbvideo.c @@ -1034,6 +1034,11 @@ int usbvideo_RegisterVideoDevice(struct uvd *uvd) info("%s: iface=%d. endpoint=$%02x paletteBits=$%08lx", __FUNCTION__, uvd->iface, uvd->video_endp, uvd->paletteBits); } + if (uvd->dev == NULL) { + err("%s: uvd->dev == NULL", __FUNCTION__); + return -EINVAL; + } + uvd->vdev.dev=&(uvd->dev->dev); if (video_register_device(&uvd->vdev, VFL_TYPE_GRABBER, video_nr) == -1) { err("%s: video_register_device failed", __FUNCTION__); return -EPIPE; @@ -1041,10 +1046,6 @@ int usbvideo_RegisterVideoDevice(struct uvd *uvd) if (uvd->debug > 1) { info("%s: video_register_device() successful", __FUNCTION__); } - if (uvd->dev == NULL) { - err("%s: uvd->dev == NULL", __FUNCTION__); - return -EINVAL; - } info("%s on /dev/video%d: canvas=%s videosize=%s", (uvd->handle != NULL) ? uvd->handle->drvName : "???", diff --git a/drivers/media/video/v4l1-compat.c b/drivers/media/video/v4l1-compat.c index dcf22a3b672..50e1ff9f2be 100644 --- a/drivers/media/video/v4l1-compat.c +++ b/drivers/media/video/v4l1-compat.c @@ -303,7 +303,11 @@ v4l_compat_translate_ioctl(struct inode *inode, { struct video_capability *cap = arg; - cap2 = kzalloc(sizeof(*cap2),GFP_KERNEL); + cap2 = kzalloc(sizeof(*cap2), GFP_KERNEL); + if (!cap2) { + err = -ENOMEM; + break; + } memset(cap, 0, sizeof(*cap)); memset(&fbuf2, 0, sizeof(fbuf2)); @@ -426,7 +430,11 @@ v4l_compat_translate_ioctl(struct inode *inode, { struct video_window *win = arg; - fmt2 = kzalloc(sizeof(*fmt2),GFP_KERNEL); + fmt2 = kzalloc(sizeof(*fmt2), GFP_KERNEL); + if (!fmt2) { + err = -ENOMEM; + break; + } memset(win,0,sizeof(*win)); fmt2->type = V4L2_BUF_TYPE_VIDEO_OVERLAY; @@ -464,7 +472,11 @@ v4l_compat_translate_ioctl(struct inode *inode, struct video_window *win = arg; int err1,err2; - fmt2 = kzalloc(sizeof(*fmt2),GFP_KERNEL); + fmt2 = kzalloc(sizeof(*fmt2), GFP_KERNEL); + if (!fmt2) { + err = -ENOMEM; + break; + } fmt2->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; drv(inode, file, VIDIOC_STREAMOFF, &fmt2->type); err1 = drv(inode, file, VIDIOC_G_FMT, fmt2); @@ -586,6 +598,12 @@ v4l_compat_translate_ioctl(struct inode *inode, { struct video_picture *pict = arg; + fmt2 = kzalloc(sizeof(*fmt2), GFP_KERNEL); + if (!fmt2) { + err = -ENOMEM; + break; + } + pict->brightness = get_v4l_control(inode, file, V4L2_CID_BRIGHTNESS,drv); pict->hue = get_v4l_control(inode, file, @@ -597,7 +615,6 @@ v4l_compat_translate_ioctl(struct inode *inode, pict->whiteness = get_v4l_control(inode, file, V4L2_CID_WHITENESS, drv); - fmt2 = kzalloc(sizeof(*fmt2),GFP_KERNEL); fmt2->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; err = drv(inode, file, VIDIOC_G_FMT, fmt2); if (err < 0) { @@ -617,6 +634,11 @@ v4l_compat_translate_ioctl(struct inode *inode, struct video_picture *pict = arg; int mem_err = 0, ovl_err = 0; + fmt2 = kzalloc(sizeof(*fmt2), GFP_KERNEL); + if (!fmt2) { + err = -ENOMEM; + break; + } memset(&fbuf2, 0, sizeof(fbuf2)); set_v4l_control(inode, file, @@ -636,7 +658,6 @@ v4l_compat_translate_ioctl(struct inode *inode, * different pixel formats for memory vs overlay. */ - fmt2 = kzalloc(sizeof(*fmt2),GFP_KERNEL); fmt2->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; err = drv(inode, file, VIDIOC_G_FMT, fmt2); /* If VIDIOC_G_FMT failed, then the driver likely doesn't @@ -890,7 +911,11 @@ v4l_compat_translate_ioctl(struct inode *inode, { struct video_mmap *mm = arg; - fmt2 = kzalloc(sizeof(*fmt2),GFP_KERNEL); + fmt2 = kzalloc(sizeof(*fmt2), GFP_KERNEL); + if (!fmt2) { + err = -ENOMEM; + break; + } memset(&buf2,0,sizeof(buf2)); fmt2->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; @@ -986,7 +1011,11 @@ v4l_compat_translate_ioctl(struct inode *inode, { struct vbi_format *fmt = arg; - fmt2 = kzalloc(sizeof(*fmt2),GFP_KERNEL); + fmt2 = kzalloc(sizeof(*fmt2), GFP_KERNEL); + if (!fmt2) { + err = -ENOMEM; + break; + } fmt2->type = V4L2_BUF_TYPE_VBI_CAPTURE; err = drv(inode, file, VIDIOC_G_FMT, fmt2); @@ -1018,8 +1047,11 @@ v4l_compat_translate_ioctl(struct inode *inode, break; } - fmt2 = kzalloc(sizeof(*fmt2),GFP_KERNEL); - + fmt2 = kzalloc(sizeof(*fmt2), GFP_KERNEL); + if (!fmt2) { + err = -ENOMEM; + break; + } fmt2->type = V4L2_BUF_TYPE_VBI_CAPTURE; fmt2->fmt.vbi.samples_per_line = fmt->samples_per_line; fmt2->fmt.vbi.sampling_rate = fmt->sampling_rate; diff --git a/drivers/memstick/Kconfig b/drivers/memstick/Kconfig index 1093fdb0729..f0ca41c2032 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 bba467fe4bc..946e3d3506a 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,14 +270,12 @@ 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; else mrq->need_card_int = 0; - - mrq->get_int_reg = 0; } EXPORT_SYMBOL(memstick_init_req_sg); @@ -306,14 +303,12 @@ 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; else mrq->need_card_int = 0; - - mrq->get_int_reg = 0; } EXPORT_SYMBOL(memstick_init_req); @@ -343,6 +338,7 @@ static int h_memstick_read_dev_id(struct memstick_dev *card, card->id.class = id_reg.class; } complete(&card->mrq_complete); + dev_dbg(&card->dev, "if_mode = %02x\n", id_reg.if_mode); return -EAGAIN; } } @@ -423,7 +419,6 @@ static void memstick_power_on(struct memstick_host *host) { host->set_param(host, MEMSTICK_POWER, MEMSTICK_POWER_ON); host->set_param(host, MEMSTICK_INTERFACE, MEMSTICK_SERIAL); - msleep(1); } static void memstick_check(struct work_struct *work) @@ -561,6 +556,32 @@ 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); + if (host->card) + memstick_power_on(host); + 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 +632,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 423ad8cf4bb..557dbbba5cb 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; @@ -122,6 +133,7 @@ struct mspro_devinfo { struct mspro_block_data { struct memstick_dev *card; unsigned int usage_count; + unsigned int caps; struct gendisk *disk; struct request_queue *queue; spinlock_t q_lock; @@ -293,6 +305,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 +331,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 +424,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 +491,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: @@ -514,7 +578,6 @@ static int h_mspro_block_wait_for_ced(struct memstick_dev *card, static int h_mspro_block_transfer_data(struct memstick_dev *card, struct memstick_request **mrq) { - struct memstick_host *host = card->host; struct mspro_block_data *msb = memstick_get_drvdata(card); unsigned char t_val = 0; struct scatterlist t_sg = { 0 }; @@ -528,12 +591,12 @@ static int h_mspro_block_transfer_data(struct memstick_dev *card, switch ((*mrq)->tpc) { case MS_TPC_WRITE_REG: memstick_init_req(*mrq, MS_TPC_SET_CMD, &msb->transfer_cmd, 1); - (*mrq)->get_int_reg = 1; + (*mrq)->need_card_int = 1; return 0; case MS_TPC_SET_CMD: t_val = (*mrq)->int_reg; memstick_init_req(*mrq, MS_TPC_GET_INT, NULL, 1); - if (host->caps & MEMSTICK_CAP_AUTO_GET_INT) + if (msb->caps & MEMSTICK_CAP_AUTO_GET_INT) goto has_int_reg; return 0; case MS_TPC_GET_INT: @@ -583,12 +646,12 @@ has_int_reg: ? MS_TPC_READ_LONG_DATA : MS_TPC_WRITE_LONG_DATA, &t_sg); - (*mrq)->get_int_reg = 1; + (*mrq)->need_card_int = 1; return 0; case MS_TPC_READ_LONG_DATA: case MS_TPC_WRITE_LONG_DATA: msb->current_page++; - if (host->caps & MEMSTICK_CAP_AUTO_GET_INT) { + if (msb->caps & MEMSTICK_CAP_AUTO_GET_INT) { t_val = (*mrq)->int_reg; goto has_int_reg; } else { @@ -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 @@ -753,15 +816,16 @@ static int mspro_block_wait_for_ced(struct memstick_dev *card) return card->current_mrq.error; } -static int mspro_block_switch_to_parallel(struct memstick_dev *card) +static int mspro_block_set_interface(struct memstick_dev *card, + unsigned char sys_reg) { struct memstick_host *host = card->host; struct mspro_block_data *msb = memstick_get_drvdata(card); struct mspro_param_register param = { - .system = 0, + .system = sys_reg, .data_count = 0, .data_address = 0, - .cmd_param = 0 + .tpc_param = 0 }; card->next_request = h_mspro_block_req_init; @@ -770,25 +834,70 @@ static int mspro_block_switch_to_parallel(struct memstick_dev *card) sizeof(param)); memstick_new_req(host); wait_for_completion(&card->mrq_complete); - if (card->current_mrq.error) - return card->current_mrq.error; + return card->current_mrq.error; +} + +static int mspro_block_switch_interface(struct memstick_dev *card) +{ + struct memstick_host *host = card->host; + struct mspro_block_data *msb = memstick_get_drvdata(card); + int rc = 0; + + if (msb->caps & MEMSTICK_CAP_PAR4) + rc = mspro_block_set_interface(card, MEMSTICK_SYS_PAR4); + else + return 0; - msb->system = 0; - host->set_param(host, MEMSTICK_INTERFACE, MEMSTICK_PARALLEL); + if (rc) { + printk(KERN_WARNING + "%s: could not switch to 4-bit mode, error %d\n", + card->dev.bus_id, rc); + return 0; + } + + msb->system = MEMSTICK_SYS_PAR4; + host->set_param(host, MEMSTICK_INTERFACE, MEMSTICK_PAR4); + printk(KERN_INFO "%s: switching to 4-bit parallel mode\n", + card->dev.bus_id); + + if (msb->caps & MEMSTICK_CAP_PAR8) { + rc = mspro_block_set_interface(card, MEMSTICK_SYS_PAR8); + + if (!rc) { + msb->system = MEMSTICK_SYS_PAR8; + host->set_param(host, MEMSTICK_INTERFACE, + MEMSTICK_PAR8); + printk(KERN_INFO + "%s: switching to 8-bit parallel mode\n", + card->dev.bus_id); + } else + printk(KERN_WARNING + "%s: could not switch to 8-bit mode, error %d\n", + card->dev.bus_id, rc); + } card->next_request = h_mspro_block_req_init; msb->mrq_handler = h_mspro_block_default; memstick_init_req(&card->current_mrq, MS_TPC_GET_INT, NULL, 1); memstick_new_req(card->host); wait_for_completion(&card->mrq_complete); + rc = card->current_mrq.error; - if (card->current_mrq.error) { - msb->system = 0x80; + if (rc) { + printk(KERN_WARNING + "%s: interface error, trying to fall back to serial\n", + card->dev.bus_id); + msb->system = MEMSTICK_SYS_SERIAL; + host->set_param(host, MEMSTICK_POWER, MEMSTICK_POWER_OFF); + msleep(10); + host->set_param(host, MEMSTICK_POWER, MEMSTICK_POWER_ON); host->set_param(host, MEMSTICK_INTERFACE, MEMSTICK_SERIAL); - return -EFAULT; - } - return 0; + rc = memstick_set_rw_addr(card); + if (!rc) + rc = mspro_block_set_interface(card, msb->system); + } + return rc; } /* Memory allocated for attributes by this function should be freed by @@ -802,7 +911,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 +1031,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 +1073,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,16 +1082,18 @@ 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 (mspro_block_switch_to_parallel(card)) - printk(KERN_WARNING "%s: could not switch to " - "parallel interface\n", card->dev.bus_id); - } + msb->caps = host->caps; + rc = mspro_block_switch_interface(card); + if (rc) + return rc; + msleep(200); rc = mspro_block_wait_for_ced(card); if (rc) return rc; dev_dbg(&card->dev, "card activated\n"); + if (msb->system != MEMSTICK_SYS_SERIAL) + msb->caps |= MEMSTICK_CAP_AUTO_GET_INT; card->next_request = h_mspro_block_req_init; msb->mrq_handler = h_mspro_block_get_ro; @@ -1348,4 +1459,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 c002fcc3c87..4ce5c8dffb6 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 ee666380efa..12530e4311d 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 00000000000..8770a5fac3b --- /dev/null +++ b/drivers/memstick/host/jmb38x_ms.c @@ -0,0 +1,954 @@ +/* + * 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/dma-mapping.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 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_BUSY 0x00080000 +#define STATUS_MS_DAT7 0x00040000 +#define STATUS_MS_DAT6 0x00020000 +#define STATUS_MS_DAT5 0x00010000 +#define STATUS_MS_DAT4 0x00008000 +#define STATUS_MS_DAT3 0x00004000 +#define STATUS_MS_DAT2 0x00002000 +#define STATUS_MS_DAT1 0x00001000 +#define STATUS_MS_DAT0 0x00000800 +#define STATUS_HAS_MEDIA 0x00000400 +#define STATUS_FIFO_EMPTY 0x00000200 +#define STATUS_FIFO_FULL 0x00000100 +#define STATUS_MS_CED 0x00000080 +#define STATUS_MS_ERR 0x00000040 +#define STATUS_MS_BRQ 0x00000020 +#define STATUS_MS_CNK 0x00000001 + +#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 + +#define CLOCK_CONTROL_40MHZ 0x00000001 +#define CLOCK_CONTROL_50MHZ 0x00000002 +#define CLOCK_CONTROL_60MHZ 0x00000008 +#define CLOCK_CONTROL_62_5MHZ 0x0000000c +#define CLOCK_CONTROL_OFF 0x00000000 + +enum { + CMD_READY = 0x01, + FIFO_READY = 0x02, + REG_DATA = 0x04, + DMA_DATA = 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_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) { + unsigned int uninitialized_var(p_off); + + 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; + + data = host->req->data; + + if (!no_dma) + host->cmd_flags |= DMA_DATA; + + if (host->req->long_data) { + data_len = host->req->sg.length; + } else { + data_len = host->req->data_len; + host->cmd_flags &= ~DMA_DATA; + } + + if (data_len <= 8) { + cmd &= ~(TPC_DATA_SEL | 0xf); + host->cmd_flags |= REG_DATA; + cmd |= data_len & 0xf; + host->cmd_flags &= ~DMA_DATA; + } + + if (host->cmd_flags & DMA_DATA) { + 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)); + + host->req->int_reg = readl(host->addr + STATUS) & 0xff; + + writel(0, host->addr + BLOCK); + writel(0, host->addr + DMA_CONTROL); + + if (host->cmd_flags & DMA_DATA) { + 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->cmd_flags & DMA_DATA) { + 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_CONTROL_RESET_REQ, host->addr + HOST_CONTROL); + + while (HOST_CONTROL_RESET_REQ + & (host_ctl = readl(host->addr + HOST_CONTROL))) { + ndelay(20); + dev_dbg(&host->chip->pdev->dev, "reset %08x\n", host_ctl); + } + + writel(HOST_CONTROL_RESET, host->addr + HOST_CONTROL); + mmiowb(); + writel(INT_STATUS_ALL, host->addr + INT_SIGNAL_ENABLE); + writel(INT_STATUS_ALL, host->addr + INT_STATUS_ENABLE); +} + +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 = readl(host->addr + HOST_CONTROL); + unsigned int clock_ctl = CLOCK_CONTROL_40MHZ, clock_delay = 0; + + 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 = 7; + host_ctl |= HOST_CONTROL_POWER_EN + | HOST_CONTROL_CLOCK_EN; + writel(host_ctl, host->addr + HOST_CONTROL); + + dev_dbg(&host->chip->pdev->dev, "power on\n"); + } else if (value == MEMSTICK_POWER_OFF) { + host_ctl &= ~(HOST_CONTROL_POWER_EN + | HOST_CONTROL_CLOCK_EN); + writel(host_ctl, 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: + host_ctl &= ~(3 << HOST_CONTROL_IF_SHIFT); + + 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; + clock_ctl = CLOCK_CONTROL_40MHZ; + clock_delay = 0; + } 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; + clock_ctl = CLOCK_CONTROL_40MHZ; + clock_delay = 4; + } 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; + clock_ctl = CLOCK_CONTROL_60MHZ; + clock_delay = 0; + } + writel(host_ctl, host->addr + HOST_CONTROL); + writel(clock_ctl, host->addr + CLOCK_CONTROL); + writel(clock_delay, host->addr + CLOCK_DELAY); + break; + }; +} + +#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(1000); + msh->request = jmb38x_ms_request; + msh->set_param = jmb38x_ms_set_param; + + 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 4fb24215bd9..eb150dfb637 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; - if (host->cmd_flags & DATA_CARRY) { - while ((fifo_offset & 3) && length) { + while (host->io_pos && length) { + buf[off++] = host->io_word & 0xff; + host->io_word >>= 8; + length--; + host->io_pos--; + } + + 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; + data = host->req->data; - 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); + host->use_dma = !no_dma; - 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); - } - - 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,29 @@ 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; + host->req->int_reg = readl(sock->addr + SOCK_MS_STATUS) & 0xff; + host->req->int_reg = (host->req->int_reg & 1) + | ((host->req->int_reg << 4) & 0xe0); - 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); - } + writel(TIFM_FIFO_INT_SETALL, + sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR); + writel(TIFM_DMA_RESET, sock->addr + SOCK_DMA_CONTROL); + + 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 +369,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 +382,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,29 +428,22 @@ 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) { - writel(TIFM_FIFO_INT_SETALL, - sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR); - 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 +499,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 +545,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 +566,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 +573,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 +598,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 +614,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 +621,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 +672,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/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index 0c303c84b37..c6be6eba7dc 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -632,8 +632,7 @@ mpt_deregister(u8 cb_idx) /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** - * mpt_event_register - Register protocol-specific event callback - * handler. + * mpt_event_register - Register protocol-specific event callback handler. * @cb_idx: previously registered (via mpt_register) callback handle * @ev_cbfunc: callback function * @@ -654,8 +653,7 @@ mpt_event_register(u8 cb_idx, MPT_EVHANDLER ev_cbfunc) /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** - * mpt_event_deregister - Deregister protocol-specific event callback - * handler. + * mpt_event_deregister - Deregister protocol-specific event callback handler * @cb_idx: previously registered callback handle * * Each protocol-specific driver should call this routine @@ -765,11 +763,13 @@ mpt_device_driver_deregister(u8 cb_idx) /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** - * mpt_get_msg_frame - Obtain a MPT request frame from the pool (of 1024) - * allocated per MPT adapter. + * mpt_get_msg_frame - Obtain an MPT request frame from the pool * @cb_idx: Handle of registered MPT protocol driver * @ioc: Pointer to MPT adapter structure * + * Obtain an MPT request frame from the pool (of 1024) that are + * allocated per MPT adapter. + * * Returns pointer to a MPT request frame or %NULL if none are available * or IOC is not active. */ @@ -834,13 +834,12 @@ mpt_get_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc) /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** - * mpt_put_msg_frame - Send a protocol specific MPT request frame - * to a IOC. + * mpt_put_msg_frame - Send a protocol-specific MPT request frame to an IOC * @cb_idx: Handle of registered MPT protocol driver * @ioc: Pointer to MPT adapter structure * @mf: Pointer to MPT request frame * - * This routine posts a MPT request frame to the request post FIFO of a + * This routine posts an MPT request frame to the request post FIFO of a * specific MPT adapter. */ void @@ -868,13 +867,15 @@ mpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf) } /** - * mpt_put_msg_frame_hi_pri - Send a protocol specific MPT request frame - * to a IOC using hi priority request queue. + * mpt_put_msg_frame_hi_pri - Send a hi-pri protocol-specific MPT request frame * @cb_idx: Handle of registered MPT protocol driver * @ioc: Pointer to MPT adapter structure * @mf: Pointer to MPT request frame * - * This routine posts a MPT request frame to the request post FIFO of a + * Send a protocol-specific MPT request frame to an IOC using + * hi-priority request queue. + * + * This routine posts an MPT request frame to the request post FIFO of a * specific MPT adapter. **/ void @@ -1429,6 +1430,98 @@ mpt_get_product_name(u16 vendor, u16 device, u8 revision, char *prod_name) sprintf(prod_name, "%s", product_str); } +/** + * mpt_mapresources - map in memory mapped io + * @ioc: Pointer to pointer to IOC adapter + * + **/ +static int +mpt_mapresources(MPT_ADAPTER *ioc) +{ + u8 __iomem *mem; + int ii; + unsigned long mem_phys; + unsigned long port; + u32 msize; + u32 psize; + u8 revision; + int r = -ENODEV; + struct pci_dev *pdev; + + pdev = ioc->pcidev; + ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM); + if (pci_enable_device_mem(pdev)) { + printk(MYIOC_s_ERR_FMT "pci_enable_device_mem() " + "failed\n", ioc->name); + return r; + } + if (pci_request_selected_regions(pdev, ioc->bars, "mpt")) { + printk(MYIOC_s_ERR_FMT "pci_request_selected_regions() with " + "MEM failed\n", ioc->name); + return r; + } + + pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); + + if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK) + && !pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK)) { + dinitprintk(ioc, printk(MYIOC_s_INFO_FMT + ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n", + ioc->name)); + } else if (!pci_set_dma_mask(pdev, DMA_32BIT_MASK) + && !pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) { + dinitprintk(ioc, printk(MYIOC_s_INFO_FMT + ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n", + ioc->name)); + } else { + printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n", + ioc->name, pci_name(pdev)); + pci_release_selected_regions(pdev, ioc->bars); + return r; + } + + mem_phys = msize = 0; + port = psize = 0; + for (ii = 0; ii < DEVICE_COUNT_RESOURCE; ii++) { + if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) { + if (psize) + continue; + /* Get I/O space! */ + port = pci_resource_start(pdev, ii); + psize = pci_resource_len(pdev, ii); + } else { + if (msize) + continue; + /* Get memmap */ + mem_phys = pci_resource_start(pdev, ii); + msize = pci_resource_len(pdev, ii); + } + } + ioc->mem_size = msize; + + mem = NULL; + /* Get logical ptr for PciMem0 space */ + /*mem = ioremap(mem_phys, msize);*/ + mem = ioremap(mem_phys, msize); + if (mem == NULL) { + printk(MYIOC_s_ERR_FMT ": ERROR - Unable to map adapter" + " memory!\n", ioc->name); + return -EINVAL; + } + ioc->memmap = mem; + dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "mem = %p, mem_phys = %lx\n", + ioc->name, mem, mem_phys)); + + ioc->mem_phys = mem_phys; + ioc->chip = (SYSIF_REGS __iomem *)mem; + + /* Save Port IO values in case we need to do downloadboot */ + ioc->pio_mem_phys = port; + ioc->pio_chip = (SYSIF_REGS __iomem *)port; + + return 0; +} + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_attach - Install a PCI intelligent MPT adapter. @@ -1451,13 +1544,6 @@ int mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) { MPT_ADAPTER *ioc; - u8 __iomem *mem; - u8 __iomem *pmem; - unsigned long mem_phys; - unsigned long port; - u32 msize; - u32 psize; - int ii; u8 cb_idx; int r = -ENODEV; u8 revision; @@ -1467,52 +1553,32 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) struct proc_dir_entry *dent, *ent; #endif - if (mpt_debug_level) - printk(KERN_INFO MYNAM ": mpt_debug_level=%xh\n", mpt_debug_level); - ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC); if (ioc == NULL) { printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n"); return -ENOMEM; } - ioc->debug_level = mpt_debug_level; + ioc->id = mpt_ids++; sprintf(ioc->name, "ioc%d", ioc->id); - ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM); - if (pci_enable_device_mem(pdev)) { - printk(MYIOC_s_ERR_FMT "pci_enable_device_mem() " - "failed\n", ioc->name); - kfree(ioc); - return r; - } - if (pci_request_selected_regions(pdev, ioc->bars, "mpt")) { - printk(MYIOC_s_ERR_FMT "pci_request_selected_regions() with " - "MEM failed\n", ioc->name); - kfree(ioc); - return r; - } + /* + * set initial debug level + * (refer to mptdebug.h) + * + */ + ioc->debug_level = mpt_debug_level; + if (mpt_debug_level) + printk(KERN_INFO "mpt_debug_level=%xh\n", mpt_debug_level); dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": mpt_adapter_install\n", ioc->name)); - if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) { - dprintk(ioc, printk(MYIOC_s_INFO_FMT - ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n", ioc->name)); - } else if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) { - printk(MYIOC_s_WARN_FMT ": 32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n", - ioc->name); + ioc->pcidev = pdev; + if (mpt_mapresources(ioc)) { kfree(ioc); return r; } - if (!pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK)) { - dprintk(ioc, printk(MYIOC_s_INFO_FMT - ": Using 64 bit consistent mask\n", ioc->name)); - } else { - dprintk(ioc, printk(MYIOC_s_INFO_FMT - ": Not using 64 bit consistent mask\n", ioc->name)); - } - ioc->alloc_total = sizeof(MPT_ADAPTER); ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */ ioc->reply_sz = MPT_REPLY_FRAME_SIZE; @@ -1550,48 +1616,9 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) /* Find lookup slot. */ INIT_LIST_HEAD(&ioc->list); - mem_phys = msize = 0; - port = psize = 0; - for (ii=0; ii < DEVICE_COUNT_RESOURCE; ii++) { - if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) { - if (psize) - continue; - /* Get I/O space! */ - port = pci_resource_start(pdev, ii); - psize = pci_resource_len(pdev,ii); - } else { - if (msize) - continue; - /* Get memmap */ - mem_phys = pci_resource_start(pdev, ii); - msize = pci_resource_len(pdev,ii); - } - } - ioc->mem_size = msize; - - mem = NULL; - /* Get logical ptr for PciMem0 space */ - /*mem = ioremap(mem_phys, msize);*/ - mem = ioremap(mem_phys, msize); - if (mem == NULL) { - printk(MYIOC_s_ERR_FMT "Unable to map adapter memory!\n", ioc->name); - kfree(ioc); - return -EINVAL; - } - ioc->memmap = mem; - dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "mem = %p, mem_phys = %lx\n", ioc->name, mem, mem_phys)); - dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n", ioc->name, &ioc->facts, &ioc->pfacts[0])); - ioc->mem_phys = mem_phys; - ioc->chip = (SYSIF_REGS __iomem *)mem; - - /* Save Port IO values in case we need to do downloadboot */ - ioc->pio_mem_phys = port; - pmem = (u8 __iomem *)port; - ioc->pio_chip = (SYSIF_REGS __iomem *)pmem; - pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); mpt_get_product_name(pdev->vendor, pdev->device, revision, ioc->prod_name); @@ -1687,7 +1714,9 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) list_del(&ioc->list); if (ioc->alt_ioc) ioc->alt_ioc->alt_ioc = NULL; - iounmap(mem); + iounmap(ioc->memmap); + if (r != -5) + pci_release_selected_regions(pdev, ioc->bars); kfree(ioc); pci_set_drvdata(pdev, NULL); return r; @@ -1783,13 +1812,10 @@ mpt_suspend(struct pci_dev *pdev, pm_message_t state) u32 device_state; MPT_ADAPTER *ioc = pci_get_drvdata(pdev); - device_state=pci_choose_state(pdev, state); - - printk(MYIOC_s_INFO_FMT - "pci-suspend: pdev=0x%p, slot=%s, Entering operating state [D%d]\n", - ioc->name, pdev, pci_name(pdev), device_state); - - pci_save_state(pdev); + device_state = pci_choose_state(pdev, state); + printk(MYIOC_s_INFO_FMT "pci-suspend: pdev=0x%p, slot=%s, Entering " + "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev), + device_state); /* put ioc into READY_STATE */ if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) { @@ -1804,10 +1830,14 @@ mpt_suspend(struct pci_dev *pdev, pm_message_t state) /* Clear any lingering interrupt */ CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); + free_irq(ioc->pci_irq, ioc); + if (mpt_msi_enable) + pci_disable_msi(ioc->pcidev); + ioc->pci_irq = -1; + pci_save_state(pdev); pci_disable_device(pdev); pci_release_selected_regions(pdev, ioc->bars); pci_set_power_state(pdev, device_state); - return 0; } @@ -1822,48 +1852,54 @@ mpt_resume(struct pci_dev *pdev) MPT_ADAPTER *ioc = pci_get_drvdata(pdev); u32 device_state = pdev->current_state; int recovery_state; + int err; - printk(MYIOC_s_INFO_FMT - "pci-resume: pdev=0x%p, slot=%s, Previous operating state [D%d]\n", - ioc->name, pdev, pci_name(pdev), device_state); + printk(MYIOC_s_INFO_FMT "pci-resume: pdev=0x%p, slot=%s, Previous " + "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev), + device_state); - pci_set_power_state(pdev, 0); + pci_set_power_state(pdev, PCI_D0); + pci_enable_wake(pdev, PCI_D0, 0); pci_restore_state(pdev); - if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT) { - ioc->bars = pci_select_bars(ioc->pcidev, IORESOURCE_MEM | - IORESOURCE_IO); - if (pci_enable_device(pdev)) - return 0; - } else { - ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM); - if (pci_enable_device_mem(pdev)) - return 0; - } - if (pci_request_selected_regions(pdev, ioc->bars, "mpt")) - return 0; + ioc->pcidev = pdev; + err = mpt_mapresources(ioc); + if (err) + return err; - /* enable interrupts */ - CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM); - ioc->active = 1; + printk(MYIOC_s_INFO_FMT "pci-resume: ioc-state=0x%x,doorbell=0x%x\n", + ioc->name, (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT), + CHIPREG_READ32(&ioc->chip->Doorbell)); - printk(MYIOC_s_INFO_FMT - "pci-resume: ioc-state=0x%x,doorbell=0x%x\n", - ioc->name, - (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT), - CHIPREG_READ32(&ioc->chip->Doorbell)); + /* + * Errata workaround for SAS pci express: + * Upon returning to the D0 state, the contents of the doorbell will be + * stale data, and this will incorrectly signal to the host driver that + * the firmware is ready to process mpt commands. The workaround is + * to issue a diagnostic reset. + */ + if (ioc->bus_type == SAS && (pdev->device == + MPI_MANUFACTPAGE_DEVID_SAS1068E || pdev->device == + MPI_MANUFACTPAGE_DEVID_SAS1064E)) { + if (KickStart(ioc, 1, CAN_SLEEP) < 0) { + printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover\n", + ioc->name); + goto out; + } + } /* bring ioc to operational state */ - if ((recovery_state = mpt_do_ioc_recovery(ioc, - MPT_HOSTEVENT_IOC_RECOVER, CAN_SLEEP)) != 0) { - printk(MYIOC_s_INFO_FMT - "pci-resume: Cannot recover, error:[%x]\n", - ioc->name, recovery_state); - } else { + printk(MYIOC_s_INFO_FMT "Sending mpt_do_ioc_recovery\n", ioc->name); + recovery_state = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP, + CAN_SLEEP); + if (recovery_state != 0) + printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover, " + "error:[%x]\n", ioc->name, recovery_state); + else printk(MYIOC_s_INFO_FMT - "pci-resume: success\n", ioc->name); - } - + "pci-resume: success\n", ioc->name); + out: return 0; + } #endif @@ -1902,6 +1938,7 @@ mpt_signal_reset(u8 index, MPT_ADAPTER *ioc, int reset_phase) * -3 if READY but PrimeIOCFifos Failed * -4 if READY but IOCInit Failed * -5 if failed to enable_device and/or request_selected_regions + * -6 if failed to upload firmware */ static int mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) @@ -2096,7 +2133,7 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) } else { printk(MYIOC_s_WARN_FMT "firmware upload failure!\n", ioc->name); - ret = -5; + ret = -6; } } } diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index f77b329f692..78734e25edd 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -1701,6 +1701,11 @@ mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info, if (error) goto out_free_consistent; + if (!buffer->NumPhys) { + error = -ENODEV; + goto out_free_consistent; + } + /* save config data */ port_info->num_phys = buffer->NumPhys; port_info->phy_info = kcalloc(port_info->num_phys, diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c index af1de0ccee2..c207bda6723 100644 --- a/drivers/message/fusion/mptscsih.c +++ b/drivers/message/fusion/mptscsih.c @@ -1170,6 +1170,10 @@ mptscsih_shutdown(struct pci_dev *pdev) int mptscsih_suspend(struct pci_dev *pdev, pm_message_t state) { + MPT_ADAPTER *ioc = pci_get_drvdata(pdev); + + scsi_block_requests(ioc->sh); + flush_scheduled_work(); mptscsih_shutdown(pdev); return mpt_suspend(pdev,state); } @@ -1183,7 +1187,12 @@ mptscsih_suspend(struct pci_dev *pdev, pm_message_t state) int mptscsih_resume(struct pci_dev *pdev) { - return mpt_resume(pdev); + MPT_ADAPTER *ioc = pci_get_drvdata(pdev); + int rc; + + rc = mpt_resume(pdev); + scsi_unblock_requests(ioc->sh); + return rc; } #endif @@ -1533,7 +1542,7 @@ mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx) * * Remark: Currently invoked from a non-interrupt thread (_bh). * - * Remark: With old EH code, at most 1 SCSI TaskMgmt function per IOC + * Note: With old EH code, at most 1 SCSI TaskMgmt function per IOC * will be active. * * Returns 0 for SUCCESS, or %FAILED. @@ -2537,14 +2546,12 @@ mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR /** * mptscsih_get_scsi_lookup - * - * retrieves scmd entry from ScsiLookup[] array list - * * @ioc: Pointer to MPT_ADAPTER structure * @i: index into the array * - * Returns the scsi_cmd pointer + * retrieves scmd entry from ScsiLookup[] array list * + * Returns the scsi_cmd pointer **/ static struct scsi_cmnd * mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i) @@ -2561,14 +2568,12 @@ mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i) /** * mptscsih_getclear_scsi_lookup - * - * retrieves and clears scmd entry from ScsiLookup[] array list - * * @ioc: Pointer to MPT_ADAPTER structure * @i: index into the array * - * Returns the scsi_cmd pointer + * retrieves and clears scmd entry from ScsiLookup[] array list * + * Returns the scsi_cmd pointer **/ static struct scsi_cmnd * mptscsih_getclear_scsi_lookup(MPT_ADAPTER *ioc, int i) diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c index afd82966f9a..13bac53db69 100644 --- a/drivers/mfd/sm501.c +++ b/drivers/mfd/sm501.c @@ -48,31 +48,13 @@ struct sm501_devdata { unsigned int pdev_id; unsigned int irq; void __iomem *regs; + unsigned int rev; }; #define MHZ (1000 * 1000) #ifdef DEBUG -static const unsigned int misc_div[] = { - [0] = 1, - [1] = 2, - [2] = 4, - [3] = 8, - [4] = 16, - [5] = 32, - [6] = 64, - [7] = 128, - [8] = 3, - [9] = 6, - [10] = 12, - [11] = 24, - [12] = 48, - [13] = 96, - [14] = 192, - [15] = 384, -}; - -static const unsigned int px_div[] = { +static const unsigned int div_tab[] = { [0] = 1, [1] = 2, [2] = 4, @@ -101,12 +83,12 @@ static const unsigned int px_div[] = { static unsigned long decode_div(unsigned long pll2, unsigned long val, unsigned int lshft, unsigned int selbit, - unsigned long mask, const unsigned int *dtab) + unsigned long mask) { if (val & selbit) pll2 = 288 * MHZ; - return pll2 / dtab[(val >> lshft) & mask]; + return pll2 / div_tab[(val >> lshft) & mask]; } #define fmt_freq(x) ((x) / MHZ), ((x) % MHZ), (x) @@ -141,10 +123,10 @@ static void sm501_dump_clk(struct sm501_devdata *sm) } sdclk0 = (misct & (1<<12)) ? pll2 : 288 * MHZ; - sdclk0 /= misc_div[((misct >> 8) & 0xf)]; + sdclk0 /= div_tab[((misct >> 8) & 0xf)]; sdclk1 = (misct & (1<<20)) ? pll2 : 288 * MHZ; - sdclk1 /= misc_div[((misct >> 16) & 0xf)]; + sdclk1 /= div_tab[((misct >> 16) & 0xf)]; dev_dbg(sm->dev, "MISCT=%08lx, PM0=%08lx, PM1=%08lx\n", misct, pm0, pm1); @@ -158,19 +140,19 @@ static void sm501_dump_clk(struct sm501_devdata *sm) "P2 %ld.%ld MHz (%ld), V2 %ld.%ld (%ld), " "M %ld.%ld (%ld), MX1 %ld.%ld (%ld)\n", (pmc & 3 ) == 0 ? '*' : '-', - fmt_freq(decode_div(pll2, pm0, 24, 1<<29, 31, px_div)), - fmt_freq(decode_div(pll2, pm0, 16, 1<<20, 15, misc_div)), - fmt_freq(decode_div(pll2, pm0, 8, 1<<12, 15, misc_div)), - fmt_freq(decode_div(pll2, pm0, 0, 1<<4, 15, misc_div))); + fmt_freq(decode_div(pll2, pm0, 24, 1<<29, 31)), + fmt_freq(decode_div(pll2, pm0, 16, 1<<20, 15)), + fmt_freq(decode_div(pll2, pm0, 8, 1<<12, 15)), + fmt_freq(decode_div(pll2, pm0, 0, 1<<4, 15))); dev_dbg(sm->dev, "PM1[%c]: " "P2 %ld.%ld MHz (%ld), V2 %ld.%ld (%ld), " "M %ld.%ld (%ld), MX1 %ld.%ld (%ld)\n", (pmc & 3 ) == 1 ? '*' : '-', - fmt_freq(decode_div(pll2, pm1, 24, 1<<29, 31, px_div)), - fmt_freq(decode_div(pll2, pm1, 16, 1<<20, 15, misc_div)), - fmt_freq(decode_div(pll2, pm1, 8, 1<<12, 15, misc_div)), - fmt_freq(decode_div(pll2, pm1, 0, 1<<4, 15, misc_div))); + fmt_freq(decode_div(pll2, pm1, 24, 1<<29, 31)), + fmt_freq(decode_div(pll2, pm1, 16, 1<<20, 15)), + fmt_freq(decode_div(pll2, pm1, 8, 1<<12, 15)), + fmt_freq(decode_div(pll2, pm1, 0, 1<<4, 15))); } static void sm501_dump_regs(struct sm501_devdata *sm) @@ -436,46 +418,108 @@ struct sm501_clock { unsigned long mclk; int divider; int shift; + unsigned int m, n, k; }; +/* sm501_calc_clock + * + * Calculates the nearest discrete clock frequency that + * can be achieved with the specified input clock. + * the maximum divisor is 3 or 5 + */ + +static int sm501_calc_clock(unsigned long freq, + struct sm501_clock *clock, + int max_div, + unsigned long mclk, + long *best_diff) +{ + int ret = 0; + int divider; + int shift; + long diff; + + /* try dividers 1 and 3 for CRT and for panel, + try divider 5 for panel only.*/ + + for (divider = 1; divider <= max_div; divider += 2) { + /* try all 8 shift values.*/ + for (shift = 0; shift < 8; shift++) { + /* Calculate difference to requested clock */ + diff = sm501fb_round_div(mclk, divider << shift) - freq; + if (diff < 0) + diff = -diff; + + /* If it is less than the current, use it */ + if (diff < *best_diff) { + *best_diff = diff; + + clock->mclk = mclk; + clock->divider = divider; + clock->shift = shift; + ret = 1; + } + } + } + + return ret; +} + +/* sm501_calc_pll + * + * Calculates the nearest discrete clock frequency that can be + * achieved using the programmable PLL. + * the maximum divisor is 3 or 5 + */ + +static unsigned long sm501_calc_pll(unsigned long freq, + struct sm501_clock *clock, + int max_div) +{ + unsigned long mclk; + unsigned int m, n, k; + long best_diff = 999999999; + + /* + * The SM502 datasheet doesn't specify the min/max values for M and N. + * N = 1 at least doesn't work in practice. + */ + for (m = 2; m <= 255; m++) { + for (n = 2; n <= 127; n++) { + for (k = 0; k <= 1; k++) { + mclk = (24000000UL * m / n) >> k; + + if (sm501_calc_clock(freq, clock, max_div, + mclk, &best_diff)) { + clock->m = m; + clock->n = n; + clock->k = k; + } + } + } + } + + /* Return best clock. */ + return clock->mclk / (clock->divider << clock->shift); +} + /* sm501_select_clock * - * selects nearest discrete clock frequency the SM501 can achive + * Calculates the nearest discrete clock frequency that can be + * achieved using the 288MHz and 336MHz PLLs. * the maximum divisor is 3 or 5 */ + static unsigned long sm501_select_clock(unsigned long freq, struct sm501_clock *clock, int max_div) { unsigned long mclk; - int divider; - int shift; - long diff; long best_diff = 999999999; /* Try 288MHz and 336MHz clocks. */ for (mclk = 288000000; mclk <= 336000000; mclk += 48000000) { - /* try dividers 1 and 3 for CRT and for panel, - try divider 5 for panel only.*/ - - for (divider = 1; divider <= max_div; divider += 2) { - /* try all 8 shift values.*/ - for (shift = 0; shift < 8; shift++) { - /* Calculate difference to requested clock */ - diff = sm501fb_round_div(mclk, divider << shift) - freq; - if (diff < 0) - diff = -diff; - - /* If it is less than the current, use it */ - if (diff < best_diff) { - best_diff = diff; - - clock->mclk = mclk; - clock->divider = divider; - clock->shift = shift; - } - } - } + sm501_calc_clock(freq, clock, max_div, mclk, &best_diff); } /* Return best clock. */ @@ -497,6 +541,7 @@ unsigned long sm501_set_clock(struct device *dev, unsigned long gate = readl(sm->regs + SM501_CURRENT_GATE); unsigned long clock = readl(sm->regs + SM501_CURRENT_CLOCK); unsigned char reg; + unsigned int pll_reg = 0; unsigned long sm501_freq; /* the actual frequency acheived */ struct sm501_clock to; @@ -511,14 +556,28 @@ unsigned long sm501_set_clock(struct device *dev, * requested frequency the value must be multiplied by * 2. This clock also has an additional pre divisor */ - sm501_freq = (sm501_select_clock(2 * req_freq, &to, 5) / 2); - reg=to.shift & 0x07;/* bottom 3 bits are shift */ - if (to.divider == 3) - reg |= 0x08; /* /3 divider required */ - else if (to.divider == 5) - reg |= 0x10; /* /5 divider required */ - if (to.mclk != 288000000) - reg |= 0x20; /* which mclk pll is source */ + if (sm->rev >= 0xC0) { + /* SM502 -> use the programmable PLL */ + sm501_freq = (sm501_calc_pll(2 * req_freq, + &to, 5) / 2); + reg = to.shift & 0x07;/* bottom 3 bits are shift */ + if (to.divider == 3) + reg |= 0x08; /* /3 divider required */ + else if (to.divider == 5) + reg |= 0x10; /* /5 divider required */ + reg |= 0x40; /* select the programmable PLL */ + pll_reg = 0x20000 | (to.k << 15) | (to.n << 8) | to.m; + } else { + sm501_freq = (sm501_select_clock(2 * req_freq, + &to, 5) / 2); + reg = to.shift & 0x07;/* bottom 3 bits are shift */ + if (to.divider == 3) + reg |= 0x08; /* /3 divider required */ + else if (to.divider == 5) + reg |= 0x10; /* /5 divider required */ + if (to.mclk != 288000000) + reg |= 0x20; /* which mclk pll is source */ + } break; case SM501_CLOCK_V2XCLK: @@ -579,6 +638,10 @@ unsigned long sm501_set_clock(struct device *dev, } writel(mode, sm->regs + SM501_POWER_MODE_CONTROL); + + if (pll_reg) + writel(pll_reg, sm->regs + SM501_PROGRAMMABLE_PLL_CONTROL); + sm501_sync_regs(sm); dev_info(sm->dev, "gate %08lx, clock %08lx, mode %08lx\n", @@ -599,15 +662,24 @@ EXPORT_SYMBOL_GPL(sm501_set_clock); * finds the closest available frequency for a given clock */ -unsigned long sm501_find_clock(int clksrc, +unsigned long sm501_find_clock(struct device *dev, + int clksrc, unsigned long req_freq) { + struct sm501_devdata *sm = dev_get_drvdata(dev); unsigned long sm501_freq; /* the frequency achiveable by the 501 */ struct sm501_clock to; switch (clksrc) { case SM501_CLOCK_P2XCLK: - sm501_freq = (sm501_select_clock(2 * req_freq, &to, 5) / 2); + if (sm->rev >= 0xC0) { + /* SM502 -> use the programmable PLL */ + sm501_freq = (sm501_calc_pll(2 * req_freq, + &to, 5) / 2); + } else { + sm501_freq = (sm501_select_clock(2 * req_freq, + &to, 5) / 2); + } break; case SM501_CLOCK_V2XCLK: @@ -914,6 +986,8 @@ static int sm501_init_dev(struct sm501_devdata *sm) dev_info(sm->dev, "SM501 At %p: Version %08lx, %ld Mb, IRQ %d\n", sm->regs, devid, (unsigned long)mem_avail >> 20, sm->irq); + sm->rev = devid & SM501_DEVICEID_REVMASK; + sm501_dump_gate(sm); ret = device_create_file(sm->dev, &dev_attr_dbg_regs); diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 982e27b86d1..962817e49fb 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 74d12b4a3ab..dd13a374992 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 899e3f75f28..02ff3d19b1c 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/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index bb269d0c677..6cb781262f9 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -1078,7 +1078,8 @@ static int hotkey_get_tablet_mode(int *status) if (!acpi_evalf(hkey_handle, &s, "MHKG", "d")) return -EIO; - return ((s & TP_HOTKEY_TABLET_MASK) != 0); + *status = ((s & TP_HOTKEY_TABLET_MASK) != 0); + return 0; } /* diff --git a/drivers/misc/tifm_7xx1.c b/drivers/misc/tifm_7xx1.c index 63a089b2954..67503ea71d2 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/core/Makefile b/drivers/mmc/core/Makefile index 4985807257a..19a1a254a0c 100644 --- a/drivers/mmc/core/Makefile +++ b/drivers/mmc/core/Makefile @@ -7,7 +7,7 @@ ifeq ($(CONFIG_MMC_DEBUG),y) endif obj-$(CONFIG_MMC) += mmc_core.o -mmc_core-y := core.o sysfs.o bus.o host.o \ +mmc_core-y := core.o bus.o host.o \ mmc.o mmc_ops.o sd.o sd_ops.o \ sdio.o sdio_ops.o sdio_bus.o \ sdio_cis.o sdio_io.o sdio_irq.o diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index b0c22cad942..fd95b18e988 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -17,7 +17,6 @@ #include <linux/mmc/card.h> #include <linux/mmc/host.h> -#include "sysfs.h" #include "core.h" #include "sdio_cis.h" #include "bus.h" @@ -43,7 +42,7 @@ static ssize_t mmc_type_show(struct device *dev, } static struct device_attribute mmc_dev_attrs[] = { - MMC_ATTR_RO(type), + __ATTR(type, S_IRUGO, mmc_type_show, NULL), __ATTR_NULL, }; @@ -189,7 +188,7 @@ static void mmc_release_card(struct device *dev) /* * Allocate and initialise a new MMC card structure. */ -struct mmc_card *mmc_alloc_card(struct mmc_host *host) +struct mmc_card *mmc_alloc_card(struct mmc_host *host, struct device_type *type) { struct mmc_card *card; @@ -204,6 +203,7 @@ struct mmc_card *mmc_alloc_card(struct mmc_host *host) card->dev.parent = mmc_classdev(host); card->dev.bus = &mmc_bus_type; card->dev.release = mmc_release_card; + card->dev.type = type; return card; } @@ -248,24 +248,10 @@ int mmc_add_card(struct mmc_card *card) type, card->rca); } - card->dev.uevent_suppress = 1; - ret = device_add(&card->dev); if (ret) return ret; - if (card->host->bus_ops->sysfs_add) { - ret = card->host->bus_ops->sysfs_add(card->host, card); - if (ret) { - device_del(&card->dev); - return ret; - } - } - - card->dev.uevent_suppress = 0; - - kobject_uevent(&card->dev.kobj, KOBJ_ADD); - mmc_card_set_present(card); return 0; @@ -285,9 +271,6 @@ void mmc_remove_card(struct mmc_card *card) printk(KERN_INFO "%s: card %04x removed\n", mmc_hostname(card->host), card->rca); } - - if (card->host->bus_ops->sysfs_remove) - card->host->bus_ops->sysfs_remove(card->host, card); device_del(&card->dev); } diff --git a/drivers/mmc/core/bus.h b/drivers/mmc/core/bus.h index 4f35431116a..18178766ab4 100644 --- a/drivers/mmc/core/bus.h +++ b/drivers/mmc/core/bus.h @@ -11,7 +11,16 @@ #ifndef _MMC_CORE_BUS_H #define _MMC_CORE_BUS_H -struct mmc_card *mmc_alloc_card(struct mmc_host *host); +#define MMC_DEV_ATTR(name, fmt, args...) \ +static ssize_t mmc_##name##_show (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct mmc_card *card = container_of(dev, struct mmc_card, dev); \ + return sprintf(buf, fmt, args); \ +} \ +static DEVICE_ATTR(name, S_IRUGO, mmc_##name##_show, NULL) + +struct mmc_card *mmc_alloc_card(struct mmc_host *host, + struct device_type *type); int mmc_add_card(struct mmc_card *card); void mmc_remove_card(struct mmc_card *card); diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h index 39daf2fb5dc..cfa8e15b592 100644 --- a/drivers/mmc/core/core.h +++ b/drivers/mmc/core/core.h @@ -18,8 +18,6 @@ struct mmc_bus_ops { void (*remove)(struct mmc_host *); void (*detect)(struct mmc_host *); - int (*sysfs_add)(struct mmc_host *, struct mmc_card *card); - void (*sysfs_remove)(struct mmc_host *, struct mmc_card *card); void (*suspend)(struct mmc_host *); void (*resume)(struct mmc_host *); }; diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 68c0e3b2f0e..3da29eef8f7 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -17,7 +17,6 @@ #include <linux/mmc/mmc.h> #include "core.h" -#include "sysfs.h" #include "bus.h" #include "mmc_ops.h" @@ -248,6 +247,44 @@ out: return err; } +MMC_DEV_ATTR(cid, "%08x%08x%08x%08x\n", card->raw_cid[0], card->raw_cid[1], + card->raw_cid[2], card->raw_cid[3]); +MMC_DEV_ATTR(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1], + card->raw_csd[2], card->raw_csd[3]); +MMC_DEV_ATTR(date, "%02d/%04d\n", card->cid.month, card->cid.year); +MMC_DEV_ATTR(fwrev, "0x%x\n", card->cid.fwrev); +MMC_DEV_ATTR(hwrev, "0x%x\n", card->cid.hwrev); +MMC_DEV_ATTR(manfid, "0x%06x\n", card->cid.manfid); +MMC_DEV_ATTR(name, "%s\n", card->cid.prod_name); +MMC_DEV_ATTR(oemid, "0x%04x\n", card->cid.oemid); +MMC_DEV_ATTR(serial, "0x%08x\n", card->cid.serial); + +static struct attribute *mmc_std_attrs[] = { + &dev_attr_cid.attr, + &dev_attr_csd.attr, + &dev_attr_date.attr, + &dev_attr_fwrev.attr, + &dev_attr_hwrev.attr, + &dev_attr_manfid.attr, + &dev_attr_name.attr, + &dev_attr_oemid.attr, + &dev_attr_serial.attr, + NULL, +}; + +static struct attribute_group mmc_std_attr_group = { + .attrs = mmc_std_attrs, +}; + +static struct attribute_group *mmc_attr_groups[] = { + &mmc_std_attr_group, + NULL, +}; + +static struct device_type mmc_type = { + .groups = mmc_attr_groups, +}; + /* * Handle the detection and initialisation of a card. * @@ -308,7 +345,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, /* * Allocate card structure. */ - card = mmc_alloc_card(host); + card = mmc_alloc_card(host, &mmc_type); if (IS_ERR(card)) { err = PTR_ERR(card); goto err; @@ -459,53 +496,6 @@ static void mmc_detect(struct mmc_host *host) } } -MMC_ATTR_FN(cid, "%08x%08x%08x%08x\n", card->raw_cid[0], card->raw_cid[1], - card->raw_cid[2], card->raw_cid[3]); -MMC_ATTR_FN(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1], - card->raw_csd[2], card->raw_csd[3]); -MMC_ATTR_FN(date, "%02d/%04d\n", card->cid.month, card->cid.year); -MMC_ATTR_FN(fwrev, "0x%x\n", card->cid.fwrev); -MMC_ATTR_FN(hwrev, "0x%x\n", card->cid.hwrev); -MMC_ATTR_FN(manfid, "0x%06x\n", card->cid.manfid); -MMC_ATTR_FN(name, "%s\n", card->cid.prod_name); -MMC_ATTR_FN(oemid, "0x%04x\n", card->cid.oemid); -MMC_ATTR_FN(serial, "0x%08x\n", card->cid.serial); - -static struct device_attribute mmc_dev_attrs[] = { - MMC_ATTR_RO(cid), - MMC_ATTR_RO(csd), - MMC_ATTR_RO(date), - MMC_ATTR_RO(fwrev), - MMC_ATTR_RO(hwrev), - MMC_ATTR_RO(manfid), - MMC_ATTR_RO(name), - MMC_ATTR_RO(oemid), - MMC_ATTR_RO(serial), - __ATTR_NULL, -}; - -/* - * Adds sysfs entries as relevant. - */ -static int mmc_sysfs_add(struct mmc_host *host, struct mmc_card *card) -{ - int ret; - - ret = mmc_add_attrs(card, mmc_dev_attrs); - if (ret < 0) - return ret; - - return 0; -} - -/* - * Removes the sysfs entries added by mmc_sysfs_add(). - */ -static void mmc_sysfs_remove(struct mmc_host *host, struct mmc_card *card) -{ - mmc_remove_attrs(card, mmc_dev_attrs); -} - #ifdef CONFIG_MMC_UNSAFE_RESUME /* @@ -560,8 +550,6 @@ static void mmc_resume(struct mmc_host *host) static const struct mmc_bus_ops mmc_ops = { .remove = mmc_remove, .detect = mmc_detect, - .sysfs_add = mmc_sysfs_add, - .sysfs_remove = mmc_sysfs_remove, .suspend = mmc_suspend, .resume = mmc_resume, }; diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index d1c1e0f592f..7ef3b15c5e3 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -18,7 +18,6 @@ #include <linux/mmc/sd.h> #include "core.h" -#include "sysfs.h" #include "bus.h" #include "mmc_ops.h" #include "sd_ops.h" @@ -283,6 +282,47 @@ out: return err; } +MMC_DEV_ATTR(cid, "%08x%08x%08x%08x\n", card->raw_cid[0], card->raw_cid[1], + card->raw_cid[2], card->raw_cid[3]); +MMC_DEV_ATTR(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1], + card->raw_csd[2], card->raw_csd[3]); +MMC_DEV_ATTR(scr, "%08x%08x\n", card->raw_scr[0], card->raw_scr[1]); +MMC_DEV_ATTR(date, "%02d/%04d\n", card->cid.month, card->cid.year); +MMC_DEV_ATTR(fwrev, "0x%x\n", card->cid.fwrev); +MMC_DEV_ATTR(hwrev, "0x%x\n", card->cid.hwrev); +MMC_DEV_ATTR(manfid, "0x%06x\n", card->cid.manfid); +MMC_DEV_ATTR(name, "%s\n", card->cid.prod_name); +MMC_DEV_ATTR(oemid, "0x%04x\n", card->cid.oemid); +MMC_DEV_ATTR(serial, "0x%08x\n", card->cid.serial); + + +static struct attribute *sd_std_attrs[] = { + &dev_attr_cid.attr, + &dev_attr_csd.attr, + &dev_attr_scr.attr, + &dev_attr_date.attr, + &dev_attr_fwrev.attr, + &dev_attr_hwrev.attr, + &dev_attr_manfid.attr, + &dev_attr_name.attr, + &dev_attr_oemid.attr, + &dev_attr_serial.attr, + NULL, +}; + +static struct attribute_group sd_std_attr_group = { + .attrs = sd_std_attrs, +}; + +static struct attribute_group *sd_attr_groups[] = { + &sd_std_attr_group, + NULL, +}; + +static struct device_type sd_type = { + .groups = sd_attr_groups, +}; + /* * Handle the detection and initialisation of a card. * @@ -352,7 +392,7 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, /* * Allocate card structure. */ - card = mmc_alloc_card(host); + card = mmc_alloc_card(host, &sd_type); if (IS_ERR(card)) { err = PTR_ERR(card); goto err; @@ -518,55 +558,6 @@ static void mmc_sd_detect(struct mmc_host *host) } } -MMC_ATTR_FN(cid, "%08x%08x%08x%08x\n", card->raw_cid[0], card->raw_cid[1], - card->raw_cid[2], card->raw_cid[3]); -MMC_ATTR_FN(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1], - card->raw_csd[2], card->raw_csd[3]); -MMC_ATTR_FN(scr, "%08x%08x\n", card->raw_scr[0], card->raw_scr[1]); -MMC_ATTR_FN(date, "%02d/%04d\n", card->cid.month, card->cid.year); -MMC_ATTR_FN(fwrev, "0x%x\n", card->cid.fwrev); -MMC_ATTR_FN(hwrev, "0x%x\n", card->cid.hwrev); -MMC_ATTR_FN(manfid, "0x%06x\n", card->cid.manfid); -MMC_ATTR_FN(name, "%s\n", card->cid.prod_name); -MMC_ATTR_FN(oemid, "0x%04x\n", card->cid.oemid); -MMC_ATTR_FN(serial, "0x%08x\n", card->cid.serial); - -static struct device_attribute mmc_sd_dev_attrs[] = { - MMC_ATTR_RO(cid), - MMC_ATTR_RO(csd), - MMC_ATTR_RO(scr), - MMC_ATTR_RO(date), - MMC_ATTR_RO(fwrev), - MMC_ATTR_RO(hwrev), - MMC_ATTR_RO(manfid), - MMC_ATTR_RO(name), - MMC_ATTR_RO(oemid), - MMC_ATTR_RO(serial), - __ATTR_NULL, -}; - -/* - * Adds sysfs entries as relevant. - */ -static int mmc_sd_sysfs_add(struct mmc_host *host, struct mmc_card *card) -{ - int ret; - - ret = mmc_add_attrs(card, mmc_sd_dev_attrs); - if (ret < 0) - return ret; - - return 0; -} - -/* - * Removes the sysfs entries added by mmc_sysfs_add(). - */ -static void mmc_sd_sysfs_remove(struct mmc_host *host, struct mmc_card *card) -{ - mmc_remove_attrs(card, mmc_sd_dev_attrs); -} - #ifdef CONFIG_MMC_UNSAFE_RESUME /* @@ -621,8 +612,6 @@ static void mmc_sd_resume(struct mmc_host *host) static const struct mmc_bus_ops mmc_sd_ops = { .remove = mmc_sd_remove, .detect = mmc_sd_detect, - .sysfs_add = mmc_sd_sysfs_add, - .sysfs_remove = mmc_sd_sysfs_remove, .suspend = mmc_sd_suspend, .resume = mmc_sd_resume, }; diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 87a50f456ef..4eab79e09cc 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -287,7 +287,7 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr) /* * Allocate card structure. */ - card = mmc_alloc_card(host); + card = mmc_alloc_card(host, NULL); if (IS_ERR(card)) { err = PTR_ERR(card); goto err; diff --git a/drivers/mmc/core/sysfs.c b/drivers/mmc/core/sysfs.c deleted file mode 100644 index 00a97e70f91..00000000000 --- a/drivers/mmc/core/sysfs.c +++ /dev/null @@ -1,43 +0,0 @@ -/* - * linux/drivers/mmc/core/sysfs.c - * - * Copyright (C) 2003 Russell King, All Rights Reserved. - * Copyright 2007 Pierre Ossman - * - * 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. - * - * MMC sysfs/driver model support. - */ -#include <linux/device.h> - -#include <linux/mmc/card.h> - -#include "sysfs.h" - -int mmc_add_attrs(struct mmc_card *card, struct device_attribute *attrs) -{ - int error = 0; - int i; - - for (i = 0; attr_name(attrs[i]); i++) { - error = device_create_file(&card->dev, &attrs[i]); - if (error) { - while (--i >= 0) - device_remove_file(&card->dev, &attrs[i]); - break; - } - } - - return error; -} - -void mmc_remove_attrs(struct mmc_card *card, struct device_attribute *attrs) -{ - int i; - - for (i = 0; attr_name(attrs[i]); i++) - device_remove_file(&card->dev, &attrs[i]); -} - diff --git a/drivers/mmc/core/sysfs.h b/drivers/mmc/core/sysfs.h deleted file mode 100644 index 4b8f670bd10..00000000000 --- a/drivers/mmc/core/sysfs.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * linux/drivers/mmc/core/sysfs.h - * - * Copyright (C) 2003 Russell King, All Rights Reserved. - * Copyright 2007 Pierre Ossman - * - * 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. - */ -#ifndef _MMC_CORE_SYSFS_H -#define _MMC_CORE_SYSFS_H - -#define MMC_ATTR_FN(name, fmt, args...) \ -static ssize_t mmc_##name##_show (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct mmc_card *card = container_of(dev, struct mmc_card, dev);\ - return sprintf(buf, fmt, args); \ -} - -#define MMC_ATTR_RO(name) __ATTR(name, S_IRUGO, mmc_##name##_show, NULL) - -int mmc_add_attrs(struct mmc_card *card, struct device_attribute *attrs); -void mmc_remove_attrs(struct mmc_card *card, struct device_attribute *attrs); - -#endif diff --git a/drivers/mmc/host/tifm_sd.c b/drivers/mmc/host/tifm_sd.c index 20d5c7bd940..1c14a186f00 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/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c index eeaaa9dce6e..ad1880c6751 100644 --- a/drivers/mtd/devices/block2mtd.c +++ b/drivers/mtd/devices/block2mtd.c @@ -408,7 +408,6 @@ static int block2mtd_setup2(const char *val) if (token[1]) { ret = parse_num(&erase_size, token[1]); if (ret) { - kfree(name); parse_err("illegal erase size"); } } diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 6ac81e35355..27596046297 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -1000,8 +1000,8 @@ static int __init ubi_init(void) mutex_unlock(&ubi_devices_mutex); if (err < 0) { put_mtd_device(mtd); - printk(KERN_ERR "UBI error: cannot attach %s\n", - p->name); + printk(KERN_ERR "UBI error: cannot attach mtd%d\n", + mtd->index); goto out_detach; } } diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h index 45771061526..a548c1d28fa 100644 --- a/drivers/mtd/ubi/ubi.h +++ b/drivers/mtd/ubi/ubi.h @@ -217,11 +217,11 @@ struct ubi_volume { void *upd_buf; int *eba_tbl; - int checked:1; - int corrupted:1; - int upd_marker:1; - int updating:1; - int changing_leb:1; + unsigned int checked:1; + unsigned int corrupted:1; + unsigned int upd_marker:1; + unsigned int updating:1; + unsigned int changing_leb:1; #ifdef CONFIG_MTD_UBI_GLUEBI /* diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c index a3ca2257e60..5be58d85c63 100644 --- a/drivers/mtd/ubi/vmt.c +++ b/drivers/mtd/ubi/vmt.c @@ -376,7 +376,9 @@ out_sysfs: get_device(&vol->dev); volume_sysfs_close(vol); out_gluebi: - ubi_destroy_gluebi(vol); + if (ubi_destroy_gluebi(vol)) + dbg_err("cannot destroy gluebi for volume %d:%d", + ubi->ubi_num, vol_id); out_cdev: cdev_del(&vol->cdev); out_mapping: diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c index 56fc3fbce83..af36b12be27 100644 --- a/drivers/mtd/ubi/vtbl.c +++ b/drivers/mtd/ubi/vtbl.c @@ -519,6 +519,7 @@ static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si, if (ubi->autoresize_vol_id != -1) { ubi_err("more then one auto-resize volume (%d " "and %d)", ubi->autoresize_vol_id, i); + kfree(vol); return -EINVAL; } diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c index 7d253686ed0..5ba4bab6d43 100644 --- a/drivers/net/3c501.c +++ b/drivers/net/3c501.c @@ -485,9 +485,7 @@ static int el_start_xmit(struct sk_buff *skb, struct net_device *dev) printk(KERN_DEBUG "%s: burped during tx load.\n", dev->name); spin_lock_irqsave(&lp->lock, flags); - } - while (1); - + } while (1); } /** @@ -612,7 +610,8 @@ static irqreturn_t el_interrupt(int irq, void *dev_id) dev->stats.tx_packets++; if (el_debug > 6) printk(KERN_DEBUG " Tx succeeded %s\n", - (txsr & TX_RDY) ? "." : "but tx is busy!"); + (txsr & TX_RDY) ? "." : + "but tx is busy!"); /* * This is safe the interrupt is atomic WRT itself. */ @@ -693,7 +692,8 @@ static void el_receive(struct net_device *dev) if (pkt_len < 60 || pkt_len > 1536) { if (el_debug) - printk(KERN_DEBUG "%s: bogus packet, length=%d\n", dev->name, pkt_len); + printk(KERN_DEBUG "%s: bogus packet, length=%d\n", + dev->name, pkt_len); dev->stats.rx_over_errors++; return; } @@ -711,7 +711,8 @@ static void el_receive(struct net_device *dev) outw(0x00, GP_LOW); if (skb == NULL) { - printk(KERN_INFO "%s: Memory squeeze, dropping packet.\n", dev->name); + printk(KERN_INFO "%s: Memory squeeze, dropping packet.\n", + dev->name); dev->stats.rx_dropped++; return; } else { @@ -748,7 +749,8 @@ static void el_reset(struct net_device *dev) if (el_debug > 2) printk(KERN_INFO "3c501 reset..."); outb(AX_RESET, AX_CMD); /* Reset the chip */ - outb(AX_LOOP, AX_CMD); /* Aux control, irq and loopback enabled */ + /* Aux control, irq and loopback enabled */ + outb(AX_LOOP, AX_CMD); { int i; for (i = 0; i < 6; i++) /* Set the station address. */ diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index a0f0e605d63..fe7b5ec0970 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 5136d94923a..b1448637107 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 c12cbdf368b..47a8275d396 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 6ab2c2d4d67..fef5560bc7a 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 cc4610db639..02cb8f1c114 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 b74dbeef805..13c293b286d 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/atl1/atl1_main.c b/drivers/net/atl1/atl1_main.c index 9200ee59d85..129b8b3aa77 100644 --- a/drivers/net/atl1/atl1_main.c +++ b/drivers/net/atl1/atl1_main.c @@ -1765,15 +1765,12 @@ static irqreturn_t atl1_intr(int irq, void *data) { struct atl1_adapter *adapter = netdev_priv(data); u32 status; - u8 update_rx; int max_ints = 10; status = adapter->cmb.cmb->int_stats; if (!status) return IRQ_NONE; - update_rx = 0; - do { /* clear CMB interrupt status at once */ adapter->cmb.cmb->int_stats = 0; diff --git a/drivers/net/b44.c b/drivers/net/b44.c index ea2a2b548e3..25f1337cd02 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -2082,6 +2082,11 @@ static int __devinit b44_get_invariants(struct b44 *bp) addr = sdev->bus->sprom.et0mac; bp->phy_addr = sdev->bus->sprom.et0phyaddr; } + /* Some ROMs have buggy PHY addresses with the high + * bits set (sign extension?). Truncate them to a + * valid PHY address. */ + bp->phy_addr &= 0x1F; + memcpy(bp->dev->dev_addr, addr, 6); if (!is_valid_ether_addr(&bp->dev->dev_addr[0])){ diff --git a/drivers/net/bnx2x.c b/drivers/net/bnx2x.c index 8af142ccf37..de32b3fba32 100644 --- a/drivers/net/bnx2x.c +++ b/drivers/net/bnx2x.c @@ -63,8 +63,8 @@ #include "bnx2x.h" #include "bnx2x_init.h" -#define DRV_MODULE_VERSION "1.40.22" -#define DRV_MODULE_RELDATE "2007/11/27" +#define DRV_MODULE_VERSION "1.42.3" +#define DRV_MODULE_RELDATE "2008/3/9" #define BNX2X_BC_VER 0x040200 /* Time in jiffies before concluding the transmitter is hung. */ @@ -8008,38 +8008,6 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) cmd->duplex, cmd->port, cmd->phy_address, cmd->transceiver, cmd->autoneg, cmd->maxtxpkt, cmd->maxrxpkt); - switch (cmd->port) { - case PORT_TP: - if (!(bp->supported & SUPPORTED_TP)) { - DP(NETIF_MSG_LINK, "TP not supported\n"); - return -EINVAL; - } - - if (bp->phy_flags & PHY_XGXS_FLAG) { - bnx2x_link_reset(bp); - bnx2x_link_settings_supported(bp, SWITCH_CFG_1G); - bnx2x_phy_deassert(bp); - } - break; - - case PORT_FIBRE: - if (!(bp->supported & SUPPORTED_FIBRE)) { - DP(NETIF_MSG_LINK, "FIBRE not supported\n"); - return -EINVAL; - } - - if (!(bp->phy_flags & PHY_XGXS_FLAG)) { - bnx2x_link_reset(bp); - bnx2x_link_settings_supported(bp, SWITCH_CFG_10G); - bnx2x_phy_deassert(bp); - } - break; - - default: - DP(NETIF_MSG_LINK, "Unknown port type\n"); - return -EINVAL; - } - if (cmd->autoneg == AUTONEG_ENABLE) { if (!(bp->supported & SUPPORTED_Autoneg)) { DP(NETIF_MSG_LINK, "Aotoneg not supported\n"); diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index cb3c6faa788..d16e0e1d2b3 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -310,7 +310,7 @@ static inline int __check_agg_selection_timer(struct port *port) */ static inline void __get_rx_machine_lock(struct port *port) { - spin_lock(&(SLAVE_AD_INFO(port->slave).rx_machine_lock)); + spin_lock_bh(&(SLAVE_AD_INFO(port->slave).rx_machine_lock)); } /** @@ -320,7 +320,7 @@ static inline void __get_rx_machine_lock(struct port *port) */ static inline void __release_rx_machine_lock(struct port *port) { - spin_unlock(&(SLAVE_AD_INFO(port->slave).rx_machine_lock)); + spin_unlock_bh(&(SLAVE_AD_INFO(port->slave).rx_machine_lock)); } /** diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index b57bc9467db..3f58c3d0b71 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -678,12 +678,8 @@ static struct slave *rlb_choose_channel(struct sk_buff *skb, struct bonding *bon } if (!list_empty(&bond->vlan_list)) { - unsigned short vlan_id; - int res = vlan_get_tag(skb, &vlan_id); - if (!res) { + if (!vlan_get_tag(skb, &client_info->vlan_id)) client_info->tag = 1; - client_info->vlan_id = vlan_id; - } } if (!client_info->assigned) { diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 0942d82f7cb..0f0675319e9 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -383,7 +383,7 @@ struct vlan_entry *bond_next_vlan(struct bonding *bond, struct vlan_entry *curr) */ int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, struct net_device *slave_dev) { - unsigned short vlan_id; + unsigned short uninitialized_var(vlan_id); if (!list_empty(&bond->vlan_list) && !(slave_dev->features & NETIF_F_HW_VLAN_TX) && @@ -4528,8 +4528,7 @@ static void bond_free_all(void) netif_tx_unlock_bh(bond_dev); /* Release the bonded slaves */ bond_release_all(bond_dev); - bond_deinit(bond_dev); - unregister_netdevice(bond_dev); + bond_destroy(bond); } #ifdef CONFIG_PROC_FS diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index 67ccad69d44..a3c74e20aa5 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -22,8 +22,8 @@ #include "bond_3ad.h" #include "bond_alb.h" -#define DRV_VERSION "3.2.4" -#define DRV_RELDATE "January 28, 2008" +#define DRV_VERSION "3.2.5" +#define DRV_RELDATE "March 21, 2008" #define DRV_NAME "bonding" #define DRV_DESCRIPTION "Ethernet Channel Bonding Driver" diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c index 979f3fc5e76..98a6bbd11d4 100644 --- a/drivers/net/cxgb3/sge.c +++ b/drivers/net/cxgb3/sge.c @@ -557,9 +557,9 @@ static void t3_free_qset(struct adapter *adapter, struct sge_qset *q) for (i = 0; i < SGE_RXQ_PER_SET; ++i) if (q->fl[i].desc) { - spin_lock(&adapter->sge.reg_lock); + spin_lock_irq(&adapter->sge.reg_lock); t3_sge_disable_fl(adapter, q->fl[i].cntxt_id); - spin_unlock(&adapter->sge.reg_lock); + spin_unlock_irq(&adapter->sge.reg_lock); free_rx_bufs(pdev, &q->fl[i]); kfree(q->fl[i].sdesc); dma_free_coherent(&pdev->dev, @@ -570,9 +570,9 @@ static void t3_free_qset(struct adapter *adapter, struct sge_qset *q) for (i = 0; i < SGE_TXQ_PER_SET; ++i) if (q->txq[i].desc) { - spin_lock(&adapter->sge.reg_lock); + spin_lock_irq(&adapter->sge.reg_lock); t3_sge_enable_ecntxt(adapter, q->txq[i].cntxt_id, 0); - spin_unlock(&adapter->sge.reg_lock); + spin_unlock_irq(&adapter->sge.reg_lock); if (q->txq[i].sdesc) { free_tx_desc(adapter, &q->txq[i], q->txq[i].in_use); @@ -586,9 +586,9 @@ static void t3_free_qset(struct adapter *adapter, struct sge_qset *q) } if (q->rspq.desc) { - spin_lock(&adapter->sge.reg_lock); + spin_lock_irq(&adapter->sge.reg_lock); t3_sge_disable_rspcntxt(adapter, q->rspq.cntxt_id); - spin_unlock(&adapter->sge.reg_lock); + spin_unlock_irq(&adapter->sge.reg_lock); dma_free_coherent(&pdev->dev, q->rspq.size * sizeof(struct rsp_desc), q->rspq.desc, q->rspq.phys_addr); @@ -1107,9 +1107,15 @@ int t3_eth_xmit(struct sk_buff *skb, struct net_device *dev) } q->in_use += ndesc; - if (unlikely(credits - ndesc < q->stop_thres)) - if (USE_GTS || !should_restart_tx(q)) - t3_stop_queue(dev, qs, q); + if (unlikely(credits - ndesc < q->stop_thres)) { + t3_stop_queue(dev, qs, q); + + if (should_restart_tx(q) && + test_and_clear_bit(TXQ_ETH, &qs->txq_stopped)) { + q->restarts++; + netif_wake_queue(dev); + } + } gen = q->gen; q->unacked += ndesc; @@ -2661,7 +2667,7 @@ int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports, (16 * 1024) - SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) : MAX_FRAME_SIZE + 2 + sizeof(struct cpl_rx_pkt); - spin_lock(&adapter->sge.reg_lock); + spin_lock_irq(&adapter->sge.reg_lock); /* FL threshold comparison uses < */ ret = t3_sge_init_rspcntxt(adapter, q->rspq.cntxt_id, irq_vec_idx, @@ -2705,7 +2711,7 @@ int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports, goto err_unlock; } - spin_unlock(&adapter->sge.reg_lock); + spin_unlock_irq(&adapter->sge.reg_lock); q->adap = adapter; q->netdev = dev; @@ -2722,7 +2728,7 @@ int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports, return 0; err_unlock: - spin_unlock(&adapter->sge.reg_lock); + spin_unlock_irq(&adapter->sge.reg_lock); err: t3_free_qset(adapter, q); return ret; diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c index 1fe305ca2cf..b09a53de1c5 100644 --- a/drivers/net/dm9000.c +++ b/drivers/net/dm9000.c @@ -798,8 +798,6 @@ dm9000_init_dm9000(struct net_device *dev) /* Set address filter table */ dm9000_hash_table(dev); - /* Activate DM9000 */ - iow(db, DM9000_RCR, RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN); /* Enable TX/RX interrupt mask */ iow(db, DM9000_IMR, IMR_PAR | IMR_PTM | IMR_PRM); @@ -1197,6 +1195,7 @@ dm9000_hash_table(struct net_device *dev) int i, oft; u32 hash_val; u16 hash_table[4]; + u8 rcr = RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN; unsigned long flags; dm9000_dbg(db, 1, "entering %s\n", __func__); @@ -1213,6 +1212,12 @@ dm9000_hash_table(struct net_device *dev) /* broadcast address */ hash_table[3] = 0x8000; + if (dev->flags & IFF_PROMISC) + rcr |= RCR_PRMSC; + + if (dev->flags & IFF_ALLMULTI) + rcr |= RCR_ALL; + /* the multicast address in Hash Table : 64 bits */ for (i = 0; i < mc_cnt; i++, mcptr = mcptr->next) { hash_val = ether_crc_le(6, mcptr->dmi_addr) & 0x3f; @@ -1225,6 +1230,7 @@ dm9000_hash_table(struct net_device *dev) iow(db, oft++, hash_table[i] >> 8); } + iow(db, DM9000_RCR, rcr); spin_unlock_irqrestore(&db->lock, flags); } diff --git a/drivers/net/e100.c b/drivers/net/e100.c index 36ba6dc96ac..2d139ec7977 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -960,7 +960,7 @@ static void e100_get_defaults(struct nic *nic) /* Template for a freshly allocated RFD */ nic->blank_rfd.command = 0; - nic->blank_rfd.rbd = 0xFFFFFFFF; + nic->blank_rfd.rbd = cpu_to_le32(0xFFFFFFFF); nic->blank_rfd.size = cpu_to_le16(VLAN_ETH_FRAME_LEN); /* MII setup */ @@ -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/ehea/ehea.h b/drivers/net/ehea/ehea.h index 7c4ead35cfa..93b7fb24696 100644 --- a/drivers/net/ehea/ehea.h +++ b/drivers/net/ehea/ehea.h @@ -40,7 +40,7 @@ #include <asm/io.h> #define DRV_NAME "ehea" -#define DRV_VERSION "EHEA_0087" +#define DRV_VERSION "EHEA_0089" /* eHEA capability flags */ #define DLPAR_PORT_ADD_REM 1 diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index 21af674b764..07c742dd3f0 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -3108,7 +3108,7 @@ struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter, dev->vlan_rx_add_vid = ehea_vlan_rx_add_vid; dev->vlan_rx_kill_vid = ehea_vlan_rx_kill_vid; dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_TSO - | NETIF_F_HIGHDMA | NETIF_F_HW_CSUM | NETIF_F_HW_VLAN_TX + | NETIF_F_HIGHDMA | NETIF_F_IP_CSUM | NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER | NETIF_F_LLTX; dev->tx_timeout = &ehea_tx_watchdog; diff --git a/drivers/net/enc28j60.c b/drivers/net/enc28j60.c index 0809a6a5a28..46a90e9ec56 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/epic100.c b/drivers/net/epic100.c index 0b365b8d947..76118ddd104 100644 --- a/drivers/net/epic100.c +++ b/drivers/net/epic100.c @@ -131,8 +131,8 @@ IIIa. Ring buffers IVb. References -http://www.smsc.com/main/datasheets/83c171.pdf -http://www.smsc.com/main/datasheets/83c175.pdf +http://www.smsc.com/main/tools/discontinued/83c171.pdf +http://www.smsc.com/main/tools/discontinued/83c175.pdf http://scyld.com/expert/NWay.html http://www.national.com/pf/DP/DP83840A.html @@ -227,7 +227,12 @@ static const u16 media2miictl[16] = { 0, 0x0C00, 0x0C00, 0x2000, 0x0100, 0x2100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; -/* The EPIC100 Rx and Tx buffer descriptors. */ +/* + * The EPIC100 Rx and Tx buffer descriptors. Note that these + * really ARE host-endian; it's not a misannotation. We tell + * the card to byteswap them internally on big-endian hosts - + * look for #ifdef CONFIG_BIG_ENDIAN in epic_open(). + */ struct epic_tx_desc { u32 txstatus; @@ -418,7 +423,7 @@ static int __devinit epic_init_one (struct pci_dev *pdev, /* Note: the '175 does not have a serial EEPROM. */ for (i = 0; i < 3; i++) - ((u16 *)dev->dev_addr)[i] = le16_to_cpu(inw(ioaddr + LAN0 + i*4)); + ((__le16 *)dev->dev_addr)[i] = cpu_to_le16(inw(ioaddr + LAN0 + i*4)); if (debug > 2) { dev_printk(KERN_DEBUG, &pdev->dev, "EEPROM contents:\n"); @@ -682,7 +687,8 @@ static int epic_open(struct net_device *dev) if (ep->chip_flags & MII_PWRDWN) outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL); -#if defined(__powerpc__) || defined(__sparc__) /* Big endian */ + /* Tell the chip to byteswap descriptors on big-endian hosts */ +#ifdef CONFIG_BIG_ENDIAN outl(0x4432 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL); inl(ioaddr + GENCTL); outl(0x0432 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL); @@ -695,7 +701,7 @@ static int epic_open(struct net_device *dev) udelay(20); /* Looks like EPII needs that if you want reliable RX init. FIXME: pci posting bug? */ for (i = 0; i < 3; i++) - outl(cpu_to_le16(((u16*)dev->dev_addr)[i]), ioaddr + LAN0 + i*4); + outl(le16_to_cpu(((__le16*)dev->dev_addr)[i]), ioaddr + LAN0 + i*4); ep->tx_threshold = TX_FIFO_THRESH; outl(ep->tx_threshold, ioaddr + TxThresh); @@ -798,7 +804,7 @@ static void epic_restart(struct net_device *dev) for (i = 16; i > 0; i--) outl(0x0008, ioaddr + TEST1); -#if defined(__powerpc__) || defined(__sparc__) /* Big endian */ +#ifdef CONFIG_BIG_ENDIAN outl(0x0432 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL); #else outl(0x0412 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL); @@ -808,7 +814,7 @@ static void epic_restart(struct net_device *dev) outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL); for (i = 0; i < 3; i++) - outl(cpu_to_le16(((u16*)dev->dev_addr)[i]), ioaddr + LAN0 + i*4); + outl(le16_to_cpu(((__le16*)dev->dev_addr)[i]), ioaddr + LAN0 + i*4); ep->tx_threshold = TX_FIFO_THRESH; outl(ep->tx_threshold, ioaddr + TxThresh); @@ -919,7 +925,7 @@ static void epic_init_ring(struct net_device *dev) /* Initialize all Rx descriptors. */ for (i = 0; i < RX_RING_SIZE; i++) { ep->rx_ring[i].rxstatus = 0; - ep->rx_ring[i].buflength = cpu_to_le32(ep->rx_buf_sz); + ep->rx_ring[i].buflength = ep->rx_buf_sz; ep->rx_ring[i].next = ep->rx_ring_dma + (i+1)*sizeof(struct epic_rx_desc); ep->rx_skbuff[i] = NULL; @@ -936,7 +942,7 @@ static void epic_init_ring(struct net_device *dev) skb_reserve(skb, 2); /* 16 byte align the IP header. */ ep->rx_ring[i].bufaddr = pci_map_single(ep->pci_dev, skb->data, ep->rx_buf_sz, PCI_DMA_FROMDEVICE); - ep->rx_ring[i].rxstatus = cpu_to_le32(DescOwn); + ep->rx_ring[i].rxstatus = DescOwn; } ep->dirty_rx = (unsigned int)(i - RX_RING_SIZE); @@ -974,20 +980,20 @@ static int epic_start_xmit(struct sk_buff *skb, struct net_device *dev) ep->tx_ring[entry].bufaddr = pci_map_single(ep->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE); if (free_count < TX_QUEUE_LEN/2) {/* Typical path */ - ctrl_word = cpu_to_le32(0x100000); /* No interrupt */ + ctrl_word = 0x100000; /* No interrupt */ } else if (free_count == TX_QUEUE_LEN/2) { - ctrl_word = cpu_to_le32(0x140000); /* Tx-done intr. */ + ctrl_word = 0x140000; /* Tx-done intr. */ } else if (free_count < TX_QUEUE_LEN - 1) { - ctrl_word = cpu_to_le32(0x100000); /* No Tx-done intr. */ + ctrl_word = 0x100000; /* No Tx-done intr. */ } else { /* Leave room for an additional entry. */ - ctrl_word = cpu_to_le32(0x140000); /* Tx-done intr. */ + ctrl_word = 0x140000; /* Tx-done intr. */ ep->tx_full = 1; } - ep->tx_ring[entry].buflength = ctrl_word | cpu_to_le32(skb->len); + ep->tx_ring[entry].buflength = ctrl_word | skb->len; ep->tx_ring[entry].txstatus = ((skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN) << 16) - | cpu_to_le32(DescOwn); + | DescOwn; ep->cur_tx++; if (ep->tx_full) @@ -1041,7 +1047,7 @@ static void epic_tx(struct net_device *dev, struct epic_private *ep) for (dirty_tx = ep->dirty_tx; cur_tx - dirty_tx > 0; dirty_tx++) { struct sk_buff *skb; int entry = dirty_tx % TX_RING_SIZE; - int txstatus = le32_to_cpu(ep->tx_ring[entry].txstatus); + int txstatus = ep->tx_ring[entry].txstatus; if (txstatus & DescOwn) break; /* It still hasn't been Txed */ @@ -1163,8 +1169,8 @@ static int epic_rx(struct net_device *dev, int budget) rx_work_limit = budget; /* If we own the next entry, it's a new packet. Send it up. */ - while ((ep->rx_ring[entry].rxstatus & cpu_to_le32(DescOwn)) == 0) { - int status = le32_to_cpu(ep->rx_ring[entry].rxstatus); + while ((ep->rx_ring[entry].rxstatus & DescOwn) == 0) { + int status = ep->rx_ring[entry].rxstatus; if (debug > 4) printk(KERN_DEBUG " epic_rx() status was %8.8x.\n", status); @@ -1238,7 +1244,8 @@ static int epic_rx(struct net_device *dev, int budget) skb->data, ep->rx_buf_sz, PCI_DMA_FROMDEVICE); work_done++; } - ep->rx_ring[entry].rxstatus = cpu_to_le32(DescOwn); + /* AV: shouldn't we add a barrier here? */ + ep->rx_ring[entry].rxstatus = DescOwn; } return work_done; } diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 0fbf1bbbaee..d7a3ea88edd 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -1253,7 +1253,7 @@ static void __inline__ fec_request_intrs(struct net_device *dev) /* Setup interrupt handlers. */ for (idp = id; idp->name; idp++) { - if (request_irq(idp->irq, idp->handler, 0, idp->name, dev) != 0) + if (request_irq(idp->irq, idp->handler, IRQF_DISABLED, idp->name, dev) != 0) printk("FEC: Could not allocate %s IRQ(%d)!\n", idp->name, idp->irq); } @@ -1382,7 +1382,7 @@ static void __inline__ fec_request_intrs(struct net_device *dev) /* Setup interrupt handlers. */ for (idp = id; idp->name; idp++) { - if (request_irq(b+idp->irq, fec_enet_interrupt, 0, idp->name, dev) != 0) + if (request_irq(b+idp->irq, fec_enet_interrupt, IRQF_DISABLED, idp->name, dev) != 0) printk("FEC: Could not allocate %s IRQ(%d)!\n", idp->name, b+idp->irq); } @@ -1553,7 +1553,7 @@ static void __inline__ fec_request_intrs(struct net_device *dev) /* Setup interrupt handlers. */ for (idp = id; idp->name; idp++) { - if (request_irq(b+idp->irq,fec_enet_interrupt,0,idp->name,dev)!=0) + if (request_irq(b+idp->irq, fec_enet_interrupt, IRQF_DISABLED, idp->name,dev) != 0) printk("FEC: Could not allocate %s IRQ(%d)!\n", idp->name, b+idp->irq); } @@ -1680,7 +1680,7 @@ static void __inline__ fec_request_intrs(struct net_device *dev) /* Setup interrupt handlers. */ for (idp = id; idp->name; idp++) { - if (request_irq(b+idp->irq,fec_enet_interrupt,0,idp->name,dev)!=0) + if (request_irq(b+idp->irq, fec_enet_interrupt, IRQF_DISABLED, idp->name,dev) != 0) printk("FEC: Could not allocate %s IRQ(%d)!\n", idp->name, b+idp->irq); } diff --git a/drivers/net/fec_mpc52xx_phy.c b/drivers/net/fec_mpc52xx_phy.c index 1837584c450..6a3ac4ea97e 100644 --- a/drivers/net/fec_mpc52xx_phy.c +++ b/drivers/net/fec_mpc52xx_phy.c @@ -109,7 +109,8 @@ static int mpc52xx_fec_mdio_probe(struct of_device *of, const struct of_device_i int irq = irq_of_parse_and_map(child, 0); if (irq != NO_IRQ) { const u32 *id = of_get_property(child, "reg", NULL); - bus->irq[*id] = irq; + if (id) + bus->irq[*id] = irq; } } diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 801b4d9cd97..6f7e3fde9e7 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -184,6 +184,7 @@ #define DEV_HAS_PAUSEFRAME_TX_V1 0x08000 /* device supports tx pause frames version 1 */ #define DEV_HAS_PAUSEFRAME_TX_V2 0x10000 /* device supports tx pause frames version 2 */ #define DEV_HAS_PAUSEFRAME_TX_V3 0x20000 /* device supports tx pause frames version 3 */ +#define DEV_NEED_TX_LIMIT 0x40000 /* device needs to limit tx */ enum { NvRegIrqStatus = 0x000, @@ -635,6 +636,8 @@ union ring_type { #define NV_RESTART_TX 0x1 #define NV_RESTART_RX 0x2 +#define NV_TX_LIMIT_COUNT 16 + /* statistics */ struct nv_ethtool_str { char name[ETH_GSTRING_LEN]; @@ -743,6 +746,8 @@ struct nv_skb_map { struct sk_buff *skb; dma_addr_t dma; unsigned int dma_len; + struct ring_desc_ex *first_tx_desc; + struct nv_skb_map *next_tx_ctx; }; /* @@ -827,6 +832,10 @@ struct fe_priv { union ring_type tx_ring; u32 tx_flags; int tx_ring_size; + int tx_limit; + u32 tx_pkts_in_progress; + struct nv_skb_map *tx_change_owner; + struct nv_skb_map *tx_end_flip; int tx_stop; /* vlan fields */ @@ -1707,6 +1716,9 @@ static void nv_init_tx(struct net_device *dev) np->last_tx.ex = &np->tx_ring.ex[np->tx_ring_size-1]; np->get_tx_ctx = np->put_tx_ctx = np->first_tx_ctx = np->tx_skb; np->last_tx_ctx = &np->tx_skb[np->tx_ring_size-1]; + np->tx_pkts_in_progress = 0; + np->tx_change_owner = NULL; + np->tx_end_flip = NULL; for (i = 0; i < np->tx_ring_size; i++) { if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { @@ -1720,6 +1732,9 @@ static void nv_init_tx(struct net_device *dev) } np->tx_skb[i].skb = NULL; np->tx_skb[i].dma = 0; + np->tx_skb[i].dma_len = 0; + np->tx_skb[i].first_tx_desc = NULL; + np->tx_skb[i].next_tx_ctx = NULL; } } @@ -1771,7 +1786,14 @@ static void nv_drain_tx(struct net_device *dev) } if (nv_release_txskb(dev, &np->tx_skb[i])) dev->stats.tx_dropped++; + np->tx_skb[i].dma = 0; + np->tx_skb[i].dma_len = 0; + np->tx_skb[i].first_tx_desc = NULL; + np->tx_skb[i].next_tx_ctx = NULL; } + np->tx_pkts_in_progress = 0; + np->tx_change_owner = NULL; + np->tx_end_flip = NULL; } static void nv_drain_rx(struct net_device *dev) @@ -1948,6 +1970,7 @@ static int nv_start_xmit_optimized(struct sk_buff *skb, struct net_device *dev) struct ring_desc_ex* start_tx; struct ring_desc_ex* prev_tx; struct nv_skb_map* prev_tx_ctx; + struct nv_skb_map* start_tx_ctx; /* add fragments to entries count */ for (i = 0; i < fragments; i++) { @@ -1965,6 +1988,7 @@ static int nv_start_xmit_optimized(struct sk_buff *skb, struct net_device *dev) } start_tx = put_tx = np->put_tx.ex; + start_tx_ctx = np->put_tx_ctx; /* setup the header buffer */ do { @@ -2037,6 +2061,26 @@ static int nv_start_xmit_optimized(struct sk_buff *skb, struct net_device *dev) spin_lock_irq(&np->lock); + if (np->tx_limit) { + /* Limit the number of outstanding tx. Setup all fragments, but + * do not set the VALID bit on the first descriptor. Save a pointer + * to that descriptor and also for next skb_map element. + */ + + if (np->tx_pkts_in_progress == NV_TX_LIMIT_COUNT) { + if (!np->tx_change_owner) + np->tx_change_owner = start_tx_ctx; + + /* remove VALID bit */ + tx_flags &= ~NV_TX2_VALID; + start_tx_ctx->first_tx_desc = start_tx; + start_tx_ctx->next_tx_ctx = np->put_tx_ctx; + np->tx_end_flip = np->put_tx_ctx; + } else { + np->tx_pkts_in_progress++; + } + } + /* set tx flags */ start_tx->flaglen |= cpu_to_le32(tx_flags | tx_flags_extra); np->put_tx.ex = put_tx; @@ -2060,6 +2104,25 @@ static int nv_start_xmit_optimized(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; } +static inline void nv_tx_flip_ownership(struct net_device *dev) +{ + struct fe_priv *np = netdev_priv(dev); + + np->tx_pkts_in_progress--; + if (np->tx_change_owner) { + __le32 flaglen = le32_to_cpu(np->tx_change_owner->first_tx_desc->flaglen); + flaglen |= NV_TX2_VALID; + np->tx_change_owner->first_tx_desc->flaglen = cpu_to_le32(flaglen); + np->tx_pkts_in_progress++; + + np->tx_change_owner = np->tx_change_owner->next_tx_ctx; + if (np->tx_change_owner == np->tx_end_flip) + np->tx_change_owner = NULL; + + writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl); + } +} + /* * nv_tx_done: check for completed packets, release the skbs. * @@ -2147,6 +2210,10 @@ static void nv_tx_done_optimized(struct net_device *dev, int limit) dev->stats.tx_packets++; dev_kfree_skb_any(np->get_tx_ctx->skb); np->get_tx_ctx->skb = NULL; + + if (np->tx_limit) { + nv_tx_flip_ownership(dev); + } } if (unlikely(np->get_tx.ex++ == np->last_tx.ex)) np->get_tx.ex = np->first_tx.ex; @@ -5333,6 +5400,21 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i np->need_linktimer = 0; } + /* Limit the number of tx's outstanding for hw bug */ + if (id->driver_data & DEV_NEED_TX_LIMIT) { + np->tx_limit = 1; + if ((id->device == PCI_DEVICE_ID_NVIDIA_NVENET_32 || + id->device == PCI_DEVICE_ID_NVIDIA_NVENET_33 || + id->device == PCI_DEVICE_ID_NVIDIA_NVENET_34 || + id->device == PCI_DEVICE_ID_NVIDIA_NVENET_35 || + id->device == PCI_DEVICE_ID_NVIDIA_NVENET_36 || + id->device == PCI_DEVICE_ID_NVIDIA_NVENET_37 || + id->device == PCI_DEVICE_ID_NVIDIA_NVENET_38 || + id->device == PCI_DEVICE_ID_NVIDIA_NVENET_39) && + pci_dev->revision >= 0xA2) + np->tx_limit = 0; + } + /* clear phy state and temporarily halt phy interrupts */ writel(0, base + NvRegMIIMask); phystate = readl(base + NvRegAdapterControl); @@ -5563,19 +5645,19 @@ static struct pci_device_id pci_tbl[] = { }, { /* CK804 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_8), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1|DEV_NEED_TX_LIMIT, }, { /* CK804 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_9), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1|DEV_NEED_TX_LIMIT, }, { /* MCP04 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_10), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1|DEV_NEED_TX_LIMIT, }, { /* MCP04 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_11), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1|DEV_NEED_TX_LIMIT, }, { /* MCP51 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_12), @@ -5587,11 +5669,11 @@ static struct pci_device_id pci_tbl[] = { }, { /* MCP55 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_14), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_NEED_TX_LIMIT, }, { /* MCP55 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_15), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_NEED_TX_LIMIT, }, { /* MCP61 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_16), @@ -5611,19 +5693,19 @@ static struct pci_device_id pci_tbl[] = { }, { /* MCP65 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_20), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_NEED_TX_LIMIT, }, { /* MCP65 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_21), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT, }, { /* MCP65 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_22), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT, }, { /* MCP65 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_23), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT, }, { /* MCP67 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_24), @@ -5659,35 +5741,35 @@ static struct pci_device_id pci_tbl[] = { }, { /* MCP77 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_32), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT, }, { /* MCP77 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_33), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT, }, { /* MCP77 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_34), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT, }, { /* MCP77 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_35), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT, }, { /* MCP79 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_36), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT, }, { /* MCP79 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_37), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT, }, { /* MCP79 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_38), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT, }, { /* MCP79 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_39), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT, }, {0,}, }; diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c index e6c69f77259..0789802d59e 100644 --- a/drivers/net/ibm_newemac/core.c +++ b/drivers/net/ibm_newemac/core.c @@ -143,6 +143,10 @@ static inline void emac_report_timeout_error(struct emac_instance *dev, #define STOP_TIMEOUT_1000 13 #define STOP_TIMEOUT_1000_JUMBO 73 +static unsigned char default_mcast_addr[] = { + 0x01, 0x80, 0xC2, 0x00, 0x00, 0x01 +}; + /* Please, keep in sync with struct ibm_emac_stats/ibm_emac_error_stats */ static const char emac_stats_keys[EMAC_ETHTOOL_STATS_COUNT][ETH_GSTRING_LEN] = { "rx_packets", "rx_bytes", "tx_packets", "tx_bytes", "rx_packets_csum", @@ -618,6 +622,9 @@ static int emac_configure(struct emac_instance *dev) if (emac_phy_gpcs(dev->phy.mode)) emac_mii_reset_phy(&dev->phy); + /* Required for Pause packet support in EMAC */ + dev_mc_add(ndev, default_mcast_addr, sizeof(default_mcast_addr), 1); + return 0; } diff --git a/drivers/net/ibm_newemac/tah.c b/drivers/net/ibm_newemac/tah.c index 96417adec32..b023d10d7e1 100644 --- a/drivers/net/ibm_newemac/tah.c +++ b/drivers/net/ibm_newemac/tah.c @@ -155,6 +155,10 @@ static int __devexit tah_remove(struct of_device *ofdev) static struct of_device_id tah_match[] = { { + .compatible = "ibm,tah", + }, + /* For backward compat with old DT */ + { .type = "tah", }, {}, diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c index 15949d3df17..af233b59153 100644 --- a/drivers/net/ifb.c +++ b/drivers/net/ifb.c @@ -35,6 +35,7 @@ #include <linux/moduleparam.h> #include <net/pkt_sched.h> #include <net/net_namespace.h> +#include <linux/lockdep.h> #define TX_TIMEOUT (2*HZ) @@ -227,6 +228,16 @@ static struct rtnl_link_ops ifb_link_ops __read_mostly = { module_param(numifbs, int, 0); MODULE_PARM_DESC(numifbs, "Number of ifb devices"); +/* + * dev_ifb->queue_lock is usually taken after dev->ingress_lock, + * reversely to e.g. qdisc_lock_tree(). It should be safe until + * ifb doesn't take dev->queue_lock with dev_ifb->ingress_lock. + * But lockdep should know that ifb has different locks from dev. + */ +static struct lock_class_key ifb_queue_lock_key; +static struct lock_class_key ifb_ingress_lock_key; + + static int __init ifb_init_one(int index) { struct net_device *dev_ifb; @@ -246,6 +257,10 @@ static int __init ifb_init_one(int index) err = register_netdevice(dev_ifb); if (err < 0) goto err; + + lockdep_set_class(&dev_ifb->queue_lock, &ifb_queue_lock_key); + lockdep_set_class(&dev_ifb->ingress_lock, &ifb_ingress_lock_key); + return 0; err: diff --git a/drivers/net/igb/e1000_82575.h b/drivers/net/igb/e1000_82575.h index 6604d96bd56..76ea846663d 100644 --- a/drivers/net/igb/e1000_82575.h +++ b/drivers/net/igb/e1000_82575.h @@ -61,28 +61,28 @@ /* Receive Descriptor - Advanced */ union e1000_adv_rx_desc { struct { - u64 pkt_addr; /* Packet buffer address */ - u64 hdr_addr; /* Header buffer address */ + __le64 pkt_addr; /* Packet buffer address */ + __le64 hdr_addr; /* Header buffer address */ } read; struct { struct { struct { - u16 pkt_info; /* RSS type, Packet type */ - u16 hdr_info; /* Split Header, - * header buffer length */ + __le16 pkt_info; /* RSS type, Packet type */ + __le16 hdr_info; /* Split Header, + * header buffer length */ } lo_dword; union { - u32 rss; /* RSS Hash */ + __le32 rss; /* RSS Hash */ struct { - u16 ip_id; /* IP id */ - u16 csum; /* Packet Checksum */ + __le16 ip_id; /* IP id */ + __le16 csum; /* Packet Checksum */ } csum_ip; } hi_dword; } lower; struct { - u32 status_error; /* ext status/error */ - u16 length; /* Packet length */ - u16 vlan; /* VLAN tag */ + __le32 status_error; /* ext status/error */ + __le16 length; /* Packet length */ + __le16 vlan; /* VLAN tag */ } upper; } wb; /* writeback */ }; @@ -97,14 +97,14 @@ union e1000_adv_rx_desc { /* Transmit Descriptor - Advanced */ union e1000_adv_tx_desc { struct { - u64 buffer_addr; /* Address of descriptor's data buf */ - u32 cmd_type_len; - u32 olinfo_status; + __le64 buffer_addr; /* Address of descriptor's data buf */ + __le32 cmd_type_len; + __le32 olinfo_status; } read; struct { - u64 rsvd; /* Reserved */ - u32 nxtseq_seed; - u32 status; + __le64 rsvd; /* Reserved */ + __le32 nxtseq_seed; + __le32 status; } wb; }; @@ -119,10 +119,10 @@ union e1000_adv_tx_desc { /* Context descriptors */ struct e1000_adv_tx_context_desc { - u32 vlan_macip_lens; - u32 seqnum_seed; - u32 type_tucmd_mlhl; - u32 mss_l4len_idx; + __le32 vlan_macip_lens; + __le32 seqnum_seed; + __le32 type_tucmd_mlhl; + __le32 mss_l4len_idx; }; #define E1000_ADVTXD_MACLEN_SHIFT 9 /* Adv ctxt desc mac len shift */ diff --git a/drivers/net/igb/e1000_hw.h b/drivers/net/igb/e1000_hw.h index 161fb68764a..7b2c70a3b8c 100644 --- a/drivers/net/igb/e1000_hw.h +++ b/drivers/net/igb/e1000_hw.h @@ -143,35 +143,35 @@ enum e1000_fc_type { /* Receive Descriptor */ struct e1000_rx_desc { - u64 buffer_addr; /* Address of the descriptor's data buffer */ - u16 length; /* Length of data DMAed into data buffer */ - u16 csum; /* Packet checksum */ + __le64 buffer_addr; /* Address of the descriptor's data buffer */ + __le16 length; /* Length of data DMAed into data buffer */ + __le16 csum; /* Packet checksum */ u8 status; /* Descriptor status */ u8 errors; /* Descriptor Errors */ - u16 special; + __le16 special; }; /* Receive Descriptor - Extended */ union e1000_rx_desc_extended { struct { - u64 buffer_addr; - u64 reserved; + __le64 buffer_addr; + __le64 reserved; } read; struct { struct { - u32 mrq; /* Multiple Rx Queues */ + __le32 mrq; /* Multiple Rx Queues */ union { - u32 rss; /* RSS Hash */ + __le32 rss; /* RSS Hash */ struct { - u16 ip_id; /* IP id */ - u16 csum; /* Packet Checksum */ + __le16 ip_id; /* IP id */ + __le16 csum; /* Packet Checksum */ } csum_ip; } hi_dword; } lower; struct { - u32 status_error; /* ext status/error */ - u16 length; - u16 vlan; /* VLAN tag */ + __le32 status_error; /* ext status/error */ + __le16 length; + __le16 vlan; /* VLAN tag */ } upper; } wb; /* writeback */ }; @@ -181,49 +181,49 @@ union e1000_rx_desc_extended { union e1000_rx_desc_packet_split { struct { /* one buffer for protocol header(s), three data buffers */ - u64 buffer_addr[MAX_PS_BUFFERS]; + __le64 buffer_addr[MAX_PS_BUFFERS]; } read; struct { struct { - u32 mrq; /* Multiple Rx Queues */ + __le32 mrq; /* Multiple Rx Queues */ union { - u32 rss; /* RSS Hash */ + __le32 rss; /* RSS Hash */ struct { - u16 ip_id; /* IP id */ - u16 csum; /* Packet Checksum */ + __le16 ip_id; /* IP id */ + __le16 csum; /* Packet Checksum */ } csum_ip; } hi_dword; } lower; struct { - u32 status_error; /* ext status/error */ - u16 length0; /* length of buffer 0 */ - u16 vlan; /* VLAN tag */ + __le32 status_error; /* ext status/error */ + __le16 length0; /* length of buffer 0 */ + __le16 vlan; /* VLAN tag */ } middle; struct { - u16 header_status; - u16 length[3]; /* length of buffers 1-3 */ + __le16 header_status; + __le16 length[3]; /* length of buffers 1-3 */ } upper; - u64 reserved; + __le64 reserved; } wb; /* writeback */ }; /* Transmit Descriptor */ struct e1000_tx_desc { - u64 buffer_addr; /* Address of the descriptor's data buffer */ + __le64 buffer_addr; /* Address of the descriptor's data buffer */ union { - u32 data; + __le32 data; struct { - u16 length; /* Data buffer length */ + __le16 length; /* Data buffer length */ u8 cso; /* Checksum offset */ u8 cmd; /* Descriptor control */ } flags; } lower; union { - u32 data; + __le32 data; struct { u8 status; /* Descriptor status */ u8 css; /* Checksum start */ - u16 special; + __le16 special; } fields; } upper; }; @@ -231,49 +231,49 @@ struct e1000_tx_desc { /* Offload Context Descriptor */ struct e1000_context_desc { union { - u32 ip_config; + __le32 ip_config; struct { u8 ipcss; /* IP checksum start */ u8 ipcso; /* IP checksum offset */ - u16 ipcse; /* IP checksum end */ + __le16 ipcse; /* IP checksum end */ } ip_fields; } lower_setup; union { - u32 tcp_config; + __le32 tcp_config; struct { u8 tucss; /* TCP checksum start */ u8 tucso; /* TCP checksum offset */ - u16 tucse; /* TCP checksum end */ + __le16 tucse; /* TCP checksum end */ } tcp_fields; } upper_setup; - u32 cmd_and_length; + __le32 cmd_and_length; union { - u32 data; + __le32 data; struct { u8 status; /* Descriptor status */ u8 hdr_len; /* Header length */ - u16 mss; /* Maximum segment size */ + __le16 mss; /* Maximum segment size */ } fields; } tcp_seg_setup; }; /* Offload data descriptor */ struct e1000_data_desc { - u64 buffer_addr; /* Address of the descriptor's buffer address */ + __le64 buffer_addr; /* Address of the descriptor's buffer address */ union { - u32 data; + __le32 data; struct { - u16 length; /* Data buffer length */ + __le16 length; /* Data buffer length */ u8 typ_len_ext; u8 cmd; } flags; } lower; union { - u32 data; + __le32 data; struct { u8 status; /* Descriptor status */ u8 popts; /* Packet Options */ - u16 special; + __le16 special; } fields; } upper; }; diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 6a1f2309209..aaee02e9e3f 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -31,7 +31,6 @@ #include <linux/vmalloc.h> #include <linux/pagemap.h> #include <linux/netdevice.h> -#include <linux/tcp.h> #include <linux/ipv6.h> #include <net/checksum.h> #include <net/ip6_checksum.h> @@ -2484,10 +2483,24 @@ static inline bool igb_tx_csum_adv(struct igb_adapter *adapter, tu_cmd |= (E1000_TXD_CMD_DEXT | E1000_ADVTXD_DTYP_CTXT); if (skb->ip_summed == CHECKSUM_PARTIAL) { - if (skb->protocol == htons(ETH_P_IP)) + switch (skb->protocol) { + case __constant_htons(ETH_P_IP): tu_cmd |= E1000_ADVTXD_TUCMD_IPV4; - if (skb->sk && (skb->sk->sk_protocol == IPPROTO_TCP)) - tu_cmd |= E1000_ADVTXD_TUCMD_L4T_TCP; + if (ip_hdr(skb)->protocol == IPPROTO_TCP) + tu_cmd |= E1000_ADVTXD_TUCMD_L4T_TCP; + break; + case __constant_htons(ETH_P_IPV6): + /* XXX what about other V6 headers?? */ + if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP) + tu_cmd |= E1000_ADVTXD_TUCMD_L4T_TCP; + break; + default: + if (unlikely(net_ratelimit())) + dev_warn(&adapter->pdev->dev, + "partial checksum but proto=%x!\n", + skb->protocol); + break; + } } context_desc->type_tucmd_mlhl = cpu_to_le32(tu_cmd); @@ -3241,6 +3254,13 @@ quit_polling: return 1; } + +static inline u32 get_head(struct igb_ring *tx_ring) +{ + void *end = (struct e1000_tx_desc *)tx_ring->desc + tx_ring->count; + return le32_to_cpu(*(volatile __le32 *)end); +} + /** * igb_clean_tx_irq - Reclaim resources after transmit completes * @adapter: board private structure @@ -3262,9 +3282,7 @@ static bool igb_clean_tx_irq(struct igb_adapter *adapter, unsigned int total_bytes = 0, total_packets = 0; rmb(); - head = *(volatile u32 *)((struct e1000_tx_desc *)tx_ring->desc - + tx_ring->count); - head = le32_to_cpu(head); + head = get_head(tx_ring); i = tx_ring->next_to_clean; while (1) { while (i != head) { @@ -3299,9 +3317,7 @@ static bool igb_clean_tx_irq(struct igb_adapter *adapter, } oldhead = head; rmb(); - head = *(volatile u32 *)((struct e1000_tx_desc *)tx_ring->desc - + tx_ring->count); - head = le32_to_cpu(head); + head = get_head(tx_ring); if (head == oldhead) goto done_cleaning; } /* while (1) */ @@ -3375,7 +3391,7 @@ done_cleaning: * @vlan: descriptor vlan field as written by hardware (no le/be conversion) * @skb: pointer to sk_buff to be indicated to stack **/ -static void igb_receive_skb(struct igb_adapter *adapter, u8 status, u16 vlan, +static void igb_receive_skb(struct igb_adapter *adapter, u8 status, __le16 vlan, struct sk_buff *skb) { if (adapter->vlgrp && (status & E1000_RXD_STAT_VP)) @@ -3439,8 +3455,8 @@ static bool igb_clean_rx_irq_adv(struct igb_adapter *adapter, * that case, it fills the header buffer and spills the rest * into the page. */ - hlen = le16_to_cpu((rx_desc->wb.lower.lo_dword.hdr_info & - E1000_RXDADV_HDRBUFLEN_MASK) >> E1000_RXDADV_HDRBUFLEN_SHIFT); + hlen = (le16_to_cpu(rx_desc->wb.lower.lo_dword.hdr_info) & + E1000_RXDADV_HDRBUFLEN_MASK) >> E1000_RXDADV_HDRBUFLEN_SHIFT; if (hlen > adapter->rx_ps_hdr_size) hlen = adapter->rx_ps_hdr_size; diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c index 373f72cdbe8..1f25263dc7e 100644 --- a/drivers/net/ioc3-eth.c +++ b/drivers/net/ioc3-eth.c @@ -1221,7 +1221,8 @@ static void __devinit ioc3_serial_probe(struct pci_dev *pdev, struct ioc3 *ioc3) } #endif -static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +static int __devinit ioc3_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) { unsigned int sw_physid1, sw_physid2; struct net_device *dev = NULL; diff --git a/drivers/net/ipg.c b/drivers/net/ipg.c index 5e5d9b527ed..9b358f61ed7 100644 --- a/drivers/net/ipg.c +++ b/drivers/net/ipg.c @@ -472,7 +472,6 @@ static int ipg_config_autoneg(struct net_device *dev) unsigned int txflowcontrol; unsigned int rxflowcontrol; unsigned int fullduplex; - unsigned int gig; u32 mac_ctrl_val; u32 asicctrl; u8 phyctrl; @@ -489,7 +488,6 @@ static int ipg_config_autoneg(struct net_device *dev) fullduplex = 0; txflowcontrol = 0; rxflowcontrol = 0; - gig = 0; /* To accomodate a problem in 10Mbps operation, * set a global flag if PHY running in 10Mbps mode. @@ -511,7 +509,6 @@ static int ipg_config_autoneg(struct net_device *dev) break; case IPG_PC_LINK_SPEED_1000MBPS: printk("1000Mbps.\n"); - gig = 1; break; default: printk("undefined!\n"); @@ -1900,8 +1897,13 @@ static int ipg_nic_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) /* Specify the TFC field within the TFD. */ txfd->tfc |= cpu_to_le64(IPG_TFC_WORDALIGNDISABLED | - (IPG_TFC_FRAMEID & cpu_to_le64(sp->tx_current)) | + (IPG_TFC_FRAMEID & sp->tx_current) | (IPG_TFC_FRAGCOUNT & (1 << 24))); + /* + * 16--17 (WordAlign) <- 3 (disable), + * 0--15 (FrameId) <- sp->tx_current, + * 24--27 (FragCount) <- 1 + */ /* Request TxComplete interrupts at an interval defined * by the constant IPG_FRAMESBETWEENTXCOMPLETES. diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index 269e6f805f4..6738b4d097f 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -2088,14 +2088,12 @@ ixgb_alloc_rx_buffers(struct ixgb_adapter *adapter) struct ixgb_buffer *buffer_info; struct sk_buff *skb; unsigned int i; - int num_group_tail_writes; long cleancount; i = rx_ring->next_to_use; buffer_info = &rx_ring->buffer_info[i]; cleancount = IXGB_DESC_UNUSED(rx_ring); - num_group_tail_writes = IXGB_RX_BUFFER_WRITE; /* leave three descriptors unused */ while(--cleancount > 2) { diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 23d0a4afe0e..c2095ce531c 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 b528ce77c40..771139e283a 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/ne2k-pci.c b/drivers/net/ne2k-pci.c index b569c90da4b..de0de744a8f 100644 --- a/drivers/net/ne2k-pci.c +++ b/drivers/net/ne2k-pci.c @@ -535,9 +535,9 @@ static void ne2k_pci_block_input(struct net_device *dev, int count, if (count & 3) { buf += count & ~3; if (count & 2) { - u16 *b = (u16 *)buf; + __le16 *b = (__le16 *)buf; - *b++ = le16_to_cpu(inw(NE_BASE + NE_DATAPORT)); + *b++ = cpu_to_le16(inw(NE_BASE + NE_DATAPORT)); buf = (char *)b; } if (count & 1) @@ -600,9 +600,9 @@ static void ne2k_pci_block_output(struct net_device *dev, int count, if (count & 3) { buf += count & ~3; if (count & 2) { - u16 *b = (u16 *)buf; + __le16 *b = (__le16 *)buf; - outw(cpu_to_le16(*b++), NE_BASE + NE_DATAPORT); + outw(le16_to_cpu(*b++), NE_BASE + NE_DATAPORT); buf = (char *)b; } } diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index 2bc5eaae141..7f20a03623a 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -85,7 +85,7 @@ (sizeof(struct netxen_cmd_buffer) * adapter->max_tx_desc_count) #define RCV_BUFFSIZE \ (sizeof(struct netxen_rx_buffer) * rcv_desc->max_rx_desc_count) -#define find_diff_among(a,b,range) ((a)<=(b)?((b)-(a)):((b)+(range)-(a))) +#define find_diff_among(a,b,range) ((a)<(b)?((b)-(a)):((b)+(range)-(a))) #define NETXEN_NETDEV_STATUS 0x1 #define NETXEN_RCV_PRODUCER_OFFSET 0 @@ -204,7 +204,7 @@ enum { ? RCV_DESC_LRO : \ (RCV_DESC_NORMAL))) -#define MAX_CMD_DESCRIPTORS 1024 +#define MAX_CMD_DESCRIPTORS 4096 #define MAX_RCV_DESCRIPTORS 16384 #define MAX_CMD_DESCRIPTORS_HOST (MAX_CMD_DESCRIPTORS / 4) #define MAX_RCV_DESCRIPTORS_1G (MAX_RCV_DESCRIPTORS / 4) @@ -818,15 +818,8 @@ struct netxen_adapter_stats { u64 badskblen; u64 nocmddescriptor; u64 polled; - u64 uphappy; - u64 updropped; - u64 uplcong; - u64 uphcong; - u64 upmcong; - u64 updunno; - u64 skbfreed; + u64 rxdropped; u64 txdropped; - u64 txnullskb; u64 csummed; u64 no_rcv; u64 rxbytes; @@ -842,7 +835,6 @@ struct netxen_rcv_desc_ctx { u32 flags; u32 producer; u32 rcv_pending; /* Num of bufs posted in phantom */ - u32 rcv_free; /* Num of bufs in free list */ dma_addr_t phys_addr; struct pci_dev *phys_pdev; struct rcv_desc *desc_head; /* address of rx ring in Phantom */ @@ -889,8 +881,6 @@ struct netxen_adapter { int mtu; int portnum; - spinlock_t tx_lock; - spinlock_t lock; struct work_struct watchdog_task; struct timer_list watchdog_timer; struct work_struct tx_timeout_task; @@ -899,16 +889,12 @@ struct netxen_adapter { u32 cmd_producer; __le32 *cmd_consumer; - u32 last_cmd_consumer; + u32 max_tx_desc_count; u32 max_rx_desc_count; u32 max_jumbo_rx_desc_count; u32 max_lro_rx_desc_count; - /* Num of instances active on cmd buffer ring */ - u32 proc_cmd_buf_counter; - - u32 num_threads, total_threads; /*Use to keep track of xmit threads */ u32 flags; u32 irq; @@ -942,6 +928,7 @@ struct netxen_adapter { struct pci_dev *ctx_desc_pdev; dma_addr_t ctx_desc_phys_addr; int intr_scheme; + int msi_mode; int (*enable_phy_interrupts) (struct netxen_adapter *); int (*disable_phy_interrupts) (struct netxen_adapter *); void (*handle_phy_intr) (struct netxen_adapter *); @@ -1075,12 +1062,10 @@ void netxen_tso_check(struct netxen_adapter *adapter, struct cmd_desc_type0 *desc, struct sk_buff *skb); int netxen_nic_hw_resources(struct netxen_adapter *adapter); void netxen_nic_clear_stats(struct netxen_adapter *adapter); -int netxen_nic_rx_has_work(struct netxen_adapter *adapter); -int netxen_nic_tx_has_work(struct netxen_adapter *adapter); void netxen_watchdog_task(struct work_struct *work); void netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ctx, u32 ringid); -int netxen_process_cmd_ring(unsigned long data); +int netxen_process_cmd_ring(struct netxen_adapter *adapter); u32 netxen_process_rcv_ring(struct netxen_adapter *adapter, int ctx, int max); void netxen_nic_set_multi(struct net_device *netdev); int netxen_nic_change_mtu(struct net_device *netdev, int new_mtu); diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c index 7a876f4b8db..6e98d830eef 100644 --- a/drivers/net/netxen/netxen_nic_ethtool.c +++ b/drivers/net/netxen/netxen_nic_ethtool.c @@ -64,15 +64,7 @@ static const struct netxen_nic_stats netxen_nic_gstrings_stats[] = { {"bad_skb_len", NETXEN_NIC_STAT(stats.badskblen)}, {"no_cmd_desc", NETXEN_NIC_STAT(stats.nocmddescriptor)}, {"polled", NETXEN_NIC_STAT(stats.polled)}, - {"uphappy", NETXEN_NIC_STAT(stats.uphappy)}, - {"updropped", NETXEN_NIC_STAT(stats.updropped)}, - {"uplcong", NETXEN_NIC_STAT(stats.uplcong)}, - {"uphcong", NETXEN_NIC_STAT(stats.uphcong)}, - {"upmcong", NETXEN_NIC_STAT(stats.upmcong)}, - {"updunno", NETXEN_NIC_STAT(stats.updunno)}, - {"skb_freed", NETXEN_NIC_STAT(stats.skbfreed)}, {"tx_dropped", NETXEN_NIC_STAT(stats.txdropped)}, - {"tx_null_skb", NETXEN_NIC_STAT(stats.txnullskb)}, {"csummed", NETXEN_NIC_STAT(stats.csummed)}, {"no_rcv", NETXEN_NIC_STAT(stats.no_rcv)}, {"rx_bytes", NETXEN_NIC_STAT(stats.rxbytes)}, diff --git a/drivers/net/netxen/netxen_nic_hdr.h b/drivers/net/netxen/netxen_nic_hdr.h index d72f8f8fcb5..160f605e58d 100644 --- a/drivers/net/netxen/netxen_nic_hdr.h +++ b/drivers/net/netxen/netxen_nic_hdr.h @@ -456,6 +456,12 @@ enum { #define ISR_INT_MASK_SLOW (NETXEN_PCIX_PS_REG(PCIX_INT_MASK)) #define ISR_INT_TARGET_STATUS (NETXEN_PCIX_PS_REG(PCIX_TARGET_STATUS)) #define ISR_INT_TARGET_MASK (NETXEN_PCIX_PS_REG(PCIX_TARGET_MASK)) +#define ISR_INT_TARGET_STATUS_F1 (NETXEN_PCIX_PS_REG(PCIX_TARGET_STATUS_F1)) +#define ISR_INT_TARGET_MASK_F1 (NETXEN_PCIX_PS_REG(PCIX_TARGET_MASK_F1)) +#define ISR_INT_TARGET_STATUS_F2 (NETXEN_PCIX_PS_REG(PCIX_TARGET_STATUS_F2)) +#define ISR_INT_TARGET_MASK_F2 (NETXEN_PCIX_PS_REG(PCIX_TARGET_MASK_F2)) +#define ISR_INT_TARGET_STATUS_F3 (NETXEN_PCIX_PS_REG(PCIX_TARGET_STATUS_F3)) +#define ISR_INT_TARGET_MASK_F3 (NETXEN_PCIX_PS_REG(PCIX_TARGET_MASK_F3)) #define NETXEN_PCI_MAPSIZE 128 #define NETXEN_PCI_DDR_NET (0x00000000UL) @@ -662,6 +668,12 @@ enum { #define PCIX_TARGET_STATUS (0x10118) #define PCIX_TARGET_MASK (0x10128) +#define PCIX_TARGET_STATUS_F1 (0x10160) +#define PCIX_TARGET_MASK_F1 (0x10170) +#define PCIX_TARGET_STATUS_F2 (0x10164) +#define PCIX_TARGET_MASK_F2 (0x10174) +#define PCIX_TARGET_STATUS_F3 (0x10168) +#define PCIX_TARGET_MASK_F3 (0x10178) #define PCIX_MSI_F0 (0x13000) #define PCIX_MSI_F1 (0x13004) diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index 01355701bf8..05748ca6f21 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -398,6 +398,8 @@ int netxen_nic_hw_resources(struct netxen_adapter *adapter) NETXEN_CRB_NORMALIZE(adapter, CRB_NIC_CAPABILITIES_FW)); printk(KERN_NOTICE "%s: FW capabilities:0x%x\n", netxen_nic_driver_name, adapter->intr_scheme); + adapter->msi_mode = readl( + NETXEN_CRB_NORMALIZE(adapter, CRB_NIC_MSI_MODE_FW)); DPRINTK(INFO, "Receive Peg ready too. starting stuff\n"); addr = netxen_alloc(adapter->ahw.pdev, diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 9e38bcb3fba..45fa33e0cb9 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -145,6 +145,8 @@ int netxen_init_firmware(struct netxen_adapter *adapter) /* Window 1 call */ writel(INTR_SCHEME_PERPORT, NETXEN_CRB_NORMALIZE(adapter, CRB_NIC_CAPABILITIES_HOST)); + writel(MSI_MODE_MULTIFUNC, + NETXEN_CRB_NORMALIZE(adapter, CRB_NIC_MSI_MODE_HOST)); writel(MPORT_MULTI_FUNCTION_MODE, NETXEN_CRB_NORMALIZE(adapter, CRB_MPORT_MODE)); writel(PHAN_INITIALIZE_ACK, @@ -183,7 +185,6 @@ void netxen_initialize_adapter_sw(struct netxen_adapter *adapter) for (ring = 0; ring < NUM_RCV_DESC_RINGS; ring++) { struct netxen_rx_buffer *rx_buf; rcv_desc = &adapter->recv_ctx[ctxid].rcv_desc[ring]; - rcv_desc->rcv_free = rcv_desc->max_rx_desc_count; rcv_desc->begin_alloc = 0; rx_buf = rcv_desc->rx_buf_arr; num_rx_bufs = rcv_desc->max_rx_desc_count; @@ -974,28 +975,6 @@ int netxen_phantom_init(struct netxen_adapter *adapter, int pegtune_val) return 0; } -int netxen_nic_rx_has_work(struct netxen_adapter *adapter) -{ - int ctx; - - for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) { - struct netxen_recv_context *recv_ctx = - &(adapter->recv_ctx[ctx]); - u32 consumer; - struct status_desc *desc_head; - struct status_desc *desc; - - consumer = recv_ctx->status_rx_consumer; - desc_head = recv_ctx->rcv_status_desc_head; - desc = &desc_head[consumer]; - - if (netxen_get_sts_owner(desc) & STATUS_OWNER_HOST) - return 1; - } - - return 0; -} - static int netxen_nic_check_temp(struct netxen_adapter *adapter) { struct net_device *netdev = adapter->netdev; @@ -1038,7 +1017,6 @@ static int netxen_nic_check_temp(struct netxen_adapter *adapter) void netxen_watchdog_task(struct work_struct *work) { - struct net_device *netdev; struct netxen_adapter *adapter = container_of(work, struct netxen_adapter, watchdog_task); @@ -1048,20 +1026,6 @@ void netxen_watchdog_task(struct work_struct *work) if (adapter->handle_phy_intr) adapter->handle_phy_intr(adapter); - netdev = adapter->netdev; - if ((netif_running(netdev)) && !netif_carrier_ok(netdev) && - netxen_nic_link_ok(adapter) ) { - printk(KERN_INFO "%s %s (port %d), Link is up\n", - netxen_nic_driver_name, netdev->name, adapter->portnum); - netif_carrier_on(netdev); - netif_wake_queue(netdev); - } else if(!(netif_running(netdev)) && netif_carrier_ok(netdev)) { - printk(KERN_ERR "%s %s Link is Down\n", - netxen_nic_driver_name, netdev->name); - netif_carrier_off(netdev); - netif_stop_queue(netdev); - } - mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ); } @@ -1125,7 +1089,7 @@ static void netxen_process_rcv(struct netxen_adapter *adapter, int ctxid, skb = (struct sk_buff *)buffer->skb; if (likely(adapter->rx_csum && - netxen_get_sts_status(sts_data) == STATUS_CKSUM_OK)) { + netxen_get_sts_status(sts_data) == STATUS_CKSUM_OK)) { adapter->stats.csummed++; skb->ip_summed = CHECKSUM_UNNECESSARY; } else @@ -1142,40 +1106,8 @@ static void netxen_process_rcv(struct netxen_adapter *adapter, int ctxid, skb->protocol = eth_type_trans(skb, netdev); ret = netif_receive_skb(skb); - - /* - * RH: Do we need these stats on a regular basis. Can we get it from - * Linux stats. - */ - switch (ret) { - case NET_RX_SUCCESS: - adapter->stats.uphappy++; - break; - - case NET_RX_CN_LOW: - adapter->stats.uplcong++; - break; - - case NET_RX_CN_MOD: - adapter->stats.upmcong++; - break; - - case NET_RX_CN_HIGH: - adapter->stats.uphcong++; - break; - - case NET_RX_DROP: - adapter->stats.updropped++; - break; - - default: - adapter->stats.updunno++; - break; - } - netdev->last_rx = jiffies; - rcv_desc->rcv_free++; rcv_desc->rcv_pending--; /* @@ -1200,13 +1132,6 @@ u32 netxen_process_rcv_ring(struct netxen_adapter *adapter, int ctxid, int max) u32 producer = 0; int count = 0, ring; - DPRINTK(INFO, "procesing receive\n"); - /* - * we assume in this case that there is only one port and that is - * port #1...changes need to be done in firmware to indicate port - * number as part of the descriptor. This way we will be able to get - * the netdev which is associated with that device. - */ while (count < max) { desc = &desc_head[consumer]; if (!(netxen_get_sts_owner(desc) & STATUS_OWNER_HOST)) { @@ -1219,11 +1144,8 @@ u32 netxen_process_rcv_ring(struct netxen_adapter *adapter, int ctxid, int max) consumer = (consumer + 1) & (adapter->max_rx_desc_count - 1); count++; } - if (count) { - for (ring = 0; ring < NUM_RCV_DESC_RINGS; ring++) { - netxen_post_rx_buffers_nodb(adapter, ctxid, ring); - } - } + for (ring = 0; ring < NUM_RCV_DESC_RINGS; ring++) + netxen_post_rx_buffers_nodb(adapter, ctxid, ring); /* update the consumer index in phantom */ if (count) { @@ -1233,108 +1155,60 @@ u32 netxen_process_rcv_ring(struct netxen_adapter *adapter, int ctxid, int max) /* Window = 1 */ writel(consumer, NETXEN_CRB_NORMALIZE(adapter, - recv_crb_registers[adapter->portnum]. + recv_crb_registers[adapter->portnum]. crb_rcv_status_consumer)); - wmb(); } return count; } /* Process Command status ring */ -int netxen_process_cmd_ring(unsigned long data) +int netxen_process_cmd_ring(struct netxen_adapter *adapter) { - u32 last_consumer; - u32 consumer; - struct netxen_adapter *adapter = (struct netxen_adapter *)data; - int count1 = 0; - int count2 = 0; + u32 last_consumer, consumer; + int count = 0, i; struct netxen_cmd_buffer *buffer; - struct pci_dev *pdev; + struct pci_dev *pdev = adapter->pdev; + struct net_device *netdev = adapter->netdev; struct netxen_skb_frag *frag; - u32 i; - int done; + int done = 0; - spin_lock(&adapter->tx_lock); last_consumer = adapter->last_cmd_consumer; - DPRINTK(INFO, "procesing xmit complete\n"); - /* we assume in this case that there is only one port and that is - * port #1...changes need to be done in firmware to indicate port - * number as part of the descriptor. This way we will be able to get - * the netdev which is associated with that device. - */ - consumer = le32_to_cpu(*(adapter->cmd_consumer)); - if (last_consumer == consumer) { /* Ring is empty */ - DPRINTK(INFO, "last_consumer %d == consumer %d\n", - last_consumer, consumer); - spin_unlock(&adapter->tx_lock); - return 1; - } - - adapter->proc_cmd_buf_counter++; - /* - * Not needed - does not seem to be used anywhere. - * adapter->cmd_consumer = consumer; - */ - spin_unlock(&adapter->tx_lock); - while ((last_consumer != consumer) && (count1 < MAX_STATUS_HANDLE)) { + while (last_consumer != consumer) { buffer = &adapter->cmd_buf_arr[last_consumer]; - pdev = adapter->pdev; if (buffer->skb) { frag = &buffer->frag_array[0]; pci_unmap_single(pdev, frag->dma, frag->length, PCI_DMA_TODEVICE); frag->dma = 0ULL; for (i = 1; i < buffer->frag_count; i++) { - DPRINTK(INFO, "getting fragment no %d\n", i); frag++; /* Get the next frag */ pci_unmap_page(pdev, frag->dma, frag->length, PCI_DMA_TODEVICE); frag->dma = 0ULL; } - adapter->stats.skbfreed++; + adapter->stats.xmitfinished++; dev_kfree_skb_any(buffer->skb); buffer->skb = NULL; - } else if (adapter->proc_cmd_buf_counter == 1) { - adapter->stats.txnullskb++; - } - if (unlikely(netif_queue_stopped(adapter->netdev) - && netif_carrier_ok(adapter->netdev)) - && ((jiffies - adapter->netdev->trans_start) > - adapter->netdev->watchdog_timeo)) { - SCHEDULE_WORK(&adapter->tx_timeout_task); } last_consumer = get_next_index(last_consumer, adapter->max_tx_desc_count); - count1++; + if (++count >= MAX_STATUS_HANDLE) + break; } - count2 = 0; - spin_lock(&adapter->tx_lock); - if ((--adapter->proc_cmd_buf_counter) == 0) { + if (count) { adapter->last_cmd_consumer = last_consumer; - while ((adapter->last_cmd_consumer != consumer) - && (count2 < MAX_STATUS_HANDLE)) { - buffer = - &adapter->cmd_buf_arr[adapter->last_cmd_consumer]; - count2++; - if (buffer->skb) - break; - else - adapter->last_cmd_consumer = - get_next_index(adapter->last_cmd_consumer, - adapter->max_tx_desc_count); - } - } - if (count1 || count2) { - if (netif_queue_stopped(adapter->netdev) - && (adapter->flags & NETXEN_NETDEV_STATUS)) { - netif_wake_queue(adapter->netdev); - adapter->flags &= ~NETXEN_NETDEV_STATUS; + smp_mb(); + if (netif_queue_stopped(netdev) && netif_running(netdev)) { + netif_tx_lock(netdev); + netif_wake_queue(netdev); + smp_mb(); + netif_tx_unlock(netdev); } } /* @@ -1350,16 +1224,9 @@ int netxen_process_cmd_ring(unsigned long data) * There is still a possible race condition and the host could miss an * interrupt. The card has to take care of this. */ - if (adapter->last_cmd_consumer == consumer && - (((adapter->cmd_producer + 1) % - adapter->max_tx_desc_count) == adapter->last_cmd_consumer)) { - consumer = le32_to_cpu(*(adapter->cmd_consumer)); - } - done = (adapter->last_cmd_consumer == consumer); + consumer = le32_to_cpu(*(adapter->cmd_consumer)); + done = (last_consumer == consumer); - spin_unlock(&adapter->tx_lock); - DPRINTK(INFO, "last consumer is %d in %s\n", last_consumer, - __FUNCTION__); return (done); } @@ -1433,8 +1300,6 @@ void netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ctx, u32 ringid) rcv_desc->begin_alloc = index; rcv_desc->rcv_pending += count; rcv_desc->producer = producer; - if (rcv_desc->rcv_free >= 32) { - rcv_desc->rcv_free = 0; /* Window = 1 */ writel((producer - 1) & (rcv_desc->max_rx_desc_count - 1), @@ -1458,8 +1323,6 @@ void netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ctx, u32 ringid) writel(msg, DB_NORMALIZE(adapter, NETXEN_RCV_PRODUCER_OFFSET)); - wmb(); - } } } @@ -1523,8 +1386,6 @@ static void netxen_post_rx_buffers_nodb(struct netxen_adapter *adapter, rcv_desc->begin_alloc = index; rcv_desc->rcv_pending += count; rcv_desc->producer = producer; - if (rcv_desc->rcv_free >= 32) { - rcv_desc->rcv_free = 0; /* Window = 1 */ writel((producer - 1) & (rcv_desc->max_rx_desc_count - 1), @@ -1534,21 +1395,9 @@ static void netxen_post_rx_buffers_nodb(struct netxen_adapter *adapter, rcv_desc_crb[ringid]. crb_rcv_producer_offset)); wmb(); - } } } -int netxen_nic_tx_has_work(struct netxen_adapter *adapter) -{ - if (find_diff_among(adapter->last_cmd_consumer, - adapter->cmd_producer, - adapter->max_tx_desc_count) > 0) - return 1; - - return 0; -} - - void netxen_nic_clear_stats(struct netxen_adapter *adapter) { memset(&adapter->stats, 0, sizeof(adapter->stats)); diff --git a/drivers/net/netxen/netxen_nic_isr.c b/drivers/net/netxen/netxen_nic_isr.c index 48a404aa66c..c81313b717b 100644 --- a/drivers/net/netxen/netxen_nic_isr.c +++ b/drivers/net/netxen/netxen_nic_isr.c @@ -59,7 +59,7 @@ struct net_device_stats *netxen_nic_get_stats(struct net_device *netdev) /* packet transmit problems */ stats->tx_errors = adapter->stats.nocmddescriptor; /* no space in linux buffers */ - stats->rx_dropped = adapter->stats.updropped; + stats->rx_dropped = adapter->stats.rxdropped; /* no space available in linux */ stats->tx_dropped = adapter->stats.txdropped; @@ -193,14 +193,14 @@ int netxen_nic_link_ok(struct netxen_adapter *adapter) void netxen_nic_xgbe_handle_phy_intr(struct netxen_adapter *adapter) { struct net_device *netdev = adapter->netdev; - u32 val, val1; + u32 val; /* WINDOW = 1 */ val = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_XG_STATE)); val >>= (physical_port[adapter->portnum] * 8); - val1 = val & 0xff; + val &= 0xff; - if (adapter->ahw.xg_linkup == 1 && val1 != XG_LINK_UP) { + if (adapter->ahw.xg_linkup == 1 && val != XG_LINK_UP) { printk(KERN_INFO "%s: %s NIC Link is down\n", netxen_nic_driver_name, netdev->name); adapter->ahw.xg_linkup = 0; @@ -208,16 +208,7 @@ void netxen_nic_xgbe_handle_phy_intr(struct netxen_adapter *adapter) netif_carrier_off(netdev); netif_stop_queue(netdev); } - /* read twice to clear sticky bits */ - /* WINDOW = 0 */ - netxen_nic_read_w0(adapter, NETXEN_NIU_XG_STATUS, &val1); - netxen_nic_read_w0(adapter, NETXEN_NIU_XG_STATUS, &val1); - - if ((val & 0xffb) != 0xffb) { - printk(KERN_INFO "%s ISR: Sync/Align BAD: 0x%08x\n", - netxen_nic_driver_name, val1); - } - } else if (adapter->ahw.xg_linkup == 0 && val1 == XG_LINK_UP) { + } else if (adapter->ahw.xg_linkup == 0 && val == XG_LINK_UP) { printk(KERN_INFO "%s: %s NIC Link is up\n", netxen_nic_driver_name, netdev->name); adapter->ahw.xg_linkup = 1; diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 9737eae5ef1..a8fb439a4d0 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -63,12 +63,12 @@ static int netxen_nic_xmit_frame(struct sk_buff *, struct net_device *); static void netxen_tx_timeout(struct net_device *netdev); static void netxen_tx_timeout_task(struct work_struct *work); static void netxen_watchdog(unsigned long); -static int netxen_handle_int(struct netxen_adapter *, struct net_device *); static int netxen_nic_poll(struct napi_struct *napi, int budget); #ifdef CONFIG_NET_POLL_CONTROLLER static void netxen_nic_poll_controller(struct net_device *netdev); #endif static irqreturn_t netxen_intr(int irq, void *data); +static irqreturn_t netxen_msi_intr(int irq, void *data); int physical_port[] = {0, 1, 2, 3}; @@ -149,33 +149,30 @@ static void netxen_nic_update_cmd_consumer(struct netxen_adapter *adapter, #define ADAPTER_LIST_SIZE 12 +static uint32_t msi_tgt_status[4] = { + ISR_INT_TARGET_STATUS, ISR_INT_TARGET_STATUS_F1, + ISR_INT_TARGET_STATUS_F2, ISR_INT_TARGET_STATUS_F3 +}; + +static uint32_t sw_int_mask[4] = { + CRB_SW_INT_MASK_0, CRB_SW_INT_MASK_1, + CRB_SW_INT_MASK_2, CRB_SW_INT_MASK_3 +}; + static void netxen_nic_disable_int(struct netxen_adapter *adapter) { - uint32_t mask = 0x7ff; + u32 mask = 0x7ff; int retries = 32; + int port = adapter->portnum; + int pci_fn = adapter->ahw.pci_func; - DPRINTK(1, INFO, "Entered ISR Disable \n"); - - switch (adapter->portnum) { - case 0: - writel(0x0, NETXEN_CRB_NORMALIZE(adapter, CRB_SW_INT_MASK_0)); - break; - case 1: - writel(0x0, NETXEN_CRB_NORMALIZE(adapter, CRB_SW_INT_MASK_1)); - break; - case 2: - writel(0x0, NETXEN_CRB_NORMALIZE(adapter, CRB_SW_INT_MASK_2)); - break; - case 3: - writel(0x0, NETXEN_CRB_NORMALIZE(adapter, CRB_SW_INT_MASK_3)); - break; - } + if (adapter->msi_mode != MSI_MODE_MULTIFUNC) + writel(0x0, NETXEN_CRB_NORMALIZE(adapter, sw_int_mask[port])); if (adapter->intr_scheme != -1 && adapter->intr_scheme != INTR_SCHEME_PERPORT) writel(mask,PCI_OFFSET_SECOND_RANGE(adapter, ISR_INT_MASK)); - /* Window = 0 or 1 */ if (!(adapter->flags & NETXEN_NIC_MSI_ENABLED)) { do { writel(0xffffffff, @@ -190,14 +187,18 @@ static void netxen_nic_disable_int(struct netxen_adapter *adapter) printk(KERN_NOTICE "%s: Failed to disable interrupt completely\n", netxen_nic_driver_name); } + } else { + if (adapter->msi_mode == MSI_MODE_MULTIFUNC) { + writel(0xffffffff, PCI_OFFSET_SECOND_RANGE(adapter, + msi_tgt_status[pci_fn])); + } } - - DPRINTK(1, INFO, "Done with Disable Int\n"); } static void netxen_nic_enable_int(struct netxen_adapter *adapter) { u32 mask; + int port = adapter->portnum; DPRINTK(1, INFO, "Entered ISR Enable \n"); @@ -218,20 +219,7 @@ static void netxen_nic_enable_int(struct netxen_adapter *adapter) writel(mask, PCI_OFFSET_SECOND_RANGE(adapter, ISR_INT_MASK)); } - switch (adapter->portnum) { - case 0: - writel(0x1, NETXEN_CRB_NORMALIZE(adapter, CRB_SW_INT_MASK_0)); - break; - case 1: - writel(0x1, NETXEN_CRB_NORMALIZE(adapter, CRB_SW_INT_MASK_1)); - break; - case 2: - writel(0x1, NETXEN_CRB_NORMALIZE(adapter, CRB_SW_INT_MASK_2)); - break; - case 3: - writel(0x1, NETXEN_CRB_NORMALIZE(adapter, CRB_SW_INT_MASK_3)); - break; - } + writel(0x1, NETXEN_CRB_NORMALIZE(adapter, sw_int_mask[port])); if (!(adapter->flags & NETXEN_NIC_MSI_ENABLED)) { mask = 0xbff; @@ -328,7 +316,6 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) adapter->ahw.pdev = pdev; adapter->ahw.pci_func = pci_func_id; - spin_lock_init(&adapter->tx_lock); /* remap phys address */ mem_base = pci_resource_start(pdev, 0); /* 0 is for BAR 0 */ @@ -401,6 +388,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /* this will be read from FW later */ adapter->intr_scheme = -1; + adapter->msi_mode = -1; /* This will be reset for mezz cards */ adapter->portnum = pci_func_id; @@ -415,7 +403,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) netdev->set_mac_address = netxen_nic_set_mac; netdev->change_mtu = netxen_nic_change_mtu; netdev->tx_timeout = netxen_tx_timeout; - netdev->watchdog_timeo = HZ; + netdev->watchdog_timeo = 2*HZ; netxen_nic_change_mtu(netdev, netdev->mtu); @@ -543,7 +531,6 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) adapter->watchdog_timer.data = (unsigned long)adapter; INIT_WORK(&adapter->watchdog_task, netxen_watchdog_task); adapter->ahw.pdev = pdev; - adapter->proc_cmd_buf_counter = 0; adapter->ahw.revision_id = pdev->revision; /* make sure Window == 1 */ @@ -833,6 +820,8 @@ static int netxen_nic_open(struct net_device *netdev) struct netxen_adapter *adapter = (struct netxen_adapter *)netdev->priv; int err = 0; int ctx, ring; + irq_handler_t handler; + unsigned long flags = IRQF_SAMPLE_RANDOM; if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC) { err = netxen_init_firmware(adapter); @@ -856,9 +845,14 @@ static int netxen_nic_open(struct net_device *netdev) netxen_post_rx_buffers(adapter, ctx, ring); } adapter->irq = adapter->ahw.pdev->irq; - err = request_irq(adapter->ahw.pdev->irq, netxen_intr, - IRQF_SHARED|IRQF_SAMPLE_RANDOM, netdev->name, - adapter); + if (adapter->flags & NETXEN_NIC_MSI_ENABLED) + handler = netxen_msi_intr; + else { + flags |= IRQF_SHARED; + handler = netxen_intr; + } + err = request_irq(adapter->irq, handler, + flags, netdev->name, adapter); if (err) { printk(KERN_ERR "request_irq failed with: %d\n", err); netxen_free_hw_resources(adapter); @@ -867,21 +861,12 @@ static int netxen_nic_open(struct net_device *netdev) adapter->is_up = NETXEN_ADAPTER_UP_MAGIC; } - if (!adapter->driver_mismatch) - mod_timer(&adapter->watchdog_timer, jiffies); - - napi_enable(&adapter->napi); - - netxen_nic_enable_int(adapter); - /* Done here again so that even if phantom sw overwrote it, * we set it */ if (adapter->init_port && adapter->init_port(adapter, adapter->portnum) != 0) { - del_timer_sync(&adapter->watchdog_timer); printk(KERN_ERR "%s: Failed to initialize port %d\n", netxen_nic_driver_name, adapter->portnum); - napi_disable(&adapter->napi); return -EIO; } if (adapter->macaddr_set) @@ -894,6 +879,12 @@ static int netxen_nic_open(struct net_device *netdev) adapter->set_mtu(adapter, netdev->mtu); if (!adapter->driver_mismatch) + mod_timer(&adapter->watchdog_timer, jiffies); + + napi_enable(&adapter->napi); + netxen_nic_enable_int(adapter); + + if (!adapter->driver_mismatch) netif_start_queue(netdev); return 0; @@ -958,41 +949,17 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) struct netxen_skb_frag *buffrag; unsigned int i; - u32 producer = 0; + u32 producer, consumer; u32 saved_producer = 0; struct cmd_desc_type0 *hwdesc; int k; struct netxen_cmd_buffer *pbuf = NULL; - static int dropped_packet = 0; int frag_count; - u32 local_producer = 0; - u32 max_tx_desc_count = 0; - u32 last_cmd_consumer = 0; int no_of_desc; + u32 num_txd = adapter->max_tx_desc_count; - adapter->stats.xmitcalled++; frag_count = skb_shinfo(skb)->nr_frags + 1; - if (unlikely(skb->len <= 0)) { - dev_kfree_skb_any(skb); - adapter->stats.badskblen++; - return NETDEV_TX_OK; - } - - if (frag_count > MAX_BUFFERS_PER_CMD) { - printk("%s: %s netxen_nic_xmit_frame: frag_count (%d) " - "too large, can handle only %d frags\n", - netxen_nic_driver_name, netdev->name, - frag_count, MAX_BUFFERS_PER_CMD); - adapter->stats.txdropped++; - if ((++dropped_packet & 0xff) == 0xff) - printk("%s: %s droppped packets = %d\n", - netxen_nic_driver_name, netdev->name, - dropped_packet); - - return NETDEV_TX_OK; - } - /* There 4 fragments per descriptor */ no_of_desc = (frag_count + 3) >> 2; if (netdev->features & NETIF_F_TSO) { @@ -1007,27 +974,16 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) } } - spin_lock_bh(&adapter->tx_lock); - if (adapter->total_threads >= MAX_XMIT_PRODUCERS) { - goto out_requeue; - } - local_producer = adapter->cmd_producer; - k = adapter->cmd_producer; - max_tx_desc_count = adapter->max_tx_desc_count; - last_cmd_consumer = adapter->last_cmd_consumer; - if ((k + no_of_desc) >= - ((last_cmd_consumer <= k) ? last_cmd_consumer + max_tx_desc_count : - last_cmd_consumer)) { - goto out_requeue; + producer = adapter->cmd_producer; + smp_mb(); + consumer = adapter->last_cmd_consumer; + if ((no_of_desc+2) > find_diff_among(producer, consumer, num_txd)) { + netif_stop_queue(netdev); + smp_mb(); + return NETDEV_TX_BUSY; } - k = get_index_range(k, max_tx_desc_count, no_of_desc); - adapter->cmd_producer = k; - adapter->total_threads++; - adapter->num_threads++; - spin_unlock_bh(&adapter->tx_lock); /* Copy the descriptors into the hardware */ - producer = local_producer; saved_producer = producer; hwdesc = &hw->cmd_desc_head[producer]; memset(hwdesc, 0, sizeof(struct cmd_desc_type0)); @@ -1067,8 +1023,7 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) /* move to next desc. if there is a need */ if ((i & 0x3) == 0) { k = 0; - producer = get_next_index(producer, - adapter->max_tx_desc_count); + producer = get_next_index(producer, num_txd); hwdesc = &hw->cmd_desc_head[producer]; memset(hwdesc, 0, sizeof(struct cmd_desc_type0)); pbuf = &adapter->cmd_buf_arr[producer]; @@ -1086,7 +1041,6 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) buffrag->dma = temp_dma; buffrag->length = temp_len; - DPRINTK(INFO, "for loop. i=%d k=%d\n", i, k); switch (k) { case 0: hwdesc->buffer1_length = cpu_to_le16(temp_len); @@ -1107,7 +1061,7 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) } frag++; } - producer = get_next_index(producer, adapter->max_tx_desc_count); + producer = get_next_index(producer, num_txd); /* might change opcode to TX_TCP_LSO */ netxen_tso_check(adapter, &hw->cmd_desc_head[saved_producer], skb); @@ -1134,7 +1088,7 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) /* copy the first 64 bytes */ memcpy(((void *)hwdesc) + 2, (void *)(skb->data), first_hdr_len); - producer = get_next_index(producer, max_tx_desc_count); + producer = get_next_index(producer, num_txd); if (more_hdr) { hwdesc = &hw->cmd_desc_head[producer]; @@ -1147,35 +1101,19 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) hwdesc, (hdr_len - first_hdr_len)); - producer = get_next_index(producer, max_tx_desc_count); + producer = get_next_index(producer, num_txd); } } - spin_lock_bh(&adapter->tx_lock); + adapter->cmd_producer = producer; adapter->stats.txbytes += skb->len; - /* Code to update the adapter considering how many producer threads - are currently working */ - if ((--adapter->num_threads) == 0) { - /* This is the last thread */ - u32 crb_producer = adapter->cmd_producer; - netxen_nic_update_cmd_producer(adapter, crb_producer); - wmb(); - adapter->total_threads = 0; - } + netxen_nic_update_cmd_producer(adapter, adapter->cmd_producer); - adapter->stats.xmitfinished++; + adapter->stats.xmitcalled++; netdev->trans_start = jiffies; - spin_unlock_bh(&adapter->tx_lock); return NETDEV_TX_OK; - -out_requeue: - netif_stop_queue(netdev); - adapter->flags |= NETXEN_NETDEV_STATUS; - - spin_unlock_bh(&adapter->tx_lock); - return NETDEV_TX_BUSY; } static void netxen_watchdog(unsigned long v) @@ -1200,87 +1138,60 @@ static void netxen_tx_timeout_task(struct work_struct *work) printk(KERN_ERR "%s %s: transmit timeout, resetting.\n", netxen_nic_driver_name, adapter->netdev->name); - netxen_nic_close(adapter->netdev); - netxen_nic_open(adapter->netdev); + netxen_nic_disable_int(adapter); + napi_disable(&adapter->napi); + adapter->netdev->trans_start = jiffies; + + napi_enable(&adapter->napi); + netxen_nic_enable_int(adapter); netif_wake_queue(adapter->netdev); } -static int -netxen_handle_int(struct netxen_adapter *adapter, struct net_device *netdev) +static inline void +netxen_handle_int(struct netxen_adapter *adapter) { - u32 ret = 0; - - DPRINTK(INFO, "Entered handle ISR\n"); - adapter->stats.ints++; - netxen_nic_disable_int(adapter); - - if (netxen_nic_rx_has_work(adapter) || netxen_nic_tx_has_work(adapter)) { - if (netif_rx_schedule_prep(netdev, &adapter->napi)) { - /* - * Interrupts are already disabled. - */ - __netif_rx_schedule(netdev, &adapter->napi); - } else { - static unsigned int intcount = 0; - if ((++intcount & 0xfff) == 0xfff) - DPRINTK(KERN_ERR - "%s: %s interrupt %d while in poll\n", - netxen_nic_driver_name, netdev->name, - intcount); - } - ret = 1; - } - - if (ret == 0) { - netxen_nic_enable_int(adapter); - } - - return ret; + napi_schedule(&adapter->napi); } -/* - * netxen_intr - Interrupt Handler - * @irq: interrupt number - * data points to adapter stucture (which may be handling more than 1 port - */ irqreturn_t netxen_intr(int irq, void *data) { struct netxen_adapter *adapter = data; - struct net_device *netdev = adapter->netdev; u32 our_int = 0; - if (!(adapter->flags & NETXEN_NIC_MSI_ENABLED)) { - our_int = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_INT_VECTOR)); - /* not our interrupt */ - if ((our_int & (0x80 << adapter->portnum)) == 0) - return IRQ_NONE; - } + our_int = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_INT_VECTOR)); + /* not our interrupt */ + if ((our_int & (0x80 << adapter->portnum)) == 0) + return IRQ_NONE; if (adapter->intr_scheme == INTR_SCHEME_PERPORT) { /* claim interrupt */ - if (!(adapter->flags & NETXEN_NIC_MSI_ENABLED)) { - writel(our_int & ~((u32)(0x80 << adapter->portnum)), + writel(our_int & ~((u32)(0x80 << adapter->portnum)), NETXEN_CRB_NORMALIZE(adapter, CRB_INT_VECTOR)); - } } - if (netif_running(netdev)) - netxen_handle_int(adapter, netdev); + netxen_handle_int(adapter); return IRQ_HANDLED; } +irqreturn_t netxen_msi_intr(int irq, void *data) +{ + struct netxen_adapter *adapter = data; + + netxen_handle_int(adapter); + return IRQ_HANDLED; +} + static int netxen_nic_poll(struct napi_struct *napi, int budget) { struct netxen_adapter *adapter = container_of(napi, struct netxen_adapter, napi); - struct net_device *netdev = adapter->netdev; - int done = 1; + int tx_complete; int ctx; int work_done; - DPRINTK(INFO, "polling for %d descriptors\n", *budget); + tx_complete = netxen_process_cmd_ring(adapter); work_done = 0; for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) { @@ -1300,16 +1211,8 @@ static int netxen_nic_poll(struct napi_struct *napi, int budget) budget / MAX_RCV_CTX); } - if (work_done >= budget) - done = 0; - - if (netxen_process_cmd_ring((unsigned long)adapter) == 0) - done = 0; - - DPRINTK(INFO, "new work_done: %d work_to_do: %d\n", - work_done, work_to_do); - if (done) { - netif_rx_complete(netdev, napi); + if ((work_done < budget) && tx_complete) { + netif_rx_complete(adapter->netdev, &adapter->napi); netxen_nic_enable_int(adapter); } diff --git a/drivers/net/netxen/netxen_nic_phan_reg.h b/drivers/net/netxen/netxen_nic_phan_reg.h index ffa3b7215ce..a566b50f36f 100644 --- a/drivers/net/netxen/netxen_nic_phan_reg.h +++ b/drivers/net/netxen/netxen_nic_phan_reg.h @@ -126,8 +126,11 @@ */ #define CRB_NIC_CAPABILITIES_HOST NETXEN_NIC_REG(0x1a8) #define CRB_NIC_CAPABILITIES_FW NETXEN_NIC_REG(0x1dc) +#define CRB_NIC_MSI_MODE_HOST NETXEN_NIC_REG(0x270) +#define CRB_NIC_MSI_MODE_FW NETXEN_NIC_REG(0x274) #define INTR_SCHEME_PERPORT 0x1 +#define MSI_MODE_MULTIFUNC 0x1 /* used for ethtool tests */ #define CRB_SCRATCHPAD_TEST NETXEN_NIC_REG(0x280) diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index e8a63e483a2..ce95c5d168f 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 f4ca0591231..3ac8529bb92 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 7ed632db00d..d926168bc78 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/phy/marvell.c b/drivers/net/phy/marvell.c index f0574073a2a..33539917e9b 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -58,9 +58,25 @@ #define MII_M1111_RX_DELAY 0x80 #define MII_M1111_TX_DELAY 0x2 #define MII_M1111_PHY_EXT_SR 0x1b -#define MII_M1111_HWCFG_MODE_MASK 0xf -#define MII_M1111_HWCFG_MODE_RGMII 0xb + +#define MII_M1111_HWCFG_MODE_MASK 0xf +#define MII_M1111_HWCFG_MODE_COPPER_RGMII 0xb +#define MII_M1111_HWCFG_MODE_FIBER_RGMII 0x3 #define MII_M1111_HWCFG_MODE_SGMII_NO_CLK 0x4 +#define MII_M1111_HWCFG_FIBER_COPPER_AUTO 0x8000 +#define MII_M1111_HWCFG_FIBER_COPPER_RES 0x2000 + +#define MII_M1111_COPPER 0 +#define MII_M1111_FIBER 1 + +#define MII_M1011_PHY_STATUS 0x11 +#define MII_M1011_PHY_STATUS_1000 0x8000 +#define MII_M1011_PHY_STATUS_100 0x4000 +#define MII_M1011_PHY_STATUS_SPD_MASK 0xc000 +#define MII_M1011_PHY_STATUS_FULLDUPLEX 0x2000 +#define MII_M1011_PHY_STATUS_RESOLVED 0x0800 +#define MII_M1011_PHY_STATUS_LINK 0x0400 + MODULE_DESCRIPTION("Marvell PHY driver"); MODULE_AUTHOR("Andy Fleming"); @@ -141,12 +157,22 @@ static int marvell_config_aneg(struct phy_device *phydev) static int m88e1111_config_init(struct phy_device *phydev) { int err; + int temp; + int mode; + + /* Enable Fiber/Copper auto selection */ + temp = phy_read(phydev, MII_M1111_PHY_EXT_SR); + temp |= MII_M1111_HWCFG_FIBER_COPPER_AUTO; + phy_write(phydev, MII_M1111_PHY_EXT_SR, temp); + + temp = phy_read(phydev, MII_BMCR); + temp |= BMCR_RESET; + phy_write(phydev, MII_BMCR, temp); if ((phydev->interface == PHY_INTERFACE_MODE_RGMII) || (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) || (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) || (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)) { - int temp; temp = phy_read(phydev, MII_M1111_PHY_EXT_CR); if (temp < 0) @@ -171,7 +197,13 @@ static int m88e1111_config_init(struct phy_device *phydev) return temp; temp &= ~(MII_M1111_HWCFG_MODE_MASK); - temp |= MII_M1111_HWCFG_MODE_RGMII; + + mode = phy_read(phydev, MII_M1111_PHY_EXT_CR); + + if (mode & MII_M1111_HWCFG_FIBER_COPPER_RES) + temp |= MII_M1111_HWCFG_MODE_FIBER_RGMII; + else + temp |= MII_M1111_HWCFG_MODE_COPPER_RGMII; err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp); if (err < 0) @@ -262,6 +294,93 @@ static int m88e1145_config_init(struct phy_device *phydev) return 0; } +/* marvell_read_status + * + * Generic status code does not detect Fiber correctly! + * Description: + * Check the link, then figure out the current state + * by comparing what we advertise with what the link partner + * advertises. Start by checking the gigabit possibilities, + * then move on to 10/100. + */ +static int marvell_read_status(struct phy_device *phydev) +{ + int adv; + int err; + int lpa; + int status = 0; + + /* Update the link, but return if there + * was an error */ + err = genphy_update_link(phydev); + if (err) + return err; + + if (AUTONEG_ENABLE == phydev->autoneg) { + status = phy_read(phydev, MII_M1011_PHY_STATUS); + if (status < 0) + return status; + + lpa = phy_read(phydev, MII_LPA); + if (lpa < 0) + return lpa; + + adv = phy_read(phydev, MII_ADVERTISE); + if (adv < 0) + return adv; + + lpa &= adv; + + if (status & MII_M1011_PHY_STATUS_FULLDUPLEX) + phydev->duplex = DUPLEX_FULL; + else + phydev->duplex = DUPLEX_HALF; + + status = status & MII_M1011_PHY_STATUS_SPD_MASK; + phydev->pause = phydev->asym_pause = 0; + + switch (status) { + case MII_M1011_PHY_STATUS_1000: + phydev->speed = SPEED_1000; + break; + + case MII_M1011_PHY_STATUS_100: + phydev->speed = SPEED_100; + break; + + default: + phydev->speed = SPEED_10; + break; + } + + if (phydev->duplex == DUPLEX_FULL) { + phydev->pause = lpa & LPA_PAUSE_CAP ? 1 : 0; + phydev->asym_pause = lpa & LPA_PAUSE_ASYM ? 1 : 0; + } + } else { + int bmcr = phy_read(phydev, MII_BMCR); + + if (bmcr < 0) + return bmcr; + + if (bmcr & BMCR_FULLDPLX) + phydev->duplex = DUPLEX_FULL; + else + phydev->duplex = DUPLEX_HALF; + + if (bmcr & BMCR_SPEED1000) + phydev->speed = SPEED_1000; + else if (bmcr & BMCR_SPEED100) + phydev->speed = SPEED_100; + else + phydev->speed = SPEED_10; + + phydev->pause = phydev->asym_pause = 0; + } + + return 0; +} + static struct phy_driver marvell_drivers[] = { { .phy_id = 0x01410c60, @@ -296,7 +415,7 @@ static struct phy_driver marvell_drivers[] = { .flags = PHY_HAS_INTERRUPT, .config_init = &m88e1111_config_init, .config_aneg = &marvell_config_aneg, - .read_status = &genphy_read_status, + .read_status = &marvell_read_status, .ack_interrupt = &marvell_ack_interrupt, .config_intr = &marvell_config_intr, .driver = { .owner = THIS_MODULE }, diff --git a/drivers/net/pppol2tp.c b/drivers/net/pppol2tp.c index e0b072d9fdb..3d10ca050b7 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++; @@ -455,6 +455,7 @@ static void pppol2tp_recv_dequeue(struct pppol2tp_session *session) skb_queue_len(&session->reorder_q)); __skb_unlink(skb, &session->reorder_q); kfree_skb(skb); + sock_put(session->sock); continue; } @@ -469,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 @@ -1058,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; @@ -1106,10 +1112,12 @@ 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]) { + struct sk_buff *skb; + session = hlist_entry(walk, struct pppol2tp_session, hlist); sk = session->sock; @@ -1126,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)) { @@ -1138,7 +1146,10 @@ again: /* Purge any queued data */ skb_queue_purge(&sk->sk_receive_queue); skb_queue_purge(&sk->sk_write_queue); - skb_queue_purge(&session->reorder_q); + while ((skb = skb_dequeue(&session->reorder_q))) { + kfree_skb(skb); + sock_put(sk); + } release_sock(sk); sock_put(sk); @@ -1148,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. @@ -1161,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); @@ -1239,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); } @@ -1386,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 @@ -1593,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); @@ -2199,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) { @@ -2217,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; @@ -2228,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/ps3_gelic_wireless.c b/drivers/net/ps3_gelic_wireless.c index daf5abab953..ddbc6e475e2 100644 --- a/drivers/net/ps3_gelic_wireless.c +++ b/drivers/net/ps3_gelic_wireless.c @@ -1644,13 +1644,24 @@ static void gelic_wl_scan_complete_event(struct gelic_wl_info *wl) } /* put them in the newtork_list */ - scan_info = wl->buf; - scan_info_size = 0; - i = 0; - while (scan_info_size < data_len) { + for (i = 0, scan_info_size = 0, scan_info = wl->buf; + scan_info_size < data_len; + i++, scan_info_size += be16_to_cpu(scan_info->size), + scan_info = (void *)scan_info + be16_to_cpu(scan_info->size)) { pr_debug("%s:size=%d bssid=%s scan_info=%p\n", __func__, be16_to_cpu(scan_info->size), print_mac(mac, &scan_info->bssid[2]), scan_info); + + /* + * The wireless firmware may return invalid channel 0 and/or + * invalid rate if the AP emits zero length SSID ie. As this + * scan information is useless, ignore it + */ + if (!be16_to_cpu(scan_info->channel) || !scan_info->rate[0]) { + pr_debug("%s: invalid scan info\n", __func__); + continue; + } + found = 0; oldest = NULL; list_for_each_entry(target, &wl->network_list, list) { @@ -1687,10 +1698,6 @@ static void gelic_wl_scan_complete_event(struct gelic_wl_info *wl) GFP_KERNEL); if (!target->hwinfo) { pr_info("%s: kzalloc failed\n", __func__); - i++; - scan_info_size += be16_to_cpu(scan_info->size); - scan_info = (void *)scan_info + - be16_to_cpu(scan_info->size); continue; } /* copy hw scan info */ @@ -1709,10 +1716,6 @@ static void gelic_wl_scan_complete_event(struct gelic_wl_info *wl) if (scan_info->ext_rate[r]) target->rate_ext_len++; list_move_tail(&target->list, &wl->network_list); - /* bump pointer */ - i++; - scan_info_size += be16_to_cpu(scan_info->size); - scan_info = (void *)scan_info + be16_to_cpu(scan_info->size); } memset(&data, 0, sizeof(data)); wireless_send_event(port_to_netdev(wl_port(wl)), SIOCGIWSCAN, &data, @@ -2389,6 +2392,8 @@ static struct net_device *gelic_wl_alloc(struct gelic_card *card) if (!netdev) return NULL; + strcpy(netdev->name, "wlan%d"); + port = netdev_priv(netdev); port->netdev = netdev; port->card = card; diff --git a/drivers/net/r6040.c b/drivers/net/r6040.c index 19184e486ae..169edc15492 100644 --- a/drivers/net/r6040.c +++ b/drivers/net/r6040.c @@ -239,7 +239,8 @@ static void r6040_free_txbufs(struct net_device *dev) for (i = 0; i < TX_DCNT; i++) { if (lp->tx_insert_ptr->skb_ptr) { - pci_unmap_single(lp->pdev, lp->tx_insert_ptr->buf, + pci_unmap_single(lp->pdev, + le32_to_cpu(lp->tx_insert_ptr->buf), MAX_BUF_SIZE, PCI_DMA_TODEVICE); dev_kfree_skb(lp->tx_insert_ptr->skb_ptr); lp->rx_insert_ptr->skb_ptr = NULL; @@ -255,7 +256,8 @@ static void r6040_free_rxbufs(struct net_device *dev) for (i = 0; i < RX_DCNT; i++) { if (lp->rx_insert_ptr->skb_ptr) { - pci_unmap_single(lp->pdev, lp->rx_insert_ptr->buf, + pci_unmap_single(lp->pdev, + le32_to_cpu(lp->rx_insert_ptr->buf), MAX_BUF_SIZE, PCI_DMA_FROMDEVICE); dev_kfree_skb(lp->rx_insert_ptr->skb_ptr); lp->rx_insert_ptr->skb_ptr = NULL; @@ -542,7 +544,7 @@ static int r6040_rx(struct net_device *dev, int limit) skb_ptr->dev = priv->dev; /* Do not count the CRC */ skb_put(skb_ptr, descptr->len - 4); - pci_unmap_single(priv->pdev, descptr->buf, + pci_unmap_single(priv->pdev, le32_to_cpu(descptr->buf), MAX_BUF_SIZE, PCI_DMA_FROMDEVICE); skb_ptr->protocol = eth_type_trans(skb_ptr, priv->dev); /* Send to upper layer */ @@ -585,7 +587,7 @@ static void r6040_tx(struct net_device *dev) if (descptr->status & 0x8000) break; /* Not complete */ skb_ptr = descptr->skb_ptr; - pci_unmap_single(priv->pdev, descptr->buf, + pci_unmap_single(priv->pdev, le32_to_cpu(descptr->buf), skb_ptr->len, PCI_DMA_TODEVICE); /* Free buffer */ dev_kfree_skb_irq(skb_ptr); diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 6179a0a2032..3c915b82e19 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; @@ -4172,6 +4172,9 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; spin_unlock_irqrestore(&fifo->tx_lock, flags); + if (sp->config.intr_type == MSI_X) + tx_intr_handler(fifo); + return 0; pci_map_failed: stats->pci_map_fail_cnt++; diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 186eb8ebfda..2e26dced13a 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -3199,12 +3199,14 @@ static int skge_poll(struct napi_struct *napi, int to_do) skge_write8(hw, Q_ADDR(rxqaddr[skge->port], Q_CSR), CSR_START); if (work_done < to_do) { - spin_lock_irq(&hw->hw_lock); + unsigned long flags; + + spin_lock_irqsave(&hw->hw_lock, flags); __netif_rx_complete(dev, napi); hw->intr_mask |= napimask[skge->port]; skge_write32(hw, B0_IMSK, hw->intr_mask); skge_read32(hw, B0_IMSK); - spin_unlock_irq(&hw->hw_lock); + spin_unlock_irqrestore(&hw->hw_lock, flags); } return work_done; diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h index 51d4134b37b..98a832a7553 100644 --- a/drivers/net/smc91x.h +++ b/drivers/net/smc91x.h @@ -92,14 +92,14 @@ #define SMC_insw(a, r, p, l) insw ((unsigned long *)((a) + (r)), p, l) # endif /* check if the mac in reg is valid */ -#define SMC_GET_MAC_ADDR(addr) \ +#define SMC_GET_MAC_ADDR(lp, addr) \ do { \ unsigned int __v; \ - __v = SMC_inw(ioaddr, ADDR0_REG); \ + __v = SMC_inw(ioaddr, ADDR0_REG(lp)); \ addr[0] = __v; addr[1] = __v >> 8; \ - __v = SMC_inw(ioaddr, ADDR1_REG); \ + __v = SMC_inw(ioaddr, ADDR1_REG(lp)); \ addr[2] = __v; addr[3] = __v >> 8; \ - __v = SMC_inw(ioaddr, ADDR2_REG); \ + __v = SMC_inw(ioaddr, ADDR2_REG(lp)); \ addr[4] = __v; addr[5] = __v >> 8; \ if (*(u32 *)(&addr[0]) == 0xFFFFFFFF) { \ random_ether_addr(addr); \ diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c index 97212799c51..4291458955e 100644 --- a/drivers/net/sungem.c +++ b/drivers/net/sungem.c @@ -912,7 +912,7 @@ static int gem_poll(struct napi_struct *napi, int budget) * rx ring - must call napi_disable(), which * schedule_timeout()'s if polling is already disabled. */ - work_done += gem_rx(gp, budget); + work_done += gem_rx(gp, budget - work_done); if (work_done >= budget) return work_done; diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 26ffb67f1da..f9ef8bd8b11 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -64,8 +64,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.87" -#define DRV_MODULE_RELDATE "December 20, 2007" +#define DRV_MODULE_VERSION "3.88" +#define DRV_MODULE_RELDATE "March 20, 2008" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 @@ -11841,7 +11841,7 @@ static int __devinit tg3_get_device_address(struct tg3 *tp) } if (!is_valid_ether_addr(&dev->dev_addr[0])) { -#ifdef CONFIG_SPARC64 +#ifdef CONFIG_SPARC if (!tg3_get_default_macaddr_sparc(tp)) return 0; #endif diff --git a/drivers/net/tokenring/smctr.c b/drivers/net/tokenring/smctr.c index 8909050b8ea..5f1c5072b96 100644 --- a/drivers/net/tokenring/smctr.c +++ b/drivers/net/tokenring/smctr.c @@ -3413,7 +3413,7 @@ static int smctr_make_tx_status_code(struct net_device *dev, tsv->svi = TRANSMIT_STATUS_CODE; tsv->svl = S_TRANSMIT_STATUS_CODE; - tsv->svv[0] = ((tx_fstatus & 0x0100 >> 6) || IBM_PASS_SOURCE_ADDR); + tsv->svv[0] = ((tx_fstatus & 0x0100 >> 6) | IBM_PASS_SOURCE_ADDR); /* Stripped frame status of Transmitted Frame */ tsv->svv[1] = tx_fstatus & 0xff; diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c index 77d9dd7ea34..1b5edd646a8 100644 --- a/drivers/net/tulip/de2104x.c +++ b/drivers/net/tulip/de2104x.c @@ -842,7 +842,7 @@ static inline int de_is_running (struct de_private *de) static void de_stop_rxtx (struct de_private *de) { u32 macmode; - unsigned int work = 1000; + unsigned int i = 1300/100; macmode = dr32(MacMode); if (macmode & RxTx) { @@ -850,10 +850,14 @@ static void de_stop_rxtx (struct de_private *de) dr32(MacMode); } - while (--work > 0) { + /* wait until in-flight frame completes. + * Max time @ 10BT: 1500*8b/10Mbps == 1200us (+ 100us margin) + * Typically expect this loop to end in < 50 us on 100BT. + */ + while (--i) { if (!de_is_running(de)) return; - cpu_relax(); + udelay(100); } printk(KERN_WARNING "%s: timeout expired stopping DMA\n", de->dev->name); @@ -910,7 +914,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/tun.c b/drivers/net/tun.c index 038c1ef94d2..7b816a03295 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -663,7 +663,11 @@ static int tun_chr_ioctl(struct inode *inode, struct file *file, case SIOCSIFHWADDR: { /* try to set the actual net device's hw address */ - int ret = dev_set_mac_address(tun->dev, &ifr.ifr_hwaddr); + int ret; + + rtnl_lock(); + ret = dev_set_mac_address(tun->dev, &ifr.ifr_hwaddr); + rtnl_unlock(); if (ret == 0) { /** Set the character device's hardware address. This is used when diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index fba0811d260..8cc316653a3 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -154,8 +154,8 @@ static struct ucc_geth_info ugeth_primary_info = { .rxQoSMode = UCC_GETH_QOS_MODE_DEFAULT, .aufc = UPSMR_AUTOMATIC_FLOW_CONTROL_MODE_NONE, .padAndCrc = MACCFG2_PAD_AND_CRC_MODE_PAD_AND_CRC, - .numThreadsTx = UCC_GETH_NUM_OF_THREADS_4, - .numThreadsRx = UCC_GETH_NUM_OF_THREADS_4, + .numThreadsTx = UCC_GETH_NUM_OF_THREADS_1, + .numThreadsRx = UCC_GETH_NUM_OF_THREADS_1, .riscTx = QE_RISC_ALLOCATION_RISC1_AND_RISC2, .riscRx = QE_RISC_ALLOCATION_RISC1_AND_RISC2, }; @@ -3975,6 +3975,8 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma ug_info->uf_info.utfs = UCC_GETH_UTFS_GIGA_INIT; ug_info->uf_info.utfet = UCC_GETH_UTFET_GIGA_INIT; ug_info->uf_info.utftt = UCC_GETH_UTFTT_GIGA_INIT; + ug_info->numThreadsTx = UCC_GETH_NUM_OF_THREADS_4; + ug_info->numThreadsRx = UCC_GETH_NUM_OF_THREADS_4; } /* Set the bus id */ diff --git a/drivers/net/usb/dm9601.c b/drivers/net/usb/dm9601.c index 4b131a6c6b7..0343b00cf1f 100644 --- a/drivers/net/usb/dm9601.c +++ b/drivers/net/usb/dm9601.c @@ -341,7 +341,7 @@ static void dm9601_set_multicast(struct net_device *net) /* We use the 20 byte dev->data for our 8 byte filter buffer * to avoid allocating memory that is tricky to free later */ u8 *hashes = (u8 *) & dev->data; - u8 rx_ctl = 0x01; + u8 rx_ctl = 0x31; memset(hashes, 0x00, DM_MCAST_SIZE); hashes[DM_MCAST_SIZE - 1] |= 0x80; /* broadcast address */ @@ -562,6 +562,10 @@ static const struct usb_device_id products[] = { USB_DEVICE(0x0a46, 0x8515), /* ADMtek ADM8515 USB NIC */ .driver_info = (unsigned long)&dm9601_info, }, + { + USB_DEVICE(0x0a47, 0x9601), /* Hirose USB-100 */ + .driver_info = (unsigned long)&dm9601_info, + }, {}, // END }; diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c index a61324757b1..369c731114b 100644 --- a/drivers/net/usb/rndis_host.c +++ b/drivers/net/usb/rndis_host.c @@ -16,10 +16,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -// #define DEBUG // error path messages, extra info -// #define VERBOSE // more; success messages - #include <linux/module.h> #include <linux/init.h> #include <linux/netdevice.h> @@ -287,7 +283,7 @@ generic_rndis_bind(struct usbnet *dev, struct usb_interface *intf, int flags) struct rndis_set_c *set_c; struct rndis_halt *halt; } u; - u32 tmp, *phym; + u32 tmp, phym_unspec, *phym; int reply_len; unsigned char *bp; @@ -318,6 +314,14 @@ generic_rndis_bind(struct usbnet *dev, struct usb_interface *intf, int flags) net->hard_header_len += sizeof (struct rndis_data_hdr); dev->hard_mtu = net->mtu + net->hard_header_len; + dev->maxpacket = usb_maxpacket(dev->udev, dev->out, 1); + if (dev->maxpacket == 0) { + if (netif_msg_probe(dev)) + dev_dbg(&intf->dev, "dev->maxpacket can't be 0\n"); + retval = -EINVAL; + goto fail_and_release; + } + dev->rx_urb_size = dev->hard_mtu + (dev->maxpacket + 1); dev->rx_urb_size &= ~(dev->maxpacket - 1); u.init->max_transfer_size = cpu_to_le32(dev->rx_urb_size); @@ -359,12 +363,15 @@ generic_rndis_bind(struct usbnet *dev, struct usb_interface *intf, int flags) goto halt_fail_and_release; /* Check physical medium */ + phym = NULL; reply_len = sizeof *phym; retval = rndis_query(dev, intf, u.buf, OID_GEN_PHYSICAL_MEDIUM, 0, (void **) &phym, &reply_len); - if (retval != 0) + if (retval != 0 || !phym) { /* OID is optional so don't fail here. */ - *phym = RNDIS_PHYSICAL_MEDIUM_UNSPECIFIED; + phym_unspec = RNDIS_PHYSICAL_MEDIUM_UNSPECIFIED; + phym = &phym_unspec; + } if ((flags & FLAG_RNDIS_PHYM_WIRELESS) && *phym != RNDIS_PHYSICAL_MEDIUM_WIRELESS_LAN) { if (netif_msg_probe(dev)) diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c index 7e1f00131f9..df56a518691 100644 --- a/drivers/net/usb/rtl8150.c +++ b/drivers/net/usb/rtl8150.c @@ -376,7 +376,7 @@ static int alloc_all_urbs(rtl8150_t * dev) return 0; } dev->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!dev->intr_urb) { + if (!dev->ctrl_urb) { usb_free_urb(dev->rx_urb); usb_free_urb(dev->tx_urb); usb_free_urb(dev->intr_urb); diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 19fd4cb0ddf..b58472cf76f 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/farsync.c b/drivers/net/wan/farsync.c index cf27bf40d36..547368e9633 100644 --- a/drivers/net/wan/farsync.c +++ b/drivers/net/wan/farsync.c @@ -2024,6 +2024,7 @@ fst_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) struct fstioc_write wrthdr; struct fstioc_info info; unsigned long flags; + void *buf; dbg(DBG_IOCTL, "ioctl: %x, %p\n", cmd, ifr->ifr_data); @@ -2065,16 +2066,22 @@ fst_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) return -ENXIO; } - /* Now copy the data to the card. - * This will probably break on some architectures. - * I'll fix it when I have something to test on. - */ - if (copy_from_user(card->mem + wrthdr.offset, + /* Now copy the data to the card. */ + + buf = kmalloc(wrthdr.size, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + if (copy_from_user(buf, ifr->ifr_data + sizeof (struct fstioc_write), wrthdr.size)) { + kfree(buf); return -EFAULT; } + memcpy_toio(card->mem + wrthdr.offset, buf, wrthdr.size); + kfree(buf); + /* Writes to the memory of a card in the reset state constitute * a download */ diff --git a/drivers/net/wan/sbni.c b/drivers/net/wan/sbni.c index 15d5c58e57b..e59255a155a 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/arlan-proc.c b/drivers/net/wireless/arlan-proc.c index c6e70dbc5de..2ab1d59870f 100644 --- a/drivers/net/wireless/arlan-proc.c +++ b/drivers/net/wireless/arlan-proc.c @@ -1202,13 +1202,6 @@ static ctl_table arlan_table[MAX_ARLANS + 1] = { .ctl_name = 0 } }; #endif -#else - -static ctl_table arlan_table[MAX_ARLANS + 1] = -{ - { .ctl_name = 0 } -}; -#endif // static int mmtu = 1234; @@ -1233,7 +1226,6 @@ static ctl_table arlan_root_table[] = //}; -#ifdef CONFIG_PROC_FS static struct ctl_table_header *arlan_device_sysctl_header; int __init init_arlan_proc(void) diff --git a/drivers/net/wireless/ath5k/hw.c b/drivers/net/wireless/ath5k/hw.c index c2de2d958e8..01757436353 100644 --- a/drivers/net/wireless/ath5k/hw.c +++ b/drivers/net/wireless/ath5k/hw.c @@ -427,6 +427,8 @@ void ath5k_hw_detach(struct ath5k_hw *ah) { ATH5K_TRACE(ah->ah_sc); + __set_bit(ATH_STAT_INVALID, ah->ah_sc->status); + if (ah->ah_rf_banks != NULL) kfree(ah->ah_rf_banks); diff --git a/drivers/net/wireless/b43/debugfs.c b/drivers/net/wireless/b43/debugfs.c index e38ed0fe72e..7fca2ebc747 100644 --- a/drivers/net/wireless/b43/debugfs.c +++ b/drivers/net/wireless/b43/debugfs.c @@ -618,6 +618,7 @@ void b43_debugfs_remove_device(struct b43_wldev *dev) kfree(e); } +/* Called with IRQs disabled. */ void b43_debugfs_log_txstat(struct b43_wldev *dev, const struct b43_txstatus *status) { @@ -629,8 +630,7 @@ void b43_debugfs_log_txstat(struct b43_wldev *dev, if (!e) return; log = &e->txstatlog; - B43_WARN_ON(!irqs_disabled()); - spin_lock(&log->lock); + spin_lock(&log->lock); /* IRQs are already disabled. */ i = log->end + 1; if (i == B43_NR_LOGGED_TXSTATUS) i = 0; diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index 3dfb28a34be..cfbc1a26f60 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c @@ -560,7 +560,7 @@ static int b43_dmacontroller_tx_reset(struct b43_wldev *dev, u16 mmio_base, /* Check if a DMA mapping address is invalid. */ static bool b43_dma_mapping_error(struct b43_dmaring *ring, dma_addr_t addr, - size_t buffersize) + size_t buffersize, bool dma_to_device) { if (unlikely(dma_mapping_error(addr))) return 1; @@ -568,11 +568,11 @@ static bool b43_dma_mapping_error(struct b43_dmaring *ring, switch (ring->type) { case B43_DMA_30BIT: if ((u64)addr + buffersize > (1ULL << 30)) - return 1; + goto address_error; break; case B43_DMA_32BIT: if ((u64)addr + buffersize > (1ULL << 32)) - return 1; + goto address_error; break; case B43_DMA_64BIT: /* Currently we can't have addresses beyond @@ -582,6 +582,12 @@ static bool b43_dma_mapping_error(struct b43_dmaring *ring, /* The address is OK. */ return 0; + +address_error: + /* We can't support this address. Unmap it again. */ + unmap_descbuffer(ring, addr, buffersize, dma_to_device); + + return 1; } static int setup_rx_descbuffer(struct b43_dmaring *ring, @@ -599,7 +605,7 @@ static int setup_rx_descbuffer(struct b43_dmaring *ring, if (unlikely(!skb)) return -ENOMEM; dmaaddr = map_descbuffer(ring, skb->data, ring->rx_buffersize, 0); - if (b43_dma_mapping_error(ring, dmaaddr, ring->rx_buffersize)) { + if (b43_dma_mapping_error(ring, dmaaddr, ring->rx_buffersize, 0)) { /* ugh. try to realloc in zone_dma */ gfp_flags |= GFP_DMA; @@ -612,7 +618,7 @@ static int setup_rx_descbuffer(struct b43_dmaring *ring, ring->rx_buffersize, 0); } - if (b43_dma_mapping_error(ring, dmaaddr, ring->rx_buffersize)) { + if (b43_dma_mapping_error(ring, dmaaddr, ring->rx_buffersize, 0)) { dev_kfree_skb_any(skb); return -EIO; } @@ -852,7 +858,8 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev, b43_txhdr_size(dev), DMA_TO_DEVICE); - if (b43_dma_mapping_error(ring, dma_test, b43_txhdr_size(dev))) { + if (b43_dma_mapping_error(ring, dma_test, + b43_txhdr_size(dev), 1)) { /* ugh realloc */ kfree(ring->txhdr_cache); ring->txhdr_cache = kcalloc(nr_slots, @@ -867,7 +874,7 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev, DMA_TO_DEVICE); if (b43_dma_mapping_error(ring, dma_test, - b43_txhdr_size(dev))) + b43_txhdr_size(dev), 1)) goto err_kfree_txhdr_cache; } @@ -1189,7 +1196,7 @@ static int dma_tx_fragment(struct b43_dmaring *ring, meta_hdr->dmaaddr = map_descbuffer(ring, (unsigned char *)header, hdrsize, 1); - if (b43_dma_mapping_error(ring, meta_hdr->dmaaddr, hdrsize)) { + if (b43_dma_mapping_error(ring, meta_hdr->dmaaddr, hdrsize, 1)) { ring->current_slot = old_top_slot; ring->used_slots = old_used_slots; return -EIO; @@ -1208,7 +1215,7 @@ static int dma_tx_fragment(struct b43_dmaring *ring, meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1); /* create a bounce buffer in zone_dma on mapping failure. */ - if (b43_dma_mapping_error(ring, meta->dmaaddr, skb->len)) { + if (b43_dma_mapping_error(ring, meta->dmaaddr, skb->len, 1)) { bounce_skb = __dev_alloc_skb(skb->len, GFP_ATOMIC | GFP_DMA); if (!bounce_skb) { ring->current_slot = old_top_slot; @@ -1222,7 +1229,7 @@ static int dma_tx_fragment(struct b43_dmaring *ring, skb = bounce_skb; meta->skb = skb; meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1); - if (b43_dma_mapping_error(ring, meta->dmaaddr, skb->len)) { + if (b43_dma_mapping_error(ring, meta->dmaaddr, skb->len, 1)) { ring->current_slot = old_top_slot; ring->used_slots = old_used_slots; err = -EIO; @@ -1337,6 +1344,7 @@ out_unlock: return err; } +/* Called with IRQs disabled. */ void b43_dma_handle_txstatus(struct b43_wldev *dev, const struct b43_txstatus *status) { @@ -1349,8 +1357,8 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, ring = parse_cookie(dev, status->cookie, &slot); if (unlikely(!ring)) return; - B43_WARN_ON(!irqs_disabled()); - spin_lock(&ring->lock); + + spin_lock(&ring->lock); /* IRQs are already disabled. */ B43_WARN_ON(!ring->tx); ops = ring->ops; diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 51dfce16178..c73a75b24cd 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -2049,7 +2049,6 @@ void b43_mac_enable(struct b43_wldev *dev) { dev->mac_suspended--; B43_WARN_ON(dev->mac_suspended < 0); - B43_WARN_ON(irqs_disabled()); if (dev->mac_suspended == 0) { b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL) @@ -2075,7 +2074,6 @@ void b43_mac_suspend(struct b43_wldev *dev) u32 tmp; might_sleep(); - B43_WARN_ON(irqs_disabled()); B43_WARN_ON(dev->mac_suspended < 0); if (dev->mac_suspended == 0) { diff --git a/drivers/net/wireless/b43/phy.c b/drivers/net/wireless/b43/phy.c index 71507b260b6..575c5436ebd 100644 --- a/drivers/net/wireless/b43/phy.c +++ b/drivers/net/wireless/b43/phy.c @@ -860,7 +860,7 @@ static void b43_phy_ww(struct b43_wldev *dev) b43_phy_write(dev, B43_PHY_OFDM(0xBB), (b43_phy_read(dev, B43_PHY_OFDM(0xBB)) & 0xF000) | 0x0053); b43_phy_write(dev, B43_PHY_OFDM61, - (b43_phy_read(dev, B43_PHY_OFDM61 & 0xFE1F)) | 0x0120); + (b43_phy_read(dev, B43_PHY_OFDM61) & 0xFE1F) | 0x0120); b43_phy_write(dev, B43_PHY_OFDM(0x13), (b43_phy_read(dev, B43_PHY_OFDM(0x13)) & 0x0FFF) | 0x3000); b43_phy_write(dev, B43_PHY_OFDM(0x14), diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index c39de422e22..5f3f34e1dbf 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -3829,7 +3829,7 @@ static void b43legacy_print_driverinfo(void) #ifdef CONFIG_B43LEGACY_DMA feat_dma = "D"; #endif - printk(KERN_INFO "Broadcom 43xx driver loaded " + printk(KERN_INFO "Broadcom 43xx-legacy driver loaded " "[ Features: %s%s%s%s%s, Firmware-ID: " B43legacy_SUPPORTED_FIRMWARE_ID " ]\n", feat_pci, feat_leds, feat_rfkill, feat_pio, feat_dma); diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index d1af938b9aa..b79a35a40ab 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig @@ -20,7 +20,7 @@ config IWL4965 runs. If you want to compile the driver as a module ( = code which can be - inserted in and remvoed from the running kernel whenever you want), + inserted in and removed from the running kernel whenever you want), say M here and read <file:Documentation/kbuild/modules.txt>. The module will be called iwl4965.ko. @@ -101,7 +101,7 @@ config IWL3945 runs. If you want to compile the driver as a module ( = code which can be - inserted in and remvoed from the running kernel whenever you want), + inserted in and removed from the running kernel whenever you want), say M here and read <file:Documentation/kbuild/modules.txt>. The module will be called iwl3945.ko. diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 40b71bc2c4a..cbaeaf18649 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -6206,11 +6206,11 @@ static void iwl3945_alive_start(struct iwl3945_priv *priv) /* At this point, the NIC is initialized and operational */ priv->notif_missed_beacons = 0; - set_bit(STATUS_READY, &priv->status); iwl3945_reg_txpower_periodic(priv); IWL_DEBUG_INFO("ALIVE processing complete.\n"); + set_bit(STATUS_READY, &priv->status); wake_up_interruptible(&priv->wait_command_queue); if (priv->error_recovering) @@ -8706,7 +8706,7 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e return err; } -static void iwl3945_pci_remove(struct pci_dev *pdev) +static void __devexit iwl3945_pci_remove(struct pci_dev *pdev) { struct iwl3945_priv *priv = pci_get_drvdata(pdev); struct list_head *p, *q; diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index a23d4798653..60ec29eab85 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -6628,11 +6628,11 @@ static void iwl4965_alive_start(struct iwl4965_priv *priv) /* At this point, the NIC is initialized and operational */ priv->notif_missed_beacons = 0; - set_bit(STATUS_READY, &priv->status); iwl4965_rf_kill_ct_config(priv); IWL_DEBUG_INFO("ALIVE processing complete.\n"); + set_bit(STATUS_READY, &priv->status); wake_up_interruptible(&priv->wait_command_queue); if (priv->error_recovering) @@ -9282,7 +9282,7 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e return err; } -static void iwl4965_pci_remove(struct pci_dev *pdev) +static void __devexit iwl4965_pci_remove(struct pci_dev *pdev) { struct iwl4965_priv *priv = pci_get_drvdata(pdev); struct list_head *p, *q; diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index 159216a9190..f0ef7081bde 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -562,9 +562,7 @@ int lbs_process_rx_command(struct lbs_private *priv) } resp = (void *)priv->upld_buf; - - curcmd = le16_to_cpu(resp->command); - + curcmd = le16_to_cpu(priv->cur_cmd->cmdbuf->command); respcmd = le16_to_cpu(resp->command); result = le16_to_cpu(resp->result); @@ -572,15 +570,15 @@ int lbs_process_rx_command(struct lbs_private *priv) respcmd, le16_to_cpu(resp->seqnum), priv->upld_len, jiffies); lbs_deb_hex(LBS_DEB_HOST, "CMD_RESP", (void *) resp, priv->upld_len); - if (resp->seqnum != resp->seqnum) { + if (resp->seqnum != priv->cur_cmd->cmdbuf->seqnum) { lbs_pr_info("Received CMD_RESP with invalid sequence %d (expected %d)\n", - le16_to_cpu(resp->seqnum), le16_to_cpu(resp->seqnum)); + le16_to_cpu(resp->seqnum), le16_to_cpu(priv->cur_cmd->cmdbuf->seqnum)); spin_unlock_irqrestore(&priv->driver_lock, flags); ret = -1; 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/p54common.c b/drivers/net/wireless/p54common.c index 5cda49aff3a..d191e055a78 100644 --- a/drivers/net/wireless/p54common.c +++ b/drivers/net/wireless/p54common.c @@ -166,18 +166,23 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) struct p54_common *priv = dev->priv; struct eeprom_pda_wrap *wrap = NULL; struct pda_entry *entry; - int i = 0; unsigned int data_len, entry_len; void *tmp; int err; + u8 *end = (u8 *)eeprom + len; wrap = (struct eeprom_pda_wrap *) eeprom; - entry = (void *)wrap->data + wrap->len; - i += 2; - i += le16_to_cpu(entry->len)*2; - while (i < len) { + entry = (void *)wrap->data + le16_to_cpu(wrap->len); + + /* verify that at least the entry length/code fits */ + while ((u8 *)entry <= end - sizeof(*entry)) { entry_len = le16_to_cpu(entry->len); data_len = ((entry_len - 1) << 1); + + /* abort if entry exceeds whole structure */ + if ((u8 *)entry + sizeof(*entry) + data_len > end) + break; + switch (le16_to_cpu(entry->code)) { case PDR_MAC_ADDRESS: SET_IEEE80211_PERM_ADDR(dev, entry->data); @@ -249,13 +254,12 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) priv->version = *(u8 *)(entry->data + 1); break; case PDR_END: - i = len; + /* make it overrun */ + entry_len = len; break; } entry = (void *)entry + (entry_len + 1)*2; - i += 2; - i += entry_len*2; } if (!priv->iq_autocal || !priv->output_limit || !priv->curve_data) { diff --git a/drivers/net/wireless/p54common.h b/drivers/net/wireless/p54common.h index a721334e20d..b67ff34e26f 100644 --- a/drivers/net/wireless/p54common.h +++ b/drivers/net/wireless/p54common.h @@ -53,10 +53,10 @@ struct pda_entry { } __attribute__ ((packed)); struct eeprom_pda_wrap { - u32 magic; - u16 pad; - u16 len; - u32 arm_opcode; + __le32 magic; + __le16 pad; + __le16 len; + __le32 arm_opcode; u8 data[0]; } __attribute__ ((packed)); diff --git a/drivers/net/wireless/p54usb.c b/drivers/net/wireless/p54usb.c index e7d4aee8799..98ddbb3b327 100644 --- a/drivers/net/wireless/p54usb.c +++ b/drivers/net/wireless/p54usb.c @@ -63,6 +63,7 @@ static struct usb_device_id p54u_table[] __devinitdata = { {USB_DEVICE(0x0cde, 0x0008)}, /* Sagem XG703A */ {USB_DEVICE(0x0d8e, 0x3762)}, /* DLink DWL-G120 Cohiba */ {USB_DEVICE(0x09aa, 0x1000)}, /* Spinnaker Proto board */ + {USB_DEVICE(0x124a, 0x4025)}, /* IOGear GWU513 (GW3887IK chip) */ {USB_DEVICE(0x13b1, 0x000a)}, /* Linksys WUSB54G ver 2 */ {USB_DEVICE(0x13B1, 0x000C)}, /* Linksys WUSB54AG */ {USB_DEVICE(0x1435, 0x0427)}, /* Inventel UR054G */ diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index d9460aed1f2..10b776c1adc 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -260,7 +260,7 @@ struct NDIS_802_11_KEY { __le32 KeyLength; u8 Bssid[6]; u8 Padding[6]; - __le64 KeyRSC; + u8 KeyRSC[8]; u8 KeyMaterial[32]; } __attribute__((packed)); @@ -1508,7 +1508,7 @@ static int rndis_iw_set_encode_ext(struct net_device *dev, struct usbnet *usbdev = dev->priv; struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); struct NDIS_802_11_KEY ndis_key; - int i, keyidx, ret; + int keyidx, ret; u8 *addr; keyidx = wrqu->encoding.flags & IW_ENCODE_INDEX; @@ -1543,9 +1543,7 @@ static int rndis_iw_set_encode_ext(struct net_device *dev, ndis_key.KeyIndex = cpu_to_le32(keyidx); if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) { - for (i = 0; i < 6; i++) - ndis_key.KeyRSC |= - cpu_to_le64(ext->rx_seq[i] << (i * 8)); + memcpy(ndis_key.KeyRSC, ext->rx_seq, 6); ndis_key.KeyIndex |= cpu_to_le32(1 << 29); } diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 05927b908f8..6c725422af5 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -620,6 +620,9 @@ struct rt2x00_dev { * This will only be compiled in when required. */ #ifdef CONFIG_RT2X00_LIB_RFKILL +unsigned long rfkill_state; +#define RFKILL_STATE_ALLOCATED 1 +#define RFKILL_STATE_REGISTERED 2 struct rfkill *rfkill; struct input_polled_dev *poll_dev; #endif /* CONFIG_RT2X00_LIB_RFKILL */ diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 0d51f478bcd..bd305f7f3ef 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -1098,7 +1098,7 @@ static void rt2x00lib_uninitialize(struct rt2x00_dev *rt2x00dev) return; /* - * Unregister rfkill. + * Unregister extra components. */ rt2x00rfkill_unregister(rt2x00dev); @@ -1139,17 +1139,12 @@ static int rt2x00lib_initialize(struct rt2x00_dev *rt2x00dev) __set_bit(DEVICE_INITIALIZED, &rt2x00dev->flags); /* - * Register the rfkill handler. + * Register the extra components. */ - status = rt2x00rfkill_register(rt2x00dev); - if (status) - goto exit_unitialize; + rt2x00rfkill_register(rt2x00dev); return 0; -exit_unitialize: - rt2x00lib_uninitialize(rt2x00dev); - exit: rt2x00lib_free_ring_entries(rt2x00dev); @@ -1313,15 +1308,9 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) } /* - * Allocatie rfkill. - */ - retval = rt2x00rfkill_allocate(rt2x00dev); - if (retval) - goto exit; - - /* - * Open the debugfs entry. + * Register extra components. */ + rt2x00rfkill_allocate(rt2x00dev); rt2x00debug_register(rt2x00dev); __set_bit(DEVICE_PRESENT, &rt2x00dev->flags); @@ -1350,13 +1339,9 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev) rt2x00lib_uninitialize(rt2x00dev); /* - * Close debugfs entry. + * Free extra components */ rt2x00debug_deregister(rt2x00dev); - - /* - * Free rfkill - */ rt2x00rfkill_free(rt2x00dev); /* @@ -1395,11 +1380,15 @@ int rt2x00lib_suspend(struct rt2x00_dev *rt2x00dev, pm_message_t state) __set_bit(DEVICE_STARTED_SUSPEND, &rt2x00dev->flags); /* - * Disable radio and unitialize all items - * that must be recreated on resume. + * Disable radio. */ rt2x00lib_stop(rt2x00dev); rt2x00lib_uninitialize(rt2x00dev); + + /* + * Suspend/disable extra components. + */ + rt2x00rfkill_suspend(rt2x00dev); rt2x00debug_deregister(rt2x00dev); exit: @@ -1422,9 +1411,10 @@ int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev) NOTICE(rt2x00dev, "Waking up.\n"); /* - * Open the debugfs entry. + * Restore/enable extra components. */ rt2x00debug_register(rt2x00dev); + rt2x00rfkill_resume(rt2x00dev); /* * Only continue if mac80211 had open interfaces. diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index 1adbd28e097..ce58c654ade 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -100,28 +100,36 @@ static inline void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev, * RFkill handlers. */ #ifdef CONFIG_RT2X00_LIB_RFKILL -int rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev); +void rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev); void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev); -int rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev); +void rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev); void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev); +void rt2x00rfkill_suspend(struct rt2x00_dev *rt2x00dev); +void rt2x00rfkill_resume(struct rt2x00_dev *rt2x00dev); #else -static inline int rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev) +static inline void rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev) { - return 0; } static inline void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev) { } -static inline int rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev) +static inline void rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev) { - return 0; } static inline void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev) { } + +static inline void rt2x00rfkill_suspend(struct rt2x00_dev *rt2x00dev) +{ +} + +static inline void rt2x00rfkill_resume(struct rt2x00_dev *rt2x00dev) +{ +} #endif /* CONFIG_RT2X00_LIB_RFKILL */ #endif /* RT2X00LIB_H */ diff --git a/drivers/net/wireless/rt2x00/rt2x00rfkill.c b/drivers/net/wireless/rt2x00/rt2x00rfkill.c index 34a96d44e30..f9557759620 100644 --- a/drivers/net/wireless/rt2x00/rt2x00rfkill.c +++ b/drivers/net/wireless/rt2x00/rt2x00rfkill.c @@ -69,56 +69,81 @@ static void rt2x00rfkill_poll(struct input_polled_dev *poll_dev) } } -int rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev) +void rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev) { - int retval; - - if (!test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags)) - return 0; + if (!test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags) || + !test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state)) + return; - retval = rfkill_register(rt2x00dev->rfkill); - if (retval) { + if (rfkill_register(rt2x00dev->rfkill)) { ERROR(rt2x00dev, "Failed to register rfkill handler.\n"); - return retval; + return; } - retval = input_register_polled_device(rt2x00dev->poll_dev); - if (retval) { + if (input_register_polled_device(rt2x00dev->poll_dev)) { ERROR(rt2x00dev, "Failed to register polled device.\n"); rfkill_unregister(rt2x00dev->rfkill); - return retval; + return; } + __set_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state); + /* * Force initial poll which will detect the initial device state, * and correctly sends the signal to the rfkill layer about this * state. */ rt2x00rfkill_poll(rt2x00dev->poll_dev); - - return 0; } void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev) { - if (!test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags)) + if (!test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags) || + !test_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state)) return; input_unregister_polled_device(rt2x00dev->poll_dev); rfkill_unregister(rt2x00dev->rfkill); + + __clear_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state); } -int rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev) +static struct input_polled_dev * +rt2x00rfkill_allocate_polldev(struct rt2x00_dev *rt2x00dev) { - struct device *device = wiphy_dev(rt2x00dev->hw->wiphy); + struct input_polled_dev *poll_dev; + + poll_dev = input_allocate_polled_device(); + if (!poll_dev) + return NULL; + + poll_dev->private = rt2x00dev; + poll_dev->poll = rt2x00rfkill_poll; + poll_dev->poll_interval = RFKILL_POLL_INTERVAL; + + poll_dev->input->name = rt2x00dev->ops->name; + poll_dev->input->phys = wiphy_name(rt2x00dev->hw->wiphy); + poll_dev->input->id.bustype = BUS_HOST; + poll_dev->input->id.vendor = 0x1814; + poll_dev->input->id.product = rt2x00dev->chip.rt; + poll_dev->input->id.version = rt2x00dev->chip.rev; + poll_dev->input->dev.parent = wiphy_dev(rt2x00dev->hw->wiphy); + poll_dev->input->evbit[0] = BIT(EV_KEY); + set_bit(KEY_WLAN, poll_dev->input->keybit); + + return poll_dev; +} +void rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev) +{ if (!test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags)) - return 0; + return; - rt2x00dev->rfkill = rfkill_allocate(device, RFKILL_TYPE_WLAN); + rt2x00dev->rfkill = + rfkill_allocate(wiphy_dev(rt2x00dev->hw->wiphy), RFKILL_TYPE_WLAN); if (!rt2x00dev->rfkill) { ERROR(rt2x00dev, "Failed to allocate rfkill handler.\n"); - goto exit; + return; } rt2x00dev->rfkill->name = rt2x00dev->ops->name; @@ -126,40 +151,49 @@ int rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev) rt2x00dev->rfkill->state = -1; rt2x00dev->rfkill->toggle_radio = rt2x00rfkill_toggle_radio; - rt2x00dev->poll_dev = input_allocate_polled_device(); + rt2x00dev->poll_dev = rt2x00rfkill_allocate_polldev(rt2x00dev); if (!rt2x00dev->poll_dev) { ERROR(rt2x00dev, "Failed to allocate polled device.\n"); - goto exit_free_rfkill; + rfkill_free(rt2x00dev->rfkill); + rt2x00dev->rfkill = NULL; + return; } - rt2x00dev->poll_dev->private = rt2x00dev; - rt2x00dev->poll_dev->poll = rt2x00rfkill_poll; - rt2x00dev->poll_dev->poll_interval = RFKILL_POLL_INTERVAL; + return; +} - rt2x00dev->poll_dev->input->name = rt2x00dev->ops->name; - rt2x00dev->poll_dev->input->phys = wiphy_name(rt2x00dev->hw->wiphy); - rt2x00dev->poll_dev->input->id.bustype = BUS_HOST; - rt2x00dev->poll_dev->input->id.vendor = 0x1814; - rt2x00dev->poll_dev->input->id.product = rt2x00dev->chip.rt; - rt2x00dev->poll_dev->input->id.version = rt2x00dev->chip.rev; - rt2x00dev->poll_dev->input->dev.parent = device; - rt2x00dev->poll_dev->input->evbit[0] = BIT(EV_KEY); - set_bit(KEY_WLAN, rt2x00dev->poll_dev->input->keybit); +void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev) +{ + if (!test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags) || + !test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state)) + return; - return 0; + input_free_polled_device(rt2x00dev->poll_dev); + rt2x00dev->poll_dev = NULL; -exit_free_rfkill: rfkill_free(rt2x00dev->rfkill); - -exit: - return -ENOMEM; + rt2x00dev->rfkill = NULL; } -void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev) +void rt2x00rfkill_suspend(struct rt2x00_dev *rt2x00dev) { - if (!test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags)) + if (!test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags) || + !test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state)) return; input_free_polled_device(rt2x00dev->poll_dev); - rfkill_free(rt2x00dev->rfkill); + rt2x00dev->poll_dev = NULL; +} + +void rt2x00rfkill_resume(struct rt2x00_dev *rt2x00dev) +{ + if (!test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags) || + !test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state)) + return; + + rt2x00dev->poll_dev = rt2x00rfkill_allocate_polldev(rt2x00dev); + if (!rt2x00dev->poll_dev) { + ERROR(rt2x00dev, "Failed to allocate polled device.\n"); + return; + } } diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index e808db98f2f..93ea212fedd 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 4fac2d414d8..3909cf42f47 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; @@ -2095,9 +2095,12 @@ static struct usb_device_id rt73usb_device_table[] = { { USB_DEVICE(0x1371, 0x9032), USB_DEVICE_DATA(&rt73usb_ops) }, /* Conceptronic */ { USB_DEVICE(0x14b2, 0x3c22), USB_DEVICE_DATA(&rt73usb_ops) }, + /* Corega */ + { USB_DEVICE(0x07aa, 0x002e), USB_DEVICE_DATA(&rt73usb_ops) }, /* 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/net/wireless/wavelan_cs.h b/drivers/net/wireless/wavelan_cs.h index fabc63ee153..2e4bfe4147c 100644 --- a/drivers/net/wireless/wavelan_cs.h +++ b/drivers/net/wireless/wavelan_cs.h @@ -309,7 +309,7 @@ struct mmw_t #define MMW_EXT_ANT_INTERNAL 0x00 /* Internal antenna */ #define MMW_EXT_ANT_EXTERNAL 0x03 /* External antenna */ #define MMW_EXT_ANT_IQ_TEST 0x1C /* IQ test pattern (set to 0) */ -}; +} __attribute__((packed)); /* Size for structure checking (if padding is correct) */ #define MMW_SIZE 37 diff --git a/drivers/parisc/Kconfig b/drivers/parisc/Kconfig index 1d3b84b4af3..553a9905299 100644 --- a/drivers/parisc/Kconfig +++ b/drivers/parisc/Kconfig @@ -103,6 +103,11 @@ config IOMMU_SBA depends on PCI_LBA default PCI_LBA +config IOMMU_HELPER + bool + depends on IOMMU_SBA || IOMMU_CCIO + default y + #config PCI_EPIC # bool "EPIC/SAGA PCI support" # depends on PCI diff --git a/drivers/parisc/ccio-dma.c b/drivers/parisc/ccio-dma.c index d08b284de19..62db3c3fe4d 100644 --- a/drivers/parisc/ccio-dma.c +++ b/drivers/parisc/ccio-dma.c @@ -43,6 +43,7 @@ #include <linux/proc_fs.h> #include <linux/seq_file.h> #include <linux/scatterlist.h> +#include <linux/iommu-helper.h> #include <asm/byteorder.h> #include <asm/cache.h> /* for L1_CACHE_BYTES */ @@ -302,13 +303,17 @@ static int ioc_count; */ #define CCIO_SEARCH_LOOP(ioc, res_idx, mask, size) \ for(; res_ptr < res_end; ++res_ptr) { \ - if(0 == (*res_ptr & mask)) { \ - *res_ptr |= mask; \ - res_idx = (unsigned int)((unsigned long)res_ptr - (unsigned long)ioc->res_map); \ - ioc->res_hint = res_idx + (size >> 3); \ - goto resource_found; \ - } \ - } + int ret;\ + unsigned int idx;\ + idx = (unsigned int)((unsigned long)res_ptr - (unsigned long)ioc->res_map); \ + ret = iommu_is_span_boundary(idx << 3, pages_needed, 0, boundary_size);\ + if ((0 == (*res_ptr & mask)) && !ret) { \ + *res_ptr |= mask; \ + res_idx = idx;\ + ioc->res_hint = res_idx + (size >> 3); \ + goto resource_found; \ + } \ + } #define CCIO_FIND_FREE_MAPPING(ioa, res_idx, mask, size) \ u##size *res_ptr = (u##size *)&((ioc)->res_map[ioa->res_hint & ~((size >> 3) - 1)]); \ @@ -341,10 +346,11 @@ static int ioc_count; * of available pages for the requested size. */ static int -ccio_alloc_range(struct ioc *ioc, size_t size) +ccio_alloc_range(struct ioc *ioc, struct device *dev, size_t size) { unsigned int pages_needed = size >> IOVP_SHIFT; unsigned int res_idx; + unsigned long boundary_size; #ifdef CCIO_SEARCH_TIME unsigned long cr_start = mfctl(16); #endif @@ -360,6 +366,9 @@ ccio_alloc_range(struct ioc *ioc, size_t size) ** ggg sacrifices another 710 to the computer gods. */ + boundary_size = ALIGN((unsigned long long)dma_get_seg_boundary(dev) + 1, + 1ULL << IOVP_SHIFT) >> IOVP_SHIFT; + if (pages_needed <= 8) { /* * LAN traffic will not thrash the TLB IFF the same NIC @@ -760,7 +769,7 @@ ccio_map_single(struct device *dev, void *addr, size_t size, ioc->msingle_pages += size >> IOVP_SHIFT; #endif - idx = ccio_alloc_range(ioc, size); + idx = ccio_alloc_range(ioc, dev, size); iovp = (dma_addr_t)MKIOVP(idx); pdir_start = &(ioc->pdir_base[idx]); diff --git a/drivers/parisc/iommu-helpers.h b/drivers/parisc/iommu-helpers.h index 97ba8286c59..a9c46cc2db3 100644 --- a/drivers/parisc/iommu-helpers.h +++ b/drivers/parisc/iommu-helpers.h @@ -96,8 +96,8 @@ iommu_fill_pdir(struct ioc *ioc, struct scatterlist *startsg, int nents, static inline unsigned int iommu_coalesce_chunks(struct ioc *ioc, struct device *dev, - struct scatterlist *startsg, int nents, - int (*iommu_alloc_range)(struct ioc *, size_t)) + struct scatterlist *startsg, int nents, + int (*iommu_alloc_range)(struct ioc *, struct device *, size_t)) { struct scatterlist *contig_sg; /* contig chunk head */ unsigned long dma_offset, dma_len; /* start/len of DMA stream */ @@ -166,7 +166,7 @@ iommu_coalesce_chunks(struct ioc *ioc, struct device *dev, dma_len = ALIGN(dma_len + dma_offset, IOVP_SIZE); sg_dma_address(contig_sg) = PIDE_FLAG - | (iommu_alloc_range(ioc, dma_len) << IOVP_SHIFT) + | (iommu_alloc_range(ioc, dev, dma_len) << IOVP_SHIFT) | dma_offset; n_mappings++; } diff --git a/drivers/parisc/pdc_stable.c b/drivers/parisc/pdc_stable.c index de34aa9d313..f9f9a5f1bbd 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 d06627c3f35..8c4d2c13d5f 100644 --- a/drivers/parisc/sba_iommu.c +++ b/drivers/parisc/sba_iommu.c @@ -29,6 +29,7 @@ #include <linux/string.h> #include <linux/pci.h> #include <linux/scatterlist.h> +#include <linux/iommu-helper.h> #include <asm/byteorder.h> #include <asm/io.h> @@ -313,6 +314,12 @@ 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) +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; +} /** * sba_search_bitmap - find free space in IO PDIR resource bitmap @@ -324,19 +331,36 @@ sba_dump_sg( struct ioc *ioc, struct scatterlist *startsg, int nents) * Cool perf optimization: search for log2(size) bits at a time. */ static SBA_INLINE unsigned long -sba_search_bitmap(struct ioc *ioc, unsigned long bits_wanted) +sba_search_bitmap(struct ioc *ioc, struct device *dev, + unsigned long bits_wanted) { unsigned long *res_ptr = ioc->res_hint; unsigned long *res_end = (unsigned long *) &(ioc->res_map[ioc->res_size]); - unsigned long pide = ~0UL; + unsigned long pide = ~0UL, tpide; + unsigned long boundary_size; + unsigned long shift; + int ret; + + boundary_size = ALIGN((unsigned long long)dma_get_seg_boundary(dev) + 1, + 1ULL << IOVP_SHIFT) >> IOVP_SHIFT; + +#if defined(ZX1_SUPPORT) + BUG_ON(ioc->ibase & ~IOVP_MASK); + shift = ioc->ibase >> IOVP_SHIFT; +#else + shift = 0; +#endif if (bits_wanted > (BITS_PER_LONG/2)) { /* Search word at a time - no mask needed */ for(; res_ptr < res_end; ++res_ptr) { - if (*res_ptr == 0) { + tpide = ptr_to_pide(ioc, res_ptr, 0); + ret = iommu_is_span_boundary(tpide, bits_wanted, + shift, + boundary_size); + if ((*res_ptr == 0) && !ret) { *res_ptr = RESMAP_MASK(bits_wanted); - pide = ((unsigned long)res_ptr - (unsigned long)ioc->res_map); - pide <<= 3; /* convert to bit address */ + pide = tpide; break; } } @@ -365,11 +389,13 @@ sba_search_bitmap(struct ioc *ioc, unsigned long bits_wanted) { DBG_RES(" %p %lx %lx\n", res_ptr, mask, *res_ptr); WARN_ON(mask == 0); - if(((*res_ptr) & mask) == 0) { + tpide = ptr_to_pide(ioc, res_ptr, bitshiftcnt); + ret = iommu_is_span_boundary(tpide, bits_wanted, + shift, + boundary_size); + if ((((*res_ptr) & mask) == 0) && !ret) { *res_ptr |= mask; /* mark resources busy! */ - pide = ((unsigned long)res_ptr - (unsigned long)ioc->res_map); - pide <<= 3; /* convert to bit address */ - pide += bitshiftcnt; + pide = tpide; break; } mask >>= o; @@ -404,7 +430,7 @@ sba_search_bitmap(struct ioc *ioc, unsigned long bits_wanted) * resource bit map. */ static int -sba_alloc_range(struct ioc *ioc, size_t size) +sba_alloc_range(struct ioc *ioc, struct device *dev, size_t size) { unsigned int pages_needed = size >> IOVP_SHIFT; #ifdef SBA_COLLECT_STATS @@ -412,9 +438,9 @@ sba_alloc_range(struct ioc *ioc, size_t size) #endif unsigned long pide; - pide = sba_search_bitmap(ioc, pages_needed); + pide = sba_search_bitmap(ioc, dev, pages_needed); if (pide >= (ioc->res_size << 3)) { - pide = sba_search_bitmap(ioc, pages_needed); + pide = sba_search_bitmap(ioc, dev, pages_needed); if (pide >= (ioc->res_size << 3)) panic("%s: I/O MMU @ %p is out of mapping resources\n", __FILE__, ioc->ioc_hpa); @@ -710,7 +736,7 @@ sba_map_single(struct device *dev, void *addr, size_t size, ioc->msingle_calls++; ioc->msingle_pages += size >> IOVP_SHIFT; #endif - pide = sba_alloc_range(ioc, size); + pide = sba_alloc_range(ioc, dev, size); iovp = (dma_addr_t) pide << IOVP_SHIFT; DBG_RUN("%s() 0x%p -> 0x%lx\n", diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index ef5a6a245f5..d708358326e 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c @@ -143,15 +143,21 @@ 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) + if (retval) + dev_err(&dev->dev, "Error registering pci_bus," + " continuing...\n"); + else { + child_bus->is_added = 1; retval = device_create_file(&child_bus->dev, &dev_attr_cpuaffinity); + } if (retval) - dev_err(&dev->dev, "Error registering pci_bus" - " device bridge symlink," - " continuing...\n"); + dev_err(&dev->dev, "Error creating cpuaffinity" + " file, continuing...\n"); } } } diff --git a/drivers/pci/hotplug-pci.c b/drivers/pci/hotplug-pci.c index a590ef68215..4d4a6447840 100644 --- a/drivers/pci/hotplug-pci.c +++ b/drivers/pci/hotplug-pci.c @@ -4,7 +4,7 @@ #include "pci.h" -unsigned int pci_do_scan_bus(struct pci_bus *bus) +unsigned int __devinit pci_do_scan_bus(struct pci_bus *bus) { unsigned int max; diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index cf22f9e01e0..5e50008d118 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -1085,7 +1085,7 @@ static int acpiphp_bus_trim(acpi_handle handle) * This function should be called per *physical slot*, * not per each slot object in ACPI namespace. */ -static int enable_device(struct acpiphp_slot *slot) +static int __ref enable_device(struct acpiphp_slot *slot) { struct pci_dev *dev; struct pci_bus *bus = slot->bridge->pci_bus; diff --git a/drivers/pci/hotplug/cpci_hotplug_pci.c b/drivers/pci/hotplug/cpci_hotplug_pci.c index 5e9be44817c..b3515fc4cd3 100644 --- a/drivers/pci/hotplug/cpci_hotplug_pci.c +++ b/drivers/pci/hotplug/cpci_hotplug_pci.c @@ -250,7 +250,7 @@ int cpci_led_off(struct slot* slot) * Device configuration functions */ -int cpci_configure_slot(struct slot* slot) +int __ref cpci_configure_slot(struct slot *slot) { struct pci_bus *parent; int fn; diff --git a/drivers/pci/hotplug/ibmphp_ebda.c b/drivers/pci/hotplug/ibmphp_ebda.c index 600ed7b67ae..bbccde9f228 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 7f4836b8e71..5fa4ba0d993 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/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 6eba9b2cfb9..698975a6a21 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -711,7 +711,8 @@ static int hpc_power_off_slot(struct slot * slot) retval = pcie_write_cmd(slot, slot_cmd, cmd_mask); if (retval) { err("%s: Write command failed!\n", __FUNCTION__); - return -1; + retval = -1; + goto out; } dbg("%s: SLOTCTRL %x write cmd %x\n", __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd); @@ -722,7 +723,7 @@ static int hpc_power_off_slot(struct slot * slot) * removed from the slot/adapter. */ msleep(1000); - + out: if (changed) pcie_unmask_bad_dllp(ctrl); diff --git a/drivers/pci/hotplug/pciehp_pci.c b/drivers/pci/hotplug/pciehp_pci.c index dd50713966d..9372a840b63 100644 --- a/drivers/pci/hotplug/pciehp_pci.c +++ b/drivers/pci/hotplug/pciehp_pci.c @@ -167,7 +167,7 @@ static void program_fw_provided_values(struct pci_dev *dev) } } -static int pciehp_add_bridge(struct pci_dev *dev) +static int __ref pciehp_add_bridge(struct pci_dev *dev) { struct pci_bus *parent = dev->bus; int pass, busnr, start = parent->secondary; diff --git a/drivers/pci/hotplug/shpchp_pci.c b/drivers/pci/hotplug/shpchp_pci.c index 0a6b25ef194..a69a2152089 100644 --- a/drivers/pci/hotplug/shpchp_pci.c +++ b/drivers/pci/hotplug/shpchp_pci.c @@ -96,7 +96,7 @@ static void program_fw_provided_values(struct pci_dev *dev) } } -int shpchp_configure_device(struct slot *p_slot) +int __ref shpchp_configure_device(struct slot *p_slot) { struct pci_dev *dev; struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate; diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c index 977d29b3229..4cb949f0ebd 100644 --- a/drivers/pci/intel-iommu.c +++ b/drivers/pci/intel-iommu.c @@ -1097,6 +1097,8 @@ static void iommu_free_domain(struct dmar_domain *domain) } static struct iova_domain reserved_iova_list; +static struct lock_class_key reserved_alloc_key; +static struct lock_class_key reserved_rbtree_key; static void dmar_init_reserved_ranges(void) { @@ -1107,6 +1109,11 @@ static void dmar_init_reserved_ranges(void) init_iova_domain(&reserved_iova_list, DMA_32BIT_PFN); + lockdep_set_class(&reserved_iova_list.iova_alloc_lock, + &reserved_alloc_key); + lockdep_set_class(&reserved_iova_list.iova_rbtree_lock, + &reserved_rbtree_key); + /* IOAPIC ranges shouldn't be accessed by DMA */ iova = reserve_iova(&reserved_iova_list, IOVA_PFN(IOAPIC_RANGE_START), IOVA_PFN(IOAPIC_RANGE_END)); diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index 4a23654184f..72f7476930c 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/pci/pci.c b/drivers/pci/pci.c index 183fddaa38b..a4445b7210b 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -314,24 +314,6 @@ int pci_find_ht_capability(struct pci_dev *dev, int ht_cap) } EXPORT_SYMBOL_GPL(pci_find_ht_capability); -void pcie_wait_pending_transaction(struct pci_dev *dev) -{ - int pos; - u16 reg16; - - pos = pci_find_capability(dev, PCI_CAP_ID_EXP); - if (!pos) - return; - while (1) { - pci_read_config_word(dev, pos + PCI_EXP_DEVSTA, ®16); - if (!(reg16 & PCI_EXP_DEVSTA_TRPND)) - break; - cpu_relax(); - } - -} -EXPORT_SYMBOL_GPL(pcie_wait_pending_transaction); - /** * pci_find_parent_resource - return resource region of parent bus of given region * @dev: PCI device structure contains resources to be searched @@ -936,9 +918,6 @@ pci_disable_device(struct pci_dev *dev) if (atomic_sub_return(1, &dev->enable_cnt) != 0) return; - /* Wait for all transactions are finished before disabling the device */ - pcie_wait_pending_transaction(dev); - pci_read_config_word(dev, PCI_COMMAND, &pci_command); if (pci_command & PCI_COMMAND_MASTER) { pci_command &= ~PCI_COMMAND_MASTER; diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 4d23b9fb551..2db2e4bb0d1 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -286,7 +286,7 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom) } } -void pci_read_bridge_bases(struct pci_bus *child) +void __devinit pci_read_bridge_bases(struct pci_bus *child) { struct pci_dev *dev = child->self; u8 io_base_lo, io_limit_lo; @@ -472,7 +472,7 @@ static void pci_fixup_parent_subordinate_busnr(struct pci_bus *child, int max) * them, we proceed to assigning numbers to the remaining buses in * order to avoid overlaps between old and new bus numbers. */ -int pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass) +int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass) { struct pci_bus *child; int is_cardbus = (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS); @@ -1008,7 +1008,7 @@ int pci_scan_slot(struct pci_bus *bus, int devfn) return nr; } -unsigned int pci_scan_child_bus(struct pci_bus *bus) +unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus) { unsigned int devfn, pass, max = bus->secondary; struct pci_dev *dev; @@ -1116,7 +1116,7 @@ err_out: return NULL; } -struct pci_bus *pci_scan_bus_parented(struct device *parent, +struct pci_bus * __devinit pci_scan_bus_parented(struct device *parent, int bus, struct pci_ops *ops, void *sysdata) { struct pci_bus *b; diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index bbad4a9f264..e9a333d9855 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -1652,9 +1652,8 @@ static void __devinit quirk_via_cx700_pci_parking_caching(struct pci_dev *dev) pci_write_config_byte(dev, 0x75, 0x1); pci_write_config_byte(dev, 0x77, 0x0); - printk(KERN_INFO - "PCI: VIA CX700 PCI parking/caching fixup on %s\n", - pci_name(dev)); + dev_info(&dev->dev, + "Disabling VIA CX700 PCI parking/caching\n"); } } } @@ -1726,32 +1725,6 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT2 quirk_msi_ht_cap); -/* - * Force enable MSI mapping capability on HT bridges - */ -static void __devinit quirk_msi_ht_cap_enable(struct pci_dev *dev) -{ - int pos, ttl = 48; - - pos = pci_find_ht_capability(dev, HT_CAPTYPE_MSI_MAPPING); - while (pos && ttl--) { - u8 flags; - - if (pci_read_config_byte(dev, pos + HT_MSI_FLAGS, &flags) == 0) { - printk(KERN_INFO "PCI: Enabling HT MSI Mapping on %s\n", - pci_name(dev)); - - pci_write_config_byte(dev, pos + HT_MSI_FLAGS, - flags | HT_MSI_FLAGS_ENABLE); - } - pos = pci_find_next_ht_capability(dev, pos, - HT_CAPTYPE_MSI_MAPPING); - } -} -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SERVERWORKS, - PCI_DEVICE_ID_SERVERWORKS_HT1000_PXB, - quirk_msi_ht_cap_enable); - /* The nVidia CK804 chipset may have 2 HT MSI mappings. * MSI are supported if the MSI capability set in any of these mappings. */ @@ -1778,9 +1751,8 @@ static void __devinit quirk_nvidia_ck804_msi_ht_cap(struct pci_dev *dev) DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_CK804_PCIE, quirk_nvidia_ck804_msi_ht_cap); -/* - * Force enable MSI mapping capability on HT bridges */ -static inline void ht_enable_msi_mapping(struct pci_dev *dev) +/* Force enable MSI mapping capability on HT bridges */ +static void __devinit ht_enable_msi_mapping(struct pci_dev *dev) { int pos, ttl = 48; @@ -1799,6 +1771,9 @@ static inline void ht_enable_msi_mapping(struct pci_dev *dev) HT_CAPTYPE_MSI_MAPPING); } } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SERVERWORKS, + PCI_DEVICE_ID_SERVERWORKS_HT1000_PXB, + ht_enable_msi_mapping); static void __devinit nv_msi_ht_cap_quirk(struct pci_dev *dev) { @@ -1830,7 +1805,7 @@ static void __devinit nv_msi_ht_cap_quirk(struct pci_dev *dev) if (pci_read_config_byte(dev, pos + HT_MSI_FLAGS, &flags) == 0) { - dev_info(&dev->dev, "Quirk disabling HT MSI mapping"); + dev_info(&dev->dev, "Disabling HT MSI mapping"); pci_write_config_byte(dev, pos + HT_MSI_FLAGS, flags & ~HT_MSI_FLAGS_ENABLE); } diff --git a/drivers/pci/rom.c b/drivers/pci/rom.c index a98b2470b9e..bd5c0e03139 100644 --- a/drivers/pci/rom.c +++ b/drivers/pci/rom.c @@ -242,8 +242,7 @@ void pci_remove_rom(struct pci_dev *pdev) #endif /* 0 */ /** - * pci_cleanup_rom - internal routine for freeing the ROM copy created - * by pci_map_rom_copy called from remove.c + * pci_cleanup_rom - free the ROM copy created by pci_map_rom_copy * @pdev: pointer to pci device struct * * Free the copied ROM if we allocated one. diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 125e7b7f34f..f7cb8e0758b 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -486,12 +486,7 @@ void __ref pci_bus_size_bridges(struct pci_bus *bus) break; case PCI_CLASS_BRIDGE_PCI: - /* don't size subtractive decoding (transparent) - * PCI-to-PCI bridges */ - if (bus->self->transparent) - break; pci_bridge_check_ranges(bus); - /* fall through */ default: pbus_size_io(bus); /* If the bridge supports prefetchable range, size it diff --git a/drivers/pnp/isapnp/core.c b/drivers/pnp/isapnp/core.c index 2c925b7cd93..257f5d827d8 100644 --- a/drivers/pnp/isapnp/core.c +++ b/drivers/pnp/isapnp/core.c @@ -88,6 +88,15 @@ MODULE_LICENSE("GPL"); #define _LTAG_MEM32RANGE 0x85 #define _LTAG_FIXEDMEM32RANGE 0x86 +/* + * Sizes of ISAPNP logical device configuration register sets. + * See PNP-ISA-v1.0a.pdf, Appendix A. + */ +#define ISAPNP_MAX_MEM 4 +#define ISAPNP_MAX_PORT 8 +#define ISAPNP_MAX_IRQ 2 +#define ISAPNP_MAX_DMA 2 + static unsigned char isapnp_checksum_value; static DEFINE_MUTEX(isapnp_cfg_mutex); static int isapnp_csn_count; @@ -945,14 +954,14 @@ static int isapnp_read_resources(struct pnp_dev *dev, dev->active = isapnp_read_byte(ISAPNP_CFG_ACTIVATE); if (dev->active) { - for (tmp = 0; tmp < PNP_MAX_PORT; tmp++) { + for (tmp = 0; tmp < ISAPNP_MAX_PORT; tmp++) { ret = isapnp_read_word(ISAPNP_CFG_PORT + (tmp << 1)); if (!ret) continue; res->port_resource[tmp].start = ret; res->port_resource[tmp].flags = IORESOURCE_IO; } - for (tmp = 0; tmp < PNP_MAX_MEM; tmp++) { + for (tmp = 0; tmp < ISAPNP_MAX_MEM; tmp++) { ret = isapnp_read_word(ISAPNP_CFG_MEM + (tmp << 3)) << 8; if (!ret) @@ -960,7 +969,7 @@ static int isapnp_read_resources(struct pnp_dev *dev, res->mem_resource[tmp].start = ret; res->mem_resource[tmp].flags = IORESOURCE_MEM; } - for (tmp = 0; tmp < PNP_MAX_IRQ; tmp++) { + for (tmp = 0; tmp < ISAPNP_MAX_IRQ; tmp++) { ret = (isapnp_read_word(ISAPNP_CFG_IRQ + (tmp << 1)) >> 8); @@ -970,7 +979,7 @@ static int isapnp_read_resources(struct pnp_dev *dev, res->irq_resource[tmp].end = ret; res->irq_resource[tmp].flags = IORESOURCE_IRQ; } - for (tmp = 0; tmp < PNP_MAX_DMA; tmp++) { + for (tmp = 0; tmp < ISAPNP_MAX_DMA; tmp++) { ret = isapnp_read_byte(ISAPNP_CFG_DMA + tmp); if (ret == 4) continue; @@ -1002,14 +1011,14 @@ static int isapnp_set_resources(struct pnp_dev *dev, isapnp_cfg_begin(dev->card->number, dev->number); dev->active = 1; for (tmp = 0; - tmp < PNP_MAX_PORT + tmp < ISAPNP_MAX_PORT && (res->port_resource[tmp]. flags & (IORESOURCE_IO | IORESOURCE_UNSET)) == IORESOURCE_IO; tmp++) isapnp_write_word(ISAPNP_CFG_PORT + (tmp << 1), res->port_resource[tmp].start); for (tmp = 0; - tmp < PNP_MAX_IRQ + tmp < ISAPNP_MAX_IRQ && (res->irq_resource[tmp]. flags & (IORESOURCE_IRQ | IORESOURCE_UNSET)) == IORESOURCE_IRQ; tmp++) { @@ -1019,14 +1028,14 @@ static int isapnp_set_resources(struct pnp_dev *dev, isapnp_write_byte(ISAPNP_CFG_IRQ + (tmp << 1), irq); } for (tmp = 0; - tmp < PNP_MAX_DMA + tmp < ISAPNP_MAX_DMA && (res->dma_resource[tmp]. flags & (IORESOURCE_DMA | IORESOURCE_UNSET)) == IORESOURCE_DMA; tmp++) isapnp_write_byte(ISAPNP_CFG_DMA + tmp, res->dma_resource[tmp].start); for (tmp = 0; - tmp < PNP_MAX_MEM + tmp < ISAPNP_MAX_MEM && (res->mem_resource[tmp]. flags & (IORESOURCE_MEM | IORESOURCE_UNSET)) == IORESOURCE_MEM; tmp++) diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c index 6aa231ef642..2dcd1960aca 100644 --- a/drivers/pnp/pnpacpi/rsparser.c +++ b/drivers/pnp/pnpacpi/rsparser.c @@ -85,7 +85,7 @@ static void pnpacpi_parse_allocated_irqresource(struct pnp_resource_table *res, i < PNP_MAX_IRQ) i++; if (i >= PNP_MAX_IRQ && !warned) { - printk(KERN_ERR "pnpacpi: exceeded the max number of IRQ " + printk(KERN_WARNING "pnpacpi: exceeded the max number of IRQ " "resources: %d \n", PNP_MAX_IRQ); warned = 1; return; @@ -187,7 +187,7 @@ static void pnpacpi_parse_allocated_dmaresource(struct pnp_resource_table *res, res->dma_resource[i].start = dma; res->dma_resource[i].end = dma; } else if (!warned) { - printk(KERN_ERR "pnpacpi: exceeded the max number of DMA " + printk(KERN_WARNING "pnpacpi: exceeded the max number of DMA " "resources: %d \n", PNP_MAX_DMA); warned = 1; } @@ -213,7 +213,7 @@ static void pnpacpi_parse_allocated_ioresource(struct pnp_resource_table *res, res->port_resource[i].start = io; res->port_resource[i].end = io + len - 1; } else if (!warned) { - printk(KERN_ERR "pnpacpi: exceeded the max number of IO " + printk(KERN_WARNING "pnpacpi: exceeded the max number of IO " "resources: %d \n", PNP_MAX_PORT); warned = 1; } @@ -241,7 +241,7 @@ static void pnpacpi_parse_allocated_memresource(struct pnp_resource_table *res, res->mem_resource[i].start = mem; res->mem_resource[i].end = mem + len - 1; } else if (!warned) { - printk(KERN_ERR "pnpacpi: exceeded the max number of mem " + printk(KERN_WARNING "pnpacpi: exceeded the max number of mem " "resources: %d\n", PNP_MAX_MEM); warned = 1; } diff --git a/drivers/pnp/quirks.c b/drivers/pnp/quirks.c index 4065139753b..37993206ae5 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/rapidio/rio-driver.c b/drivers/rapidio/rio-driver.c index 5480119ff9d..3ce9f3defc1 100644 --- a/drivers/rapidio/rio-driver.c +++ b/drivers/rapidio/rio-driver.c @@ -78,8 +78,7 @@ void rio_dev_put(struct rio_dev *rdev) } /** - * rio_device_probe - Tell if a RIO device structure has a matching RIO - * device id structure + * rio_device_probe - Tell if a RIO device structure has a matching RIO device id structure * @id: the RIO device id structure to match against * @dev: the RIO device structure to match against * @@ -137,7 +136,7 @@ static int rio_device_remove(struct device *dev) * rio_register_driver - register a new RIO driver * @rdrv: the RIO driver structure to register * - * Adds a &struct rio_driver to the list of registered drivers + * Adds a &struct rio_driver to the list of registered drivers. * Returns a negative value on error, otherwise 0. If no error * occurred, the driver remains registered even if no device * was claimed during registration. @@ -167,8 +166,7 @@ void rio_unregister_driver(struct rio_driver *rdrv) } /** - * rio_match_bus - Tell if a RIO device structure has a matching RIO - * driver device id structure + * rio_match_bus - Tell if a RIO device structure has a matching RIO driver device id structure * @dev: the standard device structure to match against * @drv: the standard driver structure containing the ids to match against * diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 6402d699072..9e7de63b26e 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -16,7 +16,7 @@ menuconfig RTC_CLASS probably want to enable one or more of the interfaces below. This driver can also be built as a module. If so, the module - will be called rtc-class. + will be called rtc-core. if RTC_CLASS @@ -250,6 +250,15 @@ config RTC_DRV_TWL92330 platforms. The support is integrated with the rest of the Menelaus driver; it's not separate module. +config RTC_DRV_S35390A + tristate "Seiko Instruments S-35390A" + help + If you say yes here you will get support for the Seiko + Instruments S-35390A. + + This driver can also be built as a module. If so the module + will be called rtc-s35390a. + endif # I2C comment "SPI RTC drivers" diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index ec703f34ab8..872f1218ff9 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -45,6 +45,7 @@ obj-$(CONFIG_RTC_DRV_R9701) += rtc-r9701.o obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o obj-$(CONFIG_RTC_DRV_RS5C348) += rtc-rs5c348.o obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o +obj-$(CONFIG_RTC_DRV_S35390A) += rtc-s35390a.o obj-$(CONFIG_RTC_DRV_S3C) += rtc-s3c.o obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c index bbf10ecf416..56728a2a338 100644 --- a/drivers/rtc/rtc-at91sam9.c +++ b/drivers/rtc/rtc-at91sam9.c @@ -274,7 +274,7 @@ static irqreturn_t at91_rtc_interrupt(int irq, void *_rtc) * SR clears it, so we must only read it in this irq handler! */ mr = rtt_readl(rtc, MR) & (AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN); - sr = rtt_readl(rtc, SR) & mr; + sr = rtt_readl(rtc, SR) & (mr >> 16); if (!sr) return IRQ_NONE; @@ -321,6 +321,10 @@ static int __init at91_rtc_probe(struct platform_device *pdev) if (!rtc) return -ENOMEM; + /* platform setup code should have handled this; sigh */ + if (!device_can_wakeup(&pdev->dev)) + device_init_wakeup(&pdev->dev, 1); + platform_set_drvdata(pdev, rtc); rtc->rtt = (void __force __iomem *) (AT91_VA_BASE_SYS - AT91_BASE_SYS); rtc->rtt += r->start; diff --git a/drivers/rtc/rtc-s35390a.c b/drivers/rtc/rtc-s35390a.c new file mode 100644 index 00000000000..e8abc90c32c --- /dev/null +++ b/drivers/rtc/rtc-s35390a.c @@ -0,0 +1,316 @@ +/* + * Seiko Instruments S-35390A RTC Driver + * + * Copyright (c) 2007 Byron Bradley + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include <linux/module.h> +#include <linux/rtc.h> +#include <linux/i2c.h> +#include <linux/bitrev.h> +#include <linux/bcd.h> +#include <linux/slab.h> + +#define S35390A_CMD_STATUS1 0 +#define S35390A_CMD_STATUS2 1 +#define S35390A_CMD_TIME1 2 + +#define S35390A_BYTE_YEAR 0 +#define S35390A_BYTE_MONTH 1 +#define S35390A_BYTE_DAY 2 +#define S35390A_BYTE_WDAY 3 +#define S35390A_BYTE_HOURS 4 +#define S35390A_BYTE_MINS 5 +#define S35390A_BYTE_SECS 6 + +#define S35390A_FLAG_POC 0x01 +#define S35390A_FLAG_BLD 0x02 +#define S35390A_FLAG_24H 0x40 +#define S35390A_FLAG_RESET 0x80 +#define S35390A_FLAG_TEST 0x01 + +struct s35390a { + struct i2c_client *client[8]; + struct rtc_device *rtc; + int twentyfourhour; +}; + +static int s35390a_set_reg(struct s35390a *s35390a, int reg, char *buf, int len) +{ + struct i2c_client *client = s35390a->client[reg]; + struct i2c_msg msg[] = { + { client->addr, 0, len, buf }, + }; + + if ((i2c_transfer(client->adapter, msg, 1)) != 1) + return -EIO; + + return 0; +} + +static int s35390a_get_reg(struct s35390a *s35390a, int reg, char *buf, int len) +{ + struct i2c_client *client = s35390a->client[reg]; + struct i2c_msg msg[] = { + { client->addr, I2C_M_RD, len, buf }, + }; + + if ((i2c_transfer(client->adapter, msg, 1)) != 1) + return -EIO; + + return 0; +} + +static int s35390a_reset(struct s35390a *s35390a) +{ + char buf[1]; + + if (s35390a_get_reg(s35390a, S35390A_CMD_STATUS1, buf, sizeof(buf)) < 0) + return -EIO; + + if (!(buf[0] & (S35390A_FLAG_POC | S35390A_FLAG_BLD))) + return 0; + + buf[0] |= (S35390A_FLAG_RESET | S35390A_FLAG_24H); + buf[0] &= 0xf0; + return s35390a_set_reg(s35390a, S35390A_CMD_STATUS1, buf, sizeof(buf)); +} + +static int s35390a_disable_test_mode(struct s35390a *s35390a) +{ + char buf[1]; + + if (s35390a_get_reg(s35390a, S35390A_CMD_STATUS2, buf, sizeof(buf)) < 0) + return -EIO; + + if (!(buf[0] & S35390A_FLAG_TEST)) + return 0; + + buf[0] &= ~S35390A_FLAG_TEST; + return s35390a_set_reg(s35390a, S35390A_CMD_STATUS2, buf, sizeof(buf)); +} + +static char s35390a_hr2reg(struct s35390a *s35390a, int hour) +{ + if (s35390a->twentyfourhour) + return BIN2BCD(hour); + + if (hour < 12) + return BIN2BCD(hour); + + return 0x40 | BIN2BCD(hour - 12); +} + +static int s35390a_reg2hr(struct s35390a *s35390a, char reg) +{ + unsigned hour; + + if (s35390a->twentyfourhour) + return BCD2BIN(reg & 0x3f); + + hour = BCD2BIN(reg & 0x3f); + if (reg & 0x40) + hour += 12; + + return hour; +} + +static int s35390a_set_datetime(struct i2c_client *client, struct rtc_time *tm) +{ + struct s35390a *s35390a = i2c_get_clientdata(client); + int i, err; + char buf[7]; + + dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d mday=%d, " + "mon=%d, year=%d, wday=%d\n", __func__, tm->tm_sec, + tm->tm_min, tm->tm_hour, tm->tm_mday, tm->tm_mon, tm->tm_year, + tm->tm_wday); + + buf[S35390A_BYTE_YEAR] = BIN2BCD(tm->tm_year - 100); + buf[S35390A_BYTE_MONTH] = BIN2BCD(tm->tm_mon + 1); + buf[S35390A_BYTE_DAY] = BIN2BCD(tm->tm_mday); + buf[S35390A_BYTE_WDAY] = BIN2BCD(tm->tm_wday); + buf[S35390A_BYTE_HOURS] = s35390a_hr2reg(s35390a, tm->tm_hour); + buf[S35390A_BYTE_MINS] = BIN2BCD(tm->tm_min); + buf[S35390A_BYTE_SECS] = BIN2BCD(tm->tm_sec); + + /* This chip expects the bits of each byte to be in reverse order */ + for (i = 0; i < 7; ++i) + buf[i] = bitrev8(buf[i]); + + err = s35390a_set_reg(s35390a, S35390A_CMD_TIME1, buf, sizeof(buf)); + + return err; +} + +static int s35390a_get_datetime(struct i2c_client *client, struct rtc_time *tm) +{ + struct s35390a *s35390a = i2c_get_clientdata(client); + char buf[7]; + int i, err; + + err = s35390a_get_reg(s35390a, S35390A_CMD_TIME1, buf, sizeof(buf)); + if (err < 0) + return err; + + /* This chip returns the bits of each byte in reverse order */ + for (i = 0; i < 7; ++i) + buf[i] = bitrev8(buf[i]); + + tm->tm_sec = BCD2BIN(buf[S35390A_BYTE_SECS]); + tm->tm_min = BCD2BIN(buf[S35390A_BYTE_MINS]); + tm->tm_hour = s35390a_reg2hr(s35390a, buf[S35390A_BYTE_HOURS]); + tm->tm_wday = BCD2BIN(buf[S35390A_BYTE_WDAY]); + tm->tm_mday = BCD2BIN(buf[S35390A_BYTE_DAY]); + tm->tm_mon = BCD2BIN(buf[S35390A_BYTE_MONTH]) - 1; + tm->tm_year = BCD2BIN(buf[S35390A_BYTE_YEAR]) + 100; + + dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, mday=%d, " + "mon=%d, year=%d, wday=%d\n", __func__, tm->tm_sec, + tm->tm_min, tm->tm_hour, tm->tm_mday, tm->tm_mon, tm->tm_year, + tm->tm_wday); + + return rtc_valid_tm(tm); +} + +static int s35390a_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + return s35390a_get_datetime(to_i2c_client(dev), tm); +} + +static int s35390a_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + return s35390a_set_datetime(to_i2c_client(dev), tm); +} + +static const struct rtc_class_ops s35390a_rtc_ops = { + .read_time = s35390a_rtc_read_time, + .set_time = s35390a_rtc_set_time, +}; + +static struct i2c_driver s35390a_driver; + +static int s35390a_probe(struct i2c_client *client) +{ + int err; + unsigned int i; + struct s35390a *s35390a; + struct rtc_time tm; + char buf[1]; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + err = -ENODEV; + goto exit; + } + + s35390a = kzalloc(sizeof(struct s35390a), GFP_KERNEL); + if (!s35390a) { + err = -ENOMEM; + goto exit; + } + + s35390a->client[0] = client; + i2c_set_clientdata(client, s35390a); + + /* This chip uses multiple addresses, use dummy devices for them */ + for (i = 1; i < 8; ++i) { + s35390a->client[i] = i2c_new_dummy(client->adapter, + client->addr + i, "rtc-s35390a"); + if (!s35390a->client[i]) { + dev_err(&client->dev, "Address %02x unavailable\n", + client->addr + i); + err = -EBUSY; + goto exit_dummy; + } + } + + err = s35390a_reset(s35390a); + if (err < 0) { + dev_err(&client->dev, "error resetting chip\n"); + goto exit_dummy; + } + + err = s35390a_disable_test_mode(s35390a); + if (err < 0) { + dev_err(&client->dev, "error disabling test mode\n"); + goto exit_dummy; + } + + err = s35390a_get_reg(s35390a, S35390A_CMD_STATUS1, buf, sizeof(buf)); + if (err < 0) { + dev_err(&client->dev, "error checking 12/24 hour mode\n"); + goto exit_dummy; + } + if (buf[0] & S35390A_FLAG_24H) + s35390a->twentyfourhour = 1; + else + s35390a->twentyfourhour = 0; + + if (s35390a_get_datetime(client, &tm) < 0) + dev_warn(&client->dev, "clock needs to be set\n"); + + s35390a->rtc = rtc_device_register(s35390a_driver.driver.name, + &client->dev, &s35390a_rtc_ops, THIS_MODULE); + + if (IS_ERR(s35390a->rtc)) { + err = PTR_ERR(s35390a->rtc); + goto exit_dummy; + } + return 0; + +exit_dummy: + for (i = 1; i < 8; ++i) + if (s35390a->client[i]) + i2c_unregister_device(s35390a->client[i]); + kfree(s35390a); + i2c_set_clientdata(client, NULL); + +exit: + return err; +} + +static int s35390a_remove(struct i2c_client *client) +{ + unsigned int i; + + struct s35390a *s35390a = i2c_get_clientdata(client); + for (i = 1; i < 8; ++i) + if (s35390a->client[i]) + i2c_unregister_device(s35390a->client[i]); + + rtc_device_unregister(s35390a->rtc); + kfree(s35390a); + i2c_set_clientdata(client, NULL); + + return 0; +} + +static struct i2c_driver s35390a_driver = { + .driver = { + .name = "rtc-s35390a", + }, + .probe = s35390a_probe, + .remove = s35390a_remove, +}; + +static int __init s35390a_rtc_init(void) +{ + return i2c_add_driver(&s35390a_driver); +} + +static void __exit s35390a_rtc_exit(void) +{ + i2c_del_driver(&s35390a_driver); +} + +MODULE_AUTHOR("Byron Bradley <byron.bbradley@gmail.com>"); +MODULE_DESCRIPTION("S35390A RTC driver"); +MODULE_LICENSE("GPL"); + +module_init(s35390a_rtc_init); +module_exit(s35390a_rtc_exit); diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c index f69714a0e9e..b19db20a0be 100644 --- a/drivers/s390/block/dasd_3990_erp.c +++ b/drivers/s390/block/dasd_3990_erp.c @@ -2310,10 +2310,8 @@ static int dasd_3990_erp_error_match(struct dasd_ccw_req *cqr1, struct dasd_ccw_req *cqr2) { - /* check failed CCW */ - if (cqr1->irb.scsw.cpa != cqr2->irb.scsw.cpa) { - // return 0; /* CCW doesn't match */ - } + if (cqr1->startdev != cqr2->startdev) + return 0; if (cqr1->irb.esw.esw0.erw.cons != cqr2->irb.esw.esw0.erw.cons) return 0; diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c index 28a86f07004..556063e8f7a 100644 --- a/drivers/s390/block/dasd_proc.c +++ b/drivers/s390/block/dasd_proc.c @@ -62,8 +62,10 @@ dasd_devices_show(struct seq_file *m, void *v) return 0; if (device->block) block = device->block; - else + else { + dasd_put_device(device); return 0; + } /* Print device number. */ seq_printf(m, "%s", device->cdev->dev.bus_id); /* Print discipline string. */ diff --git a/drivers/s390/char/defkeymap.c b/drivers/s390/char/defkeymap.c index 389346cda6c..07c7f31081b 100644 --- a/drivers/s390/char/defkeymap.c +++ b/drivers/s390/char/defkeymap.c @@ -151,8 +151,8 @@ char *func_table[MAX_NR_FUNC] = { }; struct kbdiacruc accent_table[MAX_DIACR] = { - {'^', 'c', '\003'}, {'^', 'd', '\004'}, - {'^', 'z', '\032'}, {'^', '\012', '\000'}, + {'^', 'c', 0003}, {'^', 'd', 0004}, + {'^', 'z', 0032}, {'^', 0012, 0000}, }; unsigned int accent_table_size = 4; diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c index 92f52720179..f7b258dfd52 100644 --- a/drivers/s390/char/sclp_vt220.c +++ b/drivers/s390/char/sclp_vt220.c @@ -367,7 +367,7 @@ sclp_vt220_timeout(unsigned long data) sclp_vt220_emit_current(); } -#define BUFFER_MAX_DELAY HZ/2 +#define BUFFER_MAX_DELAY HZ/20 /* * Internal implementation of the write function. Write COUNT bytes of data diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index d0c6fd3b1c1..7b0b8190129 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -490,10 +490,12 @@ static int ap_device_probe(struct device *dev) int rc; ap_dev->drv = ap_drv; - spin_lock_bh(&ap_device_lock); - list_add(&ap_dev->list, &ap_device_list); - spin_unlock_bh(&ap_device_lock); rc = ap_drv->probe ? ap_drv->probe(ap_dev) : -ENODEV; + if (!rc) { + spin_lock_bh(&ap_device_lock); + list_add(&ap_dev->list, &ap_device_list); + spin_unlock_bh(&ap_device_lock); + } return rc; } @@ -532,11 +534,11 @@ static int ap_device_remove(struct device *dev) ap_flush_queue(ap_dev); del_timer_sync(&ap_dev->timeout); - if (ap_drv->remove) - ap_drv->remove(ap_dev); spin_lock_bh(&ap_device_lock); list_del_init(&ap_dev->list); spin_unlock_bh(&ap_device_lock); + if (ap_drv->remove) + ap_drv->remove(ap_dev); spin_lock_bh(&ap_dev->lock); atomic_sub(ap_dev->queue_count, &ap_poll_requests); spin_unlock_bh(&ap_dev->lock); diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index c46666a2480..b9d374082b6 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -325,7 +325,7 @@ menuconfig SCSI_LOWLEVEL depends on SCSI!=n default y -if SCSI_LOWLEVEL +if SCSI_LOWLEVEL && SCSI config ISCSI_TCP tristate "iSCSI Initiator over TCP/IP" diff --git a/drivers/scsi/a100u2w.c b/drivers/scsi/a100u2w.c index f608d4a1d6d..792b2e807bf 100644 --- a/drivers/scsi/a100u2w.c +++ b/drivers/scsi/a100u2w.c @@ -674,12 +674,13 @@ static struct orc_scb *__orc_alloc_scb(struct orc_host * host) for (index = 0; index < 32; index++) { if ((host->allocation_map[channel][i] >> index) & 0x01) { host->allocation_map[channel][i] &= ~(1 << index); - break; + idx = index + 32 * i; + /* + * Translate the index to a structure instance + */ + return host->scb_virt + idx; } } - idx = index + 32 * i; - /* Translate the index to a structure instance */ - return (struct orc_scb *) ((unsigned long) host->scb_virt + (idx * sizeof(struct orc_scb))); } return NULL; } diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c index 3c2d6888bb8..8591585e5cc 100644 --- a/drivers/scsi/advansys.c +++ b/drivers/scsi/advansys.c @@ -6439,7 +6439,7 @@ static int AdvLoadMicrocode(AdvPortAddr iop_base, unsigned char *buf, int size, i += 2; len += 2; } else { - unsigned char off = buf[i] * 2; + unsigned int off = buf[i] * 2; unsigned short word = (buf[off + 1] << 8) | buf[off]; AdvWriteWordAutoIncLram(iop_base, word); len += 2; diff --git a/drivers/scsi/aic94xx/aic94xx.h b/drivers/scsi/aic94xx/aic94xx.h index 32f513b1b78..eb8efdcefe4 100644 --- a/drivers/scsi/aic94xx/aic94xx.h +++ b/drivers/scsi/aic94xx/aic94xx.h @@ -102,6 +102,7 @@ int asd_abort_task_set(struct domain_device *, u8 *lun); int asd_clear_aca(struct domain_device *, u8 *lun); int asd_clear_task_set(struct domain_device *, u8 *lun); int asd_lu_reset(struct domain_device *, u8 *lun); +int asd_I_T_nexus_reset(struct domain_device *dev); int asd_query_task(struct sas_task *); /* ---------- Adapter and Port management ---------- */ diff --git a/drivers/scsi/aic94xx/aic94xx_hwi.h b/drivers/scsi/aic94xx/aic94xx_hwi.h index 150f6706d23..abc757559c1 100644 --- a/drivers/scsi/aic94xx/aic94xx_hwi.h +++ b/drivers/scsi/aic94xx/aic94xx_hwi.h @@ -140,7 +140,7 @@ struct asd_ascb { /* internally generated command */ struct timer_list timer; - struct completion completion; + struct completion *completion; u8 tag_valid:1; __be16 tag; /* error recovery only */ @@ -294,7 +294,6 @@ static inline void asd_init_ascb(struct asd_ha_struct *asd_ha, ascb->timer.function = NULL; init_timer(&ascb->timer); ascb->tc_index = -1; - init_completion(&ascb->completion); } /* Must be called with the tc_index_lock held! diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c index 5d761eb6744..88d1e731b65 100644 --- a/drivers/scsi/aic94xx/aic94xx_init.c +++ b/drivers/scsi/aic94xx/aic94xx_init.c @@ -1003,7 +1003,7 @@ static struct sas_domain_function_template aic94xx_transport_functions = { .lldd_abort_task_set = asd_abort_task_set, .lldd_clear_aca = asd_clear_aca, .lldd_clear_task_set = asd_clear_task_set, - .lldd_I_T_nexus_reset = NULL, + .lldd_I_T_nexus_reset = asd_I_T_nexus_reset, .lldd_lu_reset = asd_lu_reset, .lldd_query_task = asd_query_task, diff --git a/drivers/scsi/aic94xx/aic94xx_task.c b/drivers/scsi/aic94xx/aic94xx_task.c index 965d4bb999d..008df9ab92a 100644 --- a/drivers/scsi/aic94xx/aic94xx_task.c +++ b/drivers/scsi/aic94xx/aic94xx_task.c @@ -343,11 +343,13 @@ Again: task->task_state_flags &= ~SAS_TASK_AT_INITIATOR; task->task_state_flags |= SAS_TASK_STATE_DONE; if (unlikely((task->task_state_flags & SAS_TASK_STATE_ABORTED))) { + struct completion *completion = ascb->completion; spin_unlock_irqrestore(&task->task_state_lock, flags); ASD_DPRINTK("task 0x%p done with opcode 0x%x resp 0x%x " "stat 0x%x but aborted by upper layer!\n", task, opcode, ts->resp, ts->stat); - complete(&ascb->completion); + if (completion) + complete(completion); } else { spin_unlock_irqrestore(&task->task_state_lock, flags); task->lldd_task = NULL; diff --git a/drivers/scsi/aic94xx/aic94xx_tmf.c b/drivers/scsi/aic94xx/aic94xx_tmf.c index 144f5ad2045..b9ac8f703a1 100644 --- a/drivers/scsi/aic94xx/aic94xx_tmf.c +++ b/drivers/scsi/aic94xx/aic94xx_tmf.c @@ -53,50 +53,64 @@ static int asd_enqueue_internal(struct asd_ascb *ascb, return res; } -static inline void asd_timedout_common(unsigned long data) -{ - struct asd_ascb *ascb = (void *) data; - struct asd_seq_data *seq = &ascb->ha->seq; - unsigned long flags; +/* ---------- CLEAR NEXUS ---------- */ - spin_lock_irqsave(&seq->pend_q_lock, flags); - seq->pending--; - list_del_init(&ascb->list); - spin_unlock_irqrestore(&seq->pend_q_lock, flags); -} +struct tasklet_completion_status { + int dl_opcode; + int tmf_state; + u8 tag_valid:1; + __be16 tag; +}; + +#define DECLARE_TCS(tcs) \ + struct tasklet_completion_status tcs = { \ + .dl_opcode = 0, \ + .tmf_state = 0, \ + .tag_valid = 0, \ + .tag = 0, \ + } -/* ---------- CLEAR NEXUS ---------- */ static void asd_clear_nexus_tasklet_complete(struct asd_ascb *ascb, struct done_list_struct *dl) { + struct tasklet_completion_status *tcs = ascb->uldd_task; ASD_DPRINTK("%s: here\n", __FUNCTION__); if (!del_timer(&ascb->timer)) { ASD_DPRINTK("%s: couldn't delete timer\n", __FUNCTION__); return; } ASD_DPRINTK("%s: opcode: 0x%x\n", __FUNCTION__, dl->opcode); - ascb->uldd_task = (void *) (unsigned long) dl->opcode; - complete(&ascb->completion); + tcs->dl_opcode = dl->opcode; + complete(ascb->completion); + asd_ascb_free(ascb); } static void asd_clear_nexus_timedout(unsigned long data) { - struct asd_ascb *ascb = (void *) data; + struct asd_ascb *ascb = (void *)data; + struct tasklet_completion_status *tcs = ascb->uldd_task; ASD_DPRINTK("%s: here\n", __FUNCTION__); - asd_timedout_common(data); - ascb->uldd_task = (void *) TMF_RESP_FUNC_FAILED; - complete(&ascb->completion); + tcs->dl_opcode = TMF_RESP_FUNC_FAILED; + complete(ascb->completion); } #define CLEAR_NEXUS_PRE \ + struct asd_ascb *ascb; \ + struct scb *scb; \ + int res; \ + DECLARE_COMPLETION_ONSTACK(completion); \ + DECLARE_TCS(tcs); \ + \ ASD_DPRINTK("%s: PRE\n", __FUNCTION__); \ res = 1; \ ascb = asd_ascb_alloc_list(asd_ha, &res, GFP_KERNEL); \ if (!ascb) \ return -ENOMEM; \ \ + ascb->completion = &completion; \ + ascb->uldd_task = &tcs; \ scb = ascb->scb; \ scb->header.opcode = CLEAR_NEXUS @@ -107,10 +121,11 @@ static void asd_clear_nexus_timedout(unsigned long data) if (res) \ goto out_err; \ ASD_DPRINTK("%s: clear nexus posted, waiting...\n", __FUNCTION__); \ - wait_for_completion(&ascb->completion); \ - res = (int) (unsigned long) ascb->uldd_task; \ + wait_for_completion(&completion); \ + res = tcs.dl_opcode; \ if (res == TC_NO_ERROR) \ res = TMF_RESP_FUNC_COMPLETE; \ + return res; \ out_err: \ asd_ascb_free(ascb); \ return res @@ -118,9 +133,6 @@ out_err: \ int asd_clear_nexus_ha(struct sas_ha_struct *sas_ha) { struct asd_ha_struct *asd_ha = sas_ha->lldd_ha; - struct asd_ascb *ascb; - struct scb *scb; - int res; CLEAR_NEXUS_PRE; scb->clear_nexus.nexus = NEXUS_ADAPTER; @@ -130,9 +142,6 @@ int asd_clear_nexus_ha(struct sas_ha_struct *sas_ha) int asd_clear_nexus_port(struct asd_sas_port *port) { struct asd_ha_struct *asd_ha = port->ha->lldd_ha; - struct asd_ascb *ascb; - struct scb *scb; - int res; CLEAR_NEXUS_PRE; scb->clear_nexus.nexus = NEXUS_PORT; @@ -140,29 +149,73 @@ int asd_clear_nexus_port(struct asd_sas_port *port) CLEAR_NEXUS_POST; } -#if 0 -static int asd_clear_nexus_I_T(struct domain_device *dev) +enum clear_nexus_phase { + NEXUS_PHASE_PRE, + NEXUS_PHASE_POST, + NEXUS_PHASE_RESUME, +}; + +static int asd_clear_nexus_I_T(struct domain_device *dev, + enum clear_nexus_phase phase) { struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha; - struct asd_ascb *ascb; - struct scb *scb; - int res; CLEAR_NEXUS_PRE; scb->clear_nexus.nexus = NEXUS_I_T; - scb->clear_nexus.flags = SEND_Q | EXEC_Q | NOTINQ; + switch (phase) { + case NEXUS_PHASE_PRE: + scb->clear_nexus.flags = EXEC_Q | SUSPEND_TX; + break; + case NEXUS_PHASE_POST: + scb->clear_nexus.flags = SEND_Q | NOTINQ; + break; + case NEXUS_PHASE_RESUME: + scb->clear_nexus.flags = RESUME_TX; + } scb->clear_nexus.conn_handle = cpu_to_le16((u16)(unsigned long) dev->lldd_dev); CLEAR_NEXUS_POST; } -#endif + +int asd_I_T_nexus_reset(struct domain_device *dev) +{ + int res, tmp_res, i; + struct sas_phy *phy = sas_find_local_phy(dev); + /* Standard mandates link reset for ATA (type 0) and + * hard reset for SSP (type 1) */ + int reset_type = (dev->dev_type == SATA_DEV || + (dev->tproto & SAS_PROTOCOL_STP)) ? 0 : 1; + + asd_clear_nexus_I_T(dev, NEXUS_PHASE_PRE); + /* send a hard reset */ + ASD_DPRINTK("sending %s reset to %s\n", + reset_type ? "hard" : "soft", phy->dev.bus_id); + res = sas_phy_reset(phy, reset_type); + if (res == TMF_RESP_FUNC_COMPLETE) { + /* wait for the maximum settle time */ + msleep(500); + /* clear all outstanding commands (keep nexus suspended) */ + asd_clear_nexus_I_T(dev, NEXUS_PHASE_POST); + } + for (i = 0 ; i < 3; i++) { + tmp_res = asd_clear_nexus_I_T(dev, NEXUS_PHASE_RESUME); + if (tmp_res == TC_RESUME) + return res; + msleep(500); + } + + /* This is a bit of a problem: the sequencer is still suspended + * and is refusing to resume. Hope it will resume on a bigger hammer + * or the disk is lost */ + dev_printk(KERN_ERR, &phy->dev, + "Failed to resume nexus after reset 0x%x\n", tmp_res); + + return TMF_RESP_FUNC_FAILED; +} static int asd_clear_nexus_I_T_L(struct domain_device *dev, u8 *lun) { struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha; - struct asd_ascb *ascb; - struct scb *scb; - int res; CLEAR_NEXUS_PRE; scb->clear_nexus.nexus = NEXUS_I_T_L; @@ -177,9 +230,6 @@ static int asd_clear_nexus_tag(struct sas_task *task) { struct asd_ha_struct *asd_ha = task->dev->port->ha->lldd_ha; struct asd_ascb *tascb = task->lldd_task; - struct asd_ascb *ascb; - struct scb *scb; - int res; CLEAR_NEXUS_PRE; scb->clear_nexus.nexus = NEXUS_TAG; @@ -195,9 +245,6 @@ static int asd_clear_nexus_index(struct sas_task *task) { struct asd_ha_struct *asd_ha = task->dev->port->ha->lldd_ha; struct asd_ascb *tascb = task->lldd_task; - struct asd_ascb *ascb; - struct scb *scb; - int res; CLEAR_NEXUS_PRE; scb->clear_nexus.nexus = NEXUS_TRANS_CX; @@ -213,11 +260,11 @@ static int asd_clear_nexus_index(struct sas_task *task) static void asd_tmf_timedout(unsigned long data) { struct asd_ascb *ascb = (void *) data; + struct tasklet_completion_status *tcs = ascb->uldd_task; ASD_DPRINTK("tmf timed out\n"); - asd_timedout_common(data); - ascb->uldd_task = (void *) TMF_RESP_FUNC_FAILED; - complete(&ascb->completion); + tcs->tmf_state = TMF_RESP_FUNC_FAILED; + complete(ascb->completion); } static int asd_get_tmf_resp_tasklet(struct asd_ascb *ascb, @@ -269,18 +316,24 @@ static int asd_get_tmf_resp_tasklet(struct asd_ascb *ascb, static void asd_tmf_tasklet_complete(struct asd_ascb *ascb, struct done_list_struct *dl) { + struct tasklet_completion_status *tcs; + if (!del_timer(&ascb->timer)) return; + tcs = ascb->uldd_task; ASD_DPRINTK("tmf tasklet complete\n"); - if (dl->opcode == TC_SSP_RESP) - ascb->uldd_task = (void *) (unsigned long) - asd_get_tmf_resp_tasklet(ascb, dl); - else - ascb->uldd_task = (void *) 0xFF00 + (unsigned long) dl->opcode; + tcs->dl_opcode = dl->opcode; + + if (dl->opcode == TC_SSP_RESP) { + tcs->tmf_state = asd_get_tmf_resp_tasklet(ascb, dl); + tcs->tag_valid = ascb->tag_valid; + tcs->tag = ascb->tag; + } - complete(&ascb->completion); + complete(ascb->completion); + asd_ascb_free(ascb); } static inline int asd_clear_nexus(struct sas_task *task) @@ -288,15 +341,19 @@ static inline int asd_clear_nexus(struct sas_task *task) int res = TMF_RESP_FUNC_FAILED; int leftover; struct asd_ascb *tascb = task->lldd_task; + DECLARE_COMPLETION_ONSTACK(completion); unsigned long flags; + tascb->completion = &completion; + ASD_DPRINTK("task not done, clearing nexus\n"); if (tascb->tag_valid) res = asd_clear_nexus_tag(task); else res = asd_clear_nexus_index(task); - leftover = wait_for_completion_timeout(&tascb->completion, + leftover = wait_for_completion_timeout(&completion, AIC94XX_SCB_TIMEOUT); + tascb->completion = NULL; ASD_DPRINTK("came back from clear nexus\n"); spin_lock_irqsave(&task->task_state_lock, flags); if (leftover < 1) @@ -350,6 +407,11 @@ int asd_abort_task(struct sas_task *task) struct asd_ascb *ascb = NULL; struct scb *scb; int leftover; + DECLARE_TCS(tcs); + DECLARE_COMPLETION_ONSTACK(completion); + DECLARE_COMPLETION_ONSTACK(tascb_completion); + + tascb->completion = &tascb_completion; spin_lock_irqsave(&task->task_state_lock, flags); if (task->task_state_flags & SAS_TASK_STATE_DONE) { @@ -363,8 +425,10 @@ int asd_abort_task(struct sas_task *task) ascb = asd_ascb_alloc_list(asd_ha, &res, GFP_KERNEL); if (!ascb) return -ENOMEM; - scb = ascb->scb; + ascb->uldd_task = &tcs; + ascb->completion = &completion; + scb = ascb->scb; scb->header.opcode = SCB_ABORT_TASK; switch (task->task_proto) { @@ -406,13 +470,12 @@ int asd_abort_task(struct sas_task *task) res = asd_enqueue_internal(ascb, asd_tmf_tasklet_complete, asd_tmf_timedout); if (res) - goto out; - wait_for_completion(&ascb->completion); + goto out_free; + wait_for_completion(&completion); ASD_DPRINTK("tmf came back\n"); - res = (int) (unsigned long) ascb->uldd_task; - tascb->tag = ascb->tag; - tascb->tag_valid = ascb->tag_valid; + tascb->tag = tcs.tag; + tascb->tag_valid = tcs.tag_valid; spin_lock_irqsave(&task->task_state_lock, flags); if (task->task_state_flags & SAS_TASK_STATE_DONE) { @@ -423,63 +486,68 @@ int asd_abort_task(struct sas_task *task) } spin_unlock_irqrestore(&task->task_state_lock, flags); - switch (res) { - /* The task to be aborted has been sent to the device. - * We got a Response IU for the ABORT TASK TMF. */ - case TC_NO_ERROR + 0xFF00: - case TMF_RESP_FUNC_COMPLETE: - case TMF_RESP_FUNC_FAILED: - res = asd_clear_nexus(task); - break; - case TMF_RESP_INVALID_FRAME: - case TMF_RESP_OVERLAPPED_TAG: - case TMF_RESP_FUNC_ESUPP: - case TMF_RESP_NO_LUN: - goto out_done; break; - } - /* In the following we assume that the managing layer - * will _never_ make a mistake, when issuing ABORT TASK. - */ - switch (res) { - default: - res = asd_clear_nexus(task); - /* fallthrough */ - case TC_NO_ERROR + 0xFF00: - case TMF_RESP_FUNC_COMPLETE: - break; - /* The task hasn't been sent to the device xor we never got - * a (sane) Response IU for the ABORT TASK TMF. - */ - case TF_NAK_RECV + 0xFF00: - res = TMF_RESP_INVALID_FRAME; - break; - case TF_TMF_TASK_DONE + 0xFF00: /* done but not reported yet */ + if (tcs.dl_opcode == TC_SSP_RESP) { + /* The task to be aborted has been sent to the device. + * We got a Response IU for the ABORT TASK TMF. */ + if (tcs.tmf_state == TMF_RESP_FUNC_COMPLETE) + res = asd_clear_nexus(task); + else + res = tcs.tmf_state; + } else if (tcs.dl_opcode == TC_NO_ERROR && + tcs.tmf_state == TMF_RESP_FUNC_FAILED) { + /* timeout */ res = TMF_RESP_FUNC_FAILED; - leftover = wait_for_completion_timeout(&tascb->completion, - AIC94XX_SCB_TIMEOUT); - spin_lock_irqsave(&task->task_state_lock, flags); - if (leftover < 1) + } else { + /* In the following we assume that the managing layer + * will _never_ make a mistake, when issuing ABORT + * TASK. + */ + switch (tcs.dl_opcode) { + default: + res = asd_clear_nexus(task); + /* fallthrough */ + case TC_NO_ERROR: + break; + /* The task hasn't been sent to the device xor + * we never got a (sane) Response IU for the + * ABORT TASK TMF. + */ + case TF_NAK_RECV: + res = TMF_RESP_INVALID_FRAME; + break; + case TF_TMF_TASK_DONE: /* done but not reported yet */ res = TMF_RESP_FUNC_FAILED; - if (task->task_state_flags & SAS_TASK_STATE_DONE) + leftover = + wait_for_completion_timeout(&tascb_completion, + AIC94XX_SCB_TIMEOUT); + spin_lock_irqsave(&task->task_state_lock, flags); + if (leftover < 1) + res = TMF_RESP_FUNC_FAILED; + if (task->task_state_flags & SAS_TASK_STATE_DONE) + res = TMF_RESP_FUNC_COMPLETE; + spin_unlock_irqrestore(&task->task_state_lock, flags); + break; + case TF_TMF_NO_TAG: + case TF_TMF_TAG_FREE: /* the tag is in the free list */ + case TF_TMF_NO_CONN_HANDLE: /* no such device */ res = TMF_RESP_FUNC_COMPLETE; - spin_unlock_irqrestore(&task->task_state_lock, flags); - goto out_done; - case TF_TMF_NO_TAG + 0xFF00: - case TF_TMF_TAG_FREE + 0xFF00: /* the tag is in the free list */ - case TF_TMF_NO_CONN_HANDLE + 0xFF00: /* no such device */ - res = TMF_RESP_FUNC_COMPLETE; - goto out_done; - case TF_TMF_NO_CTX + 0xFF00: /* not in seq, or proto != SSP */ - res = TMF_RESP_FUNC_ESUPP; - goto out; + break; + case TF_TMF_NO_CTX: /* not in seq, or proto != SSP */ + res = TMF_RESP_FUNC_ESUPP; + break; + } } -out_done: + out_done: + tascb->completion = NULL; if (res == TMF_RESP_FUNC_COMPLETE) { task->lldd_task = NULL; mb(); asd_ascb_free(tascb); } -out: + ASD_DPRINTK("task 0x%p aborted, res: 0x%x\n", task, res); + return res; + + out_free: asd_ascb_free(ascb); ASD_DPRINTK("task 0x%p aborted, res: 0x%x\n", task, res); return res; @@ -507,6 +575,8 @@ static int asd_initiate_ssp_tmf(struct domain_device *dev, u8 *lun, struct asd_ascb *ascb; int res = 1; struct scb *scb; + DECLARE_COMPLETION_ONSTACK(completion); + DECLARE_TCS(tcs); if (!(dev->tproto & SAS_PROTOCOL_SSP)) return TMF_RESP_FUNC_ESUPP; @@ -514,6 +584,9 @@ static int asd_initiate_ssp_tmf(struct domain_device *dev, u8 *lun, ascb = asd_ascb_alloc_list(asd_ha, &res, GFP_KERNEL); if (!ascb) return -ENOMEM; + + ascb->completion = &completion; + ascb->uldd_task = &tcs; scb = ascb->scb; if (tmf == TMF_QUERY_TASK) @@ -546,31 +619,32 @@ static int asd_initiate_ssp_tmf(struct domain_device *dev, u8 *lun, asd_tmf_timedout); if (res) goto out_err; - wait_for_completion(&ascb->completion); - res = (int) (unsigned long) ascb->uldd_task; + wait_for_completion(&completion); - switch (res) { - case TC_NO_ERROR + 0xFF00: + switch (tcs.dl_opcode) { + case TC_NO_ERROR: res = TMF_RESP_FUNC_COMPLETE; break; - case TF_NAK_RECV + 0xFF00: + case TF_NAK_RECV: res = TMF_RESP_INVALID_FRAME; break; - case TF_TMF_TASK_DONE + 0xFF00: + case TF_TMF_TASK_DONE: res = TMF_RESP_FUNC_FAILED; break; - case TF_TMF_NO_TAG + 0xFF00: - case TF_TMF_TAG_FREE + 0xFF00: /* the tag is in the free list */ - case TF_TMF_NO_CONN_HANDLE + 0xFF00: /* no such device */ + case TF_TMF_NO_TAG: + case TF_TMF_TAG_FREE: /* the tag is in the free list */ + case TF_TMF_NO_CONN_HANDLE: /* no such device */ res = TMF_RESP_FUNC_COMPLETE; break; - case TF_TMF_NO_CTX + 0xFF00: /* not in seq, or proto != SSP */ + case TF_TMF_NO_CTX: /* not in seq, or proto != SSP */ res = TMF_RESP_FUNC_ESUPP; break; default: /* Allow TMF response codes to propagate upwards */ + res = tcs.dl_opcode; break; } + return res; out_err: asd_ascb_free(ascb); return res; diff --git a/drivers/scsi/arcmsr/arcmsr.h b/drivers/scsi/arcmsr/arcmsr.h index 57786502e3e..3288be2e49f 100644 --- a/drivers/scsi/arcmsr/arcmsr.h +++ b/drivers/scsi/arcmsr/arcmsr.h @@ -48,7 +48,7 @@ struct class_device_attribute; /*The limit of outstanding scsi command that firmware can handle*/ #define ARCMSR_MAX_OUTSTANDING_CMD 256 #define ARCMSR_MAX_FREECCB_NUM 320 -#define ARCMSR_DRIVER_VERSION "Driver Version 1.20.00.15 2007/12/24" +#define ARCMSR_DRIVER_VERSION "Driver Version 1.20.00.15 2008/02/27" #define ARCMSR_SCSI_INITIATOR_ID 255 #define ARCMSR_MAX_XFER_SECTORS 512 #define ARCMSR_MAX_XFER_SECTORS_B 4096 @@ -341,13 +341,13 @@ struct MessageUnit_B uint32_t done_qbuffer[ARCMSR_MAX_HBB_POSTQUEUE]; uint32_t postq_index; uint32_t doneq_index; - uint32_t __iomem *drv2iop_doorbell_reg; - uint32_t __iomem *drv2iop_doorbell_mask_reg; - uint32_t __iomem *iop2drv_doorbell_reg; - uint32_t __iomem *iop2drv_doorbell_mask_reg; - uint32_t __iomem *msgcode_rwbuffer_reg; - uint32_t __iomem *ioctl_wbuffer_reg; - uint32_t __iomem *ioctl_rbuffer_reg; + void __iomem *drv2iop_doorbell_reg; + void __iomem *drv2iop_doorbell_mask_reg; + void __iomem *iop2drv_doorbell_reg; + void __iomem *iop2drv_doorbell_mask_reg; + void __iomem *msgcode_rwbuffer_reg; + void __iomem *ioctl_wbuffer_reg; + void __iomem *ioctl_rbuffer_reg; }; /* diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c index 6d67f5c0eb8..0b2080d3357 100644 --- a/drivers/scsi/gdth.c +++ b/drivers/scsi/gdth.c @@ -160,7 +160,7 @@ static void gdth_readapp_event(gdth_ha_str *ha, unchar application, static void gdth_clear_events(void); static void gdth_copy_internal_data(gdth_ha_str *ha, Scsi_Cmnd *scp, - char *buffer, ushort count, int to_buffer); + char *buffer, ushort count); static int gdth_internal_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp); static int gdth_fill_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, ushort hdrive); @@ -182,7 +182,6 @@ static int gdth_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, unsigned long arg); static void gdth_flush(gdth_ha_str *ha); -static int gdth_halt(struct notifier_block *nb, ulong event, void *buf); static int gdth_queuecommand(Scsi_Cmnd *scp,void (*done)(Scsi_Cmnd *)); static int __gdth_queuecommand(gdth_ha_str *ha, struct scsi_cmnd *scp, struct gdth_cmndinfo *cmndinfo); @@ -417,12 +416,6 @@ static inline void gdth_set_sglist(struct scsi_cmnd *cmd, #include "gdth_proc.h" #include "gdth_proc.c" -/* notifier block to get a notify on system shutdown/halt/reboot */ -static struct notifier_block gdth_notifier = { - gdth_halt, NULL, 0 -}; -static int notifier_disabled = 0; - static gdth_ha_str *gdth_find_ha(int hanum) { gdth_ha_str *ha; @@ -445,8 +438,8 @@ static struct gdth_cmndinfo *gdth_get_cmndinfo(gdth_ha_str *ha) for (i=0; i<GDTH_MAXCMDS; ++i) { if (ha->cmndinfo[i].index == 0) { priv = &ha->cmndinfo[i]; - priv->index = i+1; memset(priv, 0, sizeof(*priv)); + priv->index = i+1; break; } } @@ -493,7 +486,6 @@ int __gdth_execute(struct scsi_device *sdev, gdth_cmd_str *gdtcmd, char *cmnd, gdth_ha_str *ha = shost_priv(sdev->host); Scsi_Cmnd *scp; struct gdth_cmndinfo cmndinfo; - struct scatterlist one_sg; DECLARE_COMPLETION_ONSTACK(wait); int rval; @@ -501,19 +493,22 @@ int __gdth_execute(struct scsi_device *sdev, gdth_cmd_str *gdtcmd, char *cmnd, if (!scp) return -ENOMEM; + scp->sense_buffer = kzalloc(SCSI_SENSE_BUFFERSIZE, GFP_KERNEL); + if (!scp->sense_buffer) { + kfree(scp); + return -ENOMEM; + } + scp->device = sdev; memset(&cmndinfo, 0, sizeof(cmndinfo)); /* use request field to save the ptr. to completion struct. */ scp->request = (struct request *)&wait; scp->timeout_per_command = timeout*HZ; - sg_init_one(&one_sg, gdtcmd, sizeof(*gdtcmd)); - gdth_set_sglist(scp, &one_sg); - gdth_set_sg_count(scp, 1); - gdth_set_bufflen(scp, sizeof(*gdtcmd)); scp->cmd_len = 12; memcpy(scp->cmnd, cmnd, 12); cmndinfo.priority = IOCTL_PRI; + cmndinfo.internal_cmd_str = gdtcmd; cmndinfo.internal_command = 1; TRACE(("__gdth_execute() cmd 0x%x\n", scp->cmnd[0])); @@ -524,6 +519,7 @@ int __gdth_execute(struct scsi_device *sdev, gdth_cmd_str *gdtcmd, char *cmnd, rval = cmndinfo.status; if (info) *info = cmndinfo.info; + kfree(scp->sense_buffer); kfree(scp); return rval; } @@ -2355,7 +2351,7 @@ static void gdth_next(gdth_ha_str *ha) * buffers, kmap_atomic() as needed. */ static void gdth_copy_internal_data(gdth_ha_str *ha, Scsi_Cmnd *scp, - char *buffer, ushort count, int to_buffer) + char *buffer, ushort count) { ushort cpcount,i, max_sg = gdth_sg_count(scp); ushort cpsum,cpnow; @@ -2381,10 +2377,7 @@ static void gdth_copy_internal_data(gdth_ha_str *ha, Scsi_Cmnd *scp, } local_irq_save(flags); address = kmap_atomic(sg_page(sl), KM_BIO_SRC_IRQ) + sl->offset; - if (to_buffer) - memcpy(buffer, address, cpnow); - else - memcpy(address, buffer, cpnow); + memcpy(address, buffer, cpnow); flush_dcache_page(sg_page(sl)); kunmap_atomic(address, KM_BIO_SRC_IRQ); local_irq_restore(flags); @@ -2438,7 +2431,7 @@ static int gdth_internal_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp) strcpy(inq.vendor,ha->oem_name); sprintf(inq.product,"Host Drive #%02d",t); strcpy(inq.revision," "); - gdth_copy_internal_data(ha, scp, (char*)&inq, sizeof(gdth_inq_data), 0); + gdth_copy_internal_data(ha, scp, (char*)&inq, sizeof(gdth_inq_data)); break; case REQUEST_SENSE: @@ -2448,7 +2441,7 @@ static int gdth_internal_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp) sd.key = NO_SENSE; sd.info = 0; sd.add_length= 0; - gdth_copy_internal_data(ha, scp, (char*)&sd, sizeof(gdth_sense_data), 0); + gdth_copy_internal_data(ha, scp, (char*)&sd, sizeof(gdth_sense_data)); break; case MODE_SENSE: @@ -2460,7 +2453,7 @@ static int gdth_internal_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp) mpd.bd.block_length[0] = (SECTOR_SIZE & 0x00ff0000) >> 16; mpd.bd.block_length[1] = (SECTOR_SIZE & 0x0000ff00) >> 8; mpd.bd.block_length[2] = (SECTOR_SIZE & 0x000000ff); - gdth_copy_internal_data(ha, scp, (char*)&mpd, sizeof(gdth_modep_data), 0); + gdth_copy_internal_data(ha, scp, (char*)&mpd, sizeof(gdth_modep_data)); break; case READ_CAPACITY: @@ -2470,7 +2463,7 @@ static int gdth_internal_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp) else rdc.last_block_no = cpu_to_be32(ha->hdr[t].size-1); rdc.block_length = cpu_to_be32(SECTOR_SIZE); - gdth_copy_internal_data(ha, scp, (char*)&rdc, sizeof(gdth_rdcap_data), 0); + gdth_copy_internal_data(ha, scp, (char*)&rdc, sizeof(gdth_rdcap_data)); break; case SERVICE_ACTION_IN: @@ -2482,7 +2475,7 @@ static int gdth_internal_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp) rdc16.last_block_no = cpu_to_be64(ha->hdr[t].size-1); rdc16.block_length = cpu_to_be32(SECTOR_SIZE); gdth_copy_internal_data(ha, scp, (char*)&rdc16, - sizeof(gdth_rdcap16_data), 0); + sizeof(gdth_rdcap16_data)); } else { scp->result = DID_ABORT << 16; } @@ -2852,6 +2845,7 @@ static int gdth_fill_raw_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, unchar b) static int gdth_special_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp) { register gdth_cmd_str *cmdp; + struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp); int cmd_index; cmdp= ha->pccb; @@ -2860,7 +2854,7 @@ static int gdth_special_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp) if (ha->type==GDT_EISA && ha->cmd_cnt>0) return 0; - gdth_copy_internal_data(ha, scp, (char *)cmdp, sizeof(gdth_cmd_str), 1); + *cmdp = *cmndinfo->internal_cmd_str; cmdp->RequestBuffer = scp; /* search free command index */ @@ -3794,6 +3788,8 @@ static void gdth_timeout(ulong data) gdth_ha_str *ha; ulong flags; + BUG_ON(list_empty(&gdth_instances)); + ha = list_first_entry(&gdth_instances, gdth_ha_str, list); spin_lock_irqsave(&ha->smp_lock, flags); @@ -4669,45 +4665,6 @@ static void gdth_flush(gdth_ha_str *ha) } } -/* shutdown routine */ -static int gdth_halt(struct notifier_block *nb, ulong event, void *buf) -{ - gdth_ha_str *ha; -#ifndef __alpha__ - gdth_cmd_str gdtcmd; - char cmnd[MAX_COMMAND_SIZE]; -#endif - - if (notifier_disabled) - return NOTIFY_OK; - - TRACE2(("gdth_halt() event %d\n",(int)event)); - if (event != SYS_RESTART && event != SYS_HALT && event != SYS_POWER_OFF) - return NOTIFY_DONE; - - notifier_disabled = 1; - printk("GDT-HA: Flushing all host drives .. "); - list_for_each_entry(ha, &gdth_instances, list) { - gdth_flush(ha); - -#ifndef __alpha__ - /* controller reset */ - memset(cmnd, 0xff, MAX_COMMAND_SIZE); - gdtcmd.BoardNode = LOCALBOARD; - gdtcmd.Service = CACHESERVICE; - gdtcmd.OpCode = GDT_RESET; - TRACE2(("gdth_halt(): reset controller %d\n", ha->hanum)); - gdth_execute(ha->shost, &gdtcmd, cmnd, 10, NULL); -#endif - } - printk("Done.\n"); - -#ifdef GDTH_STATISTICS - del_timer(&gdth_timer); -#endif - return NOTIFY_OK; -} - /* configure lun */ static int gdth_slave_configure(struct scsi_device *sdev) { @@ -5142,13 +5099,13 @@ static void gdth_remove_one(gdth_ha_str *ha) scsi_remove_host(shp); + gdth_flush(ha); + if (ha->sdev) { scsi_free_host_dev(ha->sdev); ha->sdev = NULL; } - gdth_flush(ha); - if (shp->irq) free_irq(shp->irq,ha); @@ -5174,6 +5131,24 @@ static void gdth_remove_one(gdth_ha_str *ha) scsi_host_put(shp); } +static int gdth_halt(struct notifier_block *nb, ulong event, void *buf) +{ + gdth_ha_str *ha; + + TRACE2(("gdth_halt() event %d\n", (int)event)); + if (event != SYS_RESTART && event != SYS_HALT && event != SYS_POWER_OFF) + return NOTIFY_DONE; + + list_for_each_entry(ha, &gdth_instances, list) + gdth_flush(ha); + + return NOTIFY_OK; +} + +static struct notifier_block gdth_notifier = { + gdth_halt, NULL, 0 +}; + static int __init gdth_init(void) { if (disable) { @@ -5236,7 +5211,6 @@ static int __init gdth_init(void) add_timer(&gdth_timer); #endif major = register_chrdev(0,"gdth", &gdth_fops); - notifier_disabled = 0; register_reboot_notifier(&gdth_notifier); gdth_polling = FALSE; return 0; @@ -5246,14 +5220,15 @@ static void __exit gdth_exit(void) { gdth_ha_str *ha; - list_for_each_entry(ha, &gdth_instances, list) - gdth_remove_one(ha); + unregister_chrdev(major, "gdth"); + unregister_reboot_notifier(&gdth_notifier); #ifdef GDTH_STATISTICS - del_timer(&gdth_timer); + del_timer_sync(&gdth_timer); #endif - unregister_chrdev(major,"gdth"); - unregister_reboot_notifier(&gdth_notifier); + + list_for_each_entry(ha, &gdth_instances, list) + gdth_remove_one(ha); } module_init(gdth_init); diff --git a/drivers/scsi/gdth.h b/drivers/scsi/gdth.h index 1434c6b0297..26e4e92515e 100644 --- a/drivers/scsi/gdth.h +++ b/drivers/scsi/gdth.h @@ -915,6 +915,7 @@ typedef struct { struct gdth_cmndinfo { /* per-command private info */ int index; int internal_command; /* don't call scsi_done */ + gdth_cmd_str *internal_cmd_str; /* crier for internal messages*/ dma_addr_t sense_paddr; /* sense dma-addr */ unchar priority; int timeout; diff --git a/drivers/scsi/ibmvscsi/ibmvstgt.c b/drivers/scsi/ibmvscsi/ibmvstgt.c index bd62131b97a..e5881e92d0f 100644 --- a/drivers/scsi/ibmvscsi/ibmvstgt.c +++ b/drivers/scsi/ibmvscsi/ibmvstgt.c @@ -290,7 +290,7 @@ static int ibmvstgt_cmd_done(struct scsi_cmnd *sc, int err = 0; dprintk("%p %p %x %u\n", iue, target, vio_iu(iue)->srp.cmd.cdb[0], - cmd->usg_sg); + scsi_sg_count(sc)); if (scsi_sg_count(sc)) err = srp_transfer_data(sc, &vio_iu(iue)->srp.cmd, ibmvstgt_rdma, 1, 1); @@ -838,9 +838,6 @@ static int ibmvstgt_probe(struct vio_dev *dev, const struct vio_device_id *id) if (!shost) goto free_vport; shost->transportt = ibmvstgt_transport_template; - err = scsi_tgt_alloc_queue(shost); - if (err) - goto put_host; target = host_to_srp_target(shost); target->shost = shost; @@ -872,6 +869,10 @@ static int ibmvstgt_probe(struct vio_dev *dev, const struct vio_device_id *id) if (err) goto destroy_queue; + err = scsi_tgt_alloc_queue(shost); + if (err) + goto destroy_queue; + return 0; destroy_queue: crq_queue_destroy(target); diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 59f8445eab0..bdd7de7da39 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -1708,8 +1708,8 @@ iscsi_session_setup(struct iscsi_transport *iscsit, qdepth = ISCSI_DEF_CMD_PER_LUN; } - if (!is_power_of_2(cmds_max) || - cmds_max >= ISCSI_MGMT_ITT_OFFSET) { + if (!is_power_of_2(cmds_max) || cmds_max >= ISCSI_MGMT_ITT_OFFSET || + cmds_max < 2) { if (cmds_max != 0) printk(KERN_ERR "iscsi: invalid can_queue of %d. " "can_queue must be a power of 2 and between " diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index 7cd05b599a1..b0e5ac372a3 100644 --- a/drivers/scsi/libsas/sas_ata.c +++ b/drivers/scsi/libsas/sas_ata.c @@ -236,12 +236,12 @@ static void sas_ata_phy_reset(struct ata_port *ap) struct domain_device *dev = ap->private_data; struct sas_internal *i = to_sas_internal(dev->port->ha->core.shost->transportt); - int res = 0; + int res = TMF_RESP_FUNC_FAILED; if (i->dft->lldd_I_T_nexus_reset) res = i->dft->lldd_I_T_nexus_reset(dev); - if (res) + if (res != TMF_RESP_FUNC_COMPLETE) SAS_DPRINTK("%s: Unable to reset I T nexus?\n", __FUNCTION__); switch (dev->sata_dev.command_set) { @@ -656,21 +656,6 @@ out: return res; } -static void sas_sata_propagate_sas_addr(struct domain_device *dev) -{ - unsigned long flags; - struct asd_sas_port *port = dev->port; - struct asd_sas_phy *phy; - - BUG_ON(dev->parent); - - memcpy(port->attached_sas_addr, dev->sas_addr, SAS_ADDR_SIZE); - spin_lock_irqsave(&port->phy_list_lock, flags); - list_for_each_entry(phy, &port->phy_list, port_phy_el) - memcpy(phy->attached_sas_addr, dev->sas_addr, SAS_ADDR_SIZE); - spin_unlock_irqrestore(&port->phy_list_lock, flags); -} - #define ATA_IDENTIFY_DEV 0xEC #define ATA_IDENTIFY_PACKET_DEV 0xA1 #define ATA_SET_FEATURES 0xEF @@ -728,26 +713,6 @@ static int sas_discover_sata_dev(struct domain_device *dev) goto out_err; } cont1: - /* Get WWN */ - if (dev->port->oob_mode != SATA_OOB_MODE) { - memcpy(dev->sas_addr, dev->sata_dev.rps_resp.rps.stp_sas_addr, - SAS_ADDR_SIZE); - } else if (dev->sata_dev.command_set == ATA_COMMAND_SET && - (le16_to_cpu(dev->sata_dev.identify_device[108]) & 0xF000) - == 0x5000) { - int i; - - for (i = 0; i < 4; i++) { - dev->sas_addr[2*i] = - (le16_to_cpu(dev->sata_dev.identify_device[108+i]) & 0xFF00) >> 8; - dev->sas_addr[2*i+1] = - le16_to_cpu(dev->sata_dev.identify_device[108+i]) & 0x00FF; - } - } - sas_hash_addr(dev->hashed_sas_addr, dev->sas_addr); - if (!dev->parent) - sas_sata_propagate_sas_addr(dev); - /* XXX Hint: register this SATA device with SATL. When this returns, dev->sata_dev->lu is alive and present. diff --git a/drivers/scsi/libsas/sas_port.c b/drivers/scsi/libsas/sas_port.c index e1e2d085c92..39ae68a3b0e 100644 --- a/drivers/scsi/libsas/sas_port.c +++ b/drivers/scsi/libsas/sas_port.c @@ -92,9 +92,6 @@ static void sas_form_port(struct asd_sas_phy *phy) if (!port->phy) port->phy = phy->phy; - SAS_DPRINTK("phy%d added to port%d, phy_mask:0x%x\n", phy->id, - port->id, port->phy_mask); - if (*(u64 *)port->attached_sas_addr == 0) { port->class = phy->class; memcpy(port->attached_sas_addr, phy->attached_sas_addr, @@ -115,6 +112,11 @@ static void sas_form_port(struct asd_sas_phy *phy) } sas_port_add_phy(port->port, phy->phy); + SAS_DPRINTK("%s added to %s, phy_mask:0x%x (%16llx)\n", + phy->phy->dev.bus_id,port->port->dev.bus_id, + port->phy_mask, + SAS_ADDR(port->attached_sas_addr)); + if (port->port_dev) port->port_dev->pathways = port->num_phys; @@ -255,12 +257,11 @@ void sas_porte_hard_reset(struct work_struct *work) static void sas_init_port(struct asd_sas_port *port, struct sas_ha_struct *sas_ha, int i) { + memset(port, 0, sizeof(*port)); port->id = i; INIT_LIST_HEAD(&port->dev_list); spin_lock_init(&port->phy_list_lock); INIT_LIST_HEAD(&port->phy_list); - port->num_phys = 0; - port->phy_mask = 0; port->ha = sas_ha; spin_lock_init(&port->dev_list_lock); diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index 704ea06a6e5..1f8241563c6 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c @@ -434,7 +434,7 @@ static int sas_recover_I_T(struct domain_device *dev) } /* Find the sas_phy that's attached to this device */ -static struct sas_phy *find_local_sas_phy(struct domain_device *dev) +struct sas_phy *sas_find_local_phy(struct domain_device *dev) { struct domain_device *pdev = dev->parent; struct ex_phy *exphy = NULL; @@ -456,6 +456,7 @@ static struct sas_phy *find_local_sas_phy(struct domain_device *dev) BUG_ON(!exphy); return exphy->phy; } +EXPORT_SYMBOL_GPL(sas_find_local_phy); /* Attempt to send a LUN reset message to a device */ int sas_eh_device_reset_handler(struct scsi_cmnd *cmd) @@ -482,7 +483,7 @@ int sas_eh_device_reset_handler(struct scsi_cmnd *cmd) int sas_eh_bus_reset_handler(struct scsi_cmnd *cmd) { struct domain_device *dev = cmd_to_domain_dev(cmd); - struct sas_phy *phy = find_local_sas_phy(dev); + struct sas_phy *phy = sas_find_local_phy(dev); int res; res = sas_phy_reset(phy, 1); @@ -497,10 +498,10 @@ int sas_eh_bus_reset_handler(struct scsi_cmnd *cmd) } /* Try to reset a device */ -static int try_to_reset_cmd_device(struct Scsi_Host *shost, - struct scsi_cmnd *cmd) +static int try_to_reset_cmd_device(struct scsi_cmnd *cmd) { int res; + struct Scsi_Host *shost = cmd->device->host; if (!shost->hostt->eh_device_reset_handler) goto try_bus_reset; @@ -540,6 +541,12 @@ Again: need_reset = task->task_state_flags & SAS_TASK_NEED_DEV_RESET; spin_unlock_irqrestore(&task->task_state_lock, flags); + if (need_reset) { + SAS_DPRINTK("%s: task 0x%p requests reset\n", + __FUNCTION__, task); + goto reset; + } + SAS_DPRINTK("trying to find task 0x%p\n", task); res = sas_scsi_find_task(task); @@ -550,18 +557,15 @@ Again: SAS_DPRINTK("%s: task 0x%p is done\n", __FUNCTION__, task); sas_eh_finish_cmd(cmd); - if (need_reset) - try_to_reset_cmd_device(shost, cmd); continue; case TASK_IS_ABORTED: SAS_DPRINTK("%s: task 0x%p is aborted\n", __FUNCTION__, task); sas_eh_finish_cmd(cmd); - if (need_reset) - try_to_reset_cmd_device(shost, cmd); continue; case TASK_IS_AT_LU: SAS_DPRINTK("task 0x%p is at LU: lu recover\n", task); + reset: tmf_resp = sas_recover_lu(task->dev, cmd); if (tmf_resp == TMF_RESP_FUNC_COMPLETE) { SAS_DPRINTK("dev %016llx LU %x is " @@ -569,8 +573,6 @@ Again: SAS_ADDR(task->dev), cmd->device->lun); sas_eh_finish_cmd(cmd); - if (need_reset) - try_to_reset_cmd_device(shost, cmd); sas_scsi_clear_queue_lu(work_q, cmd); goto Again; } @@ -581,15 +583,15 @@ Again: task); tmf_resp = sas_recover_I_T(task->dev); if (tmf_resp == TMF_RESP_FUNC_COMPLETE) { + struct domain_device *dev = task->dev; SAS_DPRINTK("I_T %016llx recovered\n", SAS_ADDR(task->dev->sas_addr)); sas_eh_finish_cmd(cmd); - if (need_reset) - try_to_reset_cmd_device(shost, cmd); - sas_scsi_clear_queue_I_T(work_q, task->dev); + sas_scsi_clear_queue_I_T(work_q, dev); goto Again; } /* Hammer time :-) */ + try_to_reset_cmd_device(cmd); if (i->dft->lldd_clear_nexus_port) { struct asd_sas_port *port = task->dev->port; SAS_DPRINTK("clearing nexus for port:%d\n", @@ -599,8 +601,6 @@ Again: SAS_DPRINTK("clear nexus port:%d " "succeeded\n", port->id); sas_eh_finish_cmd(cmd); - if (need_reset) - try_to_reset_cmd_device(shost, cmd); sas_scsi_clear_queue_port(work_q, port); goto Again; @@ -613,8 +613,6 @@ Again: SAS_DPRINTK("clear nexus ha " "succeeded\n"); sas_eh_finish_cmd(cmd); - if (need_reset) - try_to_reset_cmd_device(shost, cmd); goto clear_q; } } @@ -628,8 +626,6 @@ Again: cmd->device->lun); sas_eh_finish_cmd(cmd); - if (need_reset) - try_to_reset_cmd_device(shost, cmd); goto clear_q; } } diff --git a/drivers/scsi/mvsas.c b/drivers/scsi/mvsas.c index d4a6ac3c9c4..5ec0665b3a3 100644 --- a/drivers/scsi/mvsas.c +++ b/drivers/scsi/mvsas.c @@ -40,7 +40,7 @@ #include <asm/io.h> #define DRV_NAME "mvsas" -#define DRV_VERSION "0.5" +#define DRV_VERSION "0.5.1" #define _MV_DUMP 0 #define MVS_DISABLE_NVRAM #define MVS_DISABLE_MSI @@ -1005,7 +1005,7 @@ err_out: return rc; #else /* FIXME , For SAS target mode */ - memcpy(buf, "\x00\x00\xab\x11\x30\x04\x05\x50", 8); + memcpy(buf, "\x50\x05\x04\x30\x11\xab\x00\x00", 8); return 0; #endif } @@ -1330,7 +1330,7 @@ static int mvs_int_rx(struct mvs_info *mvi, bool self_clear) mvs_hba_cq_dump(mvi); - if (unlikely(rx_desc & RXQ_DONE)) + if (likely(rx_desc & RXQ_DONE)) mvs_slot_complete(mvi, rx_desc); if (rx_desc & RXQ_ATTN) { attn = true; @@ -2720,9 +2720,8 @@ static int __devinit mvs_hw_init(struct mvs_info *mvi) msleep(100); /* init and reset phys */ for (i = 0; i < mvi->chip->n_phy; i++) { - /* FIXME: is this the correct dword order? */ - u32 lo = *((u32 *)&mvi->sas_addr[0]); - u32 hi = *((u32 *)&mvi->sas_addr[4]); + u32 lo = be32_to_cpu(*(u32 *)&mvi->sas_addr[4]); + u32 hi = be32_to_cpu(*(u32 *)&mvi->sas_addr[0]); mvs_detect_porttype(mvi, i); diff --git a/drivers/scsi/ps3rom.c b/drivers/scsi/ps3rom.c index 0cd614a0fa7..fad6cb5cba2 100644 --- a/drivers/scsi/ps3rom.c +++ b/drivers/scsi/ps3rom.c @@ -124,7 +124,7 @@ static int fill_from_dev_buffer(struct scsi_cmnd *cmd, const void *buf) } req_len += sgpnt->length; } - scsi_set_resid(cmd, req_len - act_len); + scsi_set_resid(cmd, buflen - act_len); return 0; } @@ -427,7 +427,7 @@ static struct scsi_host_template ps3rom_host_template = { .cmd_per_lun = 1, .emulated = 1, /* only sg driver uses this */ .max_sectors = PS3ROM_MAX_SECTORS, - .use_clustering = ENABLE_CLUSTERING, + .use_clustering = DISABLE_CLUSTERING, .module = THIS_MODULE, }; diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index 6226d88479f..c1808763d40 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -39,7 +39,7 @@ qla2x00_prep_ms_iocb(scsi_qla_host_t *ha, uint32_t req_size, uint32_t rsp_size) ms_pkt->entry_count = 1; SET_TARGET_ID(ha, ms_pkt->loop_id, SIMPLE_NAME_SERVER); ms_pkt->control_flags = __constant_cpu_to_le16(CF_READ | CF_HEAD_TAG); - ms_pkt->timeout = __constant_cpu_to_le16(25); + ms_pkt->timeout = cpu_to_le16(ha->r_a_tov / 10 * 2); ms_pkt->cmd_dsd_count = __constant_cpu_to_le16(1); ms_pkt->total_dsd_count = __constant_cpu_to_le16(2); ms_pkt->rsp_bytecount = cpu_to_le32(rsp_size); @@ -75,7 +75,7 @@ qla24xx_prep_ms_iocb(scsi_qla_host_t *ha, uint32_t req_size, uint32_t rsp_size) ct_pkt->entry_type = CT_IOCB_TYPE; ct_pkt->entry_count = 1; ct_pkt->nport_handle = __constant_cpu_to_le16(NPH_SNS); - ct_pkt->timeout = __constant_cpu_to_le16(25); + ct_pkt->timeout = cpu_to_le16(ha->r_a_tov / 10 * 2); ct_pkt->cmd_dsd_count = __constant_cpu_to_le16(1); ct_pkt->rsp_dsd_count = __constant_cpu_to_le16(1); ct_pkt->rsp_byte_count = cpu_to_le32(rsp_size); @@ -1144,7 +1144,7 @@ qla2x00_prep_ms_fdmi_iocb(scsi_qla_host_t *ha, uint32_t req_size, ms_pkt->entry_count = 1; SET_TARGET_ID(ha, ms_pkt->loop_id, ha->mgmt_svr_loop_id); ms_pkt->control_flags = __constant_cpu_to_le16(CF_READ | CF_HEAD_TAG); - ms_pkt->timeout = __constant_cpu_to_le16(59); + ms_pkt->timeout = cpu_to_le16(ha->r_a_tov / 10 * 2); ms_pkt->cmd_dsd_count = __constant_cpu_to_le16(1); ms_pkt->total_dsd_count = __constant_cpu_to_le16(2); ms_pkt->rsp_bytecount = cpu_to_le32(rsp_size); @@ -1181,7 +1181,7 @@ qla24xx_prep_ms_fdmi_iocb(scsi_qla_host_t *ha, uint32_t req_size, ct_pkt->entry_type = CT_IOCB_TYPE; ct_pkt->entry_count = 1; ct_pkt->nport_handle = cpu_to_le16(ha->mgmt_svr_loop_id); - ct_pkt->timeout = __constant_cpu_to_le16(59); + ct_pkt->timeout = cpu_to_le16(ha->r_a_tov / 10 * 2); ct_pkt->cmd_dsd_count = __constant_cpu_to_le16(1); ct_pkt->rsp_dsd_count = __constant_cpu_to_le16(1); ct_pkt->rsp_byte_count = cpu_to_le32(rsp_size); @@ -1761,7 +1761,7 @@ qla24xx_prep_ms_fm_iocb(scsi_qla_host_t *ha, uint32_t req_size, ct_pkt->entry_type = CT_IOCB_TYPE; ct_pkt->entry_count = 1; ct_pkt->nport_handle = cpu_to_le16(ha->mgmt_svr_loop_id); - ct_pkt->timeout = __constant_cpu_to_le16(59); + ct_pkt->timeout = cpu_to_le16(ha->r_a_tov / 10 * 2); ct_pkt->cmd_dsd_count = __constant_cpu_to_le16(1); ct_pkt->rsp_dsd_count = __constant_cpu_to_le16(1); ct_pkt->rsp_byte_count = cpu_to_le32(rsp_size); diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index d5c7853e7eb..364be7d0687 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -1733,8 +1733,8 @@ qla2x00_nvram_config(scsi_qla_host_t *ha) ha->login_timeout = nv->login_timeout; icb->login_timeout = nv->login_timeout; - /* Set minimum RATOV to 200 tenths of a second. */ - ha->r_a_tov = 200; + /* Set minimum RATOV to 100 tenths of a second. */ + ha->r_a_tov = 100; ha->loop_reset_delay = nv->reset_delay; @@ -3645,8 +3645,8 @@ qla24xx_nvram_config(scsi_qla_host_t *ha) ha->login_timeout = le16_to_cpu(nv->login_timeout); icb->login_timeout = cpu_to_le16(nv->login_timeout); - /* Set minimum RATOV to 200 tenths of a second. */ - ha->r_a_tov = 200; + /* Set minimum RATOV to 100 tenths of a second. */ + ha->r_a_tov = 100; ha->loop_reset_delay = nv->reset_delay; @@ -4022,7 +4022,8 @@ qla2x00_try_to_stop_firmware(scsi_qla_host_t *ha) return; ret = qla2x00_stop_firmware(ha); - for (retries = 5; ret != QLA_SUCCESS && retries ; retries--) { + for (retries = 5; ret != QLA_SUCCESS && ret != QLA_FUNCTION_TIMEOUT && + retries ; retries--) { qla2x00_reset_chip(ha); if (qla2x00_chip_diag(ha) != QLA_SUCCESS) continue; diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 14e6f22944b..f0337036c7b 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -958,6 +958,11 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt) } } + /* Check for overrun. */ + if (IS_FWI2_CAPABLE(ha) && comp_status == CS_COMPLETE && + scsi_status & SS_RESIDUAL_OVER) + comp_status = CS_DATA_OVERRUN; + /* * Based on Host and scsi status generate status code for Linux */ diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 99d29fff836..bb103580e1b 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -2206,7 +2206,7 @@ qla24xx_abort_target(fc_port_t *fcport) tsk->p.tsk.entry_type = TSK_MGMT_IOCB_TYPE; tsk->p.tsk.entry_count = 1; tsk->p.tsk.nport_handle = cpu_to_le16(fcport->loop_id); - tsk->p.tsk.timeout = __constant_cpu_to_le16(25); + tsk->p.tsk.timeout = cpu_to_le16(ha->r_a_tov / 10 * 2); tsk->p.tsk.control_flags = __constant_cpu_to_le32(TCF_TARGET_RESET); tsk->p.tsk.port_id[0] = fcport->d_id.b.al_pa; tsk->p.tsk.port_id[1] = fcport->d_id.b.area; diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index c5742cc15ab..ea08a129fee 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -7,7 +7,7 @@ /* * Driver version */ -#define QLA2XXX_VERSION "8.02.00-k8" +#define QLA2XXX_VERSION "8.02.00-k9" #define QLA_DRIVER_MAJOR_VER 8 #define QLA_DRIVER_MINOR_VER 2 diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c index 10b3b9a620f..109c5f5985e 100644 --- a/drivers/scsi/qla4xxx/ql4_init.c +++ b/drivers/scsi/qla4xxx/ql4_init.c @@ -1299,9 +1299,9 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, ddb_entry->fw_ddb_device_state = state; /* Device is back online. */ if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE) { + atomic_set(&ddb_entry->state, DDB_STATE_ONLINE); atomic_set(&ddb_entry->port_down_timer, ha->port_down_retry_count); - atomic_set(&ddb_entry->state, DDB_STATE_ONLINE); atomic_set(&ddb_entry->relogin_retry_count, 0); atomic_set(&ddb_entry->relogin_timer, 0); clear_bit(DF_RELOGIN, &ddb_entry->flags); diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index c3c59d76303..8b92f348f02 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -75,6 +75,7 @@ static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd); static int qla4xxx_slave_alloc(struct scsi_device *device); static int qla4xxx_slave_configure(struct scsi_device *device); static void qla4xxx_slave_destroy(struct scsi_device *sdev); +static void qla4xxx_scan_start(struct Scsi_Host *shost); static struct scsi_host_template qla4xxx_driver_template = { .module = THIS_MODULE, @@ -90,6 +91,7 @@ static struct scsi_host_template qla4xxx_driver_template = { .slave_destroy = qla4xxx_slave_destroy, .scan_finished = iscsi_scan_finished, + .scan_start = qla4xxx_scan_start, .this_id = -1, .cmd_per_lun = 3, @@ -299,6 +301,18 @@ struct ddb_entry *qla4xxx_alloc_sess(struct scsi_qla_host *ha) return ddb_entry; } +static void qla4xxx_scan_start(struct Scsi_Host *shost) +{ + struct scsi_qla_host *ha = shost_priv(shost); + struct ddb_entry *ddb_entry, *ddbtemp; + + /* finish setup of sessions that were already setup in firmware */ + list_for_each_entry_safe(ddb_entry, ddbtemp, &ha->ddb_list, list) { + if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE) + qla4xxx_add_sess(ddb_entry); + } +} + /* * Timer routines */ @@ -864,8 +878,9 @@ static void qla4xxx_flush_active_srbs(struct scsi_qla_host *ha) * qla4xxx_recover_adapter - recovers adapter after a fatal error * @ha: Pointer to host adapter structure. * @renew_ddb_list: Indicates what to do with the adapter's ddb list - * after adapter recovery has completed. - * 0=preserve ddb list, 1=destroy and rebuild ddb list + * + * renew_ddb_list value can be 0=preserve ddb list, 1=destroy and rebuild + * ddb list. **/ static int qla4xxx_recover_adapter(struct scsi_qla_host *ha, uint8_t renew_ddb_list) @@ -874,6 +889,7 @@ static int qla4xxx_recover_adapter(struct scsi_qla_host *ha, /* Stall incoming I/O until we are done */ clear_bit(AF_ONLINE, &ha->flags); + DEBUG2(printk("scsi%ld: %s calling qla4xxx_cmd_wait\n", ha->host_no, __func__)); @@ -1176,7 +1192,6 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, int ret = -ENODEV, status; struct Scsi_Host *host; struct scsi_qla_host *ha; - struct ddb_entry *ddb_entry, *ddbtemp; uint8_t init_retry_count = 0; char buf[34]; @@ -1295,13 +1310,6 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, if (ret) goto probe_failed; - /* Update transport device information for all devices. */ - list_for_each_entry_safe(ddb_entry, ddbtemp, &ha->ddb_list, list) { - if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE) - if (qla4xxx_add_sess(ddb_entry)) - goto remove_host; - } - printk(KERN_INFO " QLogic iSCSI HBA Driver version: %s\n" " QLogic ISP%04x @ %s, host#=%ld, fw=%02d.%02d.%02d.%02d\n", @@ -1311,10 +1319,6 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, scsi_scan_host(host); return 0; -remove_host: - qla4xxx_free_ddb_list(ha); - scsi_remove_host(host); - probe_failed: qla4xxx_free_adapter(ha); scsi_host_put(ha->host); @@ -1600,9 +1604,12 @@ static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd) return FAILED; } - if (qla4xxx_recover_adapter(ha, PRESERVE_DDB_LIST) == QLA_SUCCESS) { + /* make sure the dpc thread is stopped while we reset the hba */ + clear_bit(AF_ONLINE, &ha->flags); + flush_workqueue(ha->dpc_thread); + + if (qla4xxx_recover_adapter(ha, PRESERVE_DDB_LIST) == QLA_SUCCESS) return_status = SUCCESS; - } dev_info(&ha->pdev->dev, "HOST RESET %s.\n", return_status == FAILED ? "FAILED" : "SUCCEDED"); diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index fecba05b4e7..e5c6f6af876 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -757,7 +757,7 @@ void scsi_finish_command(struct scsi_cmnd *cmd) "Notifying upper driver of completion " "(result %x)\n", cmd->result)); - good_bytes = scsi_bufflen(cmd); + good_bytes = scsi_bufflen(cmd) + cmd->request->extra_len; if (cmd->request->cmd_type != REQ_TYPE_BLOCK_PC) { drv = scsi_cmd_to_driver(cmd); if (drv->done) diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index ba21d97d185..f40898dc2d1 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -2162,10 +2162,15 @@ void sdev_evt_send(struct scsi_device *sdev, struct scsi_event *evt) { unsigned long flags; +#if 0 + /* FIXME: currently this check eliminates all media change events + * for polled devices. Need to update to discriminate between AN + * and polled events */ if (!test_bit(evt->evt_type, sdev->supported_events)) { kfree(evt); return; } +#endif spin_lock_irqsave(&sdev->list_lock, flags); list_add_tail(&evt->node, &sdev->event_list); diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 1dc165ad17f..e67c14e31ba 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -1577,8 +1577,7 @@ static void __scsi_scan_target(struct device *parent, unsigned int channel, } /** - * scsi_scan_target - scan a target id, possibly including all LUNs on the - * target. + * scsi_scan_target - scan a target id, possibly including all LUNs on the target. * @parent: host to scan * @channel: channel to scan * @id: target id to scan diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index ed83cdb6e67..b9b09a70458 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -294,6 +294,7 @@ static void scsi_device_dev_release_usercontext(struct work_struct *work) } if (sdev->request_queue) { + bsg_unregister_queue(sdev->request_queue); sdev->request_queue->queuedata = NULL; /* user context needed to free queue */ scsi_free_queue(sdev->request_queue); @@ -857,7 +858,6 @@ void __scsi_remove_device(struct scsi_device *sdev) if (scsi_device_set_state(sdev, SDEV_CANCEL) != 0) return; - bsg_unregister_queue(sdev->request_queue); class_device_unregister(&sdev->sdev_classdev); transport_remove_device(dev); device_del(dev); diff --git a/drivers/scsi/scsi_tgt_lib.c b/drivers/scsi/scsi_tgt_lib.c index 3677fbb30b7..a0f308bd145 100644 --- a/drivers/scsi/scsi_tgt_lib.c +++ b/drivers/scsi/scsi_tgt_lib.c @@ -103,7 +103,6 @@ struct scsi_cmnd *scsi_host_get_command(struct Scsi_Host *shost, if (!cmd) goto release_rq; - memset(cmd, 0, sizeof(*cmd)); cmd->sc_data_direction = data_dir; cmd->jiffies_at_alloc = jiffies; cmd->request = rq; @@ -382,6 +381,11 @@ static int scsi_map_user_pages(struct scsi_tgt_cmd *tcmd, struct scsi_cmnd *cmd, scsi_release_buffers(cmd); goto unmap_rq; } + /* + * we use REQ_TYPE_BLOCK_PC so scsi_init_io doesn't set the + * length for us. + */ + cmd->sdb.length = rq->data_len; return 0; diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 9981682d530..ca7bb6f63bd 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -33,7 +33,7 @@ #define ISCSI_SESSION_ATTRS 19 #define ISCSI_CONN_ATTRS 13 #define ISCSI_HOST_ATTRS 4 -#define ISCSI_TRANSPORT_VERSION "2.0-868" +#define ISCSI_TRANSPORT_VERSION "2.0-869" struct iscsi_internal { int daemon_pid; @@ -373,24 +373,25 @@ static void session_recovery_timedout(struct work_struct *work) scsi_target_unblock(&session->dev); } -static void __iscsi_unblock_session(struct iscsi_cls_session *session) -{ - if (!cancel_delayed_work(&session->recovery_work)) - flush_workqueue(iscsi_eh_timer_workq); - scsi_target_unblock(&session->dev); -} - -void iscsi_unblock_session(struct iscsi_cls_session *session) +static void __iscsi_unblock_session(struct work_struct *work) { + struct iscsi_cls_session *session = + container_of(work, struct iscsi_cls_session, + unblock_work); struct Scsi_Host *shost = iscsi_session_to_shost(session); struct iscsi_host *ihost = shost->shost_data; unsigned long flags; + /* + * The recovery and unblock work get run from the same workqueue, + * so try to cancel it if it was going to run after this unblock. + */ + cancel_delayed_work(&session->recovery_work); spin_lock_irqsave(&session->lock, flags); session->state = ISCSI_SESSION_LOGGED_IN; spin_unlock_irqrestore(&session->lock, flags); - - __iscsi_unblock_session(session); + /* start IO */ + scsi_target_unblock(&session->dev); /* * Only do kernel scanning if the driver is properly hooked into * the async scanning code (drivers like iscsi_tcp do login and @@ -401,20 +402,43 @@ void iscsi_unblock_session(struct iscsi_cls_session *session) atomic_inc(&ihost->nr_scans); } } + +/** + * iscsi_unblock_session - set a session as logged in and start IO. + * @session: iscsi session + * + * Mark a session as ready to accept IO. + */ +void iscsi_unblock_session(struct iscsi_cls_session *session) +{ + queue_work(iscsi_eh_timer_workq, &session->unblock_work); + /* + * make sure all the events have completed before tell the driver + * it is safe + */ + flush_workqueue(iscsi_eh_timer_workq); +} EXPORT_SYMBOL_GPL(iscsi_unblock_session); -void iscsi_block_session(struct iscsi_cls_session *session) +static void __iscsi_block_session(struct work_struct *work) { + struct iscsi_cls_session *session = + container_of(work, struct iscsi_cls_session, + block_work); unsigned long flags; spin_lock_irqsave(&session->lock, flags); session->state = ISCSI_SESSION_FAILED; spin_unlock_irqrestore(&session->lock, flags); - scsi_target_block(&session->dev); queue_delayed_work(iscsi_eh_timer_workq, &session->recovery_work, session->recovery_tmo * HZ); } + +void iscsi_block_session(struct iscsi_cls_session *session) +{ + queue_work(iscsi_eh_timer_workq, &session->block_work); +} EXPORT_SYMBOL_GPL(iscsi_block_session); static void __iscsi_unbind_session(struct work_struct *work) @@ -463,6 +487,8 @@ iscsi_alloc_session(struct Scsi_Host *shost, INIT_DELAYED_WORK(&session->recovery_work, session_recovery_timedout); INIT_LIST_HEAD(&session->host_list); INIT_LIST_HEAD(&session->sess_list); + INIT_WORK(&session->unblock_work, __iscsi_unblock_session); + INIT_WORK(&session->block_work, __iscsi_block_session); INIT_WORK(&session->unbind_work, __iscsi_unbind_session); INIT_WORK(&session->scan_work, iscsi_scan_session); spin_lock_init(&session->lock); @@ -575,24 +601,25 @@ void iscsi_remove_session(struct iscsi_cls_session *session) list_del(&session->sess_list); spin_unlock_irqrestore(&sesslock, flags); + /* make sure there are no blocks/unblocks queued */ + flush_workqueue(iscsi_eh_timer_workq); + /* make sure the timedout callout is not running */ + if (!cancel_delayed_work(&session->recovery_work)) + flush_workqueue(iscsi_eh_timer_workq); /* * If we are blocked let commands flow again. The lld or iscsi * layer should set up the queuecommand to fail commands. + * We assume that LLD will not be calling block/unblock while + * removing the session. */ spin_lock_irqsave(&session->lock, flags); session->state = ISCSI_SESSION_FREE; spin_unlock_irqrestore(&session->lock, flags); - __iscsi_unblock_session(session); - __iscsi_unbind_session(&session->unbind_work); - /* flush running scans */ + scsi_target_unblock(&session->dev); + /* flush running scans then delete devices */ flush_workqueue(ihost->scan_workq); - /* - * If the session dropped while removing devices then we need to make - * sure it is not blocked - */ - if (!cancel_delayed_work(&session->recovery_work)) - flush_workqueue(iscsi_eh_timer_workq); + __iscsi_unbind_session(&session->unbind_work); /* hw iscsi may not have removed all connections from session */ err = device_for_each_child(&session->dev, NULL, @@ -802,23 +829,16 @@ EXPORT_SYMBOL_GPL(iscsi_recv_pdu); void iscsi_conn_error(struct iscsi_cls_conn *conn, enum iscsi_err error) { - struct iscsi_cls_session *session = iscsi_conn_to_session(conn); struct nlmsghdr *nlh; struct sk_buff *skb; struct iscsi_uevent *ev; struct iscsi_internal *priv; int len = NLMSG_SPACE(sizeof(*ev)); - unsigned long flags; priv = iscsi_if_transport_lookup(conn->transport); if (!priv) return; - spin_lock_irqsave(&session->lock, flags); - if (session->state == ISCSI_SESSION_LOGGED_IN) - session->state = ISCSI_SESSION_FAILED; - spin_unlock_irqrestore(&session->lock, flags); - skb = alloc_skb(len, GFP_ATOMIC); if (!skb) { iscsi_cls_conn_printk(KERN_ERR, conn, "gracefully ignored " diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 7aee64dbfbe..5fe7aaed904 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1654,6 +1654,7 @@ static int sd_probe(struct device *dev) sdkp->disk = gd; sdkp->index = index; sdkp->openers = 0; + sdkp->previous_state = 1; if (!sdp->timeout) { if (sdp->type != TYPE_MOD) diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index 208565bdbe8..7ee86d4a761 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -623,6 +623,7 @@ static int sr_probe(struct device *dev) cd->disk = disk; cd->capacity = 0x1fffff; cd->device->changed = 1; /* force recheck CD type */ + cd->previous_state = 1; cd->use = 1; cd->readcd_known = 0; cd->readcd_cdda = 0; diff --git a/drivers/serial/8250_pnp.c b/drivers/serial/8250_pnp.c index 6f09cbd7fc4..97c68d021d2 100644 --- a/drivers/serial/8250_pnp.c +++ b/drivers/serial/8250_pnp.c @@ -91,6 +91,8 @@ static const struct pnp_device_id pnp_dev_table[] = { /* Archtek America Corp. */ /* Archtek SmartLink Modem 3334BT Plug & Play */ { "GVC000F", 0 }, + /* Archtek SmartLink Modem 3334BRV 33.6K Data Fax Voice */ + { "GVC0303", 0 }, /* Hayes */ /* Hayes Optima 288 V.34-V.FC + FAX + Voice Plug & Play */ { "HAY0001", 0 }, diff --git a/drivers/serial/m32r_sio.c b/drivers/serial/m32r_sio.c index 348ee2c19b5..c2bb11c02bd 100644 --- a/drivers/serial/m32r_sio.c +++ b/drivers/serial/m32r_sio.c @@ -421,7 +421,7 @@ static void transmit_chars(struct uart_sio_port *up) up->port.icount.tx++; if (uart_circ_empty(xmit)) break; - while (!serial_in(up, UART_LSR) & UART_LSR_THRE); + while (!(serial_in(up, UART_LSR) & UART_LSR_THRE)); } while (--count > 0); diff --git a/drivers/serial/of_serial.c b/drivers/serial/of_serial.c index a64d8582199..c0e50a46105 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/serial/sh-sci.c b/drivers/serial/sh-sci.c index a8c116b80bf..9d244d1644e 100644 --- a/drivers/serial/sh-sci.c +++ b/drivers/serial/sh-sci.c @@ -414,12 +414,12 @@ static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag) defined(CONFIG_CPU_SUBTYPE_SH7785) static inline int scif_txroom(struct uart_port *port) { - return SCIF_TXROOM_MAX - (sci_in(port, SCTFDR) & 0x7f); + return SCIF_TXROOM_MAX - (sci_in(port, SCTFDR) & 0xff); } static inline int scif_rxroom(struct uart_port *port) { - return sci_in(port, SCRFDR) & 0x7f; + return sci_in(port, SCRFDR) & 0xff; } #else static inline int scif_txroom(struct uart_port *port) diff --git a/drivers/sn/ioc3.c b/drivers/sn/ioc3.c index 29fcd6d0301..a0aa33dde0a 100644 --- a/drivers/sn/ioc3.c +++ b/drivers/sn/ioc3.c @@ -561,7 +561,7 @@ void ioc3_unregister_submodule(struct ioc3_submodule *is) printk(KERN_WARNING "%s: IOC3 submodule %s remove failed " "for pci_dev %s.\n", - __FUNCTION__, module_name(is->owner), + __func__, module_name(is->owner), pci_name(idd->pdev)); idd->active[is->id] = 0; if(is->irq_mask) @@ -611,7 +611,7 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) if ((ret = pci_enable_device(pdev))) { printk(KERN_WARNING "%s: Failed to enable IOC3 device for pci_dev %s.\n", - __FUNCTION__, pci_name(pdev)); + __func__, pci_name(pdev)); goto out; } pci_set_master(pdev); @@ -623,7 +623,7 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) if (ret < 0) { printk(KERN_WARNING "%s: Unable to obtain 64 bit DMA " "for consistent allocations\n", - __FUNCTION__); + __func__); } } #endif @@ -633,7 +633,7 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) if (!idd) { printk(KERN_WARNING "%s: Failed to allocate IOC3 data for pci_dev %s.\n", - __FUNCTION__, pci_name(pdev)); + __func__, pci_name(pdev)); ret = -ENODEV; goto out_idd; } @@ -649,7 +649,7 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) printk(KERN_WARNING "%s: Unable to find IOC3 resource " "for pci_dev %s.\n", - __FUNCTION__, pci_name(pdev)); + __func__, pci_name(pdev)); ret = -ENODEV; goto out_pci; } @@ -657,7 +657,7 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) printk(KERN_WARNING "%s: Unable to request IOC3 region " "for pci_dev %s.\n", - __FUNCTION__, pci_name(pdev)); + __func__, pci_name(pdev)); ret = -ENODEV; goto out_pci; } @@ -666,7 +666,7 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) printk(KERN_WARNING "%s: Unable to remap IOC3 region " "for pci_dev %s.\n", - __FUNCTION__, pci_name(pdev)); + __func__, pci_name(pdev)); ret = -ENODEV; goto out_misc_region; } @@ -709,7 +709,7 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) } else { printk(KERN_WARNING "%s : request_irq fails for IRQ 0x%x\n ", - __FUNCTION__, pdev->irq); + __func__, pdev->irq); } if (!request_irq(pdev->irq+2, ioc3_intr_io, IRQF_SHARED, "ioc3-io", (void *)idd)) { @@ -717,7 +717,7 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) } else { printk(KERN_WARNING "%s : request_irq fails for IRQ 0x%x\n ", - __FUNCTION__, pdev->irq+2); + __func__, pdev->irq+2); } } else { if (!request_irq(pdev->irq, ioc3_intr_io, IRQF_SHARED, @@ -726,7 +726,7 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) } else { printk(KERN_WARNING "%s : request_irq fails for IRQ 0x%x\n ", - __FUNCTION__, pdev->irq); + __func__, pdev->irq); } } @@ -769,7 +769,7 @@ static void ioc3_remove(struct pci_dev *pdev) printk(KERN_WARNING "%s: IOC3 submodule 0x%s remove failed " "for pci_dev %s.\n", - __FUNCTION__, + __func__, module_name(ioc3_submodules[id]->owner), pci_name(pdev)); idd->active[id] = 0; diff --git a/drivers/spi/au1550_spi.c b/drivers/spi/au1550_spi.c index c47a650183a..41a3d00c451 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/mpc52xx_psc_spi.c b/drivers/spi/mpc52xx_psc_spi.c index 253ed5682a6..a86315a0c5b 100644 --- a/drivers/spi/mpc52xx_psc_spi.c +++ b/drivers/spi/mpc52xx_psc_spi.c @@ -42,6 +42,7 @@ struct mpc52xx_psc_spi { /* driver internal data */ struct mpc52xx_psc __iomem *psc; + struct mpc52xx_psc_fifo __iomem *fifo; unsigned int irq; u8 bits_per_word; u8 busy; @@ -139,6 +140,7 @@ static int mpc52xx_psc_spi_transfer_rxtx(struct spi_device *spi, { struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master); struct mpc52xx_psc __iomem *psc = mps->psc; + struct mpc52xx_psc_fifo __iomem *fifo = mps->fifo; unsigned rb = 0; /* number of bytes receieved */ unsigned sb = 0; /* number of bytes sent */ unsigned char *rx_buf = (unsigned char *)t->rx_buf; @@ -190,11 +192,11 @@ static int mpc52xx_psc_spi_transfer_rxtx(struct spi_device *spi, out_8(&psc->mode, 0); } else { out_8(&psc->mode, MPC52xx_PSC_MODE_FFULL); - out_be16(&psc->rfalarm, rfalarm); + out_be16(&fifo->rfalarm, rfalarm); } out_be16(&psc->mpc52xx_psc_imr, MPC52xx_PSC_IMR_RXRDY); wait_for_completion(&mps->done); - recv_at_once = in_be16(&psc->rfnum); + recv_at_once = in_be16(&fifo->rfnum); dev_dbg(&spi->dev, "%d bytes received\n", recv_at_once); send_at_once = recv_at_once; @@ -331,6 +333,7 @@ static void mpc52xx_psc_spi_cleanup(struct spi_device *spi) static int mpc52xx_psc_spi_port_config(int psc_id, struct mpc52xx_psc_spi *mps) { struct mpc52xx_psc __iomem *psc = mps->psc; + struct mpc52xx_psc_fifo __iomem *fifo = mps->fifo; u32 mclken_div; int ret = 0; @@ -346,7 +349,7 @@ static int mpc52xx_psc_spi_port_config(int psc_id, struct mpc52xx_psc_spi *mps) /* Disable interrupts, interrupts are based on alarm level */ out_be16(&psc->mpc52xx_psc_imr, 0); out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1); - out_8(&psc->rfcntl, 0); + out_8(&fifo->rfcntl, 0); out_8(&psc->mode, MPC52xx_PSC_MODE_FFULL); /* Configure 8bit codec mode as a SPI master and use EOF flags */ @@ -419,6 +422,8 @@ static int __init mpc52xx_psc_spi_do_probe(struct device *dev, u32 regaddr, ret = -EFAULT; goto free_master; } + /* On the 5200, fifo regs are immediately ajacent to the psc regs */ + mps->fifo = ((void __iomem *)mps->psc) + sizeof(struct mpc52xx_psc); ret = request_irq(mps->irq, mpc52xx_psc_spi_isr, 0, "mpc52xx-psc-spi", mps); diff --git a/drivers/spi/spi_bitbang.c b/drivers/spi/spi_bitbang.c index f7f8580edad..71e881419cd 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/ssb/driver_pcicore.c b/drivers/ssb/driver_pcicore.c index 07ab48d9cea..74b9a8aea52 100644 --- a/drivers/ssb/driver_pcicore.c +++ b/drivers/ssb/driver_pcicore.c @@ -111,7 +111,10 @@ static void __init ssb_fixup_pcibridge(struct pci_dev *dev) /* Enable PCI bridge bus mastering and memory space */ pci_set_master(dev); - pcibios_enable_device(dev, ~0); + if (pcibios_enable_device(dev, ~0) < 0) { + ssb_printk(KERN_ERR "PCI: SSB bridge enable failed\n"); + return; + } /* Enable PCI bridge BAR1 prefetch and burst */ pci_write_config_dword(dev, SSB_BAR1_CONTROL, 3); diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index 69f19f22487..17e71d56f31 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/uio/uio.c b/drivers/uio/uio.c index e8a01f26454..11759080ca5 100644 --- a/drivers/uio/uio.c +++ b/drivers/uio/uio.c @@ -470,6 +470,8 @@ static int uio_mmap_physical(struct vm_area_struct *vma) vma->vm_flags |= VM_IO | VM_RESERVED; + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + return remap_pfn_range(vma, vma->vm_start, idev->info->mem[mi].addr >> PAGE_SHIFT, diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig index 5c33cdb9cac..a2b0aa48b8e 100644 --- a/drivers/usb/core/Kconfig +++ b/drivers/usb/core/Kconfig @@ -87,12 +87,13 @@ config USB_DYNAMIC_MINORS If you are unsure about this, say N here. config USB_SUSPEND - bool "USB selective suspend/resume and wakeup (EXPERIMENTAL)" - depends on USB && PM && EXPERIMENTAL + bool "USB selective suspend/resume and wakeup" + depends on USB && PM help If you say Y here, you can use driver calls or the sysfs - "power/state" file to suspend or resume individual USB - peripherals. + "power/level" file to suspend or resume individual USB + peripherals and to enable or disable autosuspend (see + Documentation/usb/power-management.txt for more details). Also, USB "remote wakeup" signaling is supported, whereby some USB devices (like keyboards and network adapters) can wake up diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index fefb92296e8..c311f67b7f0 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1206,7 +1206,10 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) return -EINVAL; } - ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + if (dev->quirks & USB_QUIRK_NO_SET_INTF) + ret = -EPIPE; + else + ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), USB_REQ_SET_INTERFACE, USB_RECIP_INTERFACE, alternate, interface, NULL, 0, 5000); diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index f90ab5e94c5..dfc5418ea10 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -28,35 +28,41 @@ * devices is broken... */ static const struct usb_device_id usb_quirk_list[] = { - /* Action Semiconductor flash disk */ - { USB_DEVICE(0x10d6, 0x2200), .driver_info = USB_QUIRK_STRING_FETCH_255}, - /* CBM - Flash disk */ { USB_DEVICE(0x0204, 0x6025), .driver_info = USB_QUIRK_RESET_RESUME }, + /* HP 5300/5370C scanner */ - { USB_DEVICE(0x03f0, 0x0701), .driver_info = USB_QUIRK_STRING_FETCH_255 }, + { USB_DEVICE(0x03f0, 0x0701), .driver_info = + USB_QUIRK_STRING_FETCH_255 }, /* Creative SB Audigy 2 NX */ { USB_DEVICE(0x041e, 0x3020), .driver_info = USB_QUIRK_RESET_RESUME }, + /* Philips PSC805 audio device */ + { USB_DEVICE(0x0471, 0x0155), .driver_info = USB_QUIRK_RESET_RESUME }, + /* Roland SC-8820 */ { USB_DEVICE(0x0582, 0x0007), .driver_info = USB_QUIRK_RESET_RESUME }, /* Edirol SD-20 */ { USB_DEVICE(0x0582, 0x0027), .driver_info = USB_QUIRK_RESET_RESUME }, - /* INTEL VALUE SSD */ - { USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME }, - /* M-Systems Flash Disk Pioneers */ { USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME }, - /* Philips PSC805 audio device */ - { USB_DEVICE(0x0471, 0x0155), .driver_info = USB_QUIRK_RESET_RESUME }, + /* X-Rite/Gretag-Macbeth Eye-One Pro display colorimeter */ + { USB_DEVICE(0x0971, 0x2000), .driver_info = USB_QUIRK_NO_SET_INTF }, + + /* Action Semiconductor flash disk */ + { USB_DEVICE(0x10d6, 0x2200), .driver_info = + USB_QUIRK_STRING_FETCH_255 }, /* SKYMEDI USB_DRIVE */ { USB_DEVICE(0x1516, 0x8628), .driver_info = USB_QUIRK_RESET_RESUME }, + /* INTEL VALUE SSD */ + { USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME }, + { } /* terminating entry must be last */ }; diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 4e984060c98..1f0db51190c 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -99,8 +99,7 @@ struct usb_interface *usb_ifnum_to_if(const struct usb_device *dev, EXPORT_SYMBOL_GPL(usb_ifnum_to_if); /** - * usb_altnum_to_altsetting - get the altsetting structure with a given - * alternate setting number. + * usb_altnum_to_altsetting - get the altsetting structure with a given alternate setting number. * @intf: the interface containing the altsetting in question * @altnum: the desired alternate setting number * @@ -234,7 +233,7 @@ static int ksuspend_usb_init(void) * singlethreaded. Its job doesn't justify running on more * than one CPU. */ - ksuspend_usb_wq = create_singlethread_workqueue("ksuspend_usbd"); + ksuspend_usb_wq = create_freezeable_workqueue("ksuspend_usbd"); if (!ksuspend_usb_wq) return -ENOMEM; return 0; @@ -442,8 +441,7 @@ EXPORT_SYMBOL_GPL(usb_put_intf); */ /** - * usb_lock_device_for_reset - cautiously acquire the lock for a - * usb device structure + * usb_lock_device_for_reset - cautiously acquire the lock for a usb device structure * @udev: device that's being locked * @iface: interface bound to the driver making the request (optional) * diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index c1395516468..6f45dd669b3 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/gadget/inode.c b/drivers/usb/gadget/inode.c index 805602a687c..0a6feafc8d2 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -1458,7 +1458,7 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) /* currently one config, two speeds */ case USB_REQ_SET_CONFIGURATION: if (ctrl->bRequestType != 0) - break; + goto unrecognized; if (0 == (u8) w_value) { value = 0; dev->current_config = 0; @@ -1505,7 +1505,7 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) /* PXA automagically handles this request too */ case USB_REQ_GET_CONFIGURATION: if (ctrl->bRequestType != 0x80) - break; + goto unrecognized; *(u8 *)req->buf = dev->current_config; value = min (w_length, (u16) 1); break; diff --git a/drivers/usb/gadget/printer.c b/drivers/usb/gadget/printer.c index 4f6bfa100f2..2c32bd08ee7 100644 --- a/drivers/usb/gadget/printer.c +++ b/drivers/usb/gadget/printer.c @@ -92,7 +92,6 @@ struct printer_dev { u8 *current_rx_buf; u8 printer_status; u8 reset_printer; - struct class_device *printer_class_dev; struct cdev printer_cdev; struct device *pdev; u8 printer_cdev_open; diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c index 4402d6f042d..096c41cc40d 100644 --- a/drivers/usb/gadget/pxa2xx_udc.c +++ b/drivers/usb/gadget/pxa2xx_udc.c @@ -103,6 +103,12 @@ static const char ep0name [] = "ep0"; #error "Can't configure both IXP and PXA" #endif +/* IXP doesn't yet support <linux/clk.h> */ +#define clk_get(dev,name) NULL +#define clk_enable(clk) do { } while (0) +#define clk_disable(clk) do { } while (0) +#define clk_put(clk) do { } while (0) + #endif #include "pxa2xx_udc.h" @@ -934,20 +940,31 @@ static void udc_disable(struct pxa2xx_udc *); /* We disable the UDC -- and its 48 MHz clock -- whenever it's not * in active use. */ -static int pullup(struct pxa2xx_udc *udc, int is_active) +static int pullup(struct pxa2xx_udc *udc) { - is_active = is_active && udc->vbus && udc->pullup; + int is_active = udc->vbus && udc->pullup && !udc->suspended; DMSG("%s\n", is_active ? "active" : "inactive"); - if (is_active) - udc_enable(udc); - else { - if (udc->gadget.speed != USB_SPEED_UNKNOWN) { - DMSG("disconnect %s\n", udc->driver - ? udc->driver->driver.name - : "(no driver)"); - stop_activity(udc, udc->driver); + if (is_active) { + if (!udc->active) { + udc->active = 1; + /* Enable clock for USB device */ + clk_enable(udc->clk); + udc_enable(udc); } - udc_disable(udc); + } else { + if (udc->active) { + if (udc->gadget.speed != USB_SPEED_UNKNOWN) { + DMSG("disconnect %s\n", udc->driver + ? udc->driver->driver.name + : "(no driver)"); + stop_activity(udc, udc->driver); + } + udc_disable(udc); + /* Disable clock for USB device */ + clk_disable(udc->clk); + udc->active = 0; + } + } return 0; } @@ -958,9 +975,9 @@ static int pxa2xx_udc_vbus_session(struct usb_gadget *_gadget, int is_active) struct pxa2xx_udc *udc; udc = container_of(_gadget, struct pxa2xx_udc, gadget); - udc->vbus = is_active = (is_active != 0); + udc->vbus = (is_active != 0); DMSG("vbus %s\n", is_active ? "supplied" : "inactive"); - pullup(udc, is_active); + pullup(udc); return 0; } @@ -975,9 +992,8 @@ static int pxa2xx_udc_pullup(struct usb_gadget *_gadget, int is_active) if (!udc->mach->gpio_pullup && !udc->mach->udc_command) return -EOPNOTSUPP; - is_active = (is_active != 0); - udc->pullup = is_active; - pullup(udc, is_active); + udc->pullup = (is_active != 0); + pullup(udc); return 0; } @@ -997,7 +1013,7 @@ static const struct usb_gadget_ops pxa2xx_udc_ops = { #ifdef CONFIG_USB_GADGET_DEBUG_FS static int -udc_seq_show(struct seq_file *m, void *d) +udc_seq_show(struct seq_file *m, void *_d) { struct pxa2xx_udc *dev = m->private; unsigned long flags; @@ -1146,11 +1162,6 @@ static void udc_disable(struct pxa2xx_udc *dev) udc_clear_mask_UDCCR(UDCCR_UDE); -#ifdef CONFIG_ARCH_PXA - /* Disable clock for USB device */ - clk_disable(dev->clk); -#endif - ep0_idle (dev); dev->gadget.speed = USB_SPEED_UNKNOWN; } @@ -1191,11 +1202,6 @@ static void udc_enable (struct pxa2xx_udc *dev) { udc_clear_mask_UDCCR(UDCCR_UDE); -#ifdef CONFIG_ARCH_PXA - /* Enable clock for USB device */ - clk_enable(dev->clk); -#endif - /* try to clear these bits before we enable the udc */ udc_ack_int_UDCCR(UDCCR_SUSIR|/*UDCCR_RSTIR|*/UDCCR_RESIR); @@ -1286,7 +1292,7 @@ fail: * for set_configuration as well as eventual disconnect. */ DMSG("registered gadget driver '%s'\n", driver->driver.name); - pullup(dev, 1); + pullup(dev); dump_state(dev); return 0; } @@ -1329,7 +1335,8 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) return -EINVAL; local_irq_disable(); - pullup(dev, 0); + dev->pullup = 0; + pullup(dev); stop_activity(dev, driver); local_irq_enable(); @@ -2131,13 +2138,11 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev) if (irq < 0) return -ENODEV; -#ifdef CONFIG_ARCH_PXA dev->clk = clk_get(&pdev->dev, "UDCCLK"); if (IS_ERR(dev->clk)) { retval = PTR_ERR(dev->clk); goto err_clk; } -#endif pr_debug("%s: IRQ %d%s%s\n", driver_name, irq, dev->has_cfr ? "" : " (!cfr)", @@ -2250,10 +2255,8 @@ lubbock_fail0: if (dev->mach->gpio_vbus) gpio_free(dev->mach->gpio_vbus); err_gpio_vbus: -#ifdef CONFIG_ARCH_PXA clk_put(dev->clk); err_clk: -#endif return retval; } @@ -2269,7 +2272,9 @@ static int __exit pxa2xx_udc_remove(struct platform_device *pdev) if (dev->driver) return -EBUSY; - udc_disable(dev); + dev->pullup = 0; + pullup(dev); + remove_debug_files(dev); if (dev->got_irq) { @@ -2289,9 +2294,7 @@ static int __exit pxa2xx_udc_remove(struct platform_device *pdev) if (dev->mach->gpio_pullup) gpio_free(dev->mach->gpio_pullup); -#ifdef CONFIG_ARCH_PXA clk_put(dev->clk); -#endif platform_set_drvdata(pdev, NULL); the_controller = NULL; @@ -2317,10 +2320,15 @@ static int __exit pxa2xx_udc_remove(struct platform_device *pdev) static int pxa2xx_udc_suspend(struct platform_device *dev, pm_message_t state) { struct pxa2xx_udc *udc = platform_get_drvdata(dev); + unsigned long flags; if (!udc->mach->gpio_pullup && !udc->mach->udc_command) WARN("USB host won't detect disconnect!\n"); - pullup(udc, 0); + udc->suspended = 1; + + local_irq_save(flags); + pullup(udc); + local_irq_restore(flags); return 0; } @@ -2328,8 +2336,12 @@ static int pxa2xx_udc_suspend(struct platform_device *dev, pm_message_t state) static int pxa2xx_udc_resume(struct platform_device *dev) { struct pxa2xx_udc *udc = platform_get_drvdata(dev); + unsigned long flags; - pullup(udc, 1); + udc->suspended = 0; + local_irq_save(flags); + pullup(udc); + local_irq_restore(flags); return 0; } diff --git a/drivers/usb/gadget/pxa2xx_udc.h b/drivers/usb/gadget/pxa2xx_udc.h index b67e3ff5e4e..e2c19e88c87 100644 --- a/drivers/usb/gadget/pxa2xx_udc.h +++ b/drivers/usb/gadget/pxa2xx_udc.h @@ -119,7 +119,9 @@ struct pxa2xx_udc { has_cfr : 1, req_pending : 1, req_std : 1, - req_config : 1; + req_config : 1, + suspended : 1, + active : 1; #define start_watchdog(dev) mod_timer(&dev->timer, jiffies + (HZ/200)) struct timer_list timer; diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index b8ad55aff84..46ee7f4c091 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/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index 3ba01664f82..72ccd56e36d 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -152,6 +152,20 @@ static int ehci_pci_setup(struct usb_hcd *hcd) break; } break; + case PCI_VENDOR_ID_VIA: + if (pdev->device == 0x3104 && (pdev->revision & 0xf0) == 0x60) { + u8 tmp; + + /* The VT6212 defaults to a 1 usec EHCI sleep time which + * hogs the PCI bus *badly*. Setting bit 5 of 0x4B makes + * that sleep time use the conventional 10 usec. + */ + pci_read_config_byte(pdev, 0x4b, &tmp); + if (tmp & 0x20) + break; + pci_write_config_byte(pdev, 0x4b, tmp | 0x20); + } + break; } ehci_reset(ehci); diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 776a97f3391..2e49de820b1 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -319,10 +319,10 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) if (likely (last->urb != urb)) { ehci_urb_done(ehci, last->urb, last_status); count++; + last_status = -EINPROGRESS; } ehci_qtd_free (ehci, last); last = NULL; - last_status = -EINPROGRESS; } /* ignore urbs submitted during completions we reported */ diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index 0130fd8571e..d7071c85575 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -911,8 +911,7 @@ static int isp116x_hub_status_data(struct usb_hcd *hcd, char *buf) buf[0] = 0; for (i = 0; i < ports; i++) { - u32 status = isp116x->rhport[i] = - isp116x_read_reg32(isp116x, i ? HCRHPORT2 : HCRHPORT1); + u32 status = isp116x_read_reg32(isp116x, i ? HCRHPORT2 : HCRHPORT1); if (status & (RH_PS_CSC | RH_PS_PESC | RH_PS_PSSC | RH_PS_OCIC | RH_PS_PRSC)) { @@ -1031,7 +1030,9 @@ static int isp116x_hub_control(struct usb_hcd *hcd, DBG("GetPortStatus\n"); if (!wIndex || wIndex > ports) goto error; - tmp = isp116x->rhport[--wIndex]; + spin_lock_irqsave(&isp116x->lock, flags); + tmp = isp116x_read_reg32(isp116x, (--wIndex) ? HCRHPORT2 : HCRHPORT1); + spin_unlock_irqrestore(&isp116x->lock, flags); *(__le32 *) buf = cpu_to_le32(tmp); DBG("GetPortStatus: port[%d] %08x\n", wIndex + 1, tmp); break; @@ -1080,8 +1081,6 @@ static int isp116x_hub_control(struct usb_hcd *hcd, spin_lock_irqsave(&isp116x->lock, flags); isp116x_write_reg32(isp116x, wIndex ? HCRHPORT2 : HCRHPORT1, tmp); - isp116x->rhport[wIndex] = - isp116x_read_reg32(isp116x, wIndex ? HCRHPORT2 : HCRHPORT1); spin_unlock_irqrestore(&isp116x->lock, flags); break; case SetPortFeature: @@ -1095,24 +1094,22 @@ static int isp116x_hub_control(struct usb_hcd *hcd, spin_lock_irqsave(&isp116x->lock, flags); isp116x_write_reg32(isp116x, wIndex ? HCRHPORT2 : HCRHPORT1, RH_PS_PSS); + spin_unlock_irqrestore(&isp116x->lock, flags); break; case USB_PORT_FEAT_POWER: DBG("USB_PORT_FEAT_POWER\n"); spin_lock_irqsave(&isp116x->lock, flags); isp116x_write_reg32(isp116x, wIndex ? HCRHPORT2 : HCRHPORT1, RH_PS_PPS); + spin_unlock_irqrestore(&isp116x->lock, flags); break; case USB_PORT_FEAT_RESET: DBG("USB_PORT_FEAT_RESET\n"); root_port_reset(isp116x, wIndex); - spin_lock_irqsave(&isp116x->lock, flags); break; default: goto error; } - isp116x->rhport[wIndex] = - isp116x_read_reg32(isp116x, wIndex ? HCRHPORT2 : HCRHPORT1); - spin_unlock_irqrestore(&isp116x->lock, flags); break; default: diff --git a/drivers/usb/host/isp116x.h b/drivers/usb/host/isp116x.h index b91e2edd9c5..595b90a9984 100644 --- a/drivers/usb/host/isp116x.h +++ b/drivers/usb/host/isp116x.h @@ -270,7 +270,6 @@ struct isp116x { u32 rhdesca; u32 rhdescb; u32 rhstatus; - u32 rhport[2]; /* async schedule: control, bulk */ struct list_head async; diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index 08c65c1a377..779d07851a4 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 e1c7c27e18b..0388065bb79 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 76db2fef465..3abb3c86364 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -92,6 +92,7 @@ struct ftdi_sio_quirk { }; static int ftdi_jtag_probe (struct usb_serial *serial); +static int ftdi_mtxorb_hack_setup (struct usb_serial *serial); static void ftdi_USB_UIRT_setup (struct ftdi_private *priv); static void ftdi_HE_TIRA1_setup (struct ftdi_private *priv); @@ -99,6 +100,10 @@ static struct ftdi_sio_quirk ftdi_jtag_quirk = { .probe = ftdi_jtag_probe, }; +static struct ftdi_sio_quirk ftdi_mtxorb_hack_quirk = { + .probe = ftdi_mtxorb_hack_setup, +}; + static struct ftdi_sio_quirk ftdi_USB_UIRT_quirk = { .port_probe = ftdi_USB_UIRT_setup, }; @@ -161,6 +166,8 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_MTXORB_4_PID) }, { USB_DEVICE(FTDI_VID, FTDI_MTXORB_5_PID) }, { USB_DEVICE(FTDI_VID, FTDI_MTXORB_6_PID) }, + { USB_DEVICE(MTXORB_VK_VID, MTXORB_VK_PID), + .driver_info = (kernel_ulong_t)&ftdi_mtxorb_hack_quirk }, { USB_DEVICE(FTDI_VID, FTDI_PERLE_ULTRAPORT_PID) }, { USB_DEVICE(FTDI_VID, FTDI_PIEGROUP_PID) }, { USB_DEVICE(FTDI_VID, FTDI_TNC_X_PID) }, @@ -274,6 +281,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_ELV_FS20SIG_PID) }, { USB_DEVICE(FTDI_VID, FTDI_ELV_WS300PC_PID) }, { USB_DEVICE(FTDI_VID, FTDI_ELV_FHZ1300PC_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_EM1010PC_PID) }, { USB_DEVICE(FTDI_VID, FTDI_ELV_WS500_PID) }, { USB_DEVICE(FTDI_VID, LINX_SDMUSBQSS_PID) }, { USB_DEVICE(FTDI_VID, LINX_MASTERDEVEL2_PID) }, @@ -351,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), @@ -1088,6 +1097,23 @@ static int ftdi_jtag_probe(struct usb_serial *serial) return 0; } +/* + * The Matrix Orbital VK204-25-USB has an invalid IN endpoint. + * We have to correct it if we want to read from it. + */ +static int ftdi_mtxorb_hack_setup(struct usb_serial *serial) +{ + struct usb_host_endpoint *ep = serial->dev->ep_in[1]; + struct usb_endpoint_descriptor *ep_desc = &ep->desc; + + if (ep->enabled && ep_desc->wMaxPacketSize == 0) { + ep_desc->wMaxPacketSize = 0x40; + info("Fixing invalid wMaxPacketSize on read pipe"); + } + + return 0; +} + /* ftdi_shutdown is called from usbserial:usb_serial_disconnect * it is called when the usb device is disconnected * diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index 6eee2ab914e..6da539ede0e 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h @@ -102,6 +102,13 @@ * (http://www.joernonline.de/dw/doku.php?id=start&idx=projects:oocdlink) */ #define FTDI_OOCDLINK_PID 0xbaf8 /* Amontec JTAGkey */ +/* + * The following are the values for the Matrix Orbital VK204-25-USB + * display, which use the FT232RL. + */ +#define MTXORB_VK_VID 0x1b3d +#define MTXORB_VK_PID 0x0158 + /* Interbiometrics USB I/O Board */ /* Developed for Interbiometrics by Rudolf Gugler */ #define INTERBIOMETRICS_VID 0x1209 @@ -550,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 97fa3c42843..7cfce9dabb9 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/mos7840.c b/drivers/usb/serial/mos7840.c index 869ecd374cb..aeeb9cb2099 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -110,11 +110,20 @@ /* vendor id and device id defines */ +/* The native mos7840/7820 component */ #define USB_VENDOR_ID_MOSCHIP 0x9710 #define MOSCHIP_DEVICE_ID_7840 0x7840 #define MOSCHIP_DEVICE_ID_7820 0x7820 +/* The native component can have its vendor/device id's overridden + * in vendor-specific implementations. Such devices can be handled + * by making a change here, in moschip_port_id_table, and in + * moschip_id_table_combined + */ +#define USB_VENDOR_ID_BANDB 0x0856 +#define BANDB_DEVICE_ID_USOPTL4_4 0xAC44 +#define BANDB_DEVICE_ID_USOPTL4_2 0xAC42 -/* Interrupt Rotinue Defines */ +/* Interrupt Routine Defines */ #define SERIAL_IIR_RLS 0x06 #define SERIAL_IIR_MS 0x00 @@ -159,12 +168,16 @@ static struct usb_device_id moschip_port_id_table[] = { {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7840)}, {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7820)}, + {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_4)}, + {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_2)}, {} /* terminating entry */ }; static __devinitdata struct usb_device_id moschip_id_table_combined[] = { {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7840)}, {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7820)}, + {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_4)}, + {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_2)}, {} /* terminating entry */ }; diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index af2674c5741..a396fbbdc9c 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 @@ -120,6 +156,9 @@ static int option_send_setup(struct usb_serial_port *port); #define ANYDATA_PRODUCT_ADU_E100A 0x6501 #define ANYDATA_PRODUCT_ADU_500A 0x6502 +#define AXESSTEL_VENDOR_ID 0x1726 +#define AXESSTEL_PRODUCT_MV110H 0x1000 + #define BANDRICH_VENDOR_ID 0x1A8D #define BANDRICH_PRODUCT_C100_1 0x1002 #define BANDRICH_PRODUCT_C100_2 0x1003 @@ -165,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 */ @@ -192,6 +244,7 @@ static struct usb_device_id option_ids[] = { { USB_DEVICE(DELL_VENDOR_ID, 0x8137) }, /* Dell Wireless HSDPA 5520 */ { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_E100A) }, { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_500A) }, + { USB_DEVICE(AXESSTEL_VENDOR_ID, AXESSTEL_PRODUCT_MV110H) }, { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_C100_1) }, { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_C100_2) }, { USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_PRODUCT_KPC680) }, diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index ae3ec1a6400..2af778555bd 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -55,6 +55,7 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_DCU11) }, { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ3) }, { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_PHAROS) }, + { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_ALDIGA) }, { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) }, { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) }, { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) }, diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h index 237a41f6638..10cf872e5ec 100644 --- a/drivers/usb/serial/pl2303.h +++ b/drivers/usb/serial/pl2303.h @@ -13,6 +13,7 @@ #define PL2303_PRODUCT_ID_DCU11 0x1234 #define PL2303_PRODUCT_ID_PHAROS 0xaaa0 #define PL2303_PRODUCT_ID_RSAQ3 0xaaa2 +#define PL2303_PRODUCT_ID_ALDIGA 0x0611 #define ATEN_VENDOR_ID 0x0557 #define ATEN_VENDOR_ID2 0x0547 diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index e3d44ae8d44..ed678811e6a 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -14,7 +14,7 @@ Whom based his on the Keyspan driver by Hugh Blemings <hugh@blemings.org> */ -#define DRIVER_VERSION "v.1.2.7" +#define DRIVER_VERSION "v.1.2.8" #define DRIVER_AUTHOR "Kevin Lloyd <linux@sierrawireless.com>" #define DRIVER_DESC "USB Driver for Sierra Wireless USB modems" @@ -163,6 +163,7 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */ { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 & AC 875U */ { USB_DEVICE(0x1199, 0x6813) }, /* Sierra Wireless MC8775 (Thinkpad internal) */ + { USB_DEVICE(0x1199, 0x6815) }, /* Sierra Wireless MC8775 */ { USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */ { USB_DEVICE(0x1199, 0x6832) }, /* Sierra Wireless MC8780*/ { USB_DEVICE(0x1199, 0x6833) }, /* Sierra Wireless MC8781*/ @@ -196,9 +197,9 @@ struct sierra_port_private { spinlock_t lock; /* lock the structure */ int outstanding_urbs; /* number of out urbs in flight */ - /* Input endpoints and buffer for this port */ + /* Input endpoints and buffers for this port */ struct urb *in_urbs[N_IN_URB]; - char in_buffer[N_IN_URB][IN_BUFLEN]; + char *in_buffer[N_IN_URB]; /* Settings for the port */ int rts_state; /* Handshaking pins (outputs) */ @@ -638,6 +639,15 @@ static int sierra_startup(struct usb_serial *serial) return -ENOMEM; } spin_lock_init(&portdata->lock); + for (j = 0; j < N_IN_URB; j++) { + portdata->in_buffer[j] = kmalloc(IN_BUFLEN, GFP_KERNEL); + if (!portdata->in_buffer[j]) { + for (--j; j >= 0; j--) + kfree(portdata->in_buffer[j]); + kfree(portdata); + return -ENOMEM; + } + } usb_set_serial_port_data(port, portdata); @@ -681,7 +691,7 @@ static void sierra_shutdown(struct usb_serial *serial) for (j = 0; j < N_IN_URB; j++) { usb_kill_urb(portdata->in_urbs[j]); usb_free_urb(portdata->in_urbs[j]); - portdata->in_urbs[j] = NULL; + kfree(portdata->in_buffer[j]); } kfree(portdata); usb_set_serial_port_data(port, NULL); diff --git a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c index 2ae1e8673b1..971d13dd5e6 100644 --- a/drivers/usb/storage/isd200.c +++ b/drivers/usb/storage/isd200.c @@ -1230,6 +1230,7 @@ static int isd200_get_inquiry_data( struct us_data *us ) /* Free driver structure */ us->extra_destructor(info); + kfree(info); us->extra = NULL; us->extra_destructor = NULL; } @@ -1469,6 +1470,7 @@ static void isd200_free_info_ptrs(void *info_) if (info) { kfree(info->id); kfree(info->RegsBuf); + kfree(info->srb.sense_buffer); } } @@ -1494,7 +1496,9 @@ static int isd200_init_info(struct us_data *us) kzalloc(sizeof(struct hd_driveid), GFP_KERNEL); info->RegsBuf = (unsigned char *) kmalloc(sizeof(info->ATARegs), GFP_KERNEL); - if (!info->id || !info->RegsBuf) { + info->srb.sense_buffer = + kmalloc(SCSI_SENSE_BUFFERSIZE, GFP_KERNEL); + if (!info->id || !info->RegsBuf || !info->srb.sense_buffer) { isd200_free_info_ptrs(info); kfree(info); retStatus = ISD200_ERROR; diff --git a/drivers/usb/storage/protocol.c b/drivers/usb/storage/protocol.c index 958f5b17847..b9b8ede61fb 100644 --- a/drivers/usb/storage/protocol.c +++ b/drivers/usb/storage/protocol.c @@ -170,7 +170,6 @@ unsigned int usb_stor_access_xfer_buf(unsigned char *buffer, if (!sg) sg = scsi_sglist(srb); - buflen = min(buflen, scsi_bufflen(srb)); /* This loop handles a single s-g list entry, which may * include multiple pages. Find the initial page structure @@ -232,6 +231,7 @@ void usb_stor_set_xfer_buf(unsigned char *buffer, unsigned int offset = 0; struct scatterlist *sg = NULL; + buflen = min(buflen, scsi_bufflen(srb)); buflen = usb_stor_access_xfer_buf(buffer, buflen, srb, &sg, &offset, TO_XFER_BUF); if (buflen < scsi_bufflen(srb)) diff --git a/drivers/usb/storage/sddr55.c b/drivers/usb/storage/sddr55.c index d43a3415e12..6d14327c921 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/usb/storage/transport.c b/drivers/usb/storage/transport.c index 5780ed15f1a..bdd4334bed5 100644 --- a/drivers/usb/storage/transport.c +++ b/drivers/usb/storage/transport.c @@ -1009,7 +1009,8 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us) US_DEBUGP("Bulk Status S 0x%x T 0x%x R %u Stat 0x%x\n", le32_to_cpu(bcs->Signature), bcs->Tag, residue, bcs->Status); - if (bcs->Tag != us->tag || bcs->Status > US_BULK_STAT_PHASE) { + if (!(bcs->Tag == us->tag || (us->flags & US_FL_BULK_IGNORE_TAG)) || + bcs->Status > US_BULK_STAT_PHASE) { US_DEBUGP("Bulk logical error\n"); return USB_STOR_TRANSPORT_ERROR; } diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 99679a8cfa0..e5219a56947 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -1589,6 +1589,17 @@ UNUSUAL_DEV( 0x22b8, 0x4810, 0x0001, 0x0001, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_CAPACITY), +/* + * Patch by Constantin Baranov <const@tltsu.ru> + * Report by Andreas Koenecke. + * Motorola ROKR Z6. + */ +UNUSUAL_DEV( 0x22b8, 0x6426, 0x0101, 0x0101, + "Motorola", + "MSnc.", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_FIX_INQUIRY | US_FL_FIX_CAPACITY | US_FL_BULK_IGNORE_TAG), + /* Reported by Radovan Garabik <garabik@kassiopeia.juls.savba.sk> */ UNUSUAL_DEV( 0x2735, 0x100b, 0x0000, 0x9999, "MPIO", diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 758435f8a6f..1bd5fb30237 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 @@ -1880,6 +1893,20 @@ config FB_XILINX framebuffer. ML300 carries a 640*480 LCD display on the board, ML403 uses a standard DB15 VGA connector. +config FB_METRONOME + tristate "Metronome display controller support" + depends on FB && ARCH_PXA && MMU + select FB_SYS_FILLRECT + select FB_SYS_COPYAREA + select FB_SYS_IMAGEBLIT + select FB_SYS_FOPS + select FB_DEFERRED_IO + help + This enables support for the Metronome display controller. Tested + with an E-Ink 800x600 display and Gumstix Connex through an AMLCD + interface. Please read <file:Documentation/fb/metronomefb.txt> + for more information. + config FB_VIRTUAL tristate "Virtual Frame Buffer support (ONLY FOR TESTING!)" depends on FB diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 83e02b3429b..11c0e5e05f2 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -103,6 +103,7 @@ obj-$(CONFIG_FB_PMAG_AA) += pmag-aa-fb.o obj-$(CONFIG_FB_PMAG_BA) += pmag-ba-fb.o obj-$(CONFIG_FB_PMAGB_B) += pmagb-b-fb.o obj-$(CONFIG_FB_MAXINE) += maxinefb.o +obj-$(CONFIG_FB_METRONOME) += metronomefb.o obj-$(CONFIG_FB_S1D13XXX) += s1d13xxxfb.o obj-$(CONFIG_FB_IMX) += imxfb.o obj-$(CONFIG_FB_S3C2410) += s3c2410fb.o @@ -122,6 +123,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 0ce791e6f79..986a550c043 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 00000000000..a2bb2de9e02 --- /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/fb_defio.c b/drivers/video/fb_defio.c index 0f8cfb988c9..24843fdd539 100644 --- a/drivers/video/fb_defio.c +++ b/drivers/video/fb_defio.c @@ -4,7 +4,7 @@ * Copyright (C) 2006 Jaya Kumar * * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive + * License. See the file COPYING in the main directory of this archive * for more details. */ @@ -31,7 +31,7 @@ static int fb_deferred_io_fault(struct vm_area_struct *vma, unsigned long offset; struct page *page; struct fb_info *info = vma->vm_private_data; - /* info->screen_base is in System RAM */ + /* info->screen_base is virtual memory */ void *screen_base = (void __force *) info->screen_base; offset = vmf->pgoff << PAGE_SHIFT; @@ -43,6 +43,15 @@ static int fb_deferred_io_fault(struct vm_area_struct *vma, return VM_FAULT_SIGBUS; get_page(page); + + if (vma->vm_file) + page->mapping = vma->vm_file->f_mapping; + else + printk(KERN_ERR "no mapping available\n"); + + BUG_ON(!page->mapping); + page->index = vmf->pgoff; + vmf->page = page; return 0; } @@ -138,11 +147,20 @@ EXPORT_SYMBOL_GPL(fb_deferred_io_init); void fb_deferred_io_cleanup(struct fb_info *info) { + void *screen_base = (void __force *) info->screen_base; struct fb_deferred_io *fbdefio = info->fbdefio; + struct page *page; + int i; BUG_ON(!fbdefio); cancel_delayed_work(&info->deferred_work); flush_scheduled_work(); + + /* clear out the mapping that we setup */ + for (i = 0 ; i < info->fix.smem_len; i += PAGE_SIZE) { + page = vmalloc_to_page(screen_base + i); + page->mapping = NULL; + } } EXPORT_SYMBOL_GPL(fb_deferred_io_cleanup); diff --git a/drivers/video/hitfb.c b/drivers/video/hitfb.c index 756c0ce8591..392a8be6aa7 100644 --- a/drivers/video/hitfb.c +++ b/drivers/video/hitfb.c @@ -403,7 +403,7 @@ static int __init hitfb_probe(struct platform_device *dev) return 0; } -static int __devexit hitfb_remove(struct platform_device *dev) +static int __exit hitfb_remove(struct platform_device *dev) { return unregister_framebuffer(&fb_info); } @@ -439,7 +439,7 @@ static int hitfb_resume(struct platform_device *dev) static struct platform_driver hitfb_driver = { .probe = hitfb_probe, - .remove = __devexit_p(hitfb_remove), + .remove = __exit_p(hitfb_remove), #ifdef CONFIG_PM .suspend = hitfb_suspend, .resume = hitfb_resume, diff --git a/drivers/video/i810/i810_main.c b/drivers/video/i810/i810_main.c index 1d13dd099af..a24e680d2b9 100644 --- a/drivers/video/i810/i810_main.c +++ b/drivers/video/i810/i810_main.c @@ -1476,7 +1476,7 @@ static int i810fb_cursor(struct fb_info *info, struct fb_cursor *cursor) struct i810fb_par *par = info->par; u8 __iomem *mmio = par->mmio_start_virtual; - if (!(par->dev_flags & LOCKUP)) + if (par->dev_flags & LOCKUP) return -ENXIO; if (cursor->image.width > 64 || cursor->image.height > 64) diff --git a/drivers/video/mbx/mbxfb.c b/drivers/video/mbx/mbxfb.c index 80cd117ca65..01f77bcc68f 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/metronomefb.c b/drivers/video/metronomefb.c new file mode 100644 index 00000000000..e9a89fd8275 --- /dev/null +++ b/drivers/video/metronomefb.c @@ -0,0 +1,999 @@ +/* + * linux/drivers/video/metronomefb.c -- FB driver for Metronome controller + * + * Copyright (C) 2008, Jaya Kumar + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + * + * Layout is based on skeletonfb.c by James Simmons and Geert Uytterhoeven. + * + * This work was made possible by help and equipment support from E-Ink + * Corporation. http://support.eink.com/community + * + * This driver is written to be used with the Metronome display controller. + * It was tested with an E-Ink 800x600 Vizplex EPD on a Gumstix Connex board + * using the Lyre interface board. + * + * General notes: + * - User must set metronomefb_enable=1 to enable it. + * - See Documentation/fb/metronomefb.txt for how metronome works. + */ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/slab.h> +#include <linux/vmalloc.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/list.h> +#include <linux/firmware.h> +#include <linux/dma-mapping.h> +#include <linux/uaccess.h> +#include <linux/irq.h> + +#include <asm/arch/pxa-regs.h> +#include <asm/unaligned.h> + +#define DEBUG 1 +#ifdef DEBUG +#define DPRINTK(f, a...) printk(KERN_DEBUG "%s: " f, __func__ , ## a) +#else +#define DPRINTK(f, a...) +#endif + + +/* Display specific information */ +#define DPY_W 832 +#define DPY_H 622 + +struct metromem_desc { + u32 mFDADR0; + u32 mFSADR0; + u32 mFIDR0; + u32 mLDCMD0; +}; + +struct metromem_cmd { + u16 opcode; + u16 args[((64-2)/2)]; + u16 csum; +}; + +struct metronomefb_par { + unsigned char *metromem; + struct metromem_desc *metromem_desc; + struct metromem_cmd *metromem_cmd; + unsigned char *metromem_wfm; + unsigned char *metromem_img; + u16 *metromem_img_csum; + u16 *csum_table; + int metromemsize; + dma_addr_t metromem_dma; + dma_addr_t metromem_desc_dma; + struct fb_info *info; + wait_queue_head_t waitq; + u8 frame_count; +}; + +/* frame differs from image. frame includes non-visible pixels */ +struct epd_frame { + int fw; /* frame width */ + int fh; /* frame height */ +}; + +static struct epd_frame epd_frame_table[] = { + { + .fw = 832, + .fh = 622 + }, +}; + +static struct fb_fix_screeninfo metronomefb_fix __devinitdata = { + .id = "metronomefb", + .type = FB_TYPE_PACKED_PIXELS, + .visual = FB_VISUAL_STATIC_PSEUDOCOLOR, + .xpanstep = 0, + .ypanstep = 0, + .ywrapstep = 0, + .line_length = DPY_W, + .accel = FB_ACCEL_NONE, +}; + +static struct fb_var_screeninfo metronomefb_var __devinitdata = { + .xres = DPY_W, + .yres = DPY_H, + .xres_virtual = DPY_W, + .yres_virtual = DPY_H, + .bits_per_pixel = 8, + .grayscale = 1, + .nonstd = 1, + .red = { 4, 3, 0 }, + .green = { 0, 0, 0 }, + .blue = { 0, 0, 0 }, + .transp = { 0, 0, 0 }, +}; + +static unsigned int metronomefb_enable; + +struct waveform_hdr { + u8 stuff[32]; + + u8 wmta[3]; + u8 fvsn; + + u8 luts; + u8 mc; + u8 trc; + u8 stuff3; + + u8 endb; + u8 swtb; + u8 stuff2a[2]; + + u8 stuff2b[3]; + u8 wfm_cs; +} __attribute__ ((packed)); + +/* main metronomefb functions */ +static u8 calc_cksum(int start, int end, u8 *mem) +{ + u8 tmp = 0; + int i; + + for (i = start; i < end; i++) + tmp += mem[i]; + + return tmp; +} + +static u16 calc_img_cksum(u16 *start, int length) +{ + u16 tmp = 0; + + while (length--) + tmp += *start++; + + return tmp; +} + +/* here we decode the incoming waveform file and populate metromem */ +#define EXP_WFORM_SIZE 47001 +static int load_waveform(u8 *mem, size_t size, u8 *metromem, int m, int t, + u8 *frame_count) +{ + int tta; + int wmta; + int trn = 0; + int i; + unsigned char v; + u8 cksum; + int cksum_idx; + int wfm_idx, owfm_idx; + int mem_idx = 0; + struct waveform_hdr *wfm_hdr; + + if (size != EXP_WFORM_SIZE) { + printk(KERN_ERR "Error: unexpected size %d != %d\n", size, + EXP_WFORM_SIZE); + return -EINVAL; + } + + wfm_hdr = (struct waveform_hdr *) mem; + + if (wfm_hdr->fvsn != 1) { + printk(KERN_ERR "Error: bad fvsn %x\n", wfm_hdr->fvsn); + return -EINVAL; + } + if (wfm_hdr->luts != 0) { + printk(KERN_ERR "Error: bad luts %x\n", wfm_hdr->luts); + return -EINVAL; + } + cksum = calc_cksum(32, 47, mem); + if (cksum != wfm_hdr->wfm_cs) { + printk(KERN_ERR "Error: bad cksum %x != %x\n", cksum, + wfm_hdr->wfm_cs); + return -EINVAL; + } + wfm_hdr->mc += 1; + wfm_hdr->trc += 1; + for (i = 0; i < 5; i++) { + if (*(wfm_hdr->stuff2a + i) != 0) { + printk(KERN_ERR "Error: unexpected value in padding\n"); + return -EINVAL; + } + } + + /* calculating trn. trn is something used to index into + the waveform. presumably selecting the right one for the + desired temperature. it works out the offset of the first + v that exceeds the specified temperature */ + if ((sizeof(*wfm_hdr) + wfm_hdr->trc) > size) + return -EINVAL; + + for (i = sizeof(*wfm_hdr); i <= sizeof(*wfm_hdr) + wfm_hdr->trc; i++) { + if (mem[i] > t) { + trn = i - sizeof(*wfm_hdr) - 1; + break; + } + } + + /* check temperature range table checksum */ + cksum_idx = sizeof(*wfm_hdr) + wfm_hdr->trc + 1; + if (cksum_idx > size) + return -EINVAL; + cksum = calc_cksum(sizeof(*wfm_hdr), cksum_idx, mem); + if (cksum != mem[cksum_idx]) { + printk(KERN_ERR "Error: bad temperature range table cksum" + " %x != %x\n", cksum, mem[cksum_idx]); + return -EINVAL; + } + + /* check waveform mode table address checksum */ + wmta = le32_to_cpu(get_unaligned((__le32 *) wfm_hdr->wmta)); + wmta &= 0x00FFFFFF; + cksum_idx = wmta + m*4 + 3; + if (cksum_idx > size) + return -EINVAL; + cksum = calc_cksum(cksum_idx - 3, cksum_idx, mem); + if (cksum != mem[cksum_idx]) { + printk(KERN_ERR "Error: bad mode table address cksum" + " %x != %x\n", cksum, mem[cksum_idx]); + return -EINVAL; + } + + /* check waveform temperature table address checksum */ + tta = le32_to_cpu(get_unaligned((int *) (mem + wmta + m*4))); + tta &= 0x00FFFFFF; + cksum_idx = tta + trn*4 + 3; + if (cksum_idx > size) + return -EINVAL; + cksum = calc_cksum(cksum_idx - 3, cksum_idx, mem); + if (cksum != mem[cksum_idx]) { + printk(KERN_ERR "Error: bad temperature table address cksum" + " %x != %x\n", cksum, mem[cksum_idx]); + return -EINVAL; + } + + /* here we do the real work of putting the waveform into the + metromem buffer. this does runlength decoding of the waveform */ + wfm_idx = le32_to_cpu(get_unaligned((__le32 *) (mem + tta + trn*4))); + wfm_idx &= 0x00FFFFFF; + owfm_idx = wfm_idx; + if (wfm_idx > size) + return -EINVAL; + while (wfm_idx < size) { + unsigned char rl; + v = mem[wfm_idx++]; + if (v == wfm_hdr->swtb) { + while (((v = mem[wfm_idx++]) != wfm_hdr->swtb) && + wfm_idx < size) + metromem[mem_idx++] = v; + + continue; + } + + if (v == wfm_hdr->endb) + break; + + rl = mem[wfm_idx++]; + for (i = 0; i <= rl; i++) + metromem[mem_idx++] = v; + } + + cksum_idx = wfm_idx; + if (cksum_idx > size) + return -EINVAL; + cksum = calc_cksum(owfm_idx, cksum_idx, mem); + if (cksum != mem[cksum_idx]) { + printk(KERN_ERR "Error: bad waveform data cksum" + " %x != %x\n", cksum, mem[cksum_idx]); + return -EINVAL; + } + *frame_count = (mem_idx/64); + + return 0; +} + +/* register offsets for gpio control */ +#define LED_GPIO_PIN 51 +#define STDBY_GPIO_PIN 48 +#define RST_GPIO_PIN 49 +#define RDY_GPIO_PIN 32 +#define ERR_GPIO_PIN 17 +#define PCBPWR_GPIO_PIN 16 + +#define AF_SEL_GPIO_N 0x3 +#define GAFR0_U_OFFSET(pin) ((pin - 16) * 2) +#define GAFR1_L_OFFSET(pin) ((pin - 32) * 2) +#define GAFR1_U_OFFSET(pin) ((pin - 48) * 2) +#define GPDR1_OFFSET(pin) (pin - 32) +#define GPCR1_OFFSET(pin) (pin - 32) +#define GPSR1_OFFSET(pin) (pin - 32) +#define GPCR0_OFFSET(pin) (pin) +#define GPSR0_OFFSET(pin) (pin) + +static void metronome_set_gpio_output(int pin, int val) +{ + u8 index; + + index = pin >> 4; + + switch (index) { + case 1: + if (val) + GPSR0 |= (1 << GPSR0_OFFSET(pin)); + else + GPCR0 |= (1 << GPCR0_OFFSET(pin)); + break; + case 2: + break; + case 3: + if (val) + GPSR1 |= (1 << GPSR1_OFFSET(pin)); + else + GPCR1 |= (1 << GPCR1_OFFSET(pin)); + break; + default: + printk(KERN_ERR "unimplemented\n"); + } +} + +static void __devinit metronome_init_gpio_pin(int pin, int dir) +{ + u8 index; + /* dir 0 is output, 1 is input + - do 2 things here: + - set gpio alternate function to standard gpio + - set gpio direction to input or output */ + + index = pin >> 4; + switch (index) { + case 1: + GAFR0_U &= ~(AF_SEL_GPIO_N << GAFR0_U_OFFSET(pin)); + + if (dir) + GPDR0 &= ~(1 << pin); + else + GPDR0 |= (1 << pin); + break; + case 2: + GAFR1_L &= ~(AF_SEL_GPIO_N << GAFR1_L_OFFSET(pin)); + + if (dir) + GPDR1 &= ~(1 << GPDR1_OFFSET(pin)); + else + GPDR1 |= (1 << GPDR1_OFFSET(pin)); + break; + case 3: + GAFR1_U &= ~(AF_SEL_GPIO_N << GAFR1_U_OFFSET(pin)); + + if (dir) + GPDR1 &= ~(1 << GPDR1_OFFSET(pin)); + else + GPDR1 |= (1 << GPDR1_OFFSET(pin)); + break; + default: + printk(KERN_ERR "unimplemented\n"); + } +} + +static void __devinit metronome_init_gpio_regs(void) +{ + metronome_init_gpio_pin(LED_GPIO_PIN, 0); + metronome_set_gpio_output(LED_GPIO_PIN, 0); + + metronome_init_gpio_pin(STDBY_GPIO_PIN, 0); + metronome_set_gpio_output(STDBY_GPIO_PIN, 0); + + metronome_init_gpio_pin(RST_GPIO_PIN, 0); + metronome_set_gpio_output(RST_GPIO_PIN, 0); + + metronome_init_gpio_pin(RDY_GPIO_PIN, 1); + + metronome_init_gpio_pin(ERR_GPIO_PIN, 1); + + metronome_init_gpio_pin(PCBPWR_GPIO_PIN, 0); + metronome_set_gpio_output(PCBPWR_GPIO_PIN, 0); +} + +static void metronome_disable_lcd_controller(struct metronomefb_par *par) +{ + LCSR = 0xffffffff; /* Clear LCD Status Register */ + LCCR0 |= LCCR0_DIS; /* Disable LCD Controller */ + + /* we reset and just wait for things to settle */ + msleep(200); +} + +static void metronome_enable_lcd_controller(struct metronomefb_par *par) +{ + LCSR = 0xffffffff; + FDADR0 = par->metromem_desc_dma; + LCCR0 |= LCCR0_ENB; +} + +static void __devinit metronome_init_lcdc_regs(struct metronomefb_par *par) +{ + /* here we do: + - disable the lcd controller + - setup lcd control registers + - setup dma descriptor + - reenable lcd controller + */ + + /* disable the lcd controller */ + metronome_disable_lcd_controller(par); + + /* setup lcd control registers */ + LCCR0 = LCCR0_LDM | LCCR0_SFM | LCCR0_IUM | LCCR0_EFM | LCCR0_PAS + | LCCR0_QDM | LCCR0_BM | LCCR0_OUM; + + LCCR1 = (epd_frame_table[0].fw/2 - 1) /* pixels per line */ + | (27 << 10) /* hsync pulse width - 1 */ + | (33 << 16) /* eol pixel count */ + | (33 << 24); /* bol pixel count */ + + LCCR2 = (epd_frame_table[0].fh - 1) /* lines per panel */ + | (24 << 10) /* vsync pulse width - 1 */ + | (2 << 16) /* eof pixel count */ + | (0 << 24); /* bof pixel count */ + + LCCR3 = 2 /* pixel clock divisor */ + | (24 << 8) /* AC Bias pin freq */ + | LCCR3_16BPP /* BPP */ + | LCCR3_PCP; /* PCP falling edge */ + + /* setup dma descriptor */ + par->metromem_desc->mFDADR0 = par->metromem_desc_dma; + par->metromem_desc->mFSADR0 = par->metromem_dma; + par->metromem_desc->mFIDR0 = 0; + par->metromem_desc->mLDCMD0 = epd_frame_table[0].fw + * epd_frame_table[0].fh; + /* reenable lcd controller */ + metronome_enable_lcd_controller(par); +} + +static int metronome_display_cmd(struct metronomefb_par *par) +{ + int i; + u16 cs; + u16 opcode; + static u8 borderval; + u8 *ptr; + + /* setup display command + we can't immediately set the opcode since the controller + will try parse the command before we've set it all up + so we just set cs here and set the opcode at the end */ + + ptr = par->metromem; + + if (par->metromem_cmd->opcode == 0xCC40) + opcode = cs = 0xCC41; + else + opcode = cs = 0xCC40; + + /* set the args ( 2 bytes ) for display */ + i = 0; + par->metromem_cmd->args[i] = 1 << 3 /* border update */ + | ((borderval++ % 4) & 0x0F) << 4 + | (par->frame_count - 1) << 8; + cs += par->metromem_cmd->args[i++]; + + /* the rest are 0 */ + memset((u8 *) (par->metromem_cmd->args + i), 0, (32-i)*2); + + par->metromem_cmd->csum = cs; + par->metromem_cmd->opcode = opcode; /* display cmd */ + + i = wait_event_interruptible_timeout(par->waitq, (GPLR1 & 0x01), HZ); + return i; +} + +static int __devinit metronome_powerup_cmd(struct metronomefb_par *par) +{ + int i; + u16 cs; + + /* setup power up command */ + par->metromem_cmd->opcode = 0x1234; /* pwr up pseudo cmd */ + cs = par->metromem_cmd->opcode; + + /* set pwr1,2,3 to 1024 */ + for (i = 0; i < 3; i++) { + par->metromem_cmd->args[i] = 1024; + cs += par->metromem_cmd->args[i]; + } + + /* the rest are 0 */ + memset((u8 *) (par->metromem_cmd->args + i), 0, (32-i)*2); + + par->metromem_cmd->csum = cs; + + msleep(1); + metronome_set_gpio_output(RST_GPIO_PIN, 1); + + msleep(1); + metronome_set_gpio_output(STDBY_GPIO_PIN, 1); + + i = wait_event_timeout(par->waitq, (GPLR1 & 0x01), HZ); + return i; +} + +static int __devinit metronome_config_cmd(struct metronomefb_par *par) +{ + int i; + u16 cs; + + /* setup config command + we can't immediately set the opcode since the controller + will try parse the command before we've set it all up + so we just set cs here and set the opcode at the end */ + + cs = 0xCC10; + + /* set the 12 args ( 8 bytes ) for config. see spec for meanings */ + i = 0; + par->metromem_cmd->args[i] = 15 /* sdlew */ + | 2 << 8 /* sdosz */ + | 0 << 11 /* sdor */ + | 0 << 12 /* sdces */ + | 0 << 15; /* sdcer */ + cs += par->metromem_cmd->args[i++]; + + par->metromem_cmd->args[i] = 42 /* gdspl */ + | 1 << 8 /* gdr1 */ + | 1 << 9 /* sdshr */ + | 0 << 15; /* gdspp */ + cs += par->metromem_cmd->args[i++]; + + par->metromem_cmd->args[i] = 18 /* gdspw */ + | 0 << 15; /* dispc */ + cs += par->metromem_cmd->args[i++]; + + par->metromem_cmd->args[i] = 599 /* vdlc */ + | 0 << 11 /* dsi */ + | 0 << 12; /* dsic */ + cs += par->metromem_cmd->args[i++]; + + /* the rest are 0 */ + memset((u8 *) (par->metromem_cmd->args + i), 0, (32-i)*2); + + par->metromem_cmd->csum = cs; + par->metromem_cmd->opcode = 0xCC10; /* config cmd */ + + i = wait_event_timeout(par->waitq, (GPLR1 & 0x01), HZ); + return i; +} + +static int __devinit metronome_init_cmd(struct metronomefb_par *par) +{ + int i; + u16 cs; + + /* setup init command + we can't immediately set the opcode since the controller + will try parse the command before we've set it all up + so we just set cs here and set the opcode at the end */ + + cs = 0xCC20; + + /* set the args ( 2 bytes ) for init */ + i = 0; + par->metromem_cmd->args[i] = 0; + cs += par->metromem_cmd->args[i++]; + + /* the rest are 0 */ + memset((u8 *) (par->metromem_cmd->args + i), 0, (32-i)*2); + + par->metromem_cmd->csum = cs; + par->metromem_cmd->opcode = 0xCC20; /* init cmd */ + + i = wait_event_timeout(par->waitq, (GPLR1 & 0x01), HZ); + return i; +} + +static int __devinit metronome_init_regs(struct metronomefb_par *par) +{ + int res; + + metronome_init_gpio_regs(); + metronome_init_lcdc_regs(par); + + res = metronome_powerup_cmd(par); + if (res) + return res; + + res = metronome_config_cmd(par); + if (res) + return res; + + res = metronome_init_cmd(par); + if (res) + return res; + + return res; +} + +static void metronomefb_dpy_update(struct metronomefb_par *par) +{ + u16 cksum; + unsigned char *buf = (unsigned char __force *)par->info->screen_base; + + /* copy from vm to metromem */ + memcpy(par->metromem_img, buf, DPY_W*DPY_H); + + cksum = calc_img_cksum((u16 *) par->metromem_img, + (epd_frame_table[0].fw * DPY_H)/2); + *((u16 *) (par->metromem_img) + + (epd_frame_table[0].fw * DPY_H)/2) = cksum; + metronome_display_cmd(par); +} + +static u16 metronomefb_dpy_update_page(struct metronomefb_par *par, int index) +{ + int i; + u16 csum = 0; + u16 *buf = (u16 __force *) (par->info->screen_base + index); + u16 *img = (u16 *) (par->metromem_img + index); + + /* swizzle from vm to metromem and recalc cksum at the same time*/ + for (i = 0; i < PAGE_SIZE/2; i++) { + *(img + i) = (buf[i] << 5) & 0xE0E0; + csum += *(img + i); + } + return csum; +} + +/* this is called back from the deferred io workqueue */ +static void metronomefb_dpy_deferred_io(struct fb_info *info, + struct list_head *pagelist) +{ + u16 cksum; + struct page *cur; + struct fb_deferred_io *fbdefio = info->fbdefio; + struct metronomefb_par *par = info->par; + + /* walk the written page list and swizzle the data */ + list_for_each_entry(cur, &fbdefio->pagelist, lru) { + cksum = metronomefb_dpy_update_page(par, + (cur->index << PAGE_SHIFT)); + par->metromem_img_csum -= par->csum_table[cur->index]; + par->csum_table[cur->index] = cksum; + par->metromem_img_csum += cksum; + } + + metronome_display_cmd(par); +} + +static void metronomefb_fillrect(struct fb_info *info, + const struct fb_fillrect *rect) +{ + struct metronomefb_par *par = info->par; + + cfb_fillrect(info, rect); + metronomefb_dpy_update(par); +} + +static void metronomefb_copyarea(struct fb_info *info, + const struct fb_copyarea *area) +{ + struct metronomefb_par *par = info->par; + + cfb_copyarea(info, area); + metronomefb_dpy_update(par); +} + +static void metronomefb_imageblit(struct fb_info *info, + const struct fb_image *image) +{ + struct metronomefb_par *par = info->par; + + cfb_imageblit(info, image); + metronomefb_dpy_update(par); +} + +/* + * this is the slow path from userspace. they can seek and write to + * the fb. it is based on fb_sys_write + */ +static ssize_t metronomefb_write(struct fb_info *info, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct metronomefb_par *par = info->par; + unsigned long p = *ppos; + void *dst; + int err = 0; + unsigned long total_size; + + if (info->state != FBINFO_STATE_RUNNING) + return -EPERM; + + total_size = info->fix.smem_len; + + if (p > total_size) + return -EFBIG; + + if (count > total_size) { + err = -EFBIG; + count = total_size; + } + + if (count + p > total_size) { + if (!err) + err = -ENOSPC; + + count = total_size - p; + } + + dst = (void __force *) (info->screen_base + p); + + if (copy_from_user(dst, buf, count)) + err = -EFAULT; + + if (!err) + *ppos += count; + + metronomefb_dpy_update(par); + + return (err) ? err : count; +} + +static struct fb_ops metronomefb_ops = { + .owner = THIS_MODULE, + .fb_write = metronomefb_write, + .fb_fillrect = metronomefb_fillrect, + .fb_copyarea = metronomefb_copyarea, + .fb_imageblit = metronomefb_imageblit, +}; + +static struct fb_deferred_io metronomefb_defio = { + .delay = HZ, + .deferred_io = metronomefb_dpy_deferred_io, +}; + +static irqreturn_t metronome_handle_irq(int irq, void *dev_id) +{ + struct fb_info *info = dev_id; + struct metronomefb_par *par = info->par; + + wake_up_interruptible(&par->waitq); + return IRQ_HANDLED; +} + +static int __devinit metronomefb_probe(struct platform_device *dev) +{ + struct fb_info *info; + int retval = -ENOMEM; + int videomemorysize; + unsigned char *videomemory; + struct metronomefb_par *par; + const struct firmware *fw_entry; + int cmd_size, wfm_size, img_size, padding_size, totalsize; + int i; + + /* we have two blocks of memory. + info->screen_base which is vm, and is the fb used by apps. + par->metromem which is physically contiguous memory and + contains the display controller commands, waveform, + processed image data and padding. this is the data pulled + by the pxa255's LCD controller and pushed to Metronome */ + + videomemorysize = (DPY_W*DPY_H); + videomemory = vmalloc(videomemorysize); + if (!videomemory) + return retval; + + memset(videomemory, 0, videomemorysize); + + info = framebuffer_alloc(sizeof(struct metronomefb_par), &dev->dev); + if (!info) + goto err_vfree; + + info->screen_base = (char __iomem *) videomemory; + info->fbops = &metronomefb_ops; + + info->var = metronomefb_var; + info->fix = metronomefb_fix; + info->fix.smem_len = videomemorysize; + par = info->par; + par->info = info; + init_waitqueue_head(&par->waitq); + + /* this table caches per page csum values. */ + par->csum_table = vmalloc(videomemorysize/PAGE_SIZE); + if (!par->csum_table) + goto err_csum_table; + + /* the metromem buffer is divided as follows: + command | CRC | padding + 16kb waveform data | CRC | padding + image data | CRC + and an extra 256 bytes for dma descriptors + eg: IW=832 IH=622 WS=128 + */ + + cmd_size = 1 * epd_frame_table[0].fw; + wfm_size = ((16*1024 + 2 + epd_frame_table[0].fw - 1) + / epd_frame_table[0].fw) * epd_frame_table[0].fw; + img_size = epd_frame_table[0].fh * epd_frame_table[0].fw; + padding_size = 4 * epd_frame_table[0].fw; + totalsize = cmd_size + wfm_size + img_size + padding_size; + par->metromemsize = PAGE_ALIGN(totalsize + 256); + DPRINTK("desired memory size = %d\n", par->metromemsize); + dev->dev.coherent_dma_mask = 0xffffffffull; + par->metromem = dma_alloc_writecombine(&dev->dev, par->metromemsize, + &par->metromem_dma, GFP_KERNEL); + if (!par->metromem) { + printk(KERN_ERR + "metronomefb: unable to allocate dma buffer\n"); + goto err_vfree; + } + + info->fix.smem_start = par->metromem_dma; + par->metromem_cmd = (struct metromem_cmd *) par->metromem; + par->metromem_wfm = par->metromem + cmd_size; + par->metromem_img = par->metromem + cmd_size + wfm_size; + par->metromem_img_csum = (u16 *) (par->metromem_img + + (epd_frame_table[0].fw * DPY_H)); + DPRINTK("img offset=0x%x\n", cmd_size + wfm_size); + par->metromem_desc = (struct metromem_desc *) (par->metromem + cmd_size + + wfm_size + img_size + padding_size); + par->metromem_desc_dma = par->metromem_dma + cmd_size + wfm_size + + img_size + padding_size; + + /* load the waveform in. assume mode 3, temp 31 for now */ + /* a) request the waveform file from userspace + b) process waveform and decode into metromem */ + + retval = request_firmware(&fw_entry, "waveform.wbf", &dev->dev); + if (retval < 0) { + printk(KERN_ERR "metronomefb: couldn't get waveform\n"); + goto err_dma_free; + } + + retval = load_waveform((u8 *) fw_entry->data, fw_entry->size, + par->metromem_wfm, 3, 31, &par->frame_count); + if (retval < 0) { + printk(KERN_ERR "metronomefb: couldn't process waveform\n"); + goto err_ld_wfm; + } + release_firmware(fw_entry); + + retval = request_irq(IRQ_GPIO(RDY_GPIO_PIN), metronome_handle_irq, + IRQF_DISABLED, "Metronome", info); + if (retval) { + dev_err(&dev->dev, "request_irq failed: %d\n", retval); + goto err_ld_wfm; + } + set_irq_type(IRQ_GPIO(RDY_GPIO_PIN), IRQT_FALLING); + + retval = metronome_init_regs(par); + if (retval < 0) + goto err_free_irq; + + info->flags = FBINFO_FLAG_DEFAULT; + + info->fbdefio = &metronomefb_defio; + fb_deferred_io_init(info); + + retval = fb_alloc_cmap(&info->cmap, 8, 0); + if (retval < 0) { + printk(KERN_ERR "Failed to allocate colormap\n"); + goto err_fb_rel; + } + + /* set cmap */ + for (i = 0; i < 8; i++) + info->cmap.red[i] = (((2*i)+1)*(0xFFFF))/16; + memcpy(info->cmap.green, info->cmap.red, sizeof(u16)*8); + memcpy(info->cmap.blue, info->cmap.red, sizeof(u16)*8); + + retval = register_framebuffer(info); + if (retval < 0) + goto err_cmap; + + platform_set_drvdata(dev, info); + + printk(KERN_INFO + "fb%d: Metronome frame buffer device, using %dK of video" + " memory\n", info->node, videomemorysize >> 10); + + return 0; + +err_cmap: + fb_dealloc_cmap(&info->cmap); +err_fb_rel: + framebuffer_release(info); +err_free_irq: + free_irq(IRQ_GPIO(RDY_GPIO_PIN), info); +err_ld_wfm: + release_firmware(fw_entry); +err_dma_free: + dma_free_writecombine(&dev->dev, par->metromemsize, par->metromem, + par->metromem_dma); +err_csum_table: + vfree(par->csum_table); +err_vfree: + vfree(videomemory); + return retval; +} + +static int __devexit metronomefb_remove(struct platform_device *dev) +{ + struct fb_info *info = platform_get_drvdata(dev); + + if (info) { + struct metronomefb_par *par = info->par; + fb_deferred_io_cleanup(info); + dma_free_writecombine(&dev->dev, par->metromemsize, + par->metromem, par->metromem_dma); + fb_dealloc_cmap(&info->cmap); + vfree(par->csum_table); + unregister_framebuffer(info); + vfree((void __force *)info->screen_base); + free_irq(IRQ_GPIO(RDY_GPIO_PIN), info); + framebuffer_release(info); + } + return 0; +} + +static struct platform_driver metronomefb_driver = { + .probe = metronomefb_probe, + .remove = metronomefb_remove, + .driver = { + .name = "metronomefb", + }, +}; + +static struct platform_device *metronomefb_device; + +static int __init metronomefb_init(void) +{ + int ret; + + if (!metronomefb_enable) { + printk(KERN_ERR + "Use metronomefb_enable to enable the device\n"); + return -ENXIO; + } + + ret = platform_driver_register(&metronomefb_driver); + if (!ret) { + metronomefb_device = platform_device_alloc("metronomefb", 0); + if (metronomefb_device) + ret = platform_device_add(metronomefb_device); + else + ret = -ENOMEM; + + if (ret) { + platform_device_put(metronomefb_device); + platform_driver_unregister(&metronomefb_driver); + } + } + return ret; + +} + +static void __exit metronomefb_exit(void) +{ + platform_device_unregister(metronomefb_device); + platform_driver_unregister(&metronomefb_driver); +} + +module_param(metronomefb_enable, uint, 0); +MODULE_PARM_DESC(metronomefb_enable, "Enable communication with Metronome"); + +module_init(metronomefb_init); +module_exit(metronomefb_exit); + +MODULE_DESCRIPTION("fbdev driver for Metronome controller"); +MODULE_AUTHOR("Jaya Kumar"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/pvr2fb.c b/drivers/video/pvr2fb.c index 6a3d0b57489..8c863a7f654 100644 --- a/drivers/video/pvr2fb.c +++ b/drivers/video/pvr2fb.c @@ -1,16 +1,12 @@ -/* drivers/video/pvr2fb.c +/* + * drivers/video/pvr2fb.c * * Frame buffer and fbcon support for the NEC PowerVR2 found within the Sega * Dreamcast. * * Copyright (c) 2001 M. R. Brown <mrbrown@0xd6.org> - * Copyright (c) 2001, 2002, 2003, 2004, 2005 Paul Mundt <lethal@linux-sh.org> - * - * This file is part of the LinuxDC project (linuxdc.sourceforge.net). + * Copyright (c) 2001 - 2008 Paul Mundt <lethal@linux-sh.org> * - */ - -/* * This driver is mostly based on the excellent amifb and vfb sources. It uses * an odd scheme for converting hardware values to/from framebuffer values, * here are some hacked-up formulas: @@ -490,7 +486,7 @@ static int pvr2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) } else { var->sync &= ~FB_SYNC_BROADCAST; var->vmode &= ~FB_VMODE_INTERLACED; - var->vmode |= pvr2_var.vmode; + var->vmode |= FB_VMODE_NONINTERLACED; } if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_TEST) { diff --git a/drivers/video/sm501fb.c b/drivers/video/sm501fb.c index e83dfba7e63..742b5c656d6 100644 --- a/drivers/video/sm501fb.c +++ b/drivers/video/sm501fb.c @@ -237,12 +237,14 @@ static int sm501fb_check_var(struct fb_var_screeninfo *var, /* check we can fit these values into the registers */ - if (var->hsync_len > 255 || var->vsync_len > 255) + if (var->hsync_len > 255 || var->vsync_len > 63) return -EINVAL; - if ((var->xres + var->right_margin) >= 4096) + /* hdisplay end and hsync start */ + if ((var->xres + var->right_margin) > 4096) return -EINVAL; + /* vdisplay end and vsync start */ if ((var->yres + var->lower_margin) > 2048) return -EINVAL; @@ -281,19 +283,21 @@ static int sm501fb_check_var(struct fb_var_screeninfo *var, var->blue.length = var->bits_per_pixel; var->blue.offset = 0; var->transp.length = 0; + var->transp.offset = 0; break; case 16: if (sm->pdata->flags & SM501_FBPD_SWAP_FB_ENDIAN) { - var->red.offset = 11; - var->green.offset = 5; - var->blue.offset = 0; - } else { var->blue.offset = 11; var->green.offset = 5; var->red.offset = 0; + } else { + var->red.offset = 11; + var->green.offset = 5; + var->blue.offset = 0; } + var->transp.offset = 0; var->red.length = 5; var->green.length = 6; @@ -397,7 +401,7 @@ static int sm501fb_set_par_common(struct fb_info *info, break; case 16: - info->fix.visual = FB_VISUAL_DIRECTCOLOR; + info->fix.visual = FB_VISUAL_TRUECOLOR; break; case 32: @@ -613,6 +617,7 @@ static int sm501fb_set_par_crt(struct fb_info *info) case 16: control |= SM501_DC_CRT_CONTROL_16BPP; + sm501fb_setup_gamma(fbi, SM501_DC_CRT_PALETTE); break; case 32: @@ -750,6 +755,7 @@ static int sm501fb_set_par_pnl(struct fb_info *info) case 16: control |= SM501_DC_PANEL_CONTROL_16BPP; + sm501fb_setup_gamma(fbi, SM501_DC_PANEL_PALETTE); break; case 32: diff --git a/drivers/video/stifb.c b/drivers/video/stifb.c index e7c8db2eb49..f98be301140 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 70fb4ee2b42..0a4e07d43d2 100644 --- a/drivers/video/tridentfb.c +++ b/drivers/video/tridentfb.c @@ -564,7 +564,7 @@ static inline void write3CE(int reg, unsigned char val) t_outb(val, 0x3CF); } -static inline void enable_mmio(void) +static void enable_mmio(void) { /* Goto New Mode */ outb(0x0B, 0x3C4); @@ -579,6 +579,21 @@ static inline void enable_mmio(void) outb(inb(0x3D5) | 0x01, 0x3D5); } +static void disable_mmio(void) +{ + /* Goto New Mode */ + t_outb(0x0B, 0x3C4); + t_inb(0x3C5); + + /* Unprotect registers */ + t_outb(NewMode1, 0x3C4); + t_outb(0x80, 0x3C5); + + /* Disable MMIO */ + t_outb(PCIReg, 0x3D4); + t_outb(t_inb(0x3D5) & ~0x01, 0x3D5); +} + #define crtc_unlock() write3X4(CRTVSyncEnd, read3X4(CRTVSyncEnd) & 0x7F) /* Return flat panel's maximum x resolution */ @@ -730,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 */ @@ -1239,9 +1254,9 @@ static int __devinit trident_pci_probe(struct pci_dev * dev, default_par.io_virt = ioremap_nocache(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len); if (!default_par.io_virt) { - release_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len); debug("ioremap failed\n"); - return -1; + err = -1; + goto out_unmap1; } enable_mmio(); @@ -1252,25 +1267,21 @@ static int __devinit trident_pci_probe(struct pci_dev * dev, if (!request_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len, "tridentfb")) { debug("request_mem_region failed!\n"); + disable_mmio(); err = -1; - goto out_unmap; + goto out_unmap1; } fb_info.screen_base = ioremap_nocache(tridentfb_fix.smem_start, tridentfb_fix.smem_len); if (!fb_info.screen_base) { - release_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len); debug("ioremap failed\n"); err = -1; - goto out_unmap; + goto out_unmap2; } output("%s board found\n", pci_name(dev)); -#if 0 - output("Trident board found : mem = %X, io = %X, mem_v = %X, io_v = %X\n", - tridentfb_fix.smem_start, tridentfb_fix.mmio_start, fb_info.screen_base, default_par.io_virt); -#endif displaytype = get_displaytype(); if (flatpanel) @@ -1288,9 +1299,12 @@ static int __devinit trident_pci_probe(struct pci_dev * dev, if (!fb_find_mode(&default_var, &fb_info, mode, NULL, 0, NULL, bpp)) { err = -EINVAL; - goto out_unmap; + goto out_unmap2; } - fb_alloc_cmap(&fb_info.cmap, 256, 0); + err = fb_alloc_cmap(&fb_info.cmap, 256, 0); + if (err < 0) + goto out_unmap2; + if (defaultaccel && acc) default_var.accel_flags |= FB_ACCELF_TEXT; else @@ -1300,19 +1314,24 @@ static int __devinit trident_pci_probe(struct pci_dev * dev, fb_info.device = &dev->dev; if (register_framebuffer(&fb_info) < 0) { printk(KERN_ERR "tridentfb: could not register Trident framebuffer\n"); + fb_dealloc_cmap(&fb_info.cmap); err = -EINVAL; - goto out_unmap; + goto out_unmap2; } output("fb%d: %s frame buffer device %dx%d-%dbpp\n", fb_info.node, fb_info.fix.id, default_var.xres, default_var.yres, default_var.bits_per_pixel); return 0; -out_unmap: - if (default_par.io_virt) - iounmap(default_par.io_virt); +out_unmap2: if (fb_info.screen_base) iounmap(fb_info.screen_base); + release_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len); + disable_mmio(); +out_unmap1: + if (default_par.io_virt) + iounmap(default_par.io_virt); + release_mem_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len); return err; } @@ -1323,7 +1342,7 @@ static void __devexit trident_pci_remove(struct pci_dev *dev) iounmap(par->io_virt); iounmap(fb_info.screen_base); release_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len); - release_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len); + release_mem_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len); } /* List of boards that we are trying to support */ diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c index c8a4332d113..0b3efc31ee6 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 26f787ddd5f..59a8f73dec7 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 3a28c138213..aa714028641 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/w1/masters/ds1wm.c b/drivers/w1/masters/ds1wm.c index 688e435b4d9..10211e49300 100644 --- a/drivers/w1/masters/ds1wm.c +++ b/drivers/w1/masters/ds1wm.c @@ -17,6 +17,7 @@ #include <linux/pm.h> #include <linux/platform_device.h> #include <linux/clk.h> +#include <linux/err.h> #include <linux/delay.h> #include <linux/ds1wm.h> @@ -102,12 +103,12 @@ struct ds1wm_data { static inline void ds1wm_write_register(struct ds1wm_data *ds1wm_data, u32 reg, u8 val) { - __raw_writeb(val, ds1wm_data->map + (reg << ds1wm_data->bus_shift)); + __raw_writeb(val, ds1wm_data->map + (reg << ds1wm_data->bus_shift)); } static inline u8 ds1wm_read_register(struct ds1wm_data *ds1wm_data, u32 reg) { - return __raw_readb(ds1wm_data->map + (reg << ds1wm_data->bus_shift)); + return __raw_readb(ds1wm_data->map + (reg << ds1wm_data->bus_shift)); } @@ -149,8 +150,8 @@ static int ds1wm_reset(struct ds1wm_data *ds1wm_data) timeleft = wait_for_completion_timeout(&reset_done, DS1WM_TIMEOUT); ds1wm_data->reset_complete = NULL; if (!timeleft) { - dev_dbg(&ds1wm_data->pdev->dev, "reset failed\n"); - return 1; + dev_err(&ds1wm_data->pdev->dev, "reset failed\n"); + return 1; } /* Wait for the end of the reset. According to the specs, the time @@ -167,11 +168,11 @@ static int ds1wm_reset(struct ds1wm_data *ds1wm_data) (ds1wm_data->active_high ? DS1WM_INTEN_IAS : 0)); if (!ds1wm_data->slave_present) { - dev_dbg(&ds1wm_data->pdev->dev, "reset: no devices found\n"); - return 1; - } + dev_dbg(&ds1wm_data->pdev->dev, "reset: no devices found\n"); + return 1; + } - return 0; + return 0; } static int ds1wm_write(struct ds1wm_data *ds1wm_data, u8 data) @@ -334,7 +335,7 @@ static int ds1wm_probe(struct platform_device *pdev) if (!pdev) return -ENODEV; - ds1wm_data = kzalloc(sizeof (*ds1wm_data), GFP_KERNEL); + ds1wm_data = kzalloc(sizeof(*ds1wm_data), GFP_KERNEL); if (!ds1wm_data) return -ENOMEM; @@ -374,8 +375,8 @@ static int ds1wm_probe(struct platform_device *pdev) goto err1; ds1wm_data->clk = clk_get(&pdev->dev, "ds1wm"); - if (!ds1wm_data->clk) { - ret = -ENOENT; + if (IS_ERR(ds1wm_data->clk)) { + ret = PTR_ERR(ds1wm_data->clk); goto err2; } diff --git a/drivers/watchdog/cpu5wdt.c b/drivers/watchdog/cpu5wdt.c index 5941ca601a3..df72f90123d 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 a2e174b09fe..6483d1066b9 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 1b6d7d1b715..1efcad3b6fc 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 e6e07b4575e..6905135a776 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 789831b3fa0..10b89f2703b 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 0f3fd6c9c35..bf443d077a1 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 5d1c15f83d2..7645e881215 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 61dde863bd4..1277f7e9cc5 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; } |