diff options
Diffstat (limited to 'drivers')
77 files changed, 1657 insertions, 1141 deletions
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 7d6be23..8f7505d 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -125,7 +125,7 @@ static int acpi_battery_technology(struct acpi_battery *battery) return POWER_SUPPLY_TECHNOLOGY_NiMH; if (!strcasecmp("LION", battery->type)) return POWER_SUPPLY_TECHNOLOGY_LION; - if (!strcasecmp("LI-ION", battery->type)) + if (!strncasecmp("LI-ION", battery->type, 6)) return POWER_SUPPLY_TECHNOLOGY_LION; if (!strcasecmp("LiP", battery->type)) return POWER_SUPPLY_TECHNOLOGY_LIPO; diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c index ab04d84..0822d9f 100644 --- a/drivers/acpi/numa.c +++ b/drivers/acpi/numa.c @@ -38,9 +38,9 @@ ACPI_MODULE_NAME("numa"); static nodemask_t nodes_found_map = NODE_MASK_NONE; /* maps to convert between proximity domain and logical node ID */ -static int __cpuinitdata pxm_to_node_map[MAX_PXM_DOMAINS] +static int pxm_to_node_map[MAX_PXM_DOMAINS] = { [0 ... MAX_PXM_DOMAINS - 1] = NID_INVAL }; -static int __cpuinitdata node_to_pxm_map[MAX_NUMNODES] +static int node_to_pxm_map[MAX_NUMNODES] = { [0 ... MAX_NUMNODES - 1] = PXM_INVAL }; int pxm_to_node(int pxm) diff --git a/drivers/acpi/pci_bind.c b/drivers/acpi/pci_bind.c index 0289693..388300d 100644 --- a/drivers/acpi/pci_bind.c +++ b/drivers/acpi/pci_bind.c @@ -294,9 +294,6 @@ int acpi_pci_unbind(struct acpi_device *device) acpi_get_data(device->handle, acpi_pci_data_handler, (void **)&data); if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, - "Unable to get data from device %s", - acpi_device_bid(device))); result = -ENODEV; goto end; } diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c index 6045cdb..22cb95b 100644 --- a/drivers/acpi/sbs.c +++ b/drivers/acpi/sbs.c @@ -54,12 +54,6 @@ #define ACPI_BATTERY_DIR_NAME "BAT%i" #define ACPI_AC_DIR_NAME "AC0" -enum acpi_sbs_device_addr { - ACPI_SBS_CHARGER = 0x9, - ACPI_SBS_MANAGER = 0xa, - ACPI_SBS_BATTERY = 0xb, -}; - #define ACPI_SBS_NOTIFY_STATUS 0x80 #define ACPI_SBS_NOTIFY_INFO 0x81 @@ -539,7 +533,7 @@ static struct proc_dir_entry *acpi_battery_dir = NULL; static inline char *acpi_battery_units(struct acpi_battery *battery) { - return acpi_battery_mode(battery) ? " mWh" : " mAh"; + return acpi_battery_mode(battery) ? " mW" : " mA"; } @@ -556,10 +550,10 @@ static int acpi_battery_read_info(struct seq_file *seq, void *offset) if (!battery->present) goto end; - seq_printf(seq, "design capacity: %i%s\n", + seq_printf(seq, "design capacity: %i%sh\n", battery->design_capacity * acpi_battery_scale(battery), acpi_battery_units(battery)); - seq_printf(seq, "last full capacity: %i%s\n", + seq_printf(seq, "last full capacity: %i%sh\n", battery->full_charge_capacity * acpi_battery_scale(battery), acpi_battery_units(battery)); seq_printf(seq, "battery technology: rechargeable\n"); @@ -590,7 +584,7 @@ static int acpi_battery_read_state(struct seq_file *seq, void *offset) { struct acpi_battery *battery = seq->private; struct acpi_sbs *sbs = battery->sbs; - int result = 0; + int rate; mutex_lock(&sbs->lock); seq_printf(seq, "present: %s\n", @@ -604,9 +598,12 @@ static int acpi_battery_read_state(struct seq_file *seq, void *offset) seq_printf(seq, "charging state: %s\n", (battery->current_now < 0) ? "discharging" : ((battery->current_now > 0) ? "charging" : "charged")); - seq_printf(seq, "present rate: %d mA\n", - abs(battery->current_now) * acpi_battery_ipscale(battery)); - seq_printf(seq, "remaining capacity: %i%s\n", + rate = abs(battery->current_now) * acpi_battery_ipscale(battery); + rate *= (acpi_battery_mode(battery))?(battery->voltage_now * + acpi_battery_vscale(battery)/1000):1; + seq_printf(seq, "present rate: %d%s\n", rate, + acpi_battery_units(battery)); + seq_printf(seq, "remaining capacity: %i%sh\n", battery->capacity_now * acpi_battery_scale(battery), acpi_battery_units(battery)); seq_printf(seq, "present voltage: %i mV\n", @@ -614,7 +611,7 @@ static int acpi_battery_read_state(struct seq_file *seq, void *offset) end: mutex_unlock(&sbs->lock); - return result; + return 0; } static int acpi_battery_state_open_fs(struct inode *inode, struct file *file) @@ -638,7 +635,7 @@ static int acpi_battery_read_alarm(struct seq_file *seq, void *offset) acpi_battery_get_alarm(battery); seq_printf(seq, "alarm: "); if (battery->alarm_capacity) - seq_printf(seq, "%i%s\n", + seq_printf(seq, "%i%sh\n", battery->alarm_capacity * acpi_battery_scale(battery), acpi_battery_units(battery)); diff --git a/drivers/acpi/sbshc.c b/drivers/acpi/sbshc.c index 046d7c3..fd40b6a 100644 --- a/drivers/acpi/sbshc.c +++ b/drivers/acpi/sbshc.c @@ -202,10 +202,9 @@ int acpi_smbus_unregister_callback(struct acpi_smb_hc *hc) EXPORT_SYMBOL_GPL(acpi_smbus_unregister_callback); -static void acpi_smbus_callback(void *context) +static inline void acpi_smbus_callback(void *context) { struct acpi_smb_hc *hc = context; - if (hc->callback) hc->callback(hc->context); } @@ -214,6 +213,7 @@ static int smbus_alarm(void *context) { struct acpi_smb_hc *hc = context; union acpi_smb_status status; + u8 address; if (smb_hc_read(hc, ACPI_SMB_STATUS, &status.raw)) return 0; /* Check if it is only a completion notify */ @@ -222,9 +222,18 @@ static int smbus_alarm(void *context) if (!status.fields.alarm) return 0; mutex_lock(&hc->lock); + smb_hc_read(hc, ACPI_SMB_ALARM_ADDRESS, &address); + status.fields.alarm = 0; smb_hc_write(hc, ACPI_SMB_STATUS, status.raw); - if (hc->callback) - acpi_os_execute(OSL_GPE_HANDLER, acpi_smbus_callback, hc); + /* We are only interested in events coming from known devices */ + switch (address >> 1) { + case ACPI_SBS_CHARGER: + case ACPI_SBS_MANAGER: + case ACPI_SBS_BATTERY: + acpi_os_execute(OSL_GPE_HANDLER, + acpi_smbus_callback, hc); + default:; + } mutex_unlock(&hc->lock); return 0; } diff --git a/drivers/acpi/sbshc.h b/drivers/acpi/sbshc.h index 3bda349..a57b076 100644 --- a/drivers/acpi/sbshc.h +++ b/drivers/acpi/sbshc.h @@ -16,6 +16,12 @@ enum acpi_smb_protocol { static const u8 SMBUS_PEC = 0x80; +enum acpi_sbs_device_addr { + ACPI_SBS_CHARGER = 0x9, + ACPI_SBS_MANAGER = 0xa, + ACPI_SBS_BATTERY = 0xb, +}; + typedef void (*smbus_alarm_callback)(void *context); extern int acpi_smbus_read(struct acpi_smb_hc *hc, u8 protocol, u8 address, diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 44a0d9b..bd77e81 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -577,7 +577,7 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) struct acpi_video_device_brightness *br = NULL; - memset(&device->cap, 0, 4); + memset(&device->cap, 0, sizeof(device->cap)); if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_ADR", &h_dummy1))) { device->cap._ADR = 1; @@ -697,7 +697,7 @@ static void acpi_video_bus_find_cap(struct acpi_video_bus *video) { acpi_handle h_dummy1; - memset(&video->cap, 0, 4); + memset(&video->cap, 0, sizeof(video->cap)); if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_DOS", &h_dummy1))) { video->cap._DOS = 1; } diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index 545ea86..7bf4bef 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c @@ -6,6 +6,7 @@ * Copyright (C) 2006 Randy Dunlap */ +#include <linux/module.h> #include <linux/ata.h> #include <linux/delay.h> #include <linux/device.h> @@ -25,6 +26,18 @@ #include <acpi/acmacros.h> #include <acpi/actypes.h> +enum { + ATA_ACPI_FILTER_SETXFER = 1 << 0, + ATA_ACPI_FILTER_LOCK = 1 << 1, + + ATA_ACPI_FILTER_DEFAULT = ATA_ACPI_FILTER_SETXFER | + ATA_ACPI_FILTER_LOCK, +}; + +static unsigned int ata_acpi_gtf_filter = ATA_ACPI_FILTER_DEFAULT; +module_param_named(acpi_gtf_filter, ata_acpi_gtf_filter, int, 0644); +MODULE_PARM_DESC(acpi_gtf_filter, "filter mask for ACPI _GTF commands, set to filter out (0x1=set xfermode, 0x2=lock/freeze lock)"); + #define NO_PORT_MULT 0xffff #define SATA_ADR(root, pmp) (((root) << 16) | (pmp)) @@ -41,6 +54,12 @@ static int is_pci_dev(struct device *dev) return (dev->bus == &pci_bus_type); } +static void ata_acpi_clear_gtf(struct ata_device *dev) +{ + kfree(dev->gtf_cache); + dev->gtf_cache = NULL; +} + /** * ata_acpi_associate_sata_port - associate SATA port with ACPI objects * @ap: target SATA port @@ -94,6 +113,9 @@ static void ata_acpi_associate_ide_port(struct ata_port *ap) dev->acpi_handle = acpi_get_child(ap->acpi_handle, i); } + + if (ata_acpi_gtm(ap, &ap->__acpi_init_gtm) == 0) + ap->pflags |= ATA_PFLAG_INIT_GTM_VALID; } static void ata_acpi_handle_hotplug(struct ata_port *ap, struct kobject *kobj, @@ -188,6 +210,32 @@ void ata_acpi_associate(struct ata_host *host) } /** + * ata_acpi_dissociate - dissociate ATA host from ACPI objects + * @host: target ATA host + * + * This function is called during driver detach after the whole host + * is shut down. + * + * LOCKING: + * EH context. + */ +void ata_acpi_dissociate(struct ata_host *host) +{ + int i; + + /* Restore initial _GTM values so that driver which attaches + * afterward can use them too. + */ + for (i = 0; i < host->n_ports; i++) { + struct ata_port *ap = host->ports[i]; + const struct ata_acpi_gtm *gtm = ata_acpi_init_gtm(ap); + + if (ap->acpi_handle && gtm) + ata_acpi_stm(ap, gtm); + } +} + +/** * ata_acpi_gtm - execute _GTM * @ap: target ATA port * @gtm: out parameter for _GTM result @@ -200,7 +248,7 @@ void ata_acpi_associate(struct ata_host *host) * RETURNS: * 0 on success, -ENOENT if _GTM doesn't exist, -errno on failure. */ -int ata_acpi_gtm(const struct ata_port *ap, struct ata_acpi_gtm *gtm) +int ata_acpi_gtm(struct ata_port *ap, struct ata_acpi_gtm *gtm) { struct acpi_buffer output = { .length = ACPI_ALLOCATE_BUFFER }; union acpi_object *out_obj; @@ -259,15 +307,16 @@ EXPORT_SYMBOL_GPL(ata_acpi_gtm); * RETURNS: * 0 on success, -ENOENT if _STM doesn't exist, -errno on failure. */ -int ata_acpi_stm(const struct ata_port *ap, struct ata_acpi_gtm *stm) +int ata_acpi_stm(struct ata_port *ap, const struct ata_acpi_gtm *stm) { acpi_status status; + struct ata_acpi_gtm stm_buf = *stm; struct acpi_object_list input; union acpi_object in_params[3]; in_params[0].type = ACPI_TYPE_BUFFER; in_params[0].buffer.length = sizeof(struct ata_acpi_gtm); - in_params[0].buffer.pointer = (u8 *)stm; + in_params[0].buffer.pointer = (u8 *)&stm_buf; /* Buffers for id may need byteswapping ? */ in_params[1].type = ACPI_TYPE_BUFFER; in_params[1].buffer.length = 512; @@ -297,7 +346,6 @@ EXPORT_SYMBOL_GPL(ata_acpi_stm); * ata_dev_get_GTF - get the drive bootup default taskfile settings * @dev: target ATA device * @gtf: output parameter for buffer containing _GTF taskfile arrays - * @ptr_to_free: pointer which should be freed * * This applies to both PATA and SATA drives. * @@ -311,11 +359,10 @@ EXPORT_SYMBOL_GPL(ata_acpi_stm); * EH context. * * RETURNS: - * Number of taskfiles on success, 0 if _GTF doesn't exist or doesn't - * contain valid data. + * Number of taskfiles on success, 0 if _GTF doesn't exist. -EINVAL + * if _GTF is invalid. */ -static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf, - void **ptr_to_free) +static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf) { struct ata_port *ap = dev->link->ap; acpi_status status; @@ -323,6 +370,12 @@ static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf, union acpi_object *out_obj; int rc = 0; + /* if _GTF is cached, use the cached value */ + if (dev->gtf_cache) { + out_obj = dev->gtf_cache; + goto done; + } + /* set up output buffer */ output.length = ACPI_ALLOCATE_BUFFER; output.pointer = NULL; /* ACPI-CA sets this; save/free it later */ @@ -333,12 +386,14 @@ static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf, /* _GTF has no input parameters */ status = acpi_evaluate_object(dev->acpi_handle, "_GTF", NULL, &output); + out_obj = dev->gtf_cache = output.pointer; if (ACPI_FAILURE(status)) { if (status != AE_NOT_FOUND) { ata_dev_printk(dev, KERN_WARNING, "_GTF evaluation failed (AE 0x%x)\n", status); + rc = -EINVAL; } goto out_free; } @@ -350,14 +405,15 @@ static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf, __FUNCTION__, (unsigned long long)output.length, output.pointer); + rc = -EINVAL; goto out_free; } - out_obj = output.pointer; if (out_obj->type != ACPI_TYPE_BUFFER) { ata_dev_printk(dev, KERN_WARNING, "_GTF unexpected object type 0x%x\n", out_obj->type); + rc = -EINVAL; goto out_free; } @@ -365,21 +421,23 @@ static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf, ata_dev_printk(dev, KERN_WARNING, "unexpected _GTF length (%d)\n", out_obj->buffer.length); + rc = -EINVAL; goto out_free; } - *ptr_to_free = out_obj; - *gtf = (void *)out_obj->buffer.pointer; + done: rc = out_obj->buffer.length / REGS_PER_GTF; - - if (ata_msg_probe(ap)) - ata_dev_printk(dev, KERN_DEBUG, "%s: returning " - "gtf=%p, gtf_count=%d, ptr_to_free=%p\n", - __FUNCTION__, *gtf, rc, *ptr_to_free); + if (gtf) { + *gtf = (void *)out_obj->buffer.pointer; + if (ata_msg_probe(ap)) + ata_dev_printk(dev, KERN_DEBUG, + "%s: returning gtf=%p, gtf_count=%d\n", + __FUNCTION__, *gtf, rc); + } return rc; out_free: - kfree(output.pointer); + ata_acpi_clear_gtf(dev); return rc; } @@ -393,22 +451,21 @@ static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf, int ata_acpi_cbl_80wire(struct ata_port *ap) { - struct ata_acpi_gtm gtm; + const struct ata_acpi_gtm *gtm = ata_acpi_init_gtm(ap); int valid = 0; - /* No _GTM data, no information */ - if (ata_acpi_gtm(ap, >m) < 0) + if (!gtm) return 0; /* Split timing, DMA enabled */ - if ((gtm.flags & 0x11) == 0x11 && gtm.drive[0].dma < 55) + if ((gtm->flags & 0x11) == 0x11 && gtm->drive[0].dma < 55) valid |= 1; - if ((gtm.flags & 0x14) == 0x14 && gtm.drive[1].dma < 55) + if ((gtm->flags & 0x14) == 0x14 && gtm->drive[1].dma < 55) valid |= 2; /* Shared timing, DMA enabled */ - if ((gtm.flags & 0x11) == 0x01 && gtm.drive[0].dma < 55) + if ((gtm->flags & 0x11) == 0x01 && gtm->drive[0].dma < 55) valid |= 1; - if ((gtm.flags & 0x14) == 0x04 && gtm.drive[0].dma < 55) + if ((gtm->flags & 0x14) == 0x04 && gtm->drive[0].dma < 55) valid |= 2; /* Drive check */ @@ -421,8 +478,62 @@ int ata_acpi_cbl_80wire(struct ata_port *ap) EXPORT_SYMBOL_GPL(ata_acpi_cbl_80wire); +static void ata_acpi_gtf_to_tf(struct ata_device *dev, + const struct ata_acpi_gtf *gtf, + struct ata_taskfile *tf) +{ + ata_tf_init(dev, tf); + + tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf->protocol = ATA_PROT_NODATA; + tf->feature = gtf->tf[0]; /* 0x1f1 */ + tf->nsect = gtf->tf[1]; /* 0x1f2 */ + tf->lbal = gtf->tf[2]; /* 0x1f3 */ + tf->lbam = gtf->tf[3]; /* 0x1f4 */ + tf->lbah = gtf->tf[4]; /* 0x1f5 */ + tf->device = gtf->tf[5]; /* 0x1f6 */ + tf->command = gtf->tf[6]; /* 0x1f7 */ +} + +static int ata_acpi_filter_tf(const struct ata_taskfile *tf, + const struct ata_taskfile *ptf) +{ + if (ata_acpi_gtf_filter & ATA_ACPI_FILTER_SETXFER) { + /* libata doesn't use ACPI to configure transfer mode. + * It will only confuse device configuration. Skip. + */ + if (tf->command == ATA_CMD_SET_FEATURES && + tf->feature == SETFEATURES_XFER) + return 1; + } + + if (ata_acpi_gtf_filter & ATA_ACPI_FILTER_LOCK) { + /* BIOS writers, sorry but we don't wanna lock + * features unless the user explicitly said so. + */ + + /* DEVICE CONFIGURATION FREEZE LOCK */ + if (tf->command == ATA_CMD_CONF_OVERLAY && + tf->feature == ATA_DCO_FREEZE_LOCK) + return 1; + + /* SECURITY FREEZE LOCK */ + if (tf->command == ATA_CMD_SEC_FREEZE_LOCK) + return 1; + + /* SET MAX LOCK and SET MAX FREEZE LOCK */ + if ((!ptf || ptf->command != ATA_CMD_READ_NATIVE_MAX) && + tf->command == ATA_CMD_SET_MAX && + (tf->feature == ATA_SET_MAX_LOCK || + tf->feature == ATA_SET_MAX_FREEZE_LOCK)) + return 1; + } + + return 0; +} + /** - * taskfile_load_raw - send taskfile registers to host controller + * ata_acpi_run_tf - send taskfile registers to host controller * @dev: target ATA device * @gtf: raw ATA taskfile register set (0x1f1 - 0x1f7) * @@ -441,56 +552,77 @@ EXPORT_SYMBOL_GPL(ata_acpi_cbl_80wire); * EH context. * * RETURNS: - * 0 on success, -errno on failure. + * 1 if command is executed successfully. 0 if ignored, rejected or + * filtered out, -errno on other errors. */ -static int taskfile_load_raw(struct ata_device *dev, - const struct ata_acpi_gtf *gtf) +static int ata_acpi_run_tf(struct ata_device *dev, + const struct ata_acpi_gtf *gtf, + const struct ata_acpi_gtf *prev_gtf) { - struct ata_port *ap = dev->link->ap; - struct ata_taskfile tf, rtf; + struct ata_taskfile *pptf = NULL; + struct ata_taskfile tf, ptf, rtf; unsigned int err_mask; + const char *level; + char msg[60]; + int rc; if ((gtf->tf[0] == 0) && (gtf->tf[1] == 0) && (gtf->tf[2] == 0) && (gtf->tf[3] == 0) && (gtf->tf[4] == 0) && (gtf->tf[5] == 0) && (gtf->tf[6] == 0)) return 0; - ata_tf_init(dev, &tf); + ata_acpi_gtf_to_tf(dev, gtf, &tf); + if (prev_gtf) { + ata_acpi_gtf_to_tf(dev, prev_gtf, &ptf); + pptf = &ptf; + } - /* convert gtf to tf */ - tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; /* TBD */ - tf.protocol = ATA_PROT_NODATA; - tf.feature = gtf->tf[0]; /* 0x1f1 */ - tf.nsect = gtf->tf[1]; /* 0x1f2 */ - tf.lbal = gtf->tf[2]; /* 0x1f3 */ - tf.lbam = gtf->tf[3]; /* 0x1f4 */ - tf.lbah = gtf->tf[4]; /* 0x1f5 */ - tf.device = gtf->tf[5]; /* 0x1f6 */ - tf.command = gtf->tf[6]; /* 0x1f7 */ + if (!ata_acpi_filter_tf(&tf, pptf)) { + rtf = tf; + err_mask = ata_exec_internal(dev, &rtf, NULL, + DMA_NONE, NULL, 0, 0); - if (ata_msg_probe(ap)) - ata_dev_printk(dev, KERN_DEBUG, "executing ACPI cmd " - "%02x/%02x:%02x:%02x:%02x:%02x:%02x\n", - tf.command, tf.feature, tf.nsect, - tf.lbal, tf.lbam, tf.lbah, tf.device); - - rtf = tf; - err_mask = ata_exec_internal(dev, &rtf, NULL, DMA_NONE, NULL, 0, 0); - if (err_mask) { - ata_dev_printk(dev, KERN_ERR, - "ACPI cmd %02x/%02x:%02x:%02x:%02x:%02x:%02x failed " - "(Emask=0x%x Stat=0x%02x Err=0x%02x)\n", - tf.command, tf.feature, tf.nsect, tf.lbal, tf.lbam, - tf.lbah, tf.device, err_mask, rtf.command, rtf.feature); - return -EIO; + switch (err_mask) { + case 0: + level = KERN_DEBUG; + snprintf(msg, sizeof(msg), "succeeded"); + rc = 1; + break; + + case AC_ERR_DEV: + level = KERN_INFO; + snprintf(msg, sizeof(msg), + "rejected by device (Stat=0x%02x Err=0x%02x)", + rtf.command, rtf.feature); + rc = 0; + break; + + default: + level = KERN_ERR; + snprintf(msg, sizeof(msg), + "failed (Emask=0x%x Stat=0x%02x Err=0x%02x)", + err_mask, rtf.command, rtf.feature); + rc = -EIO; + break; + } + } else { + level = KERN_INFO; + snprintf(msg, sizeof(msg), "filtered out"); + rc = 0; } - return 0; + ata_dev_printk(dev, level, + "ACPI cmd %02x/%02x:%02x:%02x:%02x:%02x:%02x %s\n", + tf.command, tf.feature, tf.nsect, tf.lbal, + tf.lbam, tf.lbah, tf.device, msg); + + return rc; } /** * ata_acpi_exec_tfs - get then write drive taskfile settings * @dev: target ATA device + * @nr_executed: out paramter for the number of executed commands * * Evaluate _GTF and excute returned taskfiles. * @@ -498,35 +630,36 @@ static int taskfile_load_raw(struct ata_device *dev, * EH context. * * RETURNS: - * Number of executed taskfiles on success, 0 if _GTF doesn't exist or - * doesn't contain valid data. -errno on other errors. + * Number of executed taskfiles on success, 0 if _GTF doesn't exist. + * -errno on other errors. */ -static int ata_acpi_exec_tfs(struct ata_device *dev) +static int ata_acpi_exec_tfs(struct ata_device *dev, int *nr_executed) { - struct ata_acpi_gtf *gtf = NULL; - void *ptr_to_free = NULL; + struct ata_acpi_gtf *gtf = NULL, *pgtf = NULL; int gtf_count, i, rc; /* get taskfiles */ - gtf_count = ata_dev_get_GTF(dev, >f, &ptr_to_free); + rc = ata_dev_get_GTF(dev, >f); + if (rc < 0) + return rc; + gtf_count = rc; /* execute them */ - for (i = 0, rc = 0; i < gtf_count; i++) { - int tmp; - - /* ACPI errors are eventually ignored. Run till the - * end even after errors. - */ - tmp = taskfile_load_raw(dev, gtf++); - if (!rc) - rc = tmp; + for (i = 0; i < gtf_count; i++, gtf++) { + rc = ata_acpi_run_tf(dev, gtf, pgtf); + if (rc < 0) + break; + if (rc) { + (*nr_executed)++; + pgtf = gtf; + } } - kfree(ptr_to_free); + ata_acpi_clear_gtf(dev); - if (rc == 0) - return gtf_count; - return rc; + if (rc < 0) + return rc; + return 0; } /** @@ -596,27 +729,8 @@ static int ata_acpi_push_id(struct ata_device *dev) */ int ata_acpi_on_suspend(struct ata_port *ap) { - unsigned long flags; - int rc; - - /* proceed iff per-port acpi_handle is valid */ - if (!ap->acpi_handle) - return 0; - BUG_ON(ap->flags & ATA_FLAG_ACPI_SATA); - - /* store timing parameters */ - rc = ata_acpi_gtm(ap, &ap->acpi_gtm); - - spin_lock_irqsave(ap->lock, flags); - if (rc == 0) - ap->pflags |= ATA_PFLAG_GTM_VALID; - else - ap->pflags &= ~ATA_PFLAG_GTM_VALID; - spin_unlock_irqrestore(ap->lock, flags); - - if (rc == -ENOENT) - rc = 0; - return rc; + /* nada */ + return 0; } /** @@ -631,18 +745,34 @@ int ata_acpi_on_suspend(struct ata_port *ap) */ void ata_acpi_on_resume(struct ata_port *ap) { + const struct ata_acpi_gtm *gtm = ata_acpi_init_gtm(ap); struct ata_device *dev; - if (ap->acpi_handle && (ap->pflags & ATA_PFLAG_GTM_VALID)) { - BUG_ON(ap->flags & ATA_FLAG_ACPI_SATA); + if (ap->acpi_handle && gtm) { + /* _GTM valid */ /* restore timing parameters */ - ata_acpi_stm(ap, &ap->acpi_gtm); - } + ata_acpi_stm(ap, gtm); - /* schedule _GTF */ - ata_link_for_each_dev(dev, &ap->link) - dev->flags |= ATA_DFLAG_ACPI_PENDING; + /* _GTF should immediately follow _STM so that it can + * use values set by _STM. Cache _GTF result and + * schedule _GTF. + */ + ata_link_for_each_dev(dev, &ap->link) { + ata_acpi_clear_gtf(dev); + if (ata_dev_get_GTF(dev, NULL) >= 0) + dev->flags |= ATA_DFLAG_ACPI_PENDING; + } + } else { + /* SATA _GTF needs to be evaulated after _SDD and + * there's no reason to evaluate IDE _GTF early + * without _STM. Clear cache and schedule _GTF. + */ + ata_link_for_each_dev(dev, &ap->link) { + ata_acpi_clear_gtf(dev); + dev->flags |= ATA_DFLAG_ACPI_PENDING; + } + } } /** @@ -664,6 +794,7 @@ int ata_acpi_on_devcfg(struct ata_device *dev) struct ata_port *ap = dev->link->ap; struct ata_eh_context *ehc = &ap->link.eh_context; int acpi_sata = ap->flags & ATA_FLAG_ACPI_SATA; + int nr_executed = 0; int rc; if (!dev->acpi_handle) @@ -682,14 +813,14 @@ int ata_acpi_on_devcfg(struct ata_device *dev) } /* do _GTF */ - rc = ata_acpi_exec_tfs(dev); - if (rc < 0) + rc = ata_acpi_exec_tfs(dev, &nr_executed); + if (rc) goto acpi_err; dev->flags &= ~ATA_DFLAG_ACPI_PENDING; /* refresh IDENTIFY page if any _GTF command has been executed */ - if (rc > 0) { + if (nr_executed) { rc = ata_dev_reread_id(dev, 0); if (rc < 0) { ata_dev_printk(dev, KERN_ERR, "failed to IDENTIFY " @@ -701,17 +832,39 @@ int ata_acpi_on_devcfg(struct ata_device *dev) return 0; acpi_err: - /* let EH retry on the first failure, disable ACPI on the second */ - if (dev->flags & ATA_DFLAG_ACPI_FAILED) { - ata_dev_printk(dev, KERN_WARNING, "ACPI on devcfg failed the " - "second time, disabling (errno=%d)\n", rc); - - dev->acpi_handle = NULL; + /* ignore evaluation failure if we can continue safely */ + if (rc == -EINVAL && !nr_executed && !(ap->pflags & ATA_PFLAG_FROZEN)) + return 0; - /* if port is working, request IDENTIFY reload and continue */ - if (!(ap->pflags & ATA_PFLAG_FROZEN)) - rc = 1; + /* fail and let EH retry once more for unknown IO errors */ + if (!(dev->flags & ATA_DFLAG_ACPI_FAILED)) { + dev->flags |= ATA_DFLAG_ACPI_FAILED; + return rc; } - dev->flags |= ATA_DFLAG_ACPI_FAILED; + + ata_dev_printk(dev, KERN_WARNING, + "ACPI: failed the second time, disabled\n"); + dev->acpi_handle = NULL; + + /* We can safely continue if no _GTF command has been executed + * and port is not frozen. + */ + if (!nr_executed && !(ap->pflags & ATA_PFLAG_FROZEN)) + return 0; + return rc; } + +/** + * ata_acpi_on_disable - ATA ACPI hook called when a device is disabled + * @dev: target ATA device + * + * This function is called when @dev is about to be disabled. + * + * LOCKING: + * EH context. + */ +void ata_acpi_on_disable(struct ata_device *dev) +{ + ata_acpi_clear_gtf(dev); +} diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index e4dea86..4753a18 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -64,6 +64,7 @@ #include <linux/libata.h> #include <asm/semaphore.h> #include <asm/byteorder.h> +#include <linux/cdrom.h> #include "libata.h" @@ -622,6 +623,7 @@ void ata_dev_disable(struct ata_device *dev) if (ata_dev_enabled(dev)) { if (ata_msg_drv(dev->link->ap)) ata_dev_printk(dev, KERN_WARNING, "disabled\n"); + ata_acpi_on_disable(dev); ata_down_xfermask_limit(dev, ATA_DNXFER_FORCE_PIO0 | ATA_DNXFER_QUIET); dev->class++; @@ -3923,6 +3925,7 @@ void ata_std_postreset(struct ata_link *link, unsigned int *classes) /* clear SError */ if (sata_scr_read(link, SCR_ERROR, &serror) == 0) sata_scr_write(link, SCR_ERROR, serror); + link->eh_info.serror = 0; /* is double-select really necessary? */ if (classes[0] != ATA_DEV_NONE) @@ -4149,6 +4152,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { { "HITACHI HDS7250SASUN500G*", NULL, ATA_HORKAGE_NONCQ }, { "HITACHI HDS7225SBSUN250G*", NULL, ATA_HORKAGE_NONCQ }, { "ST380817AS", "3.42", ATA_HORKAGE_NONCQ }, + { "ST3160023AS", "3.42", ATA_HORKAGE_NONCQ }, /* Blacklist entries taken from Silicon Image 3124/3132 Windows driver .inf file - also several Linux problem reports */ @@ -4649,6 +4653,43 @@ int ata_check_atapi_dma(struct ata_queued_cmd *qc) } /** + * atapi_qc_may_overflow - Check whether data transfer may overflow + * @qc: ATA command in question + * + * ATAPI commands which transfer variable length data to host + * might overflow due to application error or hardare bug. This + * function checks whether overflow should be drained and ignored + * for @qc. + * + * LOCKING: + * None. + * + * RETURNS: + * 1 if @qc may overflow; otherwise, 0. + */ +static int atapi_qc_may_overflow(struct ata_queued_cmd *qc) +{ + if (qc->tf.protocol != ATA_PROT_ATAPI && + qc->tf.protocol != ATA_PROT_ATAPI_DMA) + return 0; + + if (qc->tf.flags & ATA_TFLAG_WRITE) + return 0; + + switch (qc->cdb[0]) { + case READ_10: + case READ_12: + case WRITE_10: + case WRITE_12: + case GPCMD_READ_CD: + case GPCMD_READ_CD_MSF: + return 0; + } + + return 1; +} + +/** * ata_std_qc_defer - Check whether a qc needs to be deferred * @qc: ATA command in question * @@ -5136,23 +5177,19 @@ static void atapi_send_cdb(struct ata_port *ap, struct ata_queued_cmd *qc) * Inherited from caller. * */ - -static void __atapi_pio_bytes(struct ata_queued_cmd *qc, unsigned int bytes) +static int __atapi_pio_bytes(struct ata_queued_cmd *qc, unsigned int bytes) { int do_write = (qc->tf.flags & ATA_TFLAG_WRITE); - struct scatterlist *sg = qc->__sg; - struct scatterlist *lsg = sg_last(qc->__sg, qc->n_elem); struct ata_port *ap = qc->ap; + struct ata_eh_info *ehi = &qc->dev->link->eh_info; + struct scatterlist *sg; struct page *page; unsigned char *buf; unsigned int offset, count; - int no_more_sg = 0; - - if (qc->curbytes + bytes >= qc->nbytes) - ap->hsm_task_state = HSM_ST_LAST; next_sg: - if (unlikely(no_more_sg)) { + sg = qc->cursg; + if (unlikely(!sg)) { /* * The end of qc->sg is reached and the device expects * more data to transfer. In order not to overrun qc->sg @@ -5161,21 +5198,28 @@ next_sg: * - for write case, padding zero data to the device */ u16 pad_buf[1] = { 0 }; - unsigned int words = bytes >> 1; unsigned int i; - if (words) /* warning if bytes > 1 */ - ata_dev_printk(qc->dev, KERN_WARNING, - "%u bytes trailing data\n", bytes); + if (bytes > qc->curbytes - qc->nbytes + ATAPI_MAX_DRAIN) { + ata_ehi_push_desc(ehi, "too much trailing data " + "buf=%u cur=%u bytes=%u", + qc->nbytes, qc->curbytes, bytes); + return -1; + } - for (i = 0; i < words; i++) + /* overflow is exptected for misc ATAPI commands */ + if (bytes && !atapi_qc_may_overflow(qc)) + ata_dev_printk(qc->dev, KERN_WARNING, "ATAPI %u bytes " + "trailing data (cdb=%02x nbytes=%u)\n", + bytes, qc->cdb[0], qc->nbytes); + + for (i = 0; i < (bytes + 1) / 2; i++) ap->ops->data_xfer(qc->dev, (unsigned char *)pad_buf, 2, do_write); - ap->hsm_task_state = HSM_ST_LAST; - return; - } + qc->curbytes += bytes; - sg = qc->cursg; + return 0; + } page = sg_page(sg); offset = sg->offset + qc->cursg_ofs; @@ -5210,19 +5254,20 @@ next_sg: } bytes -= count; + if ((count & 1) && bytes) + bytes--; qc->curbytes += count; qc->cursg_ofs += count; if (qc->cursg_ofs == sg->length) { - if (qc->cursg == lsg) - no_more_sg = 1; - qc->cursg = sg_next(qc->cursg); qc->cursg_ofs = 0; } if (bytes) goto next_sg; + + return 0; } /** @@ -5265,7 +5310,8 @@ static void atapi_pio_bytes(struct ata_queued_cmd *qc) VPRINTK("ata%u: xfering %d bytes\n", ap->print_id, bytes); - __atapi_pio_bytes(qc, bytes); + if (__atapi_pio_bytes(qc, bytes)) + goto err_out; ata_altstatus(ap); /* flush */ return; @@ -7208,18 +7254,14 @@ static void ata_port_detach(struct ata_port *ap) ata_port_wait_eh(ap); - /* EH is now guaranteed to see UNLOADING, so no new device - * will be attached. Disable all existing devices. + /* EH is now guaranteed to see UNLOADING - EH context belongs + * to us. Disable all existing devices. */ - spin_lock_irqsave(ap->lock, flags); - ata_port_for_each_link(link, ap) { ata_link_for_each_dev(dev, link) ata_dev_disable(dev); } - spin_unlock_irqrestore(ap->lock, flags); - /* Final freeze & EH. All in-flight commands are aborted. EH * will be skipped and retrials will be terminated with bad * target. @@ -7251,6 +7293,9 @@ void ata_host_detach(struct ata_host *host) for (i = 0; i < host->n_ports; i++) ata_port_detach(host->ports[i]); + + /* the host is dead now, dissociate ACPI */ + ata_acpi_dissociate(host); } /** diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index e6605f0..f0124a8 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1264,8 +1264,8 @@ static unsigned int atapi_eh_request_sense(struct ata_queued_cmd *qc) tf.feature |= ATAPI_PKT_DMA; } else { tf.protocol = ATA_PROT_ATAPI; - tf.lbam = (8 * 1024) & 0xff; - tf.lbah = (8 * 1024) >> 8; + tf.lbam = SCSI_SENSE_BUFFERSIZE; + tf.lbah = 0; } return ata_exec_internal(dev, &tf, cdb, DMA_FROM_DEVICE, diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index 0e6cf3a..bbe59c2 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -108,15 +108,19 @@ extern void ata_lpm_schedule(struct ata_port *ap, enum link_pm); #ifdef CONFIG_ATA_ACPI extern void ata_acpi_associate_sata_port(struct ata_port *ap); extern void ata_acpi_associate(struct ata_host *host); +extern void ata_acpi_dissociate(struct ata_host *host); extern int ata_acpi_on_suspend(struct ata_port *ap); extern void ata_acpi_on_resume(struct ata_port *ap); -extern int ata_acpi_on_devcfg(struct ata_device *adev); +extern int ata_acpi_on_devcfg(struct ata_device *dev); +extern void ata_acpi_on_disable(struct ata_device *dev); #else static inline void ata_acpi_associate_sata_port(struct ata_port *ap) { } static inline void ata_acpi_associate(struct ata_host *host) { } +static inline void ata_acpi_dissociate(struct ata_host *host) { } static inline int ata_acpi_on_suspend(struct ata_port *ap) { return 0; } static inline void ata_acpi_on_resume(struct ata_port *ap) { } -static inline int ata_acpi_on_devcfg(struct ata_device *adev) { return 0; } +static inline int ata_acpi_on_devcfg(struct ata_device *dev) { return 0; } +static inline void ata_acpi_on_disable(struct ata_device *dev) { } #endif /* libata-scsi.c */ diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index fe0105d..37b850a 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -2506,11 +2506,31 @@ static int mv_chip_id(struct ata_host *host, unsigned int board_idx) if (pdev->vendor == PCI_VENDOR_ID_TTI && (pdev->device == 0x2300 || pdev->device == 0x2310)) { - printk(KERN_WARNING "sata_mv: Highpoint RocketRAID BIOS" - " will CORRUPT DATA on attached drives when" - " configured as \"Legacy\". BEWARE!\n"); - printk(KERN_WARNING "sata_mv: Use BIOS \"JBOD\" volumes" - " instead for safety.\n"); + /* + * Highpoint RocketRAID PCIe 23xx series cards: + * + * Unconfigured drives are treated as "Legacy" + * by the BIOS, and it overwrites sector 8 with + * a "Lgcy" metadata block prior to Linux boot. + * + * Configured drives (RAID or JBOD) leave sector 8 + * alone, but instead overwrite a high numbered + * sector for the RAID metadata. This sector can + * be determined exactly, by truncating the physical + * drive capacity to a nice even GB value. + * + * RAID metadata is at: (dev->n_sectors & ~0xfffff) + * + * Warn the user, lest they think we're just buggy. + */ + printk(KERN_WARNING DRV_NAME ": Highpoint RocketRAID" + " BIOS CORRUPTS DATA on all attached drives," + " regardless of if/how they are configured." + " BEWARE!\n"); + printk(KERN_WARNING DRV_NAME ": For data safety, do not" + " use sectors 8-9 on \"Legacy\" drives," + " and avoid the final two gigabytes on" + " all RocketRAID BIOS initialized drives.\n"); } case chip_6042: hpriv->ops = &mv6xxx_ops; diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c index 4e6e381..f5119bf 100644 --- a/drivers/ata/sata_sil.c +++ b/drivers/ata/sata_sil.c @@ -390,23 +390,19 @@ static void sil_host_intr(struct ata_port *ap, u32 bmdma2) sil_scr_read(ap, SCR_ERROR, &serror); sil_scr_write(ap, SCR_ERROR, serror); - /* Trigger hotplug and accumulate SError only if the - * port isn't already frozen. Otherwise, PHY events - * during hardreset makes controllers with broken SIEN - * repeat probing needlessly. + /* Sometimes spurious interrupts occur, double check + * it's PHYRDY CHG. */ - if (!(ap->pflags & ATA_PFLAG_FROZEN)) { - ata_ehi_hotplugged(&ap->link.eh_info); + if (serror & SERR_PHYRDY_CHG) { ap->link.eh_info.serror |= serror; + goto freeze; } - goto freeze; + if (!(bmdma2 & SIL_DMA_COMPLETE)) + return; } - if (unlikely(!qc)) - goto freeze; - - if (unlikely(qc->tf.flags & ATA_TFLAG_POLLING)) { + if (unlikely(!qc || (qc->tf.flags & ATA_TFLAG_POLLING))) { /* this sometimes happens, just clear IRQ */ ata_chk_status(ap); return; diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c index 8b12925..f97e050 100644 --- a/drivers/atm/fore200e.c +++ b/drivers/atm/fore200e.c @@ -2689,7 +2689,7 @@ fore200e_init(struct fore200e* fore200e) return 0; } - +#ifdef CONFIG_ATM_FORE200E_PCA static int __devinit fore200e_pca_detect(struct pci_dev *pci_dev, const struct pci_device_id *pci_ent) { @@ -2756,7 +2756,6 @@ static void __devexit fore200e_pca_remove_one(struct pci_dev *pci_dev) } -#ifdef CONFIG_ATM_FORE200E_PCA static struct pci_device_id fore200e_pca_tbl[] = { { PCI_VENDOR_ID_FORE, PCI_DEVICE_ID_FORE_PCA200E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &fore200e_bus[0] }, diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index a5ee213..3535ef8 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -117,8 +117,10 @@ static struct pktcdvd_kobj* pkt_kobj_create(struct pktcdvd_device *pd, p->kobj.parent = parent; p->kobj.ktype = ktype; p->pd = pd; - if (kobject_register(&p->kobj) != 0) + if (kobject_register(&p->kobj) != 0) { + kobject_put(&p->kobj); return NULL; + } return p; } /* diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index a509b8d..ef1ed5d7 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -543,28 +543,6 @@ config PPDEV If unsure, say N. -config TIPAR - tristate "Texas Instruments parallel link cable support" - depends on PARPORT - ---help--- - If you own a Texas Instruments graphing calculator and use a - parallel link cable, then you might be interested in this driver. - - If you enable this driver, you will be able to communicate with - your calculator through a set of device nodes under /dev. The - main advantage of this driver is that you don't have to be root - to use this precise link cable (depending on the permissions on - the device nodes, though). - - To compile this driver as a module, choose M here: the - module will be called tipar. - - If you don't know what a parallel link cable is or what a Texas - Instruments graphing calculator is, then you probably don't need this - driver. - - If unsure, say N. - config HVC_DRIVER bool help diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c index e686fc9..8f45ca9 100644 --- a/drivers/char/ipmi/ipmi_watchdog.c +++ b/drivers/char/ipmi/ipmi_watchdog.c @@ -669,6 +669,7 @@ static int ipmi_ioctl(struct inode *inode, struct file *file, return 0; case WDIOC_SET_PRETIMEOUT: + case WDIOC_SETPRETIMEOUT: i = copy_from_user(&val, argp, sizeof(int)); if (i) return -EFAULT; @@ -676,6 +677,7 @@ static int ipmi_ioctl(struct inode *inode, struct file *file, return ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY); case WDIOC_GET_PRETIMEOUT: + case WDIOC_GETPRETIMEOUT: i = copy_to_user(argp, &pretimeout, sizeof(pretimeout)); if (i) return -EFAULT; diff --git a/drivers/char/tipar.c b/drivers/char/tipar.c deleted file mode 100644 index cef55c4..0000000 --- a/drivers/char/tipar.c +++ /dev/null @@ -1,557 +0,0 @@ -/* Hey EMACS -*- linux-c -*- - * - * tipar - low level driver for handling a parallel link cable designed - * for Texas Instruments graphing calculators (http://lpg.ticalc.org). - * A part of the TiLP project. - * - * Copyright (C) 2000-2002, Romain Lievin <roms@lpg.ticalc.org> - * under the terms of the GNU General Public License. - * - * Various fixes & clean-up from the Linux Kernel Mailing List - * (Alan Cox, Richard B. Johnson, Christoph Hellwig). - */ - -/* This driver should, in theory, work with any parallel port that has an - * appropriate low-level driver; all I/O is done through the parport - * abstraction layer. - * - * If this driver is built into the kernel, you can configure it using the - * kernel command-line. For example: - * - * tipar=timeout,delay (set timeout and delay) - * - * If the driver is loaded as a module, similar functionality is available - * using module parameters. The equivalent of the above commands would be: - * - * # insmod tipar timeout=15 delay=10 - */ - -/* COMPATIBILITY WITH OLD KERNELS - * - * Usually, parallel cables were bound to ports at - * particular I/O addresses, as follows: - * - * tipar0 0x378 - * tipar1 0x278 - * tipar2 0x3bc - * - * - * This driver, by default, binds tipar devices according to parport and - * the minor number. - * - */ -#undef DEBUG /* change to #define to get debugging - * output - for pr_debug() */ -#include <linux/module.h> -#include <linux/types.h> -#include <linux/errno.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/delay.h> -#include <linux/fcntl.h> -#include <linux/fs.h> -#include <linux/init.h> -#include <asm/uaccess.h> -#include <linux/ioport.h> -#include <asm/io.h> -#include <linux/bitops.h> -#include <linux/parport.h> /* Our code depend on parport */ -#include <linux/device.h> - -/* - * TI definitions - */ -#include <linux/ticable.h> - -/* - * Version Information - */ -#define DRIVER_VERSION "1.19" -#define DRIVER_AUTHOR "Romain Lievin <roms@lpg.ticalc.org>" -#define DRIVER_DESC "Device driver for TI/PC parallel link cables" -#define DRIVER_LICENSE "GPL" - -#define VERSION(ver,rel,seq) (((ver)<<16) | ((rel)<<8) | (seq)) - -/* ----- global variables --------------------------------------------- */ - -struct tipar_struct { - struct pardevice *dev; /* Parport device entry */ -}; - -#define PP_NO 3 -static struct tipar_struct table[PP_NO]; - -static int delay = IO_DELAY; /* inter-bit delay in microseconds */ -static int timeout = TIMAXTIME; /* timeout in tenth of seconds */ - -static unsigned int tp_count; /* tipar count */ -static unsigned long opened; /* opened devices */ - -static struct class *tipar_class; - -/* --- macros for parport access -------------------------------------- */ - -#define r_dtr(x) (parport_read_data(table[(x)].dev->port)) -#define r_str(x) (parport_read_status(table[(x)].dev->port)) -#define w_ctr(x,y) (parport_write_control(table[(x)].dev->port, (y))) -#define w_dtr(x,y) (parport_write_data(table[(x)].dev->port, (y))) - -/* --- setting states on the D-bus with the right timing: ------------- */ - -static inline void -outbyte(int value, int minor) -{ - w_dtr(minor, value); -} - -static inline int -inbyte(int minor) -{ - return (r_str(minor)); -} - -static inline void -init_ti_parallel(int minor) -{ - outbyte(3, minor); -} - -/* ----- global defines ----------------------------------------------- */ - -#define START(x) { x = jiffies + (HZ * timeout) / 10; } -#define WAIT(x) { \ - if (time_before((x), jiffies)) return -1; \ - if (need_resched()) schedule(); } - -/* ----- D-bus bit-banging functions ---------------------------------- */ - -/* D-bus protocol (45kbit/s max): - 1 0 0 - _______ ______|______ __________|________ __________ -Red : ________ | ____ | ____ - _ ____________|________ ______|__________ _____ -White: ________ | ______ | _______ -*/ - -/* Try to transmit a byte on the specified port (-1 if error). */ -static int -put_ti_parallel(int minor, unsigned char data) -{ - unsigned int bit; - unsigned long max; - - for (bit = 0; bit < 8; bit++) { - if (data & 1) { - outbyte(2, minor); - START(max); - do { - WAIT(max); - } while (inbyte(minor) & 0x10); - - outbyte(3, minor); - START(max); - do { - WAIT(max); - } while (!(inbyte(minor) & 0x10)); - } else { - outbyte(1, minor); - START(max); - do { - WAIT(max); - } while (inbyte(minor) & 0x20); - - outbyte(3, minor); - START(max); - do { - WAIT(max); - } while (!(inbyte(minor) & 0x20)); - } - - data >>= 1; - udelay(delay); - - if (need_resched()) - schedule(); - } - - return 0; -} - -/* Receive a byte on the specified port or -1 if error. */ -static int -get_ti_parallel(int minor) -{ - unsigned int bit; - unsigned char v, data = 0; - unsigned long max; - - for (bit = 0; bit < 8; bit++) { - START(max); - do { - WAIT(max); - } while ((v = inbyte(minor) & 0x30) == 0x30); - - if (v == 0x10) { - data = (data >> 1) | 0x80; - outbyte(1, minor); - START(max); - do { - WAIT(max); - } while (!(inbyte(minor) & 0x20)); - outbyte(3, minor); - } else { - data = data >> 1; - outbyte(2, minor); - START(max); - do { - WAIT(max); - } while (!(inbyte(minor) & 0x10)); - outbyte(3, minor); - } - - udelay(delay); - if (need_resched()) - schedule(); - } - - return (int) data; -} - -/* Try to detect a parallel link cable on the specified port */ -static int -probe_ti_parallel(int minor) -{ - int i; - int seq[] = { 0x00, 0x20, 0x10, 0x30 }; - int data; - - for (i = 3; i >= 0; i--) { - outbyte(3, minor); - outbyte(i, minor); - udelay(delay); - data = inbyte(minor) & 0x30; - pr_debug("tipar: Probing -> %i: 0x%02x 0x%02x\n", i, - data, seq[i]); - if (data != seq[i]) { - outbyte(3, minor); - return -1; - } - } - - outbyte(3, minor); - return 0; -} - -/* ----- kernel module functions--------------------------------------- */ - -static int -tipar_open(struct inode *inode, struct file *file) -{ - unsigned int minor = iminor(inode) - TIPAR_MINOR; - - if (tp_count == 0 || minor > tp_count - 1) - return -ENXIO; - - if (test_and_set_bit(minor, &opened)) - return -EBUSY; - - if (!table[minor].dev) { - printk(KERN_ERR "%s: NULL device for minor %u\n", - __FUNCTION__, minor); - return -ENXIO; - } - parport_claim_or_block(table[minor].dev); - init_ti_parallel(minor); - parport_release(table[minor].dev); - - return nonseekable_open(inode, file); -} - -static int -tipar_close(struct inode *inode, struct file *file) -{ - unsigned int minor = iminor(inode) - TIPAR_MINOR; - - if (minor > tp_count - 1) - return -ENXIO; - - clear_bit(minor, &opened); - - return 0; -} - -static ssize_t -tipar_write (struct file *file, const char __user *buf, size_t count, - loff_t * ppos) -{ - unsigned int minor = iminor(file->f_path.dentry->d_inode) - TIPAR_MINOR; - ssize_t n; - - parport_claim_or_block(table[minor].dev); - - for (n = 0; n < count; n++) { - unsigned char b; - - if (get_user(b, buf + n)) { - n = -EFAULT; - goto out; - } - - if (put_ti_parallel(minor, b) == -1) { - init_ti_parallel(minor); - n = -ETIMEDOUT; - goto out; - } - } - out: - parport_release(table[minor].dev); - return n; -} - -static ssize_t -tipar_read(struct file *file, char __user *buf, size_t count, loff_t * ppos) -{ - int b = 0; - unsigned int minor = iminor(file->f_path.dentry->d_inode) - TIPAR_MINOR; - ssize_t retval = 0; - ssize_t n = 0; - - if (count == 0) - return 0; - - parport_claim_or_block(table[minor].dev); - - while (n < count) { - b = get_ti_parallel(minor); - if (b == -1) { - init_ti_parallel(minor); - retval = -ETIMEDOUT; - goto out; - } else { - if (put_user(b, buf + n)) { - retval = -EFAULT; - break; - } else - retval = ++n; - } - - /* Non-blocking mode : try again ! */ - if (file->f_flags & O_NONBLOCK) { - retval = -EAGAIN; - goto out; - } - - /* Signal pending, try again ! */ - if (signal_pending(current)) { - retval = -ERESTARTSYS; - goto out; - } - - if (need_resched()) - schedule(); - } - - out: - parport_release(table[minor].dev); - return retval; -} - -static int -tipar_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - int retval = 0; - - switch (cmd) { - case IOCTL_TIPAR_DELAY: - delay = (int)arg; //get_user(delay, &arg); - break; - case IOCTL_TIPAR_TIMEOUT: - if (arg != 0) - timeout = (int)arg; - else - retval = -EINVAL; - break; - default: - retval = -ENOTTY; - break; - } - - return retval; -} - -/* ----- kernel module registering ------------------------------------ */ - -static const struct file_operations tipar_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = tipar_read, - .write = tipar_write, - .ioctl = tipar_ioctl, - .open = tipar_open, - .release = tipar_close, -}; - -/* --- initialisation code ------------------------------------- */ - -#ifndef MODULE -/* You must set these - there is no sane way to probe for this cable. - * You can use 'tipar=timeout,delay' to set these now. */ -static int __init -tipar_setup(char *str) -{ - int ints[3]; - - str = get_options(str, ARRAY_SIZE(ints), ints); - - if (ints[0] > 0) { - if (ints[1] != 0) - timeout = ints[1]; - else - printk(KERN_WARNING "tipar: bad timeout value (0), " - "using default value instead"); - if (ints[0] > 1) { - delay = ints[2]; - } - } - - return 1; -} -#endif - -/* - * Register our module into parport. - * Pass also 2 callbacks functions to parport: a pre-emptive function and an - * interrupt handler function (unused). - * Display a message such "tipar0: using parport0 (polling)". - */ -static int -tipar_register(int nr, struct parport *port) -{ - int err = 0; - - /* Register our module into parport */ - table[nr].dev = parport_register_device(port, "tipar", - NULL, NULL, NULL, 0, - (void *) &table[nr]); - - if (table[nr].dev == NULL) { - err = 1; - goto out; - } - - device_create(tipar_class, port->dev, MKDEV(TIPAR_MAJOR, - TIPAR_MINOR + nr), "par%d", nr); - - /* Display informations */ - pr_info("tipar%d: using %s (%s)\n", nr, port->name, (port->irq == - PARPORT_IRQ_NONE) ? "polling" : "interrupt-driven"); - - if (probe_ti_parallel(nr) != -1) - pr_info("tipar%d: link cable found\n", nr); - else - pr_info("tipar%d: link cable not found\n", nr); - - err = 0; - -out: - return err; -} - -static void -tipar_attach(struct parport *port) -{ - if (tp_count == PP_NO) { - pr_info("tipar: ignoring parallel port (max. %d)\n", PP_NO); - return; - } - - if (!tipar_register(tp_count, port)) - tp_count++; -} - -static void -tipar_detach(struct parport *port) -{ - /* Nothing to do */ -} - -static struct parport_driver tipar_driver = { - .name = "tipar", - .attach = tipar_attach, - .detach = tipar_detach, -}; - -static int __init -tipar_init_module(void) -{ - int err = 0; - - pr_info("tipar: parallel link cable driver, version %s\n", - DRIVER_VERSION); - - if (register_chrdev(TIPAR_MAJOR, "tipar", &tipar_fops)) { - printk(KERN_ERR "tipar: unable to get major %d\n", TIPAR_MAJOR); - err = -EIO; - goto out; - } - - tipar_class = class_create(THIS_MODULE, "ticables"); - if (IS_ERR(tipar_class)) { - err = PTR_ERR(tipar_class); - goto out_chrdev; - } - if (parport_register_driver(&tipar_driver)) { - printk(KERN_ERR "tipar: unable to register with parport\n"); - err = -EIO; - goto out_class; - } - - err = 0; - goto out; - -out_class: - class_destroy(tipar_class); - -out_chrdev: - unregister_chrdev(TIPAR_MAJOR, "tipar"); -out: - return err; -} - -static void __exit -tipar_cleanup_module(void) -{ - unsigned int i; - - /* Unregistering module */ - parport_unregister_driver(&tipar_driver); - - unregister_chrdev(TIPAR_MAJOR, "tipar"); - - for (i = 0; i < PP_NO; i++) { - if (table[i].dev == NULL) - continue; - parport_unregister_device(table[i].dev); - device_destroy(tipar_class, MKDEV(TIPAR_MAJOR, i)); - } - class_destroy(tipar_class); - - pr_info("tipar: module unloaded\n"); -} - -/* --------------------------------------------------------------------- */ - -__setup("tipar=", tipar_setup); -module_init(tipar_init_module); -module_exit(tipar_cleanup_module); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE(DRIVER_LICENSE); - -module_param(timeout, int, 0); -MODULE_PARM_DESC(timeout, "Timeout (default=1.5 seconds)"); -module_param(delay, int, 0); -MODULE_PARM_DESC(delay, "Inter-bit delay (default=10 microseconds)"); diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 5e626b1..79581fa 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -841,19 +841,25 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) drv_attr = cpufreq_driver->attr; while ((drv_attr) && (*drv_attr)) { ret = sysfs_create_file(&policy->kobj, &((*drv_attr)->attr)); - if (ret) + if (ret) { + unlock_policy_rwsem_write(cpu); goto err_out_driver_exit; + } drv_attr++; } if (cpufreq_driver->get){ ret = sysfs_create_file(&policy->kobj, &cpuinfo_cur_freq.attr); - if (ret) + if (ret) { + unlock_policy_rwsem_write(cpu); goto err_out_driver_exit; + } } if (cpufreq_driver->target){ ret = sysfs_create_file(&policy->kobj, &scaling_cur_freq.attr); - if (ret) + if (ret) { + unlock_policy_rwsem_write(cpu); goto err_out_driver_exit; + } } spin_lock_irqsave(&cpufreq_driver_lock, flags); diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index 8a45d0f..1b8312b 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -164,7 +164,7 @@ freq_table_get_index(struct cpufreq_stats *stat, unsigned int freq) return -1; } -static void __cpuexit cpufreq_stats_free_table(unsigned int cpu) +static void cpufreq_stats_free_table(unsigned int cpu) { struct cpufreq_stats *stat = cpufreq_stats_table[cpu]; struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); diff --git a/drivers/dma/ioat_dma.c b/drivers/dma/ioat_dma.c index c1c2dcc..45e7b46 100644 --- a/drivers/dma/ioat_dma.c +++ b/drivers/dma/ioat_dma.c @@ -173,10 +173,47 @@ static void ioat_set_dest(dma_addr_t addr, tx_to_ioat_desc(tx)->dst = addr; } +/** + * ioat_dma_memcpy_issue_pending - push potentially unrecognized appended + * descriptors to hw + * @chan: DMA channel handle + */ static inline void __ioat1_dma_memcpy_issue_pending( - struct ioat_dma_chan *ioat_chan); + struct ioat_dma_chan *ioat_chan) +{ + ioat_chan->pending = 0; + writeb(IOAT_CHANCMD_APPEND, ioat_chan->reg_base + IOAT1_CHANCMD_OFFSET); +} + +static void ioat1_dma_memcpy_issue_pending(struct dma_chan *chan) +{ + struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan); + + if (ioat_chan->pending != 0) { + spin_lock_bh(&ioat_chan->desc_lock); + __ioat1_dma_memcpy_issue_pending(ioat_chan); + spin_unlock_bh(&ioat_chan->desc_lock); + } +} + static inline void __ioat2_dma_memcpy_issue_pending( - struct ioat_dma_chan *ioat_chan); + struct ioat_dma_chan *ioat_chan) +{ + ioat_chan->pending = 0; + writew(ioat_chan->dmacount, + ioat_chan->reg_base + IOAT_CHAN_DMACOUNT_OFFSET); +} + +static void ioat2_dma_memcpy_issue_pending(struct dma_chan *chan) +{ + struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan); + + if (ioat_chan->pending != 0) { + spin_lock_bh(&ioat_chan->desc_lock); + __ioat2_dma_memcpy_issue_pending(ioat_chan); + spin_unlock_bh(&ioat_chan->desc_lock); + } +} static dma_cookie_t ioat1_tx_submit(struct dma_async_tx_descriptor *tx) { @@ -203,7 +240,7 @@ static dma_cookie_t ioat1_tx_submit(struct dma_async_tx_descriptor *tx) prev = to_ioat_desc(ioat_chan->used_desc.prev); prefetch(prev->hw); do { - copy = min((u32) len, ioat_chan->xfercap); + copy = min_t(size_t, len, ioat_chan->xfercap); new->async_tx.ack = 1; @@ -291,10 +328,12 @@ static dma_cookie_t ioat2_tx_submit(struct dma_async_tx_descriptor *tx) orig_ack = first->async_tx.ack; new = first; - /* ioat_chan->desc_lock is still in force in version 2 path */ - + /* + * ioat_chan->desc_lock is still in force in version 2 path + * it gets unlocked at end of this function + */ do { - copy = min((u32) len, ioat_chan->xfercap); + copy = min_t(size_t, len, ioat_chan->xfercap); new->async_tx.ack = 1; @@ -432,7 +471,7 @@ static void ioat2_dma_massage_chan_desc(struct ioat_dma_chan *ioat_chan) static int ioat_dma_alloc_chan_resources(struct dma_chan *chan) { struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan); - struct ioat_desc_sw *desc = NULL; + struct ioat_desc_sw *desc; u16 chanctrl; u32 chanerr; int i; @@ -575,7 +614,7 @@ static void ioat_dma_free_chan_resources(struct dma_chan *chan) static struct ioat_desc_sw * ioat1_dma_get_next_descriptor(struct ioat_dma_chan *ioat_chan) { - struct ioat_desc_sw *new = NULL; + struct ioat_desc_sw *new; if (!list_empty(&ioat_chan->free_desc)) { new = to_ioat_desc(ioat_chan->free_desc.next); @@ -583,9 +622,11 @@ ioat1_dma_get_next_descriptor(struct ioat_dma_chan *ioat_chan) } else { /* try to get another desc */ new = ioat_dma_alloc_descriptor(ioat_chan, GFP_ATOMIC); - /* will this ever happen? */ - /* TODO add upper limit on these */ - BUG_ON(!new); + if (!new) { + dev_err(&ioat_chan->device->pdev->dev, + "alloc failed\n"); + return NULL; + } } prefetch(new->hw); @@ -595,7 +636,7 @@ ioat1_dma_get_next_descriptor(struct ioat_dma_chan *ioat_chan) static struct ioat_desc_sw * ioat2_dma_get_next_descriptor(struct ioat_dma_chan *ioat_chan) { - struct ioat_desc_sw *new = NULL; + struct ioat_desc_sw *new; /* * used.prev points to where to start processing @@ -609,8 +650,8 @@ ioat2_dma_get_next_descriptor(struct ioat_dma_chan *ioat_chan) if (ioat_chan->used_desc.prev && ioat_chan->used_desc.next == ioat_chan->used_desc.prev->prev) { - struct ioat_desc_sw *desc = NULL; - struct ioat_desc_sw *noop_desc = NULL; + struct ioat_desc_sw *desc; + struct ioat_desc_sw *noop_desc; int i; /* set up the noop descriptor */ @@ -624,10 +665,14 @@ ioat2_dma_get_next_descriptor(struct ioat_dma_chan *ioat_chan) ioat_chan->pending++; ioat_chan->dmacount++; - /* get a few more descriptors */ + /* try to get a few more descriptors */ for (i = 16; i; i--) { desc = ioat_dma_alloc_descriptor(ioat_chan, GFP_ATOMIC); - BUG_ON(!desc); + if (!desc) { + dev_err(&ioat_chan->device->pdev->dev, + "alloc failed\n"); + break; + } list_add_tail(&desc->node, ioat_chan->used_desc.next); desc->hw->next @@ -677,10 +722,13 @@ static struct dma_async_tx_descriptor *ioat1_dma_prep_memcpy( spin_lock_bh(&ioat_chan->desc_lock); new = ioat_dma_get_next_descriptor(ioat_chan); - new->len = len; spin_unlock_bh(&ioat_chan->desc_lock); - return new ? &new->async_tx : NULL; + if (new) { + new->len = len; + return &new->async_tx; + } else + return NULL; } static struct dma_async_tx_descriptor *ioat2_dma_prep_memcpy( @@ -693,53 +741,17 @@ static struct dma_async_tx_descriptor *ioat2_dma_prep_memcpy( spin_lock_bh(&ioat_chan->desc_lock); new = ioat2_dma_get_next_descriptor(ioat_chan); - new->len = len; - - /* leave ioat_chan->desc_lock set in version 2 path */ - return new ? &new->async_tx : NULL; -} + /* + * leave ioat_chan->desc_lock set in ioat 2 path + * it will get unlocked at end of tx_submit + */ -/** - * ioat_dma_memcpy_issue_pending - push potentially unrecognized appended - * descriptors to hw - * @chan: DMA channel handle - */ -static inline void __ioat1_dma_memcpy_issue_pending( - struct ioat_dma_chan *ioat_chan) -{ - ioat_chan->pending = 0; - writeb(IOAT_CHANCMD_APPEND, ioat_chan->reg_base + IOAT1_CHANCMD_OFFSET); -} - -static void ioat1_dma_memcpy_issue_pending(struct dma_chan *chan) -{ - struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan); - - if (ioat_chan->pending != 0) { - spin_lock_bh(&ioat_chan->desc_lock); - __ioat1_dma_memcpy_issue_pending(ioat_chan); - spin_unlock_bh(&ioat_chan->desc_lock); - } -} - -static inline void __ioat2_dma_memcpy_issue_pending( - struct ioat_dma_chan *ioat_chan) -{ - ioat_chan->pending = 0; - writew(ioat_chan->dmacount, - ioat_chan->reg_base + IOAT_CHAN_DMACOUNT_OFFSET); -} - -static void ioat2_dma_memcpy_issue_pending(struct dma_chan *chan) -{ - struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan); - - if (ioat_chan->pending != 0) { - spin_lock_bh(&ioat_chan->desc_lock); - __ioat2_dma_memcpy_issue_pending(ioat_chan); - spin_unlock_bh(&ioat_chan->desc_lock); - } + if (new) { + new->len = len; + return &new->async_tx; + } else + return NULL; } static void ioat_dma_cleanup_tasklet(unsigned long data) @@ -1019,7 +1031,7 @@ static void ioat_dma_start_null_desc(struct ioat_dma_chan *ioat_chan) static void ioat_dma_test_callback(void *dma_async_param) { printk(KERN_ERR "ioatdma: ioat_dma_test_callback(%p)\n", - dma_async_param); + dma_async_param); } /** @@ -1032,7 +1044,7 @@ static int ioat_dma_self_test(struct ioatdma_device *device) u8 *src; u8 *dest; struct dma_chan *dma_chan; - struct dma_async_tx_descriptor *tx = NULL; + struct dma_async_tx_descriptor *tx; dma_addr_t addr; dma_cookie_t cookie; int err = 0; @@ -1351,7 +1363,7 @@ err_completion_pool: err_dma_pool: kfree(device); err_kzalloc: - dev_err(&device->pdev->dev, + dev_err(&pdev->dev, "Intel(R) I/OAT DMA Engine initialization failed\n"); return NULL; } diff --git a/drivers/dma/ioatdma.h b/drivers/dma/ioatdma.h index b668234..f2c7fed 100644 --- a/drivers/dma/ioatdma.h +++ b/drivers/dma/ioatdma.h @@ -76,7 +76,7 @@ struct ioat_dma_chan { dma_cookie_t completed_cookie; unsigned long last_completion; - u32 xfercap; /* XFERCAP register value expanded out */ + size_t xfercap; /* XFERCAP register value expanded out */ spinlock_t cleanup_lock; spinlock_t desc_lock; diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig index 45b2228..fb06555 100644 --- a/drivers/ide/Kconfig +++ b/drivers/ide/Kconfig @@ -390,7 +390,7 @@ config IDEPCI_PCIBUS_ORDER # TODO: split it on per host driver config options (or module parameters) config BLK_DEV_OFFBOARD - bool "Boot off-board chipsets first support" + bool "Boot off-board chipsets first support (DEPRECATED)" depends on BLK_DEV_IDEPCI && (BLK_DEV_AEC62XX || BLK_DEV_GENERIC || BLK_DEV_HPT34X || BLK_DEV_HPT366 || BLK_DEV_PDC202XX_NEW || BLK_DEV_PDC202XX_OLD || BLK_DEV_TC86C001) help Normally, IDE controllers built into the motherboard (on-board @@ -410,6 +410,10 @@ config BLK_DEV_OFFBOARD Note that, if you do this, the order of the hd* devices will be rearranged which may require modification of fstab and other files. + Please also note that this method of assuring stable naming of + IDE devices is unreliable and use other means for achieving it + (i.e. udev). + If in doubt, say N. config BLK_DEV_GENERIC diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index 57a5f63..92ac658d 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -1650,31 +1650,6 @@ static int cdrom_write_check_ireason(ide_drive_t *drive, int len, int ireason) return 1; } -static void post_transform_command(struct request *req) -{ - u8 *c = req->cmd; - char *ibuf; - - if (!blk_pc_request(req)) - return; - - if (req->bio) - ibuf = bio_data(req->bio); - else - ibuf = req->data; - - if (!ibuf) - return; - - /* - * set ansi-revision and response data as atapi - */ - if (c[0] == GPCMD_INQUIRY) { - ibuf[2] |= 2; - ibuf[3] = (ibuf[3] & 0xf0) | 2; - } -} - typedef void (xfer_func_t)(ide_drive_t *, void *, u32); /* @@ -1810,9 +1785,6 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive) return ide_started; end_request: - if (!rq->data_len) - post_transform_command(rq); - spin_lock_irqsave(&ide_lock, flags); blkdev_dequeue_request(rq); end_that_request_last(rq, 1); @@ -3049,12 +3021,7 @@ int ide_cdrom_probe_capabilities (ide_drive_t *drive) else printk(" drive"); - printk(", %dkB Cache", be16_to_cpu(cap.buffer_size)); - - if (drive->using_dma) - ide_dma_verbose(drive); - - printk("\n"); + printk(KERN_CONT ", %dkB Cache\n", be16_to_cpu(cap.buffer_size)); return nslots; } diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c index 00123d9..b178190 100644 --- a/drivers/ide/ide-disk.c +++ b/drivers/ide/ide-disk.c @@ -13,32 +13,6 @@ * and Andre Hedrick <andre@linux-ide.org> * * This is the IDE/ATA disk driver, as evolved from hd.c and ide.c. - * - * Version 1.00 move disk only code from ide.c to ide-disk.c - * support optional byte-swapping of all data - * Version 1.01 fix previous byte-swapping code - * Version 1.02 remove ", LBA" from drive identification msgs - * Version 1.03 fix display of id->buf_size for big-endian - * Version 1.04 add /proc configurable settings and S.M.A.R.T support - * Version 1.05 add capacity support for ATA3 >= 8GB - * Version 1.06 get boot-up messages to show full cyl count - * Version 1.07 disable door-locking if it fails - * Version 1.08 fixed CHS/LBA translations for ATA4 > 8GB, - * process of adding new ATA4 compliance. - * fixed problems in allowing fdisk to see - * the entire disk. - * Version 1.09 added increment of rq->sector in ide_multwrite - * added UDMA 3/4 reporting - * Version 1.10 request queue changes, Ultra DMA 100 - * Version 1.11 added 48-bit lba - * Version 1.12 adding taskfile io access method - * Version 1.13 added standby and flush-cache for notifier - * Version 1.14 added acoustic-wcache - * Version 1.15 convert all calls to ide_raw_taskfile - * since args will return register content. - * Version 1.16 added suspend-resume-checkpower - * Version 1.17 do flush on standby, do flush on ATA < ATA6 - * fix wcache setup. */ #define IDEDISK_VERSION "1.18" @@ -961,11 +935,8 @@ static void idedisk_setup (ide_drive_t *drive) if (id->buf_size) printk (" w/%dKiB Cache", id->buf_size/2); - printk(", CHS=%d/%d/%d", - drive->bios_cyl, drive->bios_head, drive->bios_sect); - if (drive->using_dma) - ide_dma_verbose(drive); - printk("\n"); + printk(KERN_CONT ", CHS=%d/%d/%d\n", + drive->bios_cyl, drive->bios_head, drive->bios_sect); /* write cache enabled? */ if ((id->csfo & 1) || (id->cfs_enable_1 & (1 << 5))) diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c index 0d795a1..4703837 100644 --- a/drivers/ide/ide-dma.c +++ b/drivers/ide/ide-dma.c @@ -611,12 +611,6 @@ static int __ide_dma_test_irq(ide_drive_t *drive) ide_hwif_t *hwif = HWIF(drive); u8 dma_stat = hwif->INB(hwif->dma_status); -#if 0 /* do not set unless you know what you are doing */ - if (dma_stat & 4) { - u8 stat = hwif->INB(IDE_STATUS_REG); - hwif->OUTB(hwif->dma_status, dma_stat & 0xE4); - } -#endif /* return 1 if INTR asserted */ if ((dma_stat & 4) == 4) return 1; @@ -753,10 +747,12 @@ u8 ide_find_dma_mode(ide_drive_t *drive, u8 req_mode) mode = XFER_MW_DMA_1; } - printk(KERN_DEBUG "%s: %s mode selected\n", drive->name, + mode = min(mode, req_mode); + + printk(KERN_INFO "%s: %s mode selected\n", drive->name, mode ? ide_xfer_verbose(mode) : "no DMA"); - return min(mode, req_mode); + return mode; } EXPORT_SYMBOL_GPL(ide_find_dma_mode); @@ -772,6 +768,9 @@ static int ide_tune_dma(ide_drive_t *drive) if (__ide_dma_bad_drive(drive)) return 0; + if (ide_id_dma_bug(drive)) + return 0; + if (drive->hwif->host_flags & IDE_HFLAG_TRUST_BIOS_FOR_DMA) return config_drive_for_dma(drive); @@ -806,58 +805,23 @@ static int ide_dma_check(ide_drive_t *drive) return vdma ? 0 : -1; } -void ide_dma_verbose(ide_drive_t *drive) +int ide_id_dma_bug(ide_drive_t *drive) { - struct hd_driveid *id = drive->id; - ide_hwif_t *hwif = HWIF(drive); + struct hd_driveid *id = drive->id; if (id->field_valid & 4) { if ((id->dma_ultra >> 8) && (id->dma_mword >> 8)) - goto bug_dma_off; - if (id->dma_ultra & ((id->dma_ultra >> 8) & hwif->ultra_mask)) { - if (((id->dma_ultra >> 11) & 0x1F) && - eighty_ninty_three(drive)) { - if ((id->dma_ultra >> 15) & 1) { - printk(", UDMA(mode 7)"); - } else if ((id->dma_ultra >> 14) & 1) { - printk(", UDMA(133)"); - } else if ((id->dma_ultra >> 13) & 1) { - printk(", UDMA(100)"); - } else if ((id->dma_ultra >> 12) & 1) { - printk(", UDMA(66)"); - } else if ((id->dma_ultra >> 11) & 1) { - printk(", UDMA(44)"); - } else - goto mode_two; - } else { - mode_two: - if ((id->dma_ultra >> 10) & 1) { - printk(", UDMA(33)"); - } else if ((id->dma_ultra >> 9) & 1) { - printk(", UDMA(25)"); - } else if ((id->dma_ultra >> 8) & 1) { - printk(", UDMA(16)"); - } - } - } else { - printk(", (U)DMA"); /* Can be BIOS-enabled! */ - } + goto err_out; } else if (id->field_valid & 2) { if ((id->dma_mword >> 8) && (id->dma_1word >> 8)) - goto bug_dma_off; - printk(", DMA"); - } else if (id->field_valid & 1) { - goto bug_dma_off; + goto err_out; } - return; -bug_dma_off: - printk(", BUG DMA OFF"); - hwif->dma_off_quietly(drive); - return; + return 0; +err_out: + printk(KERN_ERR "%s: bad DMA info in identify block\n", drive->name); + return 1; } -EXPORT_SYMBOL(ide_dma_verbose); - int ide_set_dma(ide_drive_t *drive) { ide_hwif_t *hwif = drive->hwif; diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index db22d1f..bef781f 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c @@ -970,7 +970,8 @@ static void ide_check_pm_state(ide_drive_t *drive, struct request *rq) if (rc) printk(KERN_WARNING "%s: bus not ready on wakeup\n", drive->name); SELECT_DRIVE(drive); - HWIF(drive)->OUTB(8, HWIF(drive)->io_ports[IDE_CONTROL_OFFSET]); + if (IDE_CONTROL_REG) + HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG); rc = ide_wait_not_busy(HWIF(drive), 100000); if (rc) printk(KERN_WARNING "%s: drive not ready on wakeup\n", drive->name); diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c index 5c32561..cef405d 100644 --- a/drivers/ide/ide-iops.c +++ b/drivers/ide/ide-iops.c @@ -748,6 +748,9 @@ int ide_driveid_update(ide_drive_t *drive) drive->id->dma_1word = id->dma_1word; /* anything more ? */ kfree(id); + + if (drive->using_dma && ide_id_dma_bug(drive)) + ide_dma_off(drive); } return 1; diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c index 1609b86..062d3bc 100644 --- a/drivers/ide/ide-lib.c +++ b/drivers/ide/ide-lib.c @@ -29,41 +29,44 @@ * Add common non I/O op stuff here. Make sure it has proper * kernel-doc function headers or your patch will be rejected */ - + +static const char *udma_str[] = + { "UDMA/16", "UDMA/25", "UDMA/33", "UDMA/44", + "UDMA/66", "UDMA/100", "UDMA/133", "UDMA7" }; +static const char *mwdma_str[] = + { "MWDMA0", "MWDMA1", "MWDMA2" }; +static const char *swdma_str[] = + { "SWDMA0", "SWDMA1", "SWDMA2" }; +static const char *pio_str[] = + { "PIO0", "PIO1", "PIO2", "PIO3", "PIO4", "PIO5" }; /** * ide_xfer_verbose - return IDE mode names - * @xfer_rate: rate to name + * @mode: transfer mode * * Returns a constant string giving the name of the mode * requested. */ -char *ide_xfer_verbose (u8 xfer_rate) +const char *ide_xfer_verbose(u8 mode) { - switch(xfer_rate) { - case XFER_UDMA_7: return("UDMA 7"); - case XFER_UDMA_6: return("UDMA 6"); - case XFER_UDMA_5: return("UDMA 5"); - case XFER_UDMA_4: return("UDMA 4"); - case XFER_UDMA_3: return("UDMA 3"); - case XFER_UDMA_2: return("UDMA 2"); - case XFER_UDMA_1: return("UDMA 1"); - case XFER_UDMA_0: return("UDMA 0"); - case XFER_MW_DMA_2: return("MW DMA 2"); - case XFER_MW_DMA_1: return("MW DMA 1"); - case XFER_MW_DMA_0: return("MW DMA 0"); - case XFER_SW_DMA_2: return("SW DMA 2"); - case XFER_SW_DMA_1: return("SW DMA 1"); - case XFER_SW_DMA_0: return("SW DMA 0"); - case XFER_PIO_4: return("PIO 4"); - case XFER_PIO_3: return("PIO 3"); - case XFER_PIO_2: return("PIO 2"); - case XFER_PIO_1: return("PIO 1"); - case XFER_PIO_0: return("PIO 0"); - case XFER_PIO_SLOW: return("PIO SLOW"); - default: return("XFER ERROR"); - } + const char *s; + u8 i = mode & 0xf; + + if (mode >= XFER_UDMA_0 && mode <= XFER_UDMA_7) + s = udma_str[i]; + else if (mode >= XFER_MW_DMA_0 && mode <= XFER_MW_DMA_2) + s = mwdma_str[i]; + else if (mode >= XFER_SW_DMA_0 && mode <= XFER_SW_DMA_2) + s = swdma_str[i]; + else if (mode >= XFER_PIO_0 && mode <= XFER_PIO_5) + s = pio_str[i & 0x7]; + else if (mode == XFER_PIO_SLOW) + s = "PIO SLOW"; + else + s = "XFER ERROR"; + + return s; } EXPORT_SYMBOL(ide_xfer_verbose); diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index ee848c7..2994523 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -13,22 +13,8 @@ * * This is the IDE probe module, as evolved from hd.c and ide.c. * - * Version 1.00 move drive probing code from ide.c to ide-probe.c - * Version 1.01 fix compilation problem for m68k - * Version 1.02 increase WAIT_PIDENTIFY to avoid CD-ROM locking at boot - * by Andrea Arcangeli - * Version 1.03 fix for (hwif->chipset == ide_4drives) - * Version 1.04 fixed buggy treatments of known flash memory cards - * - * Version 1.05 fix for (hwif->chipset == ide_pdc4030) - * added ide6/7/8/9 - * allowed for secondary flash card to be detectable - * with new flag : drive->ata_flash : 1; - * Version 1.06 stream line request queue and prep for cascade project. - * Version 1.07 max_sect <= 255; slower disks would get behind and - * then fall over when they get to 256. Paul G. - * Version 1.10 Update set for new IDE. drive->id is now always - * valid after probe time even with noprobe + * -- increase WAIT_PIDENTIFY to avoid CD-ROM locking at boot + * by Andrea Arcangeli */ #include <linux/module.h> @@ -667,7 +653,8 @@ static int wait_hwif_ready(ide_hwif_t *hwif) /* Ignore disks that we will not probe for later. */ if (!drive->noprobe || drive->present) { SELECT_DRIVE(drive); - hwif->OUTB(8, hwif->io_ports[IDE_CONTROL_OFFSET]); + if (IDE_CONTROL_REG) + hwif->OUTB(drive->ctl, IDE_CONTROL_REG); mdelay(2); rc = ide_wait_not_busy(hwif, 35000); if (rc) diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index 674a65c..54943da 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -800,11 +800,17 @@ int set_io_32bit(ide_drive_t *drive, int arg) if (arg < 0 || arg > 1 + (SUPPORT_VLB_SYNC << 1)) return -EINVAL; + if (ide_spin_wait_hwgroup(drive)) + return -EBUSY; + drive->io_32bit = arg; #ifdef CONFIG_BLK_DEV_DTC2278 if (HWIF(drive)->chipset == ide_dtc2278) HWIF(drive)->drives[!drive->select.b.unit].io_32bit = arg; #endif /* CONFIG_BLK_DEV_DTC2278 */ + + spin_unlock_irq(&ide_lock); + return 0; } @@ -1670,10 +1676,34 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, return sprintf(buf, "ide:m-%s\n", media_string(drive)); } +static ssize_t model_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + ide_drive_t *drive = to_ide_device(dev); + return sprintf(buf, "%s\n", drive->id->model); +} + +static ssize_t firmware_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + ide_drive_t *drive = to_ide_device(dev); + return sprintf(buf, "%s\n", drive->id->fw_rev); +} + +static ssize_t serial_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + ide_drive_t *drive = to_ide_device(dev); + return sprintf(buf, "%s\n", drive->id->serial_no); +} + static struct device_attribute ide_dev_attrs[] = { __ATTR_RO(media), __ATTR_RO(drivename), __ATTR_RO(modalias), + __ATTR_RO(model), + __ATTR_RO(firmware), + __ATTR(serial, 0400, serial_show, NULL), __ATTR_NULL }; diff --git a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c index 5682895..9fce25b 100644 --- a/drivers/ide/pci/hpt366.c +++ b/drivers/ide/pci/hpt366.c @@ -1,5 +1,5 @@ /* - * linux/drivers/ide/pci/hpt366.c Version 1.21 Oct 23, 2007 + * linux/drivers/ide/pci/hpt366.c Version 1.22 Dec 4, 2007 * * Copyright (C) 1999-2003 Andre Hedrick <andre@linux-ide.org> * Portions Copyright (C) 2001 Sun Microsystems, Inc. @@ -310,6 +310,8 @@ static u32 twenty_five_base_hpt36x[] = { /* XFER_PIO_0 */ 0xc0d08585 }; +#if 0 +/* These are the timing tables from the HighPoint open source drivers... */ static u32 thirty_three_base_hpt37x[] = { /* XFER_UDMA_6 */ 0x12446231, /* 0x12646231 ?? */ /* XFER_UDMA_5 */ 0x12446231, @@ -369,6 +371,73 @@ static u32 sixty_six_base_hpt37x[] = { /* XFER_PIO_1 */ 0x0d029d26, /* XFER_PIO_0 */ 0x0d029d5e }; +#else +/* + * The following are the new timing tables with PIO mode data/taskfile transfer + * overclocking fixed... + */ + +/* This table is taken from the HPT370 data manual rev. 1.02 */ +static u32 thirty_three_base_hpt37x[] = { + /* XFER_UDMA_6 */ 0x16455031, /* 0x16655031 ?? */ + /* XFER_UDMA_5 */ 0x16455031, + /* XFER_UDMA_4 */ 0x16455031, + /* XFER_UDMA_3 */ 0x166d5031, + /* XFER_UDMA_2 */ 0x16495031, + /* XFER_UDMA_1 */ 0x164d5033, + /* XFER_UDMA_0 */ 0x16515097, + + /* XFER_MW_DMA_2 */ 0x26515031, + /* XFER_MW_DMA_1 */ 0x26515033, + /* XFER_MW_DMA_0 */ 0x26515097, + + /* XFER_PIO_4 */ 0x06515021, + /* XFER_PIO_3 */ 0x06515022, + /* XFER_PIO_2 */ 0x06515033, + /* XFER_PIO_1 */ 0x06915065, + /* XFER_PIO_0 */ 0x06d1508a +}; + +static u32 fifty_base_hpt37x[] = { + /* XFER_UDMA_6 */ 0x1a861842, + /* XFER_UDMA_5 */ 0x1a861842, + /* XFER_UDMA_4 */ 0x1aae1842, + /* XFER_UDMA_3 */ 0x1a8e1842, + /* XFER_UDMA_2 */ 0x1a0e1842, + /* XFER_UDMA_1 */ 0x1a161854, + /* XFER_UDMA_0 */ 0x1a1a18ea, + + /* XFER_MW_DMA_2 */ 0x2a821842, + /* XFER_MW_DMA_1 */ 0x2a821854, + /* XFER_MW_DMA_0 */ 0x2a8218ea, + + /* XFER_PIO_4 */ 0x0a821842, + /* XFER_PIO_3 */ 0x0a821843, + /* XFER_PIO_2 */ 0x0a821855, + /* XFER_PIO_1 */ 0x0ac218a8, + /* XFER_PIO_0 */ 0x0b02190c +}; + +static u32 sixty_six_base_hpt37x[] = { + /* XFER_UDMA_6 */ 0x1c86fe62, + /* XFER_UDMA_5 */ 0x1caefe62, /* 0x1c8afe62 */ + /* XFER_UDMA_4 */ 0x1c8afe62, + /* XFER_UDMA_3 */ 0x1c8efe62, + /* XFER_UDMA_2 */ 0x1c92fe62, + /* XFER_UDMA_1 */ 0x1c9afe62, + /* XFER_UDMA_0 */ 0x1c82fe62, + + /* XFER_MW_DMA_2 */ 0x2c82fe62, + /* XFER_MW_DMA_1 */ 0x2c82fe66, + /* XFER_MW_DMA_0 */ 0x2c82ff2e, + + /* XFER_PIO_4 */ 0x0c82fe62, + /* XFER_PIO_3 */ 0x0c82fe84, + /* XFER_PIO_2 */ 0x0c82fea6, + /* XFER_PIO_1 */ 0x0d02ff26, + /* XFER_PIO_0 */ 0x0d42ff7f +}; +#endif #define HPT366_DEBUG_DRIVE_INFO 0 #define HPT371_ALLOW_ATA133_6 1 diff --git a/drivers/ide/pci/pdc202xx_new.c b/drivers/ide/pci/pdc202xx_new.c index 4234efe..2b4f44e 100644 --- a/drivers/ide/pci/pdc202xx_new.c +++ b/drivers/ide/pci/pdc202xx_new.c @@ -482,8 +482,9 @@ static struct pci_dev * __devinit pdc20270_get_dev2(struct pci_dev *dev) { struct pci_dev *dev2; - dev2 = pci_get_slot(dev->bus, PCI_DEVFN(PCI_SLOT(dev->devfn) + 2, + dev2 = pci_get_slot(dev->bus, PCI_DEVFN(PCI_SLOT(dev->devfn) + 1, PCI_FUNC(dev->devfn))); + if (dev2 && dev2->vendor == dev->vendor && dev2->device == dev->device) { diff --git a/drivers/ide/setup-pci.c b/drivers/ide/setup-pci.c index 25fd090..d2cd5a3 100644 --- a/drivers/ide/setup-pci.c +++ b/drivers/ide/setup-pci.c @@ -704,7 +704,7 @@ EXPORT_SYMBOL_GPL(ide_setup_pci_devices); /* * Module interfaces */ - + static int pre_init = 1; /* Before first ordered IDE scan */ static LIST_HEAD(ide_pci_drivers); @@ -714,7 +714,7 @@ static LIST_HEAD(ide_pci_drivers); * @module: owner module of the driver * * Registers a driver with the IDE layer. The IDE layer arranges that - * boot time setup is done in the expected device order and then + * boot time setup is done in the expected device order and then * hands the controllers off to the core PCI code to do the rest of * the work. * @@ -724,13 +724,12 @@ static LIST_HEAD(ide_pci_drivers); int __ide_pci_register_driver(struct pci_driver *driver, struct module *module, const char *mod_name) { - if(!pre_init) + if (!pre_init) return __pci_register_driver(driver, module, mod_name); driver->driver.owner = module; list_add_tail(&driver->node, &ide_pci_drivers); return 0; } - EXPORT_SYMBOL_GPL(__ide_pci_register_driver); /** @@ -741,17 +740,18 @@ EXPORT_SYMBOL_GPL(__ide_pci_register_driver); * This is only used during boot up to get the ordering correct. After * boot up the pci layer takes over the job. */ - + static int __init ide_scan_pcidev(struct pci_dev *dev) { struct list_head *l; struct pci_driver *d; - + list_for_each(l, &ide_pci_drivers) { d = list_entry(l, struct pci_driver, node); if (d->id_table) { - const struct pci_device_id *id = pci_match_id(d->id_table, - dev); + const struct pci_device_id *id = + pci_match_id(d->id_table, dev); + if (id != NULL && d->probe(dev, id) >= 0) { dev->driver = d; pci_dev_get(dev); @@ -779,13 +779,13 @@ void __init ide_scan_pcibus (int scan_direction) pre_init = 0; if (!scan_direction) - while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) + while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev))) ide_scan_pcidev(dev); else - while ((dev = pci_get_device_reverse(PCI_ANY_ID, PCI_ANY_ID, dev)) - != NULL) + while ((dev = pci_get_device_reverse(PCI_ANY_ID, PCI_ANY_ID, + dev))) ide_scan_pcidev(dev); - + /* * Hand the drivers over to the PCI layer now we * are post init. @@ -794,9 +794,10 @@ void __init ide_scan_pcibus (int scan_direction) list_for_each_safe(l, n, &ide_pci_drivers) { list_del(l); d = list_entry(l, struct pci_driver, node); - if (__pci_register_driver(d, d->driver.owner, d->driver.mod_name)) - printk(KERN_ERR "%s: failed to register driver for %s\n", - __FUNCTION__, d->driver.mod_name); + if (__pci_register_driver(d, d->driver.owner, + d->driver.mod_name)) + printk(KERN_ERR "%s: failed to register %s driver\n", + __FUNCTION__, d->driver.mod_name); } } #endif diff --git a/drivers/infiniband/hw/ehca/ehca_classes.h b/drivers/infiniband/hw/ehca/ehca_classes.h index 87f12d4..74d2b72 100644 --- a/drivers/infiniband/hw/ehca/ehca_classes.h +++ b/drivers/infiniband/hw/ehca/ehca_classes.h @@ -322,6 +322,7 @@ extern int ehca_static_rate; extern int ehca_port_act_time; extern int ehca_use_hp_mr; extern int ehca_scaling_code; +extern int ehca_lock_hcalls; struct ipzu_queue_resp { u32 qe_size; /* queue entry size */ diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c index 90d4334..6a56d86 100644 --- a/drivers/infiniband/hw/ehca/ehca_main.c +++ b/drivers/infiniband/hw/ehca/ehca_main.c @@ -43,13 +43,14 @@ #ifdef CONFIG_PPC_64K_PAGES #include <linux/slab.h> #endif + #include "ehca_classes.h" #include "ehca_iverbs.h" #include "ehca_mrmw.h" #include "ehca_tools.h" #include "hcp_if.h" -#define HCAD_VERSION "0024" +#define HCAD_VERSION "0025" MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("Christoph Raisch <raisch@de.ibm.com>"); @@ -66,6 +67,7 @@ int ehca_poll_all_eqs = 1; int ehca_static_rate = -1; int ehca_scaling_code = 0; int ehca_mr_largepage = 1; +int ehca_lock_hcalls = -1; module_param_named(open_aqp1, ehca_open_aqp1, int, S_IRUGO); module_param_named(debug_level, ehca_debug_level, int, S_IRUGO); @@ -77,6 +79,7 @@ module_param_named(poll_all_eqs, ehca_poll_all_eqs, int, S_IRUGO); module_param_named(static_rate, ehca_static_rate, int, S_IRUGO); module_param_named(scaling_code, ehca_scaling_code, int, S_IRUGO); module_param_named(mr_largepage, ehca_mr_largepage, int, S_IRUGO); +module_param_named(lock_hcalls, ehca_lock_hcalls, bool, S_IRUGO); MODULE_PARM_DESC(open_aqp1, "AQP1 on startup (0: no (default), 1: yes)"); @@ -102,6 +105,9 @@ MODULE_PARM_DESC(scaling_code, MODULE_PARM_DESC(mr_largepage, "use large page for MR (0: use PAGE_SIZE (default), " "1: use large page depending on MR size"); +MODULE_PARM_DESC(lock_hcalls, + "serialize all hCalls made by the driver " + "(default: autodetect)"); DEFINE_RWLOCK(ehca_qp_idr_lock); DEFINE_RWLOCK(ehca_cq_idr_lock); @@ -258,6 +264,7 @@ static struct cap_descr { { HCA_CAP_UD_LL_QP, "HCA_CAP_UD_LL_QP" }, { HCA_CAP_RESIZE_MR, "HCA_CAP_RESIZE_MR" }, { HCA_CAP_MINI_QP, "HCA_CAP_MINI_QP" }, + { HCA_CAP_H_ALLOC_RES_SYNC, "HCA_CAP_H_ALLOC_RES_SYNC" }, }; static int ehca_sense_attributes(struct ehca_shca *shca) @@ -333,6 +340,12 @@ static int ehca_sense_attributes(struct ehca_shca *shca) if (EHCA_BMASK_GET(hca_cap_descr[i].mask, shca->hca_cap)) ehca_gen_dbg(" %s", hca_cap_descr[i].descr); + /* Autodetect hCall locking -- the "H_ALLOC_RESOURCE synced" flag is + * a firmware property, so it's valid across all adapters + */ + if (ehca_lock_hcalls == -1) + ehca_lock_hcalls = !(shca->hca_cap & HCA_CAP_H_ALLOC_RES_SYNC); + /* translate supported MR page sizes; always support 4K */ shca->hca_cap_mr_pgsize = EHCA_PAGESIZE; if (ehca_mr_largepage) { /* support extra sizes only if enabled */ diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c index dd12668..eff5fb5 100644 --- a/drivers/infiniband/hw/ehca/ehca_qp.c +++ b/drivers/infiniband/hw/ehca/ehca_qp.c @@ -838,7 +838,7 @@ struct ib_srq *ehca_create_srq(struct ib_pd *pd, /* copy back return values */ srq_init_attr->attr.max_wr = qp_init_attr.cap.max_recv_wr; - srq_init_attr->attr.max_sge = qp_init_attr.cap.max_recv_sge; + srq_init_attr->attr.max_sge = 3; /* drive SRQ into RTR state */ mqpcb = ehca_alloc_fw_ctrlblock(GFP_KERNEL); @@ -1750,7 +1750,7 @@ int ehca_query_srq(struct ib_srq *srq, struct ib_srq_attr *srq_attr) } srq_attr->max_wr = qpcb->max_nr_outst_recv_wr - 1; - srq_attr->max_sge = qpcb->actual_nr_sges_in_rq_wqe; + srq_attr->max_sge = 3; srq_attr->srq_limit = EHCA_BMASK_GET( MQPCB_CURR_SRQ_LIMIT, qpcb->curr_srq_limit); diff --git a/drivers/infiniband/hw/ehca/hcp_if.c b/drivers/infiniband/hw/ehca/hcp_if.c index c16a213..7029aa6 100644 --- a/drivers/infiniband/hw/ehca/hcp_if.c +++ b/drivers/infiniband/hw/ehca/hcp_if.c @@ -120,26 +120,21 @@ static long ehca_plpar_hcall_norets(unsigned long opcode, unsigned long arg7) { long ret; - int i, sleep_msecs, do_lock; - unsigned long flags; + int i, sleep_msecs; + unsigned long flags = 0; ehca_gen_dbg("opcode=%lx " HCALL7_REGS_FORMAT, opcode, arg1, arg2, arg3, arg4, arg5, arg6, arg7); - /* lock H_FREE_RESOURCE(MR) against itself and H_ALLOC_RESOURCE(MR) */ - if ((opcode == H_FREE_RESOURCE) && (arg7 == 5)) { - arg7 = 0; /* better not upset firmware */ - do_lock = 1; - } - for (i = 0; i < 5; i++) { - if (do_lock) + /* serialize hCalls to work around firmware issue */ + if (ehca_lock_hcalls) spin_lock_irqsave(&hcall_lock, flags); ret = plpar_hcall_norets(opcode, arg1, arg2, arg3, arg4, arg5, arg6, arg7); - if (do_lock) + if (ehca_lock_hcalls) spin_unlock_irqrestore(&hcall_lock, flags); if (H_IS_LONG_BUSY(ret)) { @@ -174,24 +169,22 @@ static long ehca_plpar_hcall9(unsigned long opcode, unsigned long arg9) { long ret; - int i, sleep_msecs, do_lock; + int i, sleep_msecs; unsigned long flags = 0; ehca_gen_dbg("INPUT -- opcode=%lx " HCALL9_REGS_FORMAT, opcode, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); - /* lock H_ALLOC_RESOURCE(MR) against itself and H_FREE_RESOURCE(MR) */ - do_lock = ((opcode == H_ALLOC_RESOURCE) && (arg2 == 5)); - for (i = 0; i < 5; i++) { - if (do_lock) + /* serialize hCalls to work around firmware issue */ + if (ehca_lock_hcalls) spin_lock_irqsave(&hcall_lock, flags); ret = plpar_hcall9(opcode, outs, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); - if (do_lock) + if (ehca_lock_hcalls) spin_unlock_irqrestore(&hcall_lock, flags); if (H_IS_LONG_BUSY(ret)) { @@ -821,7 +814,7 @@ u64 hipz_h_free_resource_mr(const struct ipz_adapter_handle adapter_handle, return ehca_plpar_hcall_norets(H_FREE_RESOURCE, adapter_handle.handle, /* r4 */ mr->ipz_mr_handle.handle, /* r5 */ - 0, 0, 0, 0, 5); + 0, 0, 0, 0, 0); } u64 hipz_h_reregister_pmr(const struct ipz_adapter_handle adapter_handle, diff --git a/drivers/infiniband/hw/ehca/hipz_hw.h b/drivers/infiniband/hw/ehca/hipz_hw.h index 485b840..bf996c7 100644 --- a/drivers/infiniband/hw/ehca/hipz_hw.h +++ b/drivers/infiniband/hw/ehca/hipz_hw.h @@ -378,6 +378,7 @@ struct hipz_query_hca { #define HCA_CAP_UD_LL_QP EHCA_BMASK_IBM(16, 16) #define HCA_CAP_RESIZE_MR EHCA_BMASK_IBM(17, 17) #define HCA_CAP_MINI_QP EHCA_BMASK_IBM(18, 18) +#define HCA_CAP_H_ALLOC_RES_SYNC EHCA_BMASK_IBM(19, 19) /* query port response block */ struct hipz_query_port { diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index dc741d3..6123c70 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -2336,6 +2336,7 @@ powerbook_sleep_3400(void) ret = pmac_suspend_devices(); if (ret) { pbook_free_pci_save(); + iounmap(mem_ctrl); printk(KERN_ERR "Sleep rejected by devices\n"); return ret; } diff --git a/drivers/media/Makefile b/drivers/media/Makefile index 8fa1993..8cf9135 100644 --- a/drivers/media/Makefile +++ b/drivers/media/Makefile @@ -3,6 +3,6 @@ # obj-y := common/ -obj-$(CONFIG_VIDEO_DEV) += video/ +obj-y += video/ obj-$(CONFIG_VIDEO_DEV) += radio/ obj-$(CONFIG_DVB_CORE) += dvb/ diff --git a/drivers/media/dvb/frontends/s5h1409.c b/drivers/media/dvb/frontends/s5h1409.c index 8dee7ec..562d920 100644 --- a/drivers/media/dvb/frontends/s5h1409.c +++ b/drivers/media/dvb/frontends/s5h1409.c @@ -107,7 +107,7 @@ static struct vsb_snr_tab { u16 val; u16 data; } vsb_snr_tab[] = { - { 1023, 770, }, + { 924, 300, }, { 923, 300, }, { 918, 295, }, { 915, 290, }, @@ -154,6 +154,7 @@ static struct qam64_snr_tab { u16 val; u16 data; } qam64_snr_tab[] = { + { 1, 0, }, { 12, 300, }, { 15, 290, }, { 18, 280, }, @@ -217,6 +218,7 @@ static struct qam64_snr_tab { { 95, 202, }, { 96, 201, }, { 104, 200, }, + { 255, 0, }, }; /* QAM256 SNR lookup table */ @@ -224,6 +226,7 @@ static struct qam256_snr_tab { u16 val; u16 data; } qam256_snr_tab[] = { + { 1, 0, }, { 12, 400, }, { 13, 390, }, { 15, 380, }, @@ -292,6 +295,7 @@ static struct qam256_snr_tab { { 105, 262, }, { 106, 261, }, { 110, 260, }, + { 255, 0, }, }; /* 8 bit registers, 16 bit values */ @@ -670,14 +674,15 @@ static int s5h1409_read_snr(struct dvb_frontend* fe, u16* snr) u16 reg; dprintk("%s()\n", __FUNCTION__); - reg = s5h1409_readreg(state, 0xf1) & 0x1ff; - switch(state->current_modulation) { case QAM_64: + reg = s5h1409_readreg(state, 0xf0) & 0xff; return s5h1409_qam64_lookup_snr(fe, snr, reg); case QAM_256: + reg = s5h1409_readreg(state, 0xf0) & 0xff; return s5h1409_qam256_lookup_snr(fe, snr, reg); case VSB_8: + reg = s5h1409_readreg(state, 0xf1) & 0x3ff; return s5h1409_vsb_lookup_snr(fe, snr, reg); default: break; diff --git a/drivers/media/video/bt866.c b/drivers/media/video/bt866.c index b767b09..96b4155 100644 --- a/drivers/media/video/bt866.c +++ b/drivers/media/video/bt866.c @@ -300,7 +300,6 @@ static struct i2c_client bt866_client_tmpl = .addr = 0, .adapter = NULL, .driver = &i2c_driver_bt866, - .usage_count = 0 }; static int bt866_found_proc(struct i2c_adapter *adapter, diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index c6eb1e3..98c1b08 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -3221,6 +3221,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, + .tuner_config = 1, .mpeg = SAA7134_MPEG_DVB, .inputs = {{ .name = name_tv, diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c index 81f77d2..c8a5cb5 100644 --- a/drivers/media/video/videobuf-core.c +++ b/drivers/media/video/videobuf-core.c @@ -909,7 +909,7 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q, if (q->streaming) goto done; if (!q->reading) { - retval = videobuf_read_start(q); + retval = __videobuf_read_start(q); if (retval < 0) goto done; } @@ -982,7 +982,7 @@ unsigned int videobuf_poll_stream(struct file *file, struct videobuf_buffer, stream); } else { if (!q->reading) - videobuf_read_start(q); + __videobuf_read_start(q); if (!q->reading) { rc = POLLERR; } else if (NULL == q->read_buf) { diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index ab23a32..cf56647 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -987,9 +987,9 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) KEY_UNKNOWN, /* 0x0C: FN+BACKSPACE */ KEY_UNKNOWN, /* 0x0D: FN+INSERT */ KEY_UNKNOWN, /* 0x0E: FN+DELETE */ - KEY_BRIGHTNESSUP, /* 0x0F: FN+HOME (brightness up) */ + KEY_RESERVED, /* 0x0F: FN+HOME (brightness up) */ /* Scan codes 0x10 to 0x1F: Extended ACPI HKEY hot keys */ - KEY_BRIGHTNESSDOWN, /* 0x10: FN+END (brightness down) */ + KEY_RESERVED, /* 0x10: FN+END (brightness down) */ KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */ KEY_UNKNOWN, /* 0x12: FN+PGDOWN */ KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */ diff --git a/drivers/net/fs_enet/mac-scc.c b/drivers/net/fs_enet/mac-scc.c index 03134f4..48f2f30 100644 --- a/drivers/net/fs_enet/mac-scc.c +++ b/drivers/net/fs_enet/mac-scc.c @@ -158,7 +158,7 @@ static int setup_data(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); -#ifdef CONFIG_PPC_CPM_NEW_BINDING +#ifndef CONFIG_PPC_CPM_NEW_BINDING struct fs_platform_info *fpi = fep->fpi; fep->scc.idx = fs_get_scc_index(fpi->fs_no); diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c index c6355c0..9081234 100644 --- a/drivers/net/irda/irda-usb.c +++ b/drivers/net/irda/irda-usb.c @@ -1168,6 +1168,7 @@ static int stir421x_patch_device(struct irda_usb_cb *self) static int irda_usb_net_open(struct net_device *netdev) { struct irda_usb_cb *self; + unsigned long flags; char hwname[16]; int i; @@ -1177,13 +1178,16 @@ static int irda_usb_net_open(struct net_device *netdev) self = (struct irda_usb_cb *) netdev->priv; IRDA_ASSERT(self != NULL, return -1;); + spin_lock_irqsave(&self->lock, flags); /* Can only open the device if it's there */ if(!self->present) { + spin_unlock_irqrestore(&self->lock, flags); IRDA_WARNING("%s(), device not present!\n", __FUNCTION__); return -1; } if(self->needspatch) { + spin_unlock_irqrestore(&self->lock, flags); IRDA_WARNING("%s(), device needs patch\n", __FUNCTION__) ; return -EIO ; } @@ -1198,6 +1202,7 @@ static int irda_usb_net_open(struct net_device *netdev) /* To do *before* submitting Rx urbs and starting net Tx queue * Jean II */ self->netopen = 1; + spin_unlock_irqrestore(&self->lock, flags); /* * Now that everything should be initialized properly, diff --git a/drivers/net/irda/mcs7780.c b/drivers/net/irda/mcs7780.c index 0b76919..93916cf 100644 --- a/drivers/net/irda/mcs7780.c +++ b/drivers/net/irda/mcs7780.c @@ -677,6 +677,8 @@ static int mcs_net_close(struct net_device *netdev) /* Stop transmit processing */ netif_stop_queue(netdev); + kfree_skb(mcs->rx_buff.skb); + /* kill and free the receive and transmit URBs */ usb_kill_urb(mcs->rx_urb); usb_free_urb(mcs->rx_urb); diff --git a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c index 042bc2f..e59c485 100644 --- a/drivers/net/irda/stir4200.c +++ b/drivers/net/irda/stir4200.c @@ -142,9 +142,6 @@ enum StirCtrl2Mask { }; enum StirFifoCtlMask { - FIFOCTL_EOF = 0x80, - FIFOCTL_UNDER = 0x40, - FIFOCTL_OVER = 0x20, FIFOCTL_DIR = 0x10, FIFOCTL_CLR = 0x08, FIFOCTL_EMPTY = 0x04, @@ -594,9 +591,10 @@ static int fifo_txwait(struct stir_cb *stir, int space) { int err; unsigned long count, status; + unsigned long prev_count = 0x1fff; /* Read FIFO status and count */ - for(;;) { + for (;; prev_count = count) { err = read_reg(stir, REG_FIFOCTL, stir->fifo_status, FIFO_REGS_SIZE); if (unlikely(err != FIFO_REGS_SIZE)) { @@ -629,6 +627,10 @@ static int fifo_txwait(struct stir_cb *stir, int space) if (space >= 0 && STIR_FIFO_SIZE - 4 > space + count) return 0; + /* queue confused */ + if (prev_count < count) + break; + /* estimate transfer time for remaining chars */ msleep((count * 8000) / stir->speed); } diff --git a/drivers/net/wan/syncppp.c b/drivers/net/wan/syncppp.c index 232ecba..61e24b7 100644 --- a/drivers/net/wan/syncppp.c +++ b/drivers/net/wan/syncppp.c @@ -107,24 +107,24 @@ struct ppp_header { u8 address; u8 control; - u16 protocol; + __be16 protocol; }; #define PPP_HEADER_LEN sizeof (struct ppp_header) struct lcp_header { u8 type; u8 ident; - u16 len; + __be16 len; }; #define LCP_HEADER_LEN sizeof (struct lcp_header) struct cisco_packet { - u32 type; - u32 par1; - u32 par2; - u16 rel; - u16 time0; - u16 time1; + __be32 type; + __be32 par1; + __be32 par2; + __be16 rel; + __be16 time0; + __be16 time1; }; #define CISCO_PACKET_LEN 18 #define CISCO_BIG_PACKET_LEN 20 @@ -139,7 +139,7 @@ static struct sk_buff_head tx_queue; static void sppp_keepalive (unsigned long dummy); static void sppp_cp_send (struct sppp *sp, u16 proto, u8 type, u8 ident, u16 len, void *data); -static void sppp_cisco_send (struct sppp *sp, int type, long par1, long par2); +static void sppp_cisco_send (struct sppp *sp, int type, u32 par1, u32 par2); static void sppp_lcp_input (struct sppp *sp, struct sk_buff *m); static void sppp_cisco_input (struct sppp *sp, struct sk_buff *m); static void sppp_ipcp_input (struct sppp *sp, struct sk_buff *m); @@ -447,7 +447,7 @@ static void sppp_keepalive (unsigned long dummy) sppp_cisco_send (sp, CISCO_KEEPALIVE_REQ, ++sp->pp_seq, sp->pp_rseq); else if (sp->lcp.state == LCP_STATE_OPENED) { - long nmagic = htonl (sp->lcp.magic); + __be32 nmagic = htonl (sp->lcp.magic); sp->lcp.echoid = ++sp->pp_seq; sppp_cp_send (sp, PPP_LCP, LCP_ECHO_REQ, sp->lcp.echoid, 4, &nmagic); @@ -667,7 +667,7 @@ badreq: dev->name, len); break; } - if (ntohl (*(long*)(h+1)) == sp->lcp.magic) { + if (ntohl (*(__be32*)(h+1)) == sp->lcp.magic) { /* Line loopback mode detected. */ printk (KERN_WARNING "%s: loopback\n", dev->name); if_down (dev); @@ -680,7 +680,7 @@ badreq: sppp_lcp_open (sp); break; } - *(long*)(h+1) = htonl (sp->lcp.magic); + *(__be32 *)(h+1) = htonl (sp->lcp.magic); sppp_cp_send (sp, PPP_LCP, LCP_ECHO_REPLY, h->ident, len-4, h+1); break; case LCP_ECHO_REPLY: @@ -692,7 +692,7 @@ badreq: dev->name, len); break; } - if (ntohl (*(long*)(h+1)) != sp->lcp.magic) + if (ntohl(*(__be32 *)(h+1)) != sp->lcp.magic) sp->pp_alivecnt = 0; break; } @@ -765,7 +765,7 @@ static void sppp_cisco_input (struct sppp *sp, struct sk_buff *skb) { struct in_device *in_dev; struct in_ifaddr *ifa; - __be32 addr = 0, mask = ~0; /* FIXME: is the mask correct? */ + __be32 addr = 0, mask = htonl(~0U); /* FIXME: is the mask correct? */ #ifdef CONFIG_INET rcu_read_lock(); if ((in_dev = __in_dev_get_rcu(dev)) != NULL) @@ -782,8 +782,7 @@ static void sppp_cisco_input (struct sppp *sp, struct sk_buff *skb) } rcu_read_unlock(); #endif - /* I hope both addr and mask are in the net order */ - sppp_cisco_send (sp, CISCO_ADDR_REPLY, addr, mask); + sppp_cisco_send (sp, CISCO_ADDR_REPLY, ntohl(addr), ntohl(mask)); break; } } @@ -844,7 +843,7 @@ static void sppp_cp_send (struct sppp *sp, u16 proto, u8 type, * Send Cisco keepalive packet. */ -static void sppp_cisco_send (struct sppp *sp, int type, long par1, long par2) +static void sppp_cisco_send (struct sppp *sp, int type, u32 par1, u32 par2) { struct ppp_header *h; struct cisco_packet *ch; @@ -868,7 +867,7 @@ static void sppp_cisco_send (struct sppp *sp, int type, long par1, long par2) ch->type = htonl (type); ch->par1 = htonl (par1); ch->par2 = htonl (par2); - ch->rel = -1; + ch->rel = htons(0xffff); ch->time0 = htons ((u16) (t >> 16)); ch->time1 = htons ((u16) t); diff --git a/drivers/parport/procfs.c b/drivers/parport/procfs.c index ed82e41..d950fc3 100644 --- a/drivers/parport/procfs.c +++ b/drivers/parport/procfs.c @@ -384,7 +384,7 @@ parport_device_sysctl_template = { { .procname = "timeslice", .data = NULL, - .maxlen = sizeof(int), + .maxlen = sizeof(unsigned long), .mode = 0644, .proc_handler = &proc_doulongvec_ms_jiffies_minmax, .extra1 = (void*) &parport_min_timeslice_value, diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index c2f8a78..2f75d69 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -276,7 +276,8 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom) sz = pci_size(l, sz, (u32)PCI_ROM_ADDRESS_MASK); if (sz) { res->flags = (l & IORESOURCE_ROM_ENABLE) | - IORESOURCE_MEM | IORESOURCE_READONLY; + IORESOURCE_MEM | IORESOURCE_PREFETCH | + IORESOURCE_READONLY | IORESOURCE_CACHEABLE; res->start = l & PCI_ROM_ADDRESS_MASK; res->end = res->start + (unsigned long) sz; } diff --git a/drivers/rtc/rtc-at32ap700x.c b/drivers/rtc/rtc-at32ap700x.c index 2999214..d3b9b14 100644 --- a/drivers/rtc/rtc-at32ap700x.c +++ b/drivers/rtc/rtc-at32ap700x.c @@ -225,18 +225,12 @@ static int __init at32_rtc_probe(struct platform_device *pdev) goto out; } - ret = request_irq(irq, at32_rtc_interrupt, IRQF_SHARED, "rtc", rtc); - if (ret) { - dev_dbg(&pdev->dev, "could not request irq %d\n", irq); - goto out; - } - rtc->irq = irq; rtc->regs = ioremap(regs->start, regs->end - regs->start + 1); if (!rtc->regs) { ret = -ENOMEM; dev_dbg(&pdev->dev, "could not map I/O memory\n"); - goto out_free_irq; + goto out; } spin_lock_init(&rtc->lock); @@ -253,12 +247,18 @@ static int __init at32_rtc_probe(struct platform_device *pdev) | RTC_BIT(CTRL_EN)); } + ret = request_irq(irq, at32_rtc_interrupt, IRQF_SHARED, "rtc", rtc); + if (ret) { + dev_dbg(&pdev->dev, "could not request irq %d\n", irq); + goto out_iounmap; + } + rtc->rtc = rtc_device_register(pdev->name, &pdev->dev, &at32_rtc_ops, THIS_MODULE); if (IS_ERR(rtc->rtc)) { dev_dbg(&pdev->dev, "could not register rtc device\n"); ret = PTR_ERR(rtc->rtc); - goto out_iounmap; + goto out_free_irq; } platform_set_drvdata(pdev, rtc); @@ -268,10 +268,10 @@ static int __init at32_rtc_probe(struct platform_device *pdev) return 0; -out_iounmap: - iounmap(rtc->regs); out_free_irq: free_irq(irq, rtc); +out_iounmap: + iounmap(rtc->regs); out: kfree(rtc); return ret; diff --git a/drivers/sbus/char/cpwatchdog.c b/drivers/sbus/char/cpwatchdog.c index 7b5773d..a4e7581 100644 --- a/drivers/sbus/char/cpwatchdog.c +++ b/drivers/sbus/char/cpwatchdog.c @@ -154,7 +154,7 @@ struct wd_device { }; static struct wd_device wd_dev = { - 0, SPIN_LOCK_UNLOCKED, 0, 0, 0, 0, + 0, __SPIN_LOCK_UNLOCKED(wd_dev.lock), 0, 0, 0, 0, }; static struct timer_list wd_timer; diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c index 7a835a3..9706de9 100644 --- a/drivers/scsi/ide-scsi.c +++ b/drivers/scsi/ide-scsi.c @@ -242,6 +242,11 @@ static void idescsi_output_buffers (ide_drive_t *drive, idescsi_pc_t *pc, unsign } } +static void ide_scsi_hex_dump(u8 *data, int len) +{ + print_hex_dump(KERN_CONT, "", DUMP_PREFIX_NONE, 16, 1, data, len, 0); +} + static int idescsi_check_condition(ide_drive_t *drive, struct request *failed_command) { idescsi_scsi_t *scsi = drive_to_idescsi(drive); @@ -272,8 +277,7 @@ static int idescsi_check_condition(ide_drive_t *drive, struct request *failed_co pc->scsi_cmd = ((idescsi_pc_t *) failed_command->special)->scsi_cmd; if (test_bit(IDESCSI_LOG_CMD, &scsi->log)) { printk ("ide-scsi: %s: queue cmd = ", drive->name); - print_hex_dump(KERN_CONT, "", DUMP_PREFIX_NONE, 16, 1, pc->c, - 6, 0); + ide_scsi_hex_dump(pc->c, 6); } rq->rq_disk = scsi->disk; return ide_do_drive_cmd(drive, rq, ide_preempt); @@ -328,8 +332,7 @@ static int idescsi_end_request (ide_drive_t *drive, int uptodate, int nrsecs) idescsi_pc_t *opc = (idescsi_pc_t *) rq->buffer; if (log) { printk ("ide-scsi: %s: wrap up check %lu, rst = ", drive->name, opc->scsi_cmd->serial_number); - print_hex_dump(KERN_CONT, "", DUMP_PREFIX_NONE, 16, 1, - pc->buffer, 16, 0); + ide_scsi_hex_dump(pc->buffer, 16); } memcpy((void *) opc->scsi_cmd->sense_buffer, pc->buffer, SCSI_SENSE_BUFFERSIZE); kfree(pc->buffer); @@ -808,12 +811,10 @@ static int idescsi_queue (struct scsi_cmnd *cmd, if (test_bit(IDESCSI_LOG_CMD, &scsi->log)) { printk ("ide-scsi: %s: que %lu, cmd = ", drive->name, cmd->serial_number); - print_hex_dump(KERN_CONT, "", DUMP_PREFIX_NONE, 16, 1, - cmd->cmnd, cmd->cmd_len, 0); + ide_scsi_hex_dump(cmd->cmnd, cmd->cmd_len); if (memcmp(pc->c, cmd->cmnd, cmd->cmd_len)) { printk ("ide-scsi: %s: que %lu, tsl = ", drive->name, cmd->serial_number); - print_hex_dump(KERN_CONT, "", DUMP_PREFIX_NONE, 16, 1, - pc->c, 12, 0); + ide_scsi_hex_dump(pc->c, 12); } } diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index 5cf6d5f..3fb9af8 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -125,7 +125,7 @@ int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id) pci_set_master (dev); - retval = usb_add_hcd (hcd, dev->irq, IRQF_SHARED); + retval = usb_add_hcd(hcd, dev->irq, IRQF_DISABLED | IRQF_SHARED); if (retval != 0) goto err4; return retval; diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 13b326a..b04d232 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -522,9 +522,9 @@ static void hub_quiesce(struct usb_hub *hub) /* (blocking) stop khubd and related activity */ usb_kill_urb(hub->urb); if (hub->has_indicators) - cancel_delayed_work(&hub->leds); - if (hub->has_indicators || hub->tt.hub) - flush_scheduled_work(); + cancel_delayed_work_sync(&hub->leds); + if (hub->tt.hub) + cancel_work_sync(&hub->tt.kevent); } static void hub_activate(struct usb_hub *hub) diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index a6adf7e..cd62b02 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -887,6 +887,7 @@ static void pullup(struct at91_udc *udc, int is_on) if (is_on) { clk_on(udc); + at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_RXRSM); at91_udp_write(udc, AT91_UDP_TXVC, 0); if (cpu_is_at91rm9200()) at91_set_gpio_value(udc->board.pullup_pin, 1); @@ -904,6 +905,7 @@ static void pullup(struct at91_udc *udc, int is_on) } } else { stop_activity(udc); + at91_udp_write(udc, AT91_UDP_IDR, AT91_UDP_RXRSM); at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS); if (cpu_is_at91rm9200()) at91_set_gpio_value(udc->board.pullup_pin, 0); diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index b7b7bfb..430821c 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -122,7 +122,7 @@ int usb_hcd_fsl_probe(const struct hc_driver *driver, temp = in_le32(hcd->regs + 0x1a8); out_le32(hcd->regs + 0x1a8, temp | 0x3); - retval = usb_add_hcd(hcd, irq, IRQF_SHARED); + retval = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED); if (retval != 0) goto err4; return retval; diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 704f33f..ecfe800 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -732,24 +732,27 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) struct ohci_regs __iomem *regs = ohci->regs; int ints; - /* we can eliminate a (slow) ohci_readl() - * if _only_ WDH caused this irq + /* Read interrupt status (and flush pending writes). We ignore the + * optimization of checking the LSB of hcca->done_head; it doesn't + * work on all systems (edge triggering for OHCI can be a factor). */ - if ((ohci->hcca->done_head != 0) - && ! (hc32_to_cpup (ohci, &ohci->hcca->done_head) - & 0x01)) { - ints = OHCI_INTR_WDH; + ints = ohci_readl(ohci, ®s->intrstatus); - /* cardbus/... hardware gone before remove() */ - } else if ((ints = ohci_readl (ohci, ®s->intrstatus)) == ~(u32)0) { + /* Check for an all 1's result which is a typical consequence + * of dead, unclocked, or unplugged (CardBus...) devices + */ + if (ints == ~(u32)0) { disable (ohci); ohci_dbg (ohci, "device removed!\n"); return IRQ_HANDLED; + } + + /* We only care about interrupts that are enabled */ + ints &= ohci_readl(ohci, ®s->intrenable); /* interrupt for some other device? */ - } else if ((ints &= ohci_readl (ohci, ®s->intrenable)) == 0) { + if (ints == 0) return IRQ_NOTMINE; - } if (ints & OHCI_INTR_UE) { // e.g. due to PCI Master/Target Abort diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c index 0a74269..0c3e6b7 100644 --- a/drivers/usb/host/ohci-ppc-of.c +++ b/drivers/usb/host/ohci-ppc-of.c @@ -142,7 +142,7 @@ ohci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match) ohci_hcd_init(ohci); - rv = usb_add_hcd(hcd, irq, 0); + rv = usb_add_hcd(hcd, irq, IRQF_DISABLED); if (rv == 0) return 0; diff --git a/drivers/usb/host/ohci-ssb.c b/drivers/usb/host/ohci-ssb.c index fe70e72..6e9c2d6 100644 --- a/drivers/usb/host/ohci-ssb.c +++ b/drivers/usb/host/ohci-ssb.c @@ -160,7 +160,7 @@ static int ssb_ohci_attach(struct ssb_device *dev) hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); if (!hcd->regs) goto err_put_hcd; - err = usb_add_hcd(hcd, dev->irq, IRQF_SHARED); + err = usb_add_hcd(hcd, dev->irq, IRQF_DISABLED | IRQF_SHARED); if (err) goto err_iounmap; diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index ae8ec44..0ce2fc5 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -2197,7 +2197,7 @@ static int __init r8a66597_probe(struct platform_device *pdev) INIT_LIST_HEAD(&r8a66597->child_device); hcd->rsrc_start = res->start; - ret = usb_add_hcd(hcd, irq, 0); + ret = usb_add_hcd(hcd, irq, IRQF_DISABLED); if (ret != 0) { err("Failed to add hcd"); goto clean_up; diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 4db17f7..ec98789 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -378,7 +378,6 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); unsigned short status; - unsigned long flags; /* * Read the interrupt status, and write it back to clear the @@ -398,7 +397,7 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd) dev_err(uhci_dev(uhci), "host controller process " "error, something bad happened!\n"); if (status & USBSTS_HCH) { - spin_lock_irqsave(&uhci->lock, flags); + spin_lock(&uhci->lock); if (uhci->rh_state >= UHCI_RH_RUNNING) { dev_err(uhci_dev(uhci), "host controller halted, " @@ -415,16 +414,16 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd) * pending unlinks */ mod_timer(&hcd->rh_timer, jiffies); } - spin_unlock_irqrestore(&uhci->lock, flags); + spin_unlock(&uhci->lock); } } if (status & USBSTS_RD) usb_hcd_poll_rh_status(hcd); else { - spin_lock_irqsave(&uhci->lock, flags); + spin_lock(&uhci->lock); uhci_scan_schedule(uhci); - spin_unlock_irqrestore(&uhci->lock, flags); + spin_unlock(&uhci->lock); } return IRQ_HANDLED; diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c index 3a83cb4..da16b51 100644 --- a/drivers/usb/serial/cp2101.c +++ b/drivers/usb/serial/cp2101.c @@ -71,6 +71,7 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(0x10C4, 0x815E) }, /* Helicomm IP-Link 1220-DVM */ { USB_DEVICE(0x10C4, 0x81C8) }, /* Lipowsky Industrie Elektronik GmbH, Baby-JTAG */ { USB_DEVICE(0x10C4, 0x81E2) }, /* Lipowsky Industrie Elektronik GmbH, Baby-LIN */ + { USB_DEVICE(0x10C4, 0x81E7) }, /* Aerocomm Radio */ { USB_DEVICE(0x10C4, 0x8218) }, /* Lipowsky Industrie Elektronik GmbH, HARP-1 */ { USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */ { USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */ @@ -98,8 +99,8 @@ static struct usb_serial_driver cp2101_device = { .usb_driver = &cp2101_driver, .id_table = id_table, .num_interrupt_in = 0, - .num_bulk_in = 0, - .num_bulk_out = 0, + .num_bulk_in = NUM_DONT_CARE, + .num_bulk_out = NUM_DONT_CARE, .num_ports = 1, .open = cp2101_open, .close = cp2101_close, diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 4590124..d1185f5 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -158,8 +158,8 @@ static struct usb_device_id option_ids[] = { { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_KOI_MODEM) }, { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_KOI_NETWORK) }, { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) }, - { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220) }, - { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220BIS) }, + { 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 */ diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index 605ebcc..e5c2740 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -100,6 +100,7 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */ { USB_DEVICE(0x0f30, 0x1b1d) }, /* Sierra Wireless MC5720 */ { USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */ + { USB_DEVICE(0x1199, 0x0220) }, /* Sierra Wireless MC5725 */ { USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */ { USB_DEVICE(0x1199, 0x0021) }, /* Sierra Wireless AirCard 597E */ { USB_DEVICE(0x1199, 0x0120) }, /* Sierra Wireless USB Dongle 595U */ @@ -137,7 +138,6 @@ static struct usb_device_id id_table_3port [] = { { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */ { USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */ { USB_DEVICE(0x1199, 0x0220) }, /* Sierra Wireless MC5725 */ - { USB_DEVICE(0x1199, 0x0220) }, /* Sierra Wireless MC5725 */ { USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */ { USB_DEVICE(0x1199, 0x0021) }, /* Sierra Wireless AirCard 597E */ { USB_DEVICE(0x1199, 0x0120) }, /* Sierra Wireless USB Dongle 595U*/ diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c index 836a34a..7c9593b 100644 --- a/drivers/usb/storage/scsiglue.c +++ b/drivers/usb/storage/scsiglue.c @@ -114,9 +114,15 @@ static int slave_configure(struct scsi_device *sdev) * while others have trouble with more than 64K. At this time we * are limiting both to 32K (64 sectores). */ - if ((us->flags & US_FL_MAX_SECTORS_64) && - sdev->request_queue->max_sectors > 64) - blk_queue_max_sectors(sdev->request_queue, 64); + if (us->flags & (US_FL_MAX_SECTORS_64 | US_FL_MAX_SECTORS_MIN)) { + unsigned int max_sectors = 64; + + if (us->flags & US_FL_MAX_SECTORS_MIN) + max_sectors = PAGE_CACHE_SIZE >> 9; + if (sdev->request_queue->max_sectors > max_sectors) + blk_queue_max_sectors(sdev->request_queue, + max_sectors); + } /* We can't put these settings in slave_alloc() because that gets * called before the device type is known. Consequently these diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 2c27721..6d6108b 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -376,6 +376,13 @@ UNUSUAL_DEV( 0x04b0, 0x0417, 0x0100, 0x0100, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_CAPACITY), +/* Reported by Doug Maxey (dwm@austin.ibm.com) */ +UNUSUAL_DEV( 0x04b3, 0x4001, 0x0110, 0x0110, + "IBM", + "IBM RSA2", + US_SC_DEVICE, US_PR_CB, NULL, + US_FL_MAX_SECTORS_MIN), + /* BENQ DC5330 * Reported by Manuel Fombuena <mfombuena@ya.com> and * Frank Copeland <fjc@thingy.apana.org.au> */ @@ -1258,14 +1265,6 @@ UNUSUAL_DEV( 0x0ace, 0x20ff, 0x0101, 0x0101, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_IGNORE_DEVICE ), -/* SanDisk that has a second LUN for a driver ISO, reported by - * Ben Collins <bcollins@ubuntu.com> */ -UNUSUAL_DEV( 0x0781, 0x5406, 0x0000, 0xffff, - "SanDisk", - "U3 Cruzer Micro driver ISO", - US_SC_DEVICE, US_PR_DEVICE, NULL, - US_FL_SINGLE_LUN ), - #ifdef CONFIG_USB_STORAGE_ISD200 UNUSUAL_DEV( 0x0bf6, 0xa001, 0x0100, 0x0110, "ATI", diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 2792bc1..52dff40 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -392,6 +392,16 @@ config ITCO_VENDOR_SUPPORT devices. At this moment we only have additional support for some SuperMicro Inc. motherboards. +config IT8712F_WDT + tristate "IT8712F (Smart Guardian) Watchdog Timer" + depends on X86 + ---help--- + This is the driver for the built-in watchdog timer on the IT8712F + Super I/0 chipset used on many motherboards. + + To compile this driver as a module, choose M here: the + module will be called it8712f_wdt. + config SC1200_WDT tristate "National Semiconductor PC87307/PC97307 (ala SC1200) Watchdog" depends on X86 @@ -456,6 +466,19 @@ config SBC8360_WDT Most people will say N. +config SBC7240_WDT + tristate "SBC Nano 7240 Watchdog Timer" + depends on X86_32 + ---help--- + This is the driver for the hardware watchdog found on the IEI + single board computers EPIC Nano 7240 (and likely others). This + watchdog simply watches your kernel to make sure it doesn't freeze, + and if it does, it reboots your computer after a certain amount of + time. + + To compile this driver as a module, choose M here: the + module will be called sbc7240_wdt. + config CPU5_WDT tristate "SMA CPU5 Watchdog" depends on X86 diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 7d9e573..87483cc 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -66,11 +66,13 @@ obj-$(CONFIG_IBMASR) += ibmasr.o obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o obj-$(CONFIG_I6300ESB_WDT) += i6300esb.o obj-$(CONFIG_ITCO_WDT) += iTCO_wdt.o iTCO_vendor_support.o +obj-$(CONFIG_IT8712F_WDT) += it8712f_wdt.o obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o obj-$(CONFIG_PC87413_WDT) += pc87413_wdt.o obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o obj-$(CONFIG_SBC8360_WDT) += sbc8360.o +obj-$(CONFIG_SBC7240_WDT) += sbc7240_wdt.o obj-$(CONFIG_CPU5_WDT) += cpu5wdt.o obj-$(CONFIG_SMSC37B787_WDT) += smsc37b787_wdt.o obj-$(CONFIG_W83627HF_WDT) += w83627hf_wdt.o diff --git a/drivers/watchdog/at32ap700x_wdt.c b/drivers/watchdog/at32ap700x_wdt.c index 54a5161..fb5ed64 100644 --- a/drivers/watchdog/at32ap700x_wdt.c +++ b/drivers/watchdog/at32ap700x_wdt.c @@ -6,6 +6,19 @@ * 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. + * + * + * Errata: WDT Clear is blocked after WDT Reset + * + * A watchdog timer event will, after reset, block writes to the WDT_CLEAR + * register, preventing the program to clear the next Watchdog Timer Reset. + * + * If you still want to use the WDT after a WDT reset a small code can be + * insterted at the startup checking the AVR32_PM.rcause register for WDT reset + * and use a GPIO pin to reset the system. This method requires that one of the + * GPIO pins are available and connected externally to the RESET_N pin. After + * the GPIO pin has pulled down the reset line the GPIO will be reset and leave + * the pin tristated with pullup. */ #include <linux/init.h> @@ -44,6 +57,13 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" #define WDT_CLR 0x04 +#define WDT_RCAUSE 0x10 +#define WDT_RCAUSE_POR 0 +#define WDT_RCAUSE_EXT 2 +#define WDT_RCAUSE_WDT 3 +#define WDT_RCAUSE_JTAG 4 +#define WDT_RCAUSE_SERP 5 + #define WDT_BIT(name) (1 << WDT_##name) #define WDT_BF(name, value) ((value) << WDT_##name) @@ -56,6 +76,7 @@ struct wdt_at32ap700x { void __iomem *regs; spinlock_t io_lock; int timeout; + int boot_status; unsigned long users; struct miscdevice miscdev; }; @@ -126,7 +147,7 @@ static int at32_wdt_close(struct inode *inode, struct file *file) at32_wdt_stop(); } else { dev_dbg(wdt->miscdev.parent, - "Unexpected close, not stopping watchdog!\n"); + "unexpected close, not stopping watchdog!\n"); at32_wdt_pat(); } clear_bit(1, &wdt->users); @@ -154,6 +175,33 @@ static int at32_wdt_settimeout(int time) return 0; } +/* + * Get the watchdog status. + */ +static int at32_wdt_get_status(void) +{ + int rcause; + int status = 0; + + rcause = wdt_readl(wdt, RCAUSE); + + switch (rcause) { + case WDT_BIT(RCAUSE_EXT): + status = WDIOF_EXTERN1; + break; + case WDT_BIT(RCAUSE_WDT): + status = WDIOF_CARDRESET; + break; + case WDT_BIT(RCAUSE_POR): /* fall through */ + case WDT_BIT(RCAUSE_JTAG): /* fall through */ + case WDT_BIT(RCAUSE_SERP): /* fall through */ + default: + break; + } + + return status; +} + static struct watchdog_info at32_wdt_info = { .identity = "at32ap700x watchdog", .options = WDIOF_SETTIMEOUT | @@ -194,10 +242,12 @@ static int at32_wdt_ioctl(struct inode *inode, struct file *file, case WDIOC_GETTIMEOUT: ret = put_user(wdt->timeout, p); break; - case WDIOC_GETSTATUS: /* fall through */ - case WDIOC_GETBOOTSTATUS: + case WDIOC_GETSTATUS: ret = put_user(0, p); break; + case WDIOC_GETBOOTSTATUS: + ret = put_user(wdt->boot_status, p); + break; case WDIOC_SETOPTIONS: ret = get_user(time, p); if (ret) @@ -282,8 +332,19 @@ static int __init at32_wdt_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "could not map I/O memory\n"); goto err_free; } + spin_lock_init(&wdt->io_lock); - wdt->users = 0; + wdt->boot_status = at32_wdt_get_status(); + + /* Work-around for watchdog silicon errata. */ + if (wdt->boot_status & WDIOF_CARDRESET) { + dev_info(&pdev->dev, "CPU must be reset with external " + "reset or POR due to silicon errata.\n"); + ret = -EIO; + goto err_iounmap; + } else { + wdt->users = 0; + } wdt->miscdev.minor = WATCHDOG_MINOR; wdt->miscdev.name = "watchdog"; wdt->miscdev.fops = &at32_wdt_fops; diff --git a/drivers/watchdog/bfin_wdt.c b/drivers/watchdog/bfin_wdt.c index 309d279..31dc7a6 100644 --- a/drivers/watchdog/bfin_wdt.c +++ b/drivers/watchdog/bfin_wdt.c @@ -71,7 +71,7 @@ static int nowayout = WATCHDOG_NOWAYOUT; static struct watchdog_info bfin_wdt_info; static unsigned long open_check; static char expect_close; -static spinlock_t bfin_wdt_spinlock = SPIN_LOCK_UNLOCKED; +static DEFINE_SPINLOCK(bfin_wdt_spinlock); /** * bfin_wdt_keepalive - Keep the Userspace Watchdog Alive diff --git a/drivers/watchdog/it8712f_wdt.c b/drivers/watchdog/it8712f_wdt.c new file mode 100644 index 0000000..6330fc0 --- /dev/null +++ b/drivers/watchdog/it8712f_wdt.c @@ -0,0 +1,400 @@ +/* + * IT8712F "Smart Guardian" Watchdog support + * + * Copyright (c) 2006-2007 Jorge Boncompte - DTI2 <jorge@dti2.net> + * + * Based on info and code taken from: + * + * drivers/char/watchdog/scx200_wdt.c + * drivers/hwmon/it87.c + * IT8712F EC-LPC I/O Preliminary Specification 0.9.2.pdf + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * The author(s) of this software shall not be held liable for damages + * of any nature resulting due to the use of this software. This + * software is provided AS-IS with no warranties. + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/miscdevice.h> +#include <linux/watchdog.h> +#include <linux/notifier.h> +#include <linux/reboot.h> +#include <linux/fs.h> +#include <linux/pci.h> +#include <linux/spinlock.h> + +#include <asm/uaccess.h> +#include <asm/io.h> + +#define NAME "it8712f_wdt" + +MODULE_AUTHOR("Jorge Boncompte - DTI2 <jorge@dti2.net>"); +MODULE_DESCRIPTION("IT8712F Watchdog Driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); + +static int margin = 60; /* in seconds */ +module_param(margin, int, 0); +MODULE_PARM_DESC(margin, "Watchdog margin in seconds"); + +static int nowayout = WATCHDOG_NOWAYOUT; +module_param(nowayout, int, 0); +MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close"); + +static struct semaphore it8712f_wdt_sem; +static unsigned expect_close; +static spinlock_t io_lock; + +/* Dog Food address - We use the game port address */ +static unsigned short address; + +#define REG 0x2e /* The register to read/write */ +#define VAL 0x2f /* The value to read/write */ + +#define LDN 0x07 /* Register: Logical device select */ +#define DEVID 0x20 /* Register: Device ID */ +#define DEVREV 0x22 /* Register: Device Revision */ +#define ACT_REG 0x30 /* LDN Register: Activation */ +#define BASE_REG 0x60 /* LDN Register: Base address */ + +#define IT8712F_DEVID 0x8712 + +#define LDN_GPIO 0x07 /* GPIO and Watch Dog Timer */ +#define LDN_GAME 0x09 /* Game Port */ + +#define WDT_CONTROL 0x71 /* WDT Register: Control */ +#define WDT_CONFIG 0x72 /* WDT Register: Configuration */ +#define WDT_TIMEOUT 0x73 /* WDT Register: Timeout Value */ + +#define WDT_RESET_GAME 0x10 +#define WDT_RESET_KBD 0x20 +#define WDT_RESET_MOUSE 0x40 +#define WDT_RESET_CIR 0x80 + +#define WDT_UNIT_SEC 0x80 /* If 0 in MINUTES */ + +#define WDT_OUT_PWROK 0x10 +#define WDT_OUT_KRST 0x40 + +static int +superio_inb(int reg) +{ + outb(reg, REG); + return inb(VAL); +} + +static void +superio_outb(int val, int reg) +{ + outb(reg, REG); + outb(val, VAL); +} + +static int +superio_inw(int reg) +{ + int val; + outb(reg++, REG); + val = inb(VAL) << 8; + outb(reg, REG); + val |= inb(VAL); + return val; +} + +static inline void +superio_select(int ldn) +{ + outb(LDN, REG); + outb(ldn, VAL); +} + +static inline void +superio_enter(void) +{ + spin_lock(&io_lock); + outb(0x87, REG); + outb(0x01, REG); + outb(0x55, REG); + outb(0x55, REG); +} + +static inline void +superio_exit(void) +{ + outb(0x02, REG); + outb(0x02, VAL); + spin_unlock(&io_lock); +} + +static inline void +it8712f_wdt_ping(void) +{ + inb(address); +} + +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 */ + superio_outb(config, WDT_CONFIG); + + superio_outb((margin > 255) ? (margin / 60) : margin, WDT_TIMEOUT); +} + +static void +it8712f_wdt_enable(void) +{ + printk(KERN_DEBUG NAME ": enabling watchdog timer\n"); + superio_enter(); + superio_select(LDN_GPIO); + + superio_outb(WDT_RESET_GAME, WDT_CONTROL); + + it8712f_wdt_update_margin(); + + superio_exit(); + + it8712f_wdt_ping(); +} + +static void +it8712f_wdt_disable(void) +{ + printk(KERN_DEBUG NAME ": disabling watchdog timer\n"); + + superio_enter(); + superio_select(LDN_GPIO); + + superio_outb(0, WDT_CONFIG); + superio_outb(0, WDT_CONTROL); + superio_outb(0, WDT_TIMEOUT); + + superio_exit(); +} + +static int +it8712f_wdt_notify(struct notifier_block *this, + unsigned long code, void *unused) +{ + if (code == SYS_HALT || code == SYS_POWER_OFF) + if (!nowayout) + it8712f_wdt_disable(); + + return NOTIFY_DONE; +} + +static struct notifier_block it8712f_wdt_notifier = { + .notifier_call = it8712f_wdt_notify, +}; + +static ssize_t +it8712f_wdt_write(struct file *file, const char __user *data, + size_t len, loff_t *ppos) +{ + /* check for a magic close character */ + if (len) { + size_t i; + + it8712f_wdt_ping(); + + expect_close = 0; + for (i = 0; i < len; ++i) { + char c; + if (get_user(c, data+i)) + return -EFAULT; + if (c == 'V') + expect_close = 42; + } + } + + return len; +} + +static int +it8712f_wdt_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + void __user *argp = (void __user *)arg; + int __user *p = argp; + static struct watchdog_info ident = { + .identity = "IT8712F Watchdog", + .firmware_version = 1, + .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, + }; + int new_margin; + + switch (cmd) { + default: + return -ENOTTY; + case WDIOC_GETSUPPORT: + if (copy_to_user(argp, &ident, sizeof(ident))) + return -EFAULT; + return 0; + case WDIOC_GETSTATUS: + 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)) + return -EFAULT; + if (new_margin < 1) + return -EINVAL; + margin = new_margin; + superio_enter(); + superio_select(LDN_GPIO); + + it8712f_wdt_update_margin(); + + superio_exit(); + it8712f_wdt_ping(); + case WDIOC_GETTIMEOUT: + if (put_user(margin, p)) + return -EFAULT; + return 0; + } +} + +static int +it8712f_wdt_open(struct inode *inode, struct file *file) +{ + /* only allow one at a time */ + if (down_trylock(&it8712f_wdt_sem)) + return -EBUSY; + it8712f_wdt_enable(); + + return nonseekable_open(inode, file); +} + +static int +it8712f_wdt_release(struct inode *inode, struct file *file) +{ + if (expect_close != 42) { + printk(KERN_WARNING NAME + ": watchdog device closed unexpectedly, will not" + " disable the watchdog timer\n"); + } else if (!nowayout) { + it8712f_wdt_disable(); + } + expect_close = 0; + up(&it8712f_wdt_sem); + + return 0; +} + +static struct file_operations it8712f_wdt_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .write = it8712f_wdt_write, + .ioctl = it8712f_wdt_ioctl, + .open = it8712f_wdt_open, + .release = it8712f_wdt_release, +}; + +static struct miscdevice it8712f_wdt_miscdev = { + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &it8712f_wdt_fops, +}; + +static int __init +it8712f_wdt_find(unsigned short *address) +{ + int err = -ENODEV; + int chip_type; + + superio_enter(); + chip_type = superio_inw(DEVID); + if (chip_type != IT8712F_DEVID) + goto exit; + + superio_select(LDN_GAME); + superio_outb(1, ACT_REG); + if (!(superio_inb(ACT_REG) & 0x01)) { + printk(KERN_ERR NAME ": Device not activated, skipping\n"); + goto exit; + } + + *address = superio_inw(BASE_REG); + if (*address == 0) { + printk(KERN_ERR NAME ": Base address not set, skipping\n"); + goto exit; + } + + err = 0; + printk(KERN_DEBUG NAME ": Found IT%04xF chip revision %d - " + "using DogFood address 0x%x\n", + chip_type, superio_inb(DEVREV) & 0x0f, *address); + +exit: + superio_exit(); + return err; +} + +static int __init +it8712f_wdt_init(void) +{ + int err = 0; + + spin_lock_init(&io_lock); + + if (it8712f_wdt_find(&address)) + return -ENODEV; + + if (!request_region(address, 1, "IT8712F Watchdog")) { + printk(KERN_WARNING NAME ": watchdog I/O region busy\n"); + return -EBUSY; + } + + it8712f_wdt_disable(); + + sema_init(&it8712f_wdt_sem, 1); + + err = register_reboot_notifier(&it8712f_wdt_notifier); + if (err) { + printk(KERN_ERR NAME ": unable to register reboot notifier\n"); + goto out; + } + + err = misc_register(&it8712f_wdt_miscdev); + if (err) { + printk(KERN_ERR NAME + ": cannot register miscdev on minor=%d (err=%d)\n", + WATCHDOG_MINOR, err); + goto reboot_out; + } + + return 0; + + +reboot_out: + unregister_reboot_notifier(&it8712f_wdt_notifier); +out: + release_region(address, 1); + return err; +} + +static void __exit +it8712f_wdt_exit(void) +{ + misc_deregister(&it8712f_wdt_miscdev); + unregister_reboot_notifier(&it8712f_wdt_notifier); + release_region(address, 1); +} + +module_init(it8712f_wdt_init); +module_exit(it8712f_wdt_exit); diff --git a/drivers/watchdog/sbc7240_wdt.c b/drivers/watchdog/sbc7240_wdt.c new file mode 100644 index 0000000..4c8cefb --- /dev/null +++ b/drivers/watchdog/sbc7240_wdt.c @@ -0,0 +1,324 @@ +/* + * NANO7240 SBC Watchdog device driver + * + * Based on w83877f.c by Scott Jennings, + * + * 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; + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * (c) Copyright 2007 Gilles GIGAN <gilles.gigan@jcu.edu.au> + * + */ + +#include <linux/fs.h> +#include <linux/init.h> +#include <linux/ioport.h> +#include <linux/jiffies.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/miscdevice.h> +#include <linux/notifier.h> +#include <linux/reboot.h> +#include <linux/types.h> +#include <linux/watchdog.h> +#include <asm/atomic.h> +#include <asm/io.h> +#include <asm/system.h> +#include <asm/uaccess.h> + +#define SBC7240_PREFIX "sbc7240_wdt: " + +#define SBC7240_ENABLE_PORT 0x443 +#define SBC7240_DISABLE_PORT 0x043 +#define SBC7240_SET_TIMEOUT_PORT SBC7240_ENABLE_PORT +#define SBC7240_MAGIC_CHAR 'V' + +#define SBC7240_TIMEOUT 30 +#define SBC7240_MAX_TIMEOUT 255 +static int timeout = SBC7240_TIMEOUT; /* in seconds */ +module_param(timeout, int, 0); +MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. (1<=timeout<=" + __MODULE_STRING(SBC7240_MAX_TIMEOUT) ", default=" + __MODULE_STRING(SBC7240_TIMEOUT) ")"); + +static int nowayout = WATCHDOG_NOWAYOUT; +module_param(nowayout, int, 0); +MODULE_PARM_DESC(nowayout, "Disable watchdog when closing device file"); + +#define SBC7240_OPEN_STATUS_BIT 0 +#define SBC7240_ENABLED_STATUS_BIT 1 +#define SBC7240_EXPECT_CLOSE_STATUS_BIT 2 +static unsigned long wdt_status; + +/* + * Utility routines + */ + +static void wdt_disable(void) +{ + /* disable the watchdog */ + if (test_and_clear_bit(SBC7240_ENABLED_STATUS_BIT, &wdt_status)) { + inb_p(SBC7240_DISABLE_PORT); + printk(KERN_INFO SBC7240_PREFIX + "Watchdog timer is now disabled.\n"); + } +} + +static void wdt_enable(void) +{ + /* enable the watchdog */ + if (!test_and_set_bit(SBC7240_ENABLED_STATUS_BIT, &wdt_status)) { + inb_p(SBC7240_ENABLE_PORT); + printk(KERN_INFO SBC7240_PREFIX + "Watchdog timer is now enabled.\n"); + } +} + +static int wdt_set_timeout(int t) +{ + if (t < 1 || t > SBC7240_MAX_TIMEOUT) { + printk(KERN_ERR SBC7240_PREFIX + "timeout value must be 1<=x<=%d\n", + SBC7240_MAX_TIMEOUT); + return -1; + } + /* set the timeout */ + outb_p((unsigned)t, SBC7240_SET_TIMEOUT_PORT); + timeout = t; + printk(KERN_INFO SBC7240_PREFIX "timeout set to %d seconds\n", t); + return 0; +} + +/* Whack the dog */ +static inline void wdt_keepalive(void) +{ + if (test_bit(SBC7240_ENABLED_STATUS_BIT, &wdt_status)) + inb_p(SBC7240_ENABLE_PORT); +} + +/* + * /dev/watchdog handling + */ +static ssize_t fop_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + size_t i; + char c; + + if (count) { + if (!nowayout) { + clear_bit(SBC7240_EXPECT_CLOSE_STATUS_BIT, + &wdt_status); + + /* is there a magic char ? */ + for (i = 0; i != count; i++) { + if (get_user(c, buf + i)) + return -EFAULT; + if (c == SBC7240_MAGIC_CHAR) { + set_bit(SBC7240_EXPECT_CLOSE_STATUS_BIT, + &wdt_status); + break; + } + } + } + + wdt_keepalive(); + } + + return count; +} + +static int fop_open(struct inode *inode, struct file *file) +{ + if (test_and_set_bit(SBC7240_OPEN_STATUS_BIT, &wdt_status)) + return -EBUSY; + + wdt_enable(); + + return nonseekable_open(inode, file); +} + +static int fop_close(struct inode *inode, struct file *file) +{ + if (test_and_clear_bit(SBC7240_EXPECT_CLOSE_STATUS_BIT, &wdt_status) + || !nowayout) { + wdt_disable(); + } else { + printk(KERN_CRIT SBC7240_PREFIX + "Unexpected close, not stopping watchdog!\n"); + wdt_keepalive(); + } + + clear_bit(SBC7240_OPEN_STATUS_BIT, &wdt_status); + return 0; +} + +static struct watchdog_info ident = { + .options = WDIOF_KEEPALIVEPING| + WDIOF_SETTIMEOUT| + WDIOF_MAGICCLOSE, + .firmware_version = 1, + .identity = "SBC7240", +}; + + +static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + switch (cmd) { + case WDIOC_GETSUPPORT: + return copy_to_user + ((void __user *)arg, &ident, sizeof(ident)) + ? -EFAULT : 0; + case WDIOC_GETSTATUS: + case WDIOC_GETBOOTSTATUS: + return put_user(0, (int __user *)arg); + case WDIOC_KEEPALIVE: + wdt_keepalive(); + return 0; + case WDIOC_SETOPTIONS:{ + int options; + int retval = -EINVAL; + + if (get_user(options, (int __user *)arg)) + return -EFAULT; + + if (options & WDIOS_DISABLECARD) { + wdt_disable(); + retval = 0; + } + + if (options & WDIOS_ENABLECARD) { + wdt_enable(); + retval = 0; + } + + return retval; + } + case WDIOC_SETTIMEOUT:{ + int new_timeout; + + if (get_user(new_timeout, (int __user *)arg)) + return -EFAULT; + + if (wdt_set_timeout(new_timeout)) + return -EINVAL; + + /* Fall through */ + } + case WDIOC_GETTIMEOUT: + return put_user(timeout, (int __user *)arg); + default: + return -ENOTTY; + } +} + +static const struct file_operations wdt_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .write = fop_write, + .open = fop_open, + .release = fop_close, + .ioctl = fop_ioctl, +}; + +static struct miscdevice wdt_miscdev = { + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &wdt_fops, +}; + +/* + * Notifier for system down + */ + +static int wdt_notify_sys(struct notifier_block *this, unsigned long code, + void *unused) +{ + if (code == SYS_DOWN || code == SYS_HALT) + wdt_disable(); + return NOTIFY_DONE; +} + +static struct notifier_block wdt_notifier = { + .notifier_call = wdt_notify_sys, +}; + +static void __exit sbc7240_wdt_unload(void) +{ + printk(KERN_INFO SBC7240_PREFIX "Removing watchdog\n"); + misc_deregister(&wdt_miscdev); + + unregister_reboot_notifier(&wdt_notifier); + release_region(SBC7240_ENABLE_PORT, 1); +} + +static int __init sbc7240_wdt_init(void) +{ + int rc = -EBUSY; + + if (!request_region(SBC7240_ENABLE_PORT, 1, "SBC7240 WDT")) { + printk(KERN_ERR SBC7240_PREFIX + "I/O address 0x%04x already in use\n", + SBC7240_ENABLE_PORT); + rc = -EIO; + goto err_out; + } + + /* The IO port 0x043 used to disable the watchdog + * is already claimed by the system timer, so we + * cant request_region() it ...*/ + + if (timeout < 1 || timeout > SBC7240_MAX_TIMEOUT) { + timeout = SBC7240_TIMEOUT; + printk(KERN_INFO SBC7240_PREFIX + "timeout value must be 1<=x<=%d, using %d\n", + SBC7240_MAX_TIMEOUT, timeout); + } + wdt_set_timeout(timeout); + wdt_disable(); + + rc = register_reboot_notifier(&wdt_notifier); + if (rc) { + printk(KERN_ERR SBC7240_PREFIX + "cannot register reboot notifier (err=%d)\n", rc); + goto err_out_region; + } + + rc = misc_register(&wdt_miscdev); + if (rc) { + printk(KERN_ERR SBC7240_PREFIX + "cannot register miscdev on minor=%d (err=%d)\n", + wdt_miscdev.minor, rc); + goto err_out_reboot_notifier; + } + + printk(KERN_INFO SBC7240_PREFIX + "Watchdog driver for SBC7240 initialised (nowayout=%d)\n", + nowayout); + + return 0; + +err_out_reboot_notifier: + unregister_reboot_notifier(&wdt_notifier); +err_out_region: + release_region(SBC7240_ENABLE_PORT, 1); +err_out: + return rc; +} + +module_init(sbc7240_wdt_init); +module_exit(sbc7240_wdt_unload); + +MODULE_AUTHOR("Gilles Gigan"); +MODULE_DESCRIPTION("Watchdog device driver for single board" + " computers EPIC Nano 7240 from iEi"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); + diff --git a/drivers/watchdog/w83697hf_wdt.c b/drivers/watchdog/w83697hf_wdt.c index c622a0e..6ea125e 100644 --- a/drivers/watchdog/w83697hf_wdt.c +++ b/drivers/watchdog/w83697hf_wdt.c @@ -382,8 +382,10 @@ wdt_init(void) /* we will autodetect the W83697HF/HG watchdog */ for (i = 0; ((!found) && (w83697hf_ioports[i] != 0)); i++) { wdt_io = w83697hf_ioports[i]; - if (!w83697hf_check_wdt()) + if (!w83697hf_check_wdt()) { found++; + break; + } } } else { if (!w83697hf_check_wdt()) |