diff options
author | David S. Miller <davem@davemloft.net> | 2008-06-10 13:22:26 +0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-06-10 13:22:26 +0400 |
commit | 65b53e4cc90e59936733b3b95b9451d2ca47528d (patch) | |
tree | 29932718192962671c48c3fd1ea017a6112459e8 /drivers | |
parent | 788c0a53164c05c5ccdb1472474372b72ba74644 (diff) | |
parent | 2e761e0532a784816e7e822dbaaece8c5d4be14d (diff) | |
download | linux-65b53e4cc90e59936733b3b95b9451d2ca47528d.tar.xz |
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
Conflicts:
drivers/net/tg3.c
drivers/net/wireless/rt2x00/rt2x00dev.c
net/mac80211/ieee80211_i.h
Diffstat (limited to 'drivers')
321 files changed, 7229 insertions, 3144 deletions
diff --git a/drivers/acpi/dispatcher/dsmethod.c b/drivers/acpi/dispatcher/dsmethod.c index e48a3ea03117..2509809a36cf 100644 --- a/drivers/acpi/dispatcher/dsmethod.c +++ b/drivers/acpi/dispatcher/dsmethod.c @@ -565,7 +565,7 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc, acpi_os_release_mutex(method_desc->method. mutex->mutex.os_mutex); - method_desc->method.mutex->mutex.thread_id = 0; + method_desc->method.mutex->mutex.thread_id = NULL; } } diff --git a/drivers/acpi/executer/exmutex.c b/drivers/acpi/executer/exmutex.c index c873ab40cd0e..a8bf3d713e28 100644 --- a/drivers/acpi/executer/exmutex.c +++ b/drivers/acpi/executer/exmutex.c @@ -326,7 +326,7 @@ acpi_status acpi_ex_release_mutex_object(union acpi_operand_object *obj_desc) /* Clear mutex info */ - obj_desc->mutex.thread_id = 0; + obj_desc->mutex.thread_id = NULL; return_ACPI_STATUS(status); } @@ -463,7 +463,7 @@ void acpi_ex_release_all_mutexes(struct acpi_thread_state *thread) /* Mark mutex unowned */ obj_desc->mutex.owner_thread = NULL; - obj_desc->mutex.thread_id = 0; + obj_desc->mutex.thread_id = NULL; /* Update Thread sync_level (Last mutex is the important one) */ diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 97f83fb2ee2e..544b7d6c617c 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -502,10 +502,10 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(NVIDIA, 0x0bcd), board_ahci }, /* MCP7B */ { PCI_VDEVICE(NVIDIA, 0x0bce), board_ahci }, /* MCP7B */ { PCI_VDEVICE(NVIDIA, 0x0bcf), board_ahci }, /* MCP7B */ - { PCI_VDEVICE(NVIDIA, 0x0bd0), board_ahci }, /* MCP7B */ - { PCI_VDEVICE(NVIDIA, 0x0bd1), board_ahci }, /* MCP7B */ - { PCI_VDEVICE(NVIDIA, 0x0bd2), board_ahci }, /* MCP7B */ - { PCI_VDEVICE(NVIDIA, 0x0bd3), board_ahci }, /* MCP7B */ + { PCI_VDEVICE(NVIDIA, 0x0bc4), board_ahci }, /* MCP7B */ + { PCI_VDEVICE(NVIDIA, 0x0bc5), board_ahci }, /* MCP7B */ + { PCI_VDEVICE(NVIDIA, 0x0bc6), board_ahci }, /* MCP7B */ + { PCI_VDEVICE(NVIDIA, 0x0bc7), board_ahci }, /* MCP7B */ /* SiS */ { PCI_VDEVICE(SI, 0x1184), board_ahci }, /* SiS 966 */ diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index a9027b8fbdd5..3548ee7014ca 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -247,10 +247,11 @@ static const struct pci_device_id piix_pci_tbl[] = { { 0x8086, 0x2820, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata }, /* SATA Controller 2 IDE (ICH8) */ { 0x8086, 0x2825, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, - /* Mobile SATA Controller IDE (ICH8M) */ - { 0x8086, 0x2828, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata }, /* Mobile SATA Controller IDE (ICH8M), Apple */ { 0x8086, 0x2828, 0x106b, 0x00a0, 0, 0, ich8m_apple_sata }, + { 0x8086, 0x2828, 0x106b, 0x00a1, 0, 0, ich8m_apple_sata }, + /* Mobile SATA Controller IDE (ICH8M) */ + { 0x8086, 0x2828, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata }, /* SATA Controller IDE (ICH9) */ { 0x8086, 0x2920, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata }, /* SATA Controller IDE (ICH9) */ @@ -526,7 +527,7 @@ static struct ata_port_info piix_port_info[] = { [ich8m_apple_sata] = { - .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SIDPR, + .flags = PIIX_SATA_FLAGS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = ATA_UDMA6, diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index 70b77e0899a8..dbf6ca781f66 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c @@ -118,8 +118,8 @@ static void ata_acpi_associate_ide_port(struct ata_port *ap) ap->pflags |= ATA_PFLAG_INIT_GTM_VALID; } -static void ata_acpi_handle_hotplug(struct ata_port *ap, struct ata_device *dev, - u32 event) +static void ata_acpi_handle_hotplug(struct ata_port *ap, struct ata_device + *dev, u32 event) { char event_string[12]; char *envp[] = { event_string, NULL }; @@ -127,6 +127,9 @@ static void ata_acpi_handle_hotplug(struct ata_port *ap, struct ata_device *dev, struct kobject *kobj = NULL; int wait = 0; unsigned long flags; + acpi_handle handle, tmphandle; + unsigned long sta; + acpi_status status; if (!ap) ap = dev->link->ap; @@ -134,32 +137,57 @@ static void ata_acpi_handle_hotplug(struct ata_port *ap, struct ata_device *dev, spin_lock_irqsave(ap->lock, flags); + if (dev) + handle = dev->acpi_handle; + else + handle = ap->acpi_handle; + + status = acpi_get_handle(handle, "_EJ0", &tmphandle); + if (ACPI_FAILURE(status)) { + /* This device is not ejectable */ + spin_unlock_irqrestore(ap->lock, flags); + return; + } + + status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); + if (ACPI_FAILURE(status)) { + printk ("Unable to determine bay status\n"); + spin_unlock_irqrestore(ap->lock, flags); + return; + } + switch (event) { case ACPI_NOTIFY_BUS_CHECK: case ACPI_NOTIFY_DEVICE_CHECK: ata_ehi_push_desc(ehi, "ACPI event"); - ata_ehi_hotplugged(ehi); - ata_port_freeze(ap); - break; - - case ACPI_NOTIFY_EJECT_REQUEST: - ata_ehi_push_desc(ehi, "ACPI event"); - if (dev) - dev->flags |= ATA_DFLAG_DETACH; - else { - struct ata_link *tlink; - struct ata_device *tdev; - - ata_port_for_each_link(tlink, ap) - ata_link_for_each_dev(tdev, tlink) - tdev->flags |= ATA_DFLAG_DETACH; + if (!sta) { + /* Device has been unplugged */ + if (dev) + dev->flags |= ATA_DFLAG_DETACH; + else { + struct ata_link *tlink; + struct ata_device *tdev; + + ata_port_for_each_link(tlink, ap) { + ata_link_for_each_dev(tdev, tlink) { + tdev->flags |= + ATA_DFLAG_DETACH; + } + } + } + ata_port_schedule_eh(ap); + wait = 1; + } else { + ata_ehi_hotplugged(ehi); + ata_port_freeze(ap); } - - ata_port_schedule_eh(ap); - wait = 1; - break; } + spin_unlock_irqrestore(ap->lock, flags); + + if (wait) + ata_port_wait_eh(ap); + if (dev) { if (dev->sdev) kobj = &dev->sdev->sdev_gendev.kobj; @@ -170,11 +198,6 @@ static void ata_acpi_handle_hotplug(struct ata_port *ap, struct ata_device *dev, sprintf(event_string, "BAY_EVENT=%d", event); kobject_uevent_env(kobj, KOBJ_CHANGE, envp); } - - spin_unlock_irqrestore(ap->lock, flags); - - if (wait) - ata_port_wait_eh(ap); } static void ata_acpi_dev_notify(acpi_handle handle, u32 event, void *data) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 927b692d723c..cc816ca623d3 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -2126,6 +2126,13 @@ int ata_dev_configure(struct ata_device *dev) dev->horkage |= ata_dev_blacklisted(dev); ata_force_horkage(dev); + if (dev->horkage & ATA_HORKAGE_DISABLE) { + ata_dev_printk(dev, KERN_INFO, + "unsupported device, disabling\n"); + ata_dev_disable(dev); + return 0; + } + /* let ACPI work its magic */ rc = ata_acpi_on_devcfg(dev); if (rc) @@ -3490,22 +3497,11 @@ int sata_link_resume(struct ata_link *link, const unsigned long *params, if ((rc = sata_link_debounce(link, params, deadline))) return rc; - /* Clear SError. PMP and some host PHYs require this to - * operate and clearing should be done before checking PHY - * online status to avoid race condition (hotplugging between - * link resume and status check). - */ + /* clear SError, some PHYs require this even for SRST to work */ if (!(rc = sata_scr_read(link, SCR_ERROR, &serror))) rc = sata_scr_write(link, SCR_ERROR, serror); - if (rc == 0 || rc == -EINVAL) { - unsigned long flags; - spin_lock_irqsave(link->ap->lock, flags); - link->eh_info.serror = 0; - spin_unlock_irqrestore(link->ap->lock, flags); - rc = 0; - } - return rc; + return rc != -EINVAL ? rc : 0; } /** @@ -3653,9 +3649,13 @@ int sata_link_hardreset(struct ata_link *link, const unsigned long *timing, if (check_ready) rc = ata_wait_ready(link, deadline, check_ready); out: - if (rc && rc != -EAGAIN) + if (rc && rc != -EAGAIN) { + /* online is set iff link is online && reset succeeded */ + if (online) + *online = false; ata_link_printk(link, KERN_ERR, "COMRESET failed (errno=%d)\n", rc); + } DPRINTK("EXIT, rc=%d\n", rc); return rc; } @@ -3700,8 +3700,14 @@ int sata_std_hardreset(struct ata_link *link, unsigned int *class, */ void ata_std_postreset(struct ata_link *link, unsigned int *classes) { + u32 serror; + DPRINTK("ENTER\n"); + /* reset complete, clear SError */ + if (!sata_scr_read(link, SCR_ERROR, &serror)) + sata_scr_write(link, SCR_ERROR, serror); + /* print link status */ sata_print_link_status(link); @@ -3894,8 +3900,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { { "SAMSUNG CD-ROM SN-124", "N001", ATA_HORKAGE_NODMA }, { "Seagate STT20000A", NULL, ATA_HORKAGE_NODMA }, /* Odd clown on sil3726/4726 PMPs */ - { "Config Disk", NULL, ATA_HORKAGE_NODMA | - ATA_HORKAGE_SKIP_PM }, + { "Config Disk", NULL, ATA_HORKAGE_DISABLE }, /* Weird ATAPI devices */ { "TORiSAN DVD-ROM DRD-N216", NULL, ATA_HORKAGE_MAX_SEC_128 }, @@ -5398,7 +5403,7 @@ static void ata_host_stop(struct device *gendev, void *res) */ static void ata_finalize_port_ops(struct ata_port_operations *ops) { - static spinlock_t lock = SPIN_LOCK_UNLOCKED; + static DEFINE_SPINLOCK(lock); const struct ata_port_operations *cur; void **begin = (void **)ops; void **end = (void **)&ops->inherits; @@ -5616,7 +5621,7 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht) spin_lock_irqsave(ap->lock, flags); ehi->probe_mask |= ATA_ALL_DEVICES; - ehi->action |= ATA_EH_RESET; + ehi->action |= ATA_EH_RESET | ATA_EH_LPM; ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET; ap->pflags &= ~ATA_PFLAG_INITIALIZING; @@ -5649,7 +5654,6 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht) struct ata_port *ap = host->ports[i]; ata_scsi_scan_host(ap, 1); - ata_lpm_schedule(ap, ap->pm_policy); } return 0; diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 62e033146bed..7894d83ea1eb 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1308,12 +1308,7 @@ static void ata_eh_analyze_serror(struct ata_link *link) unsigned int err_mask = 0, action = 0; u32 hotplug_mask; - if (serror & SERR_PERSISTENT) { - err_mask |= AC_ERR_ATA_BUS; - action |= ATA_EH_RESET; - } - if (serror & - (SERR_DATA_RECOVERED | SERR_COMM_RECOVERED | SERR_DATA)) { + if (serror & (SERR_PERSISTENT | SERR_DATA)) { err_mask |= AC_ERR_ATA_BUS; action |= ATA_EH_RESET; } @@ -2047,19 +2042,11 @@ static int ata_do_reset(struct ata_link *link, ata_reset_fn_t reset, unsigned int *classes, unsigned long deadline) { struct ata_device *dev; - int rc; ata_link_for_each_dev(dev, link) classes[dev->devno] = ATA_DEV_UNKNOWN; - rc = reset(link, classes, deadline); - - /* convert all ATA_DEV_UNKNOWN to ATA_DEV_NONE */ - ata_link_for_each_dev(dev, link) - if (classes[dev->devno] == ATA_DEV_UNKNOWN) - classes[dev->devno] = ATA_DEV_NONE; - - return rc; + return reset(link, classes, deadline); } static int ata_eh_followup_srst_needed(struct ata_link *link, @@ -2096,9 +2083,11 @@ int ata_eh_reset(struct ata_link *link, int classify, ata_reset_fn_t reset; unsigned long flags; u32 sstatus; - int rc; + int nr_known, rc; - /* about to reset */ + /* + * Prepare to reset + */ spin_lock_irqsave(ap->lock, flags); ap->pflags |= ATA_PFLAG_RESETTING; spin_unlock_irqrestore(ap->lock, flags); @@ -2124,16 +2113,8 @@ int ata_eh_reset(struct ata_link *link, int classify, ap->ops->set_piomode(ap, dev); } - if (!softreset && !hardreset) { - if (verbose) - ata_link_printk(link, KERN_INFO, "no reset method " - "available, skipping reset\n"); - if (!(lflags & ATA_LFLAG_ASSUME_CLASS)) - lflags |= ATA_LFLAG_ASSUME_ATA; - goto done; - } - /* prefer hardreset */ + reset = NULL; ehc->i.action &= ~ATA_EH_RESET; if (hardreset) { reset = hardreset; @@ -2141,11 +2122,6 @@ int ata_eh_reset(struct ata_link *link, int classify, } else if (softreset) { reset = softreset; ehc->i.action = ATA_EH_SOFTRESET; - } else { - ata_link_printk(link, KERN_ERR, "BUG: no reset method, " - "please report to linux-ide@vger.kernel.org\n"); - dump_stack(); - return -EINVAL; } if (prereset) { @@ -2165,55 +2141,71 @@ int ata_eh_reset(struct ata_link *link, int classify, "prereset failed (errno=%d)\n", rc); goto out; } - } - /* prereset() might have cleared ATA_EH_RESET */ - if (!(ehc->i.action & ATA_EH_RESET)) { - /* prereset told us not to reset, bang classes and return */ - ata_link_for_each_dev(dev, link) - classes[dev->devno] = ATA_DEV_NONE; - rc = 0; - goto out; + /* prereset() might have cleared ATA_EH_RESET. If so, + * bang classes and return. + */ + if (reset && !(ehc->i.action & ATA_EH_RESET)) { + ata_link_for_each_dev(dev, link) + classes[dev->devno] = ATA_DEV_NONE; + rc = 0; + goto out; + } } retry: + /* + * Perform reset + */ + if (ata_is_host_link(link)) + ata_eh_freeze_port(ap); + deadline = jiffies + ata_eh_reset_timeouts[try++]; - /* shut up during boot probing */ - if (verbose) - ata_link_printk(link, KERN_INFO, "%s resetting link\n", - reset == softreset ? "soft" : "hard"); + if (reset) { + if (verbose) + ata_link_printk(link, KERN_INFO, "%s resetting link\n", + reset == softreset ? "soft" : "hard"); - /* mark that this EH session started with reset */ - if (reset == hardreset) - ehc->i.flags |= ATA_EHI_DID_HARDRESET; - else - ehc->i.flags |= ATA_EHI_DID_SOFTRESET; + /* mark that this EH session started with reset */ + if (reset == hardreset) + ehc->i.flags |= ATA_EHI_DID_HARDRESET; + else + ehc->i.flags |= ATA_EHI_DID_SOFTRESET; - rc = ata_do_reset(link, reset, classes, deadline); + rc = ata_do_reset(link, reset, classes, deadline); - if (reset == hardreset && - ata_eh_followup_srst_needed(link, rc, classify, classes)) { - /* okay, let's do follow-up softreset */ - reset = softreset; + if (reset == hardreset && + ata_eh_followup_srst_needed(link, rc, classify, classes)) { + /* okay, let's do follow-up softreset */ + reset = softreset; - if (!reset) { - ata_link_printk(link, KERN_ERR, - "follow-up softreset required " - "but no softreset avaliable\n"); - rc = -EINVAL; - goto fail; + if (!reset) { + ata_link_printk(link, KERN_ERR, + "follow-up softreset required " + "but no softreset avaliable\n"); + rc = -EINVAL; + goto fail; + } + + ata_eh_about_to_do(link, NULL, ATA_EH_RESET); + rc = ata_do_reset(link, reset, classes, deadline); } - ata_eh_about_to_do(link, NULL, ATA_EH_RESET); - rc = ata_do_reset(link, reset, classes, deadline); + /* -EAGAIN can happen if we skipped followup SRST */ + if (rc && rc != -EAGAIN) + goto fail; + } else { + if (verbose) + ata_link_printk(link, KERN_INFO, "no reset method " + "available, skipping reset\n"); + if (!(lflags & ATA_LFLAG_ASSUME_CLASS)) + lflags |= ATA_LFLAG_ASSUME_ATA; } - /* -EAGAIN can happen if we skipped followup SRST */ - if (rc && rc != -EAGAIN) - goto fail; - - done: + /* + * Post-reset processing + */ ata_link_for_each_dev(dev, link) { /* After the reset, the device state is PIO 0 and the * controller state is undefined. Reset also wakes up @@ -2236,9 +2228,53 @@ int ata_eh_reset(struct ata_link *link, int classify, if (sata_scr_read(link, SCR_STATUS, &sstatus) == 0) link->sata_spd = (sstatus >> 4) & 0xf; + /* thaw the port */ + if (ata_is_host_link(link)) + ata_eh_thaw_port(ap); + + /* postreset() should clear hardware SError. Although SError + * is cleared during link resume, clearing SError here is + * necessary as some PHYs raise hotplug events after SRST. + * This introduces race condition where hotplug occurs between + * reset and here. This race is mediated by cross checking + * link onlineness and classification result later. + */ if (postreset) postreset(link, classes); + /* clear cached SError */ + spin_lock_irqsave(link->ap->lock, flags); + link->eh_info.serror = 0; + spin_unlock_irqrestore(link->ap->lock, flags); + + /* Make sure onlineness and classification result correspond. + * Hotplug could have happened during reset and some + * controllers fail to wait while a drive is spinning up after + * being hotplugged causing misdetection. By cross checking + * link onlineness and classification result, those conditions + * can be reliably detected and retried. + */ + nr_known = 0; + ata_link_for_each_dev(dev, link) { + /* convert all ATA_DEV_UNKNOWN to ATA_DEV_NONE */ + if (classes[dev->devno] == ATA_DEV_UNKNOWN) + classes[dev->devno] = ATA_DEV_NONE; + else + nr_known++; + } + + if (classify && !nr_known && ata_link_online(link)) { + if (try < max_tries) { + ata_link_printk(link, KERN_WARNING, "link online but " + "device misclassified, retrying\n"); + rc = -EAGAIN; + goto fail; + } + ata_link_printk(link, KERN_WARNING, + "link online but device misclassified, " + "device detection might fail\n"); + } + /* reset successful, schedule revalidation */ ata_eh_done(link, NULL, ATA_EH_RESET); ehc->i.action |= ATA_EH_REVALIDATE; @@ -2587,7 +2623,7 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, struct ata_link *link; struct ata_device *dev; int nr_failed_devs, nr_disabled_devs; - int reset, rc; + int rc; unsigned long flags; DPRINTK("ENTER\n"); @@ -2630,7 +2666,6 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, rc = 0; nr_failed_devs = 0; nr_disabled_devs = 0; - reset = 0; /* if UNLOADING, finish immediately */ if (ap->pflags & ATA_PFLAG_UNLOADING) @@ -2644,40 +2679,24 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, if (ata_eh_skip_recovery(link)) ehc->i.action = 0; - /* do we need to reset? */ - if (ehc->i.action & ATA_EH_RESET) - reset = 1; - ata_link_for_each_dev(dev, link) ehc->classes[dev->devno] = ATA_DEV_UNKNOWN; } /* reset */ - if (reset) { - /* if PMP is attached, this function only deals with - * downstream links, port should stay thawed. - */ - if (!sata_pmp_attached(ap)) - ata_eh_freeze_port(ap); - - ata_port_for_each_link(link, ap) { - struct ata_eh_context *ehc = &link->eh_context; + ata_port_for_each_link(link, ap) { + struct ata_eh_context *ehc = &link->eh_context; - if (!(ehc->i.action & ATA_EH_RESET)) - continue; + if (!(ehc->i.action & ATA_EH_RESET)) + continue; - rc = ata_eh_reset(link, ata_link_nr_vacant(link), - prereset, softreset, hardreset, - postreset); - if (rc) { - ata_link_printk(link, KERN_ERR, - "reset failed, giving up\n"); - goto out; - } + rc = ata_eh_reset(link, ata_link_nr_vacant(link), + prereset, softreset, hardreset, postreset); + if (rc) { + ata_link_printk(link, KERN_ERR, + "reset failed, giving up\n"); + goto out; } - - if (!sata_pmp_attached(ap)) - ata_eh_thaw_port(ap); } /* the rest */ diff --git a/drivers/ata/libata-pmp.c b/drivers/ata/libata-pmp.c index ff1822a7da38..7daf4c0f6216 100644 --- a/drivers/ata/libata-pmp.c +++ b/drivers/ata/libata-pmp.c @@ -48,7 +48,7 @@ static unsigned int sata_pmp_read(struct ata_link *link, int reg, u32 *r_val) tf.device = link->pmp; err_mask = ata_exec_internal(pmp_dev, &tf, NULL, DMA_NONE, NULL, 0, - SATA_PMP_SCR_TIMEOUT); + SATA_PMP_RW_TIMEOUT); if (err_mask) return err_mask; @@ -88,7 +88,7 @@ static unsigned int sata_pmp_write(struct ata_link *link, int reg, u32 val) tf.lbah = (val >> 24) & 0xff; return ata_exec_internal(pmp_dev, &tf, NULL, DMA_NONE, NULL, 0, - SATA_PMP_SCR_TIMEOUT); + SATA_PMP_RW_TIMEOUT); } /** @@ -257,19 +257,6 @@ static int sata_pmp_configure(struct ata_device *dev, int print_info) goto fail; } - /* turn off notification till fan-out ports are reset and configured */ - if (gscr[SATA_PMP_GSCR_FEAT_EN] & SATA_PMP_FEAT_NOTIFY) { - gscr[SATA_PMP_GSCR_FEAT_EN] &= ~SATA_PMP_FEAT_NOTIFY; - - err_mask = sata_pmp_write(dev->link, SATA_PMP_GSCR_FEAT_EN, - gscr[SATA_PMP_GSCR_FEAT_EN]); - if (err_mask) { - rc = -EIO; - reason = "failed to write GSCR_FEAT_EN"; - goto fail; - } - } - if (print_info) { ata_dev_printk(dev, KERN_INFO, "Port Multiplier %s, " "0x%04x:0x%04x r%d, %d ports, feat 0x%x/0x%x\n", @@ -335,9 +322,12 @@ static void sata_pmp_quirks(struct ata_port *ap) if (vendor == 0x1095 && devid == 0x3726) { /* sil3726 quirks */ ata_port_for_each_link(link, ap) { - /* class code report is unreliable */ + /* Class code report is unreliable and SRST + * times out under certain configurations. + */ if (link->pmp < 5) - link->flags |= ATA_LFLAG_ASSUME_ATA; + link->flags |= ATA_LFLAG_NO_SRST | + ATA_LFLAG_ASSUME_ATA; /* port 5 is for SEMB device and it doesn't like SRST */ if (link->pmp == 5) @@ -700,8 +690,6 @@ static int sata_pmp_eh_recover_pmp(struct ata_port *ap, if (ehc->i.action & ATA_EH_RESET) { struct ata_link *tlink; - ata_eh_freeze_port(ap); - /* reset */ rc = ata_eh_reset(link, 0, prereset, softreset, hardreset, postreset); @@ -711,8 +699,6 @@ static int sata_pmp_eh_recover_pmp(struct ata_port *ap, goto fail; } - ata_eh_thaw_port(ap); - /* PMP is reset, SErrors cannot be trusted, scan all */ ata_port_for_each_link(tlink, ap) { struct ata_eh_context *ehc = &tlink->eh_context; @@ -864,6 +850,7 @@ static int sata_pmp_eh_recover(struct ata_port *ap) struct ata_link *pmp_link = &ap->link; struct ata_device *pmp_dev = pmp_link->device; struct ata_eh_context *pmp_ehc = &pmp_link->eh_context; + u32 *gscr = pmp_dev->gscr; struct ata_link *link; struct ata_device *dev; unsigned int err_mask; @@ -901,6 +888,22 @@ static int sata_pmp_eh_recover(struct ata_port *ap) if (rc) goto pmp_fail; + /* PHY event notification can disturb reset and other recovery + * operations. Turn it off. + */ + if (gscr[SATA_PMP_GSCR_FEAT_EN] & SATA_PMP_FEAT_NOTIFY) { + gscr[SATA_PMP_GSCR_FEAT_EN] &= ~SATA_PMP_FEAT_NOTIFY; + + err_mask = sata_pmp_write(pmp_link, SATA_PMP_GSCR_FEAT_EN, + gscr[SATA_PMP_GSCR_FEAT_EN]); + if (err_mask) { + ata_link_printk(pmp_link, KERN_WARNING, + "failed to disable NOTIFY (err_mask=0x%x)\n", + err_mask); + goto pmp_fail; + } + } + /* handle disabled links */ rc = sata_pmp_eh_handle_disabled_links(ap); if (rc) @@ -923,10 +926,10 @@ static int sata_pmp_eh_recover(struct ata_port *ap) /* enable notification */ if (pmp_dev->flags & ATA_DFLAG_AN) { - pmp_dev->gscr[SATA_PMP_GSCR_FEAT_EN] |= SATA_PMP_FEAT_NOTIFY; + gscr[SATA_PMP_GSCR_FEAT_EN] |= SATA_PMP_FEAT_NOTIFY; - err_mask = sata_pmp_write(pmp_dev->link, SATA_PMP_GSCR_FEAT_EN, - pmp_dev->gscr[SATA_PMP_GSCR_FEAT_EN]); + err_mask = sata_pmp_write(pmp_link, SATA_PMP_GSCR_FEAT_EN, + gscr[SATA_PMP_GSCR_FEAT_EN]); if (err_mask) { ata_dev_printk(pmp_dev, KERN_ERR, "failed to write " "PMP_FEAT_EN (Emask=0x%x)\n", err_mask); diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 3ce43920e459..2e6e1622dc6d 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -1082,12 +1082,6 @@ static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc) if (((cdb[4] >> 4) & 0xf) != 0) goto invalid_fld; /* power conditions not supported */ - if (qc->dev->horkage & ATA_HORKAGE_SKIP_PM) { - /* the device lacks PM support, finish without doing anything */ - scmd->result = SAM_STAT_GOOD; - return 1; - } - if (cdb[4] & 0x1) { tf->nsect = 1; /* 1 sector, lba=0 */ @@ -1643,6 +1637,7 @@ defer: /** * ata_scsi_rbuf_get - Map response buffer. + * @cmd: SCSI command containing buffer to be mapped. * @flags: unsigned long variable to store irq enable status * @copy_in: copy in from user buffer * @@ -1960,7 +1955,7 @@ static unsigned int ata_msense_ctl_mode(u8 *buf) /** * ata_msense_rw_recovery - Simulate MODE SENSE r/w error recovery page - * @bufp: output buffer + * @buf: output buffer * * Generate a generic MODE SENSE r/w error recovery page. * diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c index fcabe46f262b..0f3e659db99a 100644 --- a/drivers/ata/pata_ali.c +++ b/drivers/ata/pata_ali.c @@ -177,11 +177,11 @@ static void ali_program_modes(struct ata_port *ap, struct ata_device *adev, stru u8 udma; if (t != NULL) { - t->setup = FIT(t->setup, 1, 8) & 7; - t->act8b = FIT(t->act8b, 1, 8) & 7; - t->rec8b = FIT(t->rec8b, 1, 16) & 15; - t->active = FIT(t->active, 1, 8) & 7; - t->recover = FIT(t->recover, 1, 16) & 15; + t->setup = clamp_val(t->setup, 1, 8) & 7; + t->act8b = clamp_val(t->act8b, 1, 8) & 7; + t->rec8b = clamp_val(t->rec8b, 1, 16) & 15; + t->active = clamp_val(t->active, 1, 8) & 7; + t->recover = clamp_val(t->recover, 1, 16) & 15; pci_write_config_byte(pdev, cas, t->setup); pci_write_config_byte(pdev, cbt, (t->act8b << 4) | t->rec8b); diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c index 26665c396485..57dd00f463d3 100644 --- a/drivers/ata/pata_amd.c +++ b/drivers/ata/pata_amd.c @@ -84,32 +84,32 @@ static void timing_setup(struct ata_port *ap, struct ata_device *adev, int offse /* Configure the address set up timing */ pci_read_config_byte(pdev, offset + 0x0C, &t); - t = (t & ~(3 << ((3 - dn) << 1))) | ((FIT(at.setup, 1, 4) - 1) << ((3 - dn) << 1)); + t = (t & ~(3 << ((3 - dn) << 1))) | ((clamp_val(at.setup, 1, 4) - 1) << ((3 - dn) << 1)); pci_write_config_byte(pdev, offset + 0x0C , t); /* Configure the 8bit I/O timing */ pci_write_config_byte(pdev, offset + 0x0E + (1 - (dn >> 1)), - ((FIT(at.act8b, 1, 16) - 1) << 4) | (FIT(at.rec8b, 1, 16) - 1)); + ((clamp_val(at.act8b, 1, 16) - 1) << 4) | (clamp_val(at.rec8b, 1, 16) - 1)); /* Drive timing */ pci_write_config_byte(pdev, offset + 0x08 + (3 - dn), - ((FIT(at.active, 1, 16) - 1) << 4) | (FIT(at.recover, 1, 16) - 1)); + ((clamp_val(at.active, 1, 16) - 1) << 4) | (clamp_val(at.recover, 1, 16) - 1)); switch (clock) { case 1: - t = at.udma ? (0xc0 | (FIT(at.udma, 2, 5) - 2)) : 0x03; + t = at.udma ? (0xc0 | (clamp_val(at.udma, 2, 5) - 2)) : 0x03; break; case 2: - t = at.udma ? (0xc0 | amd_cyc2udma[FIT(at.udma, 2, 10)]) : 0x03; + t = at.udma ? (0xc0 | amd_cyc2udma[clamp_val(at.udma, 2, 10)]) : 0x03; break; case 3: - t = at.udma ? (0xc0 | amd_cyc2udma[FIT(at.udma, 1, 10)]) : 0x03; + t = at.udma ? (0xc0 | amd_cyc2udma[clamp_val(at.udma, 1, 10)]) : 0x03; break; case 4: - t = at.udma ? (0xc0 | amd_cyc2udma[FIT(at.udma, 1, 15)]) : 0x03; + t = at.udma ? (0xc0 | amd_cyc2udma[clamp_val(at.udma, 1, 15)]) : 0x03; break; default: diff --git a/drivers/ata/pata_at32.c b/drivers/ata/pata_at32.c index 5e104385d6a3..82fb6e273169 100644 --- a/drivers/ata/pata_at32.c +++ b/drivers/ata/pata_at32.c @@ -291,8 +291,6 @@ static int __init pata_at32_probe(struct platform_device *pdev) if (!info) return -ENOMEM; - memset(info, 0, sizeof(struct at32_ide_info)); - info->irq = irq; info->cs = board->cs; diff --git a/drivers/ata/pata_bf54x.c b/drivers/ata/pata_bf54x.c index 9ab89732cf94..55516103626a 100644 --- a/drivers/ata/pata_bf54x.c +++ b/drivers/ata/pata_bf54x.c @@ -911,7 +911,10 @@ static void bfin_bmdma_start(struct ata_queued_cmd *qc) /* Reset all transfer count */ ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) | TFRCNT_RST); - /* Set transfer length to buffer len */ + /* Set ATAPI state machine contorl in terminate sequence */ + ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) | END_ON_TERM); + + /* Set transfer length to buffer len */ for_each_sg(qc->sg, sg, qc->n_elem, si) { ATAPI_SET_XFER_LEN(base, (sg_dma_len(sg) >> 1)); } diff --git a/drivers/ata/pata_cypress.c b/drivers/ata/pata_cypress.c index a9c3218e22fd..2ff62608ae37 100644 --- a/drivers/ata/pata_cypress.c +++ b/drivers/ata/pata_cypress.c @@ -62,14 +62,14 @@ static void cy82c693_set_piomode(struct ata_port *ap, struct ata_device *adev) return; } - time_16 = FIT(t.recover, 0, 15) | (FIT(t.active, 0, 15) << 4); - time_8 = FIT(t.act8b, 0, 15) | (FIT(t.rec8b, 0, 15) << 4); + time_16 = clamp_val(t.recover, 0, 15) | (clamp_val(t.active, 0, 15) << 4); + time_8 = clamp_val(t.act8b, 0, 15) | (clamp_val(t.rec8b, 0, 15) << 4); if (adev->devno == 0) { pci_read_config_dword(pdev, CY82_IDE_ADDRSETUP, &addr); addr &= ~0x0F; /* Mask bits */ - addr |= FIT(t.setup, 0, 15); + addr |= clamp_val(t.setup, 0, 15); pci_write_config_dword(pdev, CY82_IDE_ADDRSETUP, addr); pci_write_config_byte(pdev, CY82_IDE_MASTER_IOR, time_16); @@ -79,7 +79,7 @@ static void cy82c693_set_piomode(struct ata_port *ap, struct ata_device *adev) pci_read_config_dword(pdev, CY82_IDE_ADDRSETUP, &addr); addr &= ~0xF0; /* Mask bits */ - addr |= (FIT(t.setup, 0, 15) << 4); + addr |= (clamp_val(t.setup, 0, 15) << 4); pci_write_config_dword(pdev, CY82_IDE_ADDRSETUP, addr); pci_write_config_byte(pdev, CY82_IDE_SLAVE_IOR, time_16); diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c index 7af4b29cc422..fe7cc8ed4ea4 100644 --- a/drivers/ata/pata_legacy.c +++ b/drivers/ata/pata_legacy.c @@ -343,8 +343,8 @@ static void ht6560a_set_piomode(struct ata_port *ap, struct ata_device *adev) /* Get the timing data in cycles. For now play safe at 50Mhz */ ata_timing_compute(adev, adev->pio_mode, &t, 20000, 1000); - active = FIT(t.active, 2, 15); - recover = FIT(t.recover, 4, 15); + active = clamp_val(t.active, 2, 15); + recover = clamp_val(t.recover, 4, 15); inb(0x3E6); inb(0x3E6); @@ -377,8 +377,8 @@ static void ht6560b_set_piomode(struct ata_port *ap, struct ata_device *adev) /* Get the timing data in cycles. For now play safe at 50Mhz */ ata_timing_compute(adev, adev->pio_mode, &t, 20000, 1000); - active = FIT(t.active, 2, 15); - recover = FIT(t.recover, 2, 16); + active = clamp_val(t.active, 2, 15); + recover = clamp_val(t.recover, 2, 16); recover &= 0x15; inb(0x3E6); @@ -462,9 +462,9 @@ static void opti82c611a_set_piomode(struct ata_port *ap, ata_timing_merge(&t, &tp, &t, ATA_TIMING_SETUP); } - active = FIT(t.active, 2, 17) - 2; - recover = FIT(t.recover, 1, 16) - 1; - setup = FIT(t.setup, 1, 4) - 1; + active = clamp_val(t.active, 2, 17) - 2; + recover = clamp_val(t.recover, 1, 16) - 1; + setup = clamp_val(t.setup, 1, 4) - 1; /* Select the right timing bank for write timing */ rc = ioread8(ap->ioaddr.lbal_addr); @@ -541,9 +541,9 @@ static void opti82c46x_set_piomode(struct ata_port *ap, struct ata_device *adev) ata_timing_merge(&t, &tp, &t, ATA_TIMING_SETUP); } - active = FIT(t.active, 2, 17) - 2; - recover = FIT(t.recover, 1, 16) - 1; - setup = FIT(t.setup, 1, 4) - 1; + active = clamp_val(t.active, 2, 17) - 2; + recover = clamp_val(t.recover, 1, 16) - 1; + setup = clamp_val(t.setup, 1, 4) - 1; /* Select the right timing bank for write timing */ rc = ioread8(ap->ioaddr.lbal_addr); @@ -624,11 +624,11 @@ static void qdi6500_set_piomode(struct ata_port *ap, struct ata_device *adev) ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000); if (ld_qdi->fast) { - active = 8 - FIT(t.active, 1, 8); - recovery = 18 - FIT(t.recover, 3, 18); + active = 8 - clamp_val(t.active, 1, 8); + recovery = 18 - clamp_val(t.recover, 3, 18); } else { - active = 9 - FIT(t.active, 2, 9); - recovery = 15 - FIT(t.recover, 0, 15); + active = 9 - clamp_val(t.active, 2, 9); + recovery = 15 - clamp_val(t.recover, 0, 15); } timing = (recovery << 4) | active | 0x08; @@ -658,11 +658,11 @@ static void qdi6580dp_set_piomode(struct ata_port *ap, struct ata_device *adev) ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000); if (ld_qdi->fast) { - active = 8 - FIT(t.active, 1, 8); - recovery = 18 - FIT(t.recover, 3, 18); + active = 8 - clamp_val(t.active, 1, 8); + recovery = 18 - clamp_val(t.recover, 3, 18); } else { - active = 9 - FIT(t.active, 2, 9); - recovery = 15 - FIT(t.recover, 0, 15); + active = 9 - clamp_val(t.active, 2, 9); + recovery = 15 - clamp_val(t.recover, 0, 15); } timing = (recovery << 4) | active | 0x08; @@ -695,11 +695,11 @@ static void qdi6580_set_piomode(struct ata_port *ap, struct ata_device *adev) ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000); if (ld_qdi->fast) { - active = 8 - FIT(t.active, 1, 8); - recovery = 18 - FIT(t.recover, 3, 18); + active = 8 - clamp_val(t.active, 1, 8); + recovery = 18 - clamp_val(t.recover, 3, 18); } else { - active = 9 - FIT(t.active, 2, 9); - recovery = 15 - FIT(t.recover, 0, 15); + active = 9 - clamp_val(t.active, 2, 9); + recovery = 15 - clamp_val(t.recover, 0, 15); } timing = (recovery << 4) | active | 0x08; ld_qdi->clock[adev->devno] = timing; @@ -830,8 +830,8 @@ static void winbond_set_piomode(struct ata_port *ap, struct ata_device *adev) else ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000); - active = (FIT(t.active, 3, 17) - 1) & 0x0F; - recovery = (FIT(t.recover, 1, 15) + 1) & 0x0F; + active = (clamp_val(t.active, 3, 17) - 1) & 0x0F; + recovery = (clamp_val(t.recover, 1, 15) + 1) & 0x0F; timing = (active << 4) | recovery; winbond_writecfg(ld_winbond->timing, timing, reg); @@ -842,7 +842,7 @@ static void winbond_set_piomode(struct ata_port *ap, struct ata_device *adev) reg |= 0x08; /* FIFO off */ if (!ata_pio_need_iordy(adev)) reg |= 0x02; /* IORDY off */ - reg |= (FIT(t.setup, 0, 3) << 6); + reg |= (clamp_val(t.setup, 0, 3) << 6); winbond_writecfg(ld_winbond->timing, timing + 1, reg); } diff --git a/drivers/ata/pata_ns87410.c b/drivers/ata/pata_ns87410.c index 76d2455bc453..be756b7ef07e 100644 --- a/drivers/ata/pata_ns87410.c +++ b/drivers/ata/pata_ns87410.c @@ -91,9 +91,9 @@ static void ns87410_set_piomode(struct ata_port *ap, struct ata_device *adev) return; } - at.active = FIT(at.active, 2, 16) - 2; - at.setup = FIT(at.setup, 1, 4) - 1; - at.recover = FIT(at.recover, 1, 12) - 1; + at.active = clamp_val(at.active, 2, 16) - 2; + at.setup = clamp_val(at.setup, 1, 4) - 1; + at.recover = clamp_val(at.recover, 1, 12) - 1; idetcr = (at.setup << 6) | (recoverbits[at.recover] << 3) | activebits[at.active]; diff --git a/drivers/ata/pata_ns87415.c b/drivers/ata/pata_ns87415.c index ae92b0049bd5..e0aa7eaaee0a 100644 --- a/drivers/ata/pata_ns87415.c +++ b/drivers/ata/pata_ns87415.c @@ -66,8 +66,8 @@ static void ns87415_set_mode(struct ata_port *ap, struct ata_device *adev, u8 mo ata_timing_compute(adev, adev->pio_mode, &t, T, 0); - clocking = 17 - FIT(t.active, 2, 17); - clocking |= (16 - FIT(t.recover, 1, 16)) << 4; + clocking = 17 - clamp_val(t.active, 2, 17); + clocking |= (16 - clamp_val(t.recover, 1, 16)) << 4; /* Use the same timing for read and write bytes */ clocking |= (clocking << 8); pci_write_config_word(dev, timing, clocking); diff --git a/drivers/ata/pata_qdi.c b/drivers/ata/pata_qdi.c index bf45cf017753..97e5b090d7c2 100644 --- a/drivers/ata/pata_qdi.c +++ b/drivers/ata/pata_qdi.c @@ -60,11 +60,11 @@ static void qdi6500_set_piomode(struct ata_port *ap, struct ata_device *adev) ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000); if (qdi->fast) { - active = 8 - FIT(t.active, 1, 8); - recovery = 18 - FIT(t.recover, 3, 18); + active = 8 - clamp_val(t.active, 1, 8); + recovery = 18 - clamp_val(t.recover, 3, 18); } else { - active = 9 - FIT(t.active, 2, 9); - recovery = 15 - FIT(t.recover, 0, 15); + active = 9 - clamp_val(t.active, 2, 9); + recovery = 15 - clamp_val(t.recover, 0, 15); } timing = (recovery << 4) | active | 0x08; @@ -84,11 +84,11 @@ static void qdi6580_set_piomode(struct ata_port *ap, struct ata_device *adev) ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000); if (qdi->fast) { - active = 8 - FIT(t.active, 1, 8); - recovery = 18 - FIT(t.recover, 3, 18); + active = 8 - clamp_val(t.active, 1, 8); + recovery = 18 - clamp_val(t.recover, 3, 18); } else { - active = 9 - FIT(t.active, 2, 9); - recovery = 15 - FIT(t.recover, 0, 15); + active = 9 - clamp_val(t.active, 2, 9); + recovery = 15 - clamp_val(t.recover, 0, 15); } timing = (recovery << 4) | active | 0x08; diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c index 70d94fb28a5f..69877bd81815 100644 --- a/drivers/ata/pata_sl82c105.c +++ b/drivers/ata/pata_sl82c105.c @@ -216,7 +216,7 @@ static int sl82c105_qc_defer(struct ata_queued_cmd *qc) struct ata_port *alt = host->ports[1 ^ qc->ap->port_no]; int rc; - /* First apply the usual rules */ + /* First apply the usual rules */ rc = ata_std_qc_defer(qc); if (rc != 0) return rc; diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c index 2fea6cbe7755..708ed144ede9 100644 --- a/drivers/ata/pata_via.c +++ b/drivers/ata/pata_via.c @@ -259,15 +259,15 @@ static void via_do_set_mode(struct ata_port *ap, struct ata_device *adev, int mo pci_read_config_byte(pdev, 0x4C, &setup); setup &= ~(3 << shift); - setup |= FIT(t.setup, 1, 4) << shift; /* 1,4 or 1,4 - 1 FIXME */ + setup |= clamp_val(t.setup, 1, 4) << shift; /* 1,4 or 1,4 - 1 FIXME */ pci_write_config_byte(pdev, 0x4C, setup); } /* Load the PIO mode bits */ pci_write_config_byte(pdev, 0x4F - ap->port_no, - ((FIT(t.act8b, 1, 16) - 1) << 4) | (FIT(t.rec8b, 1, 16) - 1)); + ((clamp_val(t.act8b, 1, 16) - 1) << 4) | (clamp_val(t.rec8b, 1, 16) - 1)); pci_write_config_byte(pdev, 0x48 + offset, - ((FIT(t.active, 1, 16) - 1) << 4) | (FIT(t.recover, 1, 16) - 1)); + ((clamp_val(t.active, 1, 16) - 1) << 4) | (clamp_val(t.recover, 1, 16) - 1)); /* Load the UDMA bits according to type */ switch(udma_type) { @@ -275,16 +275,16 @@ static void via_do_set_mode(struct ata_port *ap, struct ata_device *adev, int mo /* BUG() ? */ /* fall through */ case 33: - ut = t.udma ? (0xe0 | (FIT(t.udma, 2, 5) - 2)) : 0x03; + ut = t.udma ? (0xe0 | (clamp_val(t.udma, 2, 5) - 2)) : 0x03; break; case 66: - ut = t.udma ? (0xe8 | (FIT(t.udma, 2, 9) - 2)) : 0x0f; + ut = t.udma ? (0xe8 | (clamp_val(t.udma, 2, 9) - 2)) : 0x0f; break; case 100: - ut = t.udma ? (0xe0 | (FIT(t.udma, 2, 9) - 2)) : 0x07; + ut = t.udma ? (0xe0 | (clamp_val(t.udma, 2, 9) - 2)) : 0x07; break; case 133: - ut = t.udma ? (0xe0 | (FIT(t.udma, 2, 9) - 2)) : 0x07; + ut = t.udma ? (0xe0 | (clamp_val(t.udma, 2, 9) - 2)) : 0x07; break; } diff --git a/drivers/ata/pata_winbond.c b/drivers/ata/pata_winbond.c index 6e52a3573fbf..474528f8fe3d 100644 --- a/drivers/ata/pata_winbond.c +++ b/drivers/ata/pata_winbond.c @@ -75,8 +75,8 @@ static void winbond_set_piomode(struct ata_port *ap, struct ata_device *adev) else ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000); - active = (FIT(t.active, 3, 17) - 1) & 0x0F; - recovery = (FIT(t.recover, 1, 15) + 1) & 0x0F; + active = (clamp_val(t.active, 3, 17) - 1) & 0x0F; + recovery = (clamp_val(t.recover, 1, 15) + 1) & 0x0F; timing = (active << 4) | recovery; winbond_writecfg(winbond->config, timing, reg); @@ -87,7 +87,7 @@ static void winbond_set_piomode(struct ata_port *ap, struct ata_device *adev) reg |= 0x08; /* FIFO off */ if (!ata_pio_need_iordy(adev)) reg |= 0x02; /* IORDY off */ - reg |= (FIT(t.setup, 0, 3) << 6); + reg |= (clamp_val(t.setup, 0, 3) << 6); winbond_writecfg(winbond->config, timing + 1, reg); } diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c index 853559e32315..3924e7209a44 100644 --- a/drivers/ata/sata_fsl.c +++ b/drivers/ata/sata_fsl.c @@ -34,7 +34,7 @@ enum { SATA_FSL_HOST_FLAGS = (ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | - ATA_FLAG_NCQ), + ATA_FLAG_PMP | ATA_FLAG_NCQ), SATA_FSL_MAX_CMDS = SATA_FSL_QUEUE_DEPTH, SATA_FSL_CMD_HDR_SIZE = 16, /* 4 DWORDS */ @@ -395,7 +395,7 @@ static void sata_fsl_qc_prep(struct ata_queued_cmd *qc) cd = (struct command_desc *)pp->cmdentry + tag; cd_paddr = pp->cmdentry_paddr + tag * SATA_FSL_CMD_DESC_SIZE; - ata_tf_to_fis(&qc->tf, 0, 1, (u8 *) &cd->cfis); + ata_tf_to_fis(&qc->tf, qc->dev->link->pmp, 1, (u8 *) &cd->cfis); VPRINTK("Dumping cfis : 0x%x, 0x%x, 0x%x\n", cd->cfis[0], cd->cfis[1], cd->cfis[2]); @@ -438,6 +438,8 @@ static unsigned int sata_fsl_qc_issue(struct ata_queued_cmd *qc) ioread32(CA + hcr_base), ioread32(CE + hcr_base), ioread32(CC + hcr_base)); + iowrite32(qc->dev->link->pmp, CQPMP + hcr_base); + /* Simply queue command to the controller/device */ iowrite32(1 << tag, CQ + hcr_base); @@ -558,11 +560,36 @@ static void sata_fsl_thaw(struct ata_port *ap) ioread32(hcr_base + HCONTROL), ioread32(hcr_base + HSTATUS)); } +static void sata_fsl_pmp_attach(struct ata_port *ap) +{ + struct sata_fsl_host_priv *host_priv = ap->host->private_data; + void __iomem *hcr_base = host_priv->hcr_base; + u32 temp; + + temp = ioread32(hcr_base + HCONTROL); + iowrite32((temp | HCONTROL_PMP_ATTACHED), hcr_base + HCONTROL); +} + +static void sata_fsl_pmp_detach(struct ata_port *ap) +{ + struct sata_fsl_host_priv *host_priv = ap->host->private_data; + void __iomem *hcr_base = host_priv->hcr_base; + u32 temp; + + temp = ioread32(hcr_base + HCONTROL); + temp &= ~HCONTROL_PMP_ATTACHED; + iowrite32(temp, hcr_base + HCONTROL); + + /* enable interrupts on the controller/port */ + temp = ioread32(hcr_base + HCONTROL); + iowrite32((temp | DEFAULT_PORT_IRQ_ENABLE_MASK), hcr_base + HCONTROL); + +} + static int sata_fsl_port_start(struct ata_port *ap) { struct device *dev = ap->host->dev; struct sata_fsl_port_priv *pp; - int retval; void *mem; dma_addr_t mem_dma; struct sata_fsl_host_priv *host_priv = ap->host->private_data; @@ -688,12 +715,13 @@ static int sata_fsl_prereset(struct ata_link *link, unsigned long deadline) } static int sata_fsl_softreset(struct ata_link *link, unsigned int *class, - unsigned long deadline) + unsigned long deadline) { struct ata_port *ap = link->ap; struct sata_fsl_port_priv *pp = ap->private_data; struct sata_fsl_host_priv *host_priv = ap->host->private_data; void __iomem *hcr_base = host_priv->hcr_base; + int pmp = sata_srst_pmp(link); u32 temp; struct ata_taskfile tf; u8 *cfis; @@ -703,6 +731,9 @@ static int sata_fsl_softreset(struct ata_link *link, unsigned int *class, DPRINTK("in xx_softreset\n"); + if (pmp != SATA_PMP_CTRL_PORT) + goto issue_srst; + try_offline_again: /* * Force host controller to go off-line, aborting current operations @@ -746,6 +777,7 @@ try_offline_again: temp = ioread32(hcr_base + HCONTROL); temp |= (HCONTROL_ONLINE_PHY_RST | HCONTROL_SNOOP_ENABLE); + temp |= HCONTROL_PMP_ATTACHED; iowrite32(temp, hcr_base + HCONTROL); temp = ata_wait_register(hcr_base + HSTATUS, ONLINE, 0, 1, 500); @@ -771,7 +803,8 @@ try_offline_again: ata_port_printk(ap, KERN_WARNING, "No Device OR PHYRDY change,Hstatus = 0x%x\n", ioread32(hcr_base + HSTATUS)); - goto err; + *class = ATA_DEV_NONE; + goto out; } /* @@ -783,7 +816,8 @@ try_offline_again: if ((temp & 0xFF) != 0x18) { ata_port_printk(ap, KERN_WARNING, "No Signature Update\n"); - goto err; + *class = ATA_DEV_NONE; + goto out; } else { ata_port_printk(ap, KERN_INFO, "Signature Update detected @ %d msecs\n", @@ -798,6 +832,7 @@ try_offline_again: * reached here, we can send a command to the target device */ +issue_srst: DPRINTK("Sending SRST/device reset\n"); ata_tf_init(link->device, &tf); @@ -808,7 +843,7 @@ try_offline_again: SRST_CMD | CMD_DESC_SNOOP_ENABLE, 0, 0, 5); tf.ctl |= ATA_SRST; /* setup SRST bit in taskfile control reg */ - ata_tf_to_fis(&tf, 0, 0, cfis); + ata_tf_to_fis(&tf, pmp, 0, cfis); DPRINTK("Dumping cfis : 0x%x, 0x%x, 0x%x, 0x%x\n", cfis[0], cfis[1], cfis[2], cfis[3]); @@ -854,8 +889,10 @@ try_offline_again: sata_fsl_setup_cmd_hdr_entry(pp, 0, CMD_DESC_SNOOP_ENABLE, 0, 0, 5); tf.ctl &= ~ATA_SRST; /* 2nd H2D Ctl. register FIS */ - ata_tf_to_fis(&tf, 0, 0, cfis); + ata_tf_to_fis(&tf, pmp, 0, cfis); + if (pmp != SATA_PMP_CTRL_PORT) + iowrite32(pmp, CQPMP + hcr_base); iowrite32(1, CQ + hcr_base); msleep(150); /* ?? */ @@ -886,12 +923,21 @@ try_offline_again: VPRINTK("cereg = 0x%x\n", ioread32(hcr_base + CE)); } +out: return 0; err: return -EIO; } +static void sata_fsl_error_handler(struct ata_port *ap) +{ + + DPRINTK("in xx_error_handler\n"); + sata_pmp_error_handler(ap); + +} + static void sata_fsl_post_internal_cmd(struct ata_queued_cmd *qc) { if (qc->flags & ATA_QCFLAG_FAILED) @@ -905,18 +951,21 @@ static void sata_fsl_post_internal_cmd(struct ata_queued_cmd *qc) static void sata_fsl_error_intr(struct ata_port *ap) { - struct ata_link *link = &ap->link; - struct ata_eh_info *ehi = &link->eh_info; struct sata_fsl_host_priv *host_priv = ap->host->private_data; void __iomem *hcr_base = host_priv->hcr_base; - u32 hstatus, dereg, cereg = 0, SError = 0; + u32 hstatus, dereg=0, cereg = 0, SError = 0; unsigned int err_mask = 0, action = 0; - struct ata_queued_cmd *qc; - int freeze = 0; + int freeze = 0, abort=0; + struct ata_link *link = NULL; + struct ata_queued_cmd *qc = NULL; + struct ata_eh_info *ehi; hstatus = ioread32(hcr_base + HSTATUS); cereg = ioread32(hcr_base + CE); + /* first, analyze and record host port events */ + link = &ap->link; + ehi = &link->eh_info; ata_ehi_clear_desc(ehi); /* @@ -926,42 +975,28 @@ static void sata_fsl_error_intr(struct ata_port *ap) sata_fsl_scr_read(ap, SCR_ERROR, &SError); if (unlikely(SError & 0xFFFF0000)) { sata_fsl_scr_write(ap, SCR_ERROR, SError); - err_mask |= AC_ERR_ATA_BUS; } DPRINTK("error_intr,hStat=0x%x,CE=0x%x,DE =0x%x,SErr=0x%x\n", hstatus, cereg, ioread32(hcr_base + DE), SError); - /* handle single device errors */ - if (cereg) { - /* - * clear the command error, also clears queue to the device - * in error, and we can (re)issue commands to this device. - * When a device is in error all commands queued into the - * host controller and at the device are considered aborted - * and the queue for that device is stopped. Now, after - * clearing the device error, we can issue commands to the - * device to interrogate it to find the source of the error. - */ - dereg = ioread32(hcr_base + DE); - iowrite32(dereg, hcr_base + DE); - iowrite32(cereg, hcr_base + CE); + /* handle fatal errors */ + if (hstatus & FATAL_ERROR_DECODE) { + ehi->err_mask |= AC_ERR_ATA_BUS; + ehi->action |= ATA_EH_SOFTRESET; - DPRINTK("single device error, CE=0x%x, DE=0x%x\n", - ioread32(hcr_base + CE), ioread32(hcr_base + DE)); /* - * We should consider this as non fatal error, and TF must - * be updated as done below. + * Ignore serror in case of fatal errors as we always want + * to do a soft-reset of the FSL SATA controller. Analyzing + * serror may cause libata to schedule a hard-reset action, + * and hard-reset currently does not do controller + * offline/online, causing command timeouts and leads to an + * un-recoverable state, hence make libATA ignore + * autopsy in case of fatal errors. */ - err_mask |= AC_ERR_DEV; - } + ehi->flags |= ATA_EHI_NO_AUTOPSY; - /* handle fatal errors */ - if (hstatus & FATAL_ERROR_DECODE) { - err_mask |= AC_ERR_ATA_BUS; - action |= ATA_EH_RESET; - /* how will fatal error interrupts be completed ?? */ freeze = 1; } @@ -971,30 +1006,83 @@ static void sata_fsl_error_intr(struct ata_port *ap) /* Setup a soft-reset EH action */ ata_ehi_hotplugged(ehi); + ata_ehi_push_desc(ehi, "%s", "PHY RDY changed"); freeze = 1; } - /* record error info */ - qc = ata_qc_from_tag(ap, link->active_tag); + /* handle single device errors */ + if (cereg) { + /* + * clear the command error, also clears queue to the device + * in error, and we can (re)issue commands to this device. + * When a device is in error all commands queued into the + * host controller and at the device are considered aborted + * and the queue for that device is stopped. Now, after + * clearing the device error, we can issue commands to the + * device to interrogate it to find the source of the error. + */ + abort = 1; + + DPRINTK("single device error, CE=0x%x, DE=0x%x\n", + ioread32(hcr_base + CE), ioread32(hcr_base + DE)); - if (qc) + /* find out the offending link and qc */ + if (ap->nr_pmp_links) { + dereg = ioread32(hcr_base + DE); + iowrite32(dereg, hcr_base + DE); + iowrite32(cereg, hcr_base + CE); + + if (dereg < ap->nr_pmp_links) { + link = &ap->pmp_link[dereg]; + ehi = &link->eh_info; + qc = ata_qc_from_tag(ap, link->active_tag); + /* + * We should consider this as non fatal error, + * and TF must be updated as done below. + */ + + err_mask |= AC_ERR_DEV; + + } else { + err_mask |= AC_ERR_HSM; + action |= ATA_EH_HARDRESET; + freeze = 1; + } + } else { + dereg = ioread32(hcr_base + DE); + iowrite32(dereg, hcr_base + DE); + iowrite32(cereg, hcr_base + CE); + + qc = ata_qc_from_tag(ap, link->active_tag); + /* + * We should consider this as non fatal error, + * and TF must be updated as done below. + */ + err_mask |= AC_ERR_DEV; + } + } + + /* record error info */ + if (qc) { qc->err_mask |= err_mask; - else + } else ehi->err_mask |= err_mask; ehi->action |= action; - ehi->serror |= SError; /* freeze or abort */ if (freeze) ata_port_freeze(ap); - else - ata_port_abort(ap); + else if (abort) { + if (qc) + ata_link_abort(qc->dev->link); + else + ata_port_abort(ap); + } } static void sata_fsl_host_intr(struct ata_port *ap) { - struct ata_link *link = &ap->link; struct sata_fsl_host_priv *host_priv = ap->host->private_data; void __iomem *hcr_base = host_priv->hcr_base; u32 hstatus, qc_active = 0; @@ -1017,10 +1105,19 @@ static void sata_fsl_host_intr(struct ata_port *ap) return; } - if (link->sactive) { /* only true for NCQ commands */ + /* Read command completed register */ + qc_active = ioread32(hcr_base + CC); + + VPRINTK("Status of all queues :\n"); + VPRINTK("qc_active/CC = 0x%x, CA = 0x%x, CE=0x%x,CQ=0x%x,apqa=0x%x\n", + qc_active, + ioread32(hcr_base + CA), + ioread32(hcr_base + CE), + ioread32(hcr_base + CQ), + ap->qc_active); + + if (qc_active & ap->qc_active) { int i; - /* Read command completed register */ - qc_active = ioread32(hcr_base + CC); /* clear CC bit, this will also complete the interrupt */ iowrite32(qc_active, hcr_base + CC); @@ -1032,8 +1129,9 @@ static void sata_fsl_host_intr(struct ata_port *ap) for (i = 0; i < SATA_FSL_QUEUE_DEPTH; i++) { if (qc_active & (1 << i)) { qc = ata_qc_from_tag(ap, i); - if (qc) + if (qc) { ata_qc_complete(qc); + } DPRINTK ("completing ncq cmd,tag=%d,CC=0x%x,CA=0x%x\n", i, ioread32(hcr_base + CC), @@ -1042,19 +1140,21 @@ static void sata_fsl_host_intr(struct ata_port *ap) } return; - } else if (ap->qc_active) { + } else if ((ap->qc_active & (1 << ATA_TAG_INTERNAL))) { iowrite32(1, hcr_base + CC); - qc = ata_qc_from_tag(ap, link->active_tag); + qc = ata_qc_from_tag(ap, ATA_TAG_INTERNAL); - DPRINTK("completing non-ncq cmd, tag=%d,CC=0x%x\n", - link->active_tag, ioread32(hcr_base + CC)); + DPRINTK("completing non-ncq cmd, CC=0x%x\n", + ioread32(hcr_base + CC)); - if (qc) + if (qc) { ata_qc_complete(qc); + } } else { /* Spurious Interrupt!! */ DPRINTK("spurious interrupt!!, CC = 0x%x\n", ioread32(hcr_base + CC)); + iowrite32(qc_active, hcr_base + CC); return; } } @@ -1130,9 +1230,6 @@ static int sata_fsl_init_controller(struct ata_host *host) iowrite32(0x00000FFFF, hcr_base + CE); iowrite32(0x00000FFFF, hcr_base + DE); - /* initially assuming no Port multiplier, set CQPMP to 0 */ - iowrite32(0x0, hcr_base + CQPMP); - /* * host controller will be brought on-line, during xx_port_start() * callback, that should also initiate the OOB, COMINIT sequence @@ -1154,8 +1251,8 @@ static struct scsi_host_template sata_fsl_sht = { .dma_boundary = ATA_DMA_BOUNDARY, }; -static const struct ata_port_operations sata_fsl_ops = { - .inherits = &sata_port_ops, +static struct ata_port_operations sata_fsl_ops = { + .inherits = &sata_pmp_port_ops, .qc_prep = sata_fsl_qc_prep, .qc_issue = sata_fsl_qc_issue, @@ -1168,10 +1265,15 @@ static const struct ata_port_operations sata_fsl_ops = { .thaw = sata_fsl_thaw, .prereset = sata_fsl_prereset, .softreset = sata_fsl_softreset, + .pmp_softreset = sata_fsl_softreset, + .error_handler = sata_fsl_error_handler, .post_internal_cmd = sata_fsl_post_internal_cmd, .port_start = sata_fsl_port_start, .port_stop = sata_fsl_port_stop, + + .pmp_attach = sata_fsl_pmp_attach, + .pmp_detach = sata_fsl_pmp_detach, }; static const struct ata_port_info sata_fsl_port_info[] = { diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index bb73b2222627..acf347f71a2f 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -72,7 +72,7 @@ #include <linux/libata.h> #define DRV_NAME "sata_mv" -#define DRV_VERSION "1.20" +#define DRV_VERSION "1.24" enum { /* BAR's are enumerated in terms of pci_resource_start() terms */ @@ -122,14 +122,17 @@ enum { /* Host Flags */ MV_FLAG_DUAL_HC = (1 << 30), /* two SATA Host Controllers */ MV_FLAG_IRQ_COALESCE = (1 << 29), /* IRQ coalescing capability */ - /* SoC integrated controllers, no PCI interface */ - MV_FLAG_SOC = (1 << 28), MV_COMMON_FLAGS = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO | ATA_FLAG_NO_ATAPI | ATA_FLAG_PIO_POLLING, + MV_6XXX_FLAGS = MV_FLAG_IRQ_COALESCE, + MV_GENIIE_FLAGS = MV_COMMON_FLAGS | MV_6XXX_FLAGS | + ATA_FLAG_PMP | ATA_FLAG_ACPI_SATA | + ATA_FLAG_NCQ | ATA_FLAG_AN, + CRQB_FLAG_READ = (1 << 0), CRQB_TAG_SHIFT = 1, CRQB_IOID_SHIFT = 6, /* CRQB Gen-II/IIE IO Id shift */ @@ -197,13 +200,6 @@ enum { HC_MAIN_RSVD = (0x7f << 25), /* bits 31-25 */ HC_MAIN_RSVD_5 = (0x1fff << 19), /* bits 31-19 */ HC_MAIN_RSVD_SOC = (0x3fffffb << 6), /* bits 31-9, 7-6 */ - HC_MAIN_MASKED_IRQS = (TRAN_LO_DONE | TRAN_HI_DONE | - PORTS_0_3_COAL_DONE | PORTS_4_7_COAL_DONE | - PORTS_0_7_COAL_DONE | GPIO_INT | TWSI_INT | - HC_MAIN_RSVD), - HC_MAIN_MASKED_IRQS_5 = (PORTS_0_3_COAL_DONE | PORTS_4_7_COAL_DONE | - HC_MAIN_RSVD_5), - HC_MAIN_MASKED_IRQS_SOC = (PORTS_0_3_COAL_DONE | HC_MAIN_RSVD_SOC), /* SATAHC registers */ HC_CFG_OFS = 0, @@ -221,6 +217,7 @@ enum { SATA_STATUS_OFS = 0x300, /* ctrl, err regs follow status */ SATA_ACTIVE_OFS = 0x350, SATA_FIS_IRQ_CAUSE_OFS = 0x364, + SATA_FIS_IRQ_AN = (1 << 9), /* async notification */ LTMODE_OFS = 0x30c, LTMODE_BIT8 = (1 << 8), /* unknown, but necessary */ @@ -357,12 +354,12 @@ enum { MV_HP_ERRATA_50XXB2 = (1 << 2), MV_HP_ERRATA_60X1B2 = (1 << 3), MV_HP_ERRATA_60X1C0 = (1 << 4), - MV_HP_ERRATA_XX42A0 = (1 << 5), MV_HP_GEN_I = (1 << 6), /* Generation I: 50xx */ MV_HP_GEN_II = (1 << 7), /* Generation II: 60xx */ MV_HP_GEN_IIE = (1 << 8), /* Generation IIE: 6042/7042 */ MV_HP_PCIE = (1 << 9), /* PCIe bus/regs: 7042 */ MV_HP_CUT_THROUGH = (1 << 10), /* can use EDMA cut-through */ + MV_HP_FLAG_SOC = (1 << 11), /* SystemOnChip, no PCI */ /* Port private flags (pp_flags) */ MV_PP_FLAG_EDMA_EN = (1 << 0), /* is EDMA engine enabled? */ @@ -375,7 +372,7 @@ enum { #define IS_GEN_II(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_II) #define IS_GEN_IIE(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_IIE) #define IS_PCIE(hpriv) ((hpriv)->hp_flags & MV_HP_PCIE) -#define HAS_PCI(host) (!((host)->ports[0]->flags & MV_FLAG_SOC)) +#define IS_SOC(hpriv) ((hpriv)->hp_flags & MV_HP_FLAG_SOC) #define WINDOW_CTRL(i) (0x20030 + ((i) << 4)) #define WINDOW_BASE(i) (0x20034 + ((i) << 4)) @@ -459,6 +456,7 @@ struct mv_port_signal { struct mv_host_priv { u32 hp_flags; + u32 main_irq_mask; struct mv_port_signal signal[8]; const struct mv_hw_ops *ops; int n_ports; @@ -640,25 +638,19 @@ static const struct ata_port_info mv_port_info[] = { .port_ops = &mv6_ops, }, { /* chip_6042 */ - .flags = MV_COMMON_FLAGS | MV_6XXX_FLAGS | - ATA_FLAG_PMP | ATA_FLAG_ACPI_SATA | - ATA_FLAG_NCQ, + .flags = MV_GENIIE_FLAGS, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = ATA_UDMA6, .port_ops = &mv_iie_ops, }, { /* chip_7042 */ - .flags = MV_COMMON_FLAGS | MV_6XXX_FLAGS | - ATA_FLAG_PMP | ATA_FLAG_ACPI_SATA | - ATA_FLAG_NCQ, + .flags = MV_GENIIE_FLAGS, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = ATA_UDMA6, .port_ops = &mv_iie_ops, }, { /* chip_soc */ - .flags = MV_COMMON_FLAGS | MV_6XXX_FLAGS | - ATA_FLAG_PMP | ATA_FLAG_ACPI_SATA | - ATA_FLAG_NCQ | MV_FLAG_SOC, + .flags = MV_GENIIE_FLAGS, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = ATA_UDMA6, .port_ops = &mv_iie_ops, @@ -818,12 +810,7 @@ static void mv_set_edma_ptrs(void __iomem *port_mmio, writel((pp->crqb_dma >> 16) >> 16, port_mmio + EDMA_REQ_Q_BASE_HI_OFS); writelfl((pp->crqb_dma & EDMA_REQ_Q_BASE_LO_MASK) | index, port_mmio + EDMA_REQ_Q_IN_PTR_OFS); - - if (hpriv->hp_flags & MV_HP_ERRATA_XX42A0) - writelfl((pp->crqb_dma & 0xffffffff) | index, - port_mmio + EDMA_REQ_Q_OUT_PTR_OFS); - else - writelfl(index, port_mmio + EDMA_REQ_Q_OUT_PTR_OFS); + writelfl(index, port_mmio + EDMA_REQ_Q_OUT_PTR_OFS); /* * initialize response queue @@ -833,17 +820,38 @@ static void mv_set_edma_ptrs(void __iomem *port_mmio, WARN_ON(pp->crpb_dma & 0xff); writel((pp->crpb_dma >> 16) >> 16, port_mmio + EDMA_RSP_Q_BASE_HI_OFS); - - if (hpriv->hp_flags & MV_HP_ERRATA_XX42A0) - writelfl((pp->crpb_dma & 0xffffffff) | index, - port_mmio + EDMA_RSP_Q_IN_PTR_OFS); - else - writelfl(index, port_mmio + EDMA_RSP_Q_IN_PTR_OFS); - + writelfl(index, port_mmio + EDMA_RSP_Q_IN_PTR_OFS); writelfl((pp->crpb_dma & EDMA_RSP_Q_BASE_LO_MASK) | index, port_mmio + EDMA_RSP_Q_OUT_PTR_OFS); } +static void mv_set_main_irq_mask(struct ata_host *host, + u32 disable_bits, u32 enable_bits) +{ + struct mv_host_priv *hpriv = host->private_data; + u32 old_mask, new_mask; + + old_mask = hpriv->main_irq_mask; + new_mask = (old_mask & ~disable_bits) | enable_bits; + if (new_mask != old_mask) { + hpriv->main_irq_mask = new_mask; + writelfl(new_mask, hpriv->main_irq_mask_addr); + } +} + +static void mv_enable_port_irqs(struct ata_port *ap, + unsigned int port_bits) +{ + unsigned int shift, hardport, port = ap->port_no; + u32 disable_bits, enable_bits; + + MV_PORT_TO_SHIFT_AND_HARDPORT(port, shift, hardport); + + disable_bits = (DONE_IRQ | ERR_IRQ) << shift; + enable_bits = port_bits << shift; + mv_set_main_irq_mask(ap->host, disable_bits, enable_bits); +} + /** * mv_start_dma - Enable eDMA engine * @base: port base address @@ -886,9 +894,11 @@ static void mv_start_dma(struct ata_port *ap, void __iomem *port_mmio, mv_edma_cfg(ap, want_ncq); /* clear FIS IRQ Cause */ - writelfl(0, port_mmio + SATA_FIS_IRQ_CAUSE_OFS); + if (IS_GEN_IIE(hpriv)) + writelfl(0, port_mmio + SATA_FIS_IRQ_CAUSE_OFS); mv_set_edma_ptrs(port_mmio, hpriv, pp); + mv_enable_port_irqs(ap, DONE_IRQ|ERR_IRQ); writelfl(EDMA_EN, port_mmio + EDMA_CMD_OFS); pp->pp_flags |= MV_PP_FLAG_EDMA_EN; @@ -1231,7 +1241,7 @@ static void mv_edma_cfg(struct ata_port *ap, int want_ncq) cfg |= (1 << 23); /* do not mask PM field in rx'd FIS */ cfg |= (1 << 22); /* enab 4-entry host queue cache */ - if (HAS_PCI(ap->host)) + if (!IS_SOC(hpriv)) cfg |= (1 << 18); /* enab early completion */ if (hpriv->hp_flags & MV_HP_CUT_THROUGH) cfg |= (1 << 17); /* enab cut-thru (dis stor&forwrd) */ @@ -1341,6 +1351,7 @@ out_port_free_dma_mem: static void mv_port_stop(struct ata_port *ap) { mv_stop_edma(ap); + mv_enable_port_irqs(ap, 0); mv_port_free_dma_mem(ap); } @@ -1582,6 +1593,7 @@ static unsigned int mv_qc_issue(struct ata_queued_cmd *qc) * shadow block, etc registers. */ mv_stop_edma(ap); + mv_enable_port_irqs(ap, ERR_IRQ); mv_pmp_select(ap, qc->dev->link->pmp); return ata_sff_qc_issue(qc); } @@ -1670,6 +1682,18 @@ static void mv_pmp_eh_prep(struct ata_port *ap, unsigned int pmp_map) } } +static int mv_req_q_empty(struct ata_port *ap) +{ + void __iomem *port_mmio = mv_ap_base(ap); + u32 in_ptr, out_ptr; + + in_ptr = (readl(port_mmio + EDMA_REQ_Q_IN_PTR_OFS) + >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK; + out_ptr = (readl(port_mmio + EDMA_REQ_Q_OUT_PTR_OFS) + >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK; + return (in_ptr == out_ptr); /* 1 == queue_is_empty */ +} + static int mv_handle_fbs_ncq_dev_err(struct ata_port *ap) { struct mv_port_priv *pp = ap->private_data; @@ -1703,7 +1727,7 @@ static int mv_handle_fbs_ncq_dev_err(struct ata_port *ap) ap->qc_active, failed_links, ap->nr_active_links); - if (ap->nr_active_links <= failed_links) { + if (ap->nr_active_links <= failed_links && mv_req_q_empty(ap)) { mv_process_crpb_entries(ap, pp); mv_stop_edma(ap); mv_eh_freeze(ap); @@ -1812,6 +1836,7 @@ static void mv_err_intr(struct ata_port *ap) { void __iomem *port_mmio = mv_ap_base(ap); u32 edma_err_cause, eh_freeze_mask, serr = 0; + u32 fis_cause = 0; struct mv_port_priv *pp = ap->private_data; struct mv_host_priv *hpriv = ap->host->private_data; unsigned int action = 0, err_mask = 0; @@ -1821,16 +1846,19 @@ static void mv_err_intr(struct ata_port *ap) /* * Read and clear the SError and err_cause bits. + * For GenIIe, if EDMA_ERR_TRANS_IRQ_7 is set, we also must read/clear + * the FIS_IRQ_CAUSE register before clearing edma_err_cause. */ sata_scr_read(&ap->link, SCR_ERROR, &serr); sata_scr_write_flush(&ap->link, SCR_ERROR, serr); edma_err_cause = readl(port_mmio + EDMA_ERR_IRQ_CAUSE_OFS); + if (IS_GEN_IIE(hpriv) && (edma_err_cause & EDMA_ERR_TRANS_IRQ_7)) { + fis_cause = readl(port_mmio + SATA_FIS_IRQ_CAUSE_OFS); + writelfl(~fis_cause, port_mmio + SATA_FIS_IRQ_CAUSE_OFS); + } writelfl(~edma_err_cause, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS); - ata_port_printk(ap, KERN_INFO, "%s: err_cause=%08x pp_flags=0x%x\n", - __func__, edma_err_cause, pp->pp_flags); - if (edma_err_cause & EDMA_ERR_DEV) { /* * Device errors during FIS-based switching operation @@ -1844,6 +1872,18 @@ static void mv_err_intr(struct ata_port *ap) ata_ehi_clear_desc(ehi); ata_ehi_push_desc(ehi, "edma_err_cause=%08x pp_flags=%08x", edma_err_cause, pp->pp_flags); + + if (IS_GEN_IIE(hpriv) && (edma_err_cause & EDMA_ERR_TRANS_IRQ_7)) { + ata_ehi_push_desc(ehi, "fis_cause=%08x", fis_cause); + if (fis_cause & SATA_FIS_IRQ_AN) { + u32 ec = edma_err_cause & + ~(EDMA_ERR_TRANS_IRQ_7 | EDMA_ERR_IRQ_TRANSIENT); + sata_async_notification(ap); + if (!ec) + return; /* Just an AN; no need for the nukes */ + ata_ehi_push_desc(ehi, "SDB notify"); + } + } /* * All generations share these EDMA error cause bits: */ @@ -2162,20 +2202,20 @@ static irqreturn_t mv_interrupt(int irq, void *dev_instance) struct ata_host *host = dev_instance; struct mv_host_priv *hpriv = host->private_data; unsigned int handled = 0; - u32 main_irq_cause, main_irq_mask; + u32 main_irq_cause, pending_irqs; spin_lock(&host->lock); main_irq_cause = readl(hpriv->main_irq_cause_addr); - main_irq_mask = readl(hpriv->main_irq_mask_addr); + pending_irqs = main_irq_cause & hpriv->main_irq_mask; /* * Deal with cases where we either have nothing pending, or have read * a bogus register value which can indicate HW removal or PCI fault. */ - if ((main_irq_cause & main_irq_mask) && (main_irq_cause != 0xffffffffU)) { - if (unlikely((main_irq_cause & PCI_ERR) && HAS_PCI(host))) + if (pending_irqs && main_irq_cause != 0xffffffffU) { + if (unlikely((pending_irqs & PCI_ERR) && !IS_SOC(hpriv))) handled = mv_pci_error(host, hpriv->base); else - handled = mv_host_intr(host, main_irq_cause); + handled = mv_host_intr(host, pending_irqs); } spin_unlock(&host->lock); return IRQ_RETVAL(handled); @@ -2373,7 +2413,6 @@ static void mv_reset_pci_bus(struct ata_host *host, void __iomem *mmio) ZERO(MV_PCI_DISC_TIMER); ZERO(MV_PCI_MSI_TRIGGER); writel(0x000100ff, mmio + MV_PCI_XBAR_TMOUT_OFS); - ZERO(PCI_HC_MAIN_IRQ_MASK_OFS); ZERO(MV_PCI_SERR_MASK); ZERO(hpriv->irq_cause_ofs); ZERO(hpriv->irq_mask_ofs); @@ -2495,7 +2534,7 @@ static void mv6_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio, hp_flags & (MV_HP_ERRATA_60X1B2 | MV_HP_ERRATA_60X1C0); int fix_phy_mode4 = hp_flags & (MV_HP_ERRATA_60X1B2 | MV_HP_ERRATA_60X1C0); - u32 m2, tmp; + u32 m2, m3; if (fix_phy_mode2) { m2 = readl(port_mmio + PHY_MODE2); @@ -2512,28 +2551,37 @@ static void mv6_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio, udelay(200); } - /* who knows what this magic does */ - tmp = readl(port_mmio + PHY_MODE3); - tmp &= ~0x7F800000; - tmp |= 0x2A800000; - writel(tmp, port_mmio + PHY_MODE3); + /* + * Gen-II/IIe PHY_MODE3 errata RM#2: + * Achieves better receiver noise performance than the h/w default: + */ + m3 = readl(port_mmio + PHY_MODE3); + m3 = (m3 & 0x1f) | (0x5555601 << 5); + + /* Guideline 88F5182 (GL# SATA-S11) */ + if (IS_SOC(hpriv)) + m3 &= ~0x1c; if (fix_phy_mode4) { u32 m4; m4 = readl(port_mmio + PHY_MODE4); - if (hp_flags & MV_HP_ERRATA_60X1B2) - tmp = readl(port_mmio + PHY_MODE3); - /* workaround for errata FEr SATA#10 (part 1) */ m4 = (m4 & ~(1 << 1)) | (1 << 0); - writel(m4, port_mmio + PHY_MODE4); + /* enforce bit restrictions on GenIIe devices */ + if (IS_GEN_IIE(hpriv)) + m4 = (m4 & ~0x5DE3FFFC) | (1 << 2); - if (hp_flags & MV_HP_ERRATA_60X1B2) - writel(tmp, port_mmio + PHY_MODE3); + writel(m4, port_mmio + PHY_MODE4); } + /* + * Workaround for 60x1-B2 errata SATA#13: + * Any write to PHY_MODE4 (above) may corrupt PHY_MODE3, + * so we must always rewrite PHY_MODE3 after PHY_MODE4. + */ + writel(m3, port_mmio + PHY_MODE3); /* Revert values of pre-emphasis and signal amps to the saved ones */ m2 = readl(port_mmio + PHY_MODE2); @@ -2728,6 +2776,7 @@ static int mv_hardreset(struct ata_link *link, unsigned int *class, rc = sata_link_hardreset(link, timing, deadline + extra, &online, NULL); + rc = online ? -EAGAIN : rc; if (rc) return rc; sata_scr_read(link, SCR_STATUS, &sstatus); @@ -2744,32 +2793,18 @@ static int mv_hardreset(struct ata_link *link, unsigned int *class, static void mv_eh_freeze(struct ata_port *ap) { - struct mv_host_priv *hpriv = ap->host->private_data; - unsigned int shift, hardport, port = ap->port_no; - u32 main_irq_mask; - - /* FIXME: handle coalescing completion events properly */ - mv_stop_edma(ap); - MV_PORT_TO_SHIFT_AND_HARDPORT(port, shift, hardport); - - /* disable assertion of portN err, done events */ - main_irq_mask = readl(hpriv->main_irq_mask_addr); - main_irq_mask &= ~((DONE_IRQ | ERR_IRQ) << shift); - writelfl(main_irq_mask, hpriv->main_irq_mask_addr); + mv_enable_port_irqs(ap, 0); } static void mv_eh_thaw(struct ata_port *ap) { struct mv_host_priv *hpriv = ap->host->private_data; - unsigned int shift, hardport, port = ap->port_no; + unsigned int port = ap->port_no; + unsigned int hardport = mv_hardport_from_port(port); void __iomem *hc_mmio = mv_hc_base_from_port(hpriv->base, port); void __iomem *port_mmio = mv_ap_base(ap); - u32 main_irq_mask, hc_irq_cause; - - /* FIXME: handle coalescing completion events properly */ - - MV_PORT_TO_SHIFT_AND_HARDPORT(port, shift, hardport); + u32 hc_irq_cause; /* clear EDMA errors on this port */ writel(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS); @@ -2779,10 +2814,7 @@ static void mv_eh_thaw(struct ata_port *ap) hc_irq_cause &= ~((DEV_IRQ | DMA_IRQ) << hardport); writelfl(hc_irq_cause, hc_mmio + HC_IRQ_CAUSE_OFS); - /* enable assertion of portN err, done events */ - main_irq_mask = readl(hpriv->main_irq_mask_addr); - main_irq_mask |= ((DONE_IRQ | ERR_IRQ) << shift); - writelfl(main_irq_mask, hpriv->main_irq_mask_addr); + mv_enable_port_irqs(ap, ERR_IRQ); } /** @@ -2840,7 +2872,7 @@ static unsigned int mv_in_pcix_mode(struct ata_host *host) void __iomem *mmio = hpriv->base; u32 reg; - if (!HAS_PCI(host) || !IS_PCIE(hpriv)) + if (IS_SOC(hpriv) || !IS_PCIE(hpriv)) return 0; /* not PCI-X capable */ reg = readl(mmio + MV_PCI_MODE_OFS); if ((reg & MV_PCI_MODE_MASK) == 0) @@ -2967,10 +2999,7 @@ static int mv_chip_id(struct ata_host *host, unsigned int board_idx) hp_flags |= MV_HP_CUT_THROUGH; switch (pdev->revision) { - case 0x0: - hp_flags |= MV_HP_ERRATA_XX42A0; - break; - case 0x1: + case 0x2: /* Rev.B0: the first/only public release */ hp_flags |= MV_HP_ERRATA_60X1C0; break; default: @@ -2982,7 +3011,7 @@ static int mv_chip_id(struct ata_host *host, unsigned int board_idx) break; case chip_soc: hpriv->ops = &mv_soc_ops; - hp_flags |= MV_HP_ERRATA_60X1C0; + hp_flags |= MV_HP_FLAG_SOC | MV_HP_ERRATA_60X1C0; break; default: @@ -3026,16 +3055,16 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx) if (rc) goto done; - if (HAS_PCI(host)) { - hpriv->main_irq_cause_addr = mmio + PCI_HC_MAIN_IRQ_CAUSE_OFS; - hpriv->main_irq_mask_addr = mmio + PCI_HC_MAIN_IRQ_MASK_OFS; - } else { + if (IS_SOC(hpriv)) { hpriv->main_irq_cause_addr = mmio + SOC_HC_MAIN_IRQ_CAUSE_OFS; hpriv->main_irq_mask_addr = mmio + SOC_HC_MAIN_IRQ_MASK_OFS; + } else { + hpriv->main_irq_cause_addr = mmio + PCI_HC_MAIN_IRQ_CAUSE_OFS; + hpriv->main_irq_mask_addr = mmio + PCI_HC_MAIN_IRQ_MASK_OFS; } /* global interrupt mask: 0 == mask everything */ - writel(0, hpriv->main_irq_mask_addr); + mv_set_main_irq_mask(host, ~0, 0); n_hc = mv_get_hc_count(host->ports[0]->flags); @@ -3057,7 +3086,7 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx) mv_port_init(&ap->ioaddr, port_mmio); #ifdef CONFIG_PCI - if (HAS_PCI(host)) { + if (!IS_SOC(hpriv)) { unsigned int offset = port_mmio - mmio; ata_port_pbar_desc(ap, MV_PRIMARY_BAR, -1, "mmio"); ata_port_pbar_desc(ap, MV_PRIMARY_BAR, offset, "port"); @@ -3077,31 +3106,18 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx) writelfl(0, hc_mmio + HC_IRQ_CAUSE_OFS); } - if (HAS_PCI(host)) { + if (!IS_SOC(hpriv)) { /* Clear any currently outstanding host interrupt conditions */ writelfl(0, mmio + hpriv->irq_cause_ofs); /* and unmask interrupt generation for host regs */ writelfl(hpriv->unmask_all_irqs, mmio + hpriv->irq_mask_ofs); - if (IS_GEN_I(hpriv)) - writelfl(~HC_MAIN_MASKED_IRQS_5, - hpriv->main_irq_mask_addr); - else - writelfl(~HC_MAIN_MASKED_IRQS, - hpriv->main_irq_mask_addr); - - VPRINTK("HC MAIN IRQ cause/mask=0x%08x/0x%08x " - "PCI int cause/mask=0x%08x/0x%08x\n", - readl(hpriv->main_irq_cause_addr), - readl(hpriv->main_irq_mask_addr), - readl(mmio + hpriv->irq_cause_ofs), - readl(mmio + hpriv->irq_mask_ofs)); - } else { - writelfl(~HC_MAIN_MASKED_IRQS_SOC, - hpriv->main_irq_mask_addr); - VPRINTK("HC MAIN IRQ cause/mask=0x%08x/0x%08x\n", - readl(hpriv->main_irq_cause_addr), - readl(hpriv->main_irq_mask_addr)); + + /* + * enable only global host interrupts for now. + * The per-port interrupts get done later as ports are set up. + */ + mv_set_main_irq_mask(host, 0, PCI_ERR); } done: return rc; diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c index 5a10dc5048ad..030665ba76b7 100644 --- a/drivers/ata/sata_promise.c +++ b/drivers/ata/sata_promise.c @@ -53,7 +53,15 @@ enum { PDC_MMIO_BAR = 3, PDC_MAX_PRD = LIBATA_MAX_PRD - 1, /* -1 for ASIC PRD bug workaround */ - /* register offsets */ + /* host register offsets (from host->iomap[PDC_MMIO_BAR]) */ + PDC_INT_SEQMASK = 0x40, /* Mask of asserted SEQ INTs */ + PDC_FLASH_CTL = 0x44, /* Flash control register */ + PDC_SATA_PLUG_CSR = 0x6C, /* SATA Plug control/status reg */ + PDC2_SATA_PLUG_CSR = 0x60, /* SATAII Plug control/status reg */ + PDC_TBG_MODE = 0x41C, /* TBG mode (not SATAII) */ + PDC_SLEW_CTL = 0x470, /* slew rate control reg (not SATAII) */ + + /* per-port ATA register offsets (from ap->ioaddr.cmd_addr) */ PDC_FEATURE = 0x04, /* Feature/Error reg (per port) */ PDC_SECTOR_COUNT = 0x08, /* Sector count reg (per port) */ PDC_SECTOR_NUMBER = 0x0C, /* Sector number reg (per port) */ @@ -63,14 +71,11 @@ enum { PDC_COMMAND = 0x1C, /* Command/status reg (per port) */ PDC_ALTSTATUS = 0x38, /* Alternate-status/device-control reg (per port) */ PDC_PKT_SUBMIT = 0x40, /* Command packet pointer addr */ - PDC_INT_SEQMASK = 0x40, /* Mask of asserted SEQ INTs */ - PDC_FLASH_CTL = 0x44, /* Flash control register */ PDC_GLOBAL_CTL = 0x48, /* Global control/status (per port) */ PDC_CTLSTAT = 0x60, /* IDE control and status (per port) */ - PDC_SATA_PLUG_CSR = 0x6C, /* SATA Plug control/status reg */ - PDC2_SATA_PLUG_CSR = 0x60, /* SATAII Plug control/status reg */ - PDC_TBG_MODE = 0x41C, /* TBG mode (not SATAII) */ - PDC_SLEW_CTL = 0x470, /* slew rate control reg (not SATAII) */ + + /* per-port SATA register offsets (from ap->ioaddr.scr_addr) */ + PDC_PHYMODE4 = 0x14, /* PDC_GLOBAL_CTL bit definitions */ PDC_PH_ERR = (1 << 8), /* PCI error while loading packet */ @@ -134,7 +139,7 @@ struct pdc_port_priv { static int pdc_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val); static int pdc_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val); -static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); +static int pdc_ata_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); static int pdc_common_port_start(struct ata_port *ap); static int pdc_sata_port_start(struct ata_port *ap); static void pdc_qc_prep(struct ata_queued_cmd *qc); @@ -332,12 +337,12 @@ static int pdc_sata_port_start(struct ata_port *ap) /* fix up PHYMODE4 align timing */ if (ap->flags & PDC_FLAG_GEN_II) { - void __iomem *mmio = ap->ioaddr.scr_addr; + void __iomem *sata_mmio = ap->ioaddr.scr_addr; unsigned int tmp; - tmp = readl(mmio + 0x014); + tmp = readl(sata_mmio + PDC_PHYMODE4); tmp = (tmp & ~3) | 1; /* set bits 1:0 = 0:1 */ - writel(tmp, mmio + 0x014); + writel(tmp, sata_mmio + PDC_PHYMODE4); } return 0; @@ -345,32 +350,32 @@ static int pdc_sata_port_start(struct ata_port *ap) static void pdc_reset_port(struct ata_port *ap) { - void __iomem *mmio = ap->ioaddr.cmd_addr + PDC_CTLSTAT; + void __iomem *ata_ctlstat_mmio = ap->ioaddr.cmd_addr + PDC_CTLSTAT; unsigned int i; u32 tmp; for (i = 11; i > 0; i--) { - tmp = readl(mmio); + tmp = readl(ata_ctlstat_mmio); if (tmp & PDC_RESET) break; udelay(100); tmp |= PDC_RESET; - writel(tmp, mmio); + writel(tmp, ata_ctlstat_mmio); } tmp &= ~PDC_RESET; - writel(tmp, mmio); - readl(mmio); /* flush */ + writel(tmp, ata_ctlstat_mmio); + readl(ata_ctlstat_mmio); /* flush */ } static int pdc_pata_cable_detect(struct ata_port *ap) { u8 tmp; - void __iomem *mmio = ap->ioaddr.cmd_addr + PDC_CTLSTAT + 0x03; + void __iomem *ata_mmio = ap->ioaddr.cmd_addr; - tmp = readb(mmio); + tmp = readb(ata_mmio + PDC_CTLSTAT + 3); if (tmp & 0x01) return ATA_CBL_PATA40; return ATA_CBL_PATA80; @@ -557,31 +562,25 @@ static void pdc_qc_prep(struct ata_queued_cmd *qc) switch (qc->tf.protocol) { case ATA_PROT_DMA: pdc_fill_sg(qc); - /* fall through */ - + /*FALLTHROUGH*/ case ATA_PROT_NODATA: i = pdc_pkt_header(&qc->tf, qc->ap->prd_dma, qc->dev->devno, pp->pkt); - if (qc->tf.flags & ATA_TFLAG_LBA48) i = pdc_prep_lba48(&qc->tf, pp->pkt, i); else i = pdc_prep_lba28(&qc->tf, pp->pkt, i); - pdc_pkt_footer(&qc->tf, pp->pkt, i); break; - case ATAPI_PROT_PIO: pdc_fill_sg(qc); break; - case ATAPI_PROT_DMA: pdc_fill_sg(qc); /*FALLTHROUGH*/ case ATAPI_PROT_NODATA: pdc_atapi_pkt(qc); break; - default: break; } @@ -611,7 +610,7 @@ static unsigned int pdc_sata_ata_port_to_ata_no(const struct ata_port *ap) unsigned int nr_ports = pdc_sata_nr_ports(ap); unsigned int i; - for(i = 0; i < nr_ports && host->ports[i] != ap; ++i) + for (i = 0; i < nr_ports && host->ports[i] != ap; ++i) ; BUG_ON(i >= nr_ports); return pdc_port_no_to_ata_no(i, pdc_is_sataii_tx4(ap->flags)); @@ -624,14 +623,14 @@ static unsigned int pdc_sata_hotplug_offset(const struct ata_port *ap) static void pdc_freeze(struct ata_port *ap) { - void __iomem *mmio = ap->ioaddr.cmd_addr; + void __iomem *ata_mmio = ap->ioaddr.cmd_addr; u32 tmp; - tmp = readl(mmio + PDC_CTLSTAT); + tmp = readl(ata_mmio + PDC_CTLSTAT); tmp |= PDC_IRQ_DISABLE; tmp &= ~PDC_DMA_ENABLE; - writel(tmp, mmio + PDC_CTLSTAT); - readl(mmio + PDC_CTLSTAT); /* flush */ + writel(tmp, ata_mmio + PDC_CTLSTAT); + readl(ata_mmio + PDC_CTLSTAT); /* flush */ } static void pdc_sata_freeze(struct ata_port *ap) @@ -659,17 +658,17 @@ static void pdc_sata_freeze(struct ata_port *ap) static void pdc_thaw(struct ata_port *ap) { - void __iomem *mmio = ap->ioaddr.cmd_addr; + void __iomem *ata_mmio = ap->ioaddr.cmd_addr; u32 tmp; /* clear IRQ */ - readl(mmio + PDC_INT_SEQMASK); + readl(ata_mmio + PDC_COMMAND); /* turn IRQ back on */ - tmp = readl(mmio + PDC_CTLSTAT); + tmp = readl(ata_mmio + PDC_CTLSTAT); tmp &= ~PDC_IRQ_DISABLE; - writel(tmp, mmio + PDC_CTLSTAT); - readl(mmio + PDC_CTLSTAT); /* flush */ + writel(tmp, ata_mmio + PDC_CTLSTAT); + readl(ata_mmio + PDC_CTLSTAT); /* flush */ } static void pdc_sata_thaw(struct ata_port *ap) @@ -743,11 +742,11 @@ static void pdc_error_intr(struct ata_port *ap, struct ata_queued_cmd *qc, ata_port_abort(ap); } -static inline unsigned int pdc_host_intr(struct ata_port *ap, - struct ata_queued_cmd *qc) +static unsigned int pdc_host_intr(struct ata_port *ap, + struct ata_queued_cmd *qc) { unsigned int handled = 0; - void __iomem *port_mmio = ap->ioaddr.cmd_addr; + void __iomem *ata_mmio = ap->ioaddr.cmd_addr; u32 port_status, err_mask; err_mask = PDC_ERR_MASK; @@ -755,7 +754,7 @@ static inline unsigned int pdc_host_intr(struct ata_port *ap, err_mask &= ~PDC1_ERR_MASK; else err_mask &= ~PDC2_ERR_MASK; - port_status = readl(port_mmio + PDC_GLOBAL_CTL); + port_status = readl(ata_mmio + PDC_GLOBAL_CTL); if (unlikely(port_status & err_mask)) { pdc_error_intr(ap, qc, port_status, err_mask); return 1; @@ -770,7 +769,6 @@ static inline unsigned int pdc_host_intr(struct ata_port *ap, ata_qc_complete(qc); handled = 1; break; - default: ap->stats.idle_irq++; break; @@ -781,10 +779,9 @@ static inline unsigned int pdc_host_intr(struct ata_port *ap, static void pdc_irq_clear(struct ata_port *ap) { - struct ata_host *host = ap->host; - void __iomem *mmio = host->iomap[PDC_MMIO_BAR]; + void __iomem *ata_mmio = ap->ioaddr.cmd_addr; - readl(mmio + PDC_INT_SEQMASK); + readl(ata_mmio + PDC_COMMAND); } static irqreturn_t pdc_interrupt(int irq, void *dev_instance) @@ -794,7 +791,7 @@ static irqreturn_t pdc_interrupt(int irq, void *dev_instance) u32 mask = 0; unsigned int i, tmp; unsigned int handled = 0; - void __iomem *mmio_base; + void __iomem *host_mmio; unsigned int hotplug_offset, ata_no; u32 hotplug_status; int is_sataii_tx4; @@ -806,7 +803,7 @@ static irqreturn_t pdc_interrupt(int irq, void *dev_instance) return IRQ_NONE; } - mmio_base = host->iomap[PDC_MMIO_BAR]; + host_mmio = host->iomap[PDC_MMIO_BAR]; spin_lock(&host->lock); @@ -815,26 +812,26 @@ static irqreturn_t pdc_interrupt(int irq, void *dev_instance) hotplug_offset = PDC2_SATA_PLUG_CSR; else hotplug_offset = PDC_SATA_PLUG_CSR; - hotplug_status = readl(mmio_base + hotplug_offset); + hotplug_status = readl(host_mmio + hotplug_offset); if (hotplug_status & 0xff) - writel(hotplug_status | 0xff, mmio_base + hotplug_offset); + writel(hotplug_status | 0xff, host_mmio + hotplug_offset); hotplug_status &= 0xff; /* clear uninteresting bits */ /* reading should also clear interrupts */ - mask = readl(mmio_base + PDC_INT_SEQMASK); + mask = readl(host_mmio + PDC_INT_SEQMASK); if (mask == 0xffffffff && hotplug_status == 0) { VPRINTK("QUICK EXIT 2\n"); goto done_irq; } - mask &= 0xffff; /* only 16 tags possible */ + mask &= 0xffff; /* only 16 SEQIDs possible */ if (mask == 0 && hotplug_status == 0) { VPRINTK("QUICK EXIT 3\n"); goto done_irq; } - writel(mask, mmio_base + PDC_INT_SEQMASK); + writel(mask, host_mmio + PDC_INT_SEQMASK); is_sataii_tx4 = pdc_is_sataii_tx4(host->ports[0]->flags); @@ -875,23 +872,24 @@ done_irq: return IRQ_RETVAL(handled); } -static inline void pdc_packet_start(struct ata_queued_cmd *qc) +static void pdc_packet_start(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; struct pdc_port_priv *pp = ap->private_data; - void __iomem *mmio = ap->host->iomap[PDC_MMIO_BAR]; + void __iomem *host_mmio = ap->host->iomap[PDC_MMIO_BAR]; + void __iomem *ata_mmio = ap->ioaddr.cmd_addr; unsigned int port_no = ap->port_no; u8 seq = (u8) (port_no + 1); VPRINTK("ENTER, ap %p\n", ap); - writel(0x00000001, mmio + (seq * 4)); - readl(mmio + (seq * 4)); /* flush */ + writel(0x00000001, host_mmio + (seq * 4)); + readl(host_mmio + (seq * 4)); /* flush */ pp->pkt[2] = seq; wmb(); /* flush PRD, pkt writes */ - writel(pp->pkt_dma, ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); - readl(ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); /* flush */ + writel(pp->pkt_dma, ata_mmio + PDC_PKT_SUBMIT); + readl(ata_mmio + PDC_PKT_SUBMIT); /* flush */ } static unsigned int pdc_qc_issue(struct ata_queued_cmd *qc) @@ -909,11 +907,9 @@ static unsigned int pdc_qc_issue(struct ata_queued_cmd *qc) case ATA_PROT_DMA: pdc_packet_start(qc); return 0; - default: break; } - return ata_sff_qc_issue(qc); } @@ -987,7 +983,7 @@ static void pdc_ata_setup_port(struct ata_port *ap, static void pdc_host_init(struct ata_host *host) { - void __iomem *mmio = host->iomap[PDC_MMIO_BAR]; + void __iomem *host_mmio = host->iomap[PDC_MMIO_BAR]; int is_gen2 = host->ports[0]->flags & PDC_FLAG_GEN_II; int hotplug_offset; u32 tmp; @@ -1004,38 +1000,38 @@ static void pdc_host_init(struct ata_host *host) */ /* enable BMR_BURST, maybe change FIFO_SHD to 8 dwords */ - tmp = readl(mmio + PDC_FLASH_CTL); + tmp = readl(host_mmio + PDC_FLASH_CTL); tmp |= 0x02000; /* bit 13 (enable bmr burst) */ if (!is_gen2) tmp |= 0x10000; /* bit 16 (fifo threshold at 8 dw) */ - writel(tmp, mmio + PDC_FLASH_CTL); + writel(tmp, host_mmio + PDC_FLASH_CTL); /* clear plug/unplug flags for all ports */ - tmp = readl(mmio + hotplug_offset); - writel(tmp | 0xff, mmio + hotplug_offset); + tmp = readl(host_mmio + hotplug_offset); + writel(tmp | 0xff, host_mmio + hotplug_offset); /* unmask plug/unplug ints */ - tmp = readl(mmio + hotplug_offset); - writel(tmp & ~0xff0000, mmio + hotplug_offset); + tmp = readl(host_mmio + hotplug_offset); + writel(tmp & ~0xff0000, host_mmio + hotplug_offset); /* don't initialise TBG or SLEW on 2nd generation chips */ if (is_gen2) return; /* reduce TBG clock to 133 Mhz. */ - tmp = readl(mmio + PDC_TBG_MODE); + tmp = readl(host_mmio + PDC_TBG_MODE); tmp &= ~0x30000; /* clear bit 17, 16*/ tmp |= 0x10000; /* set bit 17:16 = 0:1 */ - writel(tmp, mmio + PDC_TBG_MODE); + writel(tmp, host_mmio + PDC_TBG_MODE); - readl(mmio + PDC_TBG_MODE); /* flush */ + readl(host_mmio + PDC_TBG_MODE); /* flush */ msleep(10); /* adjust slew rate control register. */ - tmp = readl(mmio + PDC_SLEW_CTL); + tmp = readl(host_mmio + PDC_SLEW_CTL); tmp &= 0xFFFFF03F; /* clear bit 11 ~ 6 */ tmp |= 0x00000900; /* set bit 11-9 = 100b , bit 8-6 = 100 */ - writel(tmp, mmio + PDC_SLEW_CTL); + writel(tmp, host_mmio + PDC_SLEW_CTL); } static int pdc_ata_init_one(struct pci_dev *pdev, @@ -1045,7 +1041,7 @@ static int pdc_ata_init_one(struct pci_dev *pdev, const struct ata_port_info *pi = &pdc_port_info[ent->driver_data]; const struct ata_port_info *ppi[PDC_MAX_PORTS]; struct ata_host *host; - void __iomem *base; + void __iomem *host_mmio; int n_ports, i, rc; int is_sataii_tx4; @@ -1062,7 +1058,7 @@ static int pdc_ata_init_one(struct pci_dev *pdev, pcim_pin_device(pdev); if (rc) return rc; - base = pcim_iomap_table(pdev)[PDC_MMIO_BAR]; + host_mmio = pcim_iomap_table(pdev)[PDC_MMIO_BAR]; /* determine port configuration and setup host */ n_ports = 2; @@ -1072,7 +1068,7 @@ static int pdc_ata_init_one(struct pci_dev *pdev, ppi[i] = pi; if (pi->flags & PDC_FLAG_SATA_PATA) { - u8 tmp = readb(base + PDC_FLASH_CTL+1); + u8 tmp = readb(host_mmio + PDC_FLASH_CTL + 1); if (!(tmp & 0x80)) ppi[n_ports++] = pi + 1; } @@ -1088,13 +1084,13 @@ static int pdc_ata_init_one(struct pci_dev *pdev, for (i = 0; i < host->n_ports; i++) { struct ata_port *ap = host->ports[i]; unsigned int ata_no = pdc_port_no_to_ata_no(i, is_sataii_tx4); - unsigned int port_offset = 0x200 + ata_no * 0x80; + unsigned int ata_offset = 0x200 + ata_no * 0x80; unsigned int scr_offset = 0x400 + ata_no * 0x100; - pdc_ata_setup_port(ap, base + port_offset, base + scr_offset); + pdc_ata_setup_port(ap, host_mmio + ata_offset, host_mmio + scr_offset); ata_port_pbar_desc(ap, PDC_MMIO_BAR, -1, "mmio"); - ata_port_pbar_desc(ap, PDC_MMIO_BAR, port_offset, "port"); + ata_port_pbar_desc(ap, PDC_MMIO_BAR, ata_offset, "ata"); } /* initialize adapter */ diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index 27a110110077..8ee6b5b4ede7 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -899,14 +899,25 @@ static bool sil24_qc_fill_rtf(struct ata_queued_cmd *qc) static void sil24_pmp_attach(struct ata_port *ap) { + u32 *gscr = ap->link.device->gscr; + sil24_config_pmp(ap, 1); sil24_init_port(ap); + + if (sata_pmp_gscr_vendor(gscr) == 0x11ab && + sata_pmp_gscr_devid(gscr) == 0x4140) { + ata_port_printk(ap, KERN_INFO, + "disabling NCQ support due to sil24-mv4140 quirk\n"); + ap->flags &= ~ATA_FLAG_NCQ; + } } static void sil24_pmp_detach(struct ata_port *ap) { sil24_init_port(ap); sil24_config_pmp(ap, 0); + + ap->flags |= ATA_FLAG_NCQ; } static int sil24_pmp_hardreset(struct ata_link *link, unsigned int *class, diff --git a/drivers/base/core.c b/drivers/base/core.c index 3eeac5a78581..422cfcad486d 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -760,6 +760,21 @@ static void device_remove_class_symlinks(struct device *dev) } /** + * dev_set_name - set a device name + * @dev: device + */ +int dev_set_name(struct device *dev, const char *fmt, ...) +{ + va_list vargs; + + va_start(vargs, fmt); + vsnprintf(dev->bus_id, sizeof(dev->bus_id), fmt, vargs); + va_end(vargs); + return 0; +} +EXPORT_SYMBOL_GPL(dev_set_name); + +/** * device_add - add device to device hierarchy. * @dev: device. * @@ -1084,11 +1099,13 @@ static void device_create_release(struct device *dev) } /** - * device_create - creates a device and registers it with sysfs + * device_create_vargs - creates a device and registers it with sysfs * @class: pointer to the struct class that this device should be registered to * @parent: pointer to the parent struct device of this new device, if any * @devt: the dev_t for the char device to be added + * @drvdata: the data to be added to the device for callbacks * @fmt: string for the device's name + * @args: va_list for the device's name * * This function can be used by char device classes. A struct device * will be created in sysfs, registered to the specified class. @@ -1104,10 +1121,10 @@ static void device_create_release(struct device *dev) * Note: the struct class passed to this function must have previously * been created with a call to class_create(). */ -struct device *device_create(struct class *class, struct device *parent, - dev_t devt, const char *fmt, ...) +struct device *device_create_vargs(struct class *class, struct device *parent, + dev_t devt, void *drvdata, const char *fmt, + va_list args) { - va_list args; struct device *dev = NULL; int retval = -ENODEV; @@ -1124,10 +1141,9 @@ struct device *device_create(struct class *class, struct device *parent, dev->class = class; dev->parent = parent; dev->release = device_create_release; + dev_set_drvdata(dev, drvdata); - va_start(args, fmt); vsnprintf(dev->bus_id, BUS_ID_SIZE, fmt, args); - va_end(args); retval = device_register(dev); if (retval) goto error; @@ -1138,6 +1154,78 @@ error: kfree(dev); return ERR_PTR(retval); } +EXPORT_SYMBOL_GPL(device_create_vargs); + +/** + * device_create_drvdata - creates a device and registers it with sysfs + * @class: pointer to the struct class that this device should be registered to + * @parent: pointer to the parent struct device of this new device, if any + * @devt: the dev_t for the char device to be added + * @drvdata: the data to be added to the device for callbacks + * @fmt: string for the device's name + * + * This function can be used by char device classes. A struct device + * will be created in sysfs, registered to the specified class. + * + * A "dev" file will be created, showing the dev_t for the device, if + * the dev_t is not 0,0. + * If a pointer to a parent struct device is passed in, the newly created + * struct device will be a child of that device in sysfs. + * The pointer to the struct device will be returned from the call. + * Any further sysfs files that might be required can be created using this + * pointer. + * + * Note: the struct class passed to this function must have previously + * been created with a call to class_create(). + */ +struct device *device_create_drvdata(struct class *class, + struct device *parent, + dev_t devt, + void *drvdata, + const char *fmt, ...) +{ + va_list vargs; + struct device *dev; + + va_start(vargs, fmt); + dev = device_create_vargs(class, parent, devt, drvdata, fmt, vargs); + va_end(vargs); + return dev; +} +EXPORT_SYMBOL_GPL(device_create_drvdata); + +/** + * device_create - creates a device and registers it with sysfs + * @class: pointer to the struct class that this device should be registered to + * @parent: pointer to the parent struct device of this new device, if any + * @devt: the dev_t for the char device to be added + * @fmt: string for the device's name + * + * This function can be used by char device classes. A struct device + * will be created in sysfs, registered to the specified class. + * + * A "dev" file will be created, showing the dev_t for the device, if + * the dev_t is not 0,0. + * If a pointer to a parent struct device is passed in, the newly created + * struct device will be a child of that device in sysfs. + * The pointer to the struct device will be returned from the call. + * Any further sysfs files that might be required can be created using this + * pointer. + * + * Note: the struct class passed to this function must have previously + * been created with a call to class_create(). + */ +struct device *device_create(struct class *class, struct device *parent, + dev_t devt, const char *fmt, ...) +{ + va_list vargs; + struct device *dev; + + va_start(vargs, fmt); + dev = device_create_vargs(class, parent, devt, NULL, fmt, vargs); + va_end(vargs); + return dev; +} EXPORT_SYMBOL_GPL(device_create); static int __match_devt(struct device *dev, void *data) diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 7b76fd3b93a4..45cc3d9eacb8 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -418,7 +418,7 @@ void __suspend_report_result(const char *function, void *fn, int ret) { if (ret) { printk(KERN_ERR "%s(): ", function); - print_fn_descriptor_symbol("%s() returns ", (unsigned long)fn); + print_fn_descriptor_symbol("%s returns ", fn); printk("%d\n", ret); } } diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c index c9751b2b57e6..7516baff3bb9 100644 --- a/drivers/block/amiflop.c +++ b/drivers/block/amiflop.c @@ -1714,10 +1714,10 @@ static int __init amiga_floppy_init(void) int i, ret; if (!MACH_IS_AMIGA) - return -ENXIO; + return -ENODEV; if (!AMIGAHW_PRESENT(AMI_FLOPPY)) - return -ENXIO; + return -ENODEV; if (register_blkdev(FLOPPY_MAJOR,"fd")) return -EBUSY; @@ -1755,7 +1755,7 @@ static int __init amiga_floppy_init(void) if (!floppy_queue) goto out_queue; - ret = -ENXIO; + ret = -ENODEV; if (fd_probe_drives() < 1) /* No usable drives */ goto out_probe; diff --git a/drivers/block/brd.c b/drivers/block/brd.c index a196ef7f147f..680cdfc00b90 100644 --- a/drivers/block/brd.c +++ b/drivers/block/brd.c @@ -447,6 +447,7 @@ static struct brd_device *brd_alloc(int i) disk->fops = &brd_fops; disk->private_data = brd; disk->queue = brd->brd_queue; + disk->flags |= GENHD_FL_SUPPRESS_PARTITION_INFO; sprintf(disk->disk_name, "ram%d", i); set_capacity(disk, rd_size * 2); diff --git a/drivers/block/viodasd.c b/drivers/block/viodasd.c index ebfe038d859e..f1c8feb5510b 100644 --- a/drivers/block/viodasd.c +++ b/drivers/block/viodasd.c @@ -3,7 +3,7 @@ * Authors: Dave Boutcher <boutcher@us.ibm.com> * Ryan Arnold <ryanarn@us.ibm.com> * Colin Devilbiss <devilbis@us.ibm.com> - * Stephen Rothwell <sfr@au1.ibm.com> + * Stephen Rothwell * * (C) Copyright 2000-2004 IBM Corporation * diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index 84e064ffee52..dd7ea203f940 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c @@ -260,6 +260,10 @@ static int virtblk_probe(struct virtio_device *vdev) if (virtio_has_feature(vdev, VIRTIO_BLK_F_BARRIER)) blk_queue_ordered(vblk->disk->queue, QUEUE_ORDERED_TAG, NULL); + /* If disk is read-only in the host, the guest should obey */ + if (virtio_has_feature(vdev, VIRTIO_BLK_F_RO)) + set_disk_ro(vblk->disk, 1); + /* Host must always specify the capacity. */ vdev->config->get(vdev, offsetof(struct virtio_blk_config, capacity), &cap, sizeof(cap)); @@ -311,6 +315,7 @@ static void virtblk_remove(struct virtio_device *vdev) /* Stop all the virtqueues. */ vdev->config->reset(vdev); + del_gendisk(vblk->disk); blk_cleanup_queue(vblk->disk->queue); put_disk(vblk->disk); mempool_destroy(vblk->pool); @@ -325,7 +330,7 @@ static struct virtio_device_id id_table[] = { static unsigned int features[] = { VIRTIO_BLK_F_BARRIER, VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX, - VIRTIO_BLK_F_GEOMETRY, + VIRTIO_BLK_F_GEOMETRY, VIRTIO_BLK_F_RO, }; static struct virtio_driver virtio_blk = { diff --git a/drivers/block/z2ram.c b/drivers/block/z2ram.c index 2d5853cbd4b0..be20a67f1fa8 100644 --- a/drivers/block/z2ram.c +++ b/drivers/block/z2ram.c @@ -332,7 +332,7 @@ z2_init(void) int ret; if (!MACH_IS_AMIGA) - return -ENXIO; + return -ENODEV; ret = -EBUSY; if (register_blkdev(Z2RAM_MAJOR, DEVICE_NAME)) diff --git a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c index 5245a4a0ba74..9d0dfe6e0d63 100644 --- a/drivers/cdrom/viocd.c +++ b/drivers/cdrom/viocd.c @@ -6,7 +6,7 @@ * Authors: Dave Boutcher <boutcher@us.ibm.com> * Ryan Arnold <ryanarn@us.ibm.com> * Colin Devilbiss <devilbis@us.ibm.com> - * Stephen Rothwell <sfr@au1.ibm.com> + * Stephen Rothwell * * (C) Copyright 2000-2004 IBM Corporation * diff --git a/drivers/char/drm/drm.h b/drivers/char/drm/drm.h index 6874f31ca8ca..3a05c6d5ebe1 100644 --- a/drivers/char/drm/drm.h +++ b/drivers/char/drm/drm.h @@ -471,7 +471,6 @@ struct drm_irq_busid { enum drm_vblank_seq_type { _DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */ _DRM_VBLANK_RELATIVE = 0x1, /**< Wait for given number of vblanks */ - _DRM_VBLANK_FLIP = 0x8000000, /**< Scheduled buffer swap should flip */ _DRM_VBLANK_NEXTONMISS = 0x10000000, /**< If missed, wait for next vblank */ _DRM_VBLANK_SECONDARY = 0x20000000, /**< Secondary display controller */ _DRM_VBLANK_SIGNAL = 0x40000000 /**< Send signal instead of blocking */ @@ -504,21 +503,6 @@ union drm_wait_vblank { struct drm_wait_vblank_reply reply; }; -enum drm_modeset_ctl_cmd { - _DRM_PRE_MODESET = 1, - _DRM_POST_MODESET = 2, -}; - -/** - * DRM_IOCTL_MODESET_CTL ioctl argument type - * - * \sa drmModesetCtl(). - */ -struct drm_modeset_ctl { - unsigned long arg; - enum drm_modeset_ctl_cmd cmd; -}; - /** * DRM_IOCTL_AGP_ENABLE ioctl argument type. * @@ -603,7 +587,6 @@ struct drm_set_version { #define DRM_IOCTL_GET_CLIENT DRM_IOWR(0x05, struct drm_client) #define DRM_IOCTL_GET_STATS DRM_IOR( 0x06, struct drm_stats) #define DRM_IOCTL_SET_VERSION DRM_IOWR(0x07, struct drm_set_version) -#define DRM_IOCTL_MODESET_CTL DRM_IOW(0x08, struct drm_modeset_ctl) #define DRM_IOCTL_SET_UNIQUE DRM_IOW( 0x10, struct drm_unique) #define DRM_IOCTL_AUTH_MAGIC DRM_IOW( 0x11, struct drm_auth) diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h index 213b3ca3468e..0764b662b339 100644 --- a/drivers/char/drm/drmP.h +++ b/drivers/char/drm/drmP.h @@ -100,8 +100,10 @@ struct drm_device; #define DRIVER_HAVE_DMA 0x20 #define DRIVER_HAVE_IRQ 0x40 #define DRIVER_IRQ_SHARED 0x80 +#define DRIVER_IRQ_VBL 0x100 #define DRIVER_DMA_QUEUE 0x200 #define DRIVER_FB_DMA 0x400 +#define DRIVER_IRQ_VBL2 0x800 /***********************************************************************/ /** \name Begin the DRM... */ @@ -577,52 +579,10 @@ struct drm_driver { int (*context_dtor) (struct drm_device *dev, int context); int (*kernel_context_switch) (struct drm_device *dev, int old, int new); - void (*kernel_context_switch_unlock) (struct drm_device * dev); - /** - * get_vblank_counter - get raw hardware vblank counter - * @dev: DRM device - * @crtc: counter to fetch - * - * Driver callback for fetching a raw hardware vblank counter - * for @crtc. If a device doesn't have a hardware counter, the - * driver can simply return the value of drm_vblank_count and - * make the enable_vblank() and disable_vblank() hooks into no-ops, - * leaving interrupts enabled at all times. - * - * Wraparound handling and loss of events due to modesetting is dealt - * with in the DRM core code. - * - * RETURNS - * Raw vblank counter value. - */ - u32 (*get_vblank_counter) (struct drm_device *dev, int crtc); - - /** - * enable_vblank - enable vblank interrupt events - * @dev: DRM device - * @crtc: which irq to enable - * - * Enable vblank interrupts for @crtc. If the device doesn't have - * a hardware vblank counter, this routine should be a no-op, since - * interrupts will have to stay on to keep the count accurate. - * - * RETURNS - * Zero on success, appropriate errno if the given @crtc's vblank - * interrupt cannot be enabled. - */ - int (*enable_vblank) (struct drm_device *dev, int crtc); - - /** - * disable_vblank - disable vblank interrupt events - * @dev: DRM device - * @crtc: which irq to enable - * - * Disable vblank interrupts for @crtc. If the device doesn't have - * a hardware vblank counter, this routine should be a no-op, since - * interrupts will have to stay on to keep the count accurate. - */ - void (*disable_vblank) (struct drm_device *dev, int crtc); - int (*dri_library_name) (struct drm_device *dev, char * buf); + void (*kernel_context_switch_unlock) (struct drm_device *dev); + int (*vblank_wait) (struct drm_device *dev, unsigned int *sequence); + int (*vblank_wait2) (struct drm_device *dev, unsigned int *sequence); + int (*dri_library_name) (struct drm_device *dev, char *buf); /** * Called by \c drm_device_is_agp. Typically used to determine if a @@ -641,7 +601,7 @@ struct drm_driver { irqreturn_t(*irq_handler) (DRM_IRQ_ARGS); void (*irq_preinstall) (struct drm_device *dev); - int (*irq_postinstall) (struct drm_device *dev); + void (*irq_postinstall) (struct drm_device *dev); void (*irq_uninstall) (struct drm_device *dev); void (*reclaim_buffers) (struct drm_device *dev, struct drm_file * file_priv); @@ -770,21 +730,13 @@ struct drm_device { /** \name VBLANK IRQ support */ /*@{ */ - wait_queue_head_t *vbl_queue; /**< VBLANK wait queue */ - atomic_t *_vblank_count; /**< number of VBLANK interrupts (driver must alloc the right number of counters) */ + wait_queue_head_t vbl_queue; /**< VBLANK wait queue */ + atomic_t vbl_received; + atomic_t vbl_received2; /**< number of secondary VBLANK interrupts */ spinlock_t vbl_lock; - struct list_head *vbl_sigs; /**< signal list to send on VBLANK */ - atomic_t vbl_signal_pending; /* number of signals pending on all crtcs*/ - atomic_t *vblank_refcount; /* number of users of vblank interrupts per crtc */ - u32 *last_vblank; /* protected by dev->vbl_lock, used */ - /* for wraparound handling */ - u32 *vblank_offset; /* used to track how many vblanks */ - int *vblank_enabled; /* so we don't call enable more than - once per disable */ - u32 *vblank_premodeset; /* were lost during modeset */ - struct timer_list vblank_disable_timer; - - unsigned long max_vblank_count; /**< size of vblank counter register */ + struct list_head vbl_sigs; /**< signal list to send on VBLANK */ + struct list_head vbl_sigs2; /**< signals to send on secondary VBLANK */ + unsigned int vbl_pending; spinlock_t tasklet_lock; /**< For drm_locked_tasklet */ void (*locked_tasklet_func)(struct drm_device *dev); @@ -804,7 +756,6 @@ struct drm_device { #ifdef __alpha__ struct pci_controller *hose; #endif - int num_crtcs; /**< Number of CRTCs on this device */ struct drm_sg_mem *sg; /**< Scatter gather memory */ void *dev_private; /**< device private data */ struct drm_sigdata sigdata; /**< For block_all_signals */ @@ -1039,19 +990,11 @@ extern void drm_driver_irq_preinstall(struct drm_device *dev); extern void drm_driver_irq_postinstall(struct drm_device *dev); extern void drm_driver_irq_uninstall(struct drm_device *dev); -extern int drm_vblank_init(struct drm_device *dev, int num_crtcs); -extern int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *filp); -extern int drm_vblank_wait(struct drm_device * dev, unsigned int *vbl_seq); -extern void drm_locked_tasklet(struct drm_device *dev, void(*func)(struct drm_device*)); -extern u32 drm_vblank_count(struct drm_device *dev, int crtc); -extern void drm_update_vblank_count(struct drm_device *dev, int crtc); -extern void drm_handle_vblank(struct drm_device *dev, int crtc); -extern int drm_vblank_get(struct drm_device *dev, int crtc); -extern void drm_vblank_put(struct drm_device *dev, int crtc); - - /* Modesetting support */ -extern int drm_modeset_ctl(struct drm_device *dev, void *data, +extern int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int drm_vblank_wait(struct drm_device *dev, unsigned int *vbl_seq); +extern void drm_vbl_send_signals(struct drm_device *dev); +extern void drm_locked_tasklet(struct drm_device *dev, void(*func)(struct drm_device*)); /* AGP/GART support (drm_agpsupport.h) */ extern struct drm_agp_head *drm_agp_init(struct drm_device *dev); diff --git a/drivers/char/drm/drm_fops.c b/drivers/char/drm/drm_fops.c index 68f0da801ed8..d2e6da85f58a 100644 --- a/drivers/char/drm/drm_fops.c +++ b/drivers/char/drm/drm_fops.c @@ -323,7 +323,6 @@ int drm_release(struct inode *inode, struct file *filp) struct drm_file *file_priv = filp->private_data; struct drm_device *dev = file_priv->minor->dev; int retcode = 0; - unsigned long irqflags; lock_kernel(); @@ -355,11 +354,9 @@ int drm_release(struct inode *inode, struct file *filp) */ do{ - spin_lock_irqsave(&dev->lock.spinlock, - irqflags); + spin_lock_bh(&dev->lock.spinlock); locked = dev->lock.idle_has_lock; - spin_unlock_irqrestore(&dev->lock.spinlock, - irqflags); + spin_unlock_bh(&dev->lock.spinlock); if (locked) break; schedule(); diff --git a/drivers/char/drm/drm_irq.c b/drivers/char/drm/drm_irq.c index 286f9d61e7d5..089c015c01d1 100644 --- a/drivers/char/drm/drm_irq.c +++ b/drivers/char/drm/drm_irq.c @@ -71,117 +71,6 @@ int drm_irq_by_busid(struct drm_device *dev, void *data, return 0; } -static void vblank_disable_fn(unsigned long arg) -{ - struct drm_device *dev = (struct drm_device *)arg; - unsigned long irqflags; - int i; - - for (i = 0; i < dev->num_crtcs; i++) { - spin_lock_irqsave(&dev->vbl_lock, irqflags); - if (atomic_read(&dev->vblank_refcount[i]) == 0 && - dev->vblank_enabled[i]) { - dev->driver->disable_vblank(dev, i); - dev->vblank_enabled[i] = 0; - } - spin_unlock_irqrestore(&dev->vbl_lock, irqflags); - } -} - -static void drm_vblank_cleanup(struct drm_device *dev) -{ - /* Bail if the driver didn't call drm_vblank_init() */ - if (dev->num_crtcs == 0) - return; - - del_timer(&dev->vblank_disable_timer); - - vblank_disable_fn((unsigned long)dev); - - drm_free(dev->vbl_queue, sizeof(*dev->vbl_queue) * dev->num_crtcs, - DRM_MEM_DRIVER); - drm_free(dev->vbl_sigs, sizeof(*dev->vbl_sigs) * dev->num_crtcs, - DRM_MEM_DRIVER); - drm_free(dev->_vblank_count, sizeof(*dev->_vblank_count) * - dev->num_crtcs, DRM_MEM_DRIVER); - drm_free(dev->vblank_refcount, sizeof(*dev->vblank_refcount) * - dev->num_crtcs, DRM_MEM_DRIVER); - drm_free(dev->vblank_enabled, sizeof(*dev->vblank_enabled) * - dev->num_crtcs, DRM_MEM_DRIVER); - drm_free(dev->last_vblank, sizeof(*dev->last_vblank) * dev->num_crtcs, - DRM_MEM_DRIVER); - drm_free(dev->vblank_premodeset, sizeof(*dev->vblank_premodeset) * - dev->num_crtcs, DRM_MEM_DRIVER); - drm_free(dev->vblank_offset, sizeof(*dev->vblank_offset) * dev->num_crtcs, - DRM_MEM_DRIVER); - - dev->num_crtcs = 0; -} - -int drm_vblank_init(struct drm_device *dev, int num_crtcs) -{ - int i, ret = -ENOMEM; - - setup_timer(&dev->vblank_disable_timer, vblank_disable_fn, - (unsigned long)dev); - spin_lock_init(&dev->vbl_lock); - atomic_set(&dev->vbl_signal_pending, 0); - dev->num_crtcs = num_crtcs; - - dev->vbl_queue = drm_alloc(sizeof(wait_queue_head_t) * num_crtcs, - DRM_MEM_DRIVER); - if (!dev->vbl_queue) - goto err; - - dev->vbl_sigs = drm_alloc(sizeof(struct list_head) * num_crtcs, - DRM_MEM_DRIVER); - if (!dev->vbl_sigs) - goto err; - - dev->_vblank_count = drm_alloc(sizeof(atomic_t) * num_crtcs, - DRM_MEM_DRIVER); - if (!dev->_vblank_count) - goto err; - - dev->vblank_refcount = drm_alloc(sizeof(atomic_t) * num_crtcs, - DRM_MEM_DRIVER); - if (!dev->vblank_refcount) - goto err; - - dev->vblank_enabled = drm_calloc(num_crtcs, sizeof(int), - DRM_MEM_DRIVER); - if (!dev->vblank_enabled) - goto err; - - dev->last_vblank = drm_calloc(num_crtcs, sizeof(u32), DRM_MEM_DRIVER); - if (!dev->last_vblank) - goto err; - - dev->vblank_premodeset = drm_calloc(num_crtcs, sizeof(u32), - DRM_MEM_DRIVER); - if (!dev->vblank_premodeset) - goto err; - - dev->vblank_offset = drm_calloc(num_crtcs, sizeof(u32), DRM_MEM_DRIVER); - if (!dev->vblank_offset) - goto err; - - /* Zero per-crtc vblank stuff */ - for (i = 0; i < num_crtcs; i++) { - init_waitqueue_head(&dev->vbl_queue[i]); - INIT_LIST_HEAD(&dev->vbl_sigs[i]); - atomic_set(&dev->_vblank_count[i], 0); - atomic_set(&dev->vblank_refcount[i], 0); - } - - return 0; - -err: - drm_vblank_cleanup(dev); - return ret; -} -EXPORT_SYMBOL(drm_vblank_init); - /** * Install IRQ handler. * @@ -220,6 +109,17 @@ static int drm_irq_install(struct drm_device * dev) DRM_DEBUG("irq=%d\n", dev->irq); + if (drm_core_check_feature(dev, DRIVER_IRQ_VBL)) { + init_waitqueue_head(&dev->vbl_queue); + + spin_lock_init(&dev->vbl_lock); + + INIT_LIST_HEAD(&dev->vbl_sigs); + INIT_LIST_HEAD(&dev->vbl_sigs2); + + dev->vbl_pending = 0; + } + /* Before installing handler */ dev->driver->irq_preinstall(dev); @@ -237,14 +137,9 @@ static int drm_irq_install(struct drm_device * dev) } /* After installing handler */ - ret = dev->driver->irq_postinstall(dev); - if (ret < 0) { - mutex_lock(&dev->struct_mutex); - dev->irq_enabled = 0; - mutex_unlock(&dev->struct_mutex); - } + dev->driver->irq_postinstall(dev); - return ret; + return 0; } /** @@ -275,8 +170,6 @@ int drm_irq_uninstall(struct drm_device * dev) free_irq(dev->irq, dev); - drm_vblank_cleanup(dev); - dev->locked_tasklet_func = NULL; return 0; @@ -321,148 +214,6 @@ int drm_control(struct drm_device *dev, void *data, } /** - * drm_vblank_count - retrieve "cooked" vblank counter value - * @dev: DRM device - * @crtc: which counter to retrieve - * - * Fetches the "cooked" vblank count value that represents the number of - * vblank events since the system was booted, including lost events due to - * modesetting activity. - */ -u32 drm_vblank_count(struct drm_device *dev, int crtc) -{ - return atomic_read(&dev->_vblank_count[crtc]) + - dev->vblank_offset[crtc]; -} -EXPORT_SYMBOL(drm_vblank_count); - -/** - * drm_update_vblank_count - update the master vblank counter - * @dev: DRM device - * @crtc: counter to update - * - * Call back into the driver to update the appropriate vblank counter - * (specified by @crtc). Deal with wraparound, if it occurred, and - * update the last read value so we can deal with wraparound on the next - * call if necessary. - */ -void drm_update_vblank_count(struct drm_device *dev, int crtc) -{ - unsigned long irqflags; - u32 cur_vblank, diff; - - /* - * Interrupts were disabled prior to this call, so deal with counter - * wrap if needed. - * NOTE! It's possible we lost a full dev->max_vblank_count events - * here if the register is small or we had vblank interrupts off for - * a long time. - */ - cur_vblank = dev->driver->get_vblank_counter(dev, crtc); - spin_lock_irqsave(&dev->vbl_lock, irqflags); - if (cur_vblank < dev->last_vblank[crtc]) { - diff = dev->max_vblank_count - - dev->last_vblank[crtc]; - diff += cur_vblank; - } else { - diff = cur_vblank - dev->last_vblank[crtc]; - } - dev->last_vblank[crtc] = cur_vblank; - spin_unlock_irqrestore(&dev->vbl_lock, irqflags); - - atomic_add(diff, &dev->_vblank_count[crtc]); -} -EXPORT_SYMBOL(drm_update_vblank_count); - -/** - * drm_vblank_get - get a reference count on vblank events - * @dev: DRM device - * @crtc: which CRTC to own - * - * Acquire a reference count on vblank events to avoid having them disabled - * while in use. Note callers will probably want to update the master counter - * using drm_update_vblank_count() above before calling this routine so that - * wakeups occur on the right vblank event. - * - * RETURNS - * Zero on success, nonzero on failure. - */ -int drm_vblank_get(struct drm_device *dev, int crtc) -{ - unsigned long irqflags; - int ret = 0; - - spin_lock_irqsave(&dev->vbl_lock, irqflags); - /* Going from 0->1 means we have to enable interrupts again */ - if (atomic_add_return(1, &dev->vblank_refcount[crtc]) == 1 && - !dev->vblank_enabled[crtc]) { - ret = dev->driver->enable_vblank(dev, crtc); - if (ret) - atomic_dec(&dev->vblank_refcount[crtc]); - else - dev->vblank_enabled[crtc] = 1; - } - spin_unlock_irqrestore(&dev->vbl_lock, irqflags); - - return ret; -} -EXPORT_SYMBOL(drm_vblank_get); - -/** - * drm_vblank_put - give up ownership of vblank events - * @dev: DRM device - * @crtc: which counter to give up - * - * Release ownership of a given vblank counter, turning off interrupts - * if possible. - */ -void drm_vblank_put(struct drm_device *dev, int crtc) -{ - /* Last user schedules interrupt disable */ - if (atomic_dec_and_test(&dev->vblank_refcount[crtc])) - mod_timer(&dev->vblank_disable_timer, jiffies + 5*DRM_HZ); -} -EXPORT_SYMBOL(drm_vblank_put); - -/** - * drm_modeset_ctl - handle vblank event counter changes across mode switch - * @DRM_IOCTL_ARGS: standard ioctl arguments - * - * Applications should call the %_DRM_PRE_MODESET and %_DRM_POST_MODESET - * ioctls around modesetting so that any lost vblank events are accounted for. - */ -int drm_modeset_ctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_modeset_ctl *modeset = data; - int crtc, ret = 0; - u32 new; - - crtc = modeset->arg; - if (crtc >= dev->num_crtcs) { - ret = -EINVAL; - goto out; - } - - switch (modeset->cmd) { - case _DRM_PRE_MODESET: - dev->vblank_premodeset[crtc] = - dev->driver->get_vblank_counter(dev, crtc); - break; - case _DRM_POST_MODESET: - new = dev->driver->get_vblank_counter(dev, crtc); - dev->vblank_offset[crtc] = dev->vblank_premodeset[crtc] - new; - break; - default: - ret = -EINVAL; - break; - } - -out: - return ret; -} - -/** * Wait for VBLANK. * * \param inode device inode. @@ -481,13 +232,12 @@ out: * * If a signal is not requested, then calls vblank_wait(). */ -int drm_wait_vblank(struct drm_device *dev, void *data, - struct drm_file *file_priv) +int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_priv) { union drm_wait_vblank *vblwait = data; struct timeval now; int ret = 0; - unsigned int flags, seq, crtc; + unsigned int flags, seq; if ((!dev->irq) || (!dev->irq_enabled)) return -EINVAL; @@ -501,13 +251,13 @@ int drm_wait_vblank(struct drm_device *dev, void *data, } flags = vblwait->request.type & _DRM_VBLANK_FLAGS_MASK; - crtc = flags & _DRM_VBLANK_SECONDARY ? 1 : 0; - if (crtc >= dev->num_crtcs) + if (!drm_core_check_feature(dev, (flags & _DRM_VBLANK_SECONDARY) ? + DRIVER_IRQ_VBL2 : DRIVER_IRQ_VBL)) return -EINVAL; - drm_update_vblank_count(dev, crtc); - seq = drm_vblank_count(dev, crtc); + seq = atomic_read((flags & _DRM_VBLANK_SECONDARY) ? &dev->vbl_received2 + : &dev->vbl_received); switch (vblwait->request.type & _DRM_VBLANK_TYPES_MASK) { case _DRM_VBLANK_RELATIVE: @@ -526,7 +276,8 @@ int drm_wait_vblank(struct drm_device *dev, void *data, if (flags & _DRM_VBLANK_SIGNAL) { unsigned long irqflags; - struct list_head *vbl_sigs = &dev->vbl_sigs[crtc]; + struct list_head *vbl_sigs = (flags & _DRM_VBLANK_SECONDARY) + ? &dev->vbl_sigs2 : &dev->vbl_sigs; struct drm_vbl_sig *vbl_sig; spin_lock_irqsave(&dev->vbl_lock, irqflags); @@ -547,26 +298,22 @@ int drm_wait_vblank(struct drm_device *dev, void *data, } } - if (atomic_read(&dev->vbl_signal_pending) >= 100) { + if (dev->vbl_pending >= 100) { spin_unlock_irqrestore(&dev->vbl_lock, irqflags); return -EBUSY; } + dev->vbl_pending++; + spin_unlock_irqrestore(&dev->vbl_lock, irqflags); - vbl_sig = drm_calloc(1, sizeof(struct drm_vbl_sig), - DRM_MEM_DRIVER); - if (!vbl_sig) + if (! + (vbl_sig = + drm_alloc(sizeof(struct drm_vbl_sig), DRM_MEM_DRIVER))) { return -ENOMEM; - - ret = drm_vblank_get(dev, crtc); - if (ret) { - drm_free(vbl_sig, sizeof(struct drm_vbl_sig), - DRM_MEM_DRIVER); - return ret; } - atomic_inc(&dev->vbl_signal_pending); + memset((void *)vbl_sig, 0, sizeof(*vbl_sig)); vbl_sig->sequence = vblwait->request.sequence; vbl_sig->info.si_signo = vblwait->request.signal; @@ -580,20 +327,17 @@ int drm_wait_vblank(struct drm_device *dev, void *data, vblwait->reply.sequence = seq; } else { - unsigned long cur_vblank; - - ret = drm_vblank_get(dev, crtc); - if (ret) - return ret; - DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ, - (((cur_vblank = drm_vblank_count(dev, crtc)) - - vblwait->request.sequence) <= (1 << 23))); - drm_vblank_put(dev, crtc); - do_gettimeofday(&now); + if (flags & _DRM_VBLANK_SECONDARY) { + if (dev->driver->vblank_wait2) + ret = dev->driver->vblank_wait2(dev, &vblwait->request.sequence); + } else if (dev->driver->vblank_wait) + ret = + dev->driver->vblank_wait(dev, + &vblwait->request.sequence); + do_gettimeofday(&now); vblwait->reply.tval_sec = now.tv_sec; vblwait->reply.tval_usec = now.tv_usec; - vblwait->reply.sequence = cur_vblank; } done: @@ -604,57 +348,44 @@ int drm_wait_vblank(struct drm_device *dev, void *data, * Send the VBLANK signals. * * \param dev DRM device. - * \param crtc CRTC where the vblank event occurred * * Sends a signal for each task in drm_device::vbl_sigs and empties the list. * * If a signal is not requested, then calls vblank_wait(). */ -static void drm_vbl_send_signals(struct drm_device * dev, int crtc) +void drm_vbl_send_signals(struct drm_device * dev) { - struct drm_vbl_sig *vbl_sig, *tmp; - struct list_head *vbl_sigs; - unsigned int vbl_seq; unsigned long flags; + int i; spin_lock_irqsave(&dev->vbl_lock, flags); - vbl_sigs = &dev->vbl_sigs[crtc]; - vbl_seq = drm_vblank_count(dev, crtc); + for (i = 0; i < 2; i++) { + struct drm_vbl_sig *vbl_sig, *tmp; + struct list_head *vbl_sigs = i ? &dev->vbl_sigs2 : &dev->vbl_sigs; + unsigned int vbl_seq = atomic_read(i ? &dev->vbl_received2 : + &dev->vbl_received); - list_for_each_entry_safe(vbl_sig, tmp, vbl_sigs, head) { - if ((vbl_seq - vbl_sig->sequence) <= (1 << 23)) { - vbl_sig->info.si_code = vbl_seq; - send_sig_info(vbl_sig->info.si_signo, - &vbl_sig->info, vbl_sig->task); + list_for_each_entry_safe(vbl_sig, tmp, vbl_sigs, head) { + if ((vbl_seq - vbl_sig->sequence) <= (1 << 23)) { + vbl_sig->info.si_code = vbl_seq; + send_sig_info(vbl_sig->info.si_signo, + &vbl_sig->info, vbl_sig->task); - list_del(&vbl_sig->head); + list_del(&vbl_sig->head); - drm_free(vbl_sig, sizeof(*vbl_sig), - DRM_MEM_DRIVER); - atomic_dec(&dev->vbl_signal_pending); - drm_vblank_put(dev, crtc); - } + drm_free(vbl_sig, sizeof(*vbl_sig), + DRM_MEM_DRIVER); + + dev->vbl_pending--; + } + } } spin_unlock_irqrestore(&dev->vbl_lock, flags); } -/** - * drm_handle_vblank - handle a vblank event - * @dev: DRM device - * @crtc: where this event occurred - * - * Drivers should call this routine in their vblank interrupt handlers to - * update the vblank counter and send any signals that may be pending. - */ -void drm_handle_vblank(struct drm_device *dev, int crtc) -{ - drm_update_vblank_count(dev, crtc); - DRM_WAKEUP(&dev->vbl_queue[crtc]); - drm_vbl_send_signals(dev, crtc); -} -EXPORT_SYMBOL(drm_handle_vblank); +EXPORT_SYMBOL(drm_vbl_send_signals); /** * Tasklet wrapper function. diff --git a/drivers/char/drm/drm_lock.c b/drivers/char/drm/drm_lock.c index 12dcdd1832f0..0998723cde79 100644 --- a/drivers/char/drm/drm_lock.c +++ b/drivers/char/drm/drm_lock.c @@ -53,7 +53,6 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv) DECLARE_WAITQUEUE(entry, current); struct drm_lock *lock = data; int ret = 0; - unsigned long irqflags; ++file_priv->lock_count; @@ -72,9 +71,9 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv) return -EINVAL; add_wait_queue(&dev->lock.lock_queue, &entry); - spin_lock_irqsave(&dev->lock.spinlock, irqflags); + spin_lock_bh(&dev->lock.spinlock); dev->lock.user_waiters++; - spin_unlock_irqrestore(&dev->lock.spinlock, irqflags); + spin_unlock_bh(&dev->lock.spinlock); for (;;) { __set_current_state(TASK_INTERRUPTIBLE); if (!dev->lock.hw_lock) { @@ -96,9 +95,9 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv) break; } } - spin_lock_irqsave(&dev->lock.spinlock, irqflags); + spin_lock_bh(&dev->lock.spinlock); dev->lock.user_waiters--; - spin_unlock_irqrestore(&dev->lock.spinlock, irqflags); + spin_unlock_bh(&dev->lock.spinlock); __set_current_state(TASK_RUNNING); remove_wait_queue(&dev->lock.lock_queue, &entry); @@ -199,9 +198,8 @@ int drm_lock_take(struct drm_lock_data *lock_data, { unsigned int old, new, prev; volatile unsigned int *lock = &lock_data->hw_lock->lock; - unsigned long irqflags; - spin_lock_irqsave(&lock_data->spinlock, irqflags); + spin_lock_bh(&lock_data->spinlock); do { old = *lock; if (old & _DRM_LOCK_HELD) @@ -213,7 +211,7 @@ int drm_lock_take(struct drm_lock_data *lock_data, } prev = cmpxchg(lock, old, new); } while (prev != old); - spin_unlock_irqrestore(&lock_data->spinlock, irqflags); + spin_unlock_bh(&lock_data->spinlock); if (_DRM_LOCKING_CONTEXT(old) == context) { if (old & _DRM_LOCK_HELD) { @@ -274,16 +272,15 @@ int drm_lock_free(struct drm_lock_data *lock_data, unsigned int context) { unsigned int old, new, prev; volatile unsigned int *lock = &lock_data->hw_lock->lock; - unsigned long irqflags; - spin_lock_irqsave(&lock_data->spinlock, irqflags); + spin_lock_bh(&lock_data->spinlock); if (lock_data->kernel_waiters != 0) { drm_lock_transfer(lock_data, 0); lock_data->idle_has_lock = 1; - spin_unlock_irqrestore(&lock_data->spinlock, irqflags); + spin_unlock_bh(&lock_data->spinlock); return 1; } - spin_unlock_irqrestore(&lock_data->spinlock, irqflags); + spin_unlock_bh(&lock_data->spinlock); do { old = *lock; @@ -347,20 +344,19 @@ static int drm_notifier(void *priv) void drm_idlelock_take(struct drm_lock_data *lock_data) { int ret = 0; - unsigned long irqflags; - spin_lock_irqsave(&lock_data->spinlock, irqflags); + spin_lock_bh(&lock_data->spinlock); lock_data->kernel_waiters++; if (!lock_data->idle_has_lock) { - spin_unlock_irqrestore(&lock_data->spinlock, irqflags); + spin_unlock_bh(&lock_data->spinlock); ret = drm_lock_take(lock_data, DRM_KERNEL_CONTEXT); - spin_lock_irqsave(&lock_data->spinlock, irqflags); + spin_lock_bh(&lock_data->spinlock); if (ret == 1) lock_data->idle_has_lock = 1; } - spin_unlock_irqrestore(&lock_data->spinlock, irqflags); + spin_unlock_bh(&lock_data->spinlock); } EXPORT_SYMBOL(drm_idlelock_take); @@ -368,9 +364,8 @@ void drm_idlelock_release(struct drm_lock_data *lock_data) { unsigned int old, prev; volatile unsigned int *lock = &lock_data->hw_lock->lock; - unsigned long irqflags; - spin_lock_irqsave(&lock_data->spinlock, irqflags); + spin_lock_bh(&lock_data->spinlock); if (--lock_data->kernel_waiters == 0) { if (lock_data->idle_has_lock) { do { @@ -381,7 +376,7 @@ void drm_idlelock_release(struct drm_lock_data *lock_data) lock_data->idle_has_lock = 0; } } - spin_unlock_irqrestore(&lock_data->spinlock, irqflags); + spin_unlock_bh(&lock_data->spinlock); } EXPORT_SYMBOL(drm_idlelock_release); diff --git a/drivers/char/drm/drm_sysfs.c b/drivers/char/drm/drm_sysfs.c index 9a32169e88fb..af211a0ef179 100644 --- a/drivers/char/drm/drm_sysfs.c +++ b/drivers/char/drm/drm_sysfs.c @@ -34,8 +34,6 @@ static int drm_sysfs_suspend(struct device *dev, pm_message_t state) struct drm_minor *drm_minor = to_drm_minor(dev); struct drm_device *drm_dev = drm_minor->dev; - printk(KERN_ERR "%s\n", __func__); - if (drm_dev->driver->suspend) return drm_dev->driver->suspend(drm_dev, state); diff --git a/drivers/char/drm/i915_dma.c b/drivers/char/drm/i915_dma.c index f47e46e3529f..88974342933c 100644 --- a/drivers/char/drm/i915_dma.c +++ b/drivers/char/drm/i915_dma.c @@ -415,13 +415,10 @@ static void i915_emit_breadcrumb(struct drm_device *dev) drm_i915_private_t *dev_priv = dev->dev_private; RING_LOCALS; - if (++dev_priv->counter > BREADCRUMB_MASK) { - dev_priv->counter = 1; - DRM_DEBUG("Breadcrumb counter wrapped around\n"); - } + dev_priv->sarea_priv->last_enqueue = ++dev_priv->counter; - if (dev_priv->sarea_priv) - dev_priv->sarea_priv->last_enqueue = dev_priv->counter; + if (dev_priv->counter > 0x7FFFFFFFUL) + dev_priv->sarea_priv->last_enqueue = dev_priv->counter = 1; BEGIN_LP_RING(4); OUT_RING(CMD_STORE_DWORD_IDX); @@ -431,26 +428,6 @@ static void i915_emit_breadcrumb(struct drm_device *dev) ADVANCE_LP_RING(); } -int i915_emit_mi_flush(struct drm_device *dev, uint32_t flush) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - uint32_t flush_cmd = CMD_MI_FLUSH; - RING_LOCALS; - - flush_cmd |= flush; - - i915_kernel_lost_context(dev); - - BEGIN_LP_RING(4); - OUT_RING(flush_cmd); - OUT_RING(0); - OUT_RING(0); - OUT_RING(0); - ADVANCE_LP_RING(); - - return 0; -} - static int i915_dispatch_cmdbuffer(struct drm_device * dev, drm_i915_cmdbuffer_t * cmd) { @@ -534,74 +511,52 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev, return 0; } -static void i915_do_dispatch_flip(struct drm_device * dev, int plane, int sync) +static int i915_dispatch_flip(struct drm_device * dev) { drm_i915_private_t *dev_priv = dev->dev_private; - u32 num_pages, current_page, next_page, dspbase; - int shift = 2 * plane, x, y; RING_LOCALS; - /* Calculate display base offset */ - num_pages = dev_priv->sarea_priv->third_handle ? 3 : 2; - current_page = (dev_priv->sarea_priv->pf_current_page >> shift) & 0x3; - next_page = (current_page + 1) % num_pages; + DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n", + __FUNCTION__, + dev_priv->current_page, + dev_priv->sarea_priv->pf_current_page); - switch (next_page) { - default: - case 0: - dspbase = dev_priv->sarea_priv->front_offset; - break; - case 1: - dspbase = dev_priv->sarea_priv->back_offset; - break; - case 2: - dspbase = dev_priv->sarea_priv->third_offset; - break; - } + i915_kernel_lost_context(dev); + + BEGIN_LP_RING(2); + OUT_RING(INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE); + OUT_RING(0); + ADVANCE_LP_RING(); - if (plane == 0) { - x = dev_priv->sarea_priv->planeA_x; - y = dev_priv->sarea_priv->planeA_y; + BEGIN_LP_RING(6); + OUT_RING(CMD_OP_DISPLAYBUFFER_INFO | ASYNC_FLIP); + OUT_RING(0); + if (dev_priv->current_page == 0) { + OUT_RING(dev_priv->back_offset); + dev_priv->current_page = 1; } else { - x = dev_priv->sarea_priv->planeB_x; - y = dev_priv->sarea_priv->planeB_y; + OUT_RING(dev_priv->front_offset); + dev_priv->current_page = 0; } + OUT_RING(0); + ADVANCE_LP_RING(); - dspbase += (y * dev_priv->sarea_priv->pitch + x) * dev_priv->cpp; + BEGIN_LP_RING(2); + OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_PLANE_A_FLIP); + OUT_RING(0); + ADVANCE_LP_RING(); - DRM_DEBUG("plane=%d current_page=%d dspbase=0x%x\n", plane, current_page, - dspbase); + dev_priv->sarea_priv->last_enqueue = dev_priv->counter++; BEGIN_LP_RING(4); - OUT_RING(sync ? 0 : - (MI_WAIT_FOR_EVENT | (plane ? MI_WAIT_FOR_PLANE_B_FLIP : - MI_WAIT_FOR_PLANE_A_FLIP))); - OUT_RING(CMD_OP_DISPLAYBUFFER_INFO | (sync ? 0 : ASYNC_FLIP) | - (plane ? DISPLAY_PLANE_B : DISPLAY_PLANE_A)); - OUT_RING(dev_priv->sarea_priv->pitch * dev_priv->cpp); - OUT_RING(dspbase); + OUT_RING(CMD_STORE_DWORD_IDX); + OUT_RING(20); + OUT_RING(dev_priv->counter); + OUT_RING(0); ADVANCE_LP_RING(); - dev_priv->sarea_priv->pf_current_page &= ~(0x3 << shift); - dev_priv->sarea_priv->pf_current_page |= next_page << shift; -} - -void i915_dispatch_flip(struct drm_device * dev, int planes, int sync) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - int i; - - DRM_DEBUG("planes=0x%x pfCurrentPage=%d\n", - planes, dev_priv->sarea_priv->pf_current_page); - - i915_emit_mi_flush(dev, MI_READ_FLUSH | MI_EXE_FLUSH); - - for (i = 0; i < 2; i++) - if (planes & (1 << i)) - i915_do_dispatch_flip(dev, i, sync); - - i915_emit_breadcrumb(dev); - + dev_priv->sarea_priv->pf_current_page = dev_priv->current_page; + return 0; } static int i915_quiescent(struct drm_device * dev) @@ -624,6 +579,7 @@ static int i915_batchbuffer(struct drm_device *dev, void *data, struct drm_file *file_priv) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + u32 *hw_status = dev_priv->hw_status_page; drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *) dev_priv->sarea_priv; drm_i915_batchbuffer_t *batch = data; @@ -646,7 +602,7 @@ static int i915_batchbuffer(struct drm_device *dev, void *data, ret = i915_dispatch_batchbuffer(dev, batch); - sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); + sarea_priv->last_dispatch = (int)hw_status[5]; return ret; } @@ -654,6 +610,7 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data, struct drm_file *file_priv) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + u32 *hw_status = dev_priv->hw_status_page; drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *) dev_priv->sarea_priv; drm_i915_cmdbuffer_t *cmdbuf = data; @@ -678,51 +635,18 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data, return ret; } - sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); - return 0; -} - -static int i915_do_cleanup_pageflip(struct drm_device * dev) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - int i, planes, num_pages = dev_priv->sarea_priv->third_handle ? 3 : 2; - - DRM_DEBUG("\n"); - - for (i = 0, planes = 0; i < 2; i++) - if (dev_priv->sarea_priv->pf_current_page & (0x3 << (2 * i))) { - dev_priv->sarea_priv->pf_current_page = - (dev_priv->sarea_priv->pf_current_page & - ~(0x3 << (2 * i))) | ((num_pages - 1) << (2 * i)); - - planes |= 1 << i; - } - - if (planes) - i915_dispatch_flip(dev, planes, 0); - + sarea_priv->last_dispatch = (int)hw_status[5]; return 0; } static int i915_flip_bufs(struct drm_device *dev, void *data, struct drm_file *file_priv) { - drm_i915_flip_t *param = data; - - DRM_DEBUG("\n"); + DRM_DEBUG("%s\n", __FUNCTION__); LOCK_TEST_WITH_RETURN(dev, file_priv); - /* This is really planes */ - if (param->pipes & ~0x3) { - DRM_ERROR("Invalid planes 0x%x, only <= 0x3 is valid\n", - param->pipes); - return -EINVAL; - } - - i915_dispatch_flip(dev, param->pipes, 0); - - return 0; + return i915_dispatch_flip(dev); } static int i915_getparam(struct drm_device *dev, void *data, @@ -883,8 +807,6 @@ void i915_driver_lastclose(struct drm_device * dev) if (!dev_priv) return; - if (drm_getsarea(dev) && dev_priv->sarea_priv) - i915_do_cleanup_pageflip(dev); if (dev_priv->agp_heap) i915_mem_takedown(&(dev_priv->agp_heap)); diff --git a/drivers/char/drm/i915_drm.h b/drivers/char/drm/i915_drm.h index 0431c00e2289..05c66cf03a9e 100644 --- a/drivers/char/drm/i915_drm.h +++ b/drivers/char/drm/i915_drm.h @@ -105,29 +105,14 @@ typedef struct _drm_i915_sarea { unsigned int rotated_tiled; unsigned int rotated2_tiled; - int planeA_x; - int planeA_y; - int planeA_w; - int planeA_h; - int planeB_x; - int planeB_y; - int planeB_w; - int planeB_h; - - /* Triple buffering */ - drm_handle_t third_handle; - int third_offset; - int third_size; - unsigned int third_tiled; - - /* buffer object handles for the static buffers. May change - * over the lifetime of the client, though it doesn't in our current - * implementation. - */ - unsigned int front_bo_handle; - unsigned int back_bo_handle; - unsigned int third_bo_handle; - unsigned int depth_bo_handle; + int pipeA_x; + int pipeA_y; + int pipeA_w; + int pipeA_h; + int pipeB_x; + int pipeB_y; + int pipeB_w; + int pipeB_h; } drm_i915_sarea_t; /* Flags for perf_boxes @@ -161,7 +146,7 @@ typedef struct _drm_i915_sarea { #define DRM_IOCTL_I915_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t) #define DRM_IOCTL_I915_FLUSH DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH) -#define DRM_IOCTL_I915_FLIP DRM_IOW( DRM_COMMAND_BASE + DRM_I915_FLIP, drm_i915_flip_t) +#define DRM_IOCTL_I915_FLIP DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLIP) #define DRM_IOCTL_I915_BATCHBUFFER DRM_IOW( DRM_COMMAND_BASE + DRM_I915_BATCHBUFFER, drm_i915_batchbuffer_t) #define DRM_IOCTL_I915_IRQ_EMIT DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_IRQ_EMIT, drm_i915_irq_emit_t) #define DRM_IOCTL_I915_IRQ_WAIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_IRQ_WAIT, drm_i915_irq_wait_t) @@ -176,18 +161,6 @@ typedef struct _drm_i915_sarea { #define DRM_IOCTL_I915_GET_VBLANK_PIPE DRM_IOR( DRM_COMMAND_BASE + DRM_I915_GET_VBLANK_PIPE, drm_i915_vblank_pipe_t) #define DRM_IOCTL_I915_VBLANK_SWAP DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_VBLANK_SWAP, drm_i915_vblank_swap_t) -/* Asynchronous page flipping: - */ -typedef struct drm_i915_flip { - /* - * This is really talking about planes, and we could rename it - * except for the fact that some of the duplicated i915_drm.h files - * out there check for HAVE_I915_FLIP and so might pick up this - * version. - */ - int pipes; -} drm_i915_flip_t; - /* Allow drivers to submit batchbuffers directly to hardware, relying * on the security mechanisms provided by hardware. */ diff --git a/drivers/char/drm/i915_drv.c b/drivers/char/drm/i915_drv.c index bb8f1b2fb383..e8f3d682e3b1 100644 --- a/drivers/char/drm/i915_drv.c +++ b/drivers/char/drm/i915_drv.c @@ -147,7 +147,7 @@ static void i915_save_vga(struct drm_device *dev) i915_write_indexed(cr_index, cr_data, 0x11, i915_read_indexed(cr_index, cr_data, 0x11) & (~0x80)); - for (i = 0; i < 0x24; i++) + for (i = 0; i <= 0x24; i++) dev_priv->saveCR[i] = i915_read_indexed(cr_index, cr_data, i); /* Make sure we don't turn off CR group 0 writes */ @@ -156,7 +156,7 @@ static void i915_save_vga(struct drm_device *dev) /* Attribute controller registers */ inb(st01); dev_priv->saveAR_INDEX = inb(VGA_AR_INDEX); - for (i = 0; i < 20; i++) + for (i = 0; i <= 0x14; i++) dev_priv->saveAR[i] = i915_read_ar(st01, i, 0); inb(st01); outb(dev_priv->saveAR_INDEX, VGA_AR_INDEX); @@ -206,7 +206,7 @@ static void i915_restore_vga(struct drm_device *dev) /* CRT controller regs */ /* Enable CR group 0 writes */ i915_write_indexed(cr_index, cr_data, 0x11, dev_priv->saveCR[0x11]); - for (i = 0; i < 0x24; i++) + for (i = 0; i <= 0x24; i++) i915_write_indexed(cr_index, cr_data, i, dev_priv->saveCR[i]); /* Graphics controller regs */ @@ -223,7 +223,7 @@ static void i915_restore_vga(struct drm_device *dev) /* Attribute controller registers */ inb(st01); - for (i = 0; i < 20; i++) + for (i = 0; i <= 0x14; i++) i915_write_ar(st01, i, dev_priv->saveAR[i], 0); inb(st01); /* switch back to index mode */ outb(dev_priv->saveAR_INDEX | 0x20, VGA_AR_INDEX); @@ -256,6 +256,9 @@ static int i915_suspend(struct drm_device *dev, pm_message_t state) pci_save_state(dev->pdev); pci_read_config_byte(dev->pdev, LBB, &dev_priv->saveLBB); + /* Display arbitration control */ + dev_priv->saveDSPARB = I915_READ(DSPARB); + /* Pipe & plane A info */ dev_priv->savePIPEACONF = I915_READ(PIPEACONF); dev_priv->savePIPEASRC = I915_READ(PIPEASRC); @@ -349,6 +352,7 @@ static int i915_suspend(struct drm_device *dev, pm_message_t state) dev_priv->saveVGACNTRL = I915_READ(VGACNTRL); /* Clock gating state */ + dev_priv->saveD_STATE = I915_READ(D_STATE); dev_priv->saveDSPCLK_GATE_D = I915_READ(DSPCLK_GATE_D); /* Cache mode state */ @@ -388,6 +392,8 @@ static int i915_resume(struct drm_device *dev) pci_write_config_byte(dev->pdev, LBB, dev_priv->saveLBB); + I915_WRITE(DSPARB, dev_priv->saveDSPARB); + /* Pipe & plane A info */ /* Prime the clock */ if (dev_priv->saveDPLL_A & DPLL_VCO_ENABLE) { @@ -507,6 +513,7 @@ static int i915_resume(struct drm_device *dev) udelay(150); /* Clock gating state */ + I915_WRITE (D_STATE, dev_priv->saveD_STATE); I915_WRITE (DSPCLK_GATE_D, dev_priv->saveDSPCLK_GATE_D); /* Cache mode state */ @@ -533,7 +540,8 @@ static struct drm_driver driver = { */ .driver_features = DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | /* DRIVER_USE_MTRR |*/ - DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED, + DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL | + DRIVER_IRQ_VBL2, .load = i915_driver_load, .unload = i915_driver_unload, .lastclose = i915_driver_lastclose, @@ -541,9 +549,8 @@ static struct drm_driver driver = { .suspend = i915_suspend, .resume = i915_resume, .device_is_agp = i915_driver_device_is_agp, - .get_vblank_counter = i915_get_vblank_counter, - .enable_vblank = i915_enable_vblank, - .disable_vblank = i915_disable_vblank, + .vblank_wait = i915_driver_vblank_wait, + .vblank_wait2 = i915_driver_vblank_wait2, .irq_preinstall = i915_driver_irq_preinstall, .irq_postinstall = i915_driver_irq_postinstall, .irq_uninstall = i915_driver_irq_uninstall, diff --git a/drivers/char/drm/i915_drv.h b/drivers/char/drm/i915_drv.h index db7001f22561..1b20f7c0639c 100644 --- a/drivers/char/drm/i915_drv.h +++ b/drivers/char/drm/i915_drv.h @@ -76,9 +76,8 @@ struct mem_block { typedef struct _drm_i915_vbl_swap { struct list_head head; drm_drawable_t drw_id; - unsigned int plane; + unsigned int pipe; unsigned int sequence; - int flip; } drm_i915_vbl_swap_t; typedef struct drm_i915_private { @@ -91,7 +90,7 @@ typedef struct drm_i915_private { drm_dma_handle_t *status_page_dmah; void *hw_status_page; dma_addr_t dma_status_page; - uint32_t counter; + unsigned long counter; unsigned int status_gfx_addr; drm_local_map_t hws_map; @@ -104,18 +103,13 @@ typedef struct drm_i915_private { wait_queue_head_t irq_queue; atomic_t irq_received; - atomic_t irq_emited; + atomic_t irq_emitted; int tex_lru_log_granularity; int allow_batchbuffer; struct mem_block *agp_heap; unsigned int sr01, adpa, ppcr, dvob, dvoc, lvds; int vblank_pipe; - spinlock_t user_irq_lock; - int user_irq_refcount; - int fence_irq_on; - uint32_t irq_enable_reg; - int irq_enabled; spinlock_t swaps_lock; drm_i915_vbl_swap_t vbl_swaps; @@ -125,6 +119,7 @@ typedef struct drm_i915_private { u8 saveLBB; u32 saveDSPACNTR; u32 saveDSPBCNTR; + u32 saveDSPARB; u32 savePIPEACONF; u32 savePIPEBCONF; u32 savePIPEASRC; @@ -194,6 +189,7 @@ typedef struct drm_i915_private { u32 saveIIR; u32 saveIMR; u32 saveCACHE_MODE_0; + u32 saveD_STATE; u32 saveDSPCLK_GATE_D; u32 saveMI_ARB_STATE; u32 saveSWF0[16]; @@ -203,10 +199,10 @@ typedef struct drm_i915_private { u8 saveSR[8]; u8 saveGR[25]; u8 saveAR_INDEX; - u8 saveAR[20]; + u8 saveAR[21]; u8 saveDACMASK; u8 saveDACDATA[256*3]; /* 256 3-byte colors */ - u8 saveCR[36]; + u8 saveCR[37]; } drm_i915_private_t; extern struct drm_ioctl_desc i915_ioctls[]; @@ -222,7 +218,7 @@ extern void i915_driver_preclose(struct drm_device *dev, extern int i915_driver_device_is_agp(struct drm_device * dev); extern long i915_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); -extern void i915_dispatch_flip(struct drm_device * dev, int pipes, int sync); + /* i915_irq.c */ extern int i915_irq_emit(struct drm_device *dev, void *data, struct drm_file *file_priv); @@ -233,7 +229,7 @@ extern int i915_driver_vblank_wait(struct drm_device *dev, unsigned int *sequenc extern int i915_driver_vblank_wait2(struct drm_device *dev, unsigned int *sequence); extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS); extern void i915_driver_irq_preinstall(struct drm_device * dev); -extern int i915_driver_irq_postinstall(struct drm_device * dev); +extern void i915_driver_irq_postinstall(struct drm_device * dev); extern void i915_driver_irq_uninstall(struct drm_device * dev); extern int i915_vblank_pipe_set(struct drm_device *dev, void *data, struct drm_file *file_priv); @@ -241,9 +237,6 @@ extern int i915_vblank_pipe_get(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int i915_vblank_swap(struct drm_device *dev, void *data, struct drm_file *file_priv); -extern int i915_enable_vblank(struct drm_device *dev, int crtc); -extern void i915_disable_vblank(struct drm_device *dev, int crtc); -extern u32 i915_get_vblank_counter(struct drm_device *dev, int crtc); /* i915_mem.c */ extern int i915_mem_alloc(struct drm_device *dev, void *data, @@ -388,91 +381,21 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); /* Interrupt bits: */ -#define I915_PIPE_CONTROL_NOTIFY_INTERRUPT (1<<18) -#define I915_DISPLAY_PORT_INTERRUPT (1<<17) -#define I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT (1<<15) -#define I915_GMCH_THERMAL_SENSOR_EVENT_INTERRUPT (1<<14) -#define I915_HWB_OOM_INTERRUPT (1<<13) /* binner out of memory */ -#define I915_SYNC_STATUS_INTERRUPT (1<<12) -#define I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT (1<<11) -#define I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT (1<<10) -#define I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT (1<<9) -#define I915_DISPLAY_PLANE_C_FLIP_PENDING_INTERRUPT (1<<8) -#define I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT (1<<7) -#define I915_DISPLAY_PIPE_A_EVENT_INTERRUPT (1<<6) -#define I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT (1<<5) -#define I915_DISPLAY_PIPE_B_EVENT_INTERRUPT (1<<4) -#define I915_DEBUG_INTERRUPT (1<<2) -#define I915_USER_INTERRUPT (1<<1) - +#define USER_INT_FLAG (1<<1) +#define VSYNC_PIPEB_FLAG (1<<5) +#define VSYNC_PIPEA_FLAG (1<<7) +#define HWB_OOM_FLAG (1<<13) /* binner out of memory */ #define I915REG_HWSTAM 0x02098 #define I915REG_INT_IDENTITY_R 0x020a4 #define I915REG_INT_MASK_R 0x020a8 #define I915REG_INT_ENABLE_R 0x020a0 -#define I915REG_INSTPM 0x020c0 - -#define PIPEADSL 0x70000 -#define PIPEBDSL 0x71000 #define I915REG_PIPEASTAT 0x70024 #define I915REG_PIPEBSTAT 0x71024 -/* - * The two pipe frame counter registers are not synchronized, so - * reading a stable value is somewhat tricky. The following code - * should work: - * - * do { - * high1 = ((INREG(PIPEAFRAMEHIGH) & PIPE_FRAME_HIGH_MASK) >> - * PIPE_FRAME_HIGH_SHIFT; - * low1 = ((INREG(PIPEAFRAMEPIXEL) & PIPE_FRAME_LOW_MASK) >> - * PIPE_FRAME_LOW_SHIFT); - * high2 = ((INREG(PIPEAFRAMEHIGH) & PIPE_FRAME_HIGH_MASK) >> - * PIPE_FRAME_HIGH_SHIFT); - * } while (high1 != high2); - * frame = (high1 << 8) | low1; - */ -#define PIPEAFRAMEHIGH 0x70040 -#define PIPEBFRAMEHIGH 0x71040 -#define PIPE_FRAME_HIGH_MASK 0x0000ffff -#define PIPE_FRAME_HIGH_SHIFT 0 -#define PIPEAFRAMEPIXEL 0x70044 -#define PIPEBFRAMEPIXEL 0x71044 -#define PIPE_FRAME_LOW_MASK 0xff000000 -#define PIPE_FRAME_LOW_SHIFT 24 -/* - * Pixel within the current frame is counted in the PIPEAFRAMEPIXEL register - * and is 24 bits wide. - */ -#define PIPE_PIXEL_MASK 0x00ffffff -#define PIPE_PIXEL_SHIFT 0 - -#define I915_FIFO_UNDERRUN_STATUS (1UL<<31) -#define I915_CRC_ERROR_ENABLE (1UL<<29) -#define I915_CRC_DONE_ENABLE (1UL<<28) -#define I915_GMBUS_EVENT_ENABLE (1UL<<27) -#define I915_VSYNC_INTERRUPT_ENABLE (1UL<<25) -#define I915_DISPLAY_LINE_COMPARE_ENABLE (1UL<<24) -#define I915_DPST_EVENT_ENABLE (1UL<<23) -#define I915_LEGACY_BLC_EVENT_ENABLE (1UL<<22) -#define I915_ODD_FIELD_INTERRUPT_ENABLE (1UL<<21) -#define I915_EVEN_FIELD_INTERRUPT_ENABLE (1UL<<20) -#define I915_START_VBLANK_INTERRUPT_ENABLE (1UL<<18) /* 965 or later */ -#define I915_VBLANK_INTERRUPT_ENABLE (1UL<<17) -#define I915_OVERLAY_UPDATED_ENABLE (1UL<<16) -#define I915_CRC_ERROR_INTERRUPT_STATUS (1UL<<13) -#define I915_CRC_DONE_INTERRUPT_STATUS (1UL<<12) -#define I915_GMBUS_INTERRUPT_STATUS (1UL<<11) -#define I915_VSYNC_INTERRUPT_STATUS (1UL<<9) -#define I915_DISPLAY_LINE_COMPARE_STATUS (1UL<<8) -#define I915_DPST_EVENT_STATUS (1UL<<7) -#define I915_LEGACY_BLC_EVENT_STATUS (1UL<<6) -#define I915_ODD_FIELD_INTERRUPT_STATUS (1UL<<5) -#define I915_EVEN_FIELD_INTERRUPT_STATUS (1UL<<4) -#define I915_START_VBLANK_INTERRUPT_STATUS (1UL<<2) /* 965 or later */ -#define I915_VBLANK_INTERRUPT_STATUS (1UL<<1) -#define I915_OVERLAY_UPDATED_STATUS (1UL<<0) +#define I915_VBLANK_INTERRUPT_ENABLE (1UL<<17) +#define I915_VBLANK_CLEAR (1UL<<1) #define SRX_INDEX 0x3c4 #define SRX_DATA 0x3c5 @@ -749,6 +672,8 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); /** P1 value is 2 greater than this field */ # define VGA0_PD_P1_MASK (0x1f << 0) +/* PCI D state control register */ +#define D_STATE 0x6104 #define DSPCLK_GATE_D 0x6200 /* I830 CRTC registers */ @@ -1059,6 +984,12 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); #define PIPECONF_INTERLACE_W_FIELD_INDICATION (6 << 21) #define PIPECONF_INTERLACE_FIELD_0_ONLY (7 << 21) +#define DSPARB 0x70030 +#define DSPARB_CSTART_MASK (0x7f << 7) +#define DSPARB_CSTART_SHIFT 7 +#define DSPARB_BSTART_MASK (0x7f) +#define DSPARB_BSTART_SHIFT 0 + #define PIPEBCONF 0x71008 #define PIPEBCONF_ENABLE (1<<31) #define PIPEBCONF_DISABLE 0 diff --git a/drivers/char/drm/i915_irq.c b/drivers/char/drm/i915_irq.c index 023ce66ef3ab..f7f16e7a8bf3 100644 --- a/drivers/char/drm/i915_irq.c +++ b/drivers/char/drm/i915_irq.c @@ -38,109 +38,6 @@ #define MAX_NOPID ((u32)~0) /** - * i915_get_pipe - return the the pipe associated with a given plane - * @dev: DRM device - * @plane: plane to look for - * - * The Intel Mesa & 2D drivers call the vblank routines with a plane number - * rather than a pipe number, since they may not always be equal. This routine - * maps the given @plane back to a pipe number. - */ -static int -i915_get_pipe(struct drm_device *dev, int plane) -{ - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - u32 dspcntr; - - dspcntr = plane ? I915_READ(DSPBCNTR) : I915_READ(DSPACNTR); - - return dspcntr & DISPPLANE_SEL_PIPE_MASK ? 1 : 0; -} - -/** - * i915_get_plane - return the the plane associated with a given pipe - * @dev: DRM device - * @pipe: pipe to look for - * - * The Intel Mesa & 2D drivers call the vblank routines with a plane number - * rather than a plane number, since they may not always be equal. This routine - * maps the given @pipe back to a plane number. - */ -static int -i915_get_plane(struct drm_device *dev, int pipe) -{ - if (i915_get_pipe(dev, 0) == pipe) - return 0; - return 1; -} - -/** - * i915_pipe_enabled - check if a pipe is enabled - * @dev: DRM device - * @pipe: pipe to check - * - * Reading certain registers when the pipe is disabled can hang the chip. - * Use this routine to make sure the PLL is running and the pipe is active - * before reading such registers if unsure. - */ -static int -i915_pipe_enabled(struct drm_device *dev, int pipe) -{ - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - unsigned long pipeconf = pipe ? PIPEBCONF : PIPEACONF; - - if (I915_READ(pipeconf) & PIPEACONF_ENABLE) - return 1; - - return 0; -} - -/** - * Emit a synchronous flip. - * - * This function must be called with the drawable spinlock held. - */ -static void -i915_dispatch_vsync_flip(struct drm_device *dev, struct drm_drawable_info *drw, - int plane) -{ - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv; - u16 x1, y1, x2, y2; - int pf_planes = 1 << plane; - - /* If the window is visible on the other plane, we have to flip on that - * plane as well. - */ - if (plane == 1) { - x1 = sarea_priv->planeA_x; - y1 = sarea_priv->planeA_y; - x2 = x1 + sarea_priv->planeA_w; - y2 = y1 + sarea_priv->planeA_h; - } else { - x1 = sarea_priv->planeB_x; - y1 = sarea_priv->planeB_y; - x2 = x1 + sarea_priv->planeB_w; - y2 = y1 + sarea_priv->planeB_h; - } - - if (x2 > 0 && y2 > 0) { - int i, num_rects = drw->num_rects; - struct drm_clip_rect *rect = drw->rects; - - for (i = 0; i < num_rects; i++) - if (!(rect[i].x1 >= x2 || rect[i].y1 >= y2 || - rect[i].x2 <= x1 || rect[i].y2 <= y1)) { - pf_planes = 0x3; - - break; - } - } - - i915_dispatch_flip(dev, pf_planes, 1); -} - -/** * Emit blits for scheduled buffer swaps. * * This function will be called with the HW lock held. @@ -148,19 +45,20 @@ i915_dispatch_vsync_flip(struct drm_device *dev, struct drm_drawable_info *drw, static void i915_vblank_tasklet(struct drm_device *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + unsigned long irqflags; struct list_head *list, *tmp, hits, *hit; - int nhits, nrects, slice[2], upper[2], lower[2], i, num_pages; - unsigned counter[2]; + int nhits, nrects, slice[2], upper[2], lower[2], i; + unsigned counter[2] = { atomic_read(&dev->vbl_received), + atomic_read(&dev->vbl_received2) }; struct drm_drawable_info *drw; drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv; - u32 cpp = dev_priv->cpp, offsets[3]; + u32 cpp = dev_priv->cpp; u32 cmd = (cpp == 4) ? (XY_SRC_COPY_BLT_CMD | XY_SRC_COPY_BLT_WRITE_ALPHA | XY_SRC_COPY_BLT_WRITE_RGB) : XY_SRC_COPY_BLT_CMD; u32 src_pitch = sarea_priv->pitch * cpp; u32 dst_pitch = sarea_priv->pitch * cpp; - /* COPY rop (0xcc), map cpp to magic color depth constants */ u32 ropcpp = (0xcc << 16) | ((cpp - 1) << 24); RING_LOCALS; @@ -173,34 +71,24 @@ static void i915_vblank_tasklet(struct drm_device *dev) src_pitch >>= 2; } - counter[0] = drm_vblank_count(dev, 0); - counter[1] = drm_vblank_count(dev, 1); - DRM_DEBUG("\n"); INIT_LIST_HEAD(&hits); nhits = nrects = 0; - /* No irqsave/restore necessary. This tasklet may be run in an - * interrupt context or normal context, but we don't have to worry - * about getting interrupted by something acquiring the lock, because - * we are the interrupt context thing that acquires the lock. - */ - spin_lock(&dev_priv->swaps_lock); + spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); /* Find buffer swaps scheduled for this vertical blank */ list_for_each_safe(list, tmp, &dev_priv->vbl_swaps.head) { drm_i915_vbl_swap_t *vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head); - int pipe = i915_get_pipe(dev, vbl_swap->plane); - if ((counter[pipe] - vbl_swap->sequence) > (1<<23)) + if ((counter[vbl_swap->pipe] - vbl_swap->sequence) > (1<<23)) continue; list_del(list); dev_priv->swaps_pending--; - drm_vblank_put(dev, pipe); spin_unlock(&dev_priv->swaps_lock); spin_lock(&dev->drw_lock); @@ -238,23 +126,43 @@ static void i915_vblank_tasklet(struct drm_device *dev) spin_lock(&dev_priv->swaps_lock); } - spin_unlock(&dev_priv->swaps_lock); - - if (nhits == 0) + if (nhits == 0) { + spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); return; + } + + spin_unlock(&dev_priv->swaps_lock); i915_kernel_lost_context(dev); - upper[0] = upper[1] = 0; - slice[0] = max(sarea_priv->planeA_h / nhits, 1); - slice[1] = max(sarea_priv->planeB_h / nhits, 1); - lower[0] = sarea_priv->planeA_y + slice[0]; - lower[1] = sarea_priv->planeB_y + slice[0]; + if (IS_I965G(dev)) { + BEGIN_LP_RING(4); + + OUT_RING(GFX_OP_DRAWRECT_INFO_I965); + OUT_RING(0); + OUT_RING(((sarea_priv->width - 1) & 0xffff) | ((sarea_priv->height - 1) << 16)); + OUT_RING(0); + ADVANCE_LP_RING(); + } else { + BEGIN_LP_RING(6); - offsets[0] = sarea_priv->front_offset; - offsets[1] = sarea_priv->back_offset; - offsets[2] = sarea_priv->third_offset; - num_pages = sarea_priv->third_handle ? 3 : 2; + OUT_RING(GFX_OP_DRAWRECT_INFO); + OUT_RING(0); + OUT_RING(0); + OUT_RING(sarea_priv->width | sarea_priv->height << 16); + OUT_RING(sarea_priv->width | sarea_priv->height << 16); + OUT_RING(0); + + ADVANCE_LP_RING(); + } + + sarea_priv->ctxOwner = DRM_KERNEL_CONTEXT; + + upper[0] = upper[1] = 0; + slice[0] = max(sarea_priv->pipeA_h / nhits, 1); + slice[1] = max(sarea_priv->pipeB_h / nhits, 1); + lower[0] = sarea_priv->pipeA_y + slice[0]; + lower[1] = sarea_priv->pipeB_y + slice[0]; spin_lock(&dev->drw_lock); @@ -266,8 +174,6 @@ static void i915_vblank_tasklet(struct drm_device *dev) for (i = 0; i++ < nhits; upper[0] = lower[0], lower[0] += slice[0], upper[1] = lower[1], lower[1] += slice[1]) { - int init_drawrect = 1; - if (i == nhits) lower[0] = lower[1] = sarea_priv->height; @@ -275,7 +181,7 @@ static void i915_vblank_tasklet(struct drm_device *dev) drm_i915_vbl_swap_t *swap_hit = list_entry(hit, drm_i915_vbl_swap_t, head); struct drm_clip_rect *rect; - int num_rects, plane, front, back; + int num_rects, pipe; unsigned short top, bottom; drw = drm_get_drawable_info(dev, swap_hit->drw_id); @@ -283,50 +189,10 @@ static void i915_vblank_tasklet(struct drm_device *dev) if (!drw) continue; - plane = swap_hit->plane; - - if (swap_hit->flip) { - i915_dispatch_vsync_flip(dev, drw, plane); - continue; - } - - if (init_drawrect) { - int width = sarea_priv->width; - int height = sarea_priv->height; - if (IS_I965G(dev)) { - BEGIN_LP_RING(4); - - OUT_RING(GFX_OP_DRAWRECT_INFO_I965); - OUT_RING(0); - OUT_RING(((width - 1) & 0xffff) | ((height - 1) << 16)); - OUT_RING(0); - - ADVANCE_LP_RING(); - } else { - BEGIN_LP_RING(6); - - OUT_RING(GFX_OP_DRAWRECT_INFO); - OUT_RING(0); - OUT_RING(0); - OUT_RING(((width - 1) & 0xffff) | ((height - 1) << 16)); - OUT_RING(0); - OUT_RING(0); - - ADVANCE_LP_RING(); - } - - sarea_priv->ctxOwner = DRM_KERNEL_CONTEXT; - - init_drawrect = 0; - } - rect = drw->rects; - top = upper[plane]; - bottom = lower[plane]; - - front = (dev_priv->sarea_priv->pf_current_page >> - (2 * plane)) & 0x3; - back = (front + 1) % num_pages; + pipe = swap_hit->pipe; + top = upper[pipe]; + bottom = lower[pipe]; for (num_rects = drw->num_rects; num_rects--; rect++) { int y1 = max(rect->y1, top); @@ -341,17 +207,17 @@ static void i915_vblank_tasklet(struct drm_device *dev) OUT_RING(ropcpp | dst_pitch); OUT_RING((y1 << 16) | rect->x1); OUT_RING((y2 << 16) | rect->x2); - OUT_RING(offsets[front]); + OUT_RING(sarea_priv->front_offset); OUT_RING((y1 << 16) | rect->x1); OUT_RING(src_pitch); - OUT_RING(offsets[back]); + OUT_RING(sarea_priv->back_offset); ADVANCE_LP_RING(); } } } - spin_unlock(&dev->drw_lock); + spin_unlock_irqrestore(&dev->drw_lock, irqflags); list_for_each_safe(hit, tmp, &hits) { drm_i915_vbl_swap_t *swap_hit = @@ -363,112 +229,67 @@ static void i915_vblank_tasklet(struct drm_device *dev) } } -u32 i915_get_vblank_counter(struct drm_device *dev, int plane) -{ - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - unsigned long high_frame; - unsigned long low_frame; - u32 high1, high2, low, count; - int pipe; - - pipe = i915_get_pipe(dev, plane); - high_frame = pipe ? PIPEBFRAMEHIGH : PIPEAFRAMEHIGH; - low_frame = pipe ? PIPEBFRAMEPIXEL : PIPEAFRAMEPIXEL; - - if (!i915_pipe_enabled(dev, pipe)) { - printk(KERN_ERR "trying to get vblank count for disabled " - "pipe %d\n", pipe); - return 0; - } - - /* - * High & low register fields aren't synchronized, so make sure - * we get a low value that's stable across two reads of the high - * register. - */ - do { - high1 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >> - PIPE_FRAME_HIGH_SHIFT); - low = ((I915_READ(low_frame) & PIPE_FRAME_LOW_MASK) >> - PIPE_FRAME_LOW_SHIFT); - high2 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >> - PIPE_FRAME_HIGH_SHIFT); - } while (high1 != high2); - - count = (high1 << 8) | low; - - /* count may be reset by other driver(e.g. 2D driver), - we have no way to know if it is wrapped or resetted - when count is zero. do a rough guess. - */ - if (count == 0 && dev->last_vblank[pipe] < dev->max_vblank_count/2) - dev->last_vblank[pipe] = 0; - - return count; -} - irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) { struct drm_device *dev = (struct drm_device *) arg; drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - u32 iir; + u16 temp; u32 pipea_stats, pipeb_stats; - int vblank = 0; - - iir = I915_READ(I915REG_INT_IDENTITY_R); - if (iir == 0) { - DRM_DEBUG ("iir 0x%08x im 0x%08x ie 0x%08x pipea 0x%08x pipeb 0x%08x\n", - iir, - I915_READ(I915REG_INT_MASK_R), - I915_READ(I915REG_INT_ENABLE_R), - I915_READ(I915REG_PIPEASTAT), - I915_READ(I915REG_PIPEBSTAT)); - return IRQ_NONE; - } - /* - * Clear the PIPE(A|B)STAT regs before the IIR otherwise - * we may get extra interrupts. - */ - if (iir & I915_DISPLAY_PIPE_A_EVENT_INTERRUPT) { - pipea_stats = I915_READ(I915REG_PIPEASTAT); - if (pipea_stats & (I915_START_VBLANK_INTERRUPT_STATUS| - I915_VBLANK_INTERRUPT_STATUS)) - { - vblank++; - drm_handle_vblank(dev, i915_get_plane(dev, 0)); - } - I915_WRITE(I915REG_PIPEASTAT, pipea_stats); - } - if (iir & I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) { - pipeb_stats = I915_READ(I915REG_PIPEBSTAT); - if (pipeb_stats & (I915_START_VBLANK_INTERRUPT_STATUS| - I915_VBLANK_INTERRUPT_STATUS)) - { - vblank++; - drm_handle_vblank(dev, i915_get_plane(dev, 1)); - } - I915_WRITE(I915REG_PIPEBSTAT, pipeb_stats); - } + pipea_stats = I915_READ(I915REG_PIPEASTAT); + pipeb_stats = I915_READ(I915REG_PIPEBSTAT); - if (dev_priv->sarea_priv) - dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); + temp = I915_READ16(I915REG_INT_IDENTITY_R); - I915_WRITE(I915REG_INT_IDENTITY_R, iir); - (void) I915_READ(I915REG_INT_IDENTITY_R); /* Flush posted write */ + temp &= (USER_INT_FLAG | VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG); - if (iir & I915_USER_INTERRUPT) { + DRM_DEBUG("%s flag=%08x\n", __FUNCTION__, temp); + + if (temp == 0) + return IRQ_NONE; + + I915_WRITE16(I915REG_INT_IDENTITY_R, temp); + (void) I915_READ16(I915REG_INT_IDENTITY_R); + DRM_READMEMORYBARRIER(); + + dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); + + if (temp & USER_INT_FLAG) DRM_WAKEUP(&dev_priv->irq_queue); - } - if (vblank) { + + if (temp & (VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG)) { + int vblank_pipe = dev_priv->vblank_pipe; + + if ((vblank_pipe & + (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B)) + == (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B)) { + if (temp & VSYNC_PIPEA_FLAG) + atomic_inc(&dev->vbl_received); + if (temp & VSYNC_PIPEB_FLAG) + atomic_inc(&dev->vbl_received2); + } else if (((temp & VSYNC_PIPEA_FLAG) && + (vblank_pipe & DRM_I915_VBLANK_PIPE_A)) || + ((temp & VSYNC_PIPEB_FLAG) && + (vblank_pipe & DRM_I915_VBLANK_PIPE_B))) + atomic_inc(&dev->vbl_received); + + DRM_WAKEUP(&dev->vbl_queue); + drm_vbl_send_signals(dev); + if (dev_priv->swaps_pending > 0) drm_locked_tasklet(dev, i915_vblank_tasklet); + I915_WRITE(I915REG_PIPEASTAT, + pipea_stats|I915_VBLANK_INTERRUPT_ENABLE| + I915_VBLANK_CLEAR); + I915_WRITE(I915REG_PIPEBSTAT, + pipeb_stats|I915_VBLANK_INTERRUPT_ENABLE| + I915_VBLANK_CLEAR); } return IRQ_HANDLED; } -static int i915_emit_irq(struct drm_device *dev) +static int i915_emit_irq(struct drm_device * dev) { drm_i915_private_t *dev_priv = dev->dev_private; RING_LOCALS; @@ -515,12 +336,42 @@ static int i915_wait_irq(struct drm_device * dev, int irq_nr) READ_BREADCRUMB(dev_priv), (int)dev_priv->counter); } - if (dev_priv->sarea_priv) - dev_priv->sarea_priv->last_dispatch = - READ_BREADCRUMB(dev_priv); + dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); return ret; } +static int i915_driver_vblank_do_wait(struct drm_device *dev, unsigned int *sequence, + atomic_t *counter) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + unsigned int cur_vblank; + int ret = 0; + + if (!dev_priv) { + DRM_ERROR("called with no initialization\n"); + return -EINVAL; + } + + DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ, + (((cur_vblank = atomic_read(counter)) + - *sequence) <= (1<<23))); + + *sequence = cur_vblank; + + return ret; +} + + +int i915_driver_vblank_wait(struct drm_device *dev, unsigned int *sequence) +{ + return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received); +} + +int i915_driver_vblank_wait2(struct drm_device *dev, unsigned int *sequence) +{ + return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received2); +} + /* Needs the lock as it touches the ring. */ int i915_irq_emit(struct drm_device *dev, void *data, @@ -563,96 +414,18 @@ int i915_irq_wait(struct drm_device *dev, void *data, return i915_wait_irq(dev, irqwait->irq_seq); } -int i915_enable_vblank(struct drm_device *dev, int plane) -{ - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - int pipe = i915_get_pipe(dev, plane); - u32 pipestat_reg = 0; - u32 pipestat; - - switch (pipe) { - case 0: - pipestat_reg = I915REG_PIPEASTAT; - dev_priv->irq_enable_reg |= I915_DISPLAY_PIPE_A_EVENT_INTERRUPT; - break; - case 1: - pipestat_reg = I915REG_PIPEBSTAT; - dev_priv->irq_enable_reg |= I915_DISPLAY_PIPE_B_EVENT_INTERRUPT; - break; - default: - DRM_ERROR("tried to enable vblank on non-existent pipe %d\n", - pipe); - break; - } - - if (pipestat_reg) - { - pipestat = I915_READ (pipestat_reg); - /* - * Older chips didn't have the start vblank interrupt, - * but - */ - if (IS_I965G (dev)) - pipestat |= I915_START_VBLANK_INTERRUPT_ENABLE; - else - pipestat |= I915_VBLANK_INTERRUPT_ENABLE; - /* - * Clear any pending status - */ - pipestat |= (I915_START_VBLANK_INTERRUPT_STATUS | - I915_VBLANK_INTERRUPT_STATUS); - I915_WRITE(pipestat_reg, pipestat); - } - I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); - - return 0; -} - -void i915_disable_vblank(struct drm_device *dev, int plane) -{ - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - int pipe = i915_get_pipe(dev, plane); - u32 pipestat_reg = 0; - u32 pipestat; - - switch (pipe) { - case 0: - pipestat_reg = I915REG_PIPEASTAT; - dev_priv->irq_enable_reg &= ~I915_DISPLAY_PIPE_A_EVENT_INTERRUPT; - break; - case 1: - pipestat_reg = I915REG_PIPEBSTAT; - dev_priv->irq_enable_reg &= ~I915_DISPLAY_PIPE_B_EVENT_INTERRUPT; - break; - default: - DRM_ERROR("tried to disable vblank on non-existent pipe %d\n", - pipe); - break; - } - - I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); - if (pipestat_reg) - { - pipestat = I915_READ (pipestat_reg); - pipestat &= ~(I915_START_VBLANK_INTERRUPT_ENABLE | - I915_VBLANK_INTERRUPT_ENABLE); - /* - * Clear any pending status - */ - pipestat |= (I915_START_VBLANK_INTERRUPT_STATUS | - I915_VBLANK_INTERRUPT_STATUS); - I915_WRITE(pipestat_reg, pipestat); - } -} - static void i915_enable_interrupt (struct drm_device *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + u16 flag; - dev_priv->irq_enable_reg |= I915_USER_INTERRUPT; + flag = 0; + if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_A) + flag |= VSYNC_PIPEA_FLAG; + if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B) + flag |= VSYNC_PIPEB_FLAG; - I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); - dev_priv->irq_enabled = 1; + I915_WRITE16(I915REG_INT_ENABLE_R, USER_INT_FLAG | flag); } /* Set the vblank monitor pipe @@ -675,6 +448,8 @@ int i915_vblank_pipe_set(struct drm_device *dev, void *data, dev_priv->vblank_pipe = pipe->pipe; + i915_enable_interrupt (dev); + return 0; } @@ -692,9 +467,9 @@ int i915_vblank_pipe_get(struct drm_device *dev, void *data, flag = I915_READ(I915REG_INT_ENABLE_R); pipe->pipe = 0; - if (flag & I915_DISPLAY_PIPE_A_EVENT_INTERRUPT) + if (flag & VSYNC_PIPEA_FLAG) pipe->pipe |= DRM_I915_VBLANK_PIPE_A; - if (flag & I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) + if (flag & VSYNC_PIPEB_FLAG) pipe->pipe |= DRM_I915_VBLANK_PIPE_B; return 0; @@ -709,30 +484,27 @@ int i915_vblank_swap(struct drm_device *dev, void *data, drm_i915_private_t *dev_priv = dev->dev_private; drm_i915_vblank_swap_t *swap = data; drm_i915_vbl_swap_t *vbl_swap; - unsigned int pipe, seqtype, curseq, plane; + unsigned int pipe, seqtype, curseq; unsigned long irqflags; struct list_head *list; - int ret; if (!dev_priv) { DRM_ERROR("%s called with no initialization\n", __func__); return -EINVAL; } - if (!dev_priv->sarea_priv || dev_priv->sarea_priv->rotation) { + if (dev_priv->sarea_priv->rotation) { DRM_DEBUG("Rotation not supported\n"); return -EINVAL; } if (swap->seqtype & ~(_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE | - _DRM_VBLANK_SECONDARY | _DRM_VBLANK_NEXTONMISS | - _DRM_VBLANK_FLIP)) { + _DRM_VBLANK_SECONDARY | _DRM_VBLANK_NEXTONMISS)) { DRM_ERROR("Invalid sequence type 0x%x\n", swap->seqtype); return -EINVAL; } - plane = (swap->seqtype & _DRM_VBLANK_SECONDARY) ? 1 : 0; - pipe = i915_get_pipe(dev, plane); + pipe = (swap->seqtype & _DRM_VBLANK_SECONDARY) ? 1 : 0; seqtype = swap->seqtype & (_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE); @@ -743,11 +515,6 @@ int i915_vblank_swap(struct drm_device *dev, void *data, spin_lock_irqsave(&dev->drw_lock, irqflags); - /* It makes no sense to schedule a swap for a drawable that doesn't have - * valid information at this point. E.g. this could mean that the X - * server is too old to push drawable information to the DRM, in which - * case all such swaps would become ineffective. - */ if (!drm_get_drawable_info(dev, swap->drawable)) { spin_unlock_irqrestore(&dev->drw_lock, irqflags); DRM_DEBUG("Invalid drawable ID %d\n", swap->drawable); @@ -756,8 +523,7 @@ int i915_vblank_swap(struct drm_device *dev, void *data, spin_unlock_irqrestore(&dev->drw_lock, irqflags); - drm_update_vblank_count(dev, pipe); - curseq = drm_vblank_count(dev, pipe); + curseq = atomic_read(pipe ? &dev->vbl_received2 : &dev->vbl_received); if (seqtype == _DRM_VBLANK_RELATIVE) swap->sequence += curseq; @@ -771,43 +537,14 @@ int i915_vblank_swap(struct drm_device *dev, void *data, } } - if (swap->seqtype & _DRM_VBLANK_FLIP) { - swap->sequence--; - - if ((curseq - swap->sequence) <= (1<<23)) { - struct drm_drawable_info *drw; - - LOCK_TEST_WITH_RETURN(dev, file_priv); - - spin_lock_irqsave(&dev->drw_lock, irqflags); - - drw = drm_get_drawable_info(dev, swap->drawable); - - if (!drw) { - spin_unlock_irqrestore(&dev->drw_lock, - irqflags); - DRM_DEBUG("Invalid drawable ID %d\n", - swap->drawable); - return -EINVAL; - } - - i915_dispatch_vsync_flip(dev, drw, plane); - - spin_unlock_irqrestore(&dev->drw_lock, irqflags); - - return 0; - } - } - spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); list_for_each(list, &dev_priv->vbl_swaps.head) { vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head); if (vbl_swap->drw_id == swap->drawable && - vbl_swap->plane == plane && + vbl_swap->pipe == pipe && vbl_swap->sequence == swap->sequence) { - vbl_swap->flip = (swap->seqtype & _DRM_VBLANK_FLIP); spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); DRM_DEBUG("Already scheduled\n"); return 0; @@ -830,19 +567,9 @@ int i915_vblank_swap(struct drm_device *dev, void *data, DRM_DEBUG("\n"); - ret = drm_vblank_get(dev, pipe); - if (ret) { - drm_free(vbl_swap, sizeof(*vbl_swap), DRM_MEM_DRIVER); - return ret; - } - vbl_swap->drw_id = swap->drawable; - vbl_swap->plane = plane; + vbl_swap->pipe = pipe; vbl_swap->sequence = swap->sequence; - vbl_swap->flip = (swap->seqtype & _DRM_VBLANK_FLIP); - - if (vbl_swap->flip) - swap->sequence++; spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); @@ -860,57 +587,37 @@ void i915_driver_irq_preinstall(struct drm_device * dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - I915_WRITE16(I915REG_HWSTAM, 0xeffe); + I915_WRITE16(I915REG_HWSTAM, 0xfffe); I915_WRITE16(I915REG_INT_MASK_R, 0x0); I915_WRITE16(I915REG_INT_ENABLE_R, 0x0); } -int i915_driver_irq_postinstall(struct drm_device * dev) +void i915_driver_irq_postinstall(struct drm_device * dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - int ret, num_pipes = 2; spin_lock_init(&dev_priv->swaps_lock); INIT_LIST_HEAD(&dev_priv->vbl_swaps.head); dev_priv->swaps_pending = 0; - dev_priv->user_irq_refcount = 0; - dev_priv->irq_enable_reg = 0; - - ret = drm_vblank_init(dev, num_pipes); - if (ret) - return ret; - - dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ - + if (!dev_priv->vblank_pipe) + dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A; i915_enable_interrupt(dev); DRM_INIT_WAITQUEUE(&dev_priv->irq_queue); - - /* - * Initialize the hardware status page IRQ location. - */ - - I915_WRITE(I915REG_INSTPM, (1 << 5) | (1 << 21)); - return 0; } void i915_driver_irq_uninstall(struct drm_device * dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - u32 temp; + u16 temp; if (!dev_priv) return; - dev_priv->irq_enabled = 0; - I915_WRITE(I915REG_HWSTAM, 0xffffffff); - I915_WRITE(I915REG_INT_MASK_R, 0xffffffff); - I915_WRITE(I915REG_INT_ENABLE_R, 0x0); - - temp = I915_READ(I915REG_PIPEASTAT); - I915_WRITE(I915REG_PIPEASTAT, temp); - temp = I915_READ(I915REG_PIPEBSTAT); - I915_WRITE(I915REG_PIPEBSTAT, temp); - temp = I915_READ(I915REG_INT_IDENTITY_R); - I915_WRITE(I915REG_INT_IDENTITY_R, temp); + I915_WRITE16(I915REG_HWSTAM, 0xffff); + I915_WRITE16(I915REG_INT_MASK_R, 0xffff); + I915_WRITE16(I915REG_INT_ENABLE_R, 0x0); + + temp = I915_READ16(I915REG_INT_IDENTITY_R); + I915_WRITE16(I915REG_INT_IDENTITY_R, temp); } diff --git a/drivers/char/drm/mga_drv.c b/drivers/char/drm/mga_drv.c index 6b3790939e76..5572939fc7d1 100644 --- a/drivers/char/drm/mga_drv.c +++ b/drivers/char/drm/mga_drv.c @@ -45,16 +45,15 @@ static struct pci_device_id pciidlist[] = { static struct drm_driver driver = { .driver_features = DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | - DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED, + DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | + DRIVER_IRQ_VBL, .dev_priv_size = sizeof(drm_mga_buf_priv_t), .load = mga_driver_load, .unload = mga_driver_unload, .lastclose = mga_driver_lastclose, .dma_quiescent = mga_driver_dma_quiescent, .device_is_agp = mga_driver_device_is_agp, - .get_vblank_counter = mga_get_vblank_counter, - .enable_vblank = mga_enable_vblank, - .disable_vblank = mga_disable_vblank, + .vblank_wait = mga_driver_vblank_wait, .irq_preinstall = mga_driver_irq_preinstall, .irq_postinstall = mga_driver_irq_postinstall, .irq_uninstall = mga_driver_irq_uninstall, diff --git a/drivers/char/drm/mga_drv.h b/drivers/char/drm/mga_drv.h index 8f7291f36363..f6ebd24bd587 100644 --- a/drivers/char/drm/mga_drv.h +++ b/drivers/char/drm/mga_drv.h @@ -120,7 +120,6 @@ typedef struct drm_mga_private { u32 clear_cmd; u32 maccess; - atomic_t vbl_received; /**< Number of vblanks received. */ wait_queue_head_t fence_queue; atomic_t last_fence_retired; u32 next_fence_to_post; @@ -182,14 +181,11 @@ extern int mga_warp_install_microcode(drm_mga_private_t * dev_priv); extern int mga_warp_init(drm_mga_private_t * dev_priv); /* mga_irq.c */ -extern int mga_enable_vblank(struct drm_device *dev, int crtc); -extern void mga_disable_vblank(struct drm_device *dev, int crtc); -extern u32 mga_get_vblank_counter(struct drm_device *dev, int crtc); extern int mga_driver_fence_wait(struct drm_device * dev, unsigned int *sequence); extern int mga_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence); extern irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS); extern void mga_driver_irq_preinstall(struct drm_device * dev); -extern int mga_driver_irq_postinstall(struct drm_device * dev); +extern void mga_driver_irq_postinstall(struct drm_device * dev); extern void mga_driver_irq_uninstall(struct drm_device * dev); extern long mga_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); diff --git a/drivers/char/drm/mga_irq.c b/drivers/char/drm/mga_irq.c index 06852fb4b278..9302cb8f0f83 100644 --- a/drivers/char/drm/mga_irq.c +++ b/drivers/char/drm/mga_irq.c @@ -35,20 +35,6 @@ #include "mga_drm.h" #include "mga_drv.h" -u32 mga_get_vblank_counter(struct drm_device *dev, int crtc) -{ - const drm_mga_private_t *const dev_priv = - (drm_mga_private_t *) dev->dev_private; - - if (crtc != 0) { - return 0; - } - - - return atomic_read(&dev_priv->vbl_received); -} - - irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS) { struct drm_device *dev = (struct drm_device *) arg; @@ -61,8 +47,9 @@ irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS) /* VBLANK interrupt */ if (status & MGA_VLINEPEN) { MGA_WRITE(MGA_ICLEAR, MGA_VLINEICLR); - atomic_inc(&dev_priv->vbl_received); - drm_handle_vblank(dev, 0); + atomic_inc(&dev->vbl_received); + DRM_WAKEUP(&dev->vbl_queue); + drm_vbl_send_signals(dev); handled = 1; } @@ -91,34 +78,22 @@ irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS) return IRQ_NONE; } -int mga_enable_vblank(struct drm_device *dev, int crtc) +int mga_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence) { - drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; - - if (crtc != 0) { - DRM_ERROR("tried to enable vblank on non-existent crtc %d\n", - crtc); - return 0; - } - - MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN); - return 0; -} + unsigned int cur_vblank; + int ret = 0; + /* Assume that the user has missed the current sequence number + * by about a day rather than she wants to wait for years + * using vertical blanks... + */ + DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ, + (((cur_vblank = atomic_read(&dev->vbl_received)) + - *sequence) <= (1 << 23))); -void mga_disable_vblank(struct drm_device *dev, int crtc) -{ - if (crtc != 0) { - DRM_ERROR("tried to disable vblank on non-existent crtc %d\n", - crtc); - } + *sequence = cur_vblank; - /* Do *NOT* disable the vertical refresh interrupt. MGA doesn't have - * a nice hardware counter that tracks the number of refreshes when - * the interrupt is disabled, and the kernel doesn't know the refresh - * rate to calculate an estimate. - */ - /* MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN); */ + return ret; } int mga_driver_fence_wait(struct drm_device * dev, unsigned int *sequence) @@ -150,22 +125,14 @@ void mga_driver_irq_preinstall(struct drm_device * dev) MGA_WRITE(MGA_ICLEAR, ~0); } -int mga_driver_irq_postinstall(struct drm_device * dev) +void mga_driver_irq_postinstall(struct drm_device * dev) { drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; - int ret; - - ret = drm_vblank_init(dev, 1); - if (ret) - return ret; DRM_INIT_WAITQUEUE(&dev_priv->fence_queue); - /* Turn on soft trap interrupt. Vertical blank interrupts are enabled - * in mga_enable_vblank. - */ - MGA_WRITE(MGA_IEN, MGA_SOFTRAPEN); - return 0; + /* Turn on vertical blank interrupt and soft trap interrupt. */ + MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN); } void mga_driver_irq_uninstall(struct drm_device * dev) diff --git a/drivers/char/drm/r128_drv.c b/drivers/char/drm/r128_drv.c index 2888aa01ebc7..6108e7587e12 100644 --- a/drivers/char/drm/r128_drv.c +++ b/drivers/char/drm/r128_drv.c @@ -43,13 +43,12 @@ static struct pci_device_id pciidlist[] = { static struct drm_driver driver = { .driver_features = DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG | - DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED, + DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | + DRIVER_IRQ_VBL, .dev_priv_size = sizeof(drm_r128_buf_priv_t), .preclose = r128_driver_preclose, .lastclose = r128_driver_lastclose, - .get_vblank_counter = r128_get_vblank_counter, - .enable_vblank = r128_enable_vblank, - .disable_vblank = r128_disable_vblank, + .vblank_wait = r128_driver_vblank_wait, .irq_preinstall = r128_driver_irq_preinstall, .irq_postinstall = r128_driver_irq_postinstall, .irq_uninstall = r128_driver_irq_uninstall, diff --git a/drivers/char/drm/r128_drv.h b/drivers/char/drm/r128_drv.h index 80af9e09e75d..011105e51ac6 100644 --- a/drivers/char/drm/r128_drv.h +++ b/drivers/char/drm/r128_drv.h @@ -97,8 +97,6 @@ typedef struct drm_r128_private { u32 crtc_offset; u32 crtc_offset_cntl; - atomic_t vbl_received; - u32 color_fmt; unsigned int front_offset; unsigned int front_pitch; @@ -151,12 +149,11 @@ extern int r128_wait_ring(drm_r128_private_t * dev_priv, int n); extern int r128_do_cce_idle(drm_r128_private_t * dev_priv); extern int r128_do_cleanup_cce(struct drm_device * dev); -extern int r128_enable_vblank(struct drm_device *dev, int crtc); -extern void r128_disable_vblank(struct drm_device *dev, int crtc); -extern u32 r128_get_vblank_counter(struct drm_device *dev, int crtc); +extern int r128_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence); + extern irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS); extern void r128_driver_irq_preinstall(struct drm_device * dev); -extern int r128_driver_irq_postinstall(struct drm_device * dev); +extern void r128_driver_irq_postinstall(struct drm_device * dev); extern void r128_driver_irq_uninstall(struct drm_device * dev); extern void r128_driver_lastclose(struct drm_device * dev); extern void r128_driver_preclose(struct drm_device * dev, diff --git a/drivers/char/drm/r128_irq.c b/drivers/char/drm/r128_irq.c index 5b95bd898f95..c76fdca7662d 100644 --- a/drivers/char/drm/r128_irq.c +++ b/drivers/char/drm/r128_irq.c @@ -35,16 +35,6 @@ #include "r128_drm.h" #include "r128_drv.h" -u32 r128_get_vblank_counter(struct drm_device *dev, int crtc) -{ - const drm_r128_private_t *dev_priv = dev->dev_private; - - if (crtc != 0) - return 0; - - return atomic_read(&dev_priv->vbl_received); -} - irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS) { struct drm_device *dev = (struct drm_device *) arg; @@ -56,38 +46,30 @@ irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS) /* VBLANK interrupt */ if (status & R128_CRTC_VBLANK_INT) { R128_WRITE(R128_GEN_INT_STATUS, R128_CRTC_VBLANK_INT_AK); - atomic_inc(&dev_priv->vbl_received); - drm_handle_vblank(dev, 0); + atomic_inc(&dev->vbl_received); + DRM_WAKEUP(&dev->vbl_queue); + drm_vbl_send_signals(dev); return IRQ_HANDLED; } return IRQ_NONE; } -int r128_enable_vblank(struct drm_device *dev, int crtc) +int r128_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence) { - drm_r128_private_t *dev_priv = dev->dev_private; - - if (crtc != 0) { - DRM_ERROR("%s: bad crtc %d\n", __FUNCTION__, crtc); - return -EINVAL; - } + unsigned int cur_vblank; + int ret = 0; - R128_WRITE(R128_GEN_INT_CNTL, R128_CRTC_VBLANK_INT_EN); - return 0; -} + /* Assume that the user has missed the current sequence number + * by about a day rather than she wants to wait for years + * using vertical blanks... + */ + DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ, + (((cur_vblank = atomic_read(&dev->vbl_received)) + - *sequence) <= (1 << 23))); -void r128_disable_vblank(struct drm_device *dev, int crtc) -{ - if (crtc != 0) - DRM_ERROR("%s: bad crtc %d\n", __FUNCTION__, crtc); + *sequence = cur_vblank; - /* - * FIXME: implement proper interrupt disable by using the vblank - * counter register (if available) - * - * R128_WRITE(R128_GEN_INT_CNTL, - * R128_READ(R128_GEN_INT_CNTL) & ~R128_CRTC_VBLANK_INT_EN); - */ + return ret; } void r128_driver_irq_preinstall(struct drm_device * dev) @@ -100,9 +82,12 @@ void r128_driver_irq_preinstall(struct drm_device * dev) R128_WRITE(R128_GEN_INT_STATUS, R128_CRTC_VBLANK_INT_AK); } -int r128_driver_irq_postinstall(struct drm_device * dev) +void r128_driver_irq_postinstall(struct drm_device * dev) { - return drm_vblank_init(dev, 1); + drm_r128_private_t *dev_priv = (drm_r128_private_t *) dev->dev_private; + + /* Turn on VBL interrupt */ + R128_WRITE(R128_GEN_INT_CNTL, R128_CRTC_VBLANK_INT_EN); } void r128_driver_irq_uninstall(struct drm_device * dev) diff --git a/drivers/char/drm/radeon_drv.c b/drivers/char/drm/radeon_drv.c index a2610319624d..349ac3d3b848 100644 --- a/drivers/char/drm/radeon_drv.c +++ b/drivers/char/drm/radeon_drv.c @@ -59,7 +59,8 @@ static struct pci_device_id pciidlist[] = { static struct drm_driver driver = { .driver_features = DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG | - DRIVER_HAVE_IRQ | DRIVER_HAVE_DMA | DRIVER_IRQ_SHARED, + DRIVER_HAVE_IRQ | DRIVER_HAVE_DMA | DRIVER_IRQ_SHARED | + DRIVER_IRQ_VBL | DRIVER_IRQ_VBL2, .dev_priv_size = sizeof(drm_radeon_buf_priv_t), .load = radeon_driver_load, .firstopen = radeon_driver_firstopen, @@ -68,9 +69,8 @@ static struct drm_driver driver = { .postclose = radeon_driver_postclose, .lastclose = radeon_driver_lastclose, .unload = radeon_driver_unload, - .get_vblank_counter = radeon_get_vblank_counter, - .enable_vblank = radeon_enable_vblank, - .disable_vblank = radeon_disable_vblank, + .vblank_wait = radeon_driver_vblank_wait, + .vblank_wait2 = radeon_driver_vblank_wait2, .dri_library_name = dri_library_name, .irq_preinstall = radeon_driver_irq_preinstall, .irq_postinstall = radeon_driver_irq_postinstall, diff --git a/drivers/char/drm/radeon_drv.h b/drivers/char/drm/radeon_drv.h index b791420bd3d9..173ae620223a 100644 --- a/drivers/char/drm/radeon_drv.h +++ b/drivers/char/drm/radeon_drv.h @@ -304,9 +304,6 @@ typedef struct drm_radeon_private { u32 scratch_ages[5]; - unsigned int crtc_last_cnt; - unsigned int crtc2_last_cnt; - /* starting from here on, data is preserved accross an open */ uint32_t flags; /* see radeon_chip_flags */ unsigned long fb_aper_offset; @@ -377,13 +374,13 @@ extern int radeon_irq_emit(struct drm_device *dev, void *data, struct drm_file * extern int radeon_irq_wait(struct drm_device *dev, void *data, struct drm_file *file_priv); extern void radeon_do_release(struct drm_device * dev); -extern u32 radeon_get_vblank_counter(struct drm_device *dev, int crtc); -extern int radeon_enable_vblank(struct drm_device *dev, int crtc); -extern void radeon_disable_vblank(struct drm_device *dev, int crtc); -extern void radeon_do_release(struct drm_device * dev); +extern int radeon_driver_vblank_wait(struct drm_device * dev, + unsigned int *sequence); +extern int radeon_driver_vblank_wait2(struct drm_device * dev, + unsigned int *sequence); extern irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS); extern void radeon_driver_irq_preinstall(struct drm_device * dev); -extern int radeon_driver_irq_postinstall(struct drm_device * dev); +extern void radeon_driver_irq_postinstall(struct drm_device * dev); extern void radeon_driver_irq_uninstall(struct drm_device * dev); extern int radeon_vblank_crtc_get(struct drm_device *dev); extern int radeon_vblank_crtc_set(struct drm_device *dev, int64_t value); @@ -561,12 +558,6 @@ extern int r300_do_cp_cmdbuf(struct drm_device * dev, ? DRM_READ32( dev_priv->ring_rptr, RADEON_SCRATCHOFF(x) ) \ : RADEON_READ( RADEON_SCRATCH_REG0 + 4*(x) ) ) -#define RADEON_CRTC_CRNT_FRAME 0x0214 -#define RADEON_CRTC2_CRNT_FRAME 0x0314 - -#define RADEON_CRTC_STATUS 0x005c -#define RADEON_CRTC2_STATUS 0x03fc - #define RADEON_GEN_INT_CNTL 0x0040 # define RADEON_CRTC_VBLANK_MASK (1 << 0) # define RADEON_CRTC2_VBLANK_MASK (1 << 9) diff --git a/drivers/char/drm/radeon_irq.c b/drivers/char/drm/radeon_irq.c index 507d6b747a13..009af3814b6f 100644 --- a/drivers/char/drm/radeon_irq.c +++ b/drivers/char/drm/radeon_irq.c @@ -35,61 +35,12 @@ #include "radeon_drm.h" #include "radeon_drv.h" -static void radeon_irq_set_state(struct drm_device *dev, u32 mask, int state) +static __inline__ u32 radeon_acknowledge_irqs(drm_radeon_private_t * dev_priv, + u32 mask) { - drm_radeon_private_t *dev_priv = dev->dev_private; - - if (state) - dev_priv->irq_enable_reg |= mask; - else - dev_priv->irq_enable_reg &= ~mask; - - RADEON_WRITE(RADEON_GEN_INT_CNTL, dev_priv->irq_enable_reg); -} - -int radeon_enable_vblank(struct drm_device *dev, int crtc) -{ - switch (crtc) { - case 0: - radeon_irq_set_state(dev, RADEON_CRTC_VBLANK_MASK, 1); - break; - case 1: - radeon_irq_set_state(dev, RADEON_CRTC2_VBLANK_MASK, 1); - break; - default: - DRM_ERROR("tried to enable vblank on non-existent crtc %d\n", - crtc); - return EINVAL; - } - - return 0; -} - -void radeon_disable_vblank(struct drm_device *dev, int crtc) -{ - switch (crtc) { - case 0: - radeon_irq_set_state(dev, RADEON_CRTC_VBLANK_MASK, 0); - break; - case 1: - radeon_irq_set_state(dev, RADEON_CRTC2_VBLANK_MASK, 0); - break; - default: - DRM_ERROR("tried to enable vblank on non-existent crtc %d\n", - crtc); - break; - } -} - -static __inline__ u32 radeon_acknowledge_irqs(drm_radeon_private_t * dev_priv) -{ - u32 irqs = RADEON_READ(RADEON_GEN_INT_STATUS) & - (RADEON_SW_INT_TEST | RADEON_CRTC_VBLANK_STAT | - RADEON_CRTC2_VBLANK_STAT); - + u32 irqs = RADEON_READ(RADEON_GEN_INT_STATUS) & mask; if (irqs) RADEON_WRITE(RADEON_GEN_INT_STATUS, irqs); - return irqs; } @@ -121,21 +72,39 @@ irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS) /* Only consider the bits we're interested in - others could be used * outside the DRM */ - stat = radeon_acknowledge_irqs(dev_priv); + stat = radeon_acknowledge_irqs(dev_priv, (RADEON_SW_INT_TEST_ACK | + RADEON_CRTC_VBLANK_STAT | + RADEON_CRTC2_VBLANK_STAT)); if (!stat) return IRQ_NONE; stat &= dev_priv->irq_enable_reg; /* SW interrupt */ - if (stat & RADEON_SW_INT_TEST) + if (stat & RADEON_SW_INT_TEST) { DRM_WAKEUP(&dev_priv->swi_queue); + } /* VBLANK interrupt */ - if (stat & RADEON_CRTC_VBLANK_STAT) - drm_handle_vblank(dev, 0); - if (stat & RADEON_CRTC2_VBLANK_STAT) - drm_handle_vblank(dev, 1); + if (stat & (RADEON_CRTC_VBLANK_STAT|RADEON_CRTC2_VBLANK_STAT)) { + int vblank_crtc = dev_priv->vblank_crtc; + + if ((vblank_crtc & + (DRM_RADEON_VBLANK_CRTC1 | DRM_RADEON_VBLANK_CRTC2)) == + (DRM_RADEON_VBLANK_CRTC1 | DRM_RADEON_VBLANK_CRTC2)) { + if (stat & RADEON_CRTC_VBLANK_STAT) + atomic_inc(&dev->vbl_received); + if (stat & RADEON_CRTC2_VBLANK_STAT) + atomic_inc(&dev->vbl_received2); + } else if (((stat & RADEON_CRTC_VBLANK_STAT) && + (vblank_crtc & DRM_RADEON_VBLANK_CRTC1)) || + ((stat & RADEON_CRTC2_VBLANK_STAT) && + (vblank_crtc & DRM_RADEON_VBLANK_CRTC2))) + atomic_inc(&dev->vbl_received); + + DRM_WAKEUP(&dev->vbl_queue); + drm_vbl_send_signals(dev); + } return IRQ_HANDLED; } @@ -175,27 +144,54 @@ static int radeon_wait_irq(struct drm_device * dev, int swi_nr) return ret; } -u32 radeon_get_vblank_counter(struct drm_device *dev, int crtc) +static int radeon_driver_vblank_do_wait(struct drm_device * dev, + unsigned int *sequence, int crtc) { - drm_radeon_private_t *dev_priv = dev->dev_private; - u32 crtc_cnt_reg, crtc_status_reg; - + drm_radeon_private_t *dev_priv = + (drm_radeon_private_t *) dev->dev_private; + unsigned int cur_vblank; + int ret = 0; + int ack = 0; + atomic_t *counter; if (!dev_priv) { DRM_ERROR("called with no initialization\n"); return -EINVAL; } - if (crtc == 0) { - crtc_cnt_reg = RADEON_CRTC_CRNT_FRAME; - crtc_status_reg = RADEON_CRTC_STATUS; - } else if (crtc == 1) { - crtc_cnt_reg = RADEON_CRTC2_CRNT_FRAME; - crtc_status_reg = RADEON_CRTC2_STATUS; - } else { + if (crtc == DRM_RADEON_VBLANK_CRTC1) { + counter = &dev->vbl_received; + ack |= RADEON_CRTC_VBLANK_STAT; + } else if (crtc == DRM_RADEON_VBLANK_CRTC2) { + counter = &dev->vbl_received2; + ack |= RADEON_CRTC2_VBLANK_STAT; + } else return -EINVAL; - } - return RADEON_READ(crtc_cnt_reg) + (RADEON_READ(crtc_status_reg) & 1); + radeon_acknowledge_irqs(dev_priv, ack); + + dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE; + + /* Assume that the user has missed the current sequence number + * by about a day rather than she wants to wait for years + * using vertical blanks... + */ + DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ, + (((cur_vblank = atomic_read(counter)) + - *sequence) <= (1 << 23))); + + *sequence = cur_vblank; + + return ret; +} + +int radeon_driver_vblank_wait(struct drm_device *dev, unsigned int *sequence) +{ + return radeon_driver_vblank_do_wait(dev, sequence, DRM_RADEON_VBLANK_CRTC1); +} + +int radeon_driver_vblank_wait2(struct drm_device *dev, unsigned int *sequence) +{ + return radeon_driver_vblank_do_wait(dev, sequence, DRM_RADEON_VBLANK_CRTC2); } /* Needs the lock as it touches the ring. @@ -238,6 +234,21 @@ int radeon_irq_wait(struct drm_device *dev, void *data, struct drm_file *file_pr return radeon_wait_irq(dev, irqwait->irq_seq); } +static void radeon_enable_interrupt(struct drm_device *dev) +{ + drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private; + + dev_priv->irq_enable_reg = RADEON_SW_INT_ENABLE; + if (dev_priv->vblank_crtc & DRM_RADEON_VBLANK_CRTC1) + dev_priv->irq_enable_reg |= RADEON_CRTC_VBLANK_MASK; + + if (dev_priv->vblank_crtc & DRM_RADEON_VBLANK_CRTC2) + dev_priv->irq_enable_reg |= RADEON_CRTC2_VBLANK_MASK; + + RADEON_WRITE(RADEON_GEN_INT_CNTL, dev_priv->irq_enable_reg); + dev_priv->irq_enabled = 1; +} + /* drm_dma.h hooks */ void radeon_driver_irq_preinstall(struct drm_device * dev) @@ -249,27 +260,20 @@ void radeon_driver_irq_preinstall(struct drm_device * dev) RADEON_WRITE(RADEON_GEN_INT_CNTL, 0); /* Clear bits if they're already high */ - radeon_acknowledge_irqs(dev_priv); + radeon_acknowledge_irqs(dev_priv, (RADEON_SW_INT_TEST_ACK | + RADEON_CRTC_VBLANK_STAT | + RADEON_CRTC2_VBLANK_STAT)); } -int radeon_driver_irq_postinstall(struct drm_device * dev) +void radeon_driver_irq_postinstall(struct drm_device * dev) { drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private; - int ret; atomic_set(&dev_priv->swi_emitted, 0); DRM_INIT_WAITQUEUE(&dev_priv->swi_queue); - ret = drm_vblank_init(dev, 2); - if (ret) - return ret; - - dev->max_vblank_count = 0x001fffff; - - radeon_irq_set_state(dev, RADEON_SW_INT_ENABLE, 1); - - return 0; + radeon_enable_interrupt(dev); } void radeon_driver_irq_uninstall(struct drm_device * dev) @@ -311,5 +315,6 @@ int radeon_vblank_crtc_set(struct drm_device *dev, int64_t value) return -EINVAL; } dev_priv->vblank_crtc = (unsigned int)value; + radeon_enable_interrupt(dev); return 0; } diff --git a/drivers/char/drm/via_drv.c b/drivers/char/drm/via_drv.c index 37870a4a3dc7..80c01cdfa37d 100644 --- a/drivers/char/drm/via_drv.c +++ b/drivers/char/drm/via_drv.c @@ -40,13 +40,11 @@ static struct pci_device_id pciidlist[] = { static struct drm_driver driver = { .driver_features = DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_HAVE_IRQ | - DRIVER_IRQ_SHARED, + DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL, .load = via_driver_load, .unload = via_driver_unload, .context_dtor = via_final_context, - .get_vblank_counter = via_get_vblank_counter, - .enable_vblank = via_enable_vblank, - .disable_vblank = via_disable_vblank, + .vblank_wait = via_driver_vblank_wait, .irq_preinstall = via_driver_irq_preinstall, .irq_postinstall = via_driver_irq_postinstall, .irq_uninstall = via_driver_irq_uninstall, diff --git a/drivers/char/drm/via_drv.h b/drivers/char/drm/via_drv.h index fe67030e39ac..2daae81874cd 100644 --- a/drivers/char/drm/via_drv.h +++ b/drivers/char/drm/via_drv.h @@ -75,7 +75,6 @@ typedef struct drm_via_private { struct timeval last_vblank; int last_vblank_valid; unsigned usec_per_vblank; - atomic_t vbl_received; drm_via_state_t hc_state; char pci_buf[VIA_PCI_BUF_SIZE]; const uint32_t *fire_offsets[VIA_FIRE_BUF_SIZE]; @@ -131,13 +130,11 @@ extern int via_init_context(struct drm_device * dev, int context); extern int via_final_context(struct drm_device * dev, int context); extern int via_do_cleanup_map(struct drm_device * dev); -extern u32 via_get_vblank_counter(struct drm_device *dev, int crtc); -extern int via_enable_vblank(struct drm_device *dev, int crtc); -extern void via_disable_vblank(struct drm_device *dev, int crtc); +extern int via_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence); extern irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS); extern void via_driver_irq_preinstall(struct drm_device * dev); -extern int via_driver_irq_postinstall(struct drm_device * dev); +extern void via_driver_irq_postinstall(struct drm_device * dev); extern void via_driver_irq_uninstall(struct drm_device * dev); extern int via_dma_cleanup(struct drm_device * dev); diff --git a/drivers/char/drm/via_irq.c b/drivers/char/drm/via_irq.c index f1ab6fc7c07e..c6bb978a1106 100644 --- a/drivers/char/drm/via_irq.c +++ b/drivers/char/drm/via_irq.c @@ -92,17 +92,8 @@ static int via_irqmap_unichrome[] = {-1, -1, -1, 0, -1, 1}; static unsigned time_diff(struct timeval *now, struct timeval *then) { return (now->tv_usec >= then->tv_usec) ? - now->tv_usec - then->tv_usec : - 1000000 - (then->tv_usec - now->tv_usec); -} - -u32 via_get_vblank_counter(struct drm_device *dev, int crtc) -{ - drm_via_private_t *dev_priv = dev->dev_private; - if (crtc != 0) - return 0; - - return atomic_read(&dev_priv->vbl_received); + now->tv_usec - then->tv_usec : + 1000000 - (then->tv_usec - now->tv_usec); } irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS) @@ -117,8 +108,8 @@ irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS) status = VIA_READ(VIA_REG_INTERRUPT); if (status & VIA_IRQ_VBLANK_PENDING) { - atomic_inc(&dev_priv->vbl_received); - if (!(atomic_read(&dev_priv->vbl_received) & 0x0F)) { + atomic_inc(&dev->vbl_received); + if (!(atomic_read(&dev->vbl_received) & 0x0F)) { do_gettimeofday(&cur_vblank); if (dev_priv->last_vblank_valid) { dev_priv->usec_per_vblank = @@ -128,11 +119,12 @@ irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS) dev_priv->last_vblank = cur_vblank; dev_priv->last_vblank_valid = 1; } - if (!(atomic_read(&dev_priv->vbl_received) & 0xFF)) { + if (!(atomic_read(&dev->vbl_received) & 0xFF)) { DRM_DEBUG("US per vblank is: %u\n", dev_priv->usec_per_vblank); } - drm_handle_vblank(dev, 0); + DRM_WAKEUP(&dev->vbl_queue); + drm_vbl_send_signals(dev); handled = 1; } @@ -171,34 +163,31 @@ static __inline__ void viadrv_acknowledge_irqs(drm_via_private_t * dev_priv) } } -int via_enable_vblank(struct drm_device *dev, int crtc) +int via_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence) { - drm_via_private_t *dev_priv = dev->dev_private; - u32 status; + drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; + unsigned int cur_vblank; + int ret = 0; - if (crtc != 0) { - DRM_ERROR("%s: bad crtc %d\n", __FUNCTION__, crtc); + DRM_DEBUG("\n"); + if (!dev_priv) { + DRM_ERROR("called with no initialization\n"); return -EINVAL; } - status = VIA_READ(VIA_REG_INTERRUPT); - VIA_WRITE(VIA_REG_INTERRUPT, status & VIA_IRQ_VBLANK_ENABLE); + viadrv_acknowledge_irqs(dev_priv); - VIA_WRITE8(0x83d4, 0x11); - VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) | 0x30); + /* Assume that the user has missed the current sequence number + * by about a day rather than she wants to wait for years + * using vertical blanks... + */ - return 0; -} + DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ, + (((cur_vblank = atomic_read(&dev->vbl_received)) - + *sequence) <= (1 << 23))); -void via_disable_vblank(struct drm_device *dev, int crtc) -{ - drm_via_private_t *dev_priv = dev->dev_private; - - VIA_WRITE8(0x83d4, 0x11); - VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) & ~0x30); - - if (crtc != 0) - DRM_ERROR("%s: bad crtc %d\n", __FUNCTION__, crtc); + *sequence = cur_vblank; + return ret; } static int @@ -303,25 +292,23 @@ void via_driver_irq_preinstall(struct drm_device * dev) } } -int via_driver_irq_postinstall(struct drm_device * dev) +void via_driver_irq_postinstall(struct drm_device * dev) { drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; u32 status; - DRM_DEBUG("via_driver_irq_postinstall\n"); - if (!dev_priv) - return -EINVAL; + DRM_DEBUG("\n"); + if (dev_priv) { + status = VIA_READ(VIA_REG_INTERRUPT); + VIA_WRITE(VIA_REG_INTERRUPT, status | VIA_IRQ_GLOBAL + | dev_priv->irq_enable_mask); - drm_vblank_init(dev, 1); - status = VIA_READ(VIA_REG_INTERRUPT); - VIA_WRITE(VIA_REG_INTERRUPT, status | VIA_IRQ_GLOBAL - | dev_priv->irq_enable_mask); + /* Some magic, oh for some data sheets ! */ - /* Some magic, oh for some data sheets ! */ - VIA_WRITE8(0x83d4, 0x11); - VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) | 0x30); + VIA_WRITE8(0x83d4, 0x11); + VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) | 0x30); - return 0; + } } void via_driver_irq_uninstall(struct drm_device * dev) diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index 8d6c2089d2a8..efd0b4db7c8e 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig @@ -112,3 +112,12 @@ config HW_RANDOM_PASEMI If unsure, say Y. +config HW_RANDOM_VIRTIO + tristate "VirtIO Random Number Generator support" + depends on HW_RANDOM && VIRTIO + ---help--- + This driver provides kernel-side support for the virtual Random Number + Generator hardware. + + To compile this driver as a module, choose M here: the + module will be called virtio-rng. If unsure, say N. diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile index c8b7300e2fb1..b4940ddbb35f 100644 --- a/drivers/char/hw_random/Makefile +++ b/drivers/char/hw_random/Makefile @@ -11,3 +11,4 @@ obj-$(CONFIG_HW_RANDOM_VIA) += via-rng.o obj-$(CONFIG_HW_RANDOM_IXP4XX) += ixp4xx-rng.o obj-$(CONFIG_HW_RANDOM_OMAP) += omap-rng.o obj-$(CONFIG_HW_RANDOM_PASEMI) += pasemi-rng.o +obj-$(CONFIG_HW_RANDOM_VIRTIO) += virtio-rng.o diff --git a/drivers/char/hw_random/virtio-rng.c b/drivers/char/hw_random/virtio-rng.c new file mode 100644 index 000000000000..d0e563e4fc39 --- /dev/null +++ b/drivers/char/hw_random/virtio-rng.c @@ -0,0 +1,155 @@ +/* + * Randomness driver for virtio + * Copyright (C) 2007, 2008 Rusty Russell IBM Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include <linux/err.h> +#include <linux/hw_random.h> +#include <linux/scatterlist.h> +#include <linux/spinlock.h> +#include <linux/virtio.h> +#include <linux/virtio_rng.h> + +/* The host will fill any buffer we give it with sweet, sweet randomness. We + * give it 64 bytes at a time, and the hwrng framework takes it 4 bytes at a + * time. */ +#define RANDOM_DATA_SIZE 64 + +static struct virtqueue *vq; +static u32 *random_data; +static unsigned int data_left; +static DECLARE_COMPLETION(have_data); + +static void random_recv_done(struct virtqueue *vq) +{ + int len; + + /* We never get spurious callbacks. */ + if (!vq->vq_ops->get_buf(vq, &len)) + BUG(); + + data_left = len / sizeof(random_data[0]); + complete(&have_data); +} + +static void register_buffer(void) +{ + struct scatterlist sg; + + sg_init_one(&sg, random_data, RANDOM_DATA_SIZE); + /* There should always be room for one buffer. */ + if (vq->vq_ops->add_buf(vq, &sg, 0, 1, random_data) != 0) + BUG(); + vq->vq_ops->kick(vq); +} + +/* At least we don't udelay() in a loop like some other drivers. */ +static int virtio_data_present(struct hwrng *rng, int wait) +{ + if (data_left) + return 1; + + if (!wait) + return 0; + + wait_for_completion(&have_data); + return 1; +} + +/* virtio_data_present() must have succeeded before this is called. */ +static int virtio_data_read(struct hwrng *rng, u32 *data) +{ + BUG_ON(!data_left); + + *data = random_data[--data_left]; + + if (!data_left) { + init_completion(&have_data); + register_buffer(); + } + return sizeof(*data); +} + +static struct hwrng virtio_hwrng = { + .name = "virtio", + .data_present = virtio_data_present, + .data_read = virtio_data_read, +}; + +static int virtrng_probe(struct virtio_device *vdev) +{ + int err; + + /* We expect a single virtqueue. */ + vq = vdev->config->find_vq(vdev, 0, random_recv_done); + if (IS_ERR(vq)) + return PTR_ERR(vq); + + err = hwrng_register(&virtio_hwrng); + if (err) { + vdev->config->del_vq(vq); + return err; + } + + register_buffer(); + return 0; +} + +static void virtrng_remove(struct virtio_device *vdev) +{ + vdev->config->reset(vdev); + hwrng_unregister(&virtio_hwrng); + vdev->config->del_vq(vq); +} + +static struct virtio_device_id id_table[] = { + { VIRTIO_ID_RNG, VIRTIO_DEV_ANY_ID }, + { 0 }, +}; + +static struct virtio_driver virtio_rng = { + .driver.name = KBUILD_MODNAME, + .driver.owner = THIS_MODULE, + .id_table = id_table, + .probe = virtrng_probe, + .remove = __devexit_p(virtrng_remove), +}; + +static int __init init(void) +{ + int err; + + random_data = kmalloc(RANDOM_DATA_SIZE, GFP_KERNEL); + if (!random_data) + return -ENOMEM; + + err = register_virtio_driver(&virtio_rng); + if (err) + kfree(random_data); + return err; +} + +static void __exit fini(void) +{ + kfree(random_data); + unregister_virtio_driver(&virtio_rng); +} +module_init(init); +module_exit(fini); + +MODULE_DEVICE_TABLE(virtio, id_table); +MODULE_DESCRIPTION("Virtio random number driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/char/ip2/Makefile b/drivers/char/ip2/Makefile index 6bfe2543ddc2..939618f62fe1 100644 --- a/drivers/char/ip2/Makefile +++ b/drivers/char/ip2/Makefile @@ -2,7 +2,7 @@ # Makefile for the Computone IntelliPort Plus Driver # -obj-$(CONFIG_COMPUTONE) += ip2.o ip2main.o +obj-$(CONFIG_COMPUTONE) += ip2.o -ip2-objs := ip2base.o +ip2-objs := ip2base.o ip2main.o diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c index 70957acaa960..c12cf8fc4be0 100644 --- a/drivers/char/ip2/ip2main.c +++ b/drivers/char/ip2/ip2main.c @@ -346,27 +346,6 @@ have_requested_irq( char irq ) } /******************************************************************************/ -/* Function: init_module() */ -/* Parameters: None */ -/* Returns: Success (0) */ -/* */ -/* Description: */ -/* This is a required entry point for an installable module. It simply calls */ -/* the driver initialisation function and returns what it returns. */ -/******************************************************************************/ -#ifdef MODULE -static int __init -ip2_init_module(void) -{ -#ifdef IP2DEBUG_INIT - printk (KERN_DEBUG "Loading module ...\n" ); -#endif - return 0; -} -module_init(ip2_init_module); -#endif /* MODULE */ - -/******************************************************************************/ /* Function: cleanup_module() */ /* Parameters: None */ /* Returns: Nothing */ @@ -779,8 +758,6 @@ out: return err; } -EXPORT_SYMBOL(ip2_loadmain); - /******************************************************************************/ /* Function: ip2_init_board() */ /* Parameters: Index of board in configuration structure */ diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c index 19105ec203f7..8096389b0dc2 100644 --- a/drivers/char/n_tty.c +++ b/drivers/char/n_tty.c @@ -282,16 +282,20 @@ static int opost(unsigned char c, struct tty_struct *tty) if (O_ONLRET(tty)) tty->column = 0; if (O_ONLCR(tty)) { - if (space < 2) + if (space < 2) { + unlock_kernel(); return -1; + } tty_put_char(tty, '\r'); tty->column = 0; } tty->canon_column = tty->column; break; case '\r': - if (O_ONOCR(tty) && tty->column == 0) + if (O_ONOCR(tty) && tty->column == 0) { + unlock_kernel(); return 0; + } if (O_OCRNL(tty)) { c = '\n'; if (O_ONLRET(tty)) @@ -303,10 +307,13 @@ static int opost(unsigned char c, struct tty_struct *tty) case '\t': spaces = 8 - (tty->column & 7); if (O_TABDLY(tty) == XTABS) { - if (space < spaces) + if (space < spaces) { + unlock_kernel(); return -1; + } tty->column += spaces; tty->ops->write(tty, " ", spaces); + unlock_kernel(); return 0; } tty->column += spaces; diff --git a/drivers/char/snsc_event.c b/drivers/char/snsc_event.c index 53b3d44f8c06..55a95892ccf9 100644 --- a/drivers/char/snsc_event.c +++ b/drivers/char/snsc_event.c @@ -17,7 +17,7 @@ #include <linux/interrupt.h> #include <linux/sched.h> -#include <linux/byteorder/generic.h> +#include <asm/byteorder.h> #include <asm/sn/sn_sal.h> #include <asm/unaligned.h> #include "snsc.h" diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c index 9e9bad8bdcf4..dbce1263bdff 100644 --- a/drivers/char/sysrq.c +++ b/drivers/char/sysrq.c @@ -402,6 +402,7 @@ static struct sysrq_key_op *sysrq_key_table[36] = { &sysrq_showstate_blocked_op, /* w */ /* x: May be registered on ppc/powerpc for xmon */ NULL, /* x */ + /* y: May be registered on sparc64 for global register dump */ NULL, /* y */ NULL /* z */ }; diff --git a/drivers/char/viocons.c b/drivers/char/viocons.c index 3d3e1c2b310f..65fb848e1cce 100644 --- a/drivers/char/viocons.c +++ b/drivers/char/viocons.c @@ -7,7 +7,7 @@ * Authors: Dave Boutcher <boutcher@us.ibm.com> * Ryan Arnold <ryanarn@us.ibm.com> * Colin Devilbiss <devilbis@us.ibm.com> - * Stephen Rothwell <sfr@au1.ibm.com> + * Stephen Rothwell * * (C) Copyright 2000, 2001, 2002, 2003, 2004 IBM Corporation * diff --git a/drivers/char/viotape.c b/drivers/char/viotape.c index 58aad63831f4..c39ddaff5e8f 100644 --- a/drivers/char/viotape.c +++ b/drivers/char/viotape.c @@ -6,7 +6,7 @@ * Authors: Dave Boutcher <boutcher@us.ibm.com> * Ryan Arnold <ryanarn@us.ibm.com> * Colin Devilbiss <devilbis@us.ibm.com> - * Stephen Rothwell <sfr@au1.ibm.com> + * Stephen Rothwell * * (C) Copyright 2000-2004 IBM Corporation * diff --git a/drivers/char/vme_scc.c b/drivers/char/vme_scc.c index e122a0e87bb0..f17ac043b551 100644 --- a/drivers/char/vme_scc.c +++ b/drivers/char/vme_scc.c @@ -89,9 +89,7 @@ static void scc_break_ctl(struct tty_struct *tty, int break_state); static struct tty_driver *scc_driver; -struct scc_port scc_ports[2]; - -int scc_initialized = 0; +static struct scc_port scc_ports[2]; /*--------------------------------------------------------------------------- * Interface from generic_serial.c back here diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 7fce038fa57e..86f0a2430624 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -928,13 +928,13 @@ static int cpufreq_add_dev(struct sys_device *sys_dev) policy->user_policy.policy = policy->policy; policy->user_policy.governor = policy->governor; - unlock_policy_rwsem_write(cpu); - if (ret) { dprintk("setting policy failed\n"); goto err_out_unregister; } + unlock_policy_rwsem_write(cpu); + kobject_uevent(&policy->kobj, KOBJ_ADD); module_put(cpufreq_driver->owner); dprintk("initialization complete\n"); diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c index ae6cd60d5c14..b64c6bc445e3 100644 --- a/drivers/cpufreq/freq_table.c +++ b/drivers/cpufreq/freq_table.c @@ -2,6 +2,11 @@ * linux/drivers/cpufreq/freq_table.c * * Copyright (C) 2002 - 2003 Dominik Brodowski + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * */ #include <linux/kernel.h> diff --git a/drivers/dma/iop-adma.c b/drivers/dma/iop-adma.c index 762b729672e0..0ec0f431e6a1 100644 --- a/drivers/dma/iop-adma.c +++ b/drivers/dma/iop-adma.c @@ -821,10 +821,10 @@ static int __devinit iop_adma_memcpy_self_test(struct iop_adma_device *device) dev_dbg(device->common.dev, "%s\n", __func__); - src = kzalloc(sizeof(u8) * IOP_ADMA_TEST_SIZE, GFP_KERNEL); + src = kmalloc(IOP_ADMA_TEST_SIZE, GFP_KERNEL); if (!src) return -ENOMEM; - dest = kzalloc(sizeof(u8) * IOP_ADMA_TEST_SIZE, GFP_KERNEL); + dest = kzalloc(IOP_ADMA_TEST_SIZE, GFP_KERNEL); if (!dest) { kfree(src); return -ENOMEM; @@ -834,8 +834,6 @@ static int __devinit iop_adma_memcpy_self_test(struct iop_adma_device *device) for (i = 0; i < IOP_ADMA_TEST_SIZE; i++) ((u8 *) src)[i] = (u8)i; - memset(dest, 0, IOP_ADMA_TEST_SIZE); - /* Start copy, using first DMA channel */ dma_chan = container_of(device->common.channels.next, struct dma_chan, diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c index 065732ddf40c..d49361bfe670 100644 --- a/drivers/edac/mpc85xx_edac.c +++ b/drivers/edac/mpc85xx_edac.c @@ -20,7 +20,6 @@ #include <linux/of_platform.h> #include <linux/of_device.h> -#include <asm/mpc85xx.h> #include "edac_module.h" #include "edac_core.h" #include "mpc85xx_edac.h" @@ -43,8 +42,6 @@ static u32 orig_pci_err_en; static u32 orig_l2_err_disable; static u32 orig_hid1; -static const char *mpc85xx_ctl_name = "MPC85xx"; - /************************ MC SYSFS parts ***********************************/ static ssize_t mpc85xx_mc_inject_data_hi_show(struct mem_ctl_info *mci, diff --git a/drivers/firewire/fw-cdev.c b/drivers/firewire/fw-cdev.c index 4a541921a14a..dda14015e873 100644 --- a/drivers/firewire/fw-cdev.c +++ b/drivers/firewire/fw-cdev.c @@ -113,6 +113,11 @@ static int fw_device_op_open(struct inode *inode, struct file *file) if (device == NULL) return -ENODEV; + if (fw_device_is_shutdown(device)) { + fw_device_put(device); + return -ENODEV; + } + client = kzalloc(sizeof(*client), GFP_KERNEL); if (client == NULL) { fw_device_put(device); @@ -901,6 +906,9 @@ fw_device_op_ioctl(struct file *file, { struct client *client = file->private_data; + if (fw_device_is_shutdown(client->device)) + return -ENODEV; + return dispatch_ioctl(client, cmd, (void __user *) arg); } @@ -911,6 +919,9 @@ fw_device_op_compat_ioctl(struct file *file, { struct client *client = file->private_data; + if (fw_device_is_shutdown(client->device)) + return -ENODEV; + return dispatch_ioctl(client, cmd, compat_ptr(arg)); } #endif @@ -922,6 +933,9 @@ static int fw_device_op_mmap(struct file *file, struct vm_area_struct *vma) unsigned long size; int page_count, retval; + if (fw_device_is_shutdown(client->device)) + return -ENODEV; + /* FIXME: We could support multiple buffers, but we don't. */ if (client->buffer.pages != NULL) return -EBUSY; diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 7f138c6195ff..beaf6b3a37dc 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -127,7 +127,7 @@ int __init gpiochip_reserve(int start, int ngpio) unsigned long flags; int i; - if (!gpio_is_valid(start) || !gpio_is_valid(start + ngpio)) + if (!gpio_is_valid(start) || !gpio_is_valid(start + ngpio - 1)) return -EINVAL; spin_lock_irqsave(&gpio_lock, flags); @@ -170,7 +170,7 @@ int gpiochip_add(struct gpio_chip *chip) unsigned id; int base = chip->base; - if ((!gpio_is_valid(base) || !gpio_is_valid(base + chip->ngpio)) + if ((!gpio_is_valid(base) || !gpio_is_valid(base + chip->ngpio - 1)) && base >= 0) { status = -EINVAL; goto fail; @@ -207,7 +207,7 @@ fail: /* failures here can mean systems won't boot... */ if (status) pr_err("gpiochip_add: gpios %d..%d (%s) not registered\n", - chip->base, chip->base + chip->ngpio, + chip->base, chip->base + chip->ngpio - 1, chip->label ? : "generic"); return status; } diff --git a/drivers/gpio/mcp23s08.c b/drivers/gpio/mcp23s08.c index 7fb5b9d009d4..7f92fdd5f0e2 100644 --- a/drivers/gpio/mcp23s08.c +++ b/drivers/gpio/mcp23s08.c @@ -168,7 +168,7 @@ static void mcp23s08_dbg_show(struct seq_file *s, struct gpio_chip *chip) { struct mcp23s08 *mcp; char bank; - unsigned t; + int t; unsigned mask; mcp = container_of(chip, struct mcp23s08, chip); diff --git a/drivers/gpio/pca953x.c b/drivers/gpio/pca953x.c index 93f916720b13..7e40e8a55edf 100644 --- a/drivers/gpio/pca953x.c +++ b/drivers/gpio/pca953x.c @@ -30,6 +30,7 @@ static const struct i2c_device_id pca953x_id[] = { { "pca9537", 4, }, { "pca9538", 8, }, { "pca9539", 16, }, + { "pca9554", 8, }, { "pca9555", 16, }, { "pca9557", 8, }, /* REVISIT several pca955x parts should work here too */ diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c index f88714b06000..47ac1a7d66e1 100644 --- a/drivers/hid/hid-debug.c +++ b/drivers/hid/hid-debug.c @@ -1,6 +1,4 @@ /* - * $Id: hid-debug.h,v 1.8 2001/09/25 09:37:57 vojtech Exp $ - * * (c) 1999 Andreas Gal <gal@cs.uni-magdeburg.de> * (c) 2000-2001 Vojtech Pavlik <vojtech@ucw.cz> * (c) 2007 Jiri Kosina diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index c3eb3f13e2ca..5c52a20ad344 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -1,6 +1,4 @@ /* - * $Id: hid-input.c,v 1.2 2002/04/23 00:59:25 rdamazio Exp $ - * * Copyright (c) 2000-2001 Vojtech Pavlik * Copyright (c) 2006-2007 Jiri Kosina * @@ -218,8 +216,9 @@ int hidinput_apple_event(struct hid_device *hid, struct input_dev *input, } } - if (test_bit(usage->code, hid->pb_pressed_numlock) || - test_bit(LED_NUML, input->led)) { + if (hid->quirks & HID_QUIRK_APPLE_NUMLOCK_EMULATION && ( + test_bit(usage->code, hid->pb_pressed_numlock) || + test_bit(LED_NUML, input->led))) { trans = find_translation(powerbook_numlock_keys, usage->code); if (trans) { diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index d3f8d9194f30..1df832a8fcbc 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -325,6 +325,10 @@ #define USB_DEVICE_ID_MGE_UPS 0xffff #define USB_DEVICE_ID_MGE_UPS1 0x0001 +#define USB_VENDOR_ID_MICROCHIP 0x04d8 +#define USB_DEVICE_ID_PICKIT1 0x0032 +#define USB_DEVICE_ID_PICKIT2 0x0033 + #define USB_VENDOR_ID_MICROSOFT 0x045e #define USB_DEVICE_ID_SIDEWINDER_GV 0x003b #define USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0 0x009d @@ -371,6 +375,9 @@ #define USB_VENDOR_ID_SONY 0x054c #define USB_DEVICE_ID_SONY_PS3_CONTROLLER 0x0268 +#define USB_VENDOR_ID_SOUNDGRAPH 0x15c2 +#define USB_DEVICE_ID_SOUNDGRAPH_IMON_LCD 0x0038 + #define USB_VENDOR_ID_SUN 0x0430 #define USB_DEVICE_ID_RARITAN_KVM_DONGLE 0xcdab @@ -567,6 +574,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_PANJIT, 0x0002, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_PANJIT, 0x0003, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_PANJIT, 0x0004, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_SOUNDGRAPH, USB_DEVICE_ID_SOUNDGRAPH_IMON_LCD, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LABPRO, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_GOTEMP, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP, HID_QUIRK_IGNORE }, @@ -580,6 +588,9 @@ static const struct hid_blacklist { { USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_FLAIR, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_302, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICKIT1, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICKIT2, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_ELITE_KBD, HID_QUIRK_LOGITECH_IGNORE_DOUBLED_WHEEL | HID_QUIRK_LOGITECH_EXPANDED_KEYMAP }, { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500, HID_QUIRK_LOGITECH_IGNORE_DOUBLED_WHEEL | HID_QUIRK_LOGITECH_EXPANDED_KEYMAP }, @@ -611,28 +622,28 @@ static const struct hid_blacklist { { USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_APPLE_ISO_KEYBOARD}, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_JIS, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_APPLE_ISO_KEYBOARD}, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_APPLE_ISO_KEYBOARD}, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_APPLE_ISO_KEYBOARD}, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_JIS, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_APPLE_ISO_KEYBOARD}, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_APPLE_ISO_KEYBOARD}, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_ANSI, HID_QUIRK_APPLE_HAS_FN }, { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_ISO, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_APPLE_ISO_KEYBOARD }, { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_JIS, HID_QUIRK_APPLE_HAS_FN }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ANSI, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ISO, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_JIS, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI, HID_QUIRK_APPLE_HAS_FN }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_APPLE_ISO_KEYBOARD }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS, HID_QUIRK_APPLE_HAS_FN }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ANSI, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ISO, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_JIS, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_APPLE_ISO_KEYBOARD }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, { USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_W7658, HID_QUIRK_RESET_LEDS }, { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_KBD, HID_QUIRK_RESET_LEDS }, diff --git a/drivers/hid/usbhid/usbkbd.c b/drivers/hid/usbhid/usbkbd.c index 5d9dbb47e4a8..3cd46d2e53c1 100644 --- a/drivers/hid/usbhid/usbkbd.c +++ b/drivers/hid/usbhid/usbkbd.c @@ -1,6 +1,4 @@ /* - * $Id: usbkbd.c,v 1.27 2001/12/27 10:37:41 vojtech Exp $ - * * Copyright (c) 1999-2001 Vojtech Pavlik * * USB HIDBP Keyboard support diff --git a/drivers/hid/usbhid/usbmouse.c b/drivers/hid/usbhid/usbmouse.c index df0d96d989de..703e9d0e8714 100644 --- a/drivers/hid/usbhid/usbmouse.c +++ b/drivers/hid/usbhid/usbmouse.c @@ -1,6 +1,4 @@ /* - * $Id: usbmouse.c,v 1.15 2001/12/27 10:37:41 vojtech Exp $ - * * Copyright (c) 1999-2001 Vojtech Pavlik * * USB HIDBP Mouse support diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 4dc76bc45c9d..00ff53348491 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -330,6 +330,20 @@ config SENSORS_CORETEMP sensor inside your CPU. Supported all are all known variants of Intel Core family. +config SENSORS_IBMAEM + tristate "IBM Active Energy Manager temperature/power sensors and control" + select IPMI_SI + depends on IPMI_HANDLER + help + If you say yes here you get support for the temperature and + power sensors and capping hardware in various IBM System X + servers that support Active Energy Manager. This includes + the x3350, x3550, x3650, x3655, x3755, x3850 M2, x3950 M2, + and certain HS2x/LS2x/QS2x blades. + + This driver can also be built as a module. If so, the module + will be called ibmaem. + config SENSORS_IBMPEX tristate "IBM PowerExecutive temperature/power sensors" select IPMI_SI diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 3bdb05a5cbd7..d098677e08de 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -41,6 +41,7 @@ obj-$(CONFIG_SENSORS_GL518SM) += gl518sm.o obj-$(CONFIG_SENSORS_GL520SM) += gl520sm.o obj-$(CONFIG_SENSORS_HDAPS) += hdaps.o obj-$(CONFIG_SENSORS_I5K_AMB) += i5k_amb.o +obj-$(CONFIG_SENSORS_IBMAEM) += ibmaem.o obj-$(CONFIG_SENSORS_IBMPEX) += ibmpex.o obj-$(CONFIG_SENSORS_IT87) += it87.o obj-$(CONFIG_SENSORS_K8TEMP) += k8temp.o diff --git a/drivers/hwmon/hdaps.c b/drivers/hwmon/hdaps.c index bab5fd2e4dfd..88e89653daaf 100644 --- a/drivers/hwmon/hdaps.c +++ b/drivers/hwmon/hdaps.c @@ -515,6 +515,7 @@ static struct dmi_system_id __initdata hdaps_whitelist[] = { HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad R50"), HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad R51"), HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad R52"), + HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad R61i"), HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad T41p"), HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad T41"), HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad T42p"), diff --git a/drivers/hwmon/i5k_amb.c b/drivers/hwmon/i5k_amb.c index 6ac5c6f53585..f9e2ed621f7b 100644 --- a/drivers/hwmon/i5k_amb.c +++ b/drivers/hwmon/i5k_amb.c @@ -111,6 +111,7 @@ struct i5k_amb_data { void __iomem *amb_mmio; struct i5k_device_attribute *attrs; unsigned int num_attrs; + unsigned long chipset_id; }; static ssize_t show_name(struct device *dev, struct device_attribute *devattr, @@ -382,7 +383,8 @@ err: return res; } -static int __devinit i5k_find_amb_registers(struct i5k_amb_data *data) +static int __devinit i5k_find_amb_registers(struct i5k_amb_data *data, + unsigned long devid) { struct pci_dev *pcidev; u32 val32; @@ -390,7 +392,7 @@ static int __devinit i5k_find_amb_registers(struct i5k_amb_data *data) /* Find AMB register memory space */ pcidev = pci_get_device(PCI_VENDOR_ID_INTEL, - PCI_DEVICE_ID_INTEL_5000_ERR, + devid, NULL); if (!pcidev) return -ENODEV; @@ -409,6 +411,8 @@ static int __devinit i5k_find_amb_registers(struct i5k_amb_data *data) goto out; } + data->chipset_id = devid; + res = 0; out: pci_dev_put(pcidev); @@ -441,10 +445,30 @@ out: return res; } +static unsigned long i5k_channel_pci_id(struct i5k_amb_data *data, + unsigned long channel) +{ + switch (data->chipset_id) { + case PCI_DEVICE_ID_INTEL_5000_ERR: + return PCI_DEVICE_ID_INTEL_5000_FBD0 + channel; + case PCI_DEVICE_ID_INTEL_5400_ERR: + return PCI_DEVICE_ID_INTEL_5400_FBD0 + channel; + default: + BUG(); + } +} + +static unsigned long chipset_ids[] = { + PCI_DEVICE_ID_INTEL_5000_ERR, + PCI_DEVICE_ID_INTEL_5400_ERR, + 0 +}; + static int __devinit i5k_amb_probe(struct platform_device *pdev) { struct i5k_amb_data *data; struct resource *reso; + int i; int res = -ENODEV; data = kzalloc(sizeof(*data), GFP_KERNEL); @@ -452,19 +476,24 @@ static int __devinit i5k_amb_probe(struct platform_device *pdev) return -ENOMEM; /* Figure out where the AMB registers live */ - res = i5k_find_amb_registers(data); + i = 0; + do { + res = i5k_find_amb_registers(data, chipset_ids[i]); + i++; + } while (res && chipset_ids[i]); + if (res) goto err; /* Copy the DIMM presence map for the first two channels */ res = i5k_channel_probe(&data->amb_present[0], - PCI_DEVICE_ID_INTEL_5000_FBD0); + i5k_channel_pci_id(data, 0)); if (res) goto err; /* Copy the DIMM presence map for the optional second two channels */ i5k_channel_probe(&data->amb_present[2], - PCI_DEVICE_ID_INTEL_5000_FBD1); + i5k_channel_pci_id(data, 1)); /* Set up resource regions */ reso = request_mem_region(data->amb_base, data->amb_len, DRVNAME); diff --git a/drivers/hwmon/ibmaem.c b/drivers/hwmon/ibmaem.c new file mode 100644 index 000000000000..5c006c9a4311 --- /dev/null +++ b/drivers/hwmon/ibmaem.c @@ -0,0 +1,1111 @@ +/* + * A hwmon driver for the IBM Active Energy Manager temperature/power sensors + * and capping functionality. + * Copyright (C) 2008 IBM + * + * Author: Darrick J. Wong <djwong@us.ibm.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/ipmi.h> +#include <linux/module.h> +#include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> +#include <linux/jiffies.h> +#include <linux/mutex.h> +#include <linux/kdev_t.h> +#include <linux/spinlock.h> +#include <linux/idr.h> +#include <linux/sched.h> +#include <linux/platform_device.h> +#include <linux/math64.h> +#include <linux/time.h> + +#define REFRESH_INTERVAL (HZ) +#define IPMI_TIMEOUT (30 * HZ) +#define DRVNAME "aem" + +#define AEM_NETFN 0x2E + +#define AEM_FIND_FW_CMD 0x80 +#define AEM_ELEMENT_CMD 0x81 +#define AEM_FW_INSTANCE_CMD 0x82 + +#define AEM_READ_ELEMENT_CFG 0x80 +#define AEM_READ_BUFFER 0x81 +#define AEM_READ_REGISTER 0x82 +#define AEM_WRITE_REGISTER 0x83 +#define AEM_SET_REG_MASK 0x84 +#define AEM_CLEAR_REG_MASK 0x85 +#define AEM_READ_ELEMENT_CFG2 0x86 + +#define AEM_CONTROL_ELEMENT 0 +#define AEM_ENERGY_ELEMENT 1 +#define AEM_CLOCK_ELEMENT 4 +#define AEM_POWER_CAP_ELEMENT 7 +#define AEM_EXHAUST_ELEMENT 9 +#define AEM_POWER_ELEMENT 10 + +#define AEM_MODULE_TYPE_ID 0x0001 + +#define AEM2_NUM_ENERGY_REGS 2 +#define AEM2_NUM_PCAP_REGS 6 +#define AEM2_NUM_TEMP_REGS 2 +#define AEM2_NUM_SENSORS 14 + +#define AEM1_NUM_ENERGY_REGS 1 +#define AEM1_NUM_SENSORS 3 + +/* AEM 2.x has more energy registers */ +#define AEM_NUM_ENERGY_REGS AEM2_NUM_ENERGY_REGS +/* AEM 2.x needs more sensor files */ +#define AEM_NUM_SENSORS AEM2_NUM_SENSORS + +#define POWER_CAP 0 +#define POWER_CAP_MAX_HOTPLUG 1 +#define POWER_CAP_MAX 2 +#define POWER_CAP_MIN_WARNING 3 +#define POWER_CAP_MIN 4 +#define POWER_AUX 5 + +#define AEM_DEFAULT_POWER_INTERVAL 1000 +#define AEM_MIN_POWER_INTERVAL 200 +#define UJ_PER_MJ 1000L + +static DEFINE_IDR(aem_idr); +static DEFINE_SPINLOCK(aem_idr_lock); + +static struct device_driver aem_driver = { + .name = DRVNAME, + .bus = &platform_bus_type, +}; + +struct aem_ipmi_data { + struct completion read_complete; + struct ipmi_addr address; + ipmi_user_t user; + int interface; + + struct kernel_ipmi_msg tx_message; + long tx_msgid; + + void *rx_msg_data; + unsigned short rx_msg_len; + unsigned char rx_result; + int rx_recv_type; + + struct device *bmc_device; +}; + +struct aem_ro_sensor_template { + char *label; + ssize_t (*show)(struct device *dev, + struct device_attribute *devattr, + char *buf); + int index; +}; + +struct aem_rw_sensor_template { + char *label; + ssize_t (*show)(struct device *dev, + struct device_attribute *devattr, + char *buf); + ssize_t (*set)(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count); + int index; +}; + +struct aem_data { + struct list_head list; + + struct device *hwmon_dev; + struct platform_device *pdev; + struct mutex lock; + char valid; + unsigned long last_updated; /* In jiffies */ + u8 ver_major; + u8 ver_minor; + u8 module_handle; + int id; + struct aem_ipmi_data ipmi; + + /* Function to update sensors */ + void (*update)(struct aem_data *data); + + /* + * AEM 1.x sensors: + * Available sensors: + * Energy meter + * Power meter + * + * AEM 2.x sensors: + * Two energy meters + * Two power meters + * Two temperature sensors + * Six power cap registers + */ + + /* sysfs attrs */ + struct sensor_device_attribute sensors[AEM_NUM_SENSORS]; + + /* energy use in mJ */ + u64 energy[AEM_NUM_ENERGY_REGS]; + + /* power sampling interval in ms */ + unsigned long power_period[AEM_NUM_ENERGY_REGS]; + + /* Everything past here is for AEM2 only */ + + /* power caps in dW */ + u16 pcap[AEM2_NUM_PCAP_REGS]; + + /* exhaust temperature in C */ + u8 temp[AEM2_NUM_TEMP_REGS]; +}; + +/* Data structures returned by the AEM firmware */ +struct aem_iana_id { + u8 bytes[3]; +}; +static struct aem_iana_id system_x_id = { + .bytes = {0x4D, 0x4F, 0x00} +}; + +/* These are used to find AEM1 instances */ +struct aem_find_firmware_req { + struct aem_iana_id id; + u8 rsvd; + u16 index; + u16 module_type_id; +} __packed; + +struct aem_find_firmware_resp { + struct aem_iana_id id; + u8 num_instances; +} __packed; + +/* These are used to find AEM2 instances */ +struct aem_find_instance_req { + struct aem_iana_id id; + u8 instance_number; + u16 module_type_id; +} __packed; + +struct aem_find_instance_resp { + struct aem_iana_id id; + u8 num_instances; + u8 major; + u8 minor; + u8 module_handle; + u16 record_id; +} __packed; + +/* These are used to query sensors */ +struct aem_read_sensor_req { + struct aem_iana_id id; + u8 module_handle; + u8 element; + u8 subcommand; + u8 reg; + u8 rx_buf_size; +} __packed; + +struct aem_read_sensor_resp { + struct aem_iana_id id; + u8 bytes[0]; +} __packed; + +/* Data structures to talk to the IPMI layer */ +struct aem_driver_data { + struct list_head aem_devices; + struct ipmi_smi_watcher bmc_events; + struct ipmi_user_hndl ipmi_hndlrs; +}; + +static void aem_register_bmc(int iface, struct device *dev); +static void aem_bmc_gone(int iface); +static void aem_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data); + +static void aem_remove_sensors(struct aem_data *data); +static int aem_init_aem1(struct aem_ipmi_data *probe); +static int aem_init_aem2(struct aem_ipmi_data *probe); +static int aem1_find_sensors(struct aem_data *data); +static int aem2_find_sensors(struct aem_data *data); +static void update_aem1_sensors(struct aem_data *data); +static void update_aem2_sensors(struct aem_data *data); + +static struct aem_driver_data driver_data = { + .aem_devices = LIST_HEAD_INIT(driver_data.aem_devices), + .bmc_events = { + .owner = THIS_MODULE, + .new_smi = aem_register_bmc, + .smi_gone = aem_bmc_gone, + }, + .ipmi_hndlrs = { + .ipmi_recv_hndl = aem_msg_handler, + }, +}; + +/* Functions to talk to the IPMI layer */ + +/* Initialize IPMI address, message buffers and user data */ +static int aem_init_ipmi_data(struct aem_ipmi_data *data, int iface, + struct device *bmc) +{ + int err; + + init_completion(&data->read_complete); + data->bmc_device = bmc; + + /* Initialize IPMI address */ + data->address.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + data->address.channel = IPMI_BMC_CHANNEL; + data->address.data[0] = 0; + data->interface = iface; + + /* Initialize message buffers */ + data->tx_msgid = 0; + data->tx_message.netfn = AEM_NETFN; + + /* Create IPMI messaging interface user */ + err = ipmi_create_user(data->interface, &driver_data.ipmi_hndlrs, + data, &data->user); + if (err < 0) { + dev_err(bmc, "Unable to register user with IPMI " + "interface %d\n", data->interface); + return -EACCES; + } + + return 0; +} + +/* Send an IPMI command */ +static int aem_send_message(struct aem_ipmi_data *data) +{ + int err; + + err = ipmi_validate_addr(&data->address, sizeof(data->address)); + if (err) + goto out; + + data->tx_msgid++; + err = ipmi_request_settime(data->user, &data->address, data->tx_msgid, + &data->tx_message, data, 0, 0, 0); + if (err) + goto out1; + + return 0; +out1: + dev_err(data->bmc_device, "request_settime=%x\n", err); + return err; +out: + dev_err(data->bmc_device, "validate_addr=%x\n", err); + return err; +} + +/* Dispatch IPMI messages to callers */ +static void aem_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data) +{ + unsigned short rx_len; + struct aem_ipmi_data *data = user_msg_data; + + if (msg->msgid != data->tx_msgid) { + dev_err(data->bmc_device, "Mismatch between received msgid " + "(%02x) and transmitted msgid (%02x)!\n", + (int)msg->msgid, + (int)data->tx_msgid); + ipmi_free_recv_msg(msg); + return; + } + + data->rx_recv_type = msg->recv_type; + if (msg->msg.data_len > 0) + data->rx_result = msg->msg.data[0]; + else + data->rx_result = IPMI_UNKNOWN_ERR_COMPLETION_CODE; + + if (msg->msg.data_len > 1) { + rx_len = msg->msg.data_len - 1; + if (data->rx_msg_len < rx_len) + rx_len = data->rx_msg_len; + data->rx_msg_len = rx_len; + memcpy(data->rx_msg_data, msg->msg.data + 1, data->rx_msg_len); + } else + data->rx_msg_len = 0; + + ipmi_free_recv_msg(msg); + complete(&data->read_complete); +} + +/* ID functions */ + +/* Obtain an id */ +static int aem_idr_get(int *id) +{ + int i, err; + +again: + if (unlikely(!idr_pre_get(&aem_idr, GFP_KERNEL))) + return -ENOMEM; + + spin_lock(&aem_idr_lock); + err = idr_get_new(&aem_idr, NULL, &i); + spin_unlock(&aem_idr_lock); + + if (unlikely(err == -EAGAIN)) + goto again; + else if (unlikely(err)) + return err; + + *id = i & MAX_ID_MASK; + return 0; +} + +/* Release an object ID */ +static void aem_idr_put(int id) +{ + spin_lock(&aem_idr_lock); + idr_remove(&aem_idr, id); + spin_unlock(&aem_idr_lock); +} + +/* Sensor support functions */ + +/* Read a sensor value */ +static int aem_read_sensor(struct aem_data *data, u8 elt, u8 reg, + void *buf, size_t size) +{ + int rs_size, res; + struct aem_read_sensor_req rs_req; + struct aem_read_sensor_resp *rs_resp; + struct aem_ipmi_data *ipmi = &data->ipmi; + + /* AEM registers are 1, 2, 4 or 8 bytes */ + switch (size) { + case 1: + case 2: + case 4: + case 8: + break; + default: + return -EINVAL; + } + + rs_req.id = system_x_id; + rs_req.module_handle = data->module_handle; + rs_req.element = elt; + rs_req.subcommand = AEM_READ_REGISTER; + rs_req.reg = reg; + rs_req.rx_buf_size = size; + + ipmi->tx_message.cmd = AEM_ELEMENT_CMD; + ipmi->tx_message.data = (char *)&rs_req; + ipmi->tx_message.data_len = sizeof(rs_req); + + rs_size = sizeof(*rs_resp) + size; + rs_resp = kzalloc(rs_size, GFP_KERNEL); + if (!rs_resp) + return -ENOMEM; + + ipmi->rx_msg_data = rs_resp; + ipmi->rx_msg_len = rs_size; + + aem_send_message(ipmi); + + res = wait_for_completion_timeout(&ipmi->read_complete, IPMI_TIMEOUT); + if (!res) + return -ETIMEDOUT; + + if (ipmi->rx_result || ipmi->rx_msg_len != rs_size || + memcmp(&rs_resp->id, &system_x_id, sizeof(system_x_id))) { + kfree(rs_resp); + return -ENOENT; + } + + switch (size) { + case 1: { + u8 *x = buf; + *x = rs_resp->bytes[0]; + break; + } + case 2: { + u16 *x = buf; + *x = be16_to_cpup((u16 *)rs_resp->bytes); + break; + } + case 4: { + u32 *x = buf; + *x = be32_to_cpup((u32 *)rs_resp->bytes); + break; + } + case 8: { + u64 *x = buf; + *x = be64_to_cpup((u64 *)rs_resp->bytes); + break; + } + } + + return 0; +} + +/* Update AEM energy registers */ +static void update_aem_energy(struct aem_data *data) +{ + aem_read_sensor(data, AEM_ENERGY_ELEMENT, 0, &data->energy[0], 8); + if (data->ver_major < 2) + return; + aem_read_sensor(data, AEM_ENERGY_ELEMENT, 1, &data->energy[1], 8); +} + +/* Update all AEM1 sensors */ +static void update_aem1_sensors(struct aem_data *data) +{ + mutex_lock(&data->lock); + if (time_before(jiffies, data->last_updated + REFRESH_INTERVAL) && + data->valid) + goto out; + + update_aem_energy(data); +out: + mutex_unlock(&data->lock); +} + +/* Update all AEM2 sensors */ +static void update_aem2_sensors(struct aem_data *data) +{ + int i; + + mutex_lock(&data->lock); + if (time_before(jiffies, data->last_updated + REFRESH_INTERVAL) && + data->valid) + goto out; + + update_aem_energy(data); + aem_read_sensor(data, AEM_EXHAUST_ELEMENT, 0, &data->temp[0], 1); + aem_read_sensor(data, AEM_EXHAUST_ELEMENT, 1, &data->temp[1], 1); + + for (i = POWER_CAP; i <= POWER_AUX; i++) + aem_read_sensor(data, AEM_POWER_CAP_ELEMENT, i, + &data->pcap[i], 2); +out: + mutex_unlock(&data->lock); +} + +/* Delete an AEM instance */ +static void aem_delete(struct aem_data *data) +{ + list_del(&data->list); + aem_remove_sensors(data); + hwmon_device_unregister(data->hwmon_dev); + ipmi_destroy_user(data->ipmi.user); + dev_set_drvdata(&data->pdev->dev, NULL); + platform_device_unregister(data->pdev); + aem_idr_put(data->id); + kfree(data); +} + +/* Probe functions for AEM1 devices */ + +/* Retrieve version and module handle for an AEM1 instance */ +static int aem_find_aem1_count(struct aem_ipmi_data *data) +{ + int res; + struct aem_find_firmware_req ff_req; + struct aem_find_firmware_resp ff_resp; + + ff_req.id = system_x_id; + ff_req.index = 0; + ff_req.module_type_id = cpu_to_be16(AEM_MODULE_TYPE_ID); + + data->tx_message.cmd = AEM_FIND_FW_CMD; + data->tx_message.data = (char *)&ff_req; + data->tx_message.data_len = sizeof(ff_req); + + data->rx_msg_data = &ff_resp; + data->rx_msg_len = sizeof(ff_resp); + + aem_send_message(data); + + res = wait_for_completion_timeout(&data->read_complete, IPMI_TIMEOUT); + if (!res) + return -ETIMEDOUT; + + if (data->rx_result || data->rx_msg_len != sizeof(ff_resp) || + memcmp(&ff_resp.id, &system_x_id, sizeof(system_x_id))) + return -ENOENT; + + return ff_resp.num_instances; +} + +/* Find and initialize one AEM1 instance */ +static int aem_init_aem1_inst(struct aem_ipmi_data *probe, u8 module_handle) +{ + struct aem_data *data; + int i; + int res = -ENOMEM; + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return res; + mutex_init(&data->lock); + + /* Copy instance data */ + data->ver_major = 1; + data->ver_minor = 0; + data->module_handle = module_handle; + for (i = 0; i < AEM1_NUM_ENERGY_REGS; i++) + data->power_period[i] = AEM_DEFAULT_POWER_INTERVAL; + + /* Create sub-device for this fw instance */ + if (aem_idr_get(&data->id)) + goto id_err; + + data->pdev = platform_device_alloc(DRVNAME, data->id); + if (!data->pdev) + goto dev_err; + data->pdev->dev.driver = &aem_driver; + + res = platform_device_add(data->pdev); + if (res) + goto ipmi_err; + + dev_set_drvdata(&data->pdev->dev, data); + + /* Set up IPMI interface */ + if (aem_init_ipmi_data(&data->ipmi, probe->interface, + probe->bmc_device)) + goto ipmi_err; + + /* Register with hwmon */ + data->hwmon_dev = hwmon_device_register(&data->pdev->dev); + + if (IS_ERR(data->hwmon_dev)) { + dev_err(&data->pdev->dev, "Unable to register hwmon " + "device for IPMI interface %d\n", + probe->interface); + goto hwmon_reg_err; + } + + data->update = update_aem1_sensors; + + /* Find sensors */ + if (aem1_find_sensors(data)) + goto sensor_err; + + /* Add to our list of AEM devices */ + list_add_tail(&data->list, &driver_data.aem_devices); + + dev_info(data->ipmi.bmc_device, "Found AEM v%d.%d at 0x%X\n", + data->ver_major, data->ver_minor, + data->module_handle); + return 0; + +sensor_err: + hwmon_device_unregister(data->hwmon_dev); +hwmon_reg_err: + ipmi_destroy_user(data->ipmi.user); +ipmi_err: + dev_set_drvdata(&data->pdev->dev, NULL); + platform_device_unregister(data->pdev); +dev_err: + aem_idr_put(data->id); +id_err: + kfree(data); + + return res; +} + +/* Find and initialize all AEM1 instances */ +static int aem_init_aem1(struct aem_ipmi_data *probe) +{ + int num, i, err; + + num = aem_find_aem1_count(probe); + for (i = 0; i < num; i++) { + err = aem_init_aem1_inst(probe, i); + if (err) { + dev_err(probe->bmc_device, + "Error %d initializing AEM1 0x%X\n", + err, i); + return err; + } + } + + return 0; +} + +/* Probe functions for AEM2 devices */ + +/* Retrieve version and module handle for an AEM2 instance */ +static int aem_find_aem2(struct aem_ipmi_data *data, + struct aem_find_instance_resp *fi_resp, + int instance_num) +{ + int res; + struct aem_find_instance_req fi_req; + + fi_req.id = system_x_id; + fi_req.instance_number = instance_num; + fi_req.module_type_id = cpu_to_be16(AEM_MODULE_TYPE_ID); + + data->tx_message.cmd = AEM_FW_INSTANCE_CMD; + data->tx_message.data = (char *)&fi_req; + data->tx_message.data_len = sizeof(fi_req); + + data->rx_msg_data = fi_resp; + data->rx_msg_len = sizeof(*fi_resp); + + aem_send_message(data); + + res = wait_for_completion_timeout(&data->read_complete, IPMI_TIMEOUT); + if (!res) + return -ETIMEDOUT; + + if (data->rx_result || data->rx_msg_len != sizeof(*fi_resp) || + memcmp(&fi_resp->id, &system_x_id, sizeof(system_x_id))) + return -ENOENT; + + return 0; +} + +/* Find and initialize one AEM2 instance */ +static int aem_init_aem2_inst(struct aem_ipmi_data *probe, + struct aem_find_instance_resp *fi_resp) +{ + struct aem_data *data; + int i; + int res = -ENOMEM; + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return res; + mutex_init(&data->lock); + + /* Copy instance data */ + data->ver_major = fi_resp->major; + data->ver_minor = fi_resp->minor; + data->module_handle = fi_resp->module_handle; + for (i = 0; i < AEM2_NUM_ENERGY_REGS; i++) + data->power_period[i] = AEM_DEFAULT_POWER_INTERVAL; + + /* Create sub-device for this fw instance */ + if (aem_idr_get(&data->id)) + goto id_err; + + data->pdev = platform_device_alloc(DRVNAME, data->id); + if (!data->pdev) + goto dev_err; + data->pdev->dev.driver = &aem_driver; + + res = platform_device_add(data->pdev); + if (res) + goto ipmi_err; + + dev_set_drvdata(&data->pdev->dev, data); + + /* Set up IPMI interface */ + if (aem_init_ipmi_data(&data->ipmi, probe->interface, + probe->bmc_device)) + goto ipmi_err; + + /* Register with hwmon */ + data->hwmon_dev = hwmon_device_register(&data->pdev->dev); + + if (IS_ERR(data->hwmon_dev)) { + dev_err(&data->pdev->dev, "Unable to register hwmon " + "device for IPMI interface %d\n", + probe->interface); + goto hwmon_reg_err; + } + + data->update = update_aem2_sensors; + + /* Find sensors */ + if (aem2_find_sensors(data)) + goto sensor_err; + + /* Add to our list of AEM devices */ + list_add_tail(&data->list, &driver_data.aem_devices); + + dev_info(data->ipmi.bmc_device, "Found AEM v%d.%d at 0x%X\n", + data->ver_major, data->ver_minor, + data->module_handle); + return 0; + +sensor_err: + hwmon_device_unregister(data->hwmon_dev); +hwmon_reg_err: + ipmi_destroy_user(data->ipmi.user); +ipmi_err: + dev_set_drvdata(&data->pdev->dev, NULL); + platform_device_unregister(data->pdev); +dev_err: + aem_idr_put(data->id); +id_err: + kfree(data); + + return res; +} + +/* Find and initialize all AEM2 instances */ +static int aem_init_aem2(struct aem_ipmi_data *probe) +{ + struct aem_find_instance_resp fi_resp; + int err; + int i = 0; + + while (!aem_find_aem2(probe, &fi_resp, i)) { + if (fi_resp.major != 2) { + dev_err(probe->bmc_device, "Unknown AEM v%d; please " + "report this to the maintainer.\n", + fi_resp.major); + i++; + continue; + } + err = aem_init_aem2_inst(probe, &fi_resp); + if (err) { + dev_err(probe->bmc_device, + "Error %d initializing AEM2 0x%X\n", + err, fi_resp.module_handle); + return err; + } + i++; + } + + return 0; +} + +/* Probe a BMC for AEM firmware instances */ +static void aem_register_bmc(int iface, struct device *dev) +{ + struct aem_ipmi_data probe; + + if (aem_init_ipmi_data(&probe, iface, dev)) + return; + + /* Ignore probe errors; they won't cause problems */ + aem_init_aem1(&probe); + aem_init_aem2(&probe); + + ipmi_destroy_user(probe.user); +} + +/* Handle BMC deletion */ +static void aem_bmc_gone(int iface) +{ + struct aem_data *p1, *next1; + + list_for_each_entry_safe(p1, next1, &driver_data.aem_devices, list) + if (p1->ipmi.interface == iface) + aem_delete(p1); +} + +/* sysfs support functions */ + +/* AEM device name */ +static ssize_t show_name(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct aem_data *data = dev_get_drvdata(dev); + + return sprintf(buf, "%s%d\n", DRVNAME, data->ver_major); +} +static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0); + +/* AEM device version */ +static ssize_t show_version(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct aem_data *data = dev_get_drvdata(dev); + + return sprintf(buf, "%d.%d\n", data->ver_major, data->ver_minor); +} +static SENSOR_DEVICE_ATTR(version, S_IRUGO, show_version, NULL, 0); + +/* Display power use */ +static ssize_t aem_show_power(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct aem_data *data = dev_get_drvdata(dev); + u64 before, after, delta, time; + signed long leftover; + struct timespec b, a; + + mutex_lock(&data->lock); + update_aem_energy(data); + getnstimeofday(&b); + before = data->energy[attr->index]; + + leftover = schedule_timeout_interruptible( + msecs_to_jiffies(data->power_period[attr->index]) + ); + if (leftover) { + mutex_unlock(&data->lock); + return 0; + } + + update_aem_energy(data); + getnstimeofday(&a); + after = data->energy[attr->index]; + mutex_unlock(&data->lock); + + time = timespec_to_ns(&a) - timespec_to_ns(&b); + delta = (after - before) * UJ_PER_MJ; + + return sprintf(buf, "%llu\n", + (unsigned long long)div64_u64(delta * NSEC_PER_SEC, time)); +} + +/* Display energy use */ +static ssize_t aem_show_energy(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct aem_data *a = dev_get_drvdata(dev); + a->update(a); + + return sprintf(buf, "%llu\n", + (unsigned long long)a->energy[attr->index] * 1000); +} + +/* Display power interval registers */ +static ssize_t aem_show_power_period(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct aem_data *a = dev_get_drvdata(dev); + a->update(a); + + return sprintf(buf, "%lu\n", a->power_period[attr->index]); +} + +/* Set power interval registers */ +static ssize_t aem_set_power_period(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct aem_data *a = dev_get_drvdata(dev); + unsigned long temp; + int res; + + res = strict_strtoul(buf, 10, &temp); + if (res) + return res; + + if (temp < AEM_MIN_POWER_INTERVAL) + return -EINVAL; + + mutex_lock(&a->lock); + a->power_period[attr->index] = temp; + mutex_unlock(&a->lock); + + return count; +} + +/* Discover sensors on an AEM device */ +static int aem_register_sensors(struct aem_data *data, + struct aem_ro_sensor_template *ro, + struct aem_rw_sensor_template *rw) +{ + struct device *dev = &data->pdev->dev; + struct sensor_device_attribute *sensors = data->sensors; + int err; + + /* Set up read-only sensors */ + while (ro->label) { + sensors->dev_attr.attr.name = ro->label; + sensors->dev_attr.attr.mode = S_IRUGO; + sensors->dev_attr.show = ro->show; + sensors->index = ro->index; + + err = device_create_file(dev, &sensors->dev_attr); + if (err) { + sensors->dev_attr.attr.name = NULL; + goto error; + } + sensors++; + ro++; + } + + /* Set up read-write sensors */ + while (rw->label) { + sensors->dev_attr.attr.name = rw->label; + sensors->dev_attr.attr.mode = S_IRUGO | S_IWUSR; + sensors->dev_attr.show = rw->show; + sensors->dev_attr.store = rw->set; + sensors->index = rw->index; + + err = device_create_file(dev, &sensors->dev_attr); + if (err) { + sensors->dev_attr.attr.name = NULL; + goto error; + } + sensors++; + rw++; + } + + err = device_create_file(dev, &sensor_dev_attr_name.dev_attr); + if (err) + goto error; + err = device_create_file(dev, &sensor_dev_attr_version.dev_attr); + return err; + +error: + aem_remove_sensors(data); + return err; +} + +/* sysfs support functions for AEM2 sensors */ + +/* Display temperature use */ +static ssize_t aem2_show_temp(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct aem_data *a = dev_get_drvdata(dev); + a->update(a); + + return sprintf(buf, "%u\n", a->temp[attr->index] * 1000); +} + +/* Display power-capping registers */ +static ssize_t aem2_show_pcap_value(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct aem_data *a = dev_get_drvdata(dev); + a->update(a); + + return sprintf(buf, "%u\n", a->pcap[attr->index] * 100000); +} + +/* Remove sensors attached to an AEM device */ +static void aem_remove_sensors(struct aem_data *data) +{ + int i; + + for (i = 0; i < AEM_NUM_SENSORS; i++) { + if (!data->sensors[i].dev_attr.attr.name) + continue; + device_remove_file(&data->pdev->dev, + &data->sensors[i].dev_attr); + } + + device_remove_file(&data->pdev->dev, + &sensor_dev_attr_name.dev_attr); + device_remove_file(&data->pdev->dev, + &sensor_dev_attr_version.dev_attr); +} + +/* Sensor probe functions */ + +/* Description of AEM1 sensors */ +static struct aem_ro_sensor_template aem1_ro_sensors[] = { +{"energy1_input", aem_show_energy, 0}, +{"power1_average", aem_show_power, 0}, +{NULL, NULL, 0}, +}; + +static struct aem_rw_sensor_template aem1_rw_sensors[] = { +{"power1_average_interval", aem_show_power_period, aem_set_power_period, 0}, +{NULL, NULL, NULL, 0}, +}; + +/* Description of AEM2 sensors */ +static struct aem_ro_sensor_template aem2_ro_sensors[] = { +{"energy1_input", aem_show_energy, 0}, +{"energy2_input", aem_show_energy, 1}, +{"power1_average", aem_show_power, 0}, +{"power2_average", aem_show_power, 1}, +{"temp1_input", aem2_show_temp, 0}, +{"temp2_input", aem2_show_temp, 1}, + +{"power4_average", aem2_show_pcap_value, POWER_CAP_MAX_HOTPLUG}, +{"power5_average", aem2_show_pcap_value, POWER_CAP_MAX}, +{"power6_average", aem2_show_pcap_value, POWER_CAP_MIN_WARNING}, +{"power7_average", aem2_show_pcap_value, POWER_CAP_MIN}, + +{"power3_average", aem2_show_pcap_value, POWER_AUX}, +{"power_cap", aem2_show_pcap_value, POWER_CAP}, +{NULL, NULL, 0}, +}; + +static struct aem_rw_sensor_template aem2_rw_sensors[] = { +{"power1_average_interval", aem_show_power_period, aem_set_power_period, 0}, +{"power2_average_interval", aem_show_power_period, aem_set_power_period, 1}, +{NULL, NULL, NULL, 0}, +}; + +/* Set up AEM1 sensor attrs */ +static int aem1_find_sensors(struct aem_data *data) +{ + return aem_register_sensors(data, aem1_ro_sensors, aem1_rw_sensors); +} + +/* Set up AEM2 sensor attrs */ +static int aem2_find_sensors(struct aem_data *data) +{ + return aem_register_sensors(data, aem2_ro_sensors, aem2_rw_sensors); +} + +/* Module init/exit routines */ + +static int __init aem_init(void) +{ + int res; + + res = driver_register(&aem_driver); + if (res) { + printk(KERN_ERR "Can't register aem driver\n"); + return res; + } + + res = ipmi_smi_watcher_register(&driver_data.bmc_events); + if (res) + goto ipmi_reg_err; + return 0; + +ipmi_reg_err: + driver_unregister(&aem_driver); + return res; + +} + +static void __exit aem_exit(void) +{ + struct aem_data *p1, *next1; + + ipmi_smi_watcher_unregister(&driver_data.bmc_events); + driver_unregister(&aem_driver); + list_for_each_entry_safe(p1, next1, &driver_data.aem_devices, list) + aem_delete(p1); +} + +MODULE_AUTHOR("Darrick J. Wong <djwong@us.ibm.com>"); +MODULE_DESCRIPTION("IBM Active Energy Manager power/temp sensor driver"); +MODULE_LICENSE("GPL"); + +module_init(aem_init); +module_exit(aem_exit); diff --git a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c index 2fa43183d375..43508d61eb7c 100644 --- a/drivers/i2c/busses/i2c-amd756.c +++ b/drivers/i2c/busses/i2c-amd756.c @@ -290,7 +290,7 @@ static u32 amd756_func(struct i2c_adapter *adapter) { return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | - I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_PROC_CALL; + I2C_FUNC_SMBUS_BLOCK_DATA; } static const struct i2c_algorithm smbus_algorithm = { diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c index 3dac920e53ea..43c9f8df9509 100644 --- a/drivers/i2c/busses/i2c-nforce2.c +++ b/drivers/i2c/busses/i2c-nforce2.c @@ -50,6 +50,7 @@ #include <linux/init.h> #include <linux/i2c.h> #include <linux/delay.h> +#include <linux/dmi.h> #include <asm/io.h> MODULE_LICENSE("GPL"); @@ -109,6 +110,18 @@ struct nforce2_smbus { /* Misc definitions */ #define MAX_TIMEOUT 100 +/* We disable the second SMBus channel on these boards */ +static struct dmi_system_id __devinitdata nforce2_dmi_blacklist2[] = { + { + .ident = "DFI Lanparty NF4 Expert", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "DFI Corp,LTD"), + DMI_MATCH(DMI_BOARD_NAME, "LP UT NF4 Expert"), + }, + }, + { } +}; + static struct pci_driver nforce2_driver; static void nforce2_abort(struct i2c_adapter *adap) @@ -367,10 +380,17 @@ static int __devinit nforce2_probe(struct pci_dev *dev, const struct pci_device_ smbuses[0].base = 0; /* to have a check value */ } /* SMBus adapter 2 */ - res2 = nforce2_probe_smb(dev, 5, NFORCE_PCI_SMB2, &smbuses[1], "SMB2"); - if (res2 < 0) { - dev_err(&dev->dev, "Error probing SMB2.\n"); - smbuses[1].base = 0; /* to have a check value */ + if (dmi_check_system(nforce2_dmi_blacklist2)) { + dev_err(&dev->dev, "Disabling SMB2 for safety reasons.\n"); + res2 = -EPERM; + smbuses[1].base = 0; + } else { + res2 = nforce2_probe_smb(dev, 5, NFORCE_PCI_SMB2, &smbuses[1], + "SMB2"); + if (res2 < 0) { + dev_err(&dev->dev, "Error probing SMB2.\n"); + smbuses[1].base = 0; /* to have a check value */ + } } if ((res1 < 0) && (res2 < 0)) { /* we did not find even one of the SMBuses, so we give up */ diff --git a/drivers/i2c/chips/max6875.c b/drivers/i2c/chips/max6875.c index fb7ea5637eca..cf507b3f60f3 100644 --- a/drivers/i2c/chips/max6875.c +++ b/drivers/i2c/chips/max6875.c @@ -207,9 +207,6 @@ static int max6875_detect(struct i2c_adapter *adapter, int address, int kind) fake_client->flags = 0; strlcpy(fake_client->name, "max6875 subclient", I2C_NAME_SIZE); - /* Prevent 24RF08 corruption (in case of user error) */ - i2c_smbus_write_quick(real_client, 0); - if ((err = i2c_attach_client(real_client)) != 0) goto exit_kfree2; diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index c99ebeadb558..d0175f4f8fc6 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -74,10 +74,7 @@ static int i2c_device_match(struct device *dev, struct device_driver *drv) if (driver->id_table) return i2c_match_id(driver->id_table, client) != NULL; - /* new style drivers use the same kind of driver matching policy - * as platform devices or SPI: compare device and driver IDs. - */ - return strcmp(client->driver_name, drv->name) == 0; + return 0; } #ifdef CONFIG_HOTPLUG @@ -91,14 +88,9 @@ static int i2c_device_uevent(struct device *dev, struct kobj_uevent_env *env) if (dev->driver) return 0; - if (client->driver_name[0]) { - if (add_uevent_var(env, "MODALIAS=%s", client->driver_name)) - return -ENOMEM; - } else { - if (add_uevent_var(env, "MODALIAS=%s%s", - I2C_MODULE_PREFIX, client->name)) - return -ENOMEM; - } + if (add_uevent_var(env, "MODALIAS=%s%s", + I2C_MODULE_PREFIX, client->name)) + return -ENOMEM; dev_dbg(dev, "uevent\n"); return 0; } @@ -206,9 +198,7 @@ static ssize_t show_client_name(struct device *dev, struct device_attribute *att static ssize_t show_modalias(struct device *dev, struct device_attribute *attr, char *buf) { struct i2c_client *client = to_i2c_client(dev); - return client->driver_name[0] - ? sprintf(buf, "%s\n", client->driver_name) - : sprintf(buf, "%s%s\n", I2C_MODULE_PREFIX, client->name); + return sprintf(buf, "%s%s\n", I2C_MODULE_PREFIX, client->name); } static struct device_attribute i2c_dev_attrs[] = { @@ -282,8 +272,6 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) client->addr = info->addr; client->irq = info->irq; - strlcpy(client->driver_name, info->driver_name, - sizeof(client->driver_name)); strlcpy(client->name, info->type, sizeof(client->name)); /* a new style driver may be bound to this device when we diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index 34b0d4f26b58..655ec7ef568a 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -648,13 +648,12 @@ static int ide_register_port(ide_hwif_t *hwif) get_device(&hwif->gendev); - hwif->portdev = device_create(ide_port_class, &hwif->gendev, - MKDEV(0, 0), hwif->name); + hwif->portdev = device_create_drvdata(ide_port_class, &hwif->gendev, + MKDEV(0, 0), hwif, hwif->name); if (IS_ERR(hwif->portdev)) { ret = PTR_ERR(hwif->portdev); device_unregister(&hwif->gendev); } - dev_set_drvdata(hwif->portdev, hwif); out: return ret; } diff --git a/drivers/ide/legacy/macide.c b/drivers/ide/legacy/macide.c index 1f527bbf8d96..caa2632dd08e 100644 --- a/drivers/ide/legacy/macide.c +++ b/drivers/ide/legacy/macide.c @@ -95,6 +95,9 @@ static int __init macide_init(void) int irq; hw_regs_t hw; + if (!MACH_IS_MAC) + return -ENODEV; + switch (macintosh_config->ide_type) { case MAC_IDE_QUADRA: base = IDE_BASE; diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c index 16b9d0ad154e..a5ceff287a28 100644 --- a/drivers/ieee1394/sbp2.c +++ b/drivers/ieee1394/sbp2.c @@ -1539,15 +1539,13 @@ static void sbp2_prep_command_orb_sg(struct sbp2_command_orb *orb, static void sbp2_create_command_orb(struct sbp2_lu *lu, struct sbp2_command_info *cmd, - unchar *scsi_cmd, - unsigned int scsi_use_sg, - unsigned int scsi_request_bufflen, - struct scatterlist *sg, - enum dma_data_direction dma_dir) + struct scsi_cmnd *SCpnt) { struct sbp2_fwhost_info *hi = lu->hi; struct sbp2_command_orb *orb = &cmd->command_orb; u32 orb_direction; + unsigned int scsi_request_bufflen = scsi_bufflen(SCpnt); + enum dma_data_direction dma_dir = SCpnt->sc_data_direction; /* * Set-up our command ORB. @@ -1580,13 +1578,14 @@ static void sbp2_create_command_orb(struct sbp2_lu *lu, orb->data_descriptor_lo = 0x0; orb->misc |= ORB_SET_DIRECTION(1); } else - sbp2_prep_command_orb_sg(orb, hi, cmd, scsi_use_sg, sg, + sbp2_prep_command_orb_sg(orb, hi, cmd, scsi_sg_count(SCpnt), + scsi_sglist(SCpnt), orb_direction, dma_dir); sbp2util_cpu_to_be32_buffer(orb, sizeof(*orb)); - memset(orb->cdb, 0, 12); - memcpy(orb->cdb, scsi_cmd, COMMAND_SIZE(*scsi_cmd)); + memset(orb->cdb, 0, sizeof(orb->cdb)); + memcpy(orb->cdb, SCpnt->cmnd, SCpnt->cmd_len); } static void sbp2_link_orb_command(struct sbp2_lu *lu, @@ -1669,16 +1668,13 @@ static void sbp2_link_orb_command(struct sbp2_lu *lu, static int sbp2_send_command(struct sbp2_lu *lu, struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) { - unchar *scsi_cmd = (unchar *)SCpnt->cmnd; struct sbp2_command_info *cmd; cmd = sbp2util_allocate_command_orb(lu, SCpnt, done); if (!cmd) return -EIO; - sbp2_create_command_orb(lu, cmd, scsi_cmd, scsi_sg_count(SCpnt), - scsi_bufflen(SCpnt), scsi_sglist(SCpnt), - SCpnt->sc_data_direction); + sbp2_create_command_orb(lu, cmd, SCpnt); sbp2_link_orb_command(lu, cmd); return 0; diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c index fbe16d5250a4..1adf2efd3cb3 100644 --- a/drivers/infiniband/core/mad.c +++ b/drivers/infiniband/core/mad.c @@ -747,7 +747,9 @@ static int handle_outgoing_dr_smp(struct ib_mad_agent_private *mad_agent_priv, break; case IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED: kmem_cache_free(ib_mad_cache, mad_priv); - break; + kfree(local); + ret = 1; + goto out; case IB_MAD_RESULT_SUCCESS: /* Treat like an incoming receive MAD */ port_priv = ib_get_mad_port(mad_agent_priv->agent.device, diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c index 3aa2db54eae4..840ede9ae965 100644 --- a/drivers/infiniband/core/user_mad.c +++ b/drivers/infiniband/core/user_mad.c @@ -1005,8 +1005,9 @@ static int ib_umad_init_port(struct ib_device *device, int port_num, if (cdev_add(port->cdev, base_dev + port->dev_num, 1)) goto err_cdev; - port->dev = device_create(umad_class, device->dma_device, - port->cdev->dev, "umad%d", port->dev_num); + port->dev = device_create_drvdata(umad_class, device->dma_device, + port->cdev->dev, port, + "umad%d", port->dev_num); if (IS_ERR(port->dev)) goto err_cdev; @@ -1024,15 +1025,12 @@ static int ib_umad_init_port(struct ib_device *device, int port_num, if (cdev_add(port->sm_cdev, base_dev + port->dev_num + IB_UMAD_MAX_PORTS, 1)) goto err_sm_cdev; - port->sm_dev = device_create(umad_class, device->dma_device, - port->sm_cdev->dev, - "issm%d", port->dev_num); + port->sm_dev = device_create_drvdata(umad_class, device->dma_device, + port->sm_cdev->dev, port, + "issm%d", port->dev_num); if (IS_ERR(port->sm_dev)) goto err_sm_cdev; - dev_set_drvdata(port->dev, port); - dev_set_drvdata(port->sm_dev, port); - if (device_create_file(port->sm_dev, &dev_attr_ibdev)) goto err_sm_dev; if (device_create_file(port->sm_dev, &dev_attr_port)) diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index cc1afa28c181..f806da184b51 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -755,14 +755,15 @@ static void ib_uverbs_add_one(struct ib_device *device) if (cdev_add(uverbs_dev->cdev, IB_UVERBS_BASE_DEV + uverbs_dev->devnum, 1)) goto err_cdev; - uverbs_dev->dev = device_create(uverbs_class, device->dma_device, - uverbs_dev->cdev->dev, - "uverbs%d", uverbs_dev->devnum); + uverbs_dev->dev = device_create_drvdata(uverbs_class, + device->dma_device, + uverbs_dev->cdev->dev, + uverbs_dev, + "uverbs%d", + uverbs_dev->devnum); if (IS_ERR(uverbs_dev->dev)) goto err_cdev; - dev_set_drvdata(uverbs_dev->dev, uverbs_dev); - if (device_create_file(uverbs_dev->dev, &dev_attr_ibdev)) goto err_class; if (device_create_file(uverbs_dev->dev, &dev_attr_abi_version)) diff --git a/drivers/infiniband/hw/cxgb3/iwch_qp.c b/drivers/infiniband/hw/cxgb3/iwch_qp.c index 79dbe5beae52..992613799228 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_qp.c +++ b/drivers/infiniband/hw/cxgb3/iwch_qp.c @@ -229,7 +229,7 @@ int iwch_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, struct ib_send_wr **bad_wr) { int err = 0; - u8 t3_wr_flit_cnt; + u8 uninitialized_var(t3_wr_flit_cnt); enum t3_wr_opcode t3_wr_opcode = 0; enum t3_wr_flags t3_wr_flags; struct iwch_qp *qhp; diff --git a/drivers/infiniband/hw/ipath/ipath_sdma.c b/drivers/infiniband/hw/ipath/ipath_sdma.c index 3697449c1ba4..0a8c1b8091a2 100644 --- a/drivers/infiniband/hw/ipath/ipath_sdma.c +++ b/drivers/infiniband/hw/ipath/ipath_sdma.c @@ -345,7 +345,7 @@ resched: * state change */ if (jiffies > dd->ipath_sdma_abort_jiffies) { - ipath_dbg("looping with status 0x%016llx\n", + ipath_dbg("looping with status 0x%08lx\n", dd->ipath_sdma_status); dd->ipath_sdma_abort_jiffies = jiffies + 5 * HZ; } @@ -615,7 +615,7 @@ void ipath_restart_sdma(struct ipath_devdata *dd) } spin_unlock_irqrestore(&dd->ipath_sdma_lock, flags); if (!needed) { - ipath_dbg("invalid attempt to restart SDMA, status 0x%016llx\n", + ipath_dbg("invalid attempt to restart SDMA, status 0x%08lx\n", dd->ipath_sdma_status); goto bail; } diff --git a/drivers/infiniband/hw/ipath/ipath_uc.c b/drivers/infiniband/hw/ipath/ipath_uc.c index 7fd18e833907..0596ec16fcbd 100644 --- a/drivers/infiniband/hw/ipath/ipath_uc.c +++ b/drivers/infiniband/hw/ipath/ipath_uc.c @@ -407,12 +407,11 @@ void ipath_uc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr, dev->n_pkt_drops++; goto done; } - /* XXX Need to free SGEs */ + wc.opcode = IB_WC_RECV; last_imm: ipath_copy_sge(&qp->r_sge, data, tlen); wc.wr_id = qp->r_wr_id; wc.status = IB_WC_SUCCESS; - wc.opcode = IB_WC_RECV; wc.qp = &qp->ibqp; wc.src_qp = qp->remote_qpn; wc.slid = qp->remote_ah_attr.dlid; @@ -514,6 +513,7 @@ void ipath_uc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr, goto done; } wc.byte_len = qp->r_len; + wc.opcode = IB_WC_RECV_RDMA_WITH_IMM; goto last_imm; case OP(RDMA_WRITE_LAST): diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c index 8e02ecfec188..a80df22deae8 100644 --- a/drivers/infiniband/hw/mlx4/qp.c +++ b/drivers/infiniband/hw/mlx4/qp.c @@ -333,6 +333,9 @@ static int set_kernel_sq_size(struct mlx4_ib_dev *dev, struct ib_qp_cap *cap, cap->max_inline_data + sizeof (struct mlx4_wqe_inline_seg)) + send_wqe_overhead(type, qp->flags); + if (s > dev->dev->caps.max_sq_desc_sz) + return -EINVAL; + /* * Hermon supports shrinking WQEs, such that a single work * request can include multiple units of 1 << wqe_shift. This @@ -372,9 +375,6 @@ static int set_kernel_sq_size(struct mlx4_ib_dev *dev, struct ib_qp_cap *cap, qp->sq.wqe_shift = ilog2(roundup_pow_of_two(s)); for (;;) { - if (1 << qp->sq.wqe_shift > dev->dev->caps.max_sq_desc_sz) - return -EINVAL; - qp->sq_max_wqes_per_wr = DIV_ROUND_UP(s, 1U << qp->sq.wqe_shift); /* @@ -395,7 +395,8 @@ static int set_kernel_sq_size(struct mlx4_ib_dev *dev, struct ib_qp_cap *cap, ++qp->sq.wqe_shift; } - qp->sq.max_gs = ((qp->sq_max_wqes_per_wr << qp->sq.wqe_shift) - + qp->sq.max_gs = (min(dev->dev->caps.max_sq_desc_sz, + (qp->sq_max_wqes_per_wr << qp->sq.wqe_shift)) - send_wqe_overhead(type, qp->flags)) / sizeof (struct mlx4_wqe_data_seg); @@ -411,7 +412,9 @@ static int set_kernel_sq_size(struct mlx4_ib_dev *dev, struct ib_qp_cap *cap, cap->max_send_wr = qp->sq.max_post = (qp->sq.wqe_cnt - qp->sq_spare_wqes) / qp->sq_max_wqes_per_wr; - cap->max_send_sge = qp->sq.max_gs; + cap->max_send_sge = min(qp->sq.max_gs, + min(dev->dev->caps.max_sq_sg, + dev->dev->caps.max_rq_sg)); /* We don't support inline sends for kernel QPs (yet) */ cap->max_inline_data = 0; @@ -1457,7 +1460,7 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, unsigned ind; int uninitialized_var(stamp); int uninitialized_var(size); - unsigned seglen; + unsigned uninitialized_var(seglen); int i; spin_lock_irqsave(&qp->sq.lock, flags); diff --git a/drivers/infiniband/hw/mthca/mthca_main.c b/drivers/infiniband/hw/mthca/mthca_main.c index 9ebadd6e0cfb..200cf13fc9bb 100644 --- a/drivers/infiniband/hw/mthca/mthca_main.c +++ b/drivers/infiniband/hw/mthca/mthca_main.c @@ -45,6 +45,7 @@ #include "mthca_cmd.h" #include "mthca_profile.h" #include "mthca_memfree.h" +#include "mthca_wqe.h" MODULE_AUTHOR("Roland Dreier"); MODULE_DESCRIPTION("Mellanox InfiniBand HCA low-level driver"); @@ -200,7 +201,18 @@ static int mthca_dev_lim(struct mthca_dev *mdev, struct mthca_dev_lim *dev_lim) mdev->limits.gid_table_len = dev_lim->max_gids; mdev->limits.pkey_table_len = dev_lim->max_pkeys; mdev->limits.local_ca_ack_delay = dev_lim->local_ca_ack_delay; - mdev->limits.max_sg = dev_lim->max_sg; + /* + * Need to allow for worst case send WQE overhead and check + * whether max_desc_sz imposes a lower limit than max_sg; UD + * send has the biggest overhead. + */ + mdev->limits.max_sg = min_t(int, dev_lim->max_sg, + (dev_lim->max_desc_sz - + sizeof (struct mthca_next_seg) - + (mthca_is_memfree(mdev) ? + sizeof (struct mthca_arbel_ud_seg) : + sizeof (struct mthca_tavor_ud_seg))) / + sizeof (struct mthca_data_seg)); mdev->limits.max_wqes = dev_lim->max_qp_sz; mdev->limits.max_qp_init_rdma = dev_lim->max_requester_per_qp; mdev->limits.reserved_qps = dev_lim->reserved_qps; diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index d00a2c174aee..3f663fb852c1 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c @@ -194,7 +194,13 @@ static int ipoib_mcast_join_finish(struct ipoib_mcast *mcast, /* Set the cached Q_Key before we attach if it's the broadcast group */ if (!memcmp(mcast->mcmember.mgid.raw, priv->dev->broadcast + 4, sizeof (union ib_gid))) { + spin_lock_irq(&priv->lock); + if (!priv->broadcast) { + spin_unlock_irq(&priv->lock); + return -EAGAIN; + } priv->qkey = be32_to_cpu(priv->broadcast->mcmember.qkey); + spin_unlock_irq(&priv->lock); priv->tx_wr.wr.ud.remote_qkey = priv->qkey; } diff --git a/drivers/input/keyboard/aaed2000_kbd.c b/drivers/input/keyboard/aaed2000_kbd.c index a293e8b3f508..8a77bfcd05bc 100644 --- a/drivers/input/keyboard/aaed2000_kbd.c +++ b/drivers/input/keyboard/aaed2000_kbd.c @@ -183,4 +183,4 @@ module_exit(aaedkbd_exit); MODULE_AUTHOR("Nicolas Bellido Y Ortega"); MODULE_DESCRIPTION("AAED-2000 Keyboard Driver"); -MODULE_LICENSE("GPLv2"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index 4a95adc4cc78..af58a6f1e898 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c @@ -807,6 +807,8 @@ static int atkbd_activate(struct atkbd *atkbd) static void atkbd_cleanup(struct serio *serio) { struct atkbd *atkbd = serio_get_drvdata(serio); + + atkbd_disable(atkbd); ps2_command(&atkbd->ps2dev, NULL, ATKBD_CMD_RESET_BAT); } diff --git a/drivers/input/keyboard/corgikbd.c b/drivers/input/keyboard/corgikbd.c index 29fbec6218b9..1aa46ae12630 100644 --- a/drivers/input/keyboard/corgikbd.c +++ b/drivers/input/keyboard/corgikbd.c @@ -412,5 +412,5 @@ module_exit(corgikbd_exit); MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>"); MODULE_DESCRIPTION("Corgi Keyboard Driver"); -MODULE_LICENSE("GPLv2"); +MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:corgi-keyboard"); diff --git a/drivers/input/keyboard/hilkbd.c b/drivers/input/keyboard/hilkbd.c index 50d80ecf0b80..aacf71f3cd44 100644 --- a/drivers/input/keyboard/hilkbd.c +++ b/drivers/input/keyboard/hilkbd.c @@ -217,6 +217,10 @@ hil_keyb_init(void) return -ENOMEM; #if defined(CONFIG_HP300) + if (!MACH_IS_HP300) { + err = -ENODEV; + goto err1; + } if (!hwreg_present((void *)(HILBASE + HIL_DATA))) { printk(KERN_ERR "HIL: hardware register was not found\n"); err = -ENODEV; diff --git a/drivers/input/keyboard/jornada680_kbd.c b/drivers/input/keyboard/jornada680_kbd.c index 9387da343f97..781fc6102860 100644 --- a/drivers/input/keyboard/jornada680_kbd.c +++ b/drivers/input/keyboard/jornada680_kbd.c @@ -275,5 +275,5 @@ module_exit(jornada680kbd_exit); MODULE_AUTHOR("Kristoffer Ericson <kristoffer.ericson@gmail.com>"); MODULE_DESCRIPTION("HP Jornada 620/660/680/690 Keyboard Driver"); -MODULE_LICENSE("GPLv2"); +MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:jornada680_kbd"); diff --git a/drivers/input/keyboard/jornada720_kbd.c b/drivers/input/keyboard/jornada720_kbd.c index a1164a0c7736..ce650af6d649 100644 --- a/drivers/input/keyboard/jornada720_kbd.c +++ b/drivers/input/keyboard/jornada720_kbd.c @@ -29,7 +29,7 @@ MODULE_AUTHOR("Kristoffer Ericson <Kristoffer.Ericson@gmail.com>"); MODULE_DESCRIPTION("HP Jornada 710/720/728 keyboard driver"); -MODULE_LICENSE("GPLv2"); +MODULE_LICENSE("GPL v2"); static unsigned short jornada_std_keymap[128] = { /* ROW */ 0, KEY_ESC, KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7, /* #1 */ diff --git a/drivers/input/keyboard/pxa27x_keypad.c b/drivers/input/keyboard/pxa27x_keypad.c index 3dea0c5077a9..45767e73f071 100644 --- a/drivers/input/keyboard/pxa27x_keypad.c +++ b/drivers/input/keyboard/pxa27x_keypad.c @@ -136,6 +136,9 @@ static void pxa27x_keypad_build_keycode(struct pxa27x_keypad *keypad) set_bit(code, input_dev->keybit); } + for (i = 0; i < pdata->direct_key_num; i++) + set_bit(pdata->direct_key_map[i], input_dev->keybit); + keypad->rotary_up_key[0] = pdata->rotary0_up_key; keypad->rotary_up_key[1] = pdata->rotary1_up_key; keypad->rotary_down_key[0] = pdata->rotary0_down_key; @@ -143,17 +146,21 @@ static void pxa27x_keypad_build_keycode(struct pxa27x_keypad *keypad) keypad->rotary_rel_code[0] = pdata->rotary0_rel_code; keypad->rotary_rel_code[1] = pdata->rotary1_rel_code; - if (pdata->rotary0_up_key && pdata->rotary0_down_key) { - set_bit(pdata->rotary0_up_key, input_dev->keybit); - set_bit(pdata->rotary0_down_key, input_dev->keybit); - } else - set_bit(pdata->rotary0_rel_code, input_dev->relbit); - - if (pdata->rotary1_up_key && pdata->rotary1_down_key) { - set_bit(pdata->rotary1_up_key, input_dev->keybit); - set_bit(pdata->rotary1_down_key, input_dev->keybit); - } else - set_bit(pdata->rotary1_rel_code, input_dev->relbit); + if (pdata->enable_rotary0) { + if (pdata->rotary0_up_key && pdata->rotary0_down_key) { + set_bit(pdata->rotary0_up_key, input_dev->keybit); + set_bit(pdata->rotary0_down_key, input_dev->keybit); + } else + set_bit(pdata->rotary0_rel_code, input_dev->relbit); + } + + if (pdata->enable_rotary1) { + if (pdata->rotary1_up_key && pdata->rotary1_down_key) { + set_bit(pdata->rotary1_up_key, input_dev->keybit); + set_bit(pdata->rotary1_down_key, input_dev->keybit); + } else + set_bit(pdata->rotary1_rel_code, input_dev->relbit); + } } static inline unsigned int lookup_matrix_keycode( @@ -484,8 +491,13 @@ static int __devinit pxa27x_keypad_probe(struct platform_device *pdev) keypad->input_dev = input_dev; input_set_drvdata(input_dev, keypad); - input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP) | - BIT_MASK(EV_REL); + input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); + if ((keypad->pdata->enable_rotary0 && + keypad->pdata->rotary0_rel_code) || + (keypad->pdata->enable_rotary1 && + keypad->pdata->rotary1_rel_code)) { + input_dev->evbit[0] |= BIT_MASK(EV_REL); + } pxa27x_keypad_build_keycode(keypad); platform_set_drvdata(pdev, keypad); diff --git a/drivers/input/keyboard/spitzkbd.c b/drivers/input/keyboard/spitzkbd.c index 61e401bc9109..1aa37181c40f 100644 --- a/drivers/input/keyboard/spitzkbd.c +++ b/drivers/input/keyboard/spitzkbd.c @@ -494,5 +494,5 @@ module_exit(spitzkbd_exit); MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>"); MODULE_DESCRIPTION("Spitz Keyboard Driver"); -MODULE_LICENSE("GPLv2"); +MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:spitz-keyboard"); diff --git a/drivers/input/misc/apanel.c b/drivers/input/misc/apanel.c index 9531d8c7444f..d82f7f727f7a 100644 --- a/drivers/input/misc/apanel.c +++ b/drivers/input/misc/apanel.c @@ -20,7 +20,6 @@ #include <linux/module.h> #include <linux/ioport.h> #include <linux/io.h> -#include <linux/module.h> #include <linux/input-polldev.h> #include <linux/i2c.h> #include <linux/workqueue.h> diff --git a/drivers/input/misc/hp_sdc_rtc.c b/drivers/input/misc/hp_sdc_rtc.c index ab76ea442fa5..45e5d05b01de 100644 --- a/drivers/input/misc/hp_sdc_rtc.c +++ b/drivers/input/misc/hp_sdc_rtc.c @@ -691,6 +691,11 @@ static int __init hp_sdc_rtc_init(void) { int ret; +#ifdef __mc68000__ + if (!MACH_IS_HP300) + return -ENODEV; +#endif + init_MUTEX(&i8042tregs); if ((ret = hp_sdc_request_timer_irq(&hp_sdc_rtc_isr))) diff --git a/drivers/input/serio/hp_sdc_mlc.c b/drivers/input/serio/hp_sdc_mlc.c index f1fd3b638a37..587398f5c9df 100644 --- a/drivers/input/serio/hp_sdc_mlc.c +++ b/drivers/input/serio/hp_sdc_mlc.c @@ -306,6 +306,11 @@ static int __init hp_sdc_mlc_init(void) { hil_mlc *mlc = &hp_sdc_mlc; +#ifdef __mc68000__ + if (!MACH_IS_HP300) + return -ENODEV; +#endif + printk(KERN_INFO PREFIX "Registering the System Domain Controller's HIL MLC.\n"); hp_sdc_mlc_priv.emtestmode = 0; diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index 5ece9f56babc..9aafa96cb746 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -331,6 +331,13 @@ static struct dmi_system_id __initdata i8042_dmi_dritek_table[] = { }, }, { + .ident = "Acer TravelMate 660", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 660"), + }, + }, + { .ident = "Acer TravelMate 2490", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index 65a74cfc187b..592ff55b62d0 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -885,6 +885,20 @@ static long i8042_panic_blink(long count) #undef DELAY +#ifdef CONFIG_X86 +static void i8042_dritek_enable(void) +{ + char param = 0x90; + int error; + + error = i8042_command(¶m, 0x1059); + if (error) + printk(KERN_WARNING + "Failed to enable DRITEK extension: %d\n", + error); +} +#endif + #ifdef CONFIG_PM /* * Here we try to restore the original BIOS settings. We only want to @@ -942,6 +956,12 @@ static int i8042_resume(struct platform_device *dev) return -EIO; } + +#ifdef CONFIG_X86 + if (i8042_dritek) + i8042_dritek_enable(); +#endif + if (i8042_mux_present) { if (i8042_set_mux_mode(1, NULL) || i8042_enable_mux_ports()) printk(KERN_WARNING @@ -1160,6 +1180,11 @@ static int __devinit i8042_probe(struct platform_device *dev) if (error) return error; +#ifdef CONFIG_X86 + if (i8042_dritek) + i8042_dritek_enable(); +#endif + if (!i8042_noaux) { error = i8042_setup_aux(); if (error && error != -ENODEV && error != -EBUSY) @@ -1171,14 +1196,6 @@ static int __devinit i8042_probe(struct platform_device *dev) if (error) goto out_fail; } -#ifdef CONFIG_X86 - if (i8042_dritek) { - char param = 0x90; - error = i8042_command(¶m, 0x1059); - if (error) - goto out_fail; - } -#endif /* * Ok, everything is ready, let's register all serio ports */ diff --git a/drivers/input/serio/q40kbd.c b/drivers/input/serio/q40kbd.c index cb89aff2e160..d962a8d78b14 100644 --- a/drivers/input/serio/q40kbd.c +++ b/drivers/input/serio/q40kbd.c @@ -156,7 +156,7 @@ static int __init q40kbd_init(void) int error; if (!MACH_IS_Q40) - return -EIO; + return -ENODEV; error = platform_driver_register(&q40kbd_driver); if (error) diff --git a/drivers/input/tablet/gtco.c b/drivers/input/tablet/gtco.c index c5a8661a1baa..1e748e46d12e 100644 --- a/drivers/input/tablet/gtco.c +++ b/drivers/input/tablet/gtco.c @@ -830,7 +830,7 @@ static int gtco_probe(struct usb_interface *usbinterface, struct gtco *gtco; struct input_dev *input_dev; struct hid_descriptor *hid_desc; - char *report = NULL; + char *report; int result = 0, retry; int error; struct usb_endpoint_descriptor *endpoint; @@ -916,12 +916,16 @@ static int gtco_probe(struct usb_interface *usbinterface, le16_to_cpu(hid_desc->wDescriptorLength), 5000); /* 5 secs */ - if (result == le16_to_cpu(hid_desc->wDescriptorLength)) + dbg("usb_control_msg result: %d", result); + if (result == le16_to_cpu(hid_desc->wDescriptorLength)) { + parse_hid_report_descriptor(gtco, report, result); break; + } } + kfree(report); + /* If we didn't get the report, fail */ - dbg("usb_control_msg result: :%d", result); if (result != le16_to_cpu(hid_desc->wDescriptorLength)) { err("Failed to get HID Report Descriptor of size: %d", hid_desc->wDescriptorLength); @@ -929,12 +933,6 @@ static int gtco_probe(struct usb_interface *usbinterface, goto err_free_urb; } - /* Now we parse the report */ - parse_hid_report_descriptor(gtco, report, result); - - /* Now we delete it */ - kfree(report); - /* Create a device file node */ usb_make_path(gtco->usbdev, gtco->usbpath, sizeof(gtco->usbpath)); strlcat(gtco->usbpath, "/input0", sizeof(gtco->usbpath)); @@ -988,7 +986,6 @@ static int gtco_probe(struct usb_interface *usbinterface, usb_buffer_free(gtco->usbdev, REPORT_MAX_SIZE, gtco->buffer, gtco->buf_dma); err_free_devs: - kfree(report); input_free_device(input_dev); kfree(gtco); return error; diff --git a/drivers/input/touchscreen/jornada720_ts.c b/drivers/input/touchscreen/jornada720_ts.c index 742242111bf1..1aca108b1031 100644 --- a/drivers/input/touchscreen/jornada720_ts.c +++ b/drivers/input/touchscreen/jornada720_ts.c @@ -24,7 +24,7 @@ MODULE_AUTHOR("Kristoffer Ericson <kristoffer.ericson@gmail.com>"); MODULE_DESCRIPTION("HP Jornada 710/720/728 touchscreen driver"); -MODULE_LICENSE("GPLv2"); +MODULE_LICENSE("GPL v2"); struct jornada_ts { struct input_dev *dev; diff --git a/drivers/input/touchscreen/wm9713.c b/drivers/input/touchscreen/wm9713.c index 01278bd7e65c..838458792ea0 100644 --- a/drivers/input/touchscreen/wm9713.c +++ b/drivers/input/touchscreen/wm9713.c @@ -85,6 +85,15 @@ module_param(delay, int, 0); MODULE_PARM_DESC(delay, "Set adc sample delay."); /* + * Set five_wire = 1 to use a 5 wire touchscreen. + * + * NOTE: Five wire mode does not allow for readback of pressure. + */ +static int five_wire; +module_param(five_wire, int, 0); +MODULE_PARM_DESC(five_wire, "Set to '1' to use 5-wire touchscreen."); + +/* * Set adc mask function. * * Sources of glitch noise, such as signals driving an LCD display, may feed @@ -162,6 +171,19 @@ static void wm9713_phy_init(struct wm97xx *wm) 64000 / rpu); } + /* Five wire panel? */ + if (five_wire) { + dig3 |= WM9713_45W; + dev_info(wm->dev, "setting 5-wire touchscreen mode."); + + if (pil) { + dev_warn(wm->dev, + "Pressure measurement not supported in 5 " + "wire mode, disabling\n"); + pil = 0; + } + } + /* touchpanel pressure */ if (pil == 2) { dig3 |= WM9712_PIL; diff --git a/drivers/input/touchscreen/wm97xx-core.c b/drivers/input/touchscreen/wm97xx-core.c index e9c7ea46b6e3..cdc24ad314e0 100644 --- a/drivers/input/touchscreen/wm97xx-core.c +++ b/drivers/input/touchscreen/wm97xx-core.c @@ -608,6 +608,17 @@ static int wm97xx_probe(struct device *dev) goto alloc_err; } + /* set up physical characteristics */ + wm->codec->phy_init(wm); + + /* load gpio cache */ + wm->gpio[0] = wm97xx_reg_read(wm, AC97_GPIO_CFG); + wm->gpio[1] = wm97xx_reg_read(wm, AC97_GPIO_POLARITY); + wm->gpio[2] = wm97xx_reg_read(wm, AC97_GPIO_STICKY); + wm->gpio[3] = wm97xx_reg_read(wm, AC97_GPIO_WAKEUP); + wm->gpio[4] = wm97xx_reg_read(wm, AC97_GPIO_STATUS); + wm->gpio[5] = wm97xx_reg_read(wm, AC97_MISC_AFE); + wm->input_dev = input_allocate_device(); if (wm->input_dev == NULL) { ret = -ENOMEM; @@ -616,6 +627,7 @@ static int wm97xx_probe(struct device *dev) /* set up touch configuration */ wm->input_dev->name = "wm97xx touchscreen"; + wm->input_dev->phys = "wm97xx"; wm->input_dev->open = wm97xx_ts_input_open; wm->input_dev->close = wm97xx_ts_input_close; set_bit(EV_ABS, wm->input_dev->evbit); @@ -634,17 +646,6 @@ static int wm97xx_probe(struct device *dev) if (ret < 0) goto dev_alloc_err; - /* set up physical characteristics */ - wm->codec->phy_init(wm); - - /* load gpio cache */ - wm->gpio[0] = wm97xx_reg_read(wm, AC97_GPIO_CFG); - wm->gpio[1] = wm97xx_reg_read(wm, AC97_GPIO_POLARITY); - wm->gpio[2] = wm97xx_reg_read(wm, AC97_GPIO_STICKY); - wm->gpio[3] = wm97xx_reg_read(wm, AC97_GPIO_WAKEUP); - wm->gpio[4] = wm97xx_reg_read(wm, AC97_GPIO_STATUS); - wm->gpio[5] = wm97xx_reg_read(wm, AC97_MISC_AFE); - /* register our battery device */ wm->battery_dev = platform_device_alloc("wm97xx-battery", -1); if (!wm->battery_dev) { @@ -801,7 +802,7 @@ void wm97xx_unregister_mach_ops(struct wm97xx *wm) EXPORT_SYMBOL_GPL(wm97xx_unregister_mach_ops); static struct device_driver wm97xx_driver = { - .name = "ac97", + .name = "wm97xx-ts", .bus = &ac97_bus_type, .owner = THIS_MODULE, .probe = wm97xx_probe, diff --git a/drivers/isdn/hysdn/hycapi.c b/drivers/isdn/hysdn/hycapi.c index d3999a8e9f88..53f6ad1235db 100644 --- a/drivers/isdn/hysdn/hycapi.c +++ b/drivers/isdn/hysdn/hycapi.c @@ -462,11 +462,11 @@ static int hycapi_read_proc(char *page, char **start, off_t off, default: s = "???"; break; } len += sprintf(page+len, "%-16s %s\n", "type", s); - if ((s = cinfo->version[VER_DRIVER]) != 0) + if ((s = cinfo->version[VER_DRIVER]) != NULL) len += sprintf(page+len, "%-16s %s\n", "ver_driver", s); - if ((s = cinfo->version[VER_CARDTYPE]) != 0) + if ((s = cinfo->version[VER_CARDTYPE]) != NULL) len += sprintf(page+len, "%-16s %s\n", "ver_cardtype", s); - if ((s = cinfo->version[VER_SERIAL]) != 0) + if ((s = cinfo->version[VER_SERIAL]) != NULL) len += sprintf(page+len, "%-16s %s\n", "ver_serial", s); len += sprintf(page+len, "%-16s %s\n", "cardname", cinfo->cardname); diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index b3c54be74556..559a40861c39 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c @@ -103,13 +103,11 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev) { int rc; - led_cdev->dev = device_create(leds_class, parent, 0, "%s", - led_cdev->name); + led_cdev->dev = device_create_drvdata(leds_class, parent, 0, led_cdev, + "%s", led_cdev->name); if (IS_ERR(led_cdev->dev)) return PTR_ERR(led_cdev->dev); - dev_set_drvdata(led_cdev->dev, led_cdev); - /* register the attributes */ rc = device_create_file(led_cdev->dev, &dev_attr_brightness); if (rc) diff --git a/drivers/lguest/lguest_device.c b/drivers/lguest/lguest_device.c index 8080249957af..1a8de57289eb 100644 --- a/drivers/lguest/lguest_device.c +++ b/drivers/lguest/lguest_device.c @@ -20,14 +20,11 @@ /* The pointer to our (page) of device descriptions. */ static void *lguest_devices; -/* Unique numbering for lguest devices. */ -static unsigned int dev_index; - /* For Guests, device memory can be used as normal memory, so we cast away the * __iomem to quieten sparse. */ static inline void *lguest_map(unsigned long phys_addr, unsigned long pages) { - return (__force void *)ioremap(phys_addr, PAGE_SIZE*pages); + return (__force void *)ioremap_cache(phys_addr, PAGE_SIZE*pages); } static inline void lguest_unmap(void *addr) @@ -325,8 +322,10 @@ static struct device lguest_root = { * As Andrew Tridgell says, "Untested code is buggy code". * * It's worth reading this carefully: we start with a pointer to the new device - * descriptor in the "lguest_devices" page. */ -static void add_lguest_device(struct lguest_device_desc *d) + * descriptor in the "lguest_devices" page, and the offset into the device + * descriptor page so we can uniquely identify it if things go badly wrong. */ +static void add_lguest_device(struct lguest_device_desc *d, + unsigned int offset) { struct lguest_device *ldev; @@ -334,18 +333,14 @@ static void add_lguest_device(struct lguest_device_desc *d) * it. */ ldev = kzalloc(sizeof(*ldev), GFP_KERNEL); if (!ldev) { - printk(KERN_EMERG "Cannot allocate lguest dev %u\n", - dev_index++); + printk(KERN_EMERG "Cannot allocate lguest dev %u type %u\n", + offset, d->type); return; } /* This devices' parent is the lguest/ dir. */ ldev->vdev.dev.parent = &lguest_root; /* We have a unique device index thanks to the dev_index counter. */ - ldev->vdev.index = dev_index++; - /* The device type comes straight from the descriptor. There's also a - * device vendor field in the virtio_device struct, which we leave as - * 0. */ ldev->vdev.id.device = d->type; /* We have a simple set of routines for querying the device's * configuration information and setting its status. */ @@ -357,8 +352,8 @@ static void add_lguest_device(struct lguest_device_desc *d) * virtio_device and calls device_register(). This makes the bus * infrastructure look for a matching driver. */ if (register_virtio_device(&ldev->vdev) != 0) { - printk(KERN_ERR "Failed to register lguest device %u\n", - ldev->vdev.index); + printk(KERN_ERR "Failed to register lguest dev %u type %u\n", + offset, d->type); kfree(ldev); } } @@ -379,7 +374,7 @@ static void scan_devices(void) break; printk("Device at %i has size %u\n", i, desc_size(d)); - add_lguest_device(d); + add_lguest_device(d, i); } } diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c index b8b9e44f7f4e..dbaad39020a1 100644 --- a/drivers/macintosh/adb.c +++ b/drivers/macintosh/adb.c @@ -334,7 +334,7 @@ int __init adb_init(void) return 0; } -__initcall(adb_init); +device_initcall(adb_init); static int do_adb_reset_bus(void) diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index c14dacdacfac..b26927ce889c 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -203,17 +203,6 @@ static void bitmap_checkfree(struct bitmap *bitmap, unsigned long page) * bitmap file handling - read and write the bitmap file and its superblock */ -/* copy the pathname of a file to a buffer */ -char *file_path(struct file *file, char *buf, int count) -{ - if (!buf) - return NULL; - - buf = d_path(&file->f_path, buf, count); - - return IS_ERR(buf) ? NULL : buf; -} - /* * basic page I/O operations */ @@ -721,11 +710,13 @@ static void bitmap_file_kick(struct bitmap *bitmap) if (bitmap->file) { path = kmalloc(PAGE_SIZE, GFP_KERNEL); if (path) - ptr = file_path(bitmap->file, path, PAGE_SIZE); + ptr = d_path(&bitmap->file->f_path, path, + PAGE_SIZE); + printk(KERN_ALERT "%s: kicking failed bitmap file %s from array!\n", - bmname(bitmap), ptr ? ptr : ""); + bmname(bitmap), IS_ERR(ptr) ? "" : ptr); kfree(path); } else diff --git a/drivers/md/md.c b/drivers/md/md.c index 83eb78b00137..51c19f86ff99 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -74,6 +74,8 @@ static DEFINE_SPINLOCK(pers_lock); static void md_print_devices(void); +static DECLARE_WAIT_QUEUE_HEAD(resync_wait); + #define MD_BUG(x...) { printk("md: bug in file %s, line %d\n", __FILE__, __LINE__); md_print_devices(); } /* @@ -3013,6 +3015,36 @@ degraded_show(mddev_t *mddev, char *page) static struct md_sysfs_entry md_degraded = __ATTR_RO(degraded); static ssize_t +sync_force_parallel_show(mddev_t *mddev, char *page) +{ + return sprintf(page, "%d\n", mddev->parallel_resync); +} + +static ssize_t +sync_force_parallel_store(mddev_t *mddev, const char *buf, size_t len) +{ + long n; + + if (strict_strtol(buf, 10, &n)) + return -EINVAL; + + if (n != 0 && n != 1) + return -EINVAL; + + mddev->parallel_resync = n; + + if (mddev->sync_thread) + wake_up(&resync_wait); + + return len; +} + +/* force parallel resync, even with shared block devices */ +static struct md_sysfs_entry md_sync_force_parallel = +__ATTR(sync_force_parallel, S_IRUGO|S_IWUSR, + sync_force_parallel_show, sync_force_parallel_store); + +static ssize_t sync_speed_show(mddev_t *mddev, char *page) { unsigned long resync, dt, db; @@ -3187,6 +3219,7 @@ static struct attribute *md_redundancy_attrs[] = { &md_sync_min.attr, &md_sync_max.attr, &md_sync_speed.attr, + &md_sync_force_parallel.attr, &md_sync_completed.attr, &md_max_sync.attr, &md_suspend_lo.attr, @@ -3691,6 +3724,8 @@ static int do_md_stop(mddev_t * mddev, int mode) module_put(mddev->pers->owner); mddev->pers = NULL; + /* tell userspace to handle 'inactive' */ + sysfs_notify(&mddev->kobj, NULL, "array_state"); set_capacity(disk, 0); mddev->changed = 1; @@ -3987,8 +4022,8 @@ static int get_bitmap_file(mddev_t * mddev, void __user * arg) if (!buf) goto out; - ptr = file_path(mddev->bitmap->file, buf, sizeof(file->pathname)); - if (!ptr) + ptr = d_path(&mddev->bitmap->file->f_path, buf, sizeof(file->pathname)); + if (IS_ERR(ptr)) goto out; strcpy(file->pathname, ptr); @@ -5399,7 +5434,7 @@ void md_done_sync(mddev_t *mddev, int blocks, int ok) atomic_sub(blocks, &mddev->recovery_active); wake_up(&mddev->recovery_wait); if (!ok) { - set_bit(MD_RECOVERY_ERR, &mddev->recovery); + set_bit(MD_RECOVERY_INTR, &mddev->recovery); md_wakeup_thread(mddev->thread); // stop recovery, signal do_sync .... } @@ -5435,8 +5470,11 @@ void md_write_start(mddev_t *mddev, struct bio *bi) md_wakeup_thread(mddev->thread); } spin_unlock_irq(&mddev->write_lock); + sysfs_notify(&mddev->kobj, NULL, "array_state"); } - wait_event(mddev->sb_wait, mddev->flags==0); + wait_event(mddev->sb_wait, + !test_bit(MD_CHANGE_CLEAN, &mddev->flags) && + !test_bit(MD_CHANGE_PENDING, &mddev->flags)); } void md_write_end(mddev_t *mddev) @@ -5471,13 +5509,17 @@ void md_allow_write(mddev_t *mddev) mddev->safemode = 1; spin_unlock_irq(&mddev->write_lock); md_update_sb(mddev, 0); + + sysfs_notify(&mddev->kobj, NULL, "array_state"); + /* wait for the dirty state to be recorded in the metadata */ + wait_event(mddev->sb_wait, + !test_bit(MD_CHANGE_CLEAN, &mddev->flags) && + !test_bit(MD_CHANGE_PENDING, &mddev->flags)); } else spin_unlock_irq(&mddev->write_lock); } EXPORT_SYMBOL_GPL(md_allow_write); -static DECLARE_WAIT_QUEUE_HEAD(resync_wait); - #define SYNC_MARKS 10 #define SYNC_MARK_STEP (3*HZ) void md_do_sync(mddev_t *mddev) @@ -5541,8 +5583,9 @@ void md_do_sync(mddev_t *mddev) for_each_mddev(mddev2, tmp) { if (mddev2 == mddev) continue; - if (mddev2->curr_resync && - match_mddev_units(mddev,mddev2)) { + if (!mddev->parallel_resync + && mddev2->curr_resync + && match_mddev_units(mddev, mddev2)) { DEFINE_WAIT(wq); if (mddev < mddev2 && mddev->curr_resync == 2) { /* arbitrarily yield */ @@ -5647,7 +5690,7 @@ void md_do_sync(mddev_t *mddev) sectors = mddev->pers->sync_request(mddev, j, &skipped, currspeed < speed_min(mddev)); if (sectors == 0) { - set_bit(MD_RECOVERY_ERR, &mddev->recovery); + set_bit(MD_RECOVERY_INTR, &mddev->recovery); goto out; } @@ -5670,8 +5713,7 @@ void md_do_sync(mddev_t *mddev) last_check = io_sectors; - if (test_bit(MD_RECOVERY_INTR, &mddev->recovery) || - test_bit(MD_RECOVERY_ERR, &mddev->recovery)) + if (test_bit(MD_RECOVERY_INTR, &mddev->recovery)) break; repeat: @@ -5725,8 +5767,7 @@ void md_do_sync(mddev_t *mddev) /* tell personality that we are finished */ mddev->pers->sync_request(mddev, max_sectors, &skipped, 1); - if (!test_bit(MD_RECOVERY_ERR, &mddev->recovery) && - !test_bit(MD_RECOVERY_CHECK, &mddev->recovery) && + if (!test_bit(MD_RECOVERY_CHECK, &mddev->recovery) && mddev->curr_resync > 2) { if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) { if (test_bit(MD_RECOVERY_INTR, &mddev->recovery)) { @@ -5795,7 +5836,10 @@ static int remove_and_add_spares(mddev_t *mddev) } if (mddev->degraded) { - rdev_for_each(rdev, rtmp, mddev) + rdev_for_each(rdev, rtmp, mddev) { + if (rdev->raid_disk >= 0 && + !test_bit(In_sync, &rdev->flags)) + spares++; if (rdev->raid_disk < 0 && !test_bit(Faulty, &rdev->flags)) { rdev->recovery_offset = 0; @@ -5813,6 +5857,7 @@ static int remove_and_add_spares(mddev_t *mddev) } else break; } + } } return spares; } @@ -5826,7 +5871,7 @@ static int remove_and_add_spares(mddev_t *mddev) * to do that as needed. * When it is determined that resync is needed, we set MD_RECOVERY_RUNNING in * "->recovery" and create a thread at ->sync_thread. - * When the thread finishes it sets MD_RECOVERY_DONE (and might set MD_RECOVERY_ERR) + * When the thread finishes it sets MD_RECOVERY_DONE * and wakeups up this thread which will reap the thread and finish up. * This thread also removes any faulty devices (with nr_pending == 0). * @@ -5901,8 +5946,7 @@ void md_check_recovery(mddev_t *mddev) /* resync has finished, collect result */ md_unregister_thread(mddev->sync_thread); mddev->sync_thread = NULL; - if (!test_bit(MD_RECOVERY_ERR, &mddev->recovery) && - !test_bit(MD_RECOVERY_INTR, &mddev->recovery)) { + if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery)) { /* success...*/ /* activate any spares */ mddev->pers->spare_active(mddev); @@ -5926,7 +5970,6 @@ void md_check_recovery(mddev_t *mddev) * might be left set */ clear_bit(MD_RECOVERY_NEEDED, &mddev->recovery); - clear_bit(MD_RECOVERY_ERR, &mddev->recovery); clear_bit(MD_RECOVERY_INTR, &mddev->recovery); clear_bit(MD_RECOVERY_DONE, &mddev->recovery); diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c index 4f4d1f383842..e968116e0de9 100644 --- a/drivers/md/multipath.c +++ b/drivers/md/multipath.c @@ -327,7 +327,8 @@ static int multipath_remove_disk(mddev_t *mddev, int number) if (rdev) { if (test_bit(In_sync, &rdev->flags) || atomic_read(&rdev->nr_pending)) { - printk(KERN_ERR "hot-remove-disk, slot %d is identified" " but is still operational!\n", number); + printk(KERN_ERR "hot-remove-disk, slot %d is identified" + " but is still operational!\n", number); err = -EBUSY; goto abort; } diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index ac409b7d83f5..c610b947218a 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -773,7 +773,7 @@ static int make_request(struct request_queue *q, struct bio * bio) r1bio_t *r1_bio; struct bio *read_bio; int i, targets = 0, disks; - struct bitmap *bitmap = mddev->bitmap; + struct bitmap *bitmap; unsigned long flags; struct bio_list bl; struct page **behind_pages = NULL; @@ -802,6 +802,8 @@ static int make_request(struct request_queue *q, struct bio * bio) wait_barrier(conf); + bitmap = mddev->bitmap; + disk_stat_inc(mddev->gendisk, ios[rw]); disk_stat_add(mddev->gendisk, sectors[rw], bio_sectors(bio)); @@ -1025,7 +1027,7 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev) /* * if recovery is running, make sure it aborts. */ - set_bit(MD_RECOVERY_ERR, &mddev->recovery); + set_bit(MD_RECOVERY_INTR, &mddev->recovery); } else set_bit(Faulty, &rdev->flags); set_bit(MD_CHANGE_DEVS, &mddev->flags); @@ -1146,6 +1148,14 @@ static int raid1_remove_disk(mddev_t *mddev, int number) err = -EBUSY; goto abort; } + /* Only remove non-faulty devices is recovery + * is not possible. + */ + if (!test_bit(Faulty, &rdev->flags) && + mddev->degraded < conf->raid_disks) { + err = -EBUSY; + goto abort; + } p->rdev = NULL; synchronize_rcu(); if (atomic_read(&rdev->nr_pending)) { @@ -1282,6 +1292,7 @@ static void sync_request_write(mddev_t *mddev, r1bio_t *r1_bio) rdev_dec_pending(conf->mirrors[i].rdev, mddev); } else { /* fixup the bio for reuse */ + int size; sbio->bi_vcnt = vcnt; sbio->bi_size = r1_bio->sectors << 9; sbio->bi_idx = 0; @@ -1295,10 +1306,20 @@ static void sync_request_write(mddev_t *mddev, r1bio_t *r1_bio) sbio->bi_sector = r1_bio->sector + conf->mirrors[i].rdev->data_offset; sbio->bi_bdev = conf->mirrors[i].rdev->bdev; - for (j = 0; j < vcnt ; j++) - memcpy(page_address(sbio->bi_io_vec[j].bv_page), + size = sbio->bi_size; + for (j = 0; j < vcnt ; j++) { + struct bio_vec *bi; + bi = &sbio->bi_io_vec[j]; + bi->bv_offset = 0; + if (size > PAGE_SIZE) + bi->bv_len = PAGE_SIZE; + else + bi->bv_len = size; + size -= PAGE_SIZE; + memcpy(page_address(bi->bv_page), page_address(pbio->bi_io_vec[j].bv_page), PAGE_SIZE); + } } } diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 8536ede1e712..1de17da34a95 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -1020,7 +1020,7 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev) /* * if recovery is running, make sure it aborts. */ - set_bit(MD_RECOVERY_ERR, &mddev->recovery); + set_bit(MD_RECOVERY_INTR, &mddev->recovery); } set_bit(Faulty, &rdev->flags); set_bit(MD_CHANGE_DEVS, &mddev->flags); @@ -1171,6 +1171,14 @@ static int raid10_remove_disk(mddev_t *mddev, int number) err = -EBUSY; goto abort; } + /* Only remove faulty devices in recovery + * is not possible. + */ + if (!test_bit(Faulty, &rdev->flags) && + enough(conf)) { + err = -EBUSY; + goto abort; + } p->rdev = NULL; synchronize_rcu(); if (atomic_read(&rdev->nr_pending)) { @@ -1237,6 +1245,7 @@ static void end_sync_write(struct bio *bio, int error) if (!uptodate) md_error(mddev, conf->mirrors[d].rdev); + update_head_pos(i, r10_bio); while (atomic_dec_and_test(&r10_bio->remaining)) { @@ -1844,7 +1853,8 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i if (rb2) atomic_dec(&rb2->remaining); r10_bio = rb2; - if (!test_and_set_bit(MD_RECOVERY_ERR, &mddev->recovery)) + if (!test_and_set_bit(MD_RECOVERY_INTR, + &mddev->recovery)) printk(KERN_INFO "raid10: %s: insufficient working devices for recovery.\n", mdname(mddev)); break; diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 93fde48c0f42..425958a76b84 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -94,6 +94,8 @@ #define __inline__ #endif +#define printk_rl(args...) ((void) (printk_ratelimit() && printk(args))) + #if !RAID6_USE_EMPTY_ZERO_PAGE /* In .bss so it's zeroed */ const char raid6_empty_zero_page[PAGE_SIZE] __attribute__((aligned(256))); @@ -1143,10 +1145,12 @@ static void raid5_end_read_request(struct bio * bi, int error) set_bit(R5_UPTODATE, &sh->dev[i].flags); if (test_bit(R5_ReadError, &sh->dev[i].flags)) { rdev = conf->disks[i].rdev; - printk(KERN_INFO "raid5:%s: read error corrected (%lu sectors at %llu on %s)\n", - mdname(conf->mddev), STRIPE_SECTORS, - (unsigned long long)(sh->sector + rdev->data_offset), - bdevname(rdev->bdev, b)); + printk_rl(KERN_INFO "raid5:%s: read error corrected" + " (%lu sectors at %llu on %s)\n", + mdname(conf->mddev), STRIPE_SECTORS, + (unsigned long long)(sh->sector + + rdev->data_offset), + bdevname(rdev->bdev, b)); clear_bit(R5_ReadError, &sh->dev[i].flags); clear_bit(R5_ReWrite, &sh->dev[i].flags); } @@ -1160,16 +1164,22 @@ static void raid5_end_read_request(struct bio * bi, int error) clear_bit(R5_UPTODATE, &sh->dev[i].flags); atomic_inc(&rdev->read_errors); if (conf->mddev->degraded) - printk(KERN_WARNING "raid5:%s: read error not correctable (sector %llu on %s).\n", - mdname(conf->mddev), - (unsigned long long)(sh->sector + rdev->data_offset), - bdn); + printk_rl(KERN_WARNING + "raid5:%s: read error not correctable " + "(sector %llu on %s).\n", + mdname(conf->mddev), + (unsigned long long)(sh->sector + + rdev->data_offset), + bdn); else if (test_bit(R5_ReWrite, &sh->dev[i].flags)) /* Oh, no!!! */ - printk(KERN_WARNING "raid5:%s: read error NOT corrected!! (sector %llu on %s).\n", - mdname(conf->mddev), - (unsigned long long)(sh->sector + rdev->data_offset), - bdn); + printk_rl(KERN_WARNING + "raid5:%s: read error NOT corrected!! " + "(sector %llu on %s).\n", + mdname(conf->mddev), + (unsigned long long)(sh->sector + + rdev->data_offset), + bdn); else if (atomic_read(&rdev->read_errors) > conf->max_nr_stripes) printk(KERN_WARNING @@ -1258,7 +1268,7 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev) /* * if recovery was running, make sure it aborts. */ - set_bit(MD_RECOVERY_ERR, &mddev->recovery); + set_bit(MD_RECOVERY_INTR, &mddev->recovery); } set_bit(Faulty, &rdev->flags); printk (KERN_ALERT @@ -4564,6 +4574,14 @@ static int raid5_remove_disk(mddev_t *mddev, int number) err = -EBUSY; goto abort; } + /* Only remove non-faulty devices if recovery + * isn't possible. + */ + if (!test_bit(Faulty, &rdev->flags) && + mddev->degraded <= conf->max_degraded) { + err = -EBUSY; + goto abort; + } p->rdev = NULL; synchronize_rcu(); if (atomic_read(&rdev->nr_pending)) { diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 89d8d37838a3..3b26fbd3e558 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -901,7 +901,7 @@ endif # V4L_USB_DRIVERS config SOC_CAMERA tristate "SoC camera support" - depends on VIDEO_V4L2 + depends on VIDEO_V4L2 && HAS_DMA select VIDEOBUF_DMA_SG help SoC Camera is a common API to several cameras, not connecting diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index 2ca3e9cfb2bb..0165aac533bf 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -2613,7 +2613,7 @@ static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf) struct bttv_fh *fh = priv; mutex_lock(&fh->cap.vb_lock); - retval = videobuf_mmap_setup(&fh->cap, gbuffers, gbufsize, + retval = __videobuf_mmap_setup(&fh->cap, gbuffers, gbufsize, V4L2_MEMORY_MMAP); if (retval < 0) { mutex_unlock(&fh->cap.vb_lock); diff --git a/drivers/media/video/cs5345.c b/drivers/media/video/cs5345.c index 2a429f9e32cd..03411503457e 100644 --- a/drivers/media/video/cs5345.c +++ b/drivers/media/video/cs5345.c @@ -160,10 +160,17 @@ static int cs5345_probe(struct i2c_client *client, /* ----------------------------------------------------------------------- */ +static const struct i2c_device_id cs5345_id[] = { + { "cs5345", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, cs5345_id); + static struct v4l2_i2c_driver_data v4l2_i2c_data = { .name = "cs5345", .driverid = I2C_DRIVERID_CS5345, .command = cs5345_command, .probe = cs5345_probe, + .id_table = cs5345_id, }; diff --git a/drivers/media/video/cs53l32a.c b/drivers/media/video/cs53l32a.c index 2dfd0afc62db..d965af860ab2 100644 --- a/drivers/media/video/cs53l32a.c +++ b/drivers/media/video/cs53l32a.c @@ -144,7 +144,8 @@ static int cs53l32a_probe(struct i2c_client *client, if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -EIO; - snprintf(client->name, sizeof(client->name) - 1, "cs53l32a"); + if (!id) + strlcpy(client->name, "cs53l32a", sizeof(client->name)); v4l_info(client, "chip found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); @@ -175,10 +176,17 @@ static int cs53l32a_probe(struct i2c_client *client, return 0; } +static const struct i2c_device_id cs53l32a_id[] = { + { "cs53l32a", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, cs53l32a_id); + static struct v4l2_i2c_driver_data v4l2_i2c_data = { .name = "cs53l32a", .driverid = I2C_DRIVERID_CS53L32A, .command = cs53l32a_command, .probe = cs53l32a_probe, + .id_table = cs53l32a_id, }; diff --git a/drivers/media/video/cx18/cx18-i2c.c b/drivers/media/video/cx18/cx18-i2c.c index 4f08a4058d1a..1d6c51a75313 100644 --- a/drivers/media/video/cx18/cx18-i2c.c +++ b/drivers/media/video/cx18/cx18-i2c.c @@ -74,7 +74,7 @@ static const u8 hw_bus[] = { }; /* This array should match the CX18_HW_ defines */ -static const char * const hw_drivernames[] = { +static const char * const hw_devicenames[] = { "tuner", "tveeprom", "cs5345", @@ -95,8 +95,7 @@ int cx18_i2c_register(struct cx18 *cx, unsigned idx) id = hw_driverids[idx]; bus = hw_bus[idx]; memset(&info, 0, sizeof(info)); - strlcpy(info.driver_name, hw_drivernames[idx], - sizeof(info.driver_name)); + strlcpy(info.type, hw_devicenames[idx], sizeof(info.type)); info.addr = hw_addrs[idx]; for (i = 0; i < I2C_CLIENTS_MAX; i++) if (cx->i2c_clients[i] == NULL) @@ -279,7 +278,7 @@ static const char *cx18_i2c_id_name(u32 id) for (i = 0; i < ARRAY_SIZE(hw_driverids); i++) if (hw_driverids[i] == id) - return hw_drivernames[i]; + return hw_devicenames[i]; return "unknown device"; } @@ -290,7 +289,7 @@ static const char *cx18_i2c_hw_name(u32 hw) for (i = 0; i < ARRAY_SIZE(hw_driverids); i++) if (1 << i == hw) - return hw_drivernames[i]; + return hw_devicenames[i]; return "unknown device"; } diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index 88823810497c..607efdcd22f8 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -1284,10 +1284,17 @@ static int cx25840_remove(struct i2c_client *client) return 0; } +static const struct i2c_device_id cx25840_id[] = { + { "cx25840", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, cx25840_id); + static struct v4l2_i2c_driver_data v4l2_i2c_data = { .name = "cx25840", .driverid = I2C_DRIVERID_CX25840, .command = cx25840_command, .probe = cx25840_probe, .remove = cx25840_remove, + .id_table = cx25840_id, }; diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c index 5e749c528a62..15d037ae25c5 100644 --- a/drivers/media/video/et61x251/et61x251_core.c +++ b/drivers/media/video/et61x251/et61x251_core.c @@ -34,7 +34,7 @@ #include <linux/mm.h> #include <linux/vmalloc.h> #include <linux/page-flags.h> -#include <linux/byteorder/generic.h> +#include <asm/byteorder.h> #include <asm/page.h> #include <asm/uaccess.h> diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c index 771adf47e944..32129f3ea836 100644 --- a/drivers/media/video/ivtv/ivtv-i2c.c +++ b/drivers/media/video/ivtv/ivtv-i2c.c @@ -136,7 +136,7 @@ static const u8 hw_addrs[] = { }; /* This array should match the IVTV_HW_ defines */ -static const char * const hw_drivernames[] = { +static const char * const hw_devicenames[] = { "cx25840", "saa7115", "saa7127", @@ -145,7 +145,7 @@ static const char * const hw_drivernames[] = { "wm8775", "cs53l32a", "tveeprom", - "saa7115", + "saa7114", "upd64031a", "upd64083", "saa717x", @@ -167,8 +167,7 @@ int ivtv_i2c_register(struct ivtv *itv, unsigned idx) return -1; id = hw_driverids[idx]; memset(&info, 0, sizeof(info)); - strlcpy(info.driver_name, hw_drivernames[idx], - sizeof(info.driver_name)); + strlcpy(info.type, hw_devicenames[idx], sizeof(info.type)); info.addr = hw_addrs[idx]; for (i = 0; itv->i2c_clients[i] && i < I2C_CLIENTS_MAX; i++) {} @@ -657,7 +656,7 @@ static const char *ivtv_i2c_id_name(u32 id) for (i = 0; i < ARRAY_SIZE(hw_driverids); i++) if (hw_driverids[i] == id) - return hw_drivernames[i]; + return hw_devicenames[i]; return "unknown device"; } @@ -668,7 +667,7 @@ static const char *ivtv_i2c_hw_name(u32 hw) for (i = 0; i < ARRAY_SIZE(hw_driverids); i++) if (1 << i == hw) - return hw_drivernames[i]; + return hw_devicenames[i]; return "unknown device"; } @@ -770,7 +769,7 @@ int init_ivtv_i2c(struct ivtv *itv) * same size and GPIO must be the last entry. */ if (ARRAY_SIZE(hw_driverids) != ARRAY_SIZE(hw_addrs) || - ARRAY_SIZE(hw_drivernames) != ARRAY_SIZE(hw_addrs) || + ARRAY_SIZE(hw_devicenames) != ARRAY_SIZE(hw_addrs) || IVTV_HW_GPIO != (1 << (ARRAY_SIZE(hw_addrs) - 1)) || hw_driverids[ARRAY_SIZE(hw_addrs) - 1]) { IVTV_ERR("Mismatched I2C hardware arrays\n"); diff --git a/drivers/media/video/m52790.c b/drivers/media/video/m52790.c index 5b9dfa2c51b4..8e0160d275ca 100644 --- a/drivers/media/video/m52790.c +++ b/drivers/media/video/m52790.c @@ -135,8 +135,6 @@ static int m52790_probe(struct i2c_client *client, if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -EIO; - snprintf(client->name, sizeof(client->name) - 1, "m52790"); - v4l_info(client, "chip found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); @@ -159,11 +157,18 @@ static int m52790_remove(struct i2c_client *client) /* ----------------------------------------------------------------------- */ +static const struct i2c_device_id m52790_id[] = { + { "m52790", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, m52790_id); + static struct v4l2_i2c_driver_data v4l2_i2c_data = { .name = "m52790", .driverid = I2C_DRIVERID_M52790, .command = m52790_command, .probe = m52790_probe, .remove = m52790_remove, + .id_table = m52790_id, }; diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c index e6273162e123..310dbaba55ff 100644 --- a/drivers/media/video/msp3400-driver.c +++ b/drivers/media/video/msp3400-driver.c @@ -815,7 +815,8 @@ static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id) int msp_product, msp_prod_hi, msp_prod_lo; int msp_rom; - snprintf(client->name, sizeof(client->name) - 1, "msp3400"); + if (!id) + strlcpy(client->name, "msp3400", sizeof(client->name)); if (msp_reset(client) == -1) { v4l_dbg(1, msp_debug, client, "msp3400 not found\n"); @@ -864,9 +865,6 @@ static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id) msp_revision = (state->rev1 & 0x0f) + '@'; msp_hard = ((state->rev1 >> 8) & 0xff) + '@'; msp_rom = state->rev2 & 0x1f; - snprintf(client->name, sizeof(client->name), "MSP%d4%02d%c-%c%d", - msp_family, msp_product, - msp_revision, msp_hard, msp_rom); /* Rev B=2, C=3, D=4, G=7 */ state->ident = msp_family * 10000 + 4000 + msp_product * 10 + msp_revision - '@'; @@ -931,7 +929,9 @@ static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id) } /* hello world :-) */ - v4l_info(client, "%s found @ 0x%x (%s)\n", client->name, + v4l_info(client, "MSP%d4%02d%c-%c%d found @ 0x%x (%s)\n", + msp_family, msp_product, + msp_revision, msp_hard, msp_rom, client->addr << 1, client->adapter->name); v4l_info(client, "%s ", client->name); if (state->has_nicam && state->has_radio) @@ -987,6 +987,12 @@ static int msp_remove(struct i2c_client *client) /* ----------------------------------------------------------------------- */ +static const struct i2c_device_id msp_id[] = { + { "msp3400", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, msp_id); + static struct v4l2_i2c_driver_data v4l2_i2c_data = { .name = "msp3400", .driverid = I2C_DRIVERID_MSP3400, @@ -995,6 +1001,7 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = { .remove = msp_remove, .suspend = msp_suspend, .resume = msp_resume, + .id_table = msp_id, }; diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c index e684108637ad..435c083cc542 100644 --- a/drivers/media/video/saa7115.c +++ b/drivers/media/video/saa7115.c @@ -1456,14 +1456,13 @@ static int saa7115_probe(struct i2c_client *client, struct saa711x_state *state; int i; char name[17]; - u8 chip_id; + char chip_id; + int autodetect = !id || id->driver_data == 1; /* Check if the adapter supports the needed features */ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -EIO; - snprintf(client->name, sizeof(client->name) - 1, "saa7115"); - for (i = 0; i < 0x0f; i++) { saa711x_write(client, 0, i); name[i] = (saa711x_read(client, 0) & 0x0f) + '0'; @@ -1472,8 +1471,7 @@ static int saa7115_probe(struct i2c_client *client, } name[i] = '\0'; - saa711x_write(client, 0, 5); - chip_id = saa711x_read(client, 0) & 0x0f; + chip_id = name[5]; /* Check whether this chip is part of the saa711x series */ if (memcmp(name, "1f711", 5)) { @@ -1482,8 +1480,14 @@ static int saa7115_probe(struct i2c_client *client, return -ENODEV; } - snprintf(client->name, sizeof(client->name) - 1, "saa711%d",chip_id); - v4l_info(client, "saa711%d found (%s) @ 0x%x (%s)\n", chip_id, name, client->addr << 1, client->adapter->name); + /* Safety check */ + if (!autodetect && id->name[6] != chip_id) { + v4l_warn(client, "found saa711%c while %s was expected\n", + chip_id, id->name); + } + snprintf(client->name, sizeof(client->name), "saa711%c", chip_id); + v4l_info(client, "saa711%c found (%s) @ 0x%x (%s)\n", chip_id, name, + client->addr << 1, client->adapter->name); state = kzalloc(sizeof(struct saa711x_state), GFP_KERNEL); i2c_set_clientdata(client, state); @@ -1499,19 +1503,19 @@ static int saa7115_probe(struct i2c_client *client, state->hue = 0; state->sat = 64; switch (chip_id) { - case 1: + case '1': state->ident = V4L2_IDENT_SAA7111; break; - case 3: + case '3': state->ident = V4L2_IDENT_SAA7113; break; - case 4: + case '4': state->ident = V4L2_IDENT_SAA7114; break; - case 5: + case '5': state->ident = V4L2_IDENT_SAA7115; break; - case 8: + case '8': state->ident = V4L2_IDENT_SAA7118; break; default: @@ -1553,6 +1557,17 @@ static int saa7115_remove(struct i2c_client *client) return 0; } +static const struct i2c_device_id saa7115_id[] = { + { "saa711x", 1 }, /* autodetect */ + { "saa7111", 0 }, + { "saa7113", 0 }, + { "saa7114", 0 }, + { "saa7115", 0 }, + { "saa7118", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, saa7115_id); + static struct v4l2_i2c_driver_data v4l2_i2c_data = { .name = "saa7115", .driverid = I2C_DRIVERID_SAA711X, @@ -1560,5 +1575,6 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = { .probe = saa7115_probe, .remove = saa7115_remove, .legacy_class = I2C_CLASS_TV_ANALOG | I2C_CLASS_TV_DIGITAL, + .id_table = saa7115_id, }; diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c index e750cd65c1c3..79d11a658bdf 100644 --- a/drivers/media/video/saa7127.c +++ b/drivers/media/video/saa7127.c @@ -672,8 +672,6 @@ static int saa7127_probe(struct i2c_client *client, if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -EIO; - snprintf(client->name, sizeof(client->name) - 1, "saa7127"); - v4l_dbg(1, debug, client, "detecting saa7127 client on address 0x%x\n", client->addr << 1); @@ -741,11 +739,18 @@ static int saa7127_remove(struct i2c_client *client) /* ----------------------------------------------------------------------- */ +static struct i2c_device_id saa7127_id[] = { + { "saa7127", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, saa7127_id); + static struct v4l2_i2c_driver_data v4l2_i2c_data = { .name = "saa7127", .driverid = I2C_DRIVERID_SAA7127, .command = saa7127_command, .probe = saa7127_probe, .remove = saa7127_remove, + .id_table = saa7127_id, }; diff --git a/drivers/media/video/saa717x.c b/drivers/media/video/saa717x.c index 72c4081feff5..2220f9569941 100644 --- a/drivers/media/video/saa717x.c +++ b/drivers/media/video/saa717x.c @@ -1429,8 +1429,6 @@ static int saa717x_probe(struct i2c_client *client, if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -EIO; - snprintf(client->name, sizeof(client->name) - 1, "saa717x"); - if (saa717x_write(client, 0x5a4, 0xfe) && saa717x_write(client, 0x5a5, 0x0f) && saa717x_write(client, 0x5a6, 0x00) && @@ -1507,6 +1505,12 @@ static int saa717x_remove(struct i2c_client *client) /* ----------------------------------------------------------------------- */ +static const struct i2c_device_id saa717x_id[] = { + { "saa717x", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, saa717x_id); + static struct v4l2_i2c_driver_data v4l2_i2c_data = { .name = "saa717x", .driverid = I2C_DRIVERID_SAA717X, @@ -1514,4 +1518,5 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = { .probe = saa717x_probe, .remove = saa717x_remove, .legacy_class = I2C_CLASS_TV_ANALOG | I2C_CLASS_TV_DIGITAL, + .id_table = saa717x_id, }; diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c index 5748b1e1a128..7f9c7bcf3c85 100644 --- a/drivers/media/video/sn9c102/sn9c102_core.c +++ b/drivers/media/video/sn9c102/sn9c102_core.c @@ -34,7 +34,7 @@ #include <linux/mm.h> #include <linux/vmalloc.h> #include <linux/page-flags.h> -#include <linux/byteorder/generic.h> +#include <asm/byteorder.h> #include <asm/page.h> #include <asm/uaccess.h> diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 5a75788b92ae..a0f7bc1edaa2 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -92,6 +92,7 @@ struct tuner { unsigned int type; /* chip type id */ unsigned int config; int (*tuner_callback) (void *dev, int command, int arg); + const char *name; }; /* standard i2c insmod options */ @@ -330,13 +331,13 @@ static void tuner_i2c_address_check(struct tuner *t) tuner_warn("Support for tuners in i2c address range 0x64 thru 0x6f\n"); tuner_warn("will soon be dropped. This message indicates that your\n"); tuner_warn("hardware has a %s tuner at i2c address 0x%02x.\n", - t->i2c->name, t->i2c->addr); + t->name, t->i2c->addr); tuner_warn("To ensure continued support for your device, please\n"); tuner_warn("send a copy of this message, along with full dmesg\n"); tuner_warn("output to v4l-dvb-maintainer@linuxtv.org\n"); tuner_warn("Please use subject line: \"obsolete tuner i2c address.\"\n"); tuner_warn("driver: %s, addr: 0x%02x, type: %d (%s)\n", - t->i2c->adapter->name, t->i2c->addr, t->type, t->i2c->name); + t->i2c->adapter->name, t->i2c->addr, t->type, t->name); tuner_warn("====================== WARNING! ======================\n"); } @@ -470,19 +471,17 @@ static void set_type(struct i2c_client *c, unsigned int type, if ((NULL == analog_ops->set_params) && (fe_tuner_ops->set_analog_params)) { - strlcpy(t->i2c->name, fe_tuner_ops->info.name, - sizeof(t->i2c->name)); + t->name = fe_tuner_ops->info.name; t->fe.analog_demod_priv = t; memcpy(analog_ops, &tuner_core_ops, sizeof(struct analog_demod_ops)); } else { - strlcpy(t->i2c->name, analog_ops->info.name, - sizeof(t->i2c->name)); + t->name = analog_ops->info.name; } - tuner_dbg("type set to %s\n", t->i2c->name); + tuner_dbg("type set to %s\n", t->name); if (t->mode_mask == T_UNINITIALIZED) t->mode_mask = new_mode_mask; @@ -1115,7 +1114,7 @@ static int tuner_probe(struct i2c_client *client, if (NULL == t) return -ENOMEM; t->i2c = client; - strlcpy(client->name, "(tuner unset)", sizeof(client->name)); + t->name = "(tuner unset)"; i2c_set_clientdata(client, t); t->type = UNSET; t->audmode = V4L2_TUNER_MODE_STEREO; @@ -1278,6 +1277,15 @@ static int tuner_remove(struct i2c_client *client) /* ----------------------------------------------------------------------- */ +/* This driver supports many devices and the idea is to let the driver + detect which device is present. So rather than listing all supported + devices here, we pretend to support a single, fake device type. */ +static const struct i2c_device_id tuner_id[] = { + { "tuner", }, /* autodetect */ + { } +}; +MODULE_DEVICE_TABLE(i2c, tuner_id); + static struct v4l2_i2c_driver_data v4l2_i2c_data = { .name = "tuner", .driverid = I2C_DRIVERID_TUNER, @@ -1287,6 +1295,7 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = { .suspend = tuner_suspend, .resume = tuner_resume, .legacy_probe = tuner_legacy_probe, + .id_table = tuner_id, }; diff --git a/drivers/media/video/upd64031a.c b/drivers/media/video/upd64031a.c index 93bfd19dec7d..b4628874933b 100644 --- a/drivers/media/video/upd64031a.c +++ b/drivers/media/video/upd64031a.c @@ -228,6 +228,11 @@ static int upd64031a_remove(struct i2c_client *client) /* ----------------------------------------------------------------------- */ +static const struct i2c_device_id upd64031a_id[] = { + { "upd64031a", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, upd64031a_id); static struct v4l2_i2c_driver_data v4l2_i2c_data = { .name = "upd64031a", @@ -235,4 +240,5 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = { .command = upd64031a_command, .probe = upd64031a_probe, .remove = upd64031a_remove, + .id_table = upd64031a_id, }; diff --git a/drivers/media/video/upd64083.c b/drivers/media/video/upd64083.c index 9ab712a56ce0..9521ce004dcc 100644 --- a/drivers/media/video/upd64083.c +++ b/drivers/media/video/upd64083.c @@ -205,6 +205,11 @@ static int upd64083_remove(struct i2c_client *client) /* ----------------------------------------------------------------------- */ +static const struct i2c_device_id upd64083_id[] = { + { "upd64083", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, upd64083_id); static struct v4l2_i2c_driver_data v4l2_i2c_data = { .name = "upd64083", @@ -212,4 +217,5 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = { .command = upd64083_command, .probe = upd64083_probe, .remove = upd64083_remove, + .id_table = upd64083_id, }; diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c index 982f4463896c..0a88c44ace00 100644 --- a/drivers/media/video/videobuf-core.c +++ b/drivers/media/video/videobuf-core.c @@ -331,7 +331,7 @@ int videobuf_mmap_free(struct videobuf_queue *q) } /* Locking: Caller holds q->vb_lock */ -static int __videobuf_mmap_setup(struct videobuf_queue *q, +int __videobuf_mmap_setup(struct videobuf_queue *q, unsigned int bcount, unsigned int bsize, enum v4l2_memory memory) { @@ -1129,6 +1129,7 @@ EXPORT_SYMBOL_GPL(videobuf_read_stream); EXPORT_SYMBOL_GPL(videobuf_read_one); EXPORT_SYMBOL_GPL(videobuf_poll_stream); +EXPORT_SYMBOL_GPL(__videobuf_mmap_setup); EXPORT_SYMBOL_GPL(videobuf_mmap_setup); EXPORT_SYMBOL_GPL(videobuf_mmap_free); EXPORT_SYMBOL_GPL(videobuf_mmap_mapper); diff --git a/drivers/media/video/vp27smpx.c b/drivers/media/video/vp27smpx.c index fac0deba24af..a1f76ee032e7 100644 --- a/drivers/media/video/vp27smpx.c +++ b/drivers/media/video/vp27smpx.c @@ -130,8 +130,6 @@ static int vp27smpx_probe(struct i2c_client *client, if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -EIO; - snprintf(client->name, sizeof(client->name) - 1, "vp27smpx"); - v4l_info(client, "chip found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); @@ -154,11 +152,18 @@ static int vp27smpx_remove(struct i2c_client *client) /* ----------------------------------------------------------------------- */ +static const struct i2c_device_id vp27smpx_id[] = { + { "vp27smpx", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, vp27smpx_id); + static struct v4l2_i2c_driver_data v4l2_i2c_data = { .name = "vp27smpx", .driverid = I2C_DRIVERID_VP27SMPX, .command = vp27smpx_command, .probe = vp27smpx_probe, .remove = vp27smpx_remove, + .id_table = vp27smpx_id, }; diff --git a/drivers/media/video/wm8739.c b/drivers/media/video/wm8739.c index 0f8ed8461fba..fc50299caa36 100644 --- a/drivers/media/video/wm8739.c +++ b/drivers/media/video/wm8739.c @@ -313,11 +313,18 @@ static int wm8739_remove(struct i2c_client *client) return 0; } +static const struct i2c_device_id wm8739_id[] = { + { "wm8739", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, wm8739_id); + static struct v4l2_i2c_driver_data v4l2_i2c_data = { .name = "wm8739", .driverid = I2C_DRIVERID_WM8739, .command = wm8739_command, .probe = wm8739_probe, .remove = wm8739_remove, + .id_table = wm8739_id, }; diff --git a/drivers/media/video/wm8775.c b/drivers/media/video/wm8775.c index 67a409e60c46..506378a508b9 100644 --- a/drivers/media/video/wm8775.c +++ b/drivers/media/video/wm8775.c @@ -216,11 +216,18 @@ static int wm8775_remove(struct i2c_client *client) return 0; } +static const struct i2c_device_id wm8775_id[] = { + { "wm8775", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, wm8775_id); + static struct v4l2_i2c_driver_data v4l2_i2c_data = { .name = "wm8775", .driverid = I2C_DRIVERID_WM8775, .command = wm8775_command, .probe = wm8775_probe, .remove = wm8775_remove, + .id_table = wm8775_id, }; diff --git a/drivers/media/video/zc0301/zc0301_core.c b/drivers/media/video/zc0301/zc0301_core.c index 363dd2b9475c..e5c4e9f5193f 100644 --- a/drivers/media/video/zc0301/zc0301_core.c +++ b/drivers/media/video/zc0301/zc0301_core.c @@ -38,7 +38,7 @@ #include <linux/mm.h> #include <linux/vmalloc.h> #include <linux/page-flags.h> -#include <linux/byteorder/generic.h> +#include <asm/byteorder.h> #include <asm/page.h> #include <asm/uaccess.h> diff --git a/drivers/media/video/zoran_device.c b/drivers/media/video/zoran_device.c index 7b60533efe45..37629ffd34c3 100644 --- a/drivers/media/video/zoran_device.c +++ b/drivers/media/video/zoran_device.c @@ -31,7 +31,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/vmalloc.h> -#include <linux/byteorder/generic.h> #include <linux/interrupt.h> #include <linux/proc_fs.h> @@ -47,6 +46,7 @@ #include <linux/delay.h> #include <linux/wait.h> +#include <asm/byteorder.h> #include <asm/io.h> #include "videocodec.h" diff --git a/drivers/media/video/zoran_driver.c b/drivers/media/video/zoran_driver.c index 0134bec1e399..345c77e46837 100644 --- a/drivers/media/video/zoran_driver.c +++ b/drivers/media/video/zoran_driver.c @@ -52,7 +52,6 @@ #include <linux/pci.h> #include <linux/vmalloc.h> #include <linux/wait.h> -#include <linux/byteorder/generic.h> #include <linux/interrupt.h> #include <linux/i2c.h> @@ -74,6 +73,7 @@ #include <media/v4l2-common.h> #include "videocodec.h" +#include <asm/byteorder.h> #include <asm/io.h> #include <asm/uaccess.h> #include <linux/proc_fs.h> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 2566479937c9..ae96bd6242f2 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -24,7 +24,7 @@ config MFD_ASIC3 config HTC_EGPIO bool "HTC EGPIO support" - depends on GENERIC_HARDIRQS && HAVE_GPIO_LIB + depends on GENERIC_HARDIRQS && HAVE_GPIO_LIB && ARM help This driver supports the CPLD egpio chip present on several HTC phones. It provides basic support for input diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 3f28f6eabdbf..a0ce0b2fa03e 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -3821,7 +3821,7 @@ TPACPI_HANDLE(led, ec, "SLED", /* 570 */ #define TPACPI_LED_NUMLEDS 8 static struct tpacpi_led_classdev *tpacpi_leds; static enum led_status_t tpacpi_led_state_cache[TPACPI_LED_NUMLEDS]; -static const char const *tpacpi_led_names[TPACPI_LED_NUMLEDS] = { +static const char * const tpacpi_led_names[TPACPI_LED_NUMLEDS] = { /* there's a limit of 19 chars + NULL before 2.6.26 */ "tpacpi::power", "tpacpi:orange:batt", @@ -3860,10 +3860,10 @@ static int led_get_status(unsigned int led) static int led_set_status(unsigned int led, enum led_status_t ledstatus) { /* off, on, blink. Index is led_status_t */ - static const int const led_sled_arg1[] = { 0, 1, 3 }; - static const int const led_exp_hlbl[] = { 0, 0, 1 }; /* led# * */ - static const int const led_exp_hlcl[] = { 0, 1, 1 }; /* led# * */ - static const int const led_led_arg1[] = { 0, 0x80, 0xc0 }; + static const int led_sled_arg1[] = { 0, 1, 3 }; + static const int led_exp_hlbl[] = { 0, 0, 1 }; /* led# * */ + static const int led_exp_hlcl[] = { 0, 1, 1 }; /* led# * */ + static const int led_led_arg1[] = { 0, 0x80, 0xc0 }; int rc = 0; diff --git a/drivers/mmc/card/Kconfig b/drivers/mmc/card/Kconfig index aa8a4e461942..dd0f398ee2f5 100644 --- a/drivers/mmc/card/Kconfig +++ b/drivers/mmc/card/Kconfig @@ -39,3 +39,15 @@ config SDIO_UART SDIO function driver for SDIO cards that implements the UART class, as well as the GPS class which appears like a UART. +config MMC_TEST + tristate "MMC host test driver" + default n + help + Development driver that performs a series of reads and writes + to a memory card in order to expose certain well known bugs + in host controllers. The tests are executed by writing to the + "test" file in sysfs under each card. Note that whatever is + on your card will be overwritten by these tests. + + This driver is only of interest to those developing or + testing a host driver. Most people should say N here. diff --git a/drivers/mmc/card/Makefile b/drivers/mmc/card/Makefile index fc5a784cfa1a..0d407514f67d 100644 --- a/drivers/mmc/card/Makefile +++ b/drivers/mmc/card/Makefile @@ -8,6 +8,7 @@ endif obj-$(CONFIG_MMC_BLOCK) += mmc_block.o mmc_block-objs := block.o queue.o +obj-$(CONFIG_MMC_TEST) += mmc_test.o obj-$(CONFIG_SDIO_UART) += sdio_uart.o diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c new file mode 100644 index 000000000000..ffadee549a41 --- /dev/null +++ b/drivers/mmc/card/mmc_test.c @@ -0,0 +1,892 @@ +/* + * linux/drivers/mmc/card/mmc_test.c + * + * Copyright 2007 Pierre Ossman + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + */ + +#include <linux/mmc/core.h> +#include <linux/mmc/card.h> +#include <linux/mmc/host.h> +#include <linux/mmc/mmc.h> + +#include <linux/scatterlist.h> + +#define RESULT_OK 0 +#define RESULT_FAIL 1 +#define RESULT_UNSUP_HOST 2 +#define RESULT_UNSUP_CARD 3 + +#define BUFFER_SIZE (PAGE_SIZE * 4) + +struct mmc_test_card { + struct mmc_card *card; + + u8 *buffer; +}; + +/*******************************************************************/ +/* Helper functions */ +/*******************************************************************/ + +static int mmc_test_set_blksize(struct mmc_test_card *test, unsigned size) +{ + struct mmc_command cmd; + int ret; + + cmd.opcode = MMC_SET_BLOCKLEN; + cmd.arg = size; + cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; + ret = mmc_wait_for_cmd(test->card->host, &cmd, 0); + if (ret) + return ret; + + return 0; +} + +static int __mmc_test_transfer(struct mmc_test_card *test, int write, + unsigned broken_xfer, u8 *buffer, unsigned addr, + unsigned blocks, unsigned blksz) +{ + int ret, busy; + + struct mmc_request mrq; + struct mmc_command cmd; + struct mmc_command stop; + struct mmc_data data; + + struct scatterlist sg; + + memset(&mrq, 0, sizeof(struct mmc_request)); + + mrq.cmd = &cmd; + mrq.data = &data; + + memset(&cmd, 0, sizeof(struct mmc_command)); + + if (broken_xfer) { + if (blocks > 1) { + cmd.opcode = write ? + MMC_WRITE_BLOCK : MMC_READ_SINGLE_BLOCK; + } else { + cmd.opcode = MMC_SEND_STATUS; + } + } else { + if (blocks > 1) { + cmd.opcode = write ? + MMC_WRITE_MULTIPLE_BLOCK : MMC_READ_MULTIPLE_BLOCK; + } else { + cmd.opcode = write ? + MMC_WRITE_BLOCK : MMC_READ_SINGLE_BLOCK; + } + } + + if (broken_xfer && blocks == 1) + cmd.arg = test->card->rca << 16; + else + cmd.arg = addr; + cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; + + memset(&stop, 0, sizeof(struct mmc_command)); + + if (!broken_xfer && (blocks > 1)) { + stop.opcode = MMC_STOP_TRANSMISSION; + stop.arg = 0; + stop.flags = MMC_RSP_R1B | MMC_CMD_AC; + + mrq.stop = &stop; + } + + memset(&data, 0, sizeof(struct mmc_data)); + + data.blksz = blksz; + data.blocks = blocks; + data.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ; + data.sg = &sg; + data.sg_len = 1; + + sg_init_one(&sg, buffer, blocks * blksz); + + mmc_set_data_timeout(&data, test->card); + + mmc_wait_for_req(test->card->host, &mrq); + + ret = 0; + + if (broken_xfer) { + if (!ret && cmd.error) + ret = cmd.error; + if (!ret && data.error == 0) + ret = RESULT_FAIL; + if (!ret && data.error != -ETIMEDOUT) + ret = data.error; + if (!ret && stop.error) + ret = stop.error; + if (blocks > 1) { + if (!ret && data.bytes_xfered > blksz) + ret = RESULT_FAIL; + } else { + if (!ret && data.bytes_xfered > 0) + ret = RESULT_FAIL; + } + } else { + if (!ret && cmd.error) + ret = cmd.error; + if (!ret && data.error) + ret = data.error; + if (!ret && stop.error) + ret = stop.error; + if (!ret && data.bytes_xfered != blocks * blksz) + ret = RESULT_FAIL; + } + + if (ret == -EINVAL) + ret = RESULT_UNSUP_HOST; + + busy = 0; + do { + int ret2; + + memset(&cmd, 0, sizeof(struct mmc_command)); + + cmd.opcode = MMC_SEND_STATUS; + cmd.arg = test->card->rca << 16; + cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; + + ret2 = mmc_wait_for_cmd(test->card->host, &cmd, 0); + if (ret2) + break; + + if (!busy && !(cmd.resp[0] & R1_READY_FOR_DATA)) { + busy = 1; + printk(KERN_INFO "%s: Warning: Host did not " + "wait for busy state to end.\n", + mmc_hostname(test->card->host)); + } + } while (!(cmd.resp[0] & R1_READY_FOR_DATA)); + + return ret; +} + +static int mmc_test_transfer(struct mmc_test_card *test, int write, + u8 *buffer, unsigned addr, unsigned blocks, unsigned blksz) +{ + return __mmc_test_transfer(test, write, 0, buffer, + addr, blocks, blksz); +} + +static int mmc_test_prepare_verify(struct mmc_test_card *test, int write) +{ + int ret, i; + + ret = mmc_test_set_blksize(test, 512); + if (ret) + return ret; + + if (write) + memset(test->buffer, 0xDF, BUFFER_SIZE); + else { + for (i = 0;i < BUFFER_SIZE;i++) + test->buffer[i] = i; + } + + for (i = 0;i < BUFFER_SIZE / 512;i++) { + ret = mmc_test_transfer(test, 1, test->buffer + i * 512, + i * 512, 1, 512); + if (ret) + return ret; + } + + return 0; +} + +static int mmc_test_prepare_verify_write(struct mmc_test_card *test) +{ + return mmc_test_prepare_verify(test, 1); +} + +static int mmc_test_prepare_verify_read(struct mmc_test_card *test) +{ + return mmc_test_prepare_verify(test, 0); +} + +static int mmc_test_verified_transfer(struct mmc_test_card *test, int write, + u8 *buffer, unsigned addr, unsigned blocks, unsigned blksz) +{ + int ret, i, sectors; + + /* + * It is assumed that the above preparation has been done. + */ + + memset(test->buffer, 0, BUFFER_SIZE); + + if (write) { + for (i = 0;i < blocks * blksz;i++) + buffer[i] = i; + } + + ret = mmc_test_set_blksize(test, blksz); + if (ret) + return ret; + + ret = mmc_test_transfer(test, write, buffer, addr, blocks, blksz); + if (ret) + return ret; + + if (write) { + ret = mmc_test_set_blksize(test, 512); + if (ret) + return ret; + + sectors = (blocks * blksz + 511) / 512; + if ((sectors * 512) == (blocks * blksz)) + sectors++; + + if ((sectors * 512) > BUFFER_SIZE) + return -EINVAL; + + memset(test->buffer, 0, sectors * 512); + + for (i = 0;i < sectors;i++) { + ret = mmc_test_transfer(test, 0, + test->buffer + i * 512, + addr + i * 512, 1, 512); + if (ret) + return ret; + } + + for (i = 0;i < blocks * blksz;i++) { + if (test->buffer[i] != (u8)i) + return RESULT_FAIL; + } + + for (;i < sectors * 512;i++) { + if (test->buffer[i] != 0xDF) + return RESULT_FAIL; + } + } else { + for (i = 0;i < blocks * blksz;i++) { + if (buffer[i] != (u8)i) + return RESULT_FAIL; + } + } + + return 0; +} + +static int mmc_test_cleanup_verify(struct mmc_test_card *test) +{ + int ret, i; + + ret = mmc_test_set_blksize(test, 512); + if (ret) + return ret; + + memset(test->buffer, 0, BUFFER_SIZE); + + for (i = 0;i < BUFFER_SIZE / 512;i++) { + ret = mmc_test_transfer(test, 1, test->buffer + i * 512, + i * 512, 1, 512); + if (ret) + return ret; + } + + return 0; +} + +/*******************************************************************/ +/* Tests */ +/*******************************************************************/ + +struct mmc_test_case { + const char *name; + + int (*prepare)(struct mmc_test_card *); + int (*run)(struct mmc_test_card *); + int (*cleanup)(struct mmc_test_card *); +}; + +static int mmc_test_basic_write(struct mmc_test_card *test) +{ + int ret; + + ret = mmc_test_set_blksize(test, 512); + if (ret) + return ret; + + ret = mmc_test_transfer(test, 1, test->buffer, 0, 1, 512); + if (ret) + return ret; + + return 0; +} + +static int mmc_test_basic_read(struct mmc_test_card *test) +{ + int ret; + + ret = mmc_test_set_blksize(test, 512); + if (ret) + return ret; + + ret = mmc_test_transfer(test, 0, test->buffer, 0, 1, 512); + if (ret) + return ret; + + return 0; +} + +static int mmc_test_verify_write(struct mmc_test_card *test) +{ + int ret; + + ret = mmc_test_verified_transfer(test, 1, test->buffer, 0, 1, 512); + if (ret) + return ret; + + return 0; +} + +static int mmc_test_verify_read(struct mmc_test_card *test) +{ + int ret; + + ret = mmc_test_verified_transfer(test, 0, test->buffer, 0, 1, 512); + if (ret) + return ret; + + return 0; +} + +static int mmc_test_multi_write(struct mmc_test_card *test) +{ + int ret; + unsigned int size; + + if (test->card->host->max_blk_count == 1) + return RESULT_UNSUP_HOST; + + size = PAGE_SIZE * 2; + size = min(size, test->card->host->max_req_size); + size = min(size, test->card->host->max_seg_size); + size = min(size, test->card->host->max_blk_count * 512); + + if (size < 1024) + return RESULT_UNSUP_HOST; + + ret = mmc_test_verified_transfer(test, 1, test->buffer, 0, + size / 512, 512); + if (ret) + return ret; + + return 0; +} + +static int mmc_test_multi_read(struct mmc_test_card *test) +{ + int ret; + unsigned int size; + + if (test->card->host->max_blk_count == 1) + return RESULT_UNSUP_HOST; + + size = PAGE_SIZE * 2; + size = min(size, test->card->host->max_req_size); + size = min(size, test->card->host->max_seg_size); + size = min(size, test->card->host->max_blk_count * 512); + + if (size < 1024) + return RESULT_UNSUP_HOST; + + ret = mmc_test_verified_transfer(test, 0, test->buffer, 0, + size / 512, 512); + if (ret) + return ret; + + return 0; +} + +static int mmc_test_pow2_write(struct mmc_test_card *test) +{ + int ret, i; + + if (!test->card->csd.write_partial) + return RESULT_UNSUP_CARD; + + for (i = 1; i < 512;i <<= 1) { + ret = mmc_test_verified_transfer(test, 1, + test->buffer, 0, 1, i); + if (ret) + return ret; + } + + return 0; +} + +static int mmc_test_pow2_read(struct mmc_test_card *test) +{ + int ret, i; + + if (!test->card->csd.read_partial) + return RESULT_UNSUP_CARD; + + for (i = 1; i < 512;i <<= 1) { + ret = mmc_test_verified_transfer(test, 0, + test->buffer, 0, 1, i); + if (ret) + return ret; + } + + return 0; +} + +static int mmc_test_weird_write(struct mmc_test_card *test) +{ + int ret, i; + + if (!test->card->csd.write_partial) + return RESULT_UNSUP_CARD; + + for (i = 3; i < 512;i += 7) { + ret = mmc_test_verified_transfer(test, 1, + test->buffer, 0, 1, i); + if (ret) + return ret; + } + + return 0; +} + +static int mmc_test_weird_read(struct mmc_test_card *test) +{ + int ret, i; + + if (!test->card->csd.read_partial) + return RESULT_UNSUP_CARD; + + for (i = 3; i < 512;i += 7) { + ret = mmc_test_verified_transfer(test, 0, + test->buffer, 0, 1, i); + if (ret) + return ret; + } + + return 0; +} + +static int mmc_test_align_write(struct mmc_test_card *test) +{ + int ret, i; + + for (i = 1;i < 4;i++) { + ret = mmc_test_verified_transfer(test, 1, test->buffer + i, + 0, 1, 512); + if (ret) + return ret; + } + + return 0; +} + +static int mmc_test_align_read(struct mmc_test_card *test) +{ + int ret, i; + + for (i = 1;i < 4;i++) { + ret = mmc_test_verified_transfer(test, 0, test->buffer + i, + 0, 1, 512); + if (ret) + return ret; + } + + return 0; +} + +static int mmc_test_align_multi_write(struct mmc_test_card *test) +{ + int ret, i; + unsigned int size; + + if (test->card->host->max_blk_count == 1) + return RESULT_UNSUP_HOST; + + size = PAGE_SIZE * 2; + size = min(size, test->card->host->max_req_size); + size = min(size, test->card->host->max_seg_size); + size = min(size, test->card->host->max_blk_count * 512); + + if (size < 1024) + return RESULT_UNSUP_HOST; + + for (i = 1;i < 4;i++) { + ret = mmc_test_verified_transfer(test, 1, test->buffer + i, + 0, size / 512, 512); + if (ret) + return ret; + } + + return 0; +} + +static int mmc_test_align_multi_read(struct mmc_test_card *test) +{ + int ret, i; + unsigned int size; + + if (test->card->host->max_blk_count == 1) + return RESULT_UNSUP_HOST; + + size = PAGE_SIZE * 2; + size = min(size, test->card->host->max_req_size); + size = min(size, test->card->host->max_seg_size); + size = min(size, test->card->host->max_blk_count * 512); + + if (size < 1024) + return RESULT_UNSUP_HOST; + + for (i = 1;i < 4;i++) { + ret = mmc_test_verified_transfer(test, 0, test->buffer + i, + 0, size / 512, 512); + if (ret) + return ret; + } + + return 0; +} + +static int mmc_test_xfersize_write(struct mmc_test_card *test) +{ + int ret; + + ret = mmc_test_set_blksize(test, 512); + if (ret) + return ret; + + ret = __mmc_test_transfer(test, 1, 1, test->buffer, 0, 1, 512); + if (ret) + return ret; + + return 0; +} + +static int mmc_test_xfersize_read(struct mmc_test_card *test) +{ + int ret; + + ret = mmc_test_set_blksize(test, 512); + if (ret) + return ret; + + ret = __mmc_test_transfer(test, 0, 1, test->buffer, 0, 1, 512); + if (ret) + return ret; + + return 0; +} + +static int mmc_test_multi_xfersize_write(struct mmc_test_card *test) +{ + int ret; + + if (test->card->host->max_blk_count == 1) + return RESULT_UNSUP_HOST; + + ret = mmc_test_set_blksize(test, 512); + if (ret) + return ret; + + ret = __mmc_test_transfer(test, 1, 1, test->buffer, 0, 2, 512); + if (ret) + return ret; + + return 0; +} + +static int mmc_test_multi_xfersize_read(struct mmc_test_card *test) +{ + int ret; + + if (test->card->host->max_blk_count == 1) + return RESULT_UNSUP_HOST; + + ret = mmc_test_set_blksize(test, 512); + if (ret) + return ret; + + ret = __mmc_test_transfer(test, 0, 1, test->buffer, 0, 2, 512); + if (ret) + return ret; + + return 0; +} + +static const struct mmc_test_case mmc_test_cases[] = { + { + .name = "Basic write (no data verification)", + .run = mmc_test_basic_write, + }, + + { + .name = "Basic read (no data verification)", + .run = mmc_test_basic_read, + }, + + { + .name = "Basic write (with data verification)", + .prepare = mmc_test_prepare_verify_write, + .run = mmc_test_verify_write, + .cleanup = mmc_test_cleanup_verify, + }, + + { + .name = "Basic read (with data verification)", + .prepare = mmc_test_prepare_verify_read, + .run = mmc_test_verify_read, + .cleanup = mmc_test_cleanup_verify, + }, + + { + .name = "Multi-block write", + .prepare = mmc_test_prepare_verify_write, + .run = mmc_test_multi_write, + .cleanup = mmc_test_cleanup_verify, + }, + + { + .name = "Multi-block read", + .prepare = mmc_test_prepare_verify_read, + .run = mmc_test_multi_read, + .cleanup = mmc_test_cleanup_verify, + }, + + { + .name = "Power of two block writes", + .prepare = mmc_test_prepare_verify_write, + .run = mmc_test_pow2_write, + .cleanup = mmc_test_cleanup_verify, + }, + + { + .name = "Power of two block reads", + .prepare = mmc_test_prepare_verify_read, + .run = mmc_test_pow2_read, + .cleanup = mmc_test_cleanup_verify, + }, + + { + .name = "Weird sized block writes", + .prepare = mmc_test_prepare_verify_write, + .run = mmc_test_weird_write, + .cleanup = mmc_test_cleanup_verify, + }, + + { + .name = "Weird sized block reads", + .prepare = mmc_test_prepare_verify_read, + .run = mmc_test_weird_read, + .cleanup = mmc_test_cleanup_verify, + }, + + { + .name = "Badly aligned write", + .prepare = mmc_test_prepare_verify_write, + .run = mmc_test_align_write, + .cleanup = mmc_test_cleanup_verify, + }, + + { + .name = "Badly aligned read", + .prepare = mmc_test_prepare_verify_read, + .run = mmc_test_align_read, + .cleanup = mmc_test_cleanup_verify, + }, + + { + .name = "Badly aligned multi-block write", + .prepare = mmc_test_prepare_verify_write, + .run = mmc_test_align_multi_write, + .cleanup = mmc_test_cleanup_verify, + }, + + { + .name = "Badly aligned multi-block read", + .prepare = mmc_test_prepare_verify_read, + .run = mmc_test_align_multi_read, + .cleanup = mmc_test_cleanup_verify, + }, + + { + .name = "Correct xfer_size at write (start failure)", + .run = mmc_test_xfersize_write, + }, + + { + .name = "Correct xfer_size at read (start failure)", + .run = mmc_test_xfersize_read, + }, + + { + .name = "Correct xfer_size at write (midway failure)", + .run = mmc_test_multi_xfersize_write, + }, + + { + .name = "Correct xfer_size at read (midway failure)", + .run = mmc_test_multi_xfersize_read, + }, +}; + +static struct mutex mmc_test_lock; + +static void mmc_test_run(struct mmc_test_card *test) +{ + int i, ret; + + printk(KERN_INFO "%s: Starting tests of card %s...\n", + mmc_hostname(test->card->host), mmc_card_id(test->card)); + + mmc_claim_host(test->card->host); + + for (i = 0;i < ARRAY_SIZE(mmc_test_cases);i++) { + printk(KERN_INFO "%s: Test case %d. %s...\n", + mmc_hostname(test->card->host), i + 1, + mmc_test_cases[i].name); + + if (mmc_test_cases[i].prepare) { + ret = mmc_test_cases[i].prepare(test); + if (ret) { + printk(KERN_INFO "%s: Result: Prepare " + "stage failed! (%d)\n", + mmc_hostname(test->card->host), + ret); + continue; + } + } + + ret = mmc_test_cases[i].run(test); + switch (ret) { + case RESULT_OK: + printk(KERN_INFO "%s: Result: OK\n", + mmc_hostname(test->card->host)); + break; + case RESULT_FAIL: + printk(KERN_INFO "%s: Result: FAILED\n", + mmc_hostname(test->card->host)); + break; + case RESULT_UNSUP_HOST: + printk(KERN_INFO "%s: Result: UNSUPPORTED " + "(by host)\n", + mmc_hostname(test->card->host)); + break; + case RESULT_UNSUP_CARD: + printk(KERN_INFO "%s: Result: UNSUPPORTED " + "(by card)\n", + mmc_hostname(test->card->host)); + break; + default: + printk(KERN_INFO "%s: Result: ERROR (%d)\n", + mmc_hostname(test->card->host), ret); + } + + if (mmc_test_cases[i].cleanup) { + ret = mmc_test_cases[i].cleanup(test); + if (ret) { + printk(KERN_INFO "%s: Warning: Cleanup " + "stage failed! (%d)\n", + mmc_hostname(test->card->host), + ret); + } + } + } + + mmc_release_host(test->card->host); + + printk(KERN_INFO "%s: Tests completed.\n", + mmc_hostname(test->card->host)); +} + +static ssize_t mmc_test_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + mutex_lock(&mmc_test_lock); + mutex_unlock(&mmc_test_lock); + + return 0; +} + +static ssize_t mmc_test_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct mmc_card *card; + struct mmc_test_card *test; + + card = container_of(dev, struct mmc_card, dev); + + test = kzalloc(sizeof(struct mmc_test_card), GFP_KERNEL); + if (!test) + return -ENOMEM; + + test->card = card; + + test->buffer = kzalloc(BUFFER_SIZE, GFP_KERNEL); + if (test->buffer) { + mutex_lock(&mmc_test_lock); + mmc_test_run(test); + mutex_unlock(&mmc_test_lock); + } + + kfree(test->buffer); + kfree(test); + + return count; +} + +static DEVICE_ATTR(test, S_IWUSR | S_IRUGO, mmc_test_show, mmc_test_store); + +static int mmc_test_probe(struct mmc_card *card) +{ + int ret; + + mutex_init(&mmc_test_lock); + + ret = device_create_file(&card->dev, &dev_attr_test); + if (ret) + return ret; + + return 0; +} + +static void mmc_test_remove(struct mmc_card *card) +{ + device_remove_file(&card->dev, &dev_attr_test); +} + +static struct mmc_driver mmc_driver = { + .drv = { + .name = "mmc_test", + }, + .probe = mmc_test_probe, + .remove = mmc_test_remove, +}; + +static int __init mmc_test_init(void) +{ + return mmc_register_driver(&mmc_driver); +} + +static void __exit mmc_test_exit(void) +{ + mmc_unregister_driver(&mmc_driver); +} + +module_init(mmc_test_init); +module_exit(mmc_test_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Multimedia Card (MMC) host test driver"); +MODULE_AUTHOR("Pierre Ossman"); diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 3b3cd0e74715..dead61754ad7 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -119,7 +119,7 @@ config MMC_TIFM_SD config MMC_SPI tristate "MMC/SD over SPI" - depends on MMC && SPI_MASTER && !HIGHMEM + depends on MMC && SPI_MASTER && !HIGHMEM && HAS_DMA select CRC7 select CRC_ITU_T help diff --git a/drivers/mmc/host/at91_mci.c b/drivers/mmc/host/at91_mci.c index a28fc2f68ce2..8979ad330a4d 100644 --- a/drivers/mmc/host/at91_mci.c +++ b/drivers/mmc/host/at91_mci.c @@ -663,9 +663,12 @@ static void at91_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) gpio_set_value(host->board->vcc_pin, 0); break; case MMC_POWER_UP: - case MMC_POWER_ON: gpio_set_value(host->board->vcc_pin, 1); break; + case MMC_POWER_ON: + break; + default: + WARN_ON(1); } } } diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index 14759e9f42ad..549517c35675 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c @@ -1003,7 +1003,7 @@ static void mmc_omap_dma_cb(int lch, u16 ch_status, void *data) static int mmc_omap_get_dma_channel(struct mmc_omap_host *host, struct mmc_data *data) { - const char *dev_name; + const char *dma_dev_name; int sync_dev, dma_ch, is_read, r; is_read = !(data->flags & MMC_DATA_WRITE); @@ -1018,21 +1018,21 @@ static int mmc_omap_get_dma_channel(struct mmc_omap_host *host, struct mmc_data if (is_read) { if (host->id == 1) { sync_dev = OMAP_DMA_MMC_RX; - dev_name = "MMC1 read"; + dma_dev_name = "MMC1 read"; } else { sync_dev = OMAP_DMA_MMC2_RX; - dev_name = "MMC2 read"; + dma_dev_name = "MMC2 read"; } } else { if (host->id == 1) { sync_dev = OMAP_DMA_MMC_TX; - dev_name = "MMC1 write"; + dma_dev_name = "MMC1 write"; } else { sync_dev = OMAP_DMA_MMC2_TX; - dev_name = "MMC2 write"; + dma_dev_name = "MMC2 write"; } } - r = omap_request_dma(sync_dev, dev_name, mmc_omap_dma_cb, + r = omap_request_dma(sync_dev, dma_dev_name, mmc_omap_dma_cb, host, &dma_ch); if (r != 0) { dev_dbg(mmc_dev(host->mmc), "omap_request_dma() failed with %d\n", r); diff --git a/drivers/mtd/maps/ck804xrom.c b/drivers/mtd/maps/ck804xrom.c index 59d8fb49270a..effaf7cdefab 100644 --- a/drivers/mtd/maps/ck804xrom.c +++ b/drivers/mtd/maps/ck804xrom.c @@ -331,15 +331,15 @@ static void __devexit ck804xrom_remove_one (struct pci_dev *pdev) } static struct pci_device_id ck804xrom_pci_tbl[] = { - { PCI_VENDOR_ID_NVIDIA, 0x0051, PCI_ANY_ID, PCI_ANY_ID, DEV_CK804 }, - { PCI_VENDOR_ID_NVIDIA, 0x0360, PCI_ANY_ID, PCI_ANY_ID, DEV_MCP55 }, - { PCI_VENDOR_ID_NVIDIA, 0x0361, PCI_ANY_ID, PCI_ANY_ID, DEV_MCP55 }, - { PCI_VENDOR_ID_NVIDIA, 0x0362, PCI_ANY_ID, PCI_ANY_ID, DEV_MCP55 }, - { PCI_VENDOR_ID_NVIDIA, 0x0363, PCI_ANY_ID, PCI_ANY_ID, DEV_MCP55 }, - { PCI_VENDOR_ID_NVIDIA, 0x0364, PCI_ANY_ID, PCI_ANY_ID, DEV_MCP55 }, - { PCI_VENDOR_ID_NVIDIA, 0x0365, PCI_ANY_ID, PCI_ANY_ID, DEV_MCP55 }, - { PCI_VENDOR_ID_NVIDIA, 0x0366, PCI_ANY_ID, PCI_ANY_ID, DEV_MCP55 }, - { PCI_VENDOR_ID_NVIDIA, 0x0367, PCI_ANY_ID, PCI_ANY_ID, DEV_MCP55 }, + { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, 0x0051), .driver_data = DEV_CK804 }, + { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, 0x0360), .driver_data = DEV_MCP55 }, + { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, 0x0361), .driver_data = DEV_MCP55 }, + { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, 0x0362), .driver_data = DEV_MCP55 }, + { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, 0x0363), .driver_data = DEV_MCP55 }, + { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, 0x0364), .driver_data = DEV_MCP55 }, + { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, 0x0365), .driver_data = DEV_MCP55 }, + { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, 0x0366), .driver_data = DEV_MCP55 }, + { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, 0x0367), .driver_data = DEV_MCP55 }, { 0, } }; diff --git a/drivers/net/82596.c b/drivers/net/82596.c index 2797da7eeee6..da292e647eb1 100644 --- a/drivers/net/82596.c +++ b/drivers/net/82596.c @@ -1162,6 +1162,7 @@ struct net_device * __init i82596_probe(int unit) memcpy(eth_addr, (void *) 0xfffc1f2c, 6); /* YUCK! Get addr from NOVRAM */ dev->base_addr = MVME_I596_BASE; dev->irq = (unsigned) MVME16x_IRQ_I596; + goto found; } #endif #ifdef ENABLE_BVME6000_NET @@ -1176,6 +1177,7 @@ struct net_device * __init i82596_probe(int unit) rtc[3] = msr; dev->base_addr = BVME_I596_BASE; dev->irq = (unsigned) BVME_IRQ_I596; + goto found; } #endif #ifdef ENABLE_APRICOT @@ -1212,8 +1214,13 @@ struct net_device * __init i82596_probe(int unit) } dev->irq = 10; + goto found; } #endif + err = -ENODEV; + goto out; + +found: dev->mem_start = (int)__get_free_pages(GFP_ATOMIC, 0); if (!dev->mem_start) { err = -ENOMEM; diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 654a78c31087..c537f53ffcb9 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -1353,7 +1353,7 @@ config APRICOT config B44 tristate "Broadcom 440x/47xx ethernet support" - depends on SSB_POSSIBLE + depends on SSB_POSSIBLE && HAS_DMA select SSB select MII help diff --git a/drivers/net/apne.c b/drivers/net/apne.c index 47a8275d3962..867f6fff543c 100644 --- a/drivers/net/apne.c +++ b/drivers/net/apne.c @@ -127,6 +127,9 @@ struct net_device * __init apne_probe(int unit) #endif int err; + if (!MACH_IS_AMIGA) + return ERR_PTR(-ENODEV); + if (apne_owned) return ERR_PTR(-ENODEV); diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c index db04bfb3460f..32dc391e63cc 100644 --- a/drivers/net/atlx/atl1.c +++ b/drivers/net/atlx/atl1.c @@ -2024,6 +2024,7 @@ rrd_ok: /* Good Receive */ pci_unmap_page(adapter->pdev, buffer_info->dma, buffer_info->length, PCI_DMA_FROMDEVICE); + buffer_info->dma = 0; skb = buffer_info->skb; length = le16_to_cpu(rrd->xsz.xsum_sz.pkt_size); diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c index 348371fda597..fba87abe78ee 100644 --- a/drivers/net/cs89x0.c +++ b/drivers/net/cs89x0.c @@ -1394,7 +1394,11 @@ net_open(struct net_device *dev) #endif if (!result) { printk(KERN_ERR "%s: EEPROM is configured for unavailable media\n", dev->name); - release_irq: +release_dma: +#if ALLOW_DMA + free_dma(dev->dma); +#endif +release_irq: #if ALLOW_DMA release_dma_buff(lp); #endif @@ -1442,12 +1446,12 @@ net_open(struct net_device *dev) if ((result = detect_bnc(dev)) != DETECTED_NONE) break; printk(KERN_ERR "%s: no media detected\n", dev->name); - goto release_irq; + goto release_dma; } switch(result) { case DETECTED_NONE: printk(KERN_ERR "%s: no network cable attached to configured media\n", dev->name); - goto release_irq; + goto release_dma; case DETECTED_RJ45H: printk(KERN_INFO "%s: using half-duplex 10Base-T (RJ-45)\n", dev->name); break; diff --git a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig index ce816ba9c40d..e6317557a531 100644 --- a/drivers/net/irda/Kconfig +++ b/drivers/net/irda/Kconfig @@ -329,6 +329,7 @@ config PXA_FICP config MCS_FIR tristate "MosChip MCS7780 IrDA-USB dongle" depends on IRDA && USB && EXPERIMENTAL + select CRC32 help Say Y or M here if you want to build support for the MosChip MCS7780 IrDA-USB bridge device driver. diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c index 9081234ab458..6f50ed7b183f 100644 --- a/drivers/net/irda/irda-usb.c +++ b/drivers/net/irda/irda-usb.c @@ -1120,7 +1120,7 @@ static int stir421x_patch_device(struct irda_usb_cb *self) } } - if (self->usbdev->descriptor.bcdDevice == fw_version) { + if (self->usbdev->descriptor.bcdDevice == cpu_to_le16(fw_version)) { /* * If we're here, we've found a correct patch * The actual image starts after the "STMP" keyword diff --git a/drivers/net/irda/irda-usb.h b/drivers/net/irda/irda-usb.h index e846c38224a3..a0ca9c1fe196 100644 --- a/drivers/net/irda/irda-usb.h +++ b/drivers/net/irda/irda-usb.h @@ -117,11 +117,11 @@ struct irda_class_desc { __u8 bLength; __u8 bDescriptorType; - __u16 bcdSpecRevision; + __le16 bcdSpecRevision; __u8 bmDataSize; __u8 bmWindowSize; __u8 bmMinTurnaroundTime; - __u16 wBaudRate; + __le16 wBaudRate; __u8 bmAdditionalBOFs; __u8 bIrdaRateSniff; __u8 bMaxUnicastList; diff --git a/drivers/net/mac89x0.c b/drivers/net/mac89x0.c index 2a66e5b7cebc..4ce8afd481c3 100644 --- a/drivers/net/mac89x0.c +++ b/drivers/net/mac89x0.c @@ -183,6 +183,9 @@ struct net_device * __init mac89x0_probe(int unit) int err = -ENODEV; DECLARE_MAC_BUF(mac); + if (!MACH_IS_MAC) + return ERR_PTR(-ENODEV); + dev = alloc_etherdev(sizeof(struct net_local)); if (!dev) return ERR_PTR(-ENOMEM); diff --git a/drivers/net/macmace.c b/drivers/net/macmace.c index 18770527df99..51ad3765e075 100644 --- a/drivers/net/macmace.c +++ b/drivers/net/macmace.c @@ -781,6 +781,9 @@ static int __init mac_mace_init_module(void) { int err; + if (!MACH_IS_MAC) + return -ENODEV; + if ((err = platform_driver_register(&mac_mace_driver))) { printk(KERN_ERR "Driver registration failed\n"); return err; diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index 93007d38df57..9a68d2ea5f3e 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -76,7 +76,7 @@ #include "myri10ge_mcp.h" #include "myri10ge_mcp_gen_header.h" -#define MYRI10GE_VERSION_STR "1.3.2-1.287" +#define MYRI10GE_VERSION_STR "1.3.99-1.347" MODULE_DESCRIPTION("Myricom 10G driver (10GbE)"); MODULE_AUTHOR("Maintainer: help@myri.com"); diff --git a/drivers/net/pppol2tp.c b/drivers/net/pppol2tp.c index 8db342f2fdc9..70cfdb46aa27 100644 --- a/drivers/net/pppol2tp.c +++ b/drivers/net/pppol2tp.c @@ -240,12 +240,15 @@ static inline struct pppol2tp_session *pppol2tp_sock_to_session(struct sock *sk) if (sk == NULL) return NULL; + sock_hold(sk); session = (struct pppol2tp_session *)(sk->sk_user_data); - if (session == NULL) - return NULL; + if (session == NULL) { + sock_put(sk); + goto out; + } BUG_ON(session->magic != L2TP_SESSION_MAGIC); - +out: return session; } @@ -256,12 +259,15 @@ static inline struct pppol2tp_tunnel *pppol2tp_sock_to_tunnel(struct sock *sk) if (sk == NULL) return NULL; + sock_hold(sk); tunnel = (struct pppol2tp_tunnel *)(sk->sk_user_data); - if (tunnel == NULL) - return NULL; + if (tunnel == NULL) { + sock_put(sk); + goto out; + } BUG_ON(tunnel->magic != L2TP_TUNNEL_MAGIC); - +out: return tunnel; } @@ -716,12 +722,14 @@ discard: session->stats.rx_errors++; kfree_skb(skb); sock_put(session->sock); + sock_put(sock); return 0; error: /* Put UDP header back */ __skb_push(skb, sizeof(struct udphdr)); + sock_put(sock); no_tunnel: return 1; @@ -745,10 +753,13 @@ static int pppol2tp_udp_encap_recv(struct sock *sk, struct sk_buff *skb) "%s: received %d bytes\n", tunnel->name, skb->len); if (pppol2tp_recv_core(sk, skb)) - goto pass_up; + goto pass_up_put; + sock_put(sk); return 0; +pass_up_put: + sock_put(sk); pass_up: return 1; } @@ -858,7 +869,7 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh tunnel = pppol2tp_sock_to_tunnel(session->tunnel_sock); if (tunnel == NULL) - goto error; + goto error_put_sess; /* What header length is configured for this session? */ hdr_len = pppol2tp_l2tp_header_len(session); @@ -870,7 +881,7 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh sizeof(ppph) + total_len, 0, GFP_KERNEL); if (!skb) - goto error; + goto error_put_sess_tun; /* Reserve space for headers. */ skb_reserve(skb, NET_SKB_PAD); @@ -900,7 +911,7 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh error = memcpy_fromiovec(skb->data, m->msg_iov, total_len); if (error < 0) { kfree_skb(skb); - goto error; + goto error_put_sess_tun; } skb_put(skb, total_len); @@ -947,10 +958,33 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh session->stats.tx_errors++; } + return error; + +error_put_sess_tun: + sock_put(session->tunnel_sock); +error_put_sess: + sock_put(sk); error: return error; } +/* Automatically called when the skb is freed. + */ +static void pppol2tp_sock_wfree(struct sk_buff *skb) +{ + sock_put(skb->sk); +} + +/* For data skbs that we transmit, we associate with the tunnel socket + * but don't do accounting. + */ +static inline void pppol2tp_skb_set_owner_w(struct sk_buff *skb, struct sock *sk) +{ + sock_hold(sk); + skb->sk = sk; + skb->destructor = pppol2tp_sock_wfree; +} + /* Transmit function called by generic PPP driver. Sends PPP frame * over PPPoL2TP socket. * @@ -993,10 +1027,10 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) sk_tun = session->tunnel_sock; if (sk_tun == NULL) - goto abort; + goto abort_put_sess; tunnel = pppol2tp_sock_to_tunnel(sk_tun); if (tunnel == NULL) - goto abort; + goto abort_put_sess; /* What header length is configured for this session? */ hdr_len = pppol2tp_l2tp_header_len(session); @@ -1009,7 +1043,7 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) sizeof(struct udphdr) + hdr_len + sizeof(ppph); old_headroom = skb_headroom(skb); if (skb_cow_head(skb, headroom)) - goto abort; + goto abort_put_sess_tun; new_headroom = skb_headroom(skb); skb_orphan(skb); @@ -1069,7 +1103,7 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) /* Get routing info from the tunnel socket */ dst_release(skb->dst); skb->dst = dst_clone(__sk_dst_get(sk_tun)); - skb->sk = sk_tun; + pppol2tp_skb_set_owner_w(skb, sk_tun); /* Queue the packet to IP for output */ len = skb->len; @@ -1086,8 +1120,14 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) session->stats.tx_errors++; } + sock_put(sk_tun); + sock_put(sk); return 1; +abort_put_sess_tun: + sock_put(sk_tun); +abort_put_sess: + sock_put(sk); abort: /* Free the original skb */ kfree_skb(skb); @@ -1191,7 +1231,7 @@ static void pppol2tp_tunnel_destruct(struct sock *sk) { struct pppol2tp_tunnel *tunnel; - tunnel = pppol2tp_sock_to_tunnel(sk); + tunnel = sk->sk_user_data; if (tunnel == NULL) goto end; @@ -1230,10 +1270,12 @@ static void pppol2tp_session_destruct(struct sock *sk) if (sk->sk_user_data != NULL) { struct pppol2tp_tunnel *tunnel; - session = pppol2tp_sock_to_session(sk); + session = sk->sk_user_data; if (session == NULL) goto out; + BUG_ON(session->magic != L2TP_SESSION_MAGIC); + /* Don't use pppol2tp_sock_to_tunnel() here to * get the tunnel context because the tunnel * socket might have already been closed (its @@ -1279,6 +1321,7 @@ out: static int pppol2tp_release(struct socket *sock) { struct sock *sk = sock->sk; + struct pppol2tp_session *session; int error; if (!sk) @@ -1296,9 +1339,18 @@ static int pppol2tp_release(struct socket *sock) sock_orphan(sk); sock->sk = NULL; + session = pppol2tp_sock_to_session(sk); + /* Purge any queued data */ skb_queue_purge(&sk->sk_receive_queue); skb_queue_purge(&sk->sk_write_queue); + if (session != NULL) { + struct sk_buff *skb; + while ((skb = skb_dequeue(&session->reorder_q))) { + kfree_skb(skb); + sock_put(sk); + } + } release_sock(sk); @@ -1601,7 +1653,7 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr, error = ppp_register_channel(&po->chan); if (error) - goto end; + goto end_put_tun; /* This is how we get the session context from the socket. */ sk->sk_user_data = session; @@ -1621,6 +1673,8 @@ out_no_ppp: PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO, "%s: created\n", session->name); +end_put_tun: + sock_put(tunnel_sock); end: release_sock(sk); @@ -1668,6 +1722,7 @@ static int pppol2tp_getname(struct socket *sock, struct sockaddr *uaddr, *usockaddr_len = len; error = 0; + sock_put(sock->sk); end: return error; @@ -1906,14 +1961,17 @@ static int pppol2tp_ioctl(struct socket *sock, unsigned int cmd, err = -EBADF; tunnel = pppol2tp_sock_to_tunnel(session->tunnel_sock); if (tunnel == NULL) - goto end; + goto end_put_sess; err = pppol2tp_tunnel_ioctl(tunnel, cmd, arg); - goto end; + sock_put(session->tunnel_sock); + goto end_put_sess; } err = pppol2tp_session_ioctl(session, cmd, arg); +end_put_sess: + sock_put(sk); end: return err; } @@ -2059,14 +2117,17 @@ static int pppol2tp_setsockopt(struct socket *sock, int level, int optname, err = -EBADF; tunnel = pppol2tp_sock_to_tunnel(session->tunnel_sock); if (tunnel == NULL) - goto end; + goto end_put_sess; err = pppol2tp_tunnel_setsockopt(sk, tunnel, optname, val); + sock_put(session->tunnel_sock); } else err = pppol2tp_session_setsockopt(sk, session, optname, val); err = 0; +end_put_sess: + sock_put(sk); end: return err; } @@ -2181,20 +2242,24 @@ static int pppol2tp_getsockopt(struct socket *sock, int level, err = -EBADF; tunnel = pppol2tp_sock_to_tunnel(session->tunnel_sock); if (tunnel == NULL) - goto end; + goto end_put_sess; err = pppol2tp_tunnel_getsockopt(sk, tunnel, optname, &val); + sock_put(session->tunnel_sock); } else err = pppol2tp_session_getsockopt(sk, session, optname, &val); err = -EFAULT; if (put_user(len, (int __user *) optlen)) - goto end; + goto end_put_sess; if (copy_to_user((void __user *) optval, &val, len)) - goto end; + goto end_put_sess; err = 0; + +end_put_sess: + sock_put(sk); end: return err; } diff --git a/drivers/net/sc92031.c b/drivers/net/sc92031.c index b4b63805ee8f..61955f8d8011 100644 --- a/drivers/net/sc92031.c +++ b/drivers/net/sc92031.c @@ -972,7 +972,7 @@ static int sc92031_start_xmit(struct sk_buff *skb, struct net_device *dev) skb_copy_and_csum_dev(skb, priv->tx_bufs + entry * TX_BUF_SIZE); len = skb->len; - if (unlikely(len < ETH_ZLEN)) { + if (len < ETH_ZLEN) { memset(priv->tx_bufs + entry * TX_BUF_SIZE + len, 0, ETH_ZLEN - len); len = ETH_ZLEN; diff --git a/drivers/net/sfc/falcon_xmac.c b/drivers/net/sfc/falcon_xmac.c index dbdcee4b0f8d..55c0d9760be8 100644 --- a/drivers/net/sfc/falcon_xmac.c +++ b/drivers/net/sfc/falcon_xmac.c @@ -459,7 +459,7 @@ static int falcon_check_xaui_link_up(struct efx_nic *efx) tries--; } - EFX_ERR(efx, "Failed to bring XAUI link back up in %d tries!\n", + EFX_LOG(efx, "Failed to bring XAUI link back up in %d tries!\n", max_tries); return 0; } diff --git a/drivers/net/sun3lance.c b/drivers/net/sun3lance.c index f8d46134daca..359452a06c67 100644 --- a/drivers/net/sun3lance.c +++ b/drivers/net/sun3lance.c @@ -250,6 +250,9 @@ struct net_device * __init sun3lance_probe(int unit) static int found; int err = -ENODEV; + if (!MACH_IS_SUN3 && !MACH_IS_SUN3X) + return ERR_PTR(-ENODEV); + /* check that this machine has an onboard lance */ switch(idprom->id_machtype) { case SM_SUN3|SM_3_50: diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index b4e7f30ea4e8..1aa425be3067 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -111,7 +111,7 @@ static __inline__ void tx_add_log(struct happy_meal *hp, unsigned int a, unsigne struct hme_tx_logent *tlp; unsigned long flags; - save_and_cli(flags); + local_irq_save(flags); tlp = &tx_log[txlog_cur_entry]; tlp->tstamp = (unsigned int)jiffies; tlp->tx_new = hp->tx_new; @@ -119,7 +119,7 @@ static __inline__ void tx_add_log(struct happy_meal *hp, unsigned int a, unsigne tlp->action = a; tlp->status = s; txlog_cur_entry = (txlog_cur_entry + 1) & (TX_LOG_LEN - 1); - restore_flags(flags); + local_irq_restore(flags); } static __inline__ void tx_dump_log(void) { diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index d9f248f23b97..633c128a6228 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -1828,6 +1828,21 @@ static void tg3_frob_aux_power(struct tg3 *tp) GRC_LCLCTRL_GPIO_OUTPUT0 | GRC_LCLCTRL_GPIO_OUTPUT1), 100); + } else if (tp->pdev->device == PCI_DEVICE_ID_TIGON3_5761) { + /* The 5761 non-e device swaps GPIO 0 and GPIO 2. */ + u32 grc_local_ctrl = GRC_LCLCTRL_GPIO_OE0 | + GRC_LCLCTRL_GPIO_OE1 | + GRC_LCLCTRL_GPIO_OE2 | + GRC_LCLCTRL_GPIO_OUTPUT0 | + GRC_LCLCTRL_GPIO_OUTPUT1 | + tp->grc_local_ctrl; + tw32_wait_f(GRC_LOCAL_CTRL, grc_local_ctrl, 100); + + grc_local_ctrl |= GRC_LCLCTRL_GPIO_OUTPUT2; + tw32_wait_f(GRC_LOCAL_CTRL, grc_local_ctrl, 100); + + grc_local_ctrl &= ~GRC_LCLCTRL_GPIO_OUTPUT0; + tw32_wait_f(GRC_LOCAL_CTRL, grc_local_ctrl, 100); } else { u32 no_gpio2; u32 grc_local_ctrl = 0; @@ -3534,8 +3549,7 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset) err |= tg3_readphy(tp, MII_BMCR, &bmcr); if ((tp->link_config.autoneg == AUTONEG_ENABLE) && !force_reset && - (tp->tg3_flags2 & TG3_FLG2_PARALLEL_DETECT) && - tp->link_config.flowctrl == tp->link_config.active_flowctrl) { + (tp->tg3_flags2 & TG3_FLG2_PARALLEL_DETECT)) { /* do nothing, just check for link up at the end */ } else if (tp->link_config.autoneg == AUTONEG_ENABLE) { u32 adv, new_adv; @@ -9008,7 +9022,7 @@ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) (cmd->speed == SPEED_1000)) return -EINVAL; else if ((cmd->speed == SPEED_1000) && - (tp->tg3_flags2 & TG3_FLAG_10_100_ONLY)) + (tp->tg3_flags & TG3_FLAG_10_100_ONLY)) return -EINVAL; tg3_full_lock(tp, 0); @@ -12275,6 +12289,15 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755) tp->grc_local_ctrl |= GRC_LCLCTRL_GPIO_UART_SEL; + if (tp->pdev->device == PCI_DEVICE_ID_TIGON3_5761) { + /* Turn off the debug UART. */ + tp->grc_local_ctrl |= GRC_LCLCTRL_GPIO_UART_SEL; + if (tp->tg3_flags2 & TG3_FLG2_IS_NIC) + /* Keep VMain power. */ + tp->grc_local_ctrl |= GRC_LCLCTRL_GPIO_OE0 | + GRC_LCLCTRL_GPIO_OUTPUT0; + } + /* Force the chip into D0. */ err = tg3_set_power_state(tp, PCI_D0); if (err) { diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index f9d13fa05d64..55670b5eb611 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -1729,12 +1729,15 @@ static int tulip_suspend (struct pci_dev *pdev, pm_message_t state) if (!dev) return -EINVAL; - if (netif_running(dev)) - tulip_down(dev); + if (!netif_running(dev)) + goto save_state; + + tulip_down(dev); netif_device_detach(dev); free_irq(dev->irq, dev); +save_state: pci_save_state(pdev); pci_disable_device(pdev); pci_set_power_state(pdev, pci_choose_state(pdev, state)); @@ -1754,6 +1757,9 @@ static int tulip_resume(struct pci_dev *pdev) pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); + if (!netif_running(dev)) + return 0; + if ((retval = pci_enable_device(pdev))) { printk (KERN_ERR "tulip: pci_enable_device failed in resume\n"); return retval; diff --git a/drivers/net/ucc_geth_ethtool.c b/drivers/net/ucc_geth_ethtool.c index 5f176f2b1c17..cfbbfee55836 100644 --- a/drivers/net/ucc_geth_ethtool.c +++ b/drivers/net/ucc_geth_ethtool.c @@ -73,6 +73,7 @@ static char tx_fw_stat_gstrings[][ETH_GSTRING_LEN] = { "tx-frames-ok", "tx-excessive-differ-frames", "tx-256-511-frames", + "tx-512-1023-frames", "tx-1024-1518-frames", "tx-jumbo-frames", }; @@ -308,7 +309,7 @@ static void uec_get_strings(struct net_device *netdev, u32 stringset, u8 *buf) buf += UEC_TX_FW_STATS_LEN * ETH_GSTRING_LEN; } if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_RX) - memcpy(buf, tx_fw_stat_gstrings, UEC_RX_FW_STATS_LEN * + memcpy(buf, rx_fw_stat_gstrings, UEC_RX_FW_STATS_LEN * ETH_GSTRING_LEN); } diff --git a/drivers/net/usb/cdc_subset.c b/drivers/net/usb/cdc_subset.c index 0ec7936cbe21..c66b9c324f54 100644 --- a/drivers/net/usb/cdc_subset.c +++ b/drivers/net/usb/cdc_subset.c @@ -218,7 +218,7 @@ static const struct driver_info blob_info = { /*-------------------------------------------------------------------------*/ #ifndef HAVE_HARDWARE -#error You need to configure some hardware for this driver +#warning You need to configure some hardware for this driver #endif /* diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index fe7cdf2a2a23..5450eac9e263 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -47,6 +47,9 @@ struct virtnet_info /* Number of input buffers, and max we've ever had. */ unsigned int num, max; + /* For cleaning up after transmission. */ + struct tasklet_struct tasklet; + /* Receive & send queues. */ struct sk_buff_head recv; struct sk_buff_head send; @@ -68,8 +71,13 @@ static void skb_xmit_done(struct virtqueue *svq) /* Suppress further interrupts. */ svq->vq_ops->disable_cb(svq); + /* We were waiting for more output buffers. */ netif_wake_queue(vi->dev); + + /* Make sure we re-xmit last_xmit_skb: if there are no more packets + * queued, start_xmit won't be called. */ + tasklet_schedule(&vi->tasklet); } static void receive_skb(struct net_device *dev, struct sk_buff *skb, @@ -278,6 +286,18 @@ static int xmit_skb(struct virtnet_info *vi, struct sk_buff *skb) return vi->svq->vq_ops->add_buf(vi->svq, sg, num, 0, skb); } +static void xmit_tasklet(unsigned long data) +{ + struct virtnet_info *vi = (void *)data; + + netif_tx_lock_bh(vi->dev); + if (vi->last_xmit_skb && xmit_skb(vi, vi->last_xmit_skb) == 0) { + vi->svq->vq_ops->kick(vi->svq); + vi->last_xmit_skb = NULL; + } + netif_tx_unlock_bh(vi->dev); +} + static int start_xmit(struct sk_buff *skb, struct net_device *dev) { struct virtnet_info *vi = netdev_priv(dev); @@ -287,21 +307,25 @@ again: free_old_xmit_skbs(vi); /* If we has a buffer left over from last time, send it now. */ - if (vi->last_xmit_skb) { + if (unlikely(vi->last_xmit_skb)) { if (xmit_skb(vi, vi->last_xmit_skb) != 0) { /* Drop this skb: we only queue one. */ vi->dev->stats.tx_dropped++; kfree_skb(skb); + skb = NULL; goto stop_queue; } vi->last_xmit_skb = NULL; } /* Put new one in send queue and do transmit */ - __skb_queue_head(&vi->send, skb); - if (xmit_skb(vi, skb) != 0) { - vi->last_xmit_skb = skb; - goto stop_queue; + if (likely(skb)) { + __skb_queue_head(&vi->send, skb); + if (xmit_skb(vi, skb) != 0) { + vi->last_xmit_skb = skb; + skb = NULL; + goto stop_queue; + } } done: vi->svq->vq_ops->kick(vi->svq); @@ -428,6 +452,8 @@ static int virtnet_probe(struct virtio_device *vdev) skb_queue_head_init(&vi->recv); skb_queue_head_init(&vi->send); + tasklet_init(&vi->tasklet, xmit_tasklet, (unsigned long)vi); + err = register_netdev(dev); if (err) { pr_debug("virtio_net: registering device failed\n"); diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 17ced37e55ed..1e1446bf4b48 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -2906,7 +2906,7 @@ EXPORT_SYMBOL(init_airo_card); static int waitbusy (struct airo_info *ai) { int delay = 0; - while ((IN4500 (ai, COMMAND) & COMMAND_BUSY) && (delay < 10000)) { + while ((IN4500(ai, COMMAND) & COMMAND_BUSY) && (delay < 10000)) { udelay (10); if ((++delay % 20) == 0) OUT4500(ai, EVACK, EV_CLEARCOMMANDBUSY); diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c index f978a9d5190b..7bb2646ae0ef 100644 --- a/drivers/net/wireless/atmel.c +++ b/drivers/net/wireless/atmel.c @@ -47,6 +47,7 @@ #include <linux/string.h> #include <linux/ctype.h> #include <linux/timer.h> +#include <asm/byteorder.h> #include <asm/io.h> #include <asm/system.h> #include <asm/uaccess.h> @@ -60,7 +61,6 @@ #include <linux/delay.h> #include <linux/wireless.h> #include <net/iw_handler.h> -#include <linux/byteorder/generic.h> #include <linux/crc32.h> #include <linux/proc_fs.h> #include <linux/device.h> diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig index f51b2d9b085b..1fa043d1802c 100644 --- a/drivers/net/wireless/b43/Kconfig +++ b/drivers/net/wireless/b43/Kconfig @@ -1,6 +1,6 @@ config B43 tristate "Broadcom 43xx wireless support (mac80211 stack)" - depends on SSB_POSSIBLE && MAC80211 && WLAN_80211 + depends on SSB_POSSIBLE && MAC80211 && WLAN_80211 && HAS_DMA select SSB select FW_LOADER select HW_RANDOM diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index e919189919bb..239e71c3d1b1 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -755,6 +755,7 @@ struct b43_wl { struct sk_buff *current_beacon; bool beacon0_uploaded; bool beacon1_uploaded; + bool beacon_templates_virgin; /* Never wrote the templates? */ struct work_struct beacon_update_trigger; /* The current QOS parameters for the 4 queues. diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index f9c14c66434e..1e31e0bca744 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -1550,6 +1550,30 @@ static void b43_write_probe_resp_template(struct b43_wldev *dev, kfree(probe_resp_data); } +static void b43_upload_beacon0(struct b43_wldev *dev) +{ + struct b43_wl *wl = dev->wl; + + if (wl->beacon0_uploaded) + return; + b43_write_beacon_template(dev, 0x68, 0x18); + /* FIXME: Probe resp upload doesn't really belong here, + * but we don't use that feature anyway. */ + b43_write_probe_resp_template(dev, 0x268, 0x4A, + &__b43_ratetable[3]); + wl->beacon0_uploaded = 1; +} + +static void b43_upload_beacon1(struct b43_wldev *dev) +{ + struct b43_wl *wl = dev->wl; + + if (wl->beacon1_uploaded) + return; + b43_write_beacon_template(dev, 0x468, 0x1A); + wl->beacon1_uploaded = 1; +} + static void handle_irq_beacon(struct b43_wldev *dev) { struct b43_wl *wl = dev->wl; @@ -1575,24 +1599,27 @@ static void handle_irq_beacon(struct b43_wldev *dev) return; } - if (!beacon0_valid) { - if (!wl->beacon0_uploaded) { - b43_write_beacon_template(dev, 0x68, 0x18); - b43_write_probe_resp_template(dev, 0x268, 0x4A, - &__b43_ratetable[3]); - wl->beacon0_uploaded = 1; - } + if (unlikely(wl->beacon_templates_virgin)) { + /* We never uploaded a beacon before. + * Upload both templates now, but only mark one valid. */ + wl->beacon_templates_virgin = 0; + b43_upload_beacon0(dev); + b43_upload_beacon1(dev); cmd = b43_read32(dev, B43_MMIO_MACCMD); cmd |= B43_MACCMD_BEACON0_VALID; b43_write32(dev, B43_MMIO_MACCMD, cmd); - } else if (!beacon1_valid) { - if (!wl->beacon1_uploaded) { - b43_write_beacon_template(dev, 0x468, 0x1A); - wl->beacon1_uploaded = 1; + } else { + if (!beacon0_valid) { + b43_upload_beacon0(dev); + cmd = b43_read32(dev, B43_MMIO_MACCMD); + cmd |= B43_MACCMD_BEACON0_VALID; + b43_write32(dev, B43_MMIO_MACCMD, cmd); + } else if (!beacon1_valid) { + b43_upload_beacon1(dev); + cmd = b43_read32(dev, B43_MMIO_MACCMD); + cmd |= B43_MACCMD_BEACON1_VALID; + b43_write32(dev, B43_MMIO_MACCMD, cmd); } - cmd = b43_read32(dev, B43_MMIO_MACCMD); - cmd |= B43_MACCMD_BEACON1_VALID; - b43_write32(dev, B43_MMIO_MACCMD, cmd); } } @@ -4172,6 +4199,9 @@ static int b43_op_start(struct ieee80211_hw *hw) wl->filter_flags = 0; wl->radiotap_enabled = 0; b43_qos_clear(wl); + wl->beacon0_uploaded = 0; + wl->beacon1_uploaded = 0; + wl->beacon_templates_virgin = 1; /* First register RFkill. * LEDs that are registered later depend on it. */ @@ -4338,7 +4368,9 @@ static void b43_chip_reset(struct work_struct *work) goto out; } } - out: +out: + if (err) + wl->current_dev = NULL; /* Failed to init the dev. */ mutex_unlock(&wl->mutex); if (err) b43err(wl, "Controller restart FAILED\n"); @@ -4479,9 +4511,11 @@ static void b43_one_core_detach(struct ssb_device *dev) struct b43_wldev *wldev; struct b43_wl *wl; + /* Do not cancel ieee80211-workqueue based work here. + * See comment in b43_remove(). */ + wldev = ssb_get_drvdata(dev); wl = wldev->wl; - cancel_work_sync(&wldev->restart_work); b43_debugfs_remove_device(wldev); b43_wireless_core_detach(wldev); list_del(&wldev->list); @@ -4666,6 +4700,10 @@ static void b43_remove(struct ssb_device *dev) struct b43_wl *wl = ssb_get_devtypedata(dev); struct b43_wldev *wldev = ssb_get_drvdata(dev); + /* We must cancel any work here before unregistering from ieee80211, + * as the ieee80211 unreg will destroy the workqueue. */ + cancel_work_sync(&wldev->restart_work); + B43_WARN_ON(!wl); if (wl->current_dev == wldev) ieee80211_unregister_hw(wl->hw); diff --git a/drivers/net/wireless/b43legacy/Kconfig b/drivers/net/wireless/b43legacy/Kconfig index 13c65faf0247..aef2298d37ac 100644 --- a/drivers/net/wireless/b43legacy/Kconfig +++ b/drivers/net/wireless/b43legacy/Kconfig @@ -1,6 +1,6 @@ config B43LEGACY tristate "Broadcom 43xx-legacy wireless support (mac80211 stack)" - depends on SSB_POSSIBLE && MAC80211 && WLAN_80211 + depends on SSB_POSSIBLE && MAC80211 && WLAN_80211 && HAS_DMA select SSB select FW_LOADER select HW_RANDOM diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index f706ca65f159..5f533b93ad5d 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -3036,7 +3036,6 @@ static void b43legacy_set_pretbtt(struct b43legacy_wldev *dev) /* Locking: wl->mutex */ static void b43legacy_wireless_core_exit(struct b43legacy_wldev *dev) { - struct b43legacy_wl *wl = dev->wl; struct b43legacy_phy *phy = &dev->phy; u32 macctl; @@ -3051,12 +3050,6 @@ static void b43legacy_wireless_core_exit(struct b43legacy_wldev *dev) macctl |= B43legacy_MACCTL_PSM_JMP0; b43legacy_write32(dev, B43legacy_MMIO_MACCTL, macctl); - mutex_unlock(&wl->mutex); - /* Must unlock as it would otherwise deadlock. No races here. - * Cancel possibly pending workqueues. */ - cancel_work_sync(&dev->restart_work); - mutex_lock(&wl->mutex); - b43legacy_leds_exit(dev); b43legacy_rng_exit(dev->wl); b43legacy_pio_free(dev); @@ -3482,6 +3475,8 @@ static void b43legacy_chip_reset(struct work_struct *work) } } out: + if (err) + wl->current_dev = NULL; /* Failed to init the dev. */ mutex_unlock(&wl->mutex); if (err) b43legacyerr(wl, "Controller restart FAILED\n"); @@ -3614,9 +3609,11 @@ static void b43legacy_one_core_detach(struct ssb_device *dev) struct b43legacy_wldev *wldev; struct b43legacy_wl *wl; + /* Do not cancel ieee80211-workqueue based work here. + * See comment in b43legacy_remove(). */ + wldev = ssb_get_drvdata(dev); wl = wldev->wl; - cancel_work_sync(&wldev->restart_work); b43legacy_debugfs_remove_device(wldev); b43legacy_wireless_core_detach(wldev); list_del(&wldev->list); @@ -3784,6 +3781,10 @@ static void b43legacy_remove(struct ssb_device *dev) struct b43legacy_wl *wl = ssb_get_devtypedata(dev); struct b43legacy_wldev *wldev = ssb_get_drvdata(dev); + /* We must cancel any work here before unregistering from ieee80211, + * as the ieee80211 unreg will destroy the workqueue. */ + cancel_work_sync(&wldev->restart_work); + B43legacy_WARN_ON(!wl); if (wl->current_dev == wldev) ieee80211_unregister_hw(wl->hw); diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index d74c061994ae..6e704608947c 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -1753,6 +1753,8 @@ static int ipw_radio_kill_sw(struct ipw_priv *priv, int disable_radio) if (priv->workqueue) { cancel_delayed_work(&priv->request_scan); + cancel_delayed_work(&priv->request_direct_scan); + cancel_delayed_work(&priv->request_passive_scan); cancel_delayed_work(&priv->scan_event); } queue_work(priv->workqueue, &priv->down); @@ -2005,6 +2007,8 @@ static void ipw_irq_tasklet(struct ipw_priv *priv) wake_up_interruptible(&priv->wait_command_queue); priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING); cancel_delayed_work(&priv->request_scan); + cancel_delayed_work(&priv->request_direct_scan); + cancel_delayed_work(&priv->request_passive_scan); cancel_delayed_work(&priv->scan_event); schedule_work(&priv->link_down); queue_delayed_work(priv->workqueue, &priv->rf_kill, 2 * HZ); @@ -4712,6 +4716,12 @@ static void ipw_rx_notification(struct ipw_priv *priv, priv->status &= ~STATUS_SCAN_FORCED; #endif /* CONFIG_IPW2200_MONITOR */ + /* Do queued direct scans first */ + if (priv->status & STATUS_DIRECT_SCAN_PENDING) { + queue_delayed_work(priv->workqueue, + &priv->request_direct_scan, 0); + } + if (!(priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING | STATUS_ROAMING | @@ -6267,7 +6277,7 @@ static void ipw_add_scan_channels(struct ipw_priv *priv, } } -static int ipw_request_scan_helper(struct ipw_priv *priv, int type) +static int ipw_request_scan_helper(struct ipw_priv *priv, int type, int direct) { struct ipw_scan_request_ext scan; int err = 0, scan_type; @@ -6278,22 +6288,31 @@ static int ipw_request_scan_helper(struct ipw_priv *priv, int type) mutex_lock(&priv->mutex); + if (direct && (priv->direct_scan_ssid_len == 0)) { + IPW_DEBUG_HC("Direct scan requested but no SSID to scan for\n"); + priv->status &= ~STATUS_DIRECT_SCAN_PENDING; + goto done; + } + if (priv->status & STATUS_SCANNING) { - IPW_DEBUG_HC("Concurrent scan requested. Ignoring.\n"); - priv->status |= STATUS_SCAN_PENDING; + IPW_DEBUG_HC("Concurrent scan requested. Queuing.\n"); + priv->status |= direct ? STATUS_DIRECT_SCAN_PENDING : + STATUS_SCAN_PENDING; goto done; } if (!(priv->status & STATUS_SCAN_FORCED) && priv->status & STATUS_SCAN_ABORTING) { IPW_DEBUG_HC("Scan request while abort pending. Queuing.\n"); - priv->status |= STATUS_SCAN_PENDING; + priv->status |= direct ? STATUS_DIRECT_SCAN_PENDING : + STATUS_SCAN_PENDING; goto done; } if (priv->status & STATUS_RF_KILL_MASK) { - IPW_DEBUG_HC("Aborting scan due to RF Kill activation\n"); - priv->status |= STATUS_SCAN_PENDING; + IPW_DEBUG_HC("Queuing scan due to RF Kill activation\n"); + priv->status |= direct ? STATUS_DIRECT_SCAN_PENDING : + STATUS_SCAN_PENDING; goto done; } @@ -6321,6 +6340,7 @@ static int ipw_request_scan_helper(struct ipw_priv *priv, int type) cpu_to_le16(20); scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = cpu_to_le16(120); + scan.dwell_time[IPW_SCAN_ACTIVE_DIRECT_SCAN] = cpu_to_le16(20); #ifdef CONFIG_IPW2200_MONITOR if (priv->ieee->iw_mode == IW_MODE_MONITOR) { @@ -6360,13 +6380,23 @@ static int ipw_request_scan_helper(struct ipw_priv *priv, int type) cpu_to_le16(2000); } else { #endif /* CONFIG_IPW2200_MONITOR */ - /* If we are roaming, then make this a directed scan for the - * current network. Otherwise, ensure that every other scan - * is a fast channel hop scan */ - if ((priv->status & STATUS_ROAMING) - || (!(priv->status & STATUS_ASSOCIATED) - && (priv->config & CFG_STATIC_ESSID) - && (le32_to_cpu(scan.full_scan_index) % 2))) { + /* Honor direct scans first, otherwise if we are roaming make + * this a direct scan for the current network. Finally, + * ensure that every other scan is a fast channel hop scan */ + if (direct) { + err = ipw_send_ssid(priv, priv->direct_scan_ssid, + priv->direct_scan_ssid_len); + if (err) { + IPW_DEBUG_HC("Attempt to send SSID command " + "failed\n"); + goto done; + } + + scan_type = IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN; + } else if ((priv->status & STATUS_ROAMING) + || (!(priv->status & STATUS_ASSOCIATED) + && (priv->config & CFG_STATIC_ESSID) + && (le32_to_cpu(scan.full_scan_index) % 2))) { err = ipw_send_ssid(priv, priv->essid, priv->essid_len); if (err) { IPW_DEBUG_HC("Attempt to send SSID command " @@ -6391,7 +6421,12 @@ send_request: } priv->status |= STATUS_SCANNING; - priv->status &= ~STATUS_SCAN_PENDING; + if (direct) { + priv->status &= ~STATUS_DIRECT_SCAN_PENDING; + priv->direct_scan_ssid_len = 0; + } else + priv->status &= ~STATUS_SCAN_PENDING; + queue_delayed_work(priv->workqueue, &priv->scan_check, IPW_SCAN_CHECK_WATCHDOG); done: @@ -6402,15 +6437,22 @@ done: static void ipw_request_passive_scan(struct work_struct *work) { struct ipw_priv *priv = - container_of(work, struct ipw_priv, request_passive_scan); - ipw_request_scan_helper(priv, IW_SCAN_TYPE_PASSIVE); + container_of(work, struct ipw_priv, request_passive_scan.work); + ipw_request_scan_helper(priv, IW_SCAN_TYPE_PASSIVE, 0); } static void ipw_request_scan(struct work_struct *work) { struct ipw_priv *priv = container_of(work, struct ipw_priv, request_scan.work); - ipw_request_scan_helper(priv, IW_SCAN_TYPE_ACTIVE); + ipw_request_scan_helper(priv, IW_SCAN_TYPE_ACTIVE, 0); +} + +static void ipw_request_direct_scan(struct work_struct *work) +{ + struct ipw_priv *priv = + container_of(work, struct ipw_priv, request_direct_scan.work); + ipw_request_scan_helper(priv, IW_SCAN_TYPE_ACTIVE, 1); } static void ipw_bg_abort_scan(struct work_struct *work) @@ -7558,8 +7600,31 @@ static int ipw_associate(void *data) priv->ieee->iw_mode == IW_MODE_ADHOC && priv->config & CFG_ADHOC_CREATE && priv->config & CFG_STATIC_ESSID && - priv->config & CFG_STATIC_CHANNEL && - !list_empty(&priv->ieee->network_free_list)) { + priv->config & CFG_STATIC_CHANNEL) { + /* Use oldest network if the free list is empty */ + if (list_empty(&priv->ieee->network_free_list)) { + struct ieee80211_network *oldest = NULL; + struct ieee80211_network *target; + DECLARE_MAC_BUF(mac); + + list_for_each_entry(target, &priv->ieee->network_list, list) { + if ((oldest == NULL) || + (target->last_scanned < oldest->last_scanned)) + oldest = target; + } + + /* If there are no more slots, expire the oldest */ + list_del(&oldest->list); + target = oldest; + IPW_DEBUG_ASSOC("Expired '%s' (%s) from " + "network list.\n", + escape_essid(target->ssid, + target->ssid_len), + print_mac(mac, target->bssid)); + list_add_tail(&target->list, + &priv->ieee->network_free_list); + } + element = priv->ieee->network_free_list.next; network = list_entry(element, struct ieee80211_network, list); ipw_adhoc_create(priv, network); @@ -9454,99 +9519,38 @@ static int ipw_wx_get_retry(struct net_device *dev, return 0; } -static int ipw_request_direct_scan(struct ipw_priv *priv, char *essid, - int essid_len) -{ - struct ipw_scan_request_ext scan; - int err = 0, scan_type; - - if (!(priv->status & STATUS_INIT) || - (priv->status & STATUS_EXIT_PENDING)) - return 0; - - mutex_lock(&priv->mutex); - - if (priv->status & STATUS_RF_KILL_MASK) { - IPW_DEBUG_HC("Aborting scan due to RF kill activation\n"); - priv->status |= STATUS_SCAN_PENDING; - goto done; - } - - IPW_DEBUG_HC("starting request direct scan!\n"); - - if (priv->status & (STATUS_SCANNING | STATUS_SCAN_ABORTING)) { - /* We should not sleep here; otherwise we will block most - * of the system (for instance, we hold rtnl_lock when we - * get here). - */ - err = -EAGAIN; - goto done; - } - memset(&scan, 0, sizeof(scan)); - - if (priv->config & CFG_SPEED_SCAN) - scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] = - cpu_to_le16(30); - else - scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] = - cpu_to_le16(20); - - scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN] = - cpu_to_le16(20); - scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = cpu_to_le16(120); - scan.dwell_time[IPW_SCAN_ACTIVE_DIRECT_SCAN] = cpu_to_le16(20); - - scan.full_scan_index = cpu_to_le32(ieee80211_get_scans(priv->ieee)); - - err = ipw_send_ssid(priv, essid, essid_len); - if (err) { - IPW_DEBUG_HC("Attempt to send SSID command failed\n"); - goto done; - } - scan_type = IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN; - - ipw_add_scan_channels(priv, &scan, scan_type); - - err = ipw_send_scan_request_ext(priv, &scan); - if (err) { - IPW_DEBUG_HC("Sending scan command failed: %08X\n", err); - goto done; - } - - priv->status |= STATUS_SCANNING; - - done: - mutex_unlock(&priv->mutex); - return err; -} - static int ipw_wx_set_scan(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { struct ipw_priv *priv = ieee80211_priv(dev); struct iw_scan_req *req = (struct iw_scan_req *)extra; + struct delayed_work *work = NULL; mutex_lock(&priv->mutex); + priv->user_requested_scan = 1; - mutex_unlock(&priv->mutex); if (wrqu->data.length == sizeof(struct iw_scan_req)) { if (wrqu->data.flags & IW_SCAN_THIS_ESSID) { - ipw_request_direct_scan(priv, req->essid, - req->essid_len); - return 0; - } - if (req->scan_type == IW_SCAN_TYPE_PASSIVE) { - queue_work(priv->workqueue, - &priv->request_passive_scan); - return 0; + int len = min((int)req->essid_len, + (int)sizeof(priv->direct_scan_ssid)); + memcpy(priv->direct_scan_ssid, req->essid, len); + priv->direct_scan_ssid_len = len; + work = &priv->request_direct_scan; + } else if (req->scan_type == IW_SCAN_TYPE_PASSIVE) { + work = &priv->request_passive_scan; } + } else { + /* Normal active broadcast scan */ + work = &priv->request_scan; } + mutex_unlock(&priv->mutex); + IPW_DEBUG_WX("Start scan\n"); - queue_delayed_work(priv->workqueue, &priv->request_scan, 0); + queue_delayed_work(priv->workqueue, work, 0); return 0; } @@ -10708,6 +10712,8 @@ static void ipw_link_up(struct ipw_priv *priv) } cancel_delayed_work(&priv->request_scan); + cancel_delayed_work(&priv->request_direct_scan); + cancel_delayed_work(&priv->request_passive_scan); cancel_delayed_work(&priv->scan_event); ipw_reset_stats(priv); /* Ensure the rate is updated immediately */ @@ -10738,6 +10744,8 @@ static void ipw_link_down(struct ipw_priv *priv) /* Cancel any queued work ... */ cancel_delayed_work(&priv->request_scan); + cancel_delayed_work(&priv->request_direct_scan); + cancel_delayed_work(&priv->request_passive_scan); cancel_delayed_work(&priv->adhoc_check); cancel_delayed_work(&priv->gather_stats); @@ -10777,8 +10785,9 @@ static int __devinit ipw_setup_deferred_work(struct ipw_priv *priv) INIT_WORK(&priv->up, ipw_bg_up); INIT_WORK(&priv->down, ipw_bg_down); INIT_DELAYED_WORK(&priv->request_scan, ipw_request_scan); + INIT_DELAYED_WORK(&priv->request_direct_scan, ipw_request_direct_scan); + INIT_DELAYED_WORK(&priv->request_passive_scan, ipw_request_passive_scan); INIT_DELAYED_WORK(&priv->scan_event, ipw_scan_event); - INIT_WORK(&priv->request_passive_scan, ipw_request_passive_scan); INIT_DELAYED_WORK(&priv->gather_stats, ipw_bg_gather_stats); INIT_WORK(&priv->abort_scan, ipw_bg_abort_scan); INIT_WORK(&priv->roam, ipw_bg_roam); @@ -11812,6 +11821,8 @@ static void __devexit ipw_pci_remove(struct pci_dev *pdev) cancel_delayed_work(&priv->adhoc_check); cancel_delayed_work(&priv->gather_stats); cancel_delayed_work(&priv->request_scan); + cancel_delayed_work(&priv->request_direct_scan); + cancel_delayed_work(&priv->request_passive_scan); cancel_delayed_work(&priv->scan_event); cancel_delayed_work(&priv->rf_kill); cancel_delayed_work(&priv->scan_check); diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h index cd3295b66dd6..d4ab28b73b32 100644 --- a/drivers/net/wireless/ipw2200.h +++ b/drivers/net/wireless/ipw2200.h @@ -1037,6 +1037,7 @@ struct ipw_cmd { /* XXX */ #define STATUS_DISASSOC_PENDING (1<<12) #define STATUS_STATE_PENDING (1<<13) +#define STATUS_DIRECT_SCAN_PENDING (1<<19) #define STATUS_SCAN_PENDING (1<<20) #define STATUS_SCANNING (1<<21) #define STATUS_SCAN_ABORTING (1<<22) @@ -1292,6 +1293,8 @@ struct ipw_priv { struct iw_public_data wireless_data; int user_requested_scan; + u8 direct_scan_ssid[IW_ESSID_MAX_SIZE]; + u8 direct_scan_ssid_len; struct workqueue_struct *workqueue; @@ -1301,8 +1304,9 @@ struct ipw_priv { struct work_struct system_config; struct work_struct rx_replenish; struct delayed_work request_scan; + struct delayed_work request_direct_scan; + struct delayed_work request_passive_scan; struct delayed_work scan_event; - struct work_struct request_passive_scan; struct work_struct adapter_restart; struct delayed_work rf_kill; struct work_struct up; diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.c b/drivers/net/wireless/iwlwifi/iwl-3945-led.c index d200d08fb086..8b1528e52d43 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.c @@ -229,14 +229,15 @@ static int iwl3945_led_register_led(struct iwl3945_priv *priv, led->led_dev.brightness_set = iwl3945_led_brightness_set; led->led_dev.default_trigger = trigger; + led->priv = priv; + led->type = type; + ret = led_classdev_register(device, &led->led_dev); if (ret) { IWL_ERROR("Error: failed to register led handler.\n"); return ret; } - led->priv = priv; - led->type = type; led->registered = 1; if (set_led && led->led_on) diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index a955f9c1b9ee..d8f2b4d33fd9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -1145,7 +1145,6 @@ static s32 rs_get_best_rate(struct iwl_priv *priv, /* Higher rate not available, use the original */ } else { - new_rate = rate; break; } } @@ -1977,7 +1976,7 @@ lq_update: * 2) Not just finishing up a search * 3) Allowing a new search */ - if (!update_lq && !done_search && !lq_sta->stay_in_tbl) { + if (!update_lq && !done_search && !lq_sta->stay_in_tbl && window->counter) { /* Save current throughput to compare with "search" throughput*/ lq_sta->last_tpt = current_tpt; diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index cf261d3487fd..75427e61898d 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -1858,6 +1858,9 @@ static void lbs_send_confirmsleep(struct lbs_private *priv) spin_lock_irqsave(&priv->driver_lock, flags); + /* We don't get a response on the sleep-confirmation */ + priv->dnld_sent = DNLD_RES_RECEIVED; + /* If nothing to do, go back to sleep (?) */ if (!__kfifo_len(priv->event_fifo) && !priv->resp_len[priv->resp_idx]) priv->psstate = PS_STATE_SLEEP; @@ -1920,12 +1923,12 @@ void lbs_ps_confirm_sleep(struct lbs_private *priv) lbs_deb_enter(LBS_DEB_HOST); + spin_lock_irqsave(&priv->driver_lock, flags); if (priv->dnld_sent) { allowed = 0; lbs_deb_host("dnld_sent was set\n"); } - spin_lock_irqsave(&priv->driver_lock, flags); /* In-progress command? */ if (priv->cur_cmd) { allowed = 0; diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c index ad2fabca9116..0aa0ce3b2c42 100644 --- a/drivers/net/wireless/libertas/debugfs.c +++ b/drivers/net/wireless/libertas/debugfs.c @@ -312,8 +312,8 @@ static ssize_t lbs_threshold_write(uint16_t tlv_type, uint16_t event_mask, if (tlv_type != TLV_TYPE_BCNMISS) tlv->freq = freq; - /* The command header, the event mask, and the one TLV */ - events->hdr.size = cpu_to_le16(sizeof(events->hdr) + 2 + sizeof(*tlv)); + /* The command header, the action, the event mask, and one TLV */ + events->hdr.size = cpu_to_le16(sizeof(events->hdr) + 4 + sizeof(*tlv)); ret = lbs_cmd_with_response(priv, CMD_802_11_SUBSCRIBE_EVENT, events); diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index b7ab3590b586..abd6d9ed8f4b 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -765,8 +765,8 @@ static int lbs_thread(void *data) lbs_deb_thread("4: currenttxskb %p, dnld_sent %d\n", priv->currenttxskb, priv->dnld_sent); - spin_lock_irq(&priv->driver_lock); /* Process any pending command response */ + spin_lock_irq(&priv->driver_lock); resp_idx = priv->resp_idx; if (priv->resp_len[resp_idx]) { spin_unlock_irq(&priv->driver_lock); diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index 98ddbb3b3273..1610a7308c1d 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c @@ -49,6 +49,7 @@ static struct usb_device_id p54u_table[] __devinitdata = { {USB_DEVICE(0x5041, 0x2235)}, /* Linksys WUSB54G Portable */ /* Version 2 devices (3887) */ + {USB_DEVICE(0x0471, 0x1230)}, /* Philips CPWUA054/00 */ {USB_DEVICE(0x050d, 0x7050)}, /* Belkin F5D7050 ver 1000 */ {USB_DEVICE(0x0572, 0x2000)}, /* Cohiba Proto board */ {USB_DEVICE(0x0572, 0x2002)}, /* Cohiba Proto board */ diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index ed310f84f28b..3954897d0678 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -116,6 +116,7 @@ MODULE_PARM_DESC(workaround_interval, #define OID_802_11_ENCRYPTION_STATUS ccpu2(0x0d01011b) #define OID_802_11_ADD_KEY ccpu2(0x0d01011d) #define OID_802_11_REMOVE_KEY ccpu2(0x0d01011e) +#define OID_802_11_ASSOCIATION_INFORMATION ccpu2(0x0d01011f) #define OID_802_11_PMKID ccpu2(0x0d010123) #define OID_802_11_NETWORK_TYPES_SUPPORTED ccpu2(0x0d010203) #define OID_802_11_NETWORK_TYPE_IN_USE ccpu2(0x0d010204) @@ -271,6 +272,26 @@ struct ndis_config_param { __le32 value_length; } __attribute__((packed)); +struct ndis_80211_assoc_info { + __le32 length; + __le16 req_ies; + struct req_ie { + __le16 capa; + __le16 listen_interval; + u8 cur_ap_address[6]; + } req_ie; + __le32 req_ie_length; + __le32 offset_req_ies; + __le16 resp_ies; + struct resp_ie { + __le16 capa; + __le16 status_code; + __le16 assoc_id; + } resp_ie; + __le32 resp_ie_length; + __le32 offset_resp_ies; +} __attribute__((packed)); + /* these have to match what is in wpa_supplicant */ enum wpa_alg { WPA_ALG_NONE, WPA_ALG_WEP, WPA_ALG_TKIP, WPA_ALG_CCMP }; enum wpa_cipher { CIPHER_NONE, CIPHER_WEP40, CIPHER_TKIP, CIPHER_CCMP, @@ -674,6 +695,12 @@ static int get_bssid(struct usbnet *usbdev, u8 bssid[ETH_ALEN]) return ret; } +static int get_association_info(struct usbnet *usbdev, + struct ndis_80211_assoc_info *info, int len) +{ + return rndis_query_oid(usbdev, OID_802_11_ASSOCIATION_INFORMATION, + info, &len); +} static int is_associated(struct usbnet *usbdev) { @@ -2182,11 +2209,40 @@ static void rndis_wext_worker(struct work_struct *work) struct usbnet *usbdev = priv->usbdev; union iwreq_data evt; unsigned char bssid[ETH_ALEN]; - int ret; + struct ndis_80211_assoc_info *info; + int assoc_size = sizeof(*info) + IW_CUSTOM_MAX + 32; + int ret, offset; if (test_and_clear_bit(WORK_CONNECTION_EVENT, &priv->work_pending)) { - ret = get_bssid(usbdev, bssid); + info = kzalloc(assoc_size, GFP_KERNEL); + if (!info) + goto get_bssid; + + /* Get association info IEs from device and send them back to + * userspace. */ + ret = get_association_info(usbdev, info, assoc_size); + if (!ret) { + evt.data.length = le32_to_cpu(info->req_ie_length); + if (evt.data.length > 0) { + offset = le32_to_cpu(info->offset_req_ies); + wireless_send_event(usbdev->net, + IWEVASSOCREQIE, &evt, + (char *)info + offset); + } + + evt.data.length = le32_to_cpu(info->resp_ie_length); + if (evt.data.length > 0) { + offset = le32_to_cpu(info->offset_resp_ies); + wireless_send_event(usbdev->net, + IWEVASSOCRESPIE, &evt, + (char *)info + offset); + } + } + + kfree(info); +get_bssid: + ret = get_bssid(usbdev, bssid); if (!ret) { evt.data.flags = 0; evt.data.length = 0; @@ -2414,6 +2470,11 @@ static int bcm4320_early_init(struct usbnet *dev) else if (priv->param_power_save > 2) priv->param_power_save = 2; + if (priv->param_power_output < 0) + priv->param_power_output = 0; + else if (priv->param_power_output > 3) + priv->param_power_output = 3; + if (priv->param_roamtrigger < -80) priv->param_roamtrigger = -80; else if (priv->param_roamtrigger > -60) diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 5c7220ea46e6..15ec797c5ec1 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -328,6 +328,11 @@ static inline int rt2x00_get_link_ant_rssi(struct link *link) return DEFAULT_RSSI; } +static inline void rt2x00_reset_link_ant_rssi(struct link *link) +{ + link->ant.rssi_ant = 0; +} + static inline int rt2x00_get_link_ant_rssi_history(struct link *link, enum antenna ant) { diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index a9930a03f450..48608e8cc8b4 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -129,6 +129,7 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, */ rt2x00dev->ops->lib->config(rt2x00dev, &libconf, CONFIG_UPDATE_ANTENNA); rt2x00lib_reset_link_tuner(rt2x00dev); + rt2x00_reset_link_ant_rssi(&rt2x00dev->link); rt2x00dev->link.ant.active.rx = libconf.ant.rx; rt2x00dev->link.ant.active.tx = libconf.ant.tx; diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 69e233610c94..f7a44170c025 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -481,9 +481,9 @@ void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev) if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) return; - ieee80211_iterate_active_interfaces(rt2x00dev->hw, - rt2x00lib_beacondone_iter, - rt2x00dev); + ieee80211_iterate_active_interfaces_atomic(rt2x00dev->hw, + rt2x00lib_beacondone_iter, + rt2x00dev); queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->intf_work); } diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index c05e05b58887..b02dbc8a666e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -114,6 +114,7 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) */ if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags)) { ieee80211_stop_queues(hw); + dev_kfree_skb_any(skb); return NETDEV_TX_OK; } diff --git a/drivers/net/wireless/rtl8180_grf5101.c b/drivers/net/wireless/rtl8180_grf5101.c index 5d47935dbac3..947ee55f18b2 100644 --- a/drivers/net/wireless/rtl8180_grf5101.c +++ b/drivers/net/wireless/rtl8180_grf5101.c @@ -88,7 +88,7 @@ static void grf5101_rf_set_channel(struct ieee80211_hw *dev, write_grf5101(dev, 0x0B, chan); write_grf5101(dev, 0x07, 0x1000); - grf5101_write_phy_antenna(dev, chan); + grf5101_write_phy_antenna(dev, channel); } static void grf5101_rf_stop(struct ieee80211_hw *dev) diff --git a/drivers/net/wireless/rtl8180_max2820.c b/drivers/net/wireless/rtl8180_max2820.c index a34dfd382b6d..6c825fd7f3b6 100644 --- a/drivers/net/wireless/rtl8180_max2820.c +++ b/drivers/net/wireless/rtl8180_max2820.c @@ -78,7 +78,8 @@ static void max2820_rf_set_channel(struct ieee80211_hw *dev, struct ieee80211_conf *conf) { struct rtl8180_priv *priv = dev->priv; - int channel = ieee80211_frequency_to_channel(conf->channel->center_freq); + int channel = conf ? + ieee80211_frequency_to_channel(conf->channel->center_freq) : 1; unsigned int chan_idx = channel - 1; u32 txpw = priv->channels[chan_idx].hw_value & 0xFF; u32 chan = max2820_chan[chan_idx]; @@ -87,7 +88,7 @@ static void max2820_rf_set_channel(struct ieee80211_hw *dev, * sa2400, for MAXIM we do this directly from BB */ rtl8180_write_phy(dev, 3, txpw); - max2820_write_phy_antenna(dev, chan); + max2820_write_phy_antenna(dev, channel); write_max2820(dev, 3, chan); } diff --git a/drivers/net/wireless/rtl8180_sa2400.c b/drivers/net/wireless/rtl8180_sa2400.c index 0311b4ea124c..cea4e0ccb92d 100644 --- a/drivers/net/wireless/rtl8180_sa2400.c +++ b/drivers/net/wireless/rtl8180_sa2400.c @@ -86,7 +86,7 @@ static void sa2400_rf_set_channel(struct ieee80211_hw *dev, write_sa2400(dev, 7, txpw); - sa2400_write_phy_antenna(dev, chan); + sa2400_write_phy_antenna(dev, channel); write_sa2400(dev, 0, chan); write_sa2400(dev, 1, 0xbb50); diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index d2378d083a35..6d86b365f150 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -647,7 +647,7 @@ int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length) fc = le16_to_cpu(*((__le16 *) buffer)); is_qos = ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) && - ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_QOS_DATA); + (fc & IEEE80211_STYPE_QOS_DATA); is_4addr = (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS); need_padding = is_qos ^ is_4addr; diff --git a/drivers/of/base.c b/drivers/of/base.c index 9bd7c4a31253..23ffb7c0caf2 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -65,6 +65,9 @@ struct property *of_find_property(const struct device_node *np, { struct property *pp; + if (!np) + return NULL; + read_lock(&devtree_lock); for (pp = np->properties; pp != 0; pp = pp->next) { if (of_prop_cmp(pp->name, name) == 0) { diff --git a/drivers/parisc/asp.c b/drivers/parisc/asp.c index 558420bc9f88..821369135369 100644 --- a/drivers/parisc/asp.c +++ b/drivers/parisc/asp.c @@ -88,7 +88,7 @@ asp_init_chip(struct parisc_device *dev) ret = -EBUSY; dev->irq = gsc_claim_irq(&gsc_irq, ASP_GSC_IRQ); if (dev->irq < 0) { - printk(KERN_ERR "%s(): cannot get GSC irq\n", __FUNCTION__); + printk(KERN_ERR "%s(): cannot get GSC irq\n", __func__); goto out; } diff --git a/drivers/parisc/ccio-dma.c b/drivers/parisc/ccio-dma.c index 07d2a8d4498f..b30e38f3a50d 100644 --- a/drivers/parisc/ccio-dma.c +++ b/drivers/parisc/ccio-dma.c @@ -359,7 +359,7 @@ ccio_alloc_range(struct ioc *ioc, struct device *dev, size_t size) BUG_ON((pages_needed * IOVP_SIZE) > DMA_CHUNK_SIZE); DBG_RES("%s() size: %d pages_needed %d\n", - __FUNCTION__, size, pages_needed); + __func__, size, pages_needed); /* ** "seek and ye shall find"...praying never hurts either... @@ -395,16 +395,16 @@ ccio_alloc_range(struct ioc *ioc, struct device *dev, size_t size) #endif } else { panic("%s: %s() Too many pages to map. pages_needed: %u\n", - __FILE__, __FUNCTION__, pages_needed); + __FILE__, __func__, pages_needed); } panic("%s: %s() I/O MMU is out of mapping resources.\n", __FILE__, - __FUNCTION__); + __func__); resource_found: DBG_RES("%s() res_idx %d res_hint: %d\n", - __FUNCTION__, res_idx, ioc->res_hint); + __func__, res_idx, ioc->res_hint); #ifdef CCIO_SEARCH_TIME { @@ -450,7 +450,7 @@ ccio_free_range(struct ioc *ioc, dma_addr_t iova, unsigned long pages_mapped) BUG_ON(pages_mapped > BITS_PER_LONG); DBG_RES("%s(): res_idx: %d pages_mapped %d\n", - __FUNCTION__, res_idx, pages_mapped); + __func__, res_idx, pages_mapped); #ifdef CCIO_MAP_STATS ioc->used_pages -= pages_mapped; @@ -474,7 +474,7 @@ ccio_free_range(struct ioc *ioc, dma_addr_t iova, unsigned long pages_mapped) #endif } else { panic("%s:%s() Too many pages to unmap.\n", __FILE__, - __FUNCTION__); + __func__); } } @@ -775,7 +775,7 @@ ccio_map_single(struct device *dev, void *addr, size_t size, pdir_start = &(ioc->pdir_base[idx]); DBG_RUN("%s() 0x%p -> 0x%lx size: %0x%x\n", - __FUNCTION__, addr, (long)iovp | offset, size); + __func__, addr, (long)iovp | offset, size); /* If not cacheline aligned, force SAFE_DMA on the whole mess */ if((size % L1_CACHE_BYTES) || ((unsigned long)addr % L1_CACHE_BYTES)) @@ -820,7 +820,7 @@ ccio_unmap_single(struct device *dev, dma_addr_t iova, size_t size, ioc = GET_IOC(dev); DBG_RUN("%s() iovp 0x%lx/%x\n", - __FUNCTION__, (long)iova, size); + __func__, (long)iova, size); iova ^= offset; /* clear offset bits */ size += offset; @@ -922,7 +922,7 @@ ccio_map_sg(struct device *dev, struct scatterlist *sglist, int nents, BUG_ON(!dev); ioc = GET_IOC(dev); - DBG_RUN_SG("%s() START %d entries\n", __FUNCTION__, nents); + DBG_RUN_SG("%s() START %d entries\n", __func__, nents); /* Fast path single entry scatterlists. */ if (nents == 1) { @@ -966,7 +966,7 @@ ccio_map_sg(struct device *dev, struct scatterlist *sglist, int nents, BUG_ON(coalesced != filled); - DBG_RUN_SG("%s() DONE %d mappings\n", __FUNCTION__, filled); + DBG_RUN_SG("%s() DONE %d mappings\n", __func__, filled); for (i = 0; i < filled; i++) current_len += sg_dma_len(sglist + i); @@ -995,7 +995,7 @@ ccio_unmap_sg(struct device *dev, struct scatterlist *sglist, int nents, ioc = GET_IOC(dev); DBG_RUN_SG("%s() START %d entries, %08lx,%x\n", - __FUNCTION__, nents, sg_virt_addr(sglist), sglist->length); + __func__, nents, sg_virt_addr(sglist), sglist->length); #ifdef CCIO_MAP_STATS ioc->usg_calls++; @@ -1011,7 +1011,7 @@ ccio_unmap_sg(struct device *dev, struct scatterlist *sglist, int nents, ++sglist; } - DBG_RUN_SG("%s() DONE (nents %d)\n", __FUNCTION__, nents); + DBG_RUN_SG("%s() DONE (nents %d)\n", __func__, nents); } static struct hppa_dma_ops ccio_ops = { @@ -1225,7 +1225,7 @@ static int ccio_get_iotlb_size(struct parisc_device *dev) { if (dev->spa_shift == 0) { - panic("%s() : Can't determine I/O TLB size.\n", __FUNCTION__); + panic("%s() : Can't determine I/O TLB size.\n", __func__); } return (1 << dev->spa_shift); } @@ -1315,7 +1315,7 @@ ccio_ioc_init(struct ioc *ioc) BUG_ON((1 << get_order(ioc->pdir_size)) != (ioc->pdir_size >> PAGE_SHIFT)); DBG_INIT("%s() hpa 0x%p mem %luMB IOV %dMB (%d bits)\n", - __FUNCTION__, ioc->ioc_regs, + __func__, ioc->ioc_regs, (unsigned long) num_physpages >> (20 - PAGE_SHIFT), iova_space_size>>20, iov_order + PAGE_SHIFT); @@ -1323,7 +1323,7 @@ ccio_ioc_init(struct ioc *ioc) ioc->pdir_base = (u64 *)__get_free_pages(GFP_KERNEL, get_order(ioc->pdir_size)); if(NULL == ioc->pdir_base) { - panic("%s() could not allocate I/O Page Table\n", __FUNCTION__); + panic("%s() could not allocate I/O Page Table\n", __func__); } memset(ioc->pdir_base, 0, ioc->pdir_size); @@ -1332,12 +1332,12 @@ ccio_ioc_init(struct ioc *ioc) /* resource map size dictated by pdir_size */ ioc->res_size = (ioc->pdir_size / sizeof(u64)) >> 3; - DBG_INIT("%s() res_size 0x%x\n", __FUNCTION__, ioc->res_size); + DBG_INIT("%s() res_size 0x%x\n", __func__, ioc->res_size); ioc->res_map = (u8 *)__get_free_pages(GFP_KERNEL, get_order(ioc->res_size)); if(NULL == ioc->res_map) { - panic("%s() could not allocate resource map\n", __FUNCTION__); + panic("%s() could not allocate resource map\n", __func__); } memset(ioc->res_map, 0, ioc->res_size); @@ -1409,7 +1409,7 @@ ccio_init_resource(struct resource *res, char *name, void __iomem *ioaddr) result = insert_resource(&iomem_resource, res); if (result < 0) { printk(KERN_ERR "%s() failed to claim CCIO bus address space (%08lx,%08lx)\n", - __FUNCTION__, res->start, res->end); + __func__, res->start, res->end); } } diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c index d9c6322a721b..fd56128525d1 100644 --- a/drivers/parisc/dino.c +++ b/drivers/parisc/dino.c @@ -180,7 +180,7 @@ static int dino_cfg_read(struct pci_bus *bus, unsigned int devfn, int where, void __iomem *base_addr = d->hba.base_addr; unsigned long flags; - DBG("%s: %p, %d, %d, %d\n", __FUNCTION__, base_addr, devfn, where, + DBG("%s: %p, %d, %d, %d\n", __func__, base_addr, devfn, where, size); spin_lock_irqsave(&d->dinosaur_pen, flags); @@ -215,7 +215,7 @@ static int dino_cfg_write(struct pci_bus *bus, unsigned int devfn, int where, void __iomem *base_addr = d->hba.base_addr; unsigned long flags; - DBG("%s: %p, %d, %d, %d\n", __FUNCTION__, base_addr, devfn, where, + DBG("%s: %p, %d, %d, %d\n", __func__, base_addr, devfn, where, size); spin_lock_irqsave(&d->dinosaur_pen, flags); @@ -301,7 +301,7 @@ static void dino_disable_irq(unsigned int irq) struct dino_device *dino_dev = irq_desc[irq].chip_data; int local_irq = gsc_find_local_irq(irq, dino_dev->global_irq, DINO_LOCAL_IRQS); - DBG(KERN_WARNING "%s(0x%p, %d)\n", __FUNCTION__, dino_dev, irq); + DBG(KERN_WARNING "%s(0x%p, %d)\n", __func__, dino_dev, irq); /* Clear the matching bit in the IMR register */ dino_dev->imr &= ~(DINO_MASK_IRQ(local_irq)); @@ -314,7 +314,7 @@ static void dino_enable_irq(unsigned int irq) int local_irq = gsc_find_local_irq(irq, dino_dev->global_irq, DINO_LOCAL_IRQS); u32 tmp; - DBG(KERN_WARNING "%s(0x%p, %d)\n", __FUNCTION__, dino_dev, irq); + DBG(KERN_WARNING "%s(0x%p, %d)\n", __func__, dino_dev, irq); /* ** clear pending IRQ bits @@ -340,7 +340,7 @@ static void dino_enable_irq(unsigned int irq) tmp = __raw_readl(dino_dev->hba.base_addr+DINO_ILR); if (tmp & DINO_MASK_IRQ(local_irq)) { DBG(KERN_WARNING "%s(): IRQ asserted! (ILR 0x%x)\n", - __FUNCTION__, tmp); + __func__, tmp); gsc_writel(dino_dev->txn_data, dino_dev->txn_addr); } } @@ -388,7 +388,7 @@ ilr_again: int local_irq = __ffs(mask); int irq = dino_dev->global_irq[local_irq]; DBG(KERN_DEBUG "%s(%d, %p) mask 0x%x\n", - __FUNCTION__, irq, intr_dev, mask); + __func__, irq, intr_dev, mask); __do_IRQ(irq); mask &= ~(1 << local_irq); } while (mask); @@ -566,7 +566,7 @@ dino_fixup_bus(struct pci_bus *bus) int port_base = HBA_PORT_BASE(dino_dev->hba.hba_num); DBG(KERN_WARNING "%s(0x%p) bus %d platform_data 0x%p\n", - __FUNCTION__, bus, bus->secondary, + __func__, bus, bus->secondary, bus->bridge->platform_data); /* Firmware doesn't set up card-mode dino, so we have to */ diff --git a/drivers/parisc/gsc.c b/drivers/parisc/gsc.c index 1b3e3fd12d95..f7d088b897ee 100644 --- a/drivers/parisc/gsc.c +++ b/drivers/parisc/gsc.c @@ -112,7 +112,7 @@ static void gsc_asic_disable_irq(unsigned int irq) int local_irq = gsc_find_local_irq(irq, irq_dev->global_irq, 32); u32 imr; - DEBPRINTK(KERN_DEBUG "%s(%d) %s: IMR 0x%x\n", __FUNCTION__, irq, + DEBPRINTK(KERN_DEBUG "%s(%d) %s: IMR 0x%x\n", __func__, irq, irq_dev->name, imr); /* Disable the IRQ line by clearing the bit in the IMR */ @@ -127,7 +127,7 @@ static void gsc_asic_enable_irq(unsigned int irq) int local_irq = gsc_find_local_irq(irq, irq_dev->global_irq, 32); u32 imr; - DEBPRINTK(KERN_DEBUG "%s(%d) %s: IMR 0x%x\n", __FUNCTION__, irq, + DEBPRINTK(KERN_DEBUG "%s(%d) %s: IMR 0x%x\n", __func__, irq, irq_dev->name, imr); /* Enable the IRQ line by setting the bit in the IMR */ diff --git a/drivers/parisc/lasi.c b/drivers/parisc/lasi.c index cb3d28176129..bee510098ce8 100644 --- a/drivers/parisc/lasi.c +++ b/drivers/parisc/lasi.c @@ -193,7 +193,7 @@ lasi_init_chip(struct parisc_device *dev) dev->irq = gsc_alloc_irq(&gsc_irq); if (dev->irq < 0) { printk(KERN_ERR "%s(): cannot get GSC irq\n", - __FUNCTION__); + __func__); kfree(lasi); return -EBUSY; } diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c index 66ce61048361..a28c8946deaa 100644 --- a/drivers/parisc/lba_pci.c +++ b/drivers/parisc/lba_pci.c @@ -377,12 +377,12 @@ static int elroy_cfg_read(struct pci_bus *bus, unsigned int devfn, int pos, int /* original - Generate config cycle on broken elroy with risk we will miss PCI bus errors. */ *data = lba_rd_cfg(d, tok, pos, size); - DBG_CFG("%s(%x+%2x) -> 0x%x (a)\n", __FUNCTION__, tok, pos, *data); + DBG_CFG("%s(%x+%2x) -> 0x%x (a)\n", __func__, tok, pos, *data); return 0; } if (LBA_SKIP_PROBE(d) && !lba_device_present(bus->secondary, devfn, d)) { - DBG_CFG("%s(%x+%2x) -> -1 (b)\n", __FUNCTION__, tok, pos); + DBG_CFG("%s(%x+%2x) -> -1 (b)\n", __func__, tok, pos); /* either don't want to look or know device isn't present. */ *data = ~0U; return(0); @@ -398,7 +398,7 @@ static int elroy_cfg_read(struct pci_bus *bus, unsigned int devfn, int pos, int case 2: *data = READ_REG16(data_reg + (pos & 2)); break; case 4: *data = READ_REG32(data_reg); break; } - DBG_CFG("%s(%x+%2x) -> 0x%x (c)\n", __FUNCTION__, tok, pos, *data); + DBG_CFG("%s(%x+%2x) -> 0x%x (c)\n", __func__, tok, pos, *data); return 0; } @@ -441,16 +441,16 @@ static int elroy_cfg_write(struct pci_bus *bus, unsigned int devfn, int pos, int if (!LBA_SKIP_PROBE(d)) { /* Original Workaround */ lba_wr_cfg(d, tok, pos, (u32) data, size); - DBG_CFG("%s(%x+%2x) = 0x%x (a)\n", __FUNCTION__, tok, pos,data); + DBG_CFG("%s(%x+%2x) = 0x%x (a)\n", __func__, tok, pos,data); return 0; } if (LBA_SKIP_PROBE(d) && (!lba_device_present(bus->secondary, devfn, d))) { - DBG_CFG("%s(%x+%2x) = 0x%x (b)\n", __FUNCTION__, tok, pos,data); + DBG_CFG("%s(%x+%2x) = 0x%x (b)\n", __func__, tok, pos,data); return 1; /* New Workaround */ } - DBG_CFG("%s(%x+%2x) = 0x%x (c)\n", __FUNCTION__, tok, pos, data); + DBG_CFG("%s(%x+%2x) = 0x%x (c)\n", __func__, tok, pos, data); /* Basic Algorithm */ LBA_CFG_ADDR_SETUP(d, tok | pos); @@ -521,7 +521,7 @@ static int mercury_cfg_write(struct pci_bus *bus, unsigned int devfn, int pos, i if ((pos > 255) || (devfn > 255)) return -EINVAL; - DBG_CFG("%s(%x+%2x) <- 0x%x (c)\n", __FUNCTION__, tok, pos, data); + DBG_CFG("%s(%x+%2x) <- 0x%x (c)\n", __func__, tok, pos, data); LBA_CFG_TR4_ADDR_SETUP(d, tok | pos); switch(size) { @@ -890,7 +890,7 @@ LBA_PORT_IN(32, 0) #define LBA_PORT_OUT(size, mask) \ static void lba_astro_out##size (struct pci_hba_data *d, u16 addr, u##size val) \ { \ - DBG_PORT("%s(0x%p, 0x%x, 0x%x)\n", __FUNCTION__, d, addr, val); \ + DBG_PORT("%s(0x%p, 0x%x, 0x%x)\n", __func__, d, addr, val); \ WRITE_REG##size(val, astro_iop_base + addr); \ if (LBA_DEV(d)->hw_rev < 3) \ lba_t32 = READ_U32(d->base_addr + LBA_FUNC_ID); \ @@ -932,7 +932,7 @@ static struct pci_port_ops lba_astro_port_ops = { static u##size lba_pat_in##size (struct pci_hba_data *l, u16 addr) \ { \ u##size t; \ - DBG_PORT("%s(0x%p, 0x%x) ->", __FUNCTION__, l, addr); \ + DBG_PORT("%s(0x%p, 0x%x) ->", __func__, l, addr); \ t = READ_REG##size(PIOP_TO_GMMIO(LBA_DEV(l), addr)); \ DBG_PORT(" 0x%x\n", t); \ return (t); \ @@ -948,7 +948,7 @@ LBA_PORT_IN(32, 0) static void lba_pat_out##size (struct pci_hba_data *l, u16 addr, u##size val) \ { \ void __iomem *where = PIOP_TO_GMMIO(LBA_DEV(l), addr); \ - DBG_PORT("%s(0x%p, 0x%x, 0x%x)\n", __FUNCTION__, l, addr, val); \ + DBG_PORT("%s(0x%p, 0x%x, 0x%x)\n", __func__, l, addr, val); \ WRITE_REG##size(val, where); \ /* flush the I/O down to the elroy at least */ \ lba_t32 = READ_U32(l->base_addr + LBA_FUNC_ID); \ @@ -1584,7 +1584,7 @@ void lba_set_iregs(struct parisc_device *lba, u32 ibase, u32 imask) WARN_ON((ibase & 0x001fffff) != 0); WARN_ON((imask & 0x001fffff) != 0); - DBG("%s() ibase 0x%x imask 0x%x\n", __FUNCTION__, ibase, imask); + DBG("%s() ibase 0x%x imask 0x%x\n", __func__, ibase, imask); WRITE_REG32( imask, base_addr + LBA_IMASK); WRITE_REG32( ibase, base_addr + LBA_IBASE); iounmap(base_addr); diff --git a/drivers/parisc/led.c b/drivers/parisc/led.c index 703b85edb004..f9b12664f9fb 100644 --- a/drivers/parisc/led.c +++ b/drivers/parisc/led.c @@ -569,7 +569,7 @@ int __init register_led_driver(int model, unsigned long cmd_reg, unsigned long d default: printk(KERN_ERR "%s: Wrong LCD/LED model %d !\n", - __FUNCTION__, lcd_info.model); + __func__, lcd_info.model); return 1; } diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c index afc849bd3f58..bc73b96346ff 100644 --- a/drivers/parisc/sba_iommu.c +++ b/drivers/parisc/sba_iommu.c @@ -384,7 +384,7 @@ sba_search_bitmap(struct ioc *ioc, struct device *dev, } mask = RESMAP_MASK(bits_wanted) >> bitshiftcnt; - DBG_RES("%s() o %ld %p", __FUNCTION__, o, res_ptr); + DBG_RES("%s() o %ld %p", __func__, o, res_ptr); while(res_ptr < res_end) { DBG_RES(" %p %lx %lx\n", res_ptr, mask, *res_ptr); @@ -454,7 +454,7 @@ sba_alloc_range(struct ioc *ioc, struct device *dev, size_t size) #endif DBG_RES("%s(%x) %d -> %lx hint %x/%x\n", - __FUNCTION__, size, pages_needed, pide, + __func__, size, pages_needed, pide, (uint) ((unsigned long) ioc->res_hint - (unsigned long) ioc->res_map), ioc->res_bitshift ); @@ -497,7 +497,7 @@ sba_free_range(struct ioc *ioc, dma_addr_t iova, size_t size) unsigned long m = RESMAP_MASK(bits_not_wanted) >> (pide & (BITS_PER_LONG - 1)); DBG_RES("%s( ,%x,%x) %x/%lx %x %p %lx\n", - __FUNCTION__, (uint) iova, size, + __func__, (uint) iova, size, bits_not_wanted, m, pide, res_ptr, *res_ptr); #ifdef SBA_COLLECT_STATS @@ -740,7 +740,7 @@ sba_map_single(struct device *dev, void *addr, size_t size, iovp = (dma_addr_t) pide << IOVP_SHIFT; DBG_RUN("%s() 0x%p -> 0x%lx\n", - __FUNCTION__, addr, (long) iovp | offset); + __func__, addr, (long) iovp | offset); pdir_start = &(ioc->pdir_base[pide]); @@ -798,7 +798,7 @@ sba_unmap_single(struct device *dev, dma_addr_t iova, size_t size, unsigned long flags; dma_addr_t offset; - DBG_RUN("%s() iovp 0x%lx/%x\n", __FUNCTION__, (long) iova, size); + DBG_RUN("%s() iovp 0x%lx/%x\n", __func__, (long) iova, size); ioc = GET_IOC(dev); offset = iova & ~IOVP_MASK; @@ -937,7 +937,7 @@ sba_map_sg(struct device *dev, struct scatterlist *sglist, int nents, int coalesced, filled = 0; unsigned long flags; - DBG_RUN_SG("%s() START %d entries\n", __FUNCTION__, nents); + DBG_RUN_SG("%s() START %d entries\n", __func__, nents); ioc = GET_IOC(dev); @@ -998,7 +998,7 @@ sba_map_sg(struct device *dev, struct scatterlist *sglist, int nents, spin_unlock_irqrestore(&ioc->res_lock, flags); - DBG_RUN_SG("%s() DONE %d mappings\n", __FUNCTION__, filled); + DBG_RUN_SG("%s() DONE %d mappings\n", __func__, filled); return filled; } @@ -1023,7 +1023,7 @@ sba_unmap_sg(struct device *dev, struct scatterlist *sglist, int nents, #endif DBG_RUN_SG("%s() START %d entries, %p,%x\n", - __FUNCTION__, nents, sg_virt_addr(sglist), sglist->length); + __func__, nents, sg_virt_addr(sglist), sglist->length); ioc = GET_IOC(dev); @@ -1047,7 +1047,7 @@ sba_unmap_sg(struct device *dev, struct scatterlist *sglist, int nents, ++sglist; } - DBG_RUN_SG("%s() DONE (nents %d)\n", __FUNCTION__, nents); + DBG_RUN_SG("%s() DONE (nents %d)\n", __func__, nents); #ifdef ASSERT_PDIR_SANITY spin_lock_irqsave(&ioc->res_lock, flags); @@ -1118,7 +1118,7 @@ sba_alloc_pdir(unsigned int pdir_size) pdir_base = __get_free_pages(GFP_KERNEL, pdir_order); if (NULL == (void *) pdir_base) { panic("%s() could not allocate I/O Page Table\n", - __FUNCTION__); + __func__); } /* If this is not PA8700 (PCX-W2) @@ -1261,7 +1261,7 @@ sba_ioc_init_pluto(struct parisc_device *sba, struct ioc *ioc, int ioc_num) ioc->pdir_size = (iova_space_size / IOVP_SIZE) * sizeof(u64); DBG_INIT("%s() hpa 0x%p IOV %dMB (%d bits)\n", - __FUNCTION__, ioc->ioc_hpa, iova_space_size >> 20, + __func__, ioc->ioc_hpa, iova_space_size >> 20, iov_order + PAGE_SHIFT); ioc->pdir_base = (void *) __get_free_pages(GFP_KERNEL, @@ -1272,7 +1272,7 @@ sba_ioc_init_pluto(struct parisc_device *sba, struct ioc *ioc, int ioc_num) memset(ioc->pdir_base, 0, ioc->pdir_size); DBG_INIT("%s() pdir %p size %x\n", - __FUNCTION__, ioc->pdir_base, ioc->pdir_size); + __func__, ioc->pdir_base, ioc->pdir_size); #ifdef SBA_HINT_SUPPORT ioc->hint_shift_pdir = iov_order + PAGE_SHIFT; @@ -1354,7 +1354,7 @@ sba_ioc_init_pluto(struct parisc_device *sba, struct ioc *ioc, int ioc_num) if (agp_found && sba_reserve_agpgart) { printk(KERN_INFO "%s: reserving %dMb of IOVA space for agpgart\n", - __FUNCTION__, (iova_space_size/2) >> 20); + __func__, (iova_space_size/2) >> 20); ioc->pdir_size /= 2; ioc->pdir_base[PDIR_INDEX(iova_space_size/2)] = SBA_AGPGART_COOKIE; } @@ -1406,7 +1406,7 @@ sba_ioc_init(struct parisc_device *sba, struct ioc *ioc, int ioc_num) ioc->pdir_size = pdir_size = (iova_space_size/IOVP_SIZE) * sizeof(u64); DBG_INIT("%s() hpa 0x%lx mem %ldMB IOV %dMB (%d bits)\n", - __FUNCTION__, + __func__, ioc->ioc_hpa, (unsigned long) num_physpages >> (20 - PAGE_SHIFT), iova_space_size>>20, @@ -1415,7 +1415,7 @@ sba_ioc_init(struct parisc_device *sba, struct ioc *ioc, int ioc_num) ioc->pdir_base = sba_alloc_pdir(pdir_size); DBG_INIT("%s() pdir %p size %x\n", - __FUNCTION__, ioc->pdir_base, pdir_size); + __func__, ioc->pdir_base, pdir_size); #ifdef SBA_HINT_SUPPORT /* FIXME : DMA HINTs not used */ @@ -1443,7 +1443,7 @@ sba_ioc_init(struct parisc_device *sba, struct ioc *ioc, int ioc_num) #endif DBG_INIT("%s() IOV base 0x%lx mask 0x%0lx\n", - __FUNCTION__, ioc->ibase, ioc->imask); + __func__, ioc->ibase, ioc->imask); /* ** FIXME: Hint registers are programmed with default hint @@ -1470,7 +1470,7 @@ sba_ioc_init(struct parisc_device *sba, struct ioc *ioc, int ioc_num) ioc->ibase = 0; /* used by SBA_IOVA and related macros */ - DBG_INIT("%s() DONE\n", __FUNCTION__); + DBG_INIT("%s() DONE\n", __func__); } @@ -1544,7 +1544,7 @@ printk("sba_hw_init(): mem_boot 0x%x 0x%x 0x%x 0x%x\n", PAGE0->mem_boot.hpa, if (!IS_PLUTO(sba_dev->dev)) { ioc_ctl = READ_REG(sba_dev->sba_hpa+IOC_CTRL); DBG_INIT("%s() hpa 0x%lx ioc_ctl 0x%Lx ->", - __FUNCTION__, sba_dev->sba_hpa, ioc_ctl); + __func__, sba_dev->sba_hpa, ioc_ctl); ioc_ctl &= ~(IOC_CTRL_RM | IOC_CTRL_NC | IOC_CTRL_CE); ioc_ctl |= IOC_CTRL_DD | IOC_CTRL_D4 | IOC_CTRL_TC; /* j6700 v1.6 firmware sets 0x294f */ @@ -1675,7 +1675,7 @@ sba_common_init(struct sba_device *sba_dev) res_size >>= 3; /* convert bit count to byte count */ DBG_INIT("%s() res_size 0x%x\n", - __FUNCTION__, res_size); + __func__, res_size); sba_dev->ioc[i].res_size = res_size; sba_dev->ioc[i].res_map = (char *) __get_free_pages(GFP_KERNEL, get_order(res_size)); @@ -1688,7 +1688,7 @@ sba_common_init(struct sba_device *sba_dev) if (NULL == sba_dev->ioc[i].res_map) { panic("%s:%s() could not allocate resource map\n", - __FILE__, __FUNCTION__ ); + __FILE__, __func__ ); } memset(sba_dev->ioc[i].res_map, 0, res_size); @@ -1725,7 +1725,7 @@ sba_common_init(struct sba_device *sba_dev) #endif DBG_INIT("%s() %d res_map %x %p\n", - __FUNCTION__, i, res_size, sba_dev->ioc[i].res_map); + __func__, i, res_size, sba_dev->ioc[i].res_map); } spin_lock_init(&sba_dev->sba_lock); diff --git a/drivers/parisc/wax.c b/drivers/parisc/wax.c index 813c2c24ab1e..892a83bbe73d 100644 --- a/drivers/parisc/wax.c +++ b/drivers/parisc/wax.c @@ -93,7 +93,7 @@ wax_init_chip(struct parisc_device *dev) dev->irq = gsc_claim_irq(&gsc_irq, WAX_GSC_IRQ); if (dev->irq < 0) { printk(KERN_ERR "%s(): cannot get GSC irq\n", - __FUNCTION__); + __func__); kfree(wax); return -EBUSY; } diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c index 925ba16355ce..a11021e8ce37 100644 --- a/drivers/pci/hotplug/pci_hotplug_core.c +++ b/drivers/pci/hotplug/pci_hotplug_core.c @@ -619,6 +619,7 @@ static struct hotplug_slot *get_slot_from_name (const char *name) int pci_hp_register (struct hotplug_slot *slot) { int result; + struct hotplug_slot *tmp; if (slot == NULL) return -ENODEV; @@ -630,7 +631,11 @@ int pci_hp_register (struct hotplug_slot *slot) return -EINVAL; } - /* this can fail if we have already registered a slot with the same name */ + /* Check if we have already registered a slot with the same name. */ + tmp = get_slot_from_name(slot->name); + if (tmp) + return -EEXIST; + slot->kobj.kset = pci_hotplug_slots_kset; result = kobject_init_and_add(&slot->kobj, &hotplug_slot_ktype, NULL, "%s", slot->name); diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index 8264a7680435..79c9ddaad3fb 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -97,6 +97,7 @@ struct controller { u8 cap_base; struct timer_list poll_timer; volatile int cmd_busy; + unsigned int no_cmd_complete:1; }; #define INT_BUTTON_IGNORE 0 @@ -135,6 +136,7 @@ struct controller { #define PWR_LED_PRSN 0x00000010 #define HP_SUPR_RM_SUP 0x00000020 #define EMI_PRSN 0x00020000 +#define NO_CMD_CMPL_SUP 0x00040000 #define ATTN_BUTTN(ctrl) ((ctrl)->slot_cap & ATTN_BUTTN_PRSN) #define POWER_CTRL(ctrl) ((ctrl)->slot_cap & PWR_CTRL_PRSN) @@ -143,13 +145,14 @@ struct controller { #define PWR_LED(ctrl) ((ctrl)->slot_cap & PWR_LED_PRSN) #define HP_SUPR_RM(ctrl) ((ctrl)->slot_cap & HP_SUPR_RM_SUP) #define EMI(ctrl) ((ctrl)->slot_cap & EMI_PRSN) +#define NO_CMD_CMPL(ctrl) ((ctrl)->slot_cap & NO_CMD_CMPL_SUP) extern int pciehp_sysfs_enable_slot(struct slot *slot); extern int pciehp_sysfs_disable_slot(struct slot *slot); -extern u8 pciehp_handle_attention_button(u8 hp_slot, struct controller *ctrl); -extern u8 pciehp_handle_switch_change(u8 hp_slot, struct controller *ctrl); -extern u8 pciehp_handle_presence_change(u8 hp_slot, struct controller *ctrl); -extern u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl); +extern u8 pciehp_handle_attention_button(struct slot *p_slot); + extern u8 pciehp_handle_switch_change(struct slot *p_slot); +extern u8 pciehp_handle_presence_change(struct slot *p_slot); +extern u8 pciehp_handle_power_fault(struct slot *p_slot); extern int pciehp_configure_device(struct slot *p_slot); extern int pciehp_unconfigure_device(struct slot *p_slot); extern void pciehp_queue_pushbutton_work(struct work_struct *work); diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index 43d8ddb2d679..48a2ed378914 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c @@ -254,7 +254,11 @@ static int init_slots(struct controller *ctrl) slot->hp_slot, slot->number, ctrl->slot_device_offset); retval = pci_hp_register(hotplug_slot); if (retval) { - err ("pci_hp_register failed with error %d\n", retval); + err("pci_hp_register failed with error %d\n", retval); + if (retval == -EEXIST) + err("Failed to register slot because of name " + "collision. Try \'pciehp_slot_with_bus\' " + "module option.\n"); goto error_info; } /* create additional sysfs entries */ diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index 0a7aa628e955..96a5d55a4983 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c @@ -55,16 +55,13 @@ static int queue_interrupt_event(struct slot *p_slot, u32 event_type) return 0; } -u8 pciehp_handle_attention_button(u8 hp_slot, struct controller *ctrl) +u8 pciehp_handle_attention_button(struct slot *p_slot) { - struct slot *p_slot; u32 event_type; /* Attention Button Change */ dbg("pciehp: Attention button interrupt received.\n"); - p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); - /* * Button pressed - See if need to TAKE ACTION!!! */ @@ -76,18 +73,15 @@ u8 pciehp_handle_attention_button(u8 hp_slot, struct controller *ctrl) return 0; } -u8 pciehp_handle_switch_change(u8 hp_slot, struct controller *ctrl) +u8 pciehp_handle_switch_change(struct slot *p_slot) { - struct slot *p_slot; u8 getstatus; u32 event_type; /* Switch Change */ dbg("pciehp: Switch interrupt received.\n"); - p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); - if (getstatus) { /* * Switch opened @@ -107,17 +101,14 @@ u8 pciehp_handle_switch_change(u8 hp_slot, struct controller *ctrl) return 1; } -u8 pciehp_handle_presence_change(u8 hp_slot, struct controller *ctrl) +u8 pciehp_handle_presence_change(struct slot *p_slot) { - struct slot *p_slot; u32 event_type; u8 presence_save; /* Presence Change */ dbg("pciehp: Presence/Notify input change.\n"); - p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); - /* Switch is open, assume a presence change * Save the presence state */ @@ -141,16 +132,13 @@ u8 pciehp_handle_presence_change(u8 hp_slot, struct controller *ctrl) return 1; } -u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl) +u8 pciehp_handle_power_fault(struct slot *p_slot) { - struct slot *p_slot; u32 event_type; /* power fault */ dbg("pciehp: Power fault interrupt received.\n"); - p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); - if ( !(p_slot->hpc_ops->query_power_fault(p_slot))) { /* * power fault Cleared @@ -163,7 +151,7 @@ u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl) */ info("Power fault on Slot(%s)\n", p_slot->name); event_type = INT_POWER_FAULT; - info("power fault bit %x set\n", hp_slot); + info("power fault bit %x set\n", 0); } queue_interrupt_event(p_slot, event_type); @@ -186,6 +174,13 @@ static void set_slot_off(struct controller *ctrl, struct slot * pslot) } } + /* + * After turning power off, we must wait for at least 1 second + * before taking any action that relies on power having been + * removed from the slot/adapter. + */ + msleep(1000); + if (PWR_LED(ctrl)) pslot->hpc_ops->green_led_off(pslot); @@ -289,6 +284,13 @@ static int remove_board(struct slot *p_slot) } } + /* + * After turning power off, we must wait for at least 1 second + * before taking any action that relies on power having been + * removed from the slot/adapter. + */ + msleep(1000); + if (PWR_LED(ctrl)) /* turn off Green LED */ p_slot->hpc_ops->green_led_off(p_slot); diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 891f81a0400c..79f104963166 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -247,14 +247,38 @@ static inline void pciehp_free_irq(struct controller *ctrl) free_irq(ctrl->pci_dev->irq, ctrl); } -static inline int pcie_wait_cmd(struct controller *ctrl) +static inline int pcie_poll_cmd(struct controller *ctrl) +{ + u16 slot_status; + int timeout = 1000; + + if (!pciehp_readw(ctrl, SLOTSTATUS, &slot_status)) + if (slot_status & CMD_COMPLETED) + goto completed; + for (timeout = 1000; timeout > 0; timeout -= 100) { + msleep(100); + if (!pciehp_readw(ctrl, SLOTSTATUS, &slot_status)) + if (slot_status & CMD_COMPLETED) + goto completed; + } + return 0; /* timeout */ + +completed: + pciehp_writew(ctrl, SLOTSTATUS, CMD_COMPLETED); + return timeout; +} + +static inline int pcie_wait_cmd(struct controller *ctrl, int poll) { int retval = 0; unsigned int msecs = pciehp_poll_mode ? 2500 : 1000; unsigned long timeout = msecs_to_jiffies(msecs); int rc; - rc = wait_event_interruptible_timeout(ctrl->queue, + if (poll) + rc = pcie_poll_cmd(ctrl); + else + rc = wait_event_interruptible_timeout(ctrl->queue, !ctrl->cmd_busy, timeout); if (!rc) dbg("Command not completed in 1000 msec\n"); @@ -286,12 +310,28 @@ static int pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask) goto out; } - if ((slot_status & CMD_COMPLETED) == CMD_COMPLETED ) { - /* After 1 sec and CMD_COMPLETED still not set, just - proceed forward to issue the next command according - to spec. Just print out the error message */ - dbg("%s: CMD_COMPLETED not clear after 1 sec.\n", - __func__); + if (slot_status & CMD_COMPLETED) { + if (!ctrl->no_cmd_complete) { + /* + * After 1 sec and CMD_COMPLETED still not set, just + * proceed forward to issue the next command according + * to spec. Just print out the error message. + */ + dbg("%s: CMD_COMPLETED not clear after 1 sec.\n", + __func__); + } else if (!NO_CMD_CMPL(ctrl)) { + /* + * This controller semms to notify of command completed + * event even though it supports none of power + * controller, attention led, power led and EMI. + */ + dbg("%s: Unexpected CMD_COMPLETED. Need to wait for " + "command completed event.\n", __func__); + ctrl->no_cmd_complete = 0; + } else { + dbg("%s: Unexpected CMD_COMPLETED. Maybe the " + "controller is broken.\n", __func__); + } } retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); @@ -315,8 +355,18 @@ static int pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask) /* * Wait for command completion. */ - if (!retval) - retval = pcie_wait_cmd(ctrl); + if (!retval && !ctrl->no_cmd_complete) { + int poll = 0; + /* + * if hotplug interrupt is not enabled or command + * completed interrupt is not enabled, we need to poll + * command completed event. + */ + if (!(slot_ctrl & HP_INTR_ENABLE) || + !(slot_ctrl & CMD_CMPL_INTR_ENABLE)) + poll = 1; + retval = pcie_wait_cmd(ctrl, poll); + } out: mutex_unlock(&ctrl->ctrl_lock); return retval; @@ -704,13 +754,6 @@ static int hpc_power_off_slot(struct slot * slot) } dbg("%s: SLOTCTRL %x write cmd %x\n", __func__, ctrl->cap_base + SLOTCTRL, slot_cmd); - - /* - * After turning power off, we must wait for at least 1 second - * before taking any action that relies on power having been - * removed from the slot/adapter. - */ - msleep(1000); out: if (changed) pcie_unmask_bad_dllp(ctrl); @@ -722,6 +765,7 @@ static irqreturn_t pcie_isr(int irq, void *dev_id) { struct controller *ctrl = (struct controller *)dev_id; u16 detected, intr_loc; + struct slot *p_slot; /* * In order to guarantee that all interrupt events are @@ -756,21 +800,38 @@ static irqreturn_t pcie_isr(int irq, void *dev_id) wake_up_interruptible(&ctrl->queue); } + if (!(intr_loc & ~CMD_COMPLETED)) + return IRQ_HANDLED; + + /* + * Return without handling events if this handler routine is + * called before controller initialization is done. This may + * happen if hotplug event or another interrupt that shares + * the IRQ with pciehp arrives before slot initialization is + * done after interrupt handler is registered. + * + * FIXME - Need more structural fixes. We need to be ready to + * handle the event before installing interrupt handler. + */ + p_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset); + if (!p_slot || !p_slot->hpc_ops) + return IRQ_HANDLED; + /* Check MRL Sensor Changed */ if (intr_loc & MRL_SENS_CHANGED) - pciehp_handle_switch_change(0, ctrl); + pciehp_handle_switch_change(p_slot); /* Check Attention Button Pressed */ if (intr_loc & ATTN_BUTTN_PRESSED) - pciehp_handle_attention_button(0, ctrl); + pciehp_handle_attention_button(p_slot); /* Check Presence Detect Changed */ if (intr_loc & PRSN_DETECT_CHANGED) - pciehp_handle_presence_change(0, ctrl); + pciehp_handle_presence_change(p_slot); /* Check Power Fault Detected */ if (intr_loc & PWR_FAULT_DETECTED) - pciehp_handle_power_fault(0, ctrl); + pciehp_handle_power_fault(p_slot); return IRQ_HANDLED; } @@ -1028,6 +1089,12 @@ static int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev) static int pcie_init_hardware_part1(struct controller *ctrl, struct pcie_device *dev) { + /* Clear all remaining event bits in Slot Status register */ + if (pciehp_writew(ctrl, SLOTSTATUS, 0x1f)) { + err("%s: Cannot write to SLOTSTATUS register\n", __func__); + return -1; + } + /* Mask Hot-plug Interrupt Enable */ if (pcie_write_cmd(ctrl, 0, HP_INTR_ENABLE | CMD_CMPL_INTR_ENABLE)) { err("%s: Cannot mask hotplug interrupt enable\n", __func__); @@ -1040,16 +1107,6 @@ int pcie_init_hardware_part2(struct controller *ctrl, struct pcie_device *dev) { u16 cmd, mask; - /* - * We need to clear all events before enabling hotplug interrupt - * notification mechanism in order for hotplug controler to - * generate interrupts. - */ - if (pciehp_writew(ctrl, SLOTSTATUS, 0x1f)) { - err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__); - return -1; - } - cmd = PRSN_DETECT_ENABLE; if (ATTN_BUTTN(ctrl)) cmd |= ATTN_BUTTN_ENABLE; @@ -1116,6 +1173,7 @@ static inline void dbg_ctrl(struct controller *ctrl) dbg(" Power Indicator : %3s\n", PWR_LED(ctrl) ? "yes" : "no"); dbg(" Hot-Plug Surprise : %3s\n", HP_SUPR_RM(ctrl) ? "yes" : "no"); dbg(" EMI Present : %3s\n", EMI(ctrl) ? "yes" : "no"); + dbg(" Comamnd Completed : %3s\n", NO_CMD_CMPL(ctrl)? "no" : "yes"); pciehp_readw(ctrl, SLOTSTATUS, ®16); dbg("Slot Status : 0x%04x\n", reg16); pciehp_readw(ctrl, SLOTSTATUS, ®16); @@ -1147,6 +1205,15 @@ int pcie_init(struct controller *ctrl, struct pcie_device *dev) mutex_init(&ctrl->ctrl_lock); init_waitqueue_head(&ctrl->queue); dbg_ctrl(ctrl); + /* + * Controller doesn't notify of command completion if the "No + * Command Completed Support" bit is set in Slot Capability + * register or the controller supports none of power + * controller, attention led, power led and EMI. + */ + if (NO_CMD_CMPL(ctrl) || + !(POWER_CTRL(ctrl) | ATTN_LED(ctrl) | PWR_LED(ctrl) | EMI(ctrl))) + ctrl->no_cmd_complete = 1; info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device, diff --git a/drivers/pci/hotplug/rpadlpar_sysfs.c b/drivers/pci/hotplug/rpadlpar_sysfs.c index e32148a8fa12..779c5db71be4 100644 --- a/drivers/pci/hotplug/rpadlpar_sysfs.c +++ b/drivers/pci/hotplug/rpadlpar_sysfs.c @@ -18,8 +18,12 @@ #include "rpadlpar.h" #define DLPAR_KOBJ_NAME "control" -#define ADD_SLOT_ATTR_NAME "add_slot" -#define REMOVE_SLOT_ATTR_NAME "remove_slot" + +/* Those two have no quotes because they are passed to __ATTR() which + * stringifies the argument (yuck !) + */ +#define ADD_SLOT_ATTR_NAME add_slot +#define REMOVE_SLOT_ATTR_NAME remove_slot #define MAX_DRC_NAME_LEN 64 diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c index 1648076600fc..97848654652a 100644 --- a/drivers/pci/hotplug/shpchp_core.c +++ b/drivers/pci/hotplug/shpchp_core.c @@ -162,6 +162,10 @@ static int init_slots(struct controller *ctrl) retval = pci_hp_register(slot->hotplug_slot); if (retval) { err("pci_hp_register failed with error %d\n", retval); + if (retval == -EEXIST) + err("Failed to register slot because of name " + "collision. Try \'shpchp_slot_with_bus\' " + "module option.\n"); goto error_info; } diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 61fedb2448b6..f82495583e63 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -506,6 +506,23 @@ static void free_link_state(struct pci_dev *pdev) pdev->link_state = NULL; } +static int pcie_aspm_sanity_check(struct pci_dev *pdev) +{ + struct pci_dev *child_dev; + int child_pos; + + /* + * Some functions in a slot might not all be PCIE functions, very + * strange. Disable ASPM for the whole slot + */ + list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) { + child_pos = pci_find_capability(child_dev, PCI_CAP_ID_EXP); + if (!child_pos) + return -EINVAL; + } + return 0; +} + /* * pcie_aspm_init_link_state: Initiate PCI express link state. * It is called after the pcie and its children devices are scaned. @@ -526,6 +543,9 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev) if (list_empty(&pdev->subordinate->devices)) goto out; + if (pcie_aspm_sanity_check(pdev)) + goto out; + mutex_lock(&aspm_lock); link_state = kzalloc(sizeof(*link_state), GFP_KERNEL); diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index f2d9c770f51a..dabb563f51d9 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -1503,8 +1503,7 @@ static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f, struct pci_f (f->device == dev->device || f->device == (u16) PCI_ANY_ID)) { #ifdef DEBUG dev_dbg(&dev->dev, "calling "); - print_fn_descriptor_symbol("%s()\n", - (unsigned long) f->hook); + print_fn_descriptor_symbol("%s\n", f->hook); #endif f->hook(dev); } diff --git a/drivers/pcmcia/electra_cf.c b/drivers/pcmcia/electra_cf.c index 0a6cea1316b4..52d0aa8c2e7a 100644 --- a/drivers/pcmcia/electra_cf.c +++ b/drivers/pcmcia/electra_cf.c @@ -352,6 +352,7 @@ static struct of_device_id electra_cf_match[] = { }, {}, }; +MODULE_DEVICE_TABLE(of, electra_cf_match); static struct of_platform_driver electra_cf_driver = { .name = (char *)driver_name, diff --git a/drivers/pnp/quirks.c b/drivers/pnp/quirks.c index ffdb12a59c40..e2b7de4cb05e 100644 --- a/drivers/pnp/quirks.c +++ b/drivers/pnp/quirks.c @@ -331,8 +331,7 @@ void pnp_fixup_device(struct pnp_dev *dev) continue; #ifdef DEBUG dev_dbg(&dev->dev, "%s: calling ", f->id); - print_fn_descriptor_symbol("%s\n", - (unsigned long) f->quirk_function); + print_fn_descriptor_symbol("%s\n", f->quirk_function); #endif f->quirk_function(dev); } diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c index 138dd76ee347..af1633eb3b70 100644 --- a/drivers/power/power_supply_core.c +++ b/drivers/power/power_supply_core.c @@ -91,15 +91,13 @@ int power_supply_register(struct device *parent, struct power_supply *psy) { int rc = 0; - psy->dev = device_create(power_supply_class, parent, 0, - "%s", psy->name); + psy->dev = device_create_drvdata(power_supply_class, parent, 0, + psy, "%s", psy->name); if (IS_ERR(psy->dev)) { rc = PTR_ERR(psy->dev); goto dev_create_failed; } - dev_set_drvdata(psy->dev, psy); - INIT_WORK(&psy->changed_work, power_supply_changed_work); rc = power_supply_create_attrs(psy); diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index ac6d4d3218b3..1a4025683362 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -63,6 +63,7 @@ static void dasd_return_cqr_cb(struct dasd_ccw_req *, void *); */ static wait_queue_head_t dasd_init_waitq; static wait_queue_head_t dasd_flush_wq; +static wait_queue_head_t generic_waitq; /* * Allocate memory for a new device structure. @@ -925,6 +926,8 @@ static void dasd_handle_killed_request(struct ccw_device *cdev, struct dasd_ccw_req *cqr; struct dasd_device *device; + if (!intparm) + return; cqr = (struct dasd_ccw_req *) intparm; if (cqr->status != DASD_CQR_IN_IO) { MESSAGE(KERN_DEBUG, @@ -976,17 +979,16 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, if (IS_ERR(irb)) { switch (PTR_ERR(irb)) { case -EIO: - dasd_handle_killed_request(cdev, intparm); break; case -ETIMEDOUT: printk(KERN_WARNING"%s(%s): request timed out\n", __func__, cdev->dev.bus_id); - //FIXME - dasd uses own timeout interface... break; default: printk(KERN_WARNING"%s(%s): unknown error %ld\n", __func__, cdev->dev.bus_id, PTR_ERR(irb)); } + dasd_handle_killed_request(cdev, intparm); return; } @@ -1150,11 +1152,15 @@ static void __dasd_device_process_final_queue(struct dasd_device *device, struct list_head *l, *n; struct dasd_ccw_req *cqr; struct dasd_block *block; + void (*callback)(struct dasd_ccw_req *, void *data); + void *callback_data; list_for_each_safe(l, n, final_queue) { cqr = list_entry(l, struct dasd_ccw_req, devlist); list_del_init(&cqr->devlist); block = cqr->block; + callback = cqr->callback; + callback_data = cqr->callback_data; if (block) spin_lock_bh(&block->queue_lock); switch (cqr->status) { @@ -1175,7 +1181,7 @@ static void __dasd_device_process_final_queue(struct dasd_device *device, BUG(); } if (cqr->callback != NULL) - (cqr->callback)(cqr, cqr->callback_data); + (callback)(cqr, callback_data); if (block) spin_unlock_bh(&block->queue_lock); } @@ -1405,17 +1411,15 @@ static inline int _wait_for_wakeup(struct dasd_ccw_req *cqr) */ int dasd_sleep_on(struct dasd_ccw_req *cqr) { - wait_queue_head_t wait_q; struct dasd_device *device; int rc; device = cqr->startdev; - init_waitqueue_head (&wait_q); cqr->callback = dasd_wakeup_cb; - cqr->callback_data = (void *) &wait_q; + cqr->callback_data = (void *) &generic_waitq; dasd_add_request_tail(cqr); - wait_event(wait_q, _wait_for_wakeup(cqr)); + wait_event(generic_waitq, _wait_for_wakeup(cqr)); /* Request status is either done or failed. */ rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO; @@ -1428,20 +1432,18 @@ int dasd_sleep_on(struct dasd_ccw_req *cqr) */ int dasd_sleep_on_interruptible(struct dasd_ccw_req *cqr) { - wait_queue_head_t wait_q; struct dasd_device *device; int rc; device = cqr->startdev; - init_waitqueue_head (&wait_q); cqr->callback = dasd_wakeup_cb; - cqr->callback_data = (void *) &wait_q; + cqr->callback_data = (void *) &generic_waitq; dasd_add_request_tail(cqr); - rc = wait_event_interruptible(wait_q, _wait_for_wakeup(cqr)); + rc = wait_event_interruptible(generic_waitq, _wait_for_wakeup(cqr)); if (rc == -ERESTARTSYS) { dasd_cancel_req(cqr); /* wait (non-interruptible) for final status */ - wait_event(wait_q, _wait_for_wakeup(cqr)); + wait_event(generic_waitq, _wait_for_wakeup(cqr)); } rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO; return rc; @@ -1465,7 +1467,6 @@ static inline int _dasd_term_running_cqr(struct dasd_device *device) int dasd_sleep_on_immediatly(struct dasd_ccw_req *cqr) { - wait_queue_head_t wait_q; struct dasd_device *device; int rc; @@ -1477,9 +1478,8 @@ int dasd_sleep_on_immediatly(struct dasd_ccw_req *cqr) return rc; } - init_waitqueue_head (&wait_q); cqr->callback = dasd_wakeup_cb; - cqr->callback_data = (void *) &wait_q; + cqr->callback_data = (void *) &generic_waitq; cqr->status = DASD_CQR_QUEUED; list_add(&cqr->devlist, &device->ccw_queue); @@ -1488,7 +1488,7 @@ int dasd_sleep_on_immediatly(struct dasd_ccw_req *cqr) spin_unlock_irq(get_ccwdev_lock(device->cdev)); - wait_event(wait_q, _wait_for_wakeup(cqr)); + wait_event(generic_waitq, _wait_for_wakeup(cqr)); /* Request status is either done or failed. */ rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO; @@ -2429,6 +2429,7 @@ static int __init dasd_init(void) init_waitqueue_head(&dasd_init_waitq); init_waitqueue_head(&dasd_flush_wq); + init_waitqueue_head(&generic_waitq); /* register 'common' DASD debug area, used for all DBF_XXX calls */ dasd_debug_area = debug_register("dasd", 1, 1, 8 * sizeof(long)); diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index f4fb40257348..d774e79476fe 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c @@ -86,10 +86,10 @@ static DEFINE_SPINLOCK(dasd_devmap_lock); static struct list_head dasd_hashlists[256]; int dasd_max_devindex; -static struct dasd_devmap *dasd_add_busid(char *, int); +static struct dasd_devmap *dasd_add_busid(const char *, int); static inline int -dasd_hash_busid(char *bus_id) +dasd_hash_busid(const char *bus_id) { int hash, i; @@ -394,7 +394,7 @@ dasd_parse(void) * devices. */ static struct dasd_devmap * -dasd_add_busid(char *bus_id, int features) +dasd_add_busid(const char *bus_id, int features) { struct dasd_devmap *devmap, *new, *tmp; int hash; @@ -430,7 +430,7 @@ dasd_add_busid(char *bus_id, int features) * Find devmap for device with given bus_id. */ static struct dasd_devmap * -dasd_find_busid(char *bus_id) +dasd_find_busid(const char *bus_id) { struct dasd_devmap *devmap, *tmp; int hash; @@ -452,7 +452,7 @@ dasd_find_busid(char *bus_id) * Check if busid has been added to the list of dasd ranges. */ int -dasd_busid_known(char *bus_id) +dasd_busid_known(const char *bus_id) { return IS_ERR(dasd_find_busid(bus_id)) ? -ENOENT : 0; } diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index 6c624bf44617..fb2f931cf844 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h @@ -598,7 +598,7 @@ struct dasd_device *dasd_device_from_cdev_locked(struct ccw_device *); struct dasd_device *dasd_device_from_devindex(int); int dasd_parse(void); -int dasd_busid_known(char *); +int dasd_busid_known(const char *); /* externals in dasd_gendisk.c */ int dasd_gendisk_init(void); diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c index 0d98f1ff2edd..848ef7e8523f 100644 --- a/drivers/s390/char/raw3270.c +++ b/drivers/s390/char/raw3270.c @@ -549,7 +549,6 @@ raw3270_start_init(struct raw3270 *rp, struct raw3270_view *view, struct raw3270_request *rq) { unsigned long flags; - wait_queue_head_t wq; int rc; #ifdef CONFIG_TN3270_CONSOLE @@ -566,20 +565,20 @@ raw3270_start_init(struct raw3270 *rp, struct raw3270_view *view, return rq->rc; } #endif - init_waitqueue_head(&wq); rq->callback = raw3270_wake_init; - rq->callback_data = &wq; + rq->callback_data = &raw3270_wait_queue; spin_lock_irqsave(get_ccwdev_lock(view->dev->cdev), flags); rc = __raw3270_start(rp, view, rq); spin_unlock_irqrestore(get_ccwdev_lock(view->dev->cdev), flags); if (rc) return rc; /* Now wait for the completion. */ - rc = wait_event_interruptible(wq, raw3270_request_final(rq)); + rc = wait_event_interruptible(raw3270_wait_queue, + raw3270_request_final(rq)); if (rc == -ERESTARTSYS) { /* Interrupted by a signal. */ raw3270_halt_io(view->dev, rq); /* No wait for the halt to complete. */ - wait_event(wq, raw3270_request_final(rq)); + wait_event(raw3270_wait_queue, raw3270_request_final(rq)); return -ERESTARTSYS; } return rq->rc; diff --git a/drivers/s390/char/sclp_config.c b/drivers/s390/char/sclp_config.c index 9e784d5f7f57..ad05a87bc480 100644 --- a/drivers/s390/char/sclp_config.c +++ b/drivers/s390/char/sclp_config.c @@ -40,7 +40,7 @@ static void sclp_cpu_capability_notify(struct work_struct *work) put_online_cpus(); } -static void sclp_cpu_change_notify(struct work_struct *work) +static void __ref sclp_cpu_change_notify(struct work_struct *work) { smp_rescan_cpus(); } diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c index 35707c04e613..62576af36f47 100644 --- a/drivers/s390/char/sclp_vt220.c +++ b/drivers/s390/char/sclp_vt220.c @@ -71,9 +71,6 @@ static struct list_head sclp_vt220_outqueue; /* Number of requests in outqueue */ static int sclp_vt220_outqueue_count; -/* Wait queue used to delay write requests while we've run out of buffers */ -static wait_queue_head_t sclp_vt220_waitq; - /* Timer used for delaying write requests to merge subsequent messages into * a single buffer */ static struct timer_list sclp_vt220_timer; @@ -133,7 +130,6 @@ sclp_vt220_process_queue(struct sclp_vt220_request *request) } while (request && __sclp_vt220_emit(request)); if (request == NULL && sclp_vt220_flush_later) sclp_vt220_emit_current(); - wake_up(&sclp_vt220_waitq); /* Check if the tty needs a wake up call */ if (sclp_vt220_tty != NULL) { tty_wakeup(sclp_vt220_tty); @@ -383,7 +379,7 @@ sclp_vt220_timeout(unsigned long data) */ static int __sclp_vt220_write(const unsigned char *buf, int count, int do_schedule, - int convertlf, int may_schedule) + int convertlf, int may_fail) { unsigned long flags; void *page; @@ -395,15 +391,14 @@ __sclp_vt220_write(const unsigned char *buf, int count, int do_schedule, overall_written = 0; spin_lock_irqsave(&sclp_vt220_lock, flags); do { - /* Create a sclp output buffer if none exists yet */ + /* Create an sclp output buffer if none exists yet */ if (sclp_vt220_current_request == NULL) { while (list_empty(&sclp_vt220_empty)) { spin_unlock_irqrestore(&sclp_vt220_lock, flags); - if (in_interrupt() || !may_schedule) - sclp_sync_wait(); + if (may_fail) + goto out; else - wait_event(sclp_vt220_waitq, - !list_empty(&sclp_vt220_empty)); + sclp_sync_wait(); spin_lock_irqsave(&sclp_vt220_lock, flags); } page = (void *) sclp_vt220_empty.next; @@ -437,6 +432,7 @@ __sclp_vt220_write(const unsigned char *buf, int count, int do_schedule, add_timer(&sclp_vt220_timer); } spin_unlock_irqrestore(&sclp_vt220_lock, flags); +out: return overall_written; } @@ -520,19 +516,11 @@ sclp_vt220_close(struct tty_struct *tty, struct file *filp) * character to the tty device. If the kernel uses this routine, * it must call the flush_chars() routine (if defined) when it is * done stuffing characters into the driver. - * - * NOTE: include/linux/tty_driver.h specifies that a character should be - * ignored if there is no room in the queue. This driver implements a different - * semantic in that it will block when there is no more room left. - * - * FIXME: putchar can currently be called from BH and other non blocking - * handlers so this semantic isn't a good idea. */ static int sclp_vt220_put_char(struct tty_struct *tty, unsigned char ch) { - __sclp_vt220_write(&ch, 1, 0, 0, 1); - return 1; + return __sclp_vt220_write(&ch, 1, 0, 0, 1); } /* @@ -653,7 +641,6 @@ static int __init __sclp_vt220_init(void) spin_lock_init(&sclp_vt220_lock); INIT_LIST_HEAD(&sclp_vt220_empty); INIT_LIST_HEAD(&sclp_vt220_outqueue); - init_waitqueue_head(&sclp_vt220_waitq); init_timer(&sclp_vt220_timer); sclp_vt220_current_request = NULL; sclp_vt220_buffered_chars = 0; diff --git a/drivers/s390/char/tape.h b/drivers/s390/char/tape.h index dddf8d62c153..d0d565a05dfe 100644 --- a/drivers/s390/char/tape.h +++ b/drivers/s390/char/tape.h @@ -231,6 +231,9 @@ struct tape_device { /* Request queue. */ struct list_head req_queue; + /* Request wait queue. */ + wait_queue_head_t wait_queue; + /* Each tape device has (currently) two minor numbers. */ int first_minor; diff --git a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c index ddc4a114e7f4..95da72bc17e8 100644 --- a/drivers/s390/char/tape_block.c +++ b/drivers/s390/char/tape_block.c @@ -179,11 +179,11 @@ tapeblock_requeue(struct work_struct *work) { tapeblock_end_request(req, -EIO); continue; } + blkdev_dequeue_request(req); + nr_queued++; spin_unlock_irq(&device->blk_data.request_queue_lock); rc = tapeblock_start_request(device, req); spin_lock_irq(&device->blk_data.request_queue_lock); - blkdev_dequeue_request(req); - nr_queued++; } spin_unlock_irq(&device->blk_data.request_queue_lock); atomic_set(&device->blk_data.requeue_scheduled, 0); diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c index 7ad8cf157641..c20e3c548343 100644 --- a/drivers/s390/char/tape_core.c +++ b/drivers/s390/char/tape_core.c @@ -76,32 +76,9 @@ const char *tape_op_verbose[TO_SIZE] = [TO_KEKL_QUERY] = "KLQ",[TO_RDC] = "RDC", }; -static int -busid_to_int(char *bus_id) +static int devid_to_int(struct ccw_dev_id *dev_id) { - int dec; - int d; - char * s; - - for(s = bus_id, d = 0; *s != '\0' && *s != '.'; s++) - d = (d * 10) + (*s - '0'); - dec = d; - for(s++, d = 0; *s != '\0' && *s != '.'; s++) - d = (d * 10) + (*s - '0'); - dec = (dec << 8) + d; - - for(s++; *s != '\0'; s++) { - if (*s >= '0' && *s <= '9') { - d = *s - '0'; - } else if (*s >= 'a' && *s <= 'f') { - d = *s - 'a' + 10; - } else { - d = *s - 'A' + 10; - } - dec = (dec << 4) + d; - } - - return dec; + return dev_id->devno + (dev_id->ssid << 16); } /* @@ -472,6 +449,7 @@ tape_alloc_device(void) INIT_LIST_HEAD(&device->req_queue); INIT_LIST_HEAD(&device->node); init_waitqueue_head(&device->state_change_wq); + init_waitqueue_head(&device->wait_queue); device->tape_state = TS_INIT; device->medium_state = MS_UNKNOWN; *device->modeset_byte = 0; @@ -551,6 +529,7 @@ tape_generic_probe(struct ccw_device *cdev) { struct tape_device *device; int ret; + struct ccw_dev_id dev_id; device = tape_alloc_device(); if (IS_ERR(device)) @@ -565,7 +544,8 @@ tape_generic_probe(struct ccw_device *cdev) cdev->dev.driver_data = device; cdev->handler = __tape_do_irq; device->cdev = cdev; - device->cdev_id = busid_to_int(cdev->dev.bus_id); + ccw_device_get_id(cdev, &dev_id); + device->cdev_id = devid_to_int(&dev_id); PRINT_INFO("tape device %s found\n", cdev->dev.bus_id); return ret; } @@ -975,21 +955,19 @@ __tape_wake_up(struct tape_request *request, void *data) int tape_do_io(struct tape_device *device, struct tape_request *request) { - wait_queue_head_t wq; int rc; - init_waitqueue_head(&wq); spin_lock_irq(get_ccwdev_lock(device->cdev)); /* Setup callback */ request->callback = __tape_wake_up; - request->callback_data = &wq; + request->callback_data = &device->wait_queue; /* Add request to request queue and try to start it. */ rc = __tape_start_request(device, request); spin_unlock_irq(get_ccwdev_lock(device->cdev)); if (rc) return rc; /* Request added to the queue. Wait for its completion. */ - wait_event(wq, (request->callback == NULL)); + wait_event(device->wait_queue, (request->callback == NULL)); /* Get rc from request */ return request->rc; } @@ -1010,20 +988,19 @@ int tape_do_io_interruptible(struct tape_device *device, struct tape_request *request) { - wait_queue_head_t wq; int rc; - init_waitqueue_head(&wq); spin_lock_irq(get_ccwdev_lock(device->cdev)); /* Setup callback */ request->callback = __tape_wake_up_interruptible; - request->callback_data = &wq; + request->callback_data = &device->wait_queue; rc = __tape_start_request(device, request); spin_unlock_irq(get_ccwdev_lock(device->cdev)); if (rc) return rc; /* Request added to the queue. Wait for its completion. */ - rc = wait_event_interruptible(wq, (request->callback == NULL)); + rc = wait_event_interruptible(device->wait_queue, + (request->callback == NULL)); if (rc != -ERESTARTSYS) /* Request finished normally. */ return request->rc; @@ -1036,7 +1013,7 @@ tape_do_io_interruptible(struct tape_device *device, /* Wait for the interrupt that acknowledges the halt. */ do { rc = wait_event_interruptible( - wq, + device->wait_queue, (request->callback == NULL) ); } while (rc == -ERESTARTSYS); diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c index d364e0bfae12..2c2428cc05d8 100644 --- a/drivers/s390/char/vmlogrdr.c +++ b/drivers/s390/char/vmlogrdr.c @@ -762,10 +762,10 @@ static int vmlogrdr_register_device(struct vmlogrdr_priv_t *priv) device_unregister(dev); return ret; } - priv->class_device = device_create(vmlogrdr_class, dev, - MKDEV(vmlogrdr_major, - priv->minor_num), - "%s", dev->bus_id); + priv->class_device = device_create_drvdata(vmlogrdr_class, dev, + MKDEV(vmlogrdr_major, + priv->minor_num), + priv, "%s", dev->bus_id); if (IS_ERR(priv->class_device)) { ret = PTR_ERR(priv->class_device); priv->class_device=NULL; @@ -773,7 +773,6 @@ static int vmlogrdr_register_device(struct vmlogrdr_priv_t *priv) device_unregister(dev); return ret; } - dev->driver_data = priv; priv->device = dev; return 0; } @@ -858,7 +857,7 @@ static int __init vmlogrdr_init(void) for (i=0; i < MAXMINOR; ++i ) { sys_ser[i].buffer = (char *) get_zeroed_page(GFP_KERNEL); if (!sys_ser[i].buffer) { - rc = ENOMEM; + rc = -ENOMEM; break; } sys_ser[i].current_position = sys_ser[i].buffer; diff --git a/drivers/s390/cio/blacklist.c b/drivers/s390/cio/blacklist.c index 9c21b8f43f9b..a4a5f2efea48 100644 --- a/drivers/s390/cio/blacklist.c +++ b/drivers/s390/cio/blacklist.c @@ -19,7 +19,6 @@ #include <asm/cio.h> #include <asm/uaccess.h> -#include <asm/cio.h> #include "blacklist.h" #include "cio.h" diff --git a/drivers/s390/cio/device_pgid.c b/drivers/s390/cio/device_pgid.c index ba559053402e..5cf7be008e98 100644 --- a/drivers/s390/cio/device_pgid.c +++ b/drivers/s390/cio/device_pgid.c @@ -243,16 +243,10 @@ __ccw_device_do_pgid(struct ccw_device *cdev, __u8 func) /* Setup sense path group id channel program. */ cdev->private->pgid[0].inf.fc = func; ccw = cdev->private->iccws; - if (!cdev->private->flags.pgid_single) { - cdev->private->pgid[0].inf.fc |= SPID_FUNC_MULTI_PATH; - ccw->cmd_code = CCW_CMD_SUSPEND_RECONN; - ccw->cda = 0; - ccw->count = 0; - ccw->flags = CCW_FLAG_SLI | CCW_FLAG_CC; - ccw++; - } else + if (cdev->private->flags.pgid_single) cdev->private->pgid[0].inf.fc |= SPID_FUNC_SINGLE_PATH; - + else + cdev->private->pgid[0].inf.fc |= SPID_FUNC_MULTI_PATH; ccw->cmd_code = CCW_CMD_SET_PGID; ccw->cda = (__u32) __pa (&cdev->private->pgid[0]); ccw->count = sizeof (struct pgid); diff --git a/drivers/s390/kvm/kvm_virtio.c b/drivers/s390/kvm/kvm_virtio.c index 47a7e6200b26..5ab34340919b 100644 --- a/drivers/s390/kvm/kvm_virtio.c +++ b/drivers/s390/kvm/kvm_virtio.c @@ -31,11 +31,6 @@ */ static void *kvm_devices; -/* - * Unique numbering for kvm devices. - */ -static unsigned int dev_index; - struct kvm_device { struct virtio_device vdev; struct kvm_device_desc *desc; @@ -78,27 +73,32 @@ static unsigned desc_size(const struct kvm_device_desc *desc) + desc->config_len; } -/* - * This tests (and acknowleges) a feature bit. - */ -static bool kvm_feature(struct virtio_device *vdev, unsigned fbit) +/* This gets the device's feature bits. */ +static u32 kvm_get_features(struct virtio_device *vdev) { + unsigned int i; + u32 features = 0; struct kvm_device_desc *desc = to_kvmdev(vdev)->desc; - u8 *features; + u8 *in_features = kvm_vq_features(desc); - if (fbit / 8 > desc->feature_len) - return false; + for (i = 0; i < min(desc->feature_len * 8, 32); i++) + if (in_features[i / 8] & (1 << (i % 8))) + features |= (1 << i); + return features; +} - features = kvm_vq_features(desc); - if (!(features[fbit / 8] & (1 << (fbit % 8)))) - return false; +static void kvm_set_features(struct virtio_device *vdev, u32 features) +{ + unsigned int i; + struct kvm_device_desc *desc = to_kvmdev(vdev)->desc; + /* Second half of bitmap is features we accept. */ + u8 *out_features = kvm_vq_features(desc) + desc->feature_len; - /* - * We set the matching bit in the other half of the bitmap to tell the - * Host we want to use this feature. - */ - features[desc->feature_len + fbit / 8] |= (1 << (fbit % 8)); - return true; + memset(out_features, 0, desc->feature_len); + for (i = 0; i < min(desc->feature_len * 8, 32); i++) { + if (features & (1 << i)) + out_features[i / 8] |= (1 << (i % 8)); + } } /* @@ -221,7 +221,8 @@ static void kvm_del_vq(struct virtqueue *vq) * The config ops structure as defined by virtio config */ static struct virtio_config_ops kvm_vq_configspace_ops = { - .feature = kvm_feature, + .get_features = kvm_get_features, + .set_features = kvm_set_features, .get = kvm_get, .set = kvm_set, .get_status = kvm_get_status, @@ -244,26 +245,25 @@ static struct device kvm_root = { * adds a new device and register it with virtio * appropriate drivers are loaded by the device model */ -static void add_kvm_device(struct kvm_device_desc *d) +static void add_kvm_device(struct kvm_device_desc *d, unsigned int offset) { struct kvm_device *kdev; kdev = kzalloc(sizeof(*kdev), GFP_KERNEL); if (!kdev) { - printk(KERN_EMERG "Cannot allocate kvm dev %u\n", - dev_index++); + printk(KERN_EMERG "Cannot allocate kvm dev %u type %u\n", + offset, d->type); return; } kdev->vdev.dev.parent = &kvm_root; - kdev->vdev.index = dev_index++; kdev->vdev.id.device = d->type; kdev->vdev.config = &kvm_vq_configspace_ops; kdev->desc = d; if (register_virtio_device(&kdev->vdev) != 0) { - printk(KERN_ERR "Failed to register kvm device %u\n", - kdev->vdev.index); + printk(KERN_ERR "Failed to register kvm device %u type %u\n", + offset, d->type); kfree(kdev); } } @@ -283,7 +283,7 @@ static void scan_devices(void) if (d->type == 0) break; - add_kvm_device(d); + add_kvm_device(d, i); } } diff --git a/drivers/sbus/char/bpp.c b/drivers/sbus/char/bpp.c index b87037ec9805..03c966059471 100644 --- a/drivers/sbus/char/bpp.c +++ b/drivers/sbus/char/bpp.c @@ -869,7 +869,7 @@ static void probeLptPort(unsigned idx) instances[idx].mode = COMPATIBILITY; instances[idx].run_length = 0; instances[idx].run_flag = 0; - if (!request_region(lpAddr,3, dev_name)) return; + if (!request_region(lpAddr,3, bpp_dev_name)) return; /* * First, make sure the instance exists. Do this by writing to @@ -1021,7 +1021,7 @@ static int __init bpp_init(void) if (rc == 0) return -ENODEV; - rc = register_chrdev(BPP_MAJOR, dev_name, &bpp_fops); + rc = register_chrdev(BPP_MAJOR, bpp_dev_name, &bpp_fops); if (rc < 0) return rc; @@ -1037,7 +1037,7 @@ static void __exit bpp_cleanup(void) { unsigned idx; - unregister_chrdev(BPP_MAJOR, dev_name); + unregister_chrdev(BPP_MAJOR, bpp_dev_name); for (idx = 0; idx < BPP_NO; idx++) { if (instances[idx].present) diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c index b31faeccb9cd..867f6fd5c2c0 100644 --- a/drivers/scsi/3w-9xxx.c +++ b/drivers/scsi/3w-9xxx.c @@ -1278,7 +1278,7 @@ static irqreturn_t twa_interrupt(int irq, void *dev_instance) error = 0; /* Check for command packet errors */ if (full_command_packet->command.newcommand.status != 0) { - if (tw_dev->srb[request_id] != 0) { + if (tw_dev->srb[request_id] != NULL) { error = twa_fill_sense(tw_dev, request_id, 1, 1); } else { /* Skip ioctl error prints */ @@ -1290,7 +1290,7 @@ static irqreturn_t twa_interrupt(int irq, void *dev_instance) /* Check for correct state */ if (tw_dev->state[request_id] != TW_S_POSTED) { - if (tw_dev->srb[request_id] != 0) { + if (tw_dev->srb[request_id] != NULL) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1a, "Received a request id that wasn't posted"); TW_CLEAR_ALL_INTERRUPTS(tw_dev); goto twa_interrupt_bail; @@ -1298,7 +1298,7 @@ static irqreturn_t twa_interrupt(int irq, void *dev_instance) } /* Check for internal command completion */ - if (tw_dev->srb[request_id] == 0) { + if (tw_dev->srb[request_id] == NULL) { if (request_id != tw_dev->chrdev_request_id) { if (twa_aen_complete(tw_dev, request_id)) TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1b, "Error completing AEN during attention interrupt"); diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c index 1dca1775f4b1..0899cb61e3dd 100644 --- a/drivers/scsi/aha152x.c +++ b/drivers/scsi/aha152x.c @@ -3582,7 +3582,7 @@ static int checksetup(struct aha152x_setup *setup) if (i == ARRAY_SIZE(ports)) return 0; - if ( request_region(setup->io_port, IO_RANGE, "aha152x")==0 ) { + if (!request_region(setup->io_port, IO_RANGE, "aha152x")) { printk(KERN_ERR "aha152x: io port 0x%x busy.\n", setup->io_port); return 0; } @@ -3842,7 +3842,7 @@ static int __init aha152x_init(void) if ((setup_count == 1) && (setup[0].io_port == ports[i])) continue; - if ( request_region(ports[i], IO_RANGE, "aha152x")==0 ) { + if (!request_region(ports[i], IO_RANGE, "aha152x")) { printk(KERN_ERR "aha152x: io port 0x%x busy.\n", ports[i]); continue; } diff --git a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c index db6de5e6afb3..7d311541c76c 100644 --- a/drivers/scsi/atp870u.c +++ b/drivers/scsi/atp870u.c @@ -747,7 +747,7 @@ static void send_s870(struct atp_unit *dev,unsigned char c) dev->quhd[c] = 0; } workreq = dev->quereq[c][dev->quhd[c]]; - if (dev->id[c][scmd_id(workreq)].curr_req == 0) { + if (dev->id[c][scmd_id(workreq)].curr_req == NULL) { dev->id[c][scmd_id(workreq)].curr_req = workreq; dev->last_cmd[c] = scmd_id(workreq); goto cmd_subp; diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c index 75c84d7b9ce8..c4b938bc30d3 100644 --- a/drivers/scsi/ch.c +++ b/drivers/scsi/ch.c @@ -910,9 +910,9 @@ static int ch_probe(struct device *dev) ch->minor = minor; sprintf(ch->name,"ch%d",ch->minor); - class_dev = device_create(ch_sysfs_class, dev, - MKDEV(SCSI_CHANGER_MAJOR,ch->minor), - "s%s", ch->name); + class_dev = device_create_drvdata(ch_sysfs_class, dev, + MKDEV(SCSI_CHANGER_MAJOR, ch->minor), + ch, "s%s", ch->name); if (IS_ERR(class_dev)) { printk(KERN_WARNING "ch%d: device_create failed\n", ch->minor); @@ -926,7 +926,6 @@ static int ch_probe(struct device *dev) if (init) ch_init_elem(ch); - dev_set_drvdata(dev, ch); sdev_printk(KERN_INFO, sd, "Attached scsi changer %s\n", ch->name); return 0; diff --git a/drivers/scsi/hptiop.c b/drivers/scsi/hptiop.c index aaa48e0c8ed0..da876d3924be 100644 --- a/drivers/scsi/hptiop.c +++ b/drivers/scsi/hptiop.c @@ -444,7 +444,7 @@ static void __iomem *hptiop_map_pci_bar(struct hptiop_hba *hba, int index) if (!(pci_resource_flags(pcidev, index) & IORESOURCE_MEM)) { printk(KERN_ERR "scsi%d: pci resource invalid\n", hba->host->host_no); - return 0; + return NULL; } mem_base_phy = pci_resource_start(pcidev, index); @@ -454,7 +454,7 @@ static void __iomem *hptiop_map_pci_bar(struct hptiop_hba *hba, int index) if (!mem_base_virt) { printk(KERN_ERR "scsi%d: Fail to ioremap memory space\n", hba->host->host_no); - return 0; + return NULL; } return mem_base_virt; } @@ -476,11 +476,11 @@ static void hptiop_unmap_pci_bar_itl(struct hptiop_hba *hba) static int hptiop_map_pci_bar_mv(struct hptiop_hba *hba) { hba->u.mv.regs = hptiop_map_pci_bar(hba, 0); - if (hba->u.mv.regs == 0) + if (hba->u.mv.regs == NULL) return -1; hba->u.mv.mu = hptiop_map_pci_bar(hba, 2); - if (hba->u.mv.mu == 0) { + if (hba->u.mv.mu == NULL) { iounmap(hba->u.mv.regs); return -1; } @@ -1210,8 +1210,8 @@ static void hptiop_remove(struct pci_dev *pcidev) static struct hptiop_adapter_ops hptiop_itl_ops = { .iop_wait_ready = iop_wait_ready_itl, - .internal_memalloc = 0, - .internal_memfree = 0, + .internal_memalloc = NULL, + .internal_memfree = NULL, .map_pci_bar = hptiop_map_pci_bar_itl, .unmap_pci_bar = hptiop_unmap_pci_bar_itl, .enable_intr = hptiop_enable_intr_itl, diff --git a/drivers/scsi/mac_esp.c b/drivers/scsi/mac_esp.c index cd37bd69a115..887682a24e36 100644 --- a/drivers/scsi/mac_esp.c +++ b/drivers/scsi/mac_esp.c @@ -650,7 +650,7 @@ static void __exit mac_esp_exit(void) MODULE_DESCRIPTION("Mac ESP SCSI driver"); MODULE_AUTHOR("Finn Thain <fthain@telegraphics.com.au>"); -MODULE_LICENSE("GPLv2"); +MODULE_LICENSE("GPL v2"); MODULE_VERSION(DRV_VERSION); module_init(mac_esp_init); diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c index 31f7aec44d90..243d8becd30f 100644 --- a/drivers/scsi/osst.c +++ b/drivers/scsi/osst.c @@ -5695,13 +5695,12 @@ static int osst_sysfs_add(dev_t dev, struct device *device, struct osst_tape * S struct device *osst_member; int err; - osst_member = device_create(osst_sysfs_class, device, dev, "%s", name); + osst_member = device_create_drvdata(osst_sysfs_class, device, dev, STp, "%s", name); if (IS_ERR(osst_member)) { printk(KERN_WARNING "osst :W: Unable to add sysfs class member %s\n", name); return PTR_ERR(osst_member); } - dev_set_drvdata(osst_member, STp); err = device_create_file(osst_member, &dev_attr_ADR_rev); if (err) goto err_out; diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index 51e2f299dbbb..3754ab87f89a 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -2811,7 +2811,7 @@ qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp) /* Check for room in outstanding command list. */ for (cnt = 0; cnt < MAX_OUTSTANDING_COMMANDS && - ha->outstanding_cmds[cnt] != 0; cnt++); + ha->outstanding_cmds[cnt] != NULL; cnt++); if (cnt >= MAX_OUTSTANDING_COMMANDS) { status = 1; diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index c9d7f721b9e2..ea0edd1b2e76 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -1441,17 +1441,18 @@ sg_add(struct device *cl_dev, struct class_interface *cl_intf) if (sg_sysfs_valid) { struct device *sg_class_member; - sg_class_member = device_create(sg_sysfs_class, cl_dev->parent, - MKDEV(SCSI_GENERIC_MAJOR, - sdp->index), - "%s", disk->disk_name); + sg_class_member = device_create_drvdata(sg_sysfs_class, + cl_dev->parent, + MKDEV(SCSI_GENERIC_MAJOR, + sdp->index), + sdp, + "%s", disk->disk_name); if (IS_ERR(sg_class_member)) { printk(KERN_ERR "sg_add: " "device_create failed\n"); error = PTR_ERR(sg_class_member); goto cdev_add_err; } - dev_set_drvdata(sg_class_member, sdp); error = sysfs_create_link(&scsidp->sdev_gendev.kobj, &sg_class_member->kobj, "generic"); if (error) diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index e8db66ad0bde..6e5a5bb31311 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -4424,17 +4424,19 @@ static int do_create_class_files(struct scsi_tape *STp, int dev_num, int mode) snprintf(name, 10, "%s%s%s", rew ? "n" : "", STp->disk->disk_name, st_formats[i]); st_class_member = - device_create(st_sysfs_class, &STp->device->sdev_gendev, - MKDEV(SCSI_TAPE_MAJOR, - TAPE_MINOR(dev_num, mode, rew)), - "%s", name); + device_create_drvdata(st_sysfs_class, + &STp->device->sdev_gendev, + MKDEV(SCSI_TAPE_MAJOR, + TAPE_MINOR(dev_num, + mode, rew)), + &STp->modes[mode], + "%s", name); if (IS_ERR(st_class_member)) { printk(KERN_WARNING "st%d: device_create failed\n", dev_num); error = PTR_ERR(st_class_member); goto out; } - dev_set_drvdata(st_class_member, &STp->modes[mode]); error = device_create_file(st_class_member, &dev_attr_defined); diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index a1ca9b7bf2d5..1bc00b721e9d 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -93,7 +93,6 @@ static unsigned int nr_uarts = CONFIG_SERIAL_8250_RUNTIME_UARTS; #define CONFIG_HUB6 1 #include <asm/serial.h> - /* * SERIAL_PORT_DFNS tells us about built-in ports that have no * standard enumeration mechanism. Platforms that can find all diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c index 53fa19cf2f06..788c3559522d 100644 --- a/drivers/serial/8250_pci.c +++ b/drivers/serial/8250_pci.c @@ -2602,7 +2602,12 @@ static struct pci_device_id serial_pci_tbl[] = { { PCI_VENDOR_ID_INTASHIELD, PCI_DEVICE_ID_INTASHIELD_IS200, PCI_ANY_ID, PCI_ANY_ID, 0, 0, /* 135a.0811 */ pbn_b2_2_115200 }, - + /* + * IntaShield IS-400 + */ + { PCI_VENDOR_ID_INTASHIELD, PCI_DEVICE_ID_INTASHIELD_IS400, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, /* 135a.0dc0 */ + pbn_b2_4_115200 }, /* * Perle PCI-RAS cards */ diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 62e6eb136a3c..9bc42763623c 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -1361,7 +1361,7 @@ config SERIAL_SC26XX_CONSOLE config SERIAL_BFIN_SPORT tristate "Blackfin SPORT emulate UART (EXPERIMENTAL)" - depends on BFIN && EXPERIMENTAL + depends on BLACKFIN && EXPERIMENTAL select SERIAL_CORE help Enble support SPORT emulate UART on Blackfin series. diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c index eab032733790..53b03c629aff 100644 --- a/drivers/serial/serial_core.c +++ b/drivers/serial/serial_core.c @@ -2054,6 +2054,8 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *port) int uart_resume_port(struct uart_driver *drv, struct uart_port *port) { struct uart_state *state = drv->state + port->line; + struct device *tty_dev; + struct uart_match match = {port, drv}; mutex_lock(&state->mutex); @@ -2063,7 +2065,8 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port) return 0; } - if (!port->suspended) { + tty_dev = device_find_child(port->dev, &match, serial_match_port); + if (!port->suspended && device_may_wakeup(tty_dev)) { disable_irq_wake(port->irq); mutex_unlock(&state->mutex); return 0; diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c index 8fdafc27fce8..ce6ee92b3a1b 100644 --- a/drivers/serial/sh-sci.c +++ b/drivers/serial/sh-sci.c @@ -184,15 +184,15 @@ static void put_string(struct sci_port *sci_port, const char *buffer, int count) int h, l; c = *p++; - h = highhex(c); - l = lowhex(c); + h = hex_asc_hi(c); + l = hex_asc_lo(c); put_char(port, h); put_char(port, l); checksum += h + l; } put_char(port, '#'); - put_char(port, highhex(checksum)); - put_char(port, lowhex(checksum)); + put_char(port, hex_asc_hi(checksum)); + put_char(port, hex_asc_lo(checksum)); } while (get_char(port) != '+'); } else #endif /* CONFIG_SH_STANDARD_BIOS || CONFIG_SH_KGDB */ diff --git a/drivers/serial/sunhv.c b/drivers/serial/sunhv.c index 145c0281495d..2847336742d7 100644 --- a/drivers/serial/sunhv.c +++ b/drivers/serial/sunhv.c @@ -499,7 +499,6 @@ static void sunhv_console_write_bychar(struct console *con, const char *s, unsig } else spin_lock(&port->lock); - spin_lock_irqsave(&port->lock, flags); for (i = 0; i < n; i++) { if (*s == '\n') sunhv_console_putchar(port, '\r'); diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c index b3518ca9f04e..41620c0fb046 100644 --- a/drivers/spi/spidev.c +++ b/drivers/spi/spidev.c @@ -68,6 +68,7 @@ static unsigned long minors[N_SPI_MINORS / BITS_PER_LONG]; struct spidev_data { struct device dev; + spinlock_t spi_lock; struct spi_device *spi; struct list_head device_entry; @@ -85,12 +86,75 @@ MODULE_PARM_DESC(bufsiz, "data bytes in biggest supported SPI message"); /*-------------------------------------------------------------------------*/ +/* + * We can't use the standard synchronous wrappers for file I/O; we + * need to protect against async removal of the underlying spi_device. + */ +static void spidev_complete(void *arg) +{ + complete(arg); +} + +static ssize_t +spidev_sync(struct spidev_data *spidev, struct spi_message *message) +{ + DECLARE_COMPLETION_ONSTACK(done); + int status; + + message->complete = spidev_complete; + message->context = &done; + + spin_lock_irq(&spidev->spi_lock); + if (spidev->spi == NULL) + status = -ESHUTDOWN; + else + status = spi_async(spidev->spi, message); + spin_unlock_irq(&spidev->spi_lock); + + if (status == 0) { + wait_for_completion(&done); + status = message->status; + if (status == 0) + status = message->actual_length; + } + return status; +} + +static inline ssize_t +spidev_sync_write(struct spidev_data *spidev, size_t len) +{ + struct spi_transfer t = { + .tx_buf = spidev->buffer, + .len = len, + }; + struct spi_message m; + + spi_message_init(&m); + spi_message_add_tail(&t, &m); + return spidev_sync(spidev, &m); +} + +static inline ssize_t +spidev_sync_read(struct spidev_data *spidev, size_t len) +{ + struct spi_transfer t = { + .rx_buf = spidev->buffer, + .len = len, + }; + struct spi_message m; + + spi_message_init(&m); + spi_message_add_tail(&t, &m); + return spidev_sync(spidev, &m); +} + +/*-------------------------------------------------------------------------*/ + /* Read-only message with current device setup */ static ssize_t spidev_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) { struct spidev_data *spidev; - struct spi_device *spi; ssize_t status = 0; /* chipselect only toggles at start or end of operation */ @@ -98,10 +162,9 @@ spidev_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) return -EMSGSIZE; spidev = filp->private_data; - spi = spidev->spi; mutex_lock(&spidev->buf_lock); - status = spi_read(spi, spidev->buffer, count); + status = spidev_sync_read(spidev, count); if (status == 0) { unsigned long missing; @@ -122,7 +185,6 @@ spidev_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) { struct spidev_data *spidev; - struct spi_device *spi; ssize_t status = 0; unsigned long missing; @@ -131,12 +193,11 @@ spidev_write(struct file *filp, const char __user *buf, return -EMSGSIZE; spidev = filp->private_data; - spi = spidev->spi; mutex_lock(&spidev->buf_lock); missing = copy_from_user(spidev->buffer, buf, count); if (missing == 0) { - status = spi_write(spi, spidev->buffer, count); + status = spidev_sync_write(spidev, count); if (status == 0) status = count; } else @@ -153,7 +214,6 @@ static int spidev_message(struct spidev_data *spidev, struct spi_transfer *k_xfers; struct spi_transfer *k_tmp; struct spi_ioc_transfer *u_tmp; - struct spi_device *spi = spidev->spi; unsigned n, total; u8 *buf; int status = -EFAULT; @@ -215,7 +275,7 @@ static int spidev_message(struct spidev_data *spidev, spi_message_add_tail(k_tmp, &msg); } - status = spi_sync(spi, &msg); + status = spidev_sync(spidev, &msg); if (status < 0) goto done; @@ -269,8 +329,16 @@ spidev_ioctl(struct inode *inode, struct file *filp, if (err) return -EFAULT; + /* guard against device removal before, or while, + * we issue this ioctl. + */ spidev = filp->private_data; - spi = spidev->spi; + spin_lock_irq(&spidev->spi_lock); + spi = spi_dev_get(spidev->spi); + spin_unlock_irq(&spidev->spi_lock); + + if (spi == NULL) + return -ESHUTDOWN; switch (cmd) { /* read requests */ @@ -356,8 +424,10 @@ spidev_ioctl(struct inode *inode, struct file *filp, default: /* segmented and/or full-duplex I/O request */ if (_IOC_NR(cmd) != _IOC_NR(SPI_IOC_MESSAGE(0)) - || _IOC_DIR(cmd) != _IOC_WRITE) - return -ENOTTY; + || _IOC_DIR(cmd) != _IOC_WRITE) { + retval = -ENOTTY; + break; + } tmp = _IOC_SIZE(cmd); if ((tmp % sizeof(struct spi_ioc_transfer)) != 0) { @@ -385,6 +455,7 @@ spidev_ioctl(struct inode *inode, struct file *filp, kfree(ioc); break; } + spi_dev_put(spi); return retval; } @@ -488,6 +559,7 @@ static int spidev_probe(struct spi_device *spi) /* Initialize the driver data */ spidev->spi = spi; + spin_lock_init(&spidev->spi_lock); mutex_init(&spidev->buf_lock); INIT_LIST_HEAD(&spidev->device_entry); @@ -526,13 +598,17 @@ static int spidev_remove(struct spi_device *spi) { struct spidev_data *spidev = dev_get_drvdata(&spi->dev); - mutex_lock(&device_list_lock); + /* make sure ops on existing fds can abort cleanly */ + spin_lock_irq(&spidev->spi_lock); + spidev->spi = NULL; + spin_unlock_irq(&spidev->spi_lock); + /* prevent new opens */ + mutex_lock(&device_list_lock); list_del(&spidev->device_entry); dev_set_drvdata(&spi->dev, NULL); clear_bit(MINOR(spidev->dev.devt), minors); device_unregister(&spidev->dev); - mutex_unlock(&device_list_lock); return 0; diff --git a/drivers/ssb/driver_pcicore.c b/drivers/ssb/driver_pcicore.c index 75def13e797d..d28c53868093 100644 --- a/drivers/ssb/driver_pcicore.c +++ b/drivers/ssb/driver_pcicore.c @@ -537,12 +537,12 @@ int ssb_pcicore_dev_irqvecs_enable(struct ssb_pcicore *pc, int err = 0; u32 tmp; - might_sleep(); - if (!pdev) goto out; bus = pdev->bus; + might_sleep_if(pdev->id.coreid != SSB_DEV_PCI); + /* Enable interrupts for this device. */ if (bus->host_pci && ((pdev->id.revision >= 6) || (pdev->id.coreid == SSB_DEV_PCIE))) { diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c index 55cc7b80422a..0a12e90ad416 100644 --- a/drivers/uio/uio.c +++ b/drivers/uio/uio.c @@ -649,15 +649,14 @@ int __uio_register_device(struct module *owner, if (ret) goto err_get_minor; - idev->dev = device_create(uio_class->class, parent, - MKDEV(uio_major, idev->minor), - "uio%d", idev->minor); + idev->dev = device_create_drvdata(uio_class->class, parent, + MKDEV(uio_major, idev->minor), idev, + "uio%d", idev->minor); if (IS_ERR(idev->dev)) { printk(KERN_ERR "UIO: device register failed\n"); ret = PTR_ERR(idev->dev); goto err_device_create; } - dev_set_drvdata(idev->dev, idev); ret = uio_dev_add_attributes(idev); if (ret) diff --git a/drivers/usb/class/Kconfig b/drivers/usb/class/Kconfig index 3a9102d2591b..66f17ed88cb5 100644 --- a/drivers/usb/class/Kconfig +++ b/drivers/usb/class/Kconfig @@ -29,3 +29,14 @@ config USB_PRINTER To compile this driver as a module, choose M here: the module will be called usblp. +config USB_WDM + tristate "USB Wireless Device Management support" + depends on USB + ---help--- + This driver supports the WMC Device Management functionality + of cell phones compliant to the CDC WMC specification. You can use + AT commands over this device. + + To compile this driver as a module, choose M here: the + module will be called cdc-wdm. + diff --git a/drivers/usb/class/Makefile b/drivers/usb/class/Makefile index cc391e6c2af8..535d59a30600 100644 --- a/drivers/usb/class/Makefile +++ b/drivers/usb/class/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_USB_ACM) += cdc-acm.o obj-$(CONFIG_USB_PRINTER) += usblp.o +obj-$(CONFIG_USB_WDM) += cdc-wdm.o diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c new file mode 100644 index 000000000000..107666d4e2ec --- /dev/null +++ b/drivers/usb/class/cdc-wdm.c @@ -0,0 +1,740 @@ +/* + * cdc-wdm.c + * + * This driver supports USB CDC WCM Device Management. + * + * Copyright (c) 2007-2008 Oliver Neukum + * + * Some code taken from cdc-acm.c + * + * Released under the GPLv2. + * + * Many thanks to Carl Nordbeck + */ +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/smp_lock.h> +#include <linux/mutex.h> +#include <linux/uaccess.h> +#include <linux/bitops.h> +#include <linux/poll.h> +#include <linux/usb.h> +#include <linux/usb/cdc.h> +#include <asm/byteorder.h> +#include <asm/unaligned.h> + +/* + * Version Information + */ +#define DRIVER_VERSION "v0.02" +#define DRIVER_AUTHOR "Oliver Neukum" + +static struct usb_device_id wdm_ids[] = { + { + .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS | + USB_DEVICE_ID_MATCH_INT_SUBCLASS, + .bInterfaceClass = USB_CLASS_COMM, + .bInterfaceSubClass = USB_CDC_SUBCLASS_DMM + }, + { } +}; + +#define WDM_MINOR_BASE 176 + + +#define WDM_IN_USE 1 +#define WDM_DISCONNECTING 2 +#define WDM_RESULT 3 +#define WDM_READ 4 +#define WDM_INT_STALL 5 +#define WDM_POLL_RUNNING 6 + + +#define WDM_MAX 16 + + +static DEFINE_MUTEX(wdm_mutex); + +/* --- method tables --- */ + +struct wdm_device { + u8 *inbuf; /* buffer for response */ + u8 *outbuf; /* buffer for command */ + u8 *sbuf; /* buffer for status */ + u8 *ubuf; /* buffer for copy to user space */ + + struct urb *command; + struct urb *response; + struct urb *validity; + struct usb_interface *intf; + struct usb_ctrlrequest *orq; + struct usb_ctrlrequest *irq; + spinlock_t iuspin; + + unsigned long flags; + u16 bufsize; + u16 wMaxCommand; + u16 wMaxPacketSize; + u16 bMaxPacketSize0; + __le16 inum; + int reslength; + int length; + int read; + int count; + dma_addr_t shandle; + dma_addr_t ihandle; + struct mutex wlock; + struct mutex rlock; + wait_queue_head_t wait; + struct work_struct rxwork; + int werr; + int rerr; +}; + +static struct usb_driver wdm_driver; + +/* --- callbacks --- */ +static void wdm_out_callback(struct urb *urb) +{ + struct wdm_device *desc; + desc = urb->context; + spin_lock(&desc->iuspin); + desc->werr = urb->status; + spin_unlock(&desc->iuspin); + clear_bit(WDM_IN_USE, &desc->flags); + kfree(desc->outbuf); + wake_up(&desc->wait); +} + +static void wdm_in_callback(struct urb *urb) +{ + struct wdm_device *desc = urb->context; + int status = urb->status; + + spin_lock(&desc->iuspin); + + if (status) { + switch (status) { + case -ENOENT: + dev_dbg(&desc->intf->dev, + "nonzero urb status received: -ENOENT"); + break; + case -ECONNRESET: + dev_dbg(&desc->intf->dev, + "nonzero urb status received: -ECONNRESET"); + break; + case -ESHUTDOWN: + dev_dbg(&desc->intf->dev, + "nonzero urb status received: -ESHUTDOWN"); + break; + case -EPIPE: + err("nonzero urb status received: -EPIPE"); + break; + default: + err("Unexpected error %d", status); + break; + } + } + + desc->rerr = status; + desc->reslength = urb->actual_length; + memmove(desc->ubuf + desc->length, desc->inbuf, desc->reslength); + desc->length += desc->reslength; + wake_up(&desc->wait); + + set_bit(WDM_READ, &desc->flags); + spin_unlock(&desc->iuspin); +} + +static void wdm_int_callback(struct urb *urb) +{ + int rv = 0; + int status = urb->status; + struct wdm_device *desc; + struct usb_ctrlrequest *req; + struct usb_cdc_notification *dr; + + desc = urb->context; + req = desc->irq; + dr = (struct usb_cdc_notification *)desc->sbuf; + + if (status) { + switch (status) { + case -ESHUTDOWN: + case -ENOENT: + case -ECONNRESET: + return; /* unplug */ + case -EPIPE: + set_bit(WDM_INT_STALL, &desc->flags); + err("Stall on int endpoint"); + goto sw; /* halt is cleared in work */ + default: + err("nonzero urb status received: %d", status); + break; + } + } + + if (urb->actual_length < sizeof(struct usb_cdc_notification)) { + err("wdm_int_callback - %d bytes", urb->actual_length); + goto exit; + } + + switch (dr->bNotificationType) { + case USB_CDC_NOTIFY_RESPONSE_AVAILABLE: + dev_dbg(&desc->intf->dev, + "NOTIFY_RESPONSE_AVAILABLE received: index %d len %d", + dr->wIndex, dr->wLength); + break; + + case USB_CDC_NOTIFY_NETWORK_CONNECTION: + + dev_dbg(&desc->intf->dev, + "NOTIFY_NETWORK_CONNECTION %s network", + dr->wValue ? "connected to" : "disconnected from"); + goto exit; + default: + clear_bit(WDM_POLL_RUNNING, &desc->flags); + err("unknown notification %d received: index %d len %d", + dr->bNotificationType, dr->wIndex, dr->wLength); + goto exit; + } + + req->bRequestType = (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE); + req->bRequest = USB_CDC_GET_ENCAPSULATED_RESPONSE; + req->wValue = 0; + req->wIndex = desc->inum; + req->wLength = cpu_to_le16(desc->bMaxPacketSize0); + + usb_fill_control_urb( + desc->response, + interface_to_usbdev(desc->intf), + /* using common endpoint 0 */ + usb_rcvctrlpipe(interface_to_usbdev(desc->intf), 0), + (unsigned char *)req, + desc->inbuf, + desc->bMaxPacketSize0, + wdm_in_callback, + desc + ); + desc->response->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + spin_lock(&desc->iuspin); + clear_bit(WDM_READ, &desc->flags); + if (!test_bit(WDM_DISCONNECTING, &desc->flags)) { + rv = usb_submit_urb(desc->response, GFP_ATOMIC); + dev_dbg(&desc->intf->dev, "%s: usb_submit_urb %d", + __func__, rv); + } + spin_unlock(&desc->iuspin); + if (rv < 0) { + if (rv == -EPERM) + return; + if (rv == -ENOMEM) { +sw: + rv = schedule_work(&desc->rxwork); + if (rv) + err("Cannot schedule work"); + } + } +exit: + rv = usb_submit_urb(urb, GFP_ATOMIC); + if (rv) + err("%s - usb_submit_urb failed with result %d", + __func__, rv); + +} + +static void kill_urbs(struct wdm_device *desc) +{ + usb_kill_urb(desc->command); + usb_kill_urb(desc->validity); + usb_kill_urb(desc->response); +} + +static void free_urbs(struct wdm_device *desc) +{ + usb_free_urb(desc->validity); + usb_free_urb(desc->response); + usb_free_urb(desc->command); +} + +static void cleanup(struct wdm_device *desc) +{ + usb_buffer_free(interface_to_usbdev(desc->intf), + desc->wMaxPacketSize, + desc->sbuf, + desc->validity->transfer_dma); + usb_buffer_free(interface_to_usbdev(desc->intf), + desc->wMaxPacketSize, + desc->inbuf, + desc->response->transfer_dma); + kfree(desc->orq); + kfree(desc->irq); + kfree(desc->ubuf); + free_urbs(desc); + kfree(desc); +} + +static ssize_t wdm_write +(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + u8 *buf; + int rv = -EMSGSIZE, r, we; + struct wdm_device *desc = file->private_data; + struct usb_ctrlrequest *req; + + if (count > desc->wMaxCommand) + count = desc->wMaxCommand; + + spin_lock_irq(&desc->iuspin); + we = desc->werr; + desc->werr = 0; + spin_unlock_irq(&desc->iuspin); + if (we < 0) + return -EIO; + + r = mutex_lock_interruptible(&desc->wlock); /* concurrent writes */ + rv = -ERESTARTSYS; + if (r) + goto outnl; + + r = wait_event_interruptible(desc->wait, !test_bit(WDM_IN_USE, + &desc->flags)); + if (r < 0) + goto out; + + if (test_bit(WDM_DISCONNECTING, &desc->flags)) { + rv = -ENODEV; + goto out; + } + + desc->outbuf = buf = kmalloc(count, GFP_KERNEL); + if (!buf) { + rv = -ENOMEM; + goto out; + } + + r = copy_from_user(buf, buffer, count); + if (r > 0) { + kfree(buf); + rv = -EFAULT; + goto out; + } + + req = desc->orq; + usb_fill_control_urb( + desc->command, + interface_to_usbdev(desc->intf), + /* using common endpoint 0 */ + usb_sndctrlpipe(interface_to_usbdev(desc->intf), 0), + (unsigned char *)req, + buf, + count, + wdm_out_callback, + desc + ); + + req->bRequestType = (USB_DIR_OUT | USB_TYPE_CLASS | + USB_RECIP_INTERFACE); + req->bRequest = USB_CDC_SEND_ENCAPSULATED_COMMAND; + req->wValue = 0; + req->wIndex = desc->inum; + req->wLength = cpu_to_le16(count); + set_bit(WDM_IN_USE, &desc->flags); + + rv = usb_submit_urb(desc->command, GFP_KERNEL); + if (rv < 0) { + kfree(buf); + clear_bit(WDM_IN_USE, &desc->flags); + } else { + dev_dbg(&desc->intf->dev, "Tx URB has been submitted index=%d", + req->wIndex); + } +out: + mutex_unlock(&desc->wlock); +outnl: + return rv < 0 ? rv : count; +} + +static ssize_t wdm_read +(struct file *file, char __user *buffer, size_t count, loff_t *ppos) +{ + int rv, cntr; + int i = 0; + struct wdm_device *desc = file->private_data; + + + rv = mutex_lock_interruptible(&desc->rlock); /*concurrent reads */ + if (rv < 0) + return -ERESTARTSYS; + + if (desc->length == 0) { + desc->read = 0; +retry: + i++; + rv = wait_event_interruptible(desc->wait, + test_bit(WDM_READ, &desc->flags)); + + if (rv < 0) { + rv = -ERESTARTSYS; + goto err; + } + + spin_lock_irq(&desc->iuspin); + + if (desc->rerr) { /* read completed, error happened */ + int t = desc->rerr; + desc->rerr = 0; + spin_unlock_irq(&desc->iuspin); + err("reading had resulted in %d", t); + rv = -EIO; + goto err; + } + /* + * recheck whether we've lost the race + * against the completion handler + */ + if (!test_bit(WDM_READ, &desc->flags)) { /* lost race */ + spin_unlock_irq(&desc->iuspin); + goto retry; + } + if (!desc->reslength) { /* zero length read */ + spin_unlock_irq(&desc->iuspin); + goto retry; + } + clear_bit(WDM_READ, &desc->flags); + spin_unlock_irq(&desc->iuspin); + } + + cntr = count > desc->length ? desc->length : count; + rv = copy_to_user(buffer, desc->ubuf, cntr); + if (rv > 0) { + rv = -EFAULT; + goto err; + } + + for (i = 0; i < desc->length - cntr; i++) + desc->ubuf[i] = desc->ubuf[i + cntr]; + + desc->length -= cntr; + rv = cntr; + +err: + mutex_unlock(&desc->rlock); + if (rv < 0) + err("wdm_read: exit error"); + return rv; +} + +static int wdm_flush(struct file *file, fl_owner_t id) +{ + struct wdm_device *desc = file->private_data; + + wait_event(desc->wait, !test_bit(WDM_IN_USE, &desc->flags)); + if (desc->werr < 0) + err("Error in flush path: %d", desc->werr); + + return desc->werr; +} + +static unsigned int wdm_poll(struct file *file, struct poll_table_struct *wait) +{ + struct wdm_device *desc = file->private_data; + unsigned long flags; + unsigned int mask = 0; + + spin_lock_irqsave(&desc->iuspin, flags); + if (test_bit(WDM_DISCONNECTING, &desc->flags)) { + mask = POLLERR; + spin_unlock_irqrestore(&desc->iuspin, flags); + goto desc_out; + } + if (test_bit(WDM_READ, &desc->flags)) + mask = POLLIN | POLLRDNORM; + if (desc->rerr || desc->werr) + mask |= POLLERR; + if (!test_bit(WDM_IN_USE, &desc->flags)) + mask |= POLLOUT | POLLWRNORM; + spin_unlock_irqrestore(&desc->iuspin, flags); + + poll_wait(file, &desc->wait, wait); + +desc_out: + return mask; +} + +static int wdm_open(struct inode *inode, struct file *file) +{ + int minor = iminor(inode); + int rv = -ENODEV; + struct usb_interface *intf; + struct wdm_device *desc; + + mutex_lock(&wdm_mutex); + intf = usb_find_interface(&wdm_driver, minor); + if (!intf) + goto out; + + desc = usb_get_intfdata(intf); + if (test_bit(WDM_DISCONNECTING, &desc->flags)) + goto out; + + desc->count++; + file->private_data = desc; + + rv = usb_submit_urb(desc->validity, GFP_KERNEL); + + if (rv < 0) { + desc->count--; + err("Error submitting int urb - %d", rv); + goto out; + } + rv = 0; + +out: + mutex_unlock(&wdm_mutex); + return rv; +} + +static int wdm_release(struct inode *inode, struct file *file) +{ + struct wdm_device *desc = file->private_data; + + mutex_lock(&wdm_mutex); + desc->count--; + if (!desc->count) { + dev_dbg(&desc->intf->dev, "wdm_release: cleanup"); + kill_urbs(desc); + } + mutex_unlock(&wdm_mutex); + return 0; +} + +static const struct file_operations wdm_fops = { + .owner = THIS_MODULE, + .read = wdm_read, + .write = wdm_write, + .open = wdm_open, + .flush = wdm_flush, + .release = wdm_release, + .poll = wdm_poll +}; + +static struct usb_class_driver wdm_class = { + .name = "cdc-wdm%d", + .fops = &wdm_fops, + .minor_base = WDM_MINOR_BASE, +}; + +/* --- error handling --- */ +static void wdm_rxwork(struct work_struct *work) +{ + struct wdm_device *desc = container_of(work, struct wdm_device, rxwork); + unsigned long flags; + int rv; + + spin_lock_irqsave(&desc->iuspin, flags); + if (test_bit(WDM_DISCONNECTING, &desc->flags)) { + spin_unlock_irqrestore(&desc->iuspin, flags); + } else { + spin_unlock_irqrestore(&desc->iuspin, flags); + rv = usb_submit_urb(desc->response, GFP_KERNEL); + if (rv < 0 && rv != -EPERM) { + spin_lock_irqsave(&desc->iuspin, flags); + if (!test_bit(WDM_DISCONNECTING, &desc->flags)) + schedule_work(&desc->rxwork); + spin_unlock_irqrestore(&desc->iuspin, flags); + } + } +} + +/* --- hotplug --- */ + +static int wdm_probe(struct usb_interface *intf, const struct usb_device_id *id) +{ + int rv = -EINVAL; + struct usb_device *udev = interface_to_usbdev(intf); + struct wdm_device *desc; + struct usb_host_interface *iface; + struct usb_endpoint_descriptor *ep; + struct usb_cdc_dmm_desc *dmhd; + u8 *buffer = intf->altsetting->extra; + int buflen = intf->altsetting->extralen; + u16 maxcom = 0; + + if (!buffer) + goto out; + + while (buflen > 0) { + if (buffer [1] != USB_DT_CS_INTERFACE) { + err("skipping garbage"); + goto next_desc; + } + + switch (buffer [2]) { + case USB_CDC_HEADER_TYPE: + break; + case USB_CDC_DMM_TYPE: + dmhd = (struct usb_cdc_dmm_desc *)buffer; + maxcom = le16_to_cpu(dmhd->wMaxCommand); + dev_dbg(&intf->dev, + "Finding maximum buffer length: %d", maxcom); + break; + default: + err("Ignoring extra header, type %d, length %d", + buffer[2], buffer[0]); + break; + } +next_desc: + buflen -= buffer[0]; + buffer += buffer[0]; + } + + rv = -ENOMEM; + desc = kzalloc(sizeof(struct wdm_device), GFP_KERNEL); + if (!desc) + goto out; + mutex_init(&desc->wlock); + mutex_init(&desc->rlock); + spin_lock_init(&desc->iuspin); + init_waitqueue_head(&desc->wait); + desc->wMaxCommand = maxcom; + desc->inum = cpu_to_le16((u16)intf->cur_altsetting->desc.bInterfaceNumber); + desc->intf = intf; + INIT_WORK(&desc->rxwork, wdm_rxwork); + + iface = &intf->altsetting[0]; + ep = &iface->endpoint[0].desc; + if (!usb_endpoint_is_int_in(ep)) { + rv = -EINVAL; + goto err; + } + + desc->wMaxPacketSize = ep->wMaxPacketSize; + desc->bMaxPacketSize0 = cpu_to_le16(udev->descriptor.bMaxPacketSize0); + + desc->orq = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL); + if (!desc->orq) + goto err; + desc->irq = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL); + if (!desc->irq) + goto err; + + desc->validity = usb_alloc_urb(0, GFP_KERNEL); + if (!desc->validity) + goto err; + + desc->response = usb_alloc_urb(0, GFP_KERNEL); + if (!desc->response) + goto err; + + desc->command = usb_alloc_urb(0, GFP_KERNEL); + if (!desc->command) + goto err; + + desc->ubuf = kmalloc(desc->wMaxCommand, GFP_KERNEL); + if (!desc->ubuf) + goto err; + + desc->sbuf = usb_buffer_alloc(interface_to_usbdev(intf), + desc->wMaxPacketSize, + GFP_KERNEL, + &desc->validity->transfer_dma); + if (!desc->sbuf) + goto err; + + desc->inbuf = usb_buffer_alloc(interface_to_usbdev(intf), + desc->bMaxPacketSize0, + GFP_KERNEL, + &desc->response->transfer_dma); + if (!desc->inbuf) + goto err2; + + usb_fill_int_urb( + desc->validity, + interface_to_usbdev(intf), + usb_rcvintpipe(interface_to_usbdev(intf), ep->bEndpointAddress), + desc->sbuf, + desc->wMaxPacketSize, + wdm_int_callback, + desc, + ep->bInterval + ); + desc->validity->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + + usb_set_intfdata(intf, desc); + rv = usb_register_dev(intf, &wdm_class); + dev_info(&intf->dev, "cdc-wdm%d: USB WDM device\n", + intf->minor - WDM_MINOR_BASE); + if (rv < 0) + goto err; +out: + return rv; +err2: + usb_buffer_free(interface_to_usbdev(desc->intf), + desc->wMaxPacketSize, + desc->sbuf, + desc->validity->transfer_dma); +err: + free_urbs(desc); + kfree(desc->ubuf); + kfree(desc->orq); + kfree(desc->irq); + kfree(desc); + return rv; +} + +static void wdm_disconnect(struct usb_interface *intf) +{ + struct wdm_device *desc; + unsigned long flags; + + usb_deregister_dev(intf, &wdm_class); + mutex_lock(&wdm_mutex); + desc = usb_get_intfdata(intf); + + /* the spinlock makes sure no new urbs are generated in the callbacks */ + spin_lock_irqsave(&desc->iuspin, flags); + set_bit(WDM_DISCONNECTING, &desc->flags); + set_bit(WDM_READ, &desc->flags); + clear_bit(WDM_IN_USE, &desc->flags); + spin_unlock_irqrestore(&desc->iuspin, flags); + cancel_work_sync(&desc->rxwork); + kill_urbs(desc); + wake_up_all(&desc->wait); + if (!desc->count) + cleanup(desc); + mutex_unlock(&wdm_mutex); +} + +static struct usb_driver wdm_driver = { + .name = "cdc_wdm", + .probe = wdm_probe, + .disconnect = wdm_disconnect, + .id_table = wdm_ids, +}; + +/* --- low level module stuff --- */ + +static int __init wdm_init(void) +{ + int rv; + + rv = usb_register(&wdm_driver); + + return rv; +} + +static void __exit wdm_exit(void) +{ + usb_deregister(&wdm_driver); +} + +module_init(wdm_init); +module_exit(wdm_exit); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION("USB Abstract Control Model driver for " + "USB WCM Device Management"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c index c1cb94e9f242..7e912f21fd36 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c @@ -155,9 +155,6 @@ static int generic_probe(struct usb_device *udev) { int err, c; - /* put device-specific files into sysfs */ - usb_create_sysfs_dev_files(udev); - /* Choose and set the configuration. This registers the interfaces * with the driver core and lets interface drivers bind to them. */ @@ -189,8 +186,6 @@ static void generic_disconnect(struct usb_device *udev) * unconfigure the device */ if (udev->actconfig) usb_set_configuration(udev, -1); - - usb_remove_sysfs_dev_files(udev); } #ifdef CONFIG_PM diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index bf10e9c4195e..09a53e7f3327 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -818,12 +818,12 @@ static int usb_register_bus(struct usb_bus *bus) set_bit (busnum, busmap.busmap); bus->busnum = busnum; - bus->dev = device_create(usb_host_class, bus->controller, MKDEV(0, 0), - "usb_host%d", busnum); + bus->dev = device_create_drvdata(usb_host_class, bus->controller, + MKDEV(0, 0), bus, + "usb_host%d", busnum); result = PTR_ERR(bus->dev); if (IS_ERR(bus->dev)) goto error_create_class_dev; - dev_set_drvdata(bus->dev, bus); /* Add it to the local list of buses */ list_add (&bus->bus_list, &usb_bus_list); diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index 1e4b81e9eb50..a0bf5df6cb6f 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -213,6 +213,8 @@ struct hc_driver { /* force handover of high-speed port to full-speed companion */ void (*relinquish_port)(struct usb_hcd *, int); + /* has a port been handed over to a companion? */ + int (*port_handed_over)(struct usb_hcd *, int); }; extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb); diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index eb57fcc701d7..8eb4da332f56 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1326,6 +1326,12 @@ void usb_disconnect(struct usb_device **pdev) usb_unlock_device(udev); + /* Remove the device-specific files from sysfs. This must be + * done with udev unlocked, because some of the attribute + * routines try to acquire the device lock. + */ + usb_remove_sysfs_dev_files(udev); + /* Unregister the device. The device driver is responsible * for removing the device files from usbfs and sysfs and for * de-configuring the device. @@ -1541,6 +1547,9 @@ int usb_new_device(struct usb_device *udev) goto fail; } + /* put device-specific files into sysfs */ + usb_create_sysfs_dev_files(udev); + /* Tell the world! */ announce_device(udev); return err; @@ -2744,7 +2753,11 @@ loop: if ((status == -ENOTCONN) || (status == -ENOTSUPP)) break; } - dev_err(hub_dev, "unable to enumerate USB device on port %d\n", port1); + if (hub->hdev->parent || + !hcd->driver->port_handed_over || + !(hcd->driver->port_handed_over)(hcd, port1)) + dev_err(hub_dev, "unable to enumerate USB device on port %d\n", + port1); done: hub_port_disable(hub, port1, 1); diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 2e2019390290..3da1ab4b389d 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -47,6 +47,10 @@ static const struct usb_device_id usb_quirk_list[] = { /* Edirol SD-20 */ { USB_DEVICE(0x0582, 0x0027), .driver_info = USB_QUIRK_RESET_RESUME }, + /* Avision AV600U */ + { USB_DEVICE(0x0638, 0x0a13), .driver_info = + USB_QUIRK_STRING_FETCH_255 }, + /* M-Systems Flash Disk Pioneers */ { USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME }, diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index c783cb111847..5e1f5d55bf04 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -588,35 +588,33 @@ read_descriptors(struct kobject *kobj, struct bin_attribute *attr, container_of(kobj, struct device, kobj)); size_t nleft = count; size_t srclen, n; + int cfgno; + void *src; - usb_lock_device(udev); - - /* The binary attribute begins with the device descriptor */ - srclen = sizeof(struct usb_device_descriptor); - if (off < srclen) { - n = min_t(size_t, nleft, srclen - off); - memcpy(buf, off + (char *) &udev->descriptor, n); - nleft -= n; - buf += n; - off = 0; - } else { - off -= srclen; - } - - /* Then follows the raw descriptor entry for the current - * configuration (config plus subsidiary descriptors). + /* The binary attribute begins with the device descriptor. + * Following that are the raw descriptor entries for all the + * configurations (config plus subsidiary descriptors). */ - if (udev->actconfig) { - int cfgno = udev->actconfig - udev->config; - - srclen = __le16_to_cpu(udev->actconfig->desc.wTotalLength); + for (cfgno = -1; cfgno < udev->descriptor.bNumConfigurations && + nleft > 0; ++cfgno) { + if (cfgno < 0) { + src = &udev->descriptor; + srclen = sizeof(struct usb_device_descriptor); + } else { + src = udev->rawdescriptors[cfgno]; + srclen = __le16_to_cpu(udev->config[cfgno].desc. + wTotalLength); + } if (off < srclen) { - n = min_t(size_t, nleft, srclen - off); - memcpy(buf, off + udev->rawdescriptors[cfgno], n); + n = min(nleft, srclen - (size_t) off); + memcpy(buf, src + off, n); nleft -= n; + buf += n; + off = 0; + } else { + off -= srclen; } } - usb_unlock_device(udev); return count - nleft; } diff --git a/drivers/usb/gadget/fsl_usb2_udc.c b/drivers/usb/gadget/fsl_usb2_udc.c index 651b82701394..18687543d7fa 100644 --- a/drivers/usb/gadget/fsl_usb2_udc.c +++ b/drivers/usb/gadget/fsl_usb2_udc.c @@ -1627,7 +1627,9 @@ static int reset_queues(struct fsl_udc *udc) udc_reset_ep_queue(udc, pipe); /* report disconnect; the driver is already quiesced */ + spin_unlock(&udc->lock); udc->driver->disconnect(&udc->gadget); + spin_lock(&udc->lock); return 0; } diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c index 499b7a23f351..e02bfd4df3a6 100644 --- a/drivers/usb/gadget/pxa27x_udc.c +++ b/drivers/usb/gadget/pxa27x_udc.c @@ -1526,7 +1526,8 @@ static void udc_disable(struct pxa_udc *udc) ep0_idle(udc); udc->gadget.speed = USB_SPEED_UNKNOWN; - udc->mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT); + if (udc->mach->udc_command) + udc->mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT); } /** diff --git a/drivers/usb/host/ehci-au1xxx.c b/drivers/usb/host/ehci-au1xxx.c index 8b5f991e949c..08a4335401a9 100644 --- a/drivers/usb/host/ehci-au1xxx.c +++ b/drivers/usb/host/ehci-au1xxx.c @@ -223,6 +223,7 @@ static const struct hc_driver ehci_au1xxx_hc_driver = { .bus_suspend = ehci_bus_suspend, .bus_resume = ehci_bus_resume, .relinquish_port = ehci_relinquish_port, + .port_handed_over = ehci_port_handed_over, }; /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index 6d9bed6c1f48..7370d6187c64 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -269,7 +269,7 @@ static int ehci_fsl_setup(struct usb_hcd *hcd) if (retval) return retval; - ehci->is_tdi_rh_tt = 1; + hcd->has_tt = 1; ehci->sbrn = 0x20; @@ -295,10 +295,6 @@ static const struct hc_driver ehci_fsl_hc_driver = { */ .reset = ehci_fsl_setup, .start = ehci_run, -#ifdef CONFIG_PM - .suspend = ehci_bus_suspend, - .resume = ehci_bus_resume, -#endif .stop = ehci_stop, .shutdown = ehci_shutdown, @@ -322,6 +318,7 @@ static const struct hc_driver ehci_fsl_hc_driver = { .bus_suspend = ehci_bus_suspend, .bus_resume = ehci_bus_resume, .relinquish_port = ehci_relinquish_port, + .port_handed_over = ehci_port_handed_over, }; static int ehci_fsl_drv_probe(struct platform_device *pdev) diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 382587c4457c..740835bb8575 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -609,7 +609,7 @@ static int ehci_hub_control ( } break; case USB_PORT_FEAT_C_SUSPEND: - /* we auto-clear this feature */ + clear_bit(wIndex, &ehci->port_c_suspend); break; case USB_PORT_FEAT_POWER: if (HCS_PPC (ehci->hcs_params)) @@ -688,7 +688,7 @@ static int ehci_hub_control ( /* resume completed? */ else if (time_after_eq(jiffies, ehci->reset_done[wIndex])) { - status |= 1 << USB_PORT_FEAT_C_SUSPEND; + set_bit(wIndex, &ehci->port_c_suspend); ehci->reset_done[wIndex] = 0; /* stop resume signaling */ @@ -765,6 +765,8 @@ static int ehci_hub_control ( status |= 1 << USB_PORT_FEAT_RESET; if (temp & PORT_POWER) status |= 1 << USB_PORT_FEAT_POWER; + if (test_bit(wIndex, &ehci->port_c_suspend)) + status |= 1 << USB_PORT_FEAT_C_SUSPEND; #ifndef VERBOSE_DEBUG if (status & ~0xffff) /* only if wPortChange is interesting */ @@ -875,3 +877,13 @@ static void ehci_relinquish_port(struct usb_hcd *hcd, int portnum) set_owner(ehci, --portnum, PORT_OWNER); } +static int ehci_port_handed_over(struct usb_hcd *hcd, int portnum) +{ + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + u32 __iomem *reg; + + if (ehci_is_TDI(ehci)) + return 0; + reg = &ehci->regs->port_status[portnum - 1]; + return ehci_readl(ehci, reg) & PORT_OWNER; +} diff --git a/drivers/usb/host/ehci-ixp4xx.c b/drivers/usb/host/ehci-ixp4xx.c index 601c8795a854..9d042f220097 100644 --- a/drivers/usb/host/ehci-ixp4xx.c +++ b/drivers/usb/host/ehci-ixp4xx.c @@ -26,7 +26,7 @@ static int ixp4xx_ehci_init(struct usb_hcd *hcd) + HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase)); ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); - ehci->is_tdi_rh_tt = 1; + hcd->has_tt = 1; ehci_reset(ehci); retval = ehci_init(hcd); @@ -58,6 +58,8 @@ static const struct hc_driver ixp4xx_ehci_hc_driver = { .bus_suspend = ehci_bus_suspend, .bus_resume = ehci_bus_resume, #endif + .relinquish_port = ehci_relinquish_port, + .port_handed_over = ehci_port_handed_over, }; static int ixp4xx_ehci_probe(struct platform_device *pdev) diff --git a/drivers/usb/host/ehci-orion.c b/drivers/usb/host/ehci-orion.c index d187d0313742..ab625f0ba1d9 100644 --- a/drivers/usb/host/ehci-orion.c +++ b/drivers/usb/host/ehci-orion.c @@ -115,6 +115,8 @@ static int ehci_orion_setup(struct usb_hcd *hcd) if (retval) return retval; + hcd->has_tt = 1; + ehci_reset(ehci); ehci_port_power(ehci, 0); @@ -137,10 +139,6 @@ static const struct hc_driver ehci_orion_hc_driver = { */ .reset = ehci_orion_setup, .start = ehci_run, -#ifdef CONFIG_PM - .suspend = ehci_bus_suspend, - .resume = ehci_bus_resume, -#endif .stop = ehci_stop, .shutdown = ehci_shutdown, @@ -163,6 +161,8 @@ static const struct hc_driver ehci_orion_hc_driver = { .hub_control = ehci_hub_control, .bus_suspend = ehci_bus_suspend, .bus_resume = ehci_bus_resume, + .relinquish_port = ehci_relinquish_port, + .port_handed_over = ehci_port_handed_over, }; static void __init @@ -248,7 +248,7 @@ static int __init ehci_orion_drv_probe(struct platform_device *pdev) ehci->regs = hcd->regs + 0x100 + HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase)); ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); - ehci->is_tdi_rh_tt = 1; + hcd->has_tt = 1; ehci->sbrn = 0x20; /* diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index 5bb7f6bb13f3..c46a58f9181d 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -129,7 +129,6 @@ static int ehci_pci_setup(struct usb_hcd *hcd) switch (pdev->vendor) { case PCI_VENDOR_ID_TDI: if (pdev->device == PCI_DEVICE_ID_TDI_EHCI) { - ehci->is_tdi_rh_tt = 1; hcd->has_tt = 1; tdi_reset(ehci); } @@ -379,7 +378,8 @@ static const struct hc_driver ehci_pci_hc_driver = { .hub_control = ehci_hub_control, .bus_suspend = ehci_bus_suspend, .bus_resume = ehci_bus_resume, - .relinquish_port = ehci_relinquish_port, + .relinquish_port = ehci_relinquish_port, + .port_handed_over = ehci_port_handed_over, }; /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/ehci-ppc-of.c b/drivers/usb/host/ehci-ppc-of.c index ee305b1f99ff..b018deed2e8f 100644 --- a/drivers/usb/host/ehci-ppc-of.c +++ b/drivers/usb/host/ehci-ppc-of.c @@ -76,6 +76,8 @@ static const struct hc_driver ehci_ppc_of_hc_driver = { .bus_suspend = ehci_bus_suspend, .bus_resume = ehci_bus_resume, #endif + .relinquish_port = ehci_relinquish_port, + .port_handed_over = ehci_port_handed_over, }; diff --git a/drivers/usb/host/ehci-ppc-soc.c b/drivers/usb/host/ehci-ppc-soc.c index 6c76036783a1..529590eb4037 100644 --- a/drivers/usb/host/ehci-ppc-soc.c +++ b/drivers/usb/host/ehci-ppc-soc.c @@ -163,6 +163,7 @@ static const struct hc_driver ehci_ppc_soc_hc_driver = { .bus_suspend = ehci_bus_suspend, .bus_resume = ehci_bus_resume, .relinquish_port = ehci_relinquish_port, + .port_handed_over = ehci_port_handed_over, }; static int ehci_hcd_ppc_soc_drv_probe(struct platform_device *pdev) diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c index 69782221bcf3..37e6abeb794c 100644 --- a/drivers/usb/host/ehci-ps3.c +++ b/drivers/usb/host/ehci-ps3.c @@ -73,6 +73,7 @@ static const struct hc_driver ps3_ehci_hc_driver = { .bus_resume = ehci_bus_resume, #endif .relinquish_port = ehci_relinquish_port, + .port_handed_over = ehci_port_handed_over, }; static int ps3_ehci_probe(struct ps3_system_bus_device *dev) diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index be575e46eac3..b7853c8bac0f 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -1349,18 +1349,27 @@ iso_stream_schedule ( /* when's the last uframe this urb could start? */ max = now + mod; - /* typical case: reuse current schedule. stream is still active, - * and no gaps from host falling behind (irq delays etc) + /* Typical case: reuse current schedule, stream is still active. + * Hopefully there are no gaps from the host falling behind + * (irq delays etc), but if there are we'll take the next + * slot in the schedule, implicitly assuming URB_ISO_ASAP. */ if (likely (!list_empty (&stream->td_list))) { start = stream->next_uframe; if (start < now) start += mod; - if (likely ((start + sched->span) < max)) - goto ready; - /* else fell behind; someday, try to reschedule */ - status = -EL2NSYNC; - goto fail; + + /* Fell behind (by up to twice the slop amount)? */ + if (start >= max - 2 * 8 * SCHEDULE_SLOP) + start += stream->interval * DIV_ROUND_UP( + max - start, stream->interval) - mod; + + /* Tried to schedule too far into the future? */ + if (unlikely((start + sched->span) >= max)) { + status = -EFBIG; + goto fail; + } + goto ready; } /* need to schedule; when's the next (u)frame we could start? @@ -1613,6 +1622,9 @@ itd_complete ( } else if (likely ((t & EHCI_ISOC_ACTIVE) == 0)) { desc->status = 0; desc->actual_length = EHCI_ITD_LENGTH (t); + } else { + /* URB was too late */ + desc->status = -EXDEV; } } @@ -2095,7 +2107,7 @@ done: static void scan_periodic (struct ehci_hcd *ehci) { - unsigned frame, clock, now_uframe, mod; + unsigned now_uframe, frame, clock, clock_frame, mod; unsigned modified; mod = ehci->periodic_size << 3; @@ -2111,6 +2123,7 @@ scan_periodic (struct ehci_hcd *ehci) else clock = now_uframe + mod - 1; clock %= mod; + clock_frame = clock >> 3; for (;;) { union ehci_shadow q, *q_p; @@ -2157,22 +2170,26 @@ restart: case Q_TYPE_ITD: /* If this ITD is still active, leave it for * later processing ... check the next entry. + * No need to check for activity unless the + * frame is current. */ - rmb (); - for (uf = 0; uf < 8 && live; uf++) { - if (0 == (q.itd->hw_transaction [uf] - & ITD_ACTIVE(ehci))) - continue; - incomplete = true; - q_p = &q.itd->itd_next; - hw_p = &q.itd->hw_next; - type = Q_NEXT_TYPE(ehci, + if (frame == clock_frame && live) { + rmb(); + for (uf = 0; uf < 8; uf++) { + if (q.itd->hw_transaction[uf] & + ITD_ACTIVE(ehci)) + break; + } + if (uf < 8) { + incomplete = true; + q_p = &q.itd->itd_next; + hw_p = &q.itd->hw_next; + type = Q_NEXT_TYPE(ehci, q.itd->hw_next); - q = *q_p; - break; + q = *q_p; + break; + } } - if (uf < 8 && live) - break; /* Take finished ITDs out of the schedule * and process them: recycle, maybe report @@ -2189,9 +2206,12 @@ restart: case Q_TYPE_SITD: /* If this SITD is still active, leave it for * later processing ... check the next entry. + * No need to check for activity unless the + * frame is current. */ - if ((q.sitd->hw_results & SITD_ACTIVE(ehci)) - && live) { + if (frame == clock_frame && live && + (q.sitd->hw_results & + SITD_ACTIVE(ehci))) { incomplete = true; q_p = &q.sitd->sitd_next; hw_p = &q.sitd->hw_next; @@ -2260,6 +2280,7 @@ restart: /* rescan the rest of this frame, then ... */ clock = now; + clock_frame = clock >> 3; } else { now_uframe++; now_uframe %= mod; diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index bf92d209a1a9..35a03095757e 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -97,6 +97,8 @@ struct ehci_hcd { /* one per controller */ dedicated to the companion controller */ unsigned long owned_ports; /* which ports are owned by the companion during a bus suspend */ + unsigned long port_c_suspend; /* which ports have + the change-suspend feature turned on */ /* per-HC memory pools (could be per-bus, but ...) */ struct dma_pool *qh_pool; /* qh per active urb */ @@ -112,7 +114,6 @@ struct ehci_hcd { /* one per controller */ u32 command; /* SILICON QUIRKS */ - unsigned is_tdi_rh_tt:1; /* TDI roothub with TT */ unsigned no_selective_suspend:1; unsigned has_fsl_port_bug:1; /* FreeScale */ unsigned big_endian_mmio:1; @@ -678,7 +679,7 @@ struct ehci_fstn { * needed (mostly in root hub code). */ -#define ehci_is_TDI(e) ((e)->is_tdi_rh_tt) +#define ehci_is_TDI(e) (ehci_to_hcd(e)->has_tt) /* Returns the speed of a device attached to a port on the root hub. */ static inline unsigned int diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index a53db1d4e07a..eb6c06979f3b 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig @@ -269,3 +269,14 @@ config USB_TEST See <http://www.linux-usb.org/usbtest/> for more information, including sample test device firmware and "how to use it". +config USB_ISIGHTFW + tristate "iSight firmware loading support" + depends on USB + help + This driver loads firmware for USB Apple iSight cameras, allowing + them to be driven by the USB video class driver available at + http://linux-uvc.berlios.de + + The firmware for this driver must be extracted from the MacOS + driver beforehand. Tools for doing so are available at + http://bersace03.free.fr diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile index b68e6b774f1a..aba091cb5ec0 100644 --- a/drivers/usb/misc/Makefile +++ b/drivers/usb/misc/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_USB_EMI62) += emi62.o obj-$(CONFIG_USB_FTDI_ELAN) += ftdi-elan.o obj-$(CONFIG_USB_IDMOUSE) += idmouse.o obj-$(CONFIG_USB_IOWARRIOR) += iowarrior.o +obj-$(CONFIG_USB_ISIGHTFW) += isight_firmware.o obj-$(CONFIG_USB_LCD) += usblcd.o obj-$(CONFIG_USB_LD) += ldusb.o obj-$(CONFIG_USB_LED) += usbled.o diff --git a/drivers/usb/misc/isight_firmware.c b/drivers/usb/misc/isight_firmware.c new file mode 100644 index 000000000000..390e04885536 --- /dev/null +++ b/drivers/usb/misc/isight_firmware.c @@ -0,0 +1,131 @@ +/* + * Driver for loading USB isight firmware + * + * Copyright (C) 2008 Matthew Garrett <mjg@redhat.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, version 2. + * + * The USB isight cameras in recent Apples are roughly compatible with the USB + * video class specification, and can be driven by uvcvideo. However, they + * need firmware to be loaded beforehand. After firmware loading, the device + * detaches from the USB bus and reattaches with a new device ID. It can then + * be claimed by the uvc driver. + * + * The firmware is non-free and must be extracted by the user. Tools to do this + * are available at http://bersace03.free.fr/ift/ + * + * The isight firmware loading was reverse engineered by Johannes Berg + * <johannes@sipsolutions.de>, and this driver is based on code by Ronald + * Bultje <rbultje@ronald.bitfreak.net> + */ + +#include <linux/usb.h> +#include <linux/firmware.h> +#include <linux/errno.h> +#include <linux/module.h> + +static struct usb_device_id id_table[] = { + {USB_DEVICE(0x05ac, 0x8300)}, + {}, +}; + +MODULE_DEVICE_TABLE(usb, id_table); + +static int isight_firmware_load(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_device *dev = interface_to_usbdev(intf); + int llen, len, req, ret = 0; + const struct firmware *firmware; + unsigned char *buf; + unsigned char data[4]; + char *ptr; + + if (request_firmware(&firmware, "isight.fw", &dev->dev) != 0) { + printk(KERN_ERR "Unable to load isight firmware\n"); + return -ENODEV; + } + + ptr = firmware->data; + + if (usb_control_msg + (dev, usb_sndctrlpipe(dev, 0), 0xa0, 0x40, 0xe600, 0, "\1", 1, + 300) != 1) { + printk(KERN_ERR + "Failed to initialise isight firmware loader\n"); + ret = -ENODEV; + goto out; + } + + while (1) { + memcpy(data, ptr, 4); + len = (data[0] << 8 | data[1]); + req = (data[2] << 8 | data[3]); + ptr += 4; + + if (len == 0x8001) + break; /* success */ + else if (len == 0) + continue; + + for (; len > 0; req += 50) { + llen = len > 50 ? 50 : len; + len -= llen; + + buf = kmalloc(llen, GFP_KERNEL); + memcpy(buf, ptr, llen); + + ptr += llen; + + if (usb_control_msg + (dev, usb_sndctrlpipe(dev, 0), 0xa0, 0x40, req, 0, + buf, llen, 300) != llen) { + printk(KERN_ERR + "Failed to load isight firmware\n"); + kfree(buf); + ret = -ENODEV; + goto out; + } + + kfree(buf); + } + } + if (usb_control_msg + (dev, usb_sndctrlpipe(dev, 0), 0xa0, 0x40, 0xe600, 0, "\0", 1, + 300) != 1) { + printk(KERN_ERR "isight firmware loading completion failed\n"); + ret = -ENODEV; + } +out: + release_firmware(firmware); + return ret; +} + +static void isight_firmware_disconnect(struct usb_interface *intf) +{ +} + +static struct usb_driver isight_firmware_driver = { + .name = "isight_firmware", + .probe = isight_firmware_load, + .disconnect = isight_firmware_disconnect, + .id_table = id_table, +}; + +static int __init isight_firmware_init(void) +{ + return usb_register(&isight_firmware_driver); +} + +static void __exit isight_firmware_exit(void) +{ + usb_deregister(&isight_firmware_driver); +} + +module_init(isight_firmware_init); +module_exit(isight_firmware_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>"); diff --git a/drivers/usb/misc/phidgetkit.c b/drivers/usb/misc/phidgetkit.c index 24230c638b8e..4cfa25b0f44e 100644 --- a/drivers/usb/misc/phidgetkit.c +++ b/drivers/usb/misc/phidgetkit.c @@ -595,14 +595,14 @@ static int interfacekit_probe(struct usb_interface *intf, const struct usb_devic } while(value); kit->dev_no = bit; - kit->dev = device_create(phidget_class, &kit->udev->dev, 0, - "interfacekit%d", kit->dev_no); + kit->dev = device_create_drvdata(phidget_class, &kit->udev->dev, + MKDEV(0, 0), kit, + "interfacekit%d", kit->dev_no); if (IS_ERR(kit->dev)) { rc = PTR_ERR(kit->dev); kit->dev = NULL; goto out; } - dev_set_drvdata(kit->dev, kit); if (usb_submit_urb(kit->irq, GFP_KERNEL)) { rc = -EIO; diff --git a/drivers/usb/misc/phidgetmotorcontrol.c b/drivers/usb/misc/phidgetmotorcontrol.c index f0113c17cc5a..9b4696f21b22 100644 --- a/drivers/usb/misc/phidgetmotorcontrol.c +++ b/drivers/usb/misc/phidgetmotorcontrol.c @@ -365,16 +365,15 @@ static int motorcontrol_probe(struct usb_interface *intf, const struct usb_devic } while(value); mc->dev_no = bit; - mc->dev = device_create(phidget_class, &mc->udev->dev, 0, - "motorcontrol%d", mc->dev_no); + mc->dev = device_create_drvdata(phidget_class, &mc->udev->dev, + MKDEV(0, 0), mc, + "motorcontrol%d", mc->dev_no); if (IS_ERR(mc->dev)) { rc = PTR_ERR(mc->dev); mc->dev = NULL; goto out; } - dev_set_drvdata(mc->dev, mc); - if (usb_submit_urb(mc->irq, GFP_KERNEL)) { rc = -EIO; goto out; diff --git a/drivers/usb/misc/phidgetservo.c b/drivers/usb/misc/phidgetservo.c index 7d590c09434a..1ca7ddb41d4d 100644 --- a/drivers/usb/misc/phidgetservo.c +++ b/drivers/usb/misc/phidgetservo.c @@ -275,14 +275,14 @@ servo_probe(struct usb_interface *interface, const struct usb_device_id *id) } while (value); dev->dev_no = bit; - dev->dev = device_create(phidget_class, &dev->udev->dev, 0, - "servo%d", dev->dev_no); + dev->dev = device_create_drvdata(phidget_class, &dev->udev->dev, + MKDEV(0, 0), dev, + "servo%d", dev->dev_no); if (IS_ERR(dev->dev)) { rc = PTR_ERR(dev->dev); dev->dev = NULL; goto out; } - dev_set_drvdata(dev->dev, dev); servo_count = dev->type & SERVO_COUNT_QUAD ? 4 : 1; diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c index ba28fdc9ccd2..1f7c86bd8297 100644 --- a/drivers/usb/serial/ch341.c +++ b/drivers/usb/serial/ch341.c @@ -28,6 +28,7 @@ static int debug; static struct usb_device_id id_table [] = { { USB_DEVICE(0x4348, 0x5523) }, + { USB_DEVICE(0x1a86, 0x7523) }, { }, }; MODULE_DEVICE_TABLE(usb, id_table); diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 5b349ece7247..5234e7a3bd2c 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -174,8 +174,270 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_MTXORB_4_PID) }, { USB_DEVICE(FTDI_VID, FTDI_MTXORB_5_PID) }, { USB_DEVICE(FTDI_VID, FTDI_MTXORB_6_PID) }, - { USB_DEVICE(MTXORB_VK_VID, MTXORB_VK_PID), + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0100_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0101_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0102_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0103_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0104_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0105_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0106_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0107_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0108_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0109_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_010A_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_010B_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_010C_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_010D_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_010E_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_010F_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0110_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0111_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0112_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0113_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0114_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0115_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0116_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0117_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0118_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0119_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_011A_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_011B_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_011C_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_011D_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_011E_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_011F_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0120_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0121_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0122_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0123_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0124_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0125_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0126_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0127_PID), .driver_info = (kernel_ulong_t)&ftdi_mtxorb_hack_quirk }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0128_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0129_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_012A_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_012B_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_012C_PID), + .driver_info = (kernel_ulong_t)&ftdi_mtxorb_hack_quirk }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_012D_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_012E_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_012F_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0130_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0131_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0132_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0133_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0134_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0135_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0136_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0137_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0138_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0139_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_013A_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_013B_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_013C_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_013D_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_013E_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_013F_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0140_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0141_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0142_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0143_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0144_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0145_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0146_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0147_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0148_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0149_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_014A_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_014B_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_014C_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_014D_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_014E_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_014F_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0150_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0151_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0152_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0153_PID), + .driver_info = (kernel_ulong_t)&ftdi_mtxorb_hack_quirk }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0154_PID), + .driver_info = (kernel_ulong_t)&ftdi_mtxorb_hack_quirk }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0155_PID), + .driver_info = (kernel_ulong_t)&ftdi_mtxorb_hack_quirk }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0156_PID), + .driver_info = (kernel_ulong_t)&ftdi_mtxorb_hack_quirk }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0157_PID), + .driver_info = (kernel_ulong_t)&ftdi_mtxorb_hack_quirk }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0158_PID), + .driver_info = (kernel_ulong_t)&ftdi_mtxorb_hack_quirk }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0159_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_015A_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_015B_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_015C_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_015D_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_015E_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_015F_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0160_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0161_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0162_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0163_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0164_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0165_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0166_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0167_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0168_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0169_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_016A_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_016B_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_016C_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_016D_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_016E_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_016F_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0170_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0171_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0172_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0173_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0174_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0175_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0176_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0177_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0178_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0179_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_017A_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_017B_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_017C_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_017D_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_017E_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_017F_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0180_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0181_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0182_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0183_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0184_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0185_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0186_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0187_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0188_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0189_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_018A_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_018B_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_018C_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_018D_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_018E_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_018F_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0190_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0191_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0192_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0193_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0194_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0195_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0196_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0197_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0198_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0199_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_019A_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_019B_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_019C_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_019D_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_019E_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_019F_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01A0_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01A1_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01A2_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01A3_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01A4_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01A5_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01A6_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01A7_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01A8_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01A9_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01AA_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01AB_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01AC_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01AD_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01AE_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01AF_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01B0_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01B1_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01B2_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01B3_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01B4_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01B5_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01B6_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01B7_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01B8_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01B9_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01BA_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01BB_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01BC_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01BD_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01BE_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01BF_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01C0_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01C1_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01C2_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01C3_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01C4_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01C5_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01C6_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01C7_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01C8_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01C9_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01CA_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01CB_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01CC_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01CD_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01CE_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01CF_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01D0_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01D1_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01D2_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01D3_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01D4_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01D5_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01D6_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01D7_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01D8_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01D9_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01DA_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01DB_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01DC_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01DD_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01DE_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01DF_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01E0_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01E1_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01E2_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01E3_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01E4_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01E5_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01E6_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01E7_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01E8_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01E9_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01EA_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01EB_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01EC_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01ED_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01EE_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01EF_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01F0_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01F1_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01F2_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01F3_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01F4_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01F5_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01F6_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01F7_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01F8_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01F9_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01FA_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01FB_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01FC_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01FD_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01FE_PID) }, + { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01FF_PID) }, { USB_DEVICE(FTDI_VID, FTDI_PERLE_ULTRAPORT_PID) }, { USB_DEVICE(FTDI_VID, FTDI_PIEGROUP_PID) }, { USB_DEVICE(FTDI_VID, FTDI_TNC_X_PID) }, @@ -374,6 +636,7 @@ static struct usb_device_id id_table_combined [] = { .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, { USB_DEVICE(FTDI_VID, FTDI_OOCDLINK_PID), .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, + { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_USB60F) }, { }, /* Optional parameter entry */ { } /* Terminating entry */ }; diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index 504edf8c3a3f..06e0ecabb3eb 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h @@ -114,11 +114,268 @@ #define FTDI_OOCDLINK_PID 0xbaf8 /* Amontec JTAGkey */ /* - * The following are the values for the Matrix Orbital VK204-25-USB - * display, which use the FT232RL. - */ -#define MTXORB_VK_VID 0x1b3d -#define MTXORB_VK_PID 0x0158 + * The following are the values for the Matrix Orbital FTDI Range + * Anything in this range will use an FT232RL. + */ +#define MTXORB_VID 0x1B3D +#define MTXORB_FTDI_RANGE_0100_PID 0x0100 +#define MTXORB_FTDI_RANGE_0101_PID 0x0101 +#define MTXORB_FTDI_RANGE_0102_PID 0x0102 +#define MTXORB_FTDI_RANGE_0103_PID 0x0103 +#define MTXORB_FTDI_RANGE_0104_PID 0x0104 +#define MTXORB_FTDI_RANGE_0105_PID 0x0105 +#define MTXORB_FTDI_RANGE_0106_PID 0x0106 +#define MTXORB_FTDI_RANGE_0107_PID 0x0107 +#define MTXORB_FTDI_RANGE_0108_PID 0x0108 +#define MTXORB_FTDI_RANGE_0109_PID 0x0109 +#define MTXORB_FTDI_RANGE_010A_PID 0x010A +#define MTXORB_FTDI_RANGE_010B_PID 0x010B +#define MTXORB_FTDI_RANGE_010C_PID 0x010C +#define MTXORB_FTDI_RANGE_010D_PID 0x010D +#define MTXORB_FTDI_RANGE_010E_PID 0x010E +#define MTXORB_FTDI_RANGE_010F_PID 0x010F +#define MTXORB_FTDI_RANGE_0110_PID 0x0110 +#define MTXORB_FTDI_RANGE_0111_PID 0x0111 +#define MTXORB_FTDI_RANGE_0112_PID 0x0112 +#define MTXORB_FTDI_RANGE_0113_PID 0x0113 +#define MTXORB_FTDI_RANGE_0114_PID 0x0114 +#define MTXORB_FTDI_RANGE_0115_PID 0x0115 +#define MTXORB_FTDI_RANGE_0116_PID 0x0116 +#define MTXORB_FTDI_RANGE_0117_PID 0x0117 +#define MTXORB_FTDI_RANGE_0118_PID 0x0118 +#define MTXORB_FTDI_RANGE_0119_PID 0x0119 +#define MTXORB_FTDI_RANGE_011A_PID 0x011A +#define MTXORB_FTDI_RANGE_011B_PID 0x011B +#define MTXORB_FTDI_RANGE_011C_PID 0x011C +#define MTXORB_FTDI_RANGE_011D_PID 0x011D +#define MTXORB_FTDI_RANGE_011E_PID 0x011E +#define MTXORB_FTDI_RANGE_011F_PID 0x011F +#define MTXORB_FTDI_RANGE_0120_PID 0x0120 +#define MTXORB_FTDI_RANGE_0121_PID 0x0121 +#define MTXORB_FTDI_RANGE_0122_PID 0x0122 +#define MTXORB_FTDI_RANGE_0123_PID 0x0123 +#define MTXORB_FTDI_RANGE_0124_PID 0x0124 +#define MTXORB_FTDI_RANGE_0125_PID 0x0125 +#define MTXORB_FTDI_RANGE_0126_PID 0x0126 +#define MTXORB_FTDI_RANGE_0127_PID 0x0127 +#define MTXORB_FTDI_RANGE_0128_PID 0x0128 +#define MTXORB_FTDI_RANGE_0129_PID 0x0129 +#define MTXORB_FTDI_RANGE_012A_PID 0x012A +#define MTXORB_FTDI_RANGE_012B_PID 0x012B +#define MTXORB_FTDI_RANGE_012C_PID 0x012C +#define MTXORB_FTDI_RANGE_012D_PID 0x012D +#define MTXORB_FTDI_RANGE_012E_PID 0x012E +#define MTXORB_FTDI_RANGE_012F_PID 0x012F +#define MTXORB_FTDI_RANGE_0130_PID 0x0130 +#define MTXORB_FTDI_RANGE_0131_PID 0x0131 +#define MTXORB_FTDI_RANGE_0132_PID 0x0132 +#define MTXORB_FTDI_RANGE_0133_PID 0x0133 +#define MTXORB_FTDI_RANGE_0134_PID 0x0134 +#define MTXORB_FTDI_RANGE_0135_PID 0x0135 +#define MTXORB_FTDI_RANGE_0136_PID 0x0136 +#define MTXORB_FTDI_RANGE_0137_PID 0x0137 +#define MTXORB_FTDI_RANGE_0138_PID 0x0138 +#define MTXORB_FTDI_RANGE_0139_PID 0x0139 +#define MTXORB_FTDI_RANGE_013A_PID 0x013A +#define MTXORB_FTDI_RANGE_013B_PID 0x013B +#define MTXORB_FTDI_RANGE_013C_PID 0x013C +#define MTXORB_FTDI_RANGE_013D_PID 0x013D +#define MTXORB_FTDI_RANGE_013E_PID 0x013E +#define MTXORB_FTDI_RANGE_013F_PID 0x013F +#define MTXORB_FTDI_RANGE_0140_PID 0x0140 +#define MTXORB_FTDI_RANGE_0141_PID 0x0141 +#define MTXORB_FTDI_RANGE_0142_PID 0x0142 +#define MTXORB_FTDI_RANGE_0143_PID 0x0143 +#define MTXORB_FTDI_RANGE_0144_PID 0x0144 +#define MTXORB_FTDI_RANGE_0145_PID 0x0145 +#define MTXORB_FTDI_RANGE_0146_PID 0x0146 +#define MTXORB_FTDI_RANGE_0147_PID 0x0147 +#define MTXORB_FTDI_RANGE_0148_PID 0x0148 +#define MTXORB_FTDI_RANGE_0149_PID 0x0149 +#define MTXORB_FTDI_RANGE_014A_PID 0x014A +#define MTXORB_FTDI_RANGE_014B_PID 0x014B +#define MTXORB_FTDI_RANGE_014C_PID 0x014C +#define MTXORB_FTDI_RANGE_014D_PID 0x014D +#define MTXORB_FTDI_RANGE_014E_PID 0x014E +#define MTXORB_FTDI_RANGE_014F_PID 0x014F +#define MTXORB_FTDI_RANGE_0150_PID 0x0150 +#define MTXORB_FTDI_RANGE_0151_PID 0x0151 +#define MTXORB_FTDI_RANGE_0152_PID 0x0152 +#define MTXORB_FTDI_RANGE_0153_PID 0x0153 +#define MTXORB_FTDI_RANGE_0154_PID 0x0154 +#define MTXORB_FTDI_RANGE_0155_PID 0x0155 +#define MTXORB_FTDI_RANGE_0156_PID 0x0156 +#define MTXORB_FTDI_RANGE_0157_PID 0x0157 +#define MTXORB_FTDI_RANGE_0158_PID 0x0158 +#define MTXORB_FTDI_RANGE_0159_PID 0x0159 +#define MTXORB_FTDI_RANGE_015A_PID 0x015A +#define MTXORB_FTDI_RANGE_015B_PID 0x015B +#define MTXORB_FTDI_RANGE_015C_PID 0x015C +#define MTXORB_FTDI_RANGE_015D_PID 0x015D +#define MTXORB_FTDI_RANGE_015E_PID 0x015E +#define MTXORB_FTDI_RANGE_015F_PID 0x015F +#define MTXORB_FTDI_RANGE_0160_PID 0x0160 +#define MTXORB_FTDI_RANGE_0161_PID 0x0161 +#define MTXORB_FTDI_RANGE_0162_PID 0x0162 +#define MTXORB_FTDI_RANGE_0163_PID 0x0163 +#define MTXORB_FTDI_RANGE_0164_PID 0x0164 +#define MTXORB_FTDI_RANGE_0165_PID 0x0165 +#define MTXORB_FTDI_RANGE_0166_PID 0x0166 +#define MTXORB_FTDI_RANGE_0167_PID 0x0167 +#define MTXORB_FTDI_RANGE_0168_PID 0x0168 +#define MTXORB_FTDI_RANGE_0169_PID 0x0169 +#define MTXORB_FTDI_RANGE_016A_PID 0x016A +#define MTXORB_FTDI_RANGE_016B_PID 0x016B +#define MTXORB_FTDI_RANGE_016C_PID 0x016C +#define MTXORB_FTDI_RANGE_016D_PID 0x016D +#define MTXORB_FTDI_RANGE_016E_PID 0x016E +#define MTXORB_FTDI_RANGE_016F_PID 0x016F +#define MTXORB_FTDI_RANGE_0170_PID 0x0170 +#define MTXORB_FTDI_RANGE_0171_PID 0x0171 +#define MTXORB_FTDI_RANGE_0172_PID 0x0172 +#define MTXORB_FTDI_RANGE_0173_PID 0x0173 +#define MTXORB_FTDI_RANGE_0174_PID 0x0174 +#define MTXORB_FTDI_RANGE_0175_PID 0x0175 +#define MTXORB_FTDI_RANGE_0176_PID 0x0176 +#define MTXORB_FTDI_RANGE_0177_PID 0x0177 +#define MTXORB_FTDI_RANGE_0178_PID 0x0178 +#define MTXORB_FTDI_RANGE_0179_PID 0x0179 +#define MTXORB_FTDI_RANGE_017A_PID 0x017A +#define MTXORB_FTDI_RANGE_017B_PID 0x017B +#define MTXORB_FTDI_RANGE_017C_PID 0x017C +#define MTXORB_FTDI_RANGE_017D_PID 0x017D +#define MTXORB_FTDI_RANGE_017E_PID 0x017E +#define MTXORB_FTDI_RANGE_017F_PID 0x017F +#define MTXORB_FTDI_RANGE_0180_PID 0x0180 +#define MTXORB_FTDI_RANGE_0181_PID 0x0181 +#define MTXORB_FTDI_RANGE_0182_PID 0x0182 +#define MTXORB_FTDI_RANGE_0183_PID 0x0183 +#define MTXORB_FTDI_RANGE_0184_PID 0x0184 +#define MTXORB_FTDI_RANGE_0185_PID 0x0185 +#define MTXORB_FTDI_RANGE_0186_PID 0x0186 +#define MTXORB_FTDI_RANGE_0187_PID 0x0187 +#define MTXORB_FTDI_RANGE_0188_PID 0x0188 +#define MTXORB_FTDI_RANGE_0189_PID 0x0189 +#define MTXORB_FTDI_RANGE_018A_PID 0x018A +#define MTXORB_FTDI_RANGE_018B_PID 0x018B +#define MTXORB_FTDI_RANGE_018C_PID 0x018C +#define MTXORB_FTDI_RANGE_018D_PID 0x018D +#define MTXORB_FTDI_RANGE_018E_PID 0x018E +#define MTXORB_FTDI_RANGE_018F_PID 0x018F +#define MTXORB_FTDI_RANGE_0190_PID 0x0190 +#define MTXORB_FTDI_RANGE_0191_PID 0x0191 +#define MTXORB_FTDI_RANGE_0192_PID 0x0192 +#define MTXORB_FTDI_RANGE_0193_PID 0x0193 +#define MTXORB_FTDI_RANGE_0194_PID 0x0194 +#define MTXORB_FTDI_RANGE_0195_PID 0x0195 +#define MTXORB_FTDI_RANGE_0196_PID 0x0196 +#define MTXORB_FTDI_RANGE_0197_PID 0x0197 +#define MTXORB_FTDI_RANGE_0198_PID 0x0198 +#define MTXORB_FTDI_RANGE_0199_PID 0x0199 +#define MTXORB_FTDI_RANGE_019A_PID 0x019A +#define MTXORB_FTDI_RANGE_019B_PID 0x019B +#define MTXORB_FTDI_RANGE_019C_PID 0x019C +#define MTXORB_FTDI_RANGE_019D_PID 0x019D +#define MTXORB_FTDI_RANGE_019E_PID 0x019E +#define MTXORB_FTDI_RANGE_019F_PID 0x019F +#define MTXORB_FTDI_RANGE_01A0_PID 0x01A0 +#define MTXORB_FTDI_RANGE_01A1_PID 0x01A1 +#define MTXORB_FTDI_RANGE_01A2_PID 0x01A2 +#define MTXORB_FTDI_RANGE_01A3_PID 0x01A3 +#define MTXORB_FTDI_RANGE_01A4_PID 0x01A4 +#define MTXORB_FTDI_RANGE_01A5_PID 0x01A5 +#define MTXORB_FTDI_RANGE_01A6_PID 0x01A6 +#define MTXORB_FTDI_RANGE_01A7_PID 0x01A7 +#define MTXORB_FTDI_RANGE_01A8_PID 0x01A8 +#define MTXORB_FTDI_RANGE_01A9_PID 0x01A9 +#define MTXORB_FTDI_RANGE_01AA_PID 0x01AA +#define MTXORB_FTDI_RANGE_01AB_PID 0x01AB +#define MTXORB_FTDI_RANGE_01AC_PID 0x01AC +#define MTXORB_FTDI_RANGE_01AD_PID 0x01AD +#define MTXORB_FTDI_RANGE_01AE_PID 0x01AE +#define MTXORB_FTDI_RANGE_01AF_PID 0x01AF +#define MTXORB_FTDI_RANGE_01B0_PID 0x01B0 +#define MTXORB_FTDI_RANGE_01B1_PID 0x01B1 +#define MTXORB_FTDI_RANGE_01B2_PID 0x01B2 +#define MTXORB_FTDI_RANGE_01B3_PID 0x01B3 +#define MTXORB_FTDI_RANGE_01B4_PID 0x01B4 +#define MTXORB_FTDI_RANGE_01B5_PID 0x01B5 +#define MTXORB_FTDI_RANGE_01B6_PID 0x01B6 +#define MTXORB_FTDI_RANGE_01B7_PID 0x01B7 +#define MTXORB_FTDI_RANGE_01B8_PID 0x01B8 +#define MTXORB_FTDI_RANGE_01B9_PID 0x01B9 +#define MTXORB_FTDI_RANGE_01BA_PID 0x01BA +#define MTXORB_FTDI_RANGE_01BB_PID 0x01BB +#define MTXORB_FTDI_RANGE_01BC_PID 0x01BC +#define MTXORB_FTDI_RANGE_01BD_PID 0x01BD +#define MTXORB_FTDI_RANGE_01BE_PID 0x01BE +#define MTXORB_FTDI_RANGE_01BF_PID 0x01BF +#define MTXORB_FTDI_RANGE_01C0_PID 0x01C0 +#define MTXORB_FTDI_RANGE_01C1_PID 0x01C1 +#define MTXORB_FTDI_RANGE_01C2_PID 0x01C2 +#define MTXORB_FTDI_RANGE_01C3_PID 0x01C3 +#define MTXORB_FTDI_RANGE_01C4_PID 0x01C4 +#define MTXORB_FTDI_RANGE_01C5_PID 0x01C5 +#define MTXORB_FTDI_RANGE_01C6_PID 0x01C6 +#define MTXORB_FTDI_RANGE_01C7_PID 0x01C7 +#define MTXORB_FTDI_RANGE_01C8_PID 0x01C8 +#define MTXORB_FTDI_RANGE_01C9_PID 0x01C9 +#define MTXORB_FTDI_RANGE_01CA_PID 0x01CA +#define MTXORB_FTDI_RANGE_01CB_PID 0x01CB +#define MTXORB_FTDI_RANGE_01CC_PID 0x01CC +#define MTXORB_FTDI_RANGE_01CD_PID 0x01CD +#define MTXORB_FTDI_RANGE_01CE_PID 0x01CE +#define MTXORB_FTDI_RANGE_01CF_PID 0x01CF +#define MTXORB_FTDI_RANGE_01D0_PID 0x01D0 +#define MTXORB_FTDI_RANGE_01D1_PID 0x01D1 +#define MTXORB_FTDI_RANGE_01D2_PID 0x01D2 +#define MTXORB_FTDI_RANGE_01D3_PID 0x01D3 +#define MTXORB_FTDI_RANGE_01D4_PID 0x01D4 +#define MTXORB_FTDI_RANGE_01D5_PID 0x01D5 +#define MTXORB_FTDI_RANGE_01D6_PID 0x01D6 +#define MTXORB_FTDI_RANGE_01D7_PID 0x01D7 +#define MTXORB_FTDI_RANGE_01D8_PID 0x01D8 +#define MTXORB_FTDI_RANGE_01D9_PID 0x01D9 +#define MTXORB_FTDI_RANGE_01DA_PID 0x01DA +#define MTXORB_FTDI_RANGE_01DB_PID 0x01DB +#define MTXORB_FTDI_RANGE_01DC_PID 0x01DC +#define MTXORB_FTDI_RANGE_01DD_PID 0x01DD +#define MTXORB_FTDI_RANGE_01DE_PID 0x01DE +#define MTXORB_FTDI_RANGE_01DF_PID 0x01DF +#define MTXORB_FTDI_RANGE_01E0_PID 0x01E0 +#define MTXORB_FTDI_RANGE_01E1_PID 0x01E1 +#define MTXORB_FTDI_RANGE_01E2_PID 0x01E2 +#define MTXORB_FTDI_RANGE_01E3_PID 0x01E3 +#define MTXORB_FTDI_RANGE_01E4_PID 0x01E4 +#define MTXORB_FTDI_RANGE_01E5_PID 0x01E5 +#define MTXORB_FTDI_RANGE_01E6_PID 0x01E6 +#define MTXORB_FTDI_RANGE_01E7_PID 0x01E7 +#define MTXORB_FTDI_RANGE_01E8_PID 0x01E8 +#define MTXORB_FTDI_RANGE_01E9_PID 0x01E9 +#define MTXORB_FTDI_RANGE_01EA_PID 0x01EA +#define MTXORB_FTDI_RANGE_01EB_PID 0x01EB +#define MTXORB_FTDI_RANGE_01EC_PID 0x01EC +#define MTXORB_FTDI_RANGE_01ED_PID 0x01ED +#define MTXORB_FTDI_RANGE_01EE_PID 0x01EE +#define MTXORB_FTDI_RANGE_01EF_PID 0x01EF +#define MTXORB_FTDI_RANGE_01F0_PID 0x01F0 +#define MTXORB_FTDI_RANGE_01F1_PID 0x01F1 +#define MTXORB_FTDI_RANGE_01F2_PID 0x01F2 +#define MTXORB_FTDI_RANGE_01F3_PID 0x01F3 +#define MTXORB_FTDI_RANGE_01F4_PID 0x01F4 +#define MTXORB_FTDI_RANGE_01F5_PID 0x01F5 +#define MTXORB_FTDI_RANGE_01F6_PID 0x01F6 +#define MTXORB_FTDI_RANGE_01F7_PID 0x01F7 +#define MTXORB_FTDI_RANGE_01F8_PID 0x01F8 +#define MTXORB_FTDI_RANGE_01F9_PID 0x01F9 +#define MTXORB_FTDI_RANGE_01FA_PID 0x01FA +#define MTXORB_FTDI_RANGE_01FB_PID 0x01FB +#define MTXORB_FTDI_RANGE_01FC_PID 0x01FC +#define MTXORB_FTDI_RANGE_01FD_PID 0x01FD +#define MTXORB_FTDI_RANGE_01FE_PID 0x01FE +#define MTXORB_FTDI_RANGE_01FF_PID 0x01FF + + /* Interbiometrics USB I/O Board */ /* Developed for Interbiometrics by Rudolf Gugler */ @@ -592,6 +849,12 @@ #define FIC_NEO1973_DEBUG_PID 0x5118 /* + * RATOC REX-USB60F + */ +#define RATOC_VENDOR_ID 0x0584 +#define RATOC_PRODUCT_ID_USB60F 0xb020 + +/* * BmRequestType: 1100 0000b * bRequest: FTDI_E2_READ * wValue: 0 diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index e7e016e60333..43cfde83a93b 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -183,6 +183,7 @@ static int option_send_setup(struct usb_serial_port *port); #define AXESSTEL_PRODUCT_MV110H 0x1000 #define ONDA_VENDOR_ID 0x19d2 +#define ONDA_PRODUCT_MSA501HS 0x0001 #define ONDA_PRODUCT_ET502HS 0x0002 #define BANDRICH_VENDOR_ID 0x1A8D @@ -196,6 +197,9 @@ static int option_send_setup(struct usb_serial_port *port); #define MAXON_VENDOR_ID 0x16d8 +#define TELIT_VENDOR_ID 0x1bc7 +#define TELIT_PRODUCT_UC864E 0x1003 + static struct usb_device_id option_ids[] = { { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) }, { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) }, @@ -232,25 +236,25 @@ static struct usb_device_id option_ids[] = { { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_NETWORK_EX) }, { 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_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600, 0xff, 0xff, 0xff) }, { 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(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1401) }, - { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1403) }, - { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1405) }, - { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1406) }, - { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1408) }, - { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1409) }, - { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1410) }, - { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1411) }, - { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1412) }, - { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1413) }, - { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1414) }, - { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1415) }, - { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1416) }, - { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1417) }, - { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1418) }, - { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1419) }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1401, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1403, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1405, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1406, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1408, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1409, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1410, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1411, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1412, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1413, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1414, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1415, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1416, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1417, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1418, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1419, 0xff, 0xff, 0xff) }, { USB_DEVICE(AMOI_VENDOR_ID, AMOI_PRODUCT_9508) }, { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V640) }, /* Novatel Merlin V640/XV620 */ { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V620) }, /* Novatel Merlin V620/S620 */ @@ -297,13 +301,14 @@ static struct usb_device_id option_ids[] = { { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_E100A) }, { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_500A) }, { USB_DEVICE(AXESSTEL_VENDOR_ID, AXESSTEL_PRODUCT_MV110H) }, + { USB_DEVICE(ONDA_VENDOR_ID, ONDA_PRODUCT_MSA501HS) }, { USB_DEVICE(ONDA_VENDOR_ID, ONDA_PRODUCT_ET502HS) }, { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_C100_1) }, { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_C100_2) }, { USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_PRODUCT_KPC680) }, { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6613)}, /* Onda H600/ZTE MF330 */ { USB_DEVICE(MAXON_VENDOR_ID, 0x6280) }, /* BP3-USB & BP3-EXT HSDPA */ - { USB_DEVICE(0x19d2, 0x0001) }, /* Telstra NextG CDMA */ + { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UC864E) }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, option_ids); diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index c605fb68f807..103195abd417 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -56,6 +56,7 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ3) }, { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_PHAROS) }, { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_ALDIGA) }, + { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MMX) }, { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) }, { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) }, { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) }, @@ -66,7 +67,6 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID_2080) }, { USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) }, { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) }, - { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_USB60F) }, { USB_DEVICE(TRIPP_VENDOR_ID, TRIPP_PRODUCT_ID) }, { USB_DEVICE(RADIOSHACK_VENDOR_ID, RADIOSHACK_PRODUCT_ID) }, { USB_DEVICE(DCU10_VENDOR_ID, DCU10_PRODUCT_ID) }, diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h index 10cf872e5ecb..cff160abb130 100644 --- a/drivers/usb/serial/pl2303.h +++ b/drivers/usb/serial/pl2303.h @@ -14,6 +14,7 @@ #define PL2303_PRODUCT_ID_PHAROS 0xaaa0 #define PL2303_PRODUCT_ID_RSAQ3 0xaaa2 #define PL2303_PRODUCT_ID_ALDIGA 0x0611 +#define PL2303_PRODUCT_ID_MMX 0x0612 #define ATEN_VENDOR_ID 0x0557 #define ATEN_VENDOR_ID2 0x0547 @@ -36,7 +37,6 @@ #define RATOC_VENDOR_ID 0x0584 #define RATOC_PRODUCT_ID 0xb000 -#define RATOC_PRODUCT_ID_USB60F 0xb020 #define TRIPP_VENDOR_ID 0x2478 #define TRIPP_PRODUCT_ID 0x2008 diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 1b09578cbb10..45fe3663fa7f 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -405,7 +405,7 @@ UNUSUAL_DEV( 0x04a5, 0x3010, 0x0100, 0x0100, UNUSUAL_DEV( 0x04b4, 0x6830, 0x0000, 0x9999, "Cypress", "Cypress AT2LP", - US_SC_CYP_ATACB, US_PR_BULK, NULL, + US_SC_CYP_ATACB, US_PR_DEVICE, NULL, 0), #endif @@ -1522,7 +1522,7 @@ UNUSUAL_DEV( 0x0fce, 0xe031, 0x0000, 0x0000, "Sony Ericsson", "M600i", US_SC_DEVICE, US_PR_DEVICE, NULL, - US_FL_FIX_CAPACITY ), + US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ), /* Reported by Kevin Cernekee <kpc-usbdev@gelato.uiuc.edu> * Tested on hardware version 1.10. @@ -1716,10 +1716,12 @@ UNUSUAL_DEV( 0x22b8, 0x3010, 0x0001, 0x0001, /* * Patch by Pete Zaitcev <zaitcev@redhat.com> * Report by Mark Patton. Red Hat bz#208928. + * Added support for rev 0x0002 (Motorola ROKR W5) + * by Javier Smaldone <javier@smaldone.com.ar> */ -UNUSUAL_DEV( 0x22b8, 0x4810, 0x0001, 0x0001, +UNUSUAL_DEV( 0x22b8, 0x4810, 0x0001, 0x0002, "Motorola", - "RAZR V3i", + "RAZR V3i/ROKR W5", US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_CAPACITY), diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 2cdaf1ff8315..002b61b4f0f6 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -627,11 +627,9 @@ config FB_MAC select FB_CFB_IMAGEBLIT select FB_MACMODES -# bool ' Apple DAFB display support' CONFIG_FB_DAFB config FB_HP300 bool - depends on (FB = y) && HP300 - select FB_CFB_FILLRECT + depends on (FB = y) && DIO select FB_CFB_IMAGEBLIT default y diff --git a/drivers/video/amifb.c b/drivers/video/amifb.c index e6492c1048bf..05a328c11a8b 100644 --- a/drivers/video/amifb.c +++ b/drivers/video/amifb.c @@ -2261,7 +2261,7 @@ int __init amifb_init(void) amifb_setup(option); #endif if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_VIDEO)) - return -ENXIO; + return -ENODEV; /* * We request all registers starting from bplpt[0] @@ -2333,7 +2333,7 @@ default_chipset: strcat(fb_info.fix.id, "Unknown"); goto default_chipset; #else /* CONFIG_FB_AMIGA_OCS */ - err = -ENXIO; + err = -ENODEV; goto amifb_error; #endif /* CONFIG_FB_AMIGA_OCS */ break; diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c index e4bcf5376a99..bd4ac0bafecb 100644 --- a/drivers/video/aty/atyfb_base.c +++ b/drivers/video/aty/atyfb_base.c @@ -3356,7 +3356,7 @@ static int __devinit atyfb_setup_generic(struct pci_dev *pdev, struct fb_info *i info->fix.mmio_start = raddr; par->ati_regbase = ioremap(info->fix.mmio_start, 0x1000); - if (par->ati_regbase == 0) + if (par->ati_regbase == NULL) return -ENOMEM; info->fix.mmio_start += par->aux_start ? 0x400 : 0xc00; diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c index 72cd0d2f14ec..400e9264e456 100644 --- a/drivers/video/aty/radeon_base.c +++ b/drivers/video/aty/radeon_base.c @@ -2277,8 +2277,8 @@ static int __devinit radeonfb_pci_register (struct pci_dev *pdev, do { rinfo->fb_base = ioremap (rinfo->fb_base_phys, rinfo->mapped_vram); - } while ( rinfo->fb_base == 0 && - ((rinfo->mapped_vram /=2) >= MIN_MAPPED_VRAM) ); + } while (rinfo->fb_base == NULL && + ((rinfo->mapped_vram /= 2) >= MIN_MAPPED_VRAM)); if (rinfo->fb_base == NULL) { printk (KERN_ERR "radeonfb (%s): cannot map FB\n", diff --git a/drivers/video/display/display-sysfs.c b/drivers/video/display/display-sysfs.c index 35477177bef4..6ef800bdf482 100644 --- a/drivers/video/display/display-sysfs.c +++ b/drivers/video/display/display-sysfs.c @@ -26,6 +26,7 @@ #include <linux/ctype.h> #include <linux/idr.h> #include <linux/err.h> +#include <linux/kdev_t.h> static ssize_t display_show_name(struct device *dev, struct device_attribute *attr, char *buf) @@ -152,10 +153,13 @@ struct display_device *display_device_register(struct display_driver *driver, mutex_unlock(&allocated_dsp_lock); if (!ret) { - new_dev->dev = device_create(display_class, parent, 0, - "display%d", new_dev->idx); + new_dev->dev = device_create_drvdata(display_class, + parent, + MKDEV(0,0), + new_dev, + "display%d", + new_dev->idx); if (!IS_ERR(new_dev->dev)) { - dev_set_drvdata(new_dev->dev, new_dev); new_dev->parent = parent; new_dev->driver = driver; mutex_init(&new_dev->lock); diff --git a/drivers/video/dnfb.c b/drivers/video/dnfb.c index b083ea7e9c69..606da043f4b4 100644 --- a/drivers/video/dnfb.c +++ b/drivers/video/dnfb.c @@ -284,6 +284,9 @@ int __init dnfb_init(void) { int ret; + if (!MACH_IS_APOLLO) + return -ENODEV; + if (fb_get_options("dnfb", NULL)) return -ENODEV; diff --git a/drivers/video/hpfb.c b/drivers/video/hpfb.c index 2eb4fb159084..b8ebff1e8493 100644 --- a/drivers/video/hpfb.c +++ b/drivers/video/hpfb.c @@ -382,7 +382,7 @@ int __init hpfb_init(void) #define INTFBPADDR 0x560000 if (!MACH_IS_HP300) - return -ENXIO; + return -ENODEV; if (fb_get_options("hpfb", NULL)) return -ENODEV; diff --git a/drivers/video/matrox/matroxfb_base.h b/drivers/video/matrox/matroxfb_base.h index f3107ad7e545..95883236c0cd 100644 --- a/drivers/video/matrox/matroxfb_base.h +++ b/drivers/video/matrox/matroxfb_base.h @@ -200,7 +200,7 @@ static inline int mga_ioremap(unsigned long phys, unsigned long size, int flags, virt->vaddr = ioremap_nocache(phys, size); else virt->vaddr = ioremap(phys, size); - return (virt->vaddr == 0); /* 0, !0... 0, error_code in future */ + return (virt->vaddr == NULL); /* 0, !0... 0, error_code in future */ } static inline void mga_iounmap(vaddr_t va) { diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c index 48aea39c35a5..274bc93ab7d8 100644 --- a/drivers/video/pxafb.c +++ b/drivers/video/pxafb.c @@ -355,9 +355,8 @@ static int pxafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) } #ifdef CONFIG_CPU_FREQ - pr_debug("pxafb: dma period = %d ps, clock = %d kHz\n", - pxafb_display_dma_period(var), - get_clk_frequency_khz(0)); + pr_debug("pxafb: dma period = %d ps\n", + pxafb_display_dma_period(var)); #endif return 0; @@ -1352,7 +1351,6 @@ static struct pxafb_info * __init pxafb_init_fbinfo(struct device *dev) struct pxafb_info *fbi; void *addr; struct pxafb_mach_info *inf = dev->platform_data; - struct pxafb_mode_info *mode = inf->modes; /* Alloc the pxafb_info and pseudo_palette in one step */ fbi = kmalloc(sizeof(struct pxafb_info) + sizeof(u32) * 16, GFP_KERNEL); diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c index 13b38cbbe4cf..f0598961c6b0 100644 --- a/drivers/video/s3c2410fb.c +++ b/drivers/video/s3c2410fb.c @@ -1,75 +1,15 @@ -/* - * linux/drivers/video/s3c2410fb.c - * Copyright (c) Arnaud Patard, Ben Dooks +/* linux/drivers/video/s3c2410fb.c + * Copyright (c) 2004,2005 Arnaud Patard + * Copyright (c) 2004-2008 Ben Dooks + * + * S3C2410 LCD Framebuffer Driver * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive for * more details. * - * S3C2410 LCD Controller Frame Buffer Driver - * based on skeletonfb.c, sa1100fb.c and others - * - * ChangeLog - * 2005-04-07: Arnaud Patard <arnaud.patard@rtp-net.org> - * - u32 state -> pm_message_t state - * - S3C2410_{VA,SZ}_LCD -> S3C24XX - * - * 2005-03-15: Arnaud Patard <arnaud.patard@rtp-net.org> - * - Removed the ioctl - * - use readl/writel instead of __raw_writel/__raw_readl - * - * 2004-12-04: Arnaud Patard <arnaud.patard@rtp-net.org> - * - Added the possibility to set on or off the - * debugging messages - * - Replaced 0 and 1 by on or off when reading the - * /sys files - * - * 2005-03-23: Ben Dooks <ben-linux@fluff.org> - * - added non 16bpp modes - * - updated platform information for range of x/y/bpp - * - add code to ensure palette is written correctly - * - add pixel clock divisor control - * - * 2004-11-11: Arnaud Patard <arnaud.patard@rtp-net.org> - * - Removed the use of currcon as it no more exists - * - Added LCD power sysfs interface - * - * 2004-11-03: Ben Dooks <ben-linux@fluff.org> - * - minor cleanups - * - add suspend/resume support - * - s3c2410fb_setcolreg() not valid in >8bpp modes - * - removed last CONFIG_FB_S3C2410_FIXED - * - ensure lcd controller stopped before cleanup - * - added sysfs interface for backlight power - * - added mask for gpio configuration - * - ensured IRQs disabled during GPIO configuration - * - disable TPAL before enabling video - * - * 2004-09-20: Arnaud Patard <arnaud.patard@rtp-net.org> - * - Suppress command line options - * - * 2004-09-15: Arnaud Patard <arnaud.patard@rtp-net.org> - * - code cleanup - * - * 2004-09-07: Arnaud Patard <arnaud.patard@rtp-net.org> - * - Renamed from h1940fb.c to s3c2410fb.c - * - Add support for different devices - * - Backlight support - * - * 2004-09-05: Herbert Pötzl <herbert@13thfloor.at> - * - added clock (de-)allocation code - * - added fixem fbmem option - * - * 2004-07-27: Arnaud Patard <arnaud.patard@rtp-net.org> - * - code cleanup - * - added a forgotten return in h1940fb_init - * - * 2004-07-19: Herbert Pötzl <herbert@13thfloor.at> - * - code cleanup and extended debugging - * - * 2004-07-15: Arnaud Patard <arnaud.patard@rtp-net.org> - * - First version - */ + * Driver based on skeletonfb.c, sa1100fb.c and others. +*/ #include <linux/module.h> #include <linux/kernel.h> @@ -580,6 +520,27 @@ static int s3c2410fb_setcolreg(unsigned regno, return 0; } +/* s3c2410fb_lcd_enable + * + * shutdown the lcd controller + */ +static void s3c2410fb_lcd_enable(struct s3c2410fb_info *fbi, int enable) +{ + unsigned long flags; + + local_irq_save(flags); + + if (enable) + fbi->regs.lcdcon1 |= S3C2410_LCDCON1_ENVID; + else + fbi->regs.lcdcon1 &= ~S3C2410_LCDCON1_ENVID; + + writel(fbi->regs.lcdcon1, fbi->io + S3C2410_LCDCON1); + + local_irq_restore(flags); +} + + /* * s3c2410fb_blank * @blank_mode: the blank mode we want. @@ -589,9 +550,6 @@ static int s3c2410fb_setcolreg(unsigned regno, * blanking succeeded, != 0 if un-/blanking failed due to e.g. a * video mode which doesn't support it. Implements VESA suspend * and powerdown modes on hardware that supports disabling hsync/vsync: - * blank_mode == 2: suspend vsync - * blank_mode == 3: suspend hsync - * blank_mode == 4: powerdown * * Returns negative errno on error, or zero on success. * @@ -605,6 +563,12 @@ static int s3c2410fb_blank(int blank_mode, struct fb_info *info) tpal_reg += is_s3c2412(fbi) ? S3C2412_TPAL : S3C2410_TPAL; + if (blank_mode == FB_BLANK_POWERDOWN) { + s3c2410fb_lcd_enable(fbi, 0); + } else { + s3c2410fb_lcd_enable(fbi, 1); + } + if (blank_mode == FB_BLANK_UNBLANK) writel(0x0, tpal_reg); else { @@ -948,7 +912,10 @@ static int __init s3c24xxfb_probe(struct platform_device *pdev, } /* create device files */ - device_create_file(&pdev->dev, &dev_attr_debug); + ret = device_create_file(&pdev->dev, &dev_attr_debug); + if (ret) { + printk(KERN_ERR "failed to add debug attribute\n"); + } printk(KERN_INFO "fb%d: %s frame buffer device\n", fbinfo->node, fbinfo->fix.id); @@ -983,21 +950,6 @@ static int __init s3c2412fb_probe(struct platform_device *pdev) return s3c24xxfb_probe(pdev, DRV_S3C2412); } -/* s3c2410fb_stop_lcd - * - * shutdown the lcd controller - */ -static void s3c2410fb_stop_lcd(struct s3c2410fb_info *fbi) -{ - unsigned long flags; - - local_irq_save(flags); - - fbi->regs.lcdcon1 &= ~S3C2410_LCDCON1_ENVID; - writel(fbi->regs.lcdcon1, fbi->io + S3C2410_LCDCON1); - - local_irq_restore(flags); -} /* * Cleanup @@ -1010,7 +962,7 @@ static int s3c2410fb_remove(struct platform_device *pdev) unregister_framebuffer(fbinfo); - s3c2410fb_stop_lcd(info); + s3c2410fb_lcd_enable(info, 0); msleep(1); s3c2410fb_unmap_video_memory(fbinfo); @@ -1043,7 +995,7 @@ static int s3c2410fb_suspend(struct platform_device *dev, pm_message_t state) struct fb_info *fbinfo = platform_get_drvdata(dev); struct s3c2410fb_info *info = fbinfo->par; - s3c2410fb_stop_lcd(info); + s3c2410fb_lcd_enable(info, 0); /* sleep before disabling the clock, we need to ensure * the LCD DMA engine is not going to get back on the bus @@ -1118,3 +1070,5 @@ MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>, " "Ben Dooks <ben-linux@fluff.org>"); MODULE_DESCRIPTION("Framebuffer driver for the s3c2410"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:s3c2410-lcd"); +MODULE_ALIAS("platform:s3c2412-lcd"); diff --git a/drivers/video/s3c2410fb.h b/drivers/video/s3c2410fb.h index dbb73b95e2ef..9a6ba3e9d1b8 100644 --- a/drivers/video/s3c2410fb.h +++ b/drivers/video/s3c2410fb.h @@ -1,26 +1,14 @@ /* * linux/drivers/video/s3c2410fb.h - * Copyright (c) Arnaud Patard + * Copyright (c) 2004 Arnaud Patard + * + * S3C2410 LCD Framebuffer Driver * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive for * more details. * - * S3C2410 LCD Controller Frame Buffer Driver - * based on skeletonfb.c, sa1100fb.h - * - * ChangeLog - * - * 2004-12-04: Arnaud Patard <arnaud.patard@rtp-net.org> - * - Moved dprintk to s3c2410fb.c - * - * 2004-09-07: Arnaud Patard <arnaud.patard@rtp-net.org> - * - Renamed from h1940fb.h to s3c2410fb.h - * - Changed h1940 to s3c2410 - * - * 2004-07-15: Arnaud Patard <arnaud.patard@rtp-net.org> - * - First version - */ +*/ #ifndef __S3C2410FB_H #define __S3C2410FB_H diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c index 73803624c131..b9343844cd1f 100644 --- a/drivers/video/sis/sis_main.c +++ b/drivers/video/sis/sis_main.c @@ -5787,7 +5787,7 @@ sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) } else { struct sis_video_info *countvideo = card_list; ivideo->cardnumber = 1; - while((countvideo = countvideo->next) != 0) + while((countvideo = countvideo->next) != NULL) ivideo->cardnumber++; } diff --git a/drivers/video/sm501fb.c b/drivers/video/sm501fb.c index 742b5c656d66..15d4a768b1f6 100644 --- a/drivers/video/sm501fb.c +++ b/drivers/video/sm501fb.c @@ -663,14 +663,14 @@ static void sm501fb_panel_power(struct sm501fb_info *fbi, int to) sm501fb_sync_regs(fbi); mdelay(10); - if (pd->flags & SM501FB_FLAG_PANEL_USE_VBIASEN) { + if (!(pd->flags & SM501FB_FLAG_PANEL_NO_VBIASEN)) { control |= SM501_DC_PANEL_CONTROL_BIAS; /* VBIASEN */ writel(control, ctrl_reg); sm501fb_sync_regs(fbi); mdelay(10); } - if (pd->flags & SM501FB_FLAG_PANEL_USE_FPEN) { + if (!(pd->flags & SM501FB_FLAG_PANEL_NO_FPEN)) { control |= SM501_DC_PANEL_CONTROL_FPEN; writel(control, ctrl_reg); sm501fb_sync_regs(fbi); @@ -678,14 +678,14 @@ static void sm501fb_panel_power(struct sm501fb_info *fbi, int to) } } else if (!to && (control & SM501_DC_PANEL_CONTROL_VDD) != 0) { /* disable panel power */ - if (pd->flags & SM501FB_FLAG_PANEL_USE_FPEN) { + if (!(pd->flags & SM501FB_FLAG_PANEL_NO_FPEN)) { control &= ~SM501_DC_PANEL_CONTROL_FPEN; writel(control, ctrl_reg); sm501fb_sync_regs(fbi); mdelay(10); } - if (pd->flags & SM501FB_FLAG_PANEL_USE_VBIASEN) { + if (!(pd->flags & SM501FB_FLAG_PANEL_NO_VBIASEN)) { control &= ~SM501_DC_PANEL_CONTROL_BIAS; writel(control, ctrl_reg); sm501fb_sync_regs(fbi); diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c index 13866789b356..0f3c2bb7bf35 100644 --- a/drivers/virtio/virtio.c +++ b/drivers/virtio/virtio.c @@ -2,6 +2,9 @@ #include <linux/spinlock.h> #include <linux/virtio_config.h> +/* Unique numbering for virtio devices. */ +static unsigned int dev_index; + static ssize_t device_show(struct device *_d, struct device_attribute *attr, char *buf) { @@ -166,7 +169,10 @@ int register_virtio_device(struct virtio_device *dev) int err; dev->dev.bus = &virtio_bus; - sprintf(dev->dev.bus_id, "%u", dev->index); + + /* Assign a unique device index and hence name. */ + dev->index = dev_index++; + sprintf(dev->dev.bus_id, "virtio%u", dev->index); /* We always start by resetting the device, in case a previous * driver messed it up. This also tests that code path a little. */ diff --git a/drivers/virtio/virtio_pci.c b/drivers/virtio/virtio_pci.c index 27e9fc9117cd..eae7236310e4 100644 --- a/drivers/virtio/virtio_pci.c +++ b/drivers/virtio/virtio_pci.c @@ -78,9 +78,6 @@ static struct device virtio_pci_root = { .bus_id = "virtio-pci", }; -/* Unique numbering for devices under the kvm root */ -static unsigned int dev_index; - /* Convert a generic virtio device to our structure */ static struct virtio_pci_device *to_vp_device(struct virtio_device *vdev) { @@ -325,10 +322,6 @@ static int __devinit virtio_pci_probe(struct pci_dev *pci_dev, if (vp_dev == NULL) return -ENOMEM; - snprintf(vp_dev->vdev.dev.bus_id, BUS_ID_SIZE, "virtio%d", dev_index); - vp_dev->vdev.index = dev_index; - dev_index++; - vp_dev->vdev.dev.parent = &virtio_pci_root; vp_dev->vdev.config = &virtio_pci_config_ops; vp_dev->pci_dev = pci_dev; diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c index 937a49d6772c..72bf8bc09014 100644 --- a/drivers/virtio/virtio_ring.c +++ b/drivers/virtio/virtio_ring.c @@ -227,7 +227,6 @@ static bool vring_enable_cb(struct virtqueue *_vq) struct vring_virtqueue *vq = to_vvq(_vq); START_USE(vq); - BUG_ON(!(vq->vring.avail->flags & VRING_AVAIL_F_NO_INTERRUPT)); /* We optimistically turn back on interrupts, then check if there was * more to do. */ @@ -254,13 +253,6 @@ irqreturn_t vring_interrupt(int irq, void *_vq) if (unlikely(vq->broken)) return IRQ_HANDLED; - /* Other side may have missed us turning off the interrupt, - * but we should preserve disable semantic for virtio users. */ - if (unlikely(vq->vring.avail->flags & VRING_AVAIL_F_NO_INTERRUPT)) { - pr_debug("virtqueue interrupt after disable for %p\n", vq); - return IRQ_HANDLED; - } - pr_debug("virtqueue callback for %p (%p)\n", vq, vq->vq.callback); if (vq->vq.callback) vq->vq.callback(&vq->vq); diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 254d115cafab..ccb78f66c2b6 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -295,6 +295,19 @@ config ALIM7101_WDT Most people will say N. +config GEODE_WDT + tristate "AMD Geode CS5535/CS5536 Watchdog" + depends on MGEODE_LX + help + This driver enables a watchdog capability built into the + CS5535/CS5536 companion chips for the AMD Geode GX and LX + processors. This watchdog watches your kernel to make sure + it doesn't freeze, and if it does, it reboots your computer after + a certain amount of time. + + You can compile this driver directly into the kernel, or use + it as a module. The module will be called geodewdt. + config SC520_WDT tristate "AMD Elan SC520 processor Watchdog" depends on X86 diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index f3fb170fe5c6..25b352b664d9 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -59,6 +59,7 @@ obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o obj-$(CONFIG_ADVANTECH_WDT) += advantechwdt.o obj-$(CONFIG_ALIM1535_WDT) += alim1535_wdt.o obj-$(CONFIG_ALIM7101_WDT) += alim7101_wdt.o +obj-$(CONFIG_GEODE_WDT) += geodewdt.o obj-$(CONFIG_SC520_WDT) += sc520_wdt.o obj-$(CONFIG_EUROTECH_WDT) += eurotechwdt.o obj-$(CONFIG_IB700_WDT) += ib700wdt.o diff --git a/drivers/watchdog/bfin_wdt.c b/drivers/watchdog/bfin_wdt.c index 1237113dc14a..03b3e3d91e7c 100644 --- a/drivers/watchdog/bfin_wdt.c +++ b/drivers/watchdog/bfin_wdt.c @@ -29,7 +29,8 @@ #define stamp(fmt, args...) pr_debug("%s:%i: " fmt "\n", __func__, __LINE__, ## args) #define stampit() stamp("here i am") -#define pr_init(fmt, args...) ({ static const __initdata char __fmt[] = fmt; printk(__fmt, ## args); }) +#define pr_devinit(fmt, args...) ({ static const __devinitconst char __fmt[] = fmt; printk(__fmt, ## args); }) +#define pr_init(fmt, args...) ({ static const __initconst char __fmt[] = fmt; printk(__fmt, ## args); }) #define WATCHDOG_NAME "bfin-wdt" #define PFX WATCHDOG_NAME ": " @@ -377,20 +378,6 @@ static int bfin_wdt_resume(struct platform_device *pdev) # define bfin_wdt_resume NULL #endif -static struct platform_device bfin_wdt_device = { - .name = WATCHDOG_NAME, - .id = -1, -}; - -static struct platform_driver bfin_wdt_driver = { - .driver = { - .name = WATCHDOG_NAME, - .owner = THIS_MODULE, - }, - .suspend = bfin_wdt_suspend, - .resume = bfin_wdt_resume, -}; - static const struct file_operations bfin_wdt_fops = { .owner = THIS_MODULE, .llseek = no_llseek, @@ -418,11 +405,67 @@ static struct notifier_block bfin_wdt_notifier = { }; /** - * bfin_wdt_init - Initialize module + * bfin_wdt_probe - Initialize module * - * Registers the device and notifier handler. Actual device + * Registers the misc device and notifier handler. Actual device * initialization is handled by bfin_wdt_open(). */ +static int __devinit bfin_wdt_probe(struct platform_device *pdev) +{ + int ret; + + ret = register_reboot_notifier(&bfin_wdt_notifier); + if (ret) { + pr_devinit(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", ret); + return ret; + } + + ret = misc_register(&bfin_wdt_miscdev); + if (ret) { + pr_devinit(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", + WATCHDOG_MINOR, ret); + unregister_reboot_notifier(&bfin_wdt_notifier); + return ret; + } + + pr_devinit(KERN_INFO PFX "initialized: timeout=%d sec (nowayout=%d)\n", + timeout, nowayout); + + return 0; +} + +/** + * bfin_wdt_remove - Initialize module + * + * Unregisters the misc device and notifier handler. Actual device + * deinitialization is handled by bfin_wdt_close(). + */ +static int __devexit bfin_wdt_remove(struct platform_device *pdev) +{ + misc_deregister(&bfin_wdt_miscdev); + unregister_reboot_notifier(&bfin_wdt_notifier); + return 0; +} + +static struct platform_device *bfin_wdt_device; + +static struct platform_driver bfin_wdt_driver = { + .probe = bfin_wdt_probe, + .remove = __devexit_p(bfin_wdt_remove), + .suspend = bfin_wdt_suspend, + .resume = bfin_wdt_resume, + .driver = { + .name = WATCHDOG_NAME, + .owner = THIS_MODULE, + }, +}; + +/** + * bfin_wdt_init - Initialize module + * + * Checks the module params and registers the platform device & driver. + * Real work is in the platform probe function. + */ static int __init bfin_wdt_init(void) { int ret; @@ -436,44 +479,32 @@ static int __init bfin_wdt_init(void) /* Since this is an on-chip device and needs no board-specific * resources, we'll handle all the platform device stuff here. */ - ret = platform_device_register(&bfin_wdt_device); - if (ret) - return ret; - - ret = platform_driver_probe(&bfin_wdt_driver, NULL); - if (ret) - return ret; - - ret = register_reboot_notifier(&bfin_wdt_notifier); + ret = platform_driver_register(&bfin_wdt_driver); if (ret) { - pr_init(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", ret); + pr_init(KERN_ERR PFX "unable to register driver\n"); return ret; } - ret = misc_register(&bfin_wdt_miscdev); - if (ret) { - pr_init(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", - WATCHDOG_MINOR, ret); - unregister_reboot_notifier(&bfin_wdt_notifier); - return ret; + bfin_wdt_device = platform_device_register_simple(WATCHDOG_NAME, -1, NULL, 0); + if (IS_ERR(bfin_wdt_device)) { + pr_init(KERN_ERR PFX "unable to register device\n"); + platform_driver_unregister(&bfin_wdt_driver); + return PTR_ERR(bfin_wdt_device); } - pr_init(KERN_INFO PFX "initialized: timeout=%d sec (nowayout=%d)\n", - timeout, nowayout); - return 0; } /** * bfin_wdt_exit - Deinitialize module * - * Unregisters the device and notifier handler. Actual device - * deinitialization is handled by bfin_wdt_close(). + * Back out the platform device & driver steps. Real work is in the + * platform remove function. */ static void __exit bfin_wdt_exit(void) { - misc_deregister(&bfin_wdt_miscdev); - unregister_reboot_notifier(&bfin_wdt_notifier); + platform_device_unregister(bfin_wdt_device); + platform_driver_unregister(&bfin_wdt_driver); } module_init(bfin_wdt_init); diff --git a/drivers/watchdog/booke_wdt.c b/drivers/watchdog/booke_wdt.c index d362f5bf658a..c1ba0db48501 100644 --- a/drivers/watchdog/booke_wdt.c +++ b/drivers/watchdog/booke_wdt.c @@ -1,12 +1,10 @@ /* - * drivers/char/watchdog/booke_wdt.c - * * Watchdog timer for PowerPC Book-E systems * * Author: Matthew McClintock * Maintainer: Kumar Gala <galak@kernel.crashing.org> * - * Copyright 2005 Freescale Semiconductor Inc. + * Copyright 2005, 2008 Freescale Semiconductor Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -16,6 +14,7 @@ #include <linux/module.h> #include <linux/fs.h> +#include <linux/smp.h> #include <linux/miscdevice.h> #include <linux/notifier.h> #include <linux/watchdog.h> @@ -38,7 +37,7 @@ #define WDT_PERIOD_DEFAULT 3 /* Refer to the PPC40x and PPC4xx manuals */ #endif /* for timing information */ -u32 booke_wdt_enabled = 0; +u32 booke_wdt_enabled; u32 booke_wdt_period = WDT_PERIOD_DEFAULT; #ifdef CONFIG_FSL_BOOKE @@ -47,33 +46,31 @@ u32 booke_wdt_period = WDT_PERIOD_DEFAULT; #define WDTP(x) (TCR_WP(x)) #endif -/* - * booke_wdt_ping: - */ -static __inline__ void booke_wdt_ping(void) +static DEFINE_SPINLOCK(booke_wdt_lock); + +static void __booke_wdt_ping(void *data) { mtspr(SPRN_TSR, TSR_ENW|TSR_WIS); } -/* - * booke_wdt_enable: - */ -static __inline__ void booke_wdt_enable(void) +static void booke_wdt_ping(void) +{ + on_each_cpu(__booke_wdt_ping, NULL, 0, 0); +} + +static void __booke_wdt_enable(void *data) { u32 val; /* clear status before enabling watchdog */ - booke_wdt_ping(); + __booke_wdt_ping(NULL); val = mfspr(SPRN_TCR); val |= (TCR_WIE|TCR_WRC(WRC_CHIP)|WDTP(booke_wdt_period)); mtspr(SPRN_TCR, val); } -/* - * booke_wdt_write: - */ -static ssize_t booke_wdt_write (struct file *file, const char __user *buf, +static ssize_t booke_wdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { booke_wdt_ping(); @@ -81,15 +78,11 @@ static ssize_t booke_wdt_write (struct file *file, const char __user *buf, } static struct watchdog_info ident = { - .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, - .firmware_version = 0, - .identity = "PowerPC Book-E Watchdog", + .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, + .identity = "PowerPC Book-E Watchdog", }; -/* - * booke_wdt_ioctl: - */ -static int booke_wdt_ioctl (struct inode *inode, struct file *file, +static int booke_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { u32 tmp = 0; @@ -97,7 +90,7 @@ static int booke_wdt_ioctl (struct inode *inode, struct file *file, switch (cmd) { case WDIOC_GETSUPPORT: - if (copy_to_user ((struct watchdog_info __user *) arg, &ident, + if (copy_to_user((struct watchdog_info __user *)arg, &ident, sizeof(struct watchdog_info))) return -EFAULT; case WDIOC_GETSTATUS: @@ -132,33 +125,33 @@ static int booke_wdt_ioctl (struct inode *inode, struct file *file, return 0; } -/* - * booke_wdt_open: - */ -static int booke_wdt_open (struct inode *inode, struct file *file) + +static int booke_wdt_open(struct inode *inode, struct file *file) { + spin_lock(&booke_wdt_lock); if (booke_wdt_enabled == 0) { booke_wdt_enabled = 1; - booke_wdt_enable(); - printk (KERN_INFO "PowerPC Book-E Watchdog Timer Enabled (wdt_period=%d)\n", - booke_wdt_period); + on_each_cpu(__booke_wdt_enable, NULL, 0, 0); + printk(KERN_INFO "PowerPC Book-E Watchdog Timer Enabled " + "(wdt_period=%d)\n", booke_wdt_period); } + spin_unlock(&booke_wdt_lock); return nonseekable_open(inode, file); } static const struct file_operations booke_wdt_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .write = booke_wdt_write, - .ioctl = booke_wdt_ioctl, - .open = booke_wdt_open, + .owner = THIS_MODULE, + .llseek = no_llseek, + .write = booke_wdt_write, + .ioctl = booke_wdt_ioctl, + .open = booke_wdt_open, }; static struct miscdevice booke_wdt_miscdev = { - .minor = WATCHDOG_MINOR, - .name = "watchdog", - .fops = &booke_wdt_fops, + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &booke_wdt_fops, }; static void __exit booke_wdt_exit(void) @@ -166,28 +159,27 @@ static void __exit booke_wdt_exit(void) misc_deregister(&booke_wdt_miscdev); } -/* - * booke_wdt_init: - */ static int __init booke_wdt_init(void) { int ret = 0; - printk (KERN_INFO "PowerPC Book-E Watchdog Timer Loaded\n"); + printk(KERN_INFO "PowerPC Book-E Watchdog Timer Loaded\n"); ident.firmware_version = cur_cpu_spec->pvr_value; ret = misc_register(&booke_wdt_miscdev); if (ret) { - printk (KERN_CRIT "Cannot register miscdev on minor=%d (err=%d)\n", + printk(KERN_CRIT "Cannot register miscdev on minor=%d: %d\n", WATCHDOG_MINOR, ret); return ret; } + spin_lock(&booke_wdt_lock); if (booke_wdt_enabled == 1) { - printk (KERN_INFO "PowerPC Book-E Watchdog Timer Enabled (wdt_period=%d)\n", - booke_wdt_period); - booke_wdt_enable(); + printk(KERN_INFO "PowerPC Book-E Watchdog Timer Enabled " + "(wdt_period=%d)\n", booke_wdt_period); + on_each_cpu(__booke_wdt_enable, NULL, 0, 0); } + spin_unlock(&booke_wdt_lock); return ret; } diff --git a/drivers/watchdog/geodewdt.c b/drivers/watchdog/geodewdt.c new file mode 100644 index 000000000000..30d09cbbad94 --- /dev/null +++ b/drivers/watchdog/geodewdt.c @@ -0,0 +1,308 @@ +/* Watchdog timer for the Geode GX/LX with the CS5535/CS5536 companion chip + * + * Copyright (C) 2006-2007, Advanced Micro Devices, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/types.h> +#include <linux/miscdevice.h> +#include <linux/watchdog.h> +#include <linux/fs.h> +#include <linux/platform_device.h> +#include <linux/reboot.h> + +#include <asm/uaccess.h> +#include <asm/geode.h> + +#define GEODEWDT_HZ 500 +#define GEODEWDT_SCALE 6 +#define GEODEWDT_MAX_SECONDS 131 + +#define WDT_FLAGS_OPEN 1 +#define WDT_FLAGS_ORPHAN 2 + +#define DRV_NAME "geodewdt" +#define WATCHDOG_NAME "Geode GX/LX WDT" +#define WATCHDOG_TIMEOUT 60 + +static int timeout = WATCHDOG_TIMEOUT; +module_param(timeout, int, 0); +MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. 1<= timeout <=131, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) "."); + +static int nowayout = WATCHDOG_NOWAYOUT; +module_param(nowayout, int, 0); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); + +static struct platform_device *geodewdt_platform_device; +static unsigned long wdt_flags; +static int wdt_timer; +static int safe_close; + +static void geodewdt_ping(void) +{ + /* Stop the counter */ + geode_mfgpt_write(wdt_timer, MFGPT_REG_SETUP, 0); + + /* Reset the counter */ + geode_mfgpt_write(wdt_timer, MFGPT_REG_COUNTER, 0); + + /* Enable the counter */ + geode_mfgpt_write(wdt_timer, MFGPT_REG_SETUP, MFGPT_SETUP_CNTEN); +} + +static void geodewdt_disable(void) +{ + geode_mfgpt_write(wdt_timer, MFGPT_REG_SETUP, 0); + geode_mfgpt_write(wdt_timer, MFGPT_REG_COUNTER, 0); +} + +static int geodewdt_set_heartbeat(int val) +{ + if (val < 1 || val > GEODEWDT_MAX_SECONDS) + return -EINVAL; + + geode_mfgpt_write(wdt_timer, MFGPT_REG_SETUP, 0); + geode_mfgpt_write(wdt_timer, MFGPT_REG_CMP2, val * GEODEWDT_HZ); + geode_mfgpt_write(wdt_timer, MFGPT_REG_COUNTER, 0); + geode_mfgpt_write(wdt_timer, MFGPT_REG_SETUP, MFGPT_SETUP_CNTEN); + + timeout = val; + return 0; +} + +static int +geodewdt_open(struct inode *inode, struct file *file) +{ + if (test_and_set_bit(WDT_FLAGS_OPEN, &wdt_flags)) + return -EBUSY; + + if (!test_and_clear_bit(WDT_FLAGS_ORPHAN, &wdt_flags)) + __module_get(THIS_MODULE); + + geodewdt_ping(); + return nonseekable_open(inode, file); +} + +static int +geodewdt_release(struct inode *inode, struct file *file) +{ + if (safe_close) { + geodewdt_disable(); + module_put(THIS_MODULE); + } + else { + printk(KERN_CRIT "Unexpected close - watchdog is not stopping.\n"); + geodewdt_ping(); + + set_bit(WDT_FLAGS_ORPHAN, &wdt_flags); + } + + clear_bit(WDT_FLAGS_OPEN, &wdt_flags); + safe_close = 0; + return 0; +} + +static ssize_t +geodewdt_write(struct file *file, const char __user *data, size_t len, + loff_t *ppos) +{ + if(len) { + if (!nowayout) { + size_t i; + safe_close = 0; + + for (i = 0; i != len; i++) { + char c; + + if (get_user(c, data + i)) + return -EFAULT; + + if (c == 'V') + safe_close = 1; + } + } + + geodewdt_ping(); + } + return len; +} + +static int +geodewdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + void __user *argp = (void __user *)arg; + int __user *p = argp; + int interval; + + static struct watchdog_info ident = { + .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING + | WDIOF_MAGICCLOSE, + .firmware_version = 1, + .identity = WATCHDOG_NAME, + }; + + switch(cmd) { + case WDIOC_GETSUPPORT: + return copy_to_user(argp, &ident, + sizeof(ident)) ? -EFAULT : 0; + break; + + case WDIOC_GETSTATUS: + case WDIOC_GETBOOTSTATUS: + return put_user(0, p); + + case WDIOC_KEEPALIVE: + geodewdt_ping(); + return 0; + + case WDIOC_SETTIMEOUT: + if (get_user(interval, p)) + return -EFAULT; + + if (geodewdt_set_heartbeat(interval)) + return -EINVAL; + +/* Fall through */ + + case WDIOC_GETTIMEOUT: + return put_user(timeout, p); + + case WDIOC_SETOPTIONS: + { + int options, ret = -EINVAL; + + if (get_user(options, p)) + return -EFAULT; + + if (options & WDIOS_DISABLECARD) { + geodewdt_disable(); + ret = 0; + } + + if (options & WDIOS_ENABLECARD) { + geodewdt_ping(); + ret = 0; + } + + return ret; + } + default: + return -ENOTTY; + } + + return 0; +} + +static const struct file_operations geodewdt_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .write = geodewdt_write, + .ioctl = geodewdt_ioctl, + .open = geodewdt_open, + .release = geodewdt_release, +}; + +static struct miscdevice geodewdt_miscdev = { + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &geodewdt_fops +}; + +static int __devinit +geodewdt_probe(struct platform_device *dev) +{ + int ret, timer; + + timer = geode_mfgpt_alloc_timer(MFGPT_TIMER_ANY, MFGPT_DOMAIN_WORKING); + + if (timer == -1) { + printk(KERN_ERR "geodewdt: No timers were available\n"); + return -ENODEV; + } + + wdt_timer = timer; + + /* Set up the timer */ + + geode_mfgpt_write(wdt_timer, MFGPT_REG_SETUP, + GEODEWDT_SCALE | (3 << 8)); + + /* Set up comparator 2 to reset when the event fires */ + geode_mfgpt_toggle_event(wdt_timer, MFGPT_CMP2, MFGPT_EVENT_RESET, 1); + + /* Set up the initial timeout */ + + geode_mfgpt_write(wdt_timer, MFGPT_REG_CMP2, + timeout * GEODEWDT_HZ); + + ret = misc_register(&geodewdt_miscdev); + + return ret; +} + +static int __devexit +geodewdt_remove(struct platform_device *dev) +{ + misc_deregister(&geodewdt_miscdev); + return 0; +} + +static void +geodewdt_shutdown(struct platform_device *dev) +{ + geodewdt_disable(); +} + +static struct platform_driver geodewdt_driver = { + .probe = geodewdt_probe, + .remove = __devexit_p(geodewdt_remove), + .shutdown = geodewdt_shutdown, + .driver = { + .owner = THIS_MODULE, + .name = DRV_NAME, + }, +}; + +static int __init +geodewdt_init(void) +{ + int ret; + + ret = platform_driver_register(&geodewdt_driver); + if (ret) + return ret; + + geodewdt_platform_device = platform_device_register_simple(DRV_NAME, -1, NULL, 0); + if (IS_ERR(geodewdt_platform_device)) { + ret = PTR_ERR(geodewdt_platform_device); + goto err; + } + + return 0; +err: + platform_driver_unregister(&geodewdt_driver); + return ret; +} + +static void __exit +geodewdt_exit(void) +{ + platform_device_unregister(geodewdt_platform_device); + platform_driver_unregister(&geodewdt_driver); +} + +module_init(geodewdt_init); +module_exit(geodewdt_exit); + +MODULE_AUTHOR("Advanced Micro Devices, Inc"); +MODULE_DESCRIPTION("Geode GX/LX Watchdog Driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c index 6483d1066b95..6a63535fc04d 100644 --- a/drivers/watchdog/hpwdt.c +++ b/drivers/watchdog/hpwdt.c @@ -418,23 +418,20 @@ static int hpwdt_pretimeout(struct notifier_block *nb, unsigned long ulReason, static unsigned long rom_pl; static int die_nmi_called; - if (ulReason != DIE_NMI && ulReason != DIE_NMI_IPI) - return NOTIFY_OK; - - spin_lock_irqsave(&rom_lock, rom_pl); - if (!die_nmi_called) - asminline_call(&cmn_regs, cru_rom_addr); - die_nmi_called = 1; - spin_unlock_irqrestore(&rom_lock, rom_pl); - if (cmn_regs.u1.ral == 0) { - printk(KERN_WARNING "hpwdt: An NMI occurred, " - "but unable to determine source.\n"); - } else { - panic("An NMI occurred, please see the Integrated " - "Management Log for details.\n"); + if (ulReason == DIE_NMI || ulReason == DIE_NMI_IPI) { + spin_lock_irqsave(&rom_lock, rom_pl); + if (!die_nmi_called) + asminline_call(&cmn_regs, cru_rom_addr); + die_nmi_called = 1; + spin_unlock_irqrestore(&rom_lock, rom_pl); + if (cmn_regs.u1.ral != 0) { + panic("An NMI occurred, please see the Integrated " + "Management Log for details.\n"); + } } - return NOTIFY_STOP; + die_nmi_called = 0; + return NOTIFY_DONE; } /* diff --git a/drivers/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c index a0e6809e369f..95ba985bd341 100644 --- a/drivers/watchdog/iTCO_wdt.c +++ b/drivers/watchdog/iTCO_wdt.c @@ -41,9 +41,10 @@ * 82801HH (ICH8DH) : document number 313056-003, 313057-009, * 82801HO (ICH8DO) : document number 313056-003, 313057-009, * 82801HEM (ICH8M-E) : document number 313056-003, 313057-009, - * 82801IB (ICH9) : document number 316972-001, 316973-001, - * 82801IR (ICH9R) : document number 316972-001, 316973-001, - * 82801IH (ICH9DH) : document number 316972-001, 316973-001, + * 82801IB (ICH9) : document number 316972-001, 316973-006, + * 82801IR (ICH9R) : document number 316972-001, 316973-006, + * 82801IH (ICH9DH) : document number 316972-001, 316973-006, + * 82801IO (ICH9DO) : document number 316972-001, 316973-006, * 6300ESB (6300ESB) : document number 300641-003, 300884-010, * 631xESB (631xESB) : document number 313082-001, 313075-005, * 632xESB (632xESB) : document number 313082-001, 313075-005 @@ -55,8 +56,8 @@ /* Module and version information */ #define DRV_NAME "iTCO_wdt" -#define DRV_VERSION "1.02" -#define DRV_RELDATE "26-Jul-2007" +#define DRV_VERSION "1.03" +#define DRV_RELDATE "30-Apr-2008" #define PFX DRV_NAME ": " /* Includes */ @@ -104,6 +105,7 @@ enum iTCO_chipsets { TCO_ICH9, /* ICH9 */ TCO_ICH9R, /* ICH9R */ TCO_ICH9DH, /* ICH9DH */ + TCO_ICH9DO, /* ICH9DO */ TCO_631XESB, /* 631xESB/632xESB */ }; @@ -136,6 +138,7 @@ static struct { {"ICH9", 2}, {"ICH9R", 2}, {"ICH9DH", 2}, + {"ICH9DO", 2}, {"631xESB/632xESB", 2}, {NULL,0} }; @@ -181,6 +184,7 @@ static struct pci_device_id iTCO_wdt_pci_tbl[] = { { ITCO_PCI_DEVICE(0x2918, TCO_ICH9 )}, { ITCO_PCI_DEVICE(0x2916, TCO_ICH9R )}, { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH9_2, TCO_ICH9DH )}, + { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH9_4, TCO_ICH9DO )}, { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ESB2_0, TCO_631XESB)}, { ITCO_PCI_DEVICE(0x2671, TCO_631XESB)}, { ITCO_PCI_DEVICE(0x2672, TCO_631XESB)}, diff --git a/drivers/watchdog/w83697hf_wdt.c b/drivers/watchdog/w83697hf_wdt.c index c622a0e6c9ae..528b882420b6 100644 --- a/drivers/watchdog/w83697hf_wdt.c +++ b/drivers/watchdog/w83697hf_wdt.c @@ -44,6 +44,7 @@ #define WATCHDOG_NAME "w83697hf/hg WDT" #define PFX WATCHDOG_NAME ": " #define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */ +#define WATCHDOG_EARLY_DISABLE 1 /* Disable until userland kicks in */ static unsigned long wdt_is_open; static char expect_close; @@ -56,12 +57,16 @@ MODULE_PARM_DESC(wdt_io, "w83697hf/hg WDT io port (default 0x2e, 0 = autodetect) static int timeout = WATCHDOG_TIMEOUT; /* in seconds */ module_param(timeout, int, 0); -MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. 1<= timeout <=255, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) "."); +MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. 1<= timeout <=255 (default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")"); static int nowayout = WATCHDOG_NOWAYOUT; module_param(nowayout, int, 0); MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); +static int early_disable = WATCHDOG_EARLY_DISABLE; +module_param(early_disable, int, 0); +MODULE_PARM_DESC(early_disable, "Watchdog gets disabled at boot time (default=" __MODULE_STRING(WATCHDOG_EARLY_DISABLE) ")"); + /* * Kernel methods. */ @@ -140,7 +145,7 @@ w83697hf_init(void) w83697hf_deselect_wdt(); } -static int +static void wdt_ping(void) { spin_lock(&io_lock); @@ -150,10 +155,9 @@ wdt_ping(void) w83697hf_deselect_wdt(); spin_unlock(&io_lock); - return 0; } -static int +static void wdt_enable(void) { spin_lock(&io_lock); @@ -164,10 +168,9 @@ wdt_enable(void) w83697hf_deselect_wdt(); spin_unlock(&io_lock); - return 0; } -static int +static void wdt_disable(void) { spin_lock(&io_lock); @@ -178,7 +181,22 @@ wdt_disable(void) w83697hf_deselect_wdt(); spin_unlock(&io_lock); - return 0; +} + +static unsigned char +wdt_running(void) +{ + unsigned char t; + + spin_lock(&io_lock); + w83697hf_select_wdt(); + + t = w83697hf_get_reg(0xF4); /* Read timer */ + + w83697hf_deselect_wdt(); + spin_unlock(&io_lock); + + return t; } static int @@ -397,7 +415,11 @@ wdt_init(void) } w83697hf_init(); - wdt_disable(); /* Disable watchdog until first use */ + if (early_disable) { + if (wdt_running()) + printk (KERN_WARNING PFX "Stopping previously enabled watchdog until userland kicks in\n"); + wdt_disable(); + } if (wdt_set_heartbeat(timeout)) { wdt_set_heartbeat(WATCHDOG_TIMEOUT); |