diff options
Diffstat (limited to 'drivers')
52 files changed, 1915 insertions, 1814 deletions
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..3c89f205c83f 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 }, @@ -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..0f9386d4a5a0 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", @@ -700,8 +687,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 +696,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 +847,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 +885,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 +923,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..aeb6e01d82ce 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 */ 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_mv.c b/drivers/ata/sata_mv.c index bb73b2222627..fb81f0c7a8c2 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.21" enum { /* BAR's are enumerated in terms of pci_resource_start() terms */ @@ -128,8 +128,13 @@ enum { 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 +202,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 +219,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 */ @@ -459,6 +458,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 +640,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 | MV_FLAG_SOC, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = ATA_UDMA6, .port_ops = &mv_iie_ops, @@ -844,6 +838,33 @@ static void mv_set_edma_ptrs(void __iomem *port_mmio, 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 +907,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; @@ -1341,6 +1364,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 +1606,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 +1695,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 +1740,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 +1849,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 +1859,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 +1885,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 +2215,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) && HAS_PCI(host))) 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 +2426,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); @@ -2728,6 +2780,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 +2797,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 +2818,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); } /** @@ -3035,7 +3071,7 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx) } /* 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); @@ -3083,25 +3119,12 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx) /* 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/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/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/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/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/s390/kvm/kvm_virtio.c b/drivers/s390/kvm/kvm_virtio.c index 47a7e6200b26..9f55ce6f3c78 100644 --- a/drivers/s390/kvm/kvm_virtio.c +++ b/drivers/s390/kvm/kvm_virtio.c @@ -78,27 +78,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 +226,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, diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index a1ca9b7bf2d5..1400ea6a2491 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -43,6 +43,7 @@ #include <asm/io.h> #include <asm/irq.h> +#include <asm/serial.h> #include "8250.h" @@ -92,8 +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 @@ -1548,6 +1547,8 @@ static int serial_link_irq_chain(struct uart_8250_port *up) i->head = &up->list; spin_unlock_irq(&i->lock); + irq_flags |= SERIAL_EXTRA_IRQ_FLAGS; + ret = request_irq(up->port.irq, serial8250_interrupt, irq_flags, "serial", i); if (ret < 0) diff --git a/drivers/serial/8250.h b/drivers/serial/8250.h index 91bd28f2bb47..a10a40cc0d9e 100644 --- a/drivers/serial/8250.h +++ b/drivers/serial/8250.h @@ -78,3 +78,8 @@ struct serial8250_config { #else #define ALPHA_KLUDGE_MCR 0 #endif + +#ifndef SERIAL_EXTRA_IRQ_FLAGS +#define SERIAL_EXTRA_IRQ_FLAGS 0 +#endif + 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/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 */ |