From: Pierre Ossman Signed-off-by: Andrew Morton --- drivers/mmc/sdhci.c | 53 +++++++++++++++++++++++++++++------------- drivers/mmc/sdhci.h | 12 +++++++-- 2 files changed, 46 insertions(+), 19 deletions(-) diff -puN drivers/mmc/sdhci.c~mmc-secure-digital-host-controller-interface-driver-fix drivers/mmc/sdhci.c --- devel/drivers/mmc/sdhci.c~mmc-secure-digital-host-controller-interface-driver-fix 2006-02-19 20:51:29.000000000 -0800 +++ devel-akpm/drivers/mmc/sdhci.c 2006-02-19 20:51:29.000000000 -0800 @@ -204,6 +204,9 @@ static void sdhci_transfer_pio(struct sd "Please report this to " BUGMAIL ".\n", mmc_hostname(host->mmc)); sdhci_dumpregs(host); + + sdhci_kunmap_sg(host); + host->data->error = MMC_ERR_FAILED; sdhci_finish_data(host); return; @@ -578,8 +581,12 @@ static void sdhci_set_ios(struct mmc_hos * Reset the chip on each power off. * Should clear out any weird states. */ - if (ios->power_mode == MMC_POWER_OFF) + if (ios->power_mode == MMC_POWER_OFF) { + writel(0, host->ioaddr + SDHCI_SIGNAL_ENABLE); + spin_unlock_irqrestore(&host->lock, flags); sdhci_init(host); + spin_lock_irqsave(&host->lock, flags); + } sdhci_set_clock(host, ios->clock); @@ -970,6 +977,21 @@ static int __devinit sdhci_probe_slot(st first_bar &= PCI_SLOT_INFO_FIRST_BAR_MASK; + if (first_bar > 5) { + printk(KERN_ERR DRIVER_NAME ": Invalid first BAR. Aborting.\n"); + return -ENODEV; + } + + if (!(pci_resource_flags(pdev, first_bar + slot) & IORESOURCE_MEM)) { + printk(KERN_ERR DRIVER_NAME ": BAR is not iomem. Aborting.\n"); + return -ENODEV; + } + + if (pci_resource_len(pdev, first_bar + slot) != 0x100) { + printk(KERN_ERR DRIVER_NAME ": Invalid iomem size. Aborting.\n"); + return -ENODEV; + } + mmc = mmc_alloc_host(sizeof(struct sdhci_host), &pdev->dev); if (!mmc) return -ENOMEM; @@ -984,8 +1006,6 @@ static int __devinit sdhci_probe_slot(st DBG("slot %d at 0x%08lx, irq %d\n", slot, host->addr, host->irq); - BUG_ON(!(pci_resource_flags(pdev, first_bar + slot) & IORESOURCE_MEM)); - snprintf(host->slot_descr, 20, "sdhci:slot%d", slot); ret = pci_request_region(pdev, host->bar, host->slot_descr); @@ -999,11 +1019,6 @@ static int __devinit sdhci_probe_slot(st goto release; } - ret = request_irq(host->irq, sdhci_irq, SA_SHIRQ, - host->slot_descr, host); - if (ret) - goto unmap; - caps = readl(host->ioaddr + SDHCI_CAPABILITIES); if ((caps & SDHCI_CAN_DO_DMA) && ((pdev->class & 0x0000FF) == 0x01)) @@ -1065,9 +1080,12 @@ static int __devinit sdhci_probe_slot(st tasklet_init(&host->finish_tasklet, sdhci_tasklet_finish, (unsigned long)host); - init_timer(&host->timer); - host->timer.data = (unsigned long)host; - host->timer.function = sdhci_timeout_timer; + setup_timer(&host->timer, sdhci_timeout_timer, (int)host); + + ret = request_irq(host->irq, sdhci_irq, SA_SHIRQ, + host->slot_descr, host); + if (ret) + goto unmap; sdhci_init(host); @@ -1087,6 +1105,9 @@ static int __devinit sdhci_probe_slot(st return 0; unmap: + tasklet_kill(&host->card_tasklet); + tasklet_kill(&host->finish_tasklet); + iounmap(host->ioaddr); release: pci_release_region(pdev, host->bar); @@ -1110,10 +1131,12 @@ static void sdhci_remove_slot(struct pci mmc_remove_host(mmc); - del_timer_sync(&host->timer); - sdhci_reset(host, SDHCI_RESET_ALL); + free_irq(host->irq, host); + + del_timer_sync(&host->timer); + tasklet_kill(&host->card_tasklet); tasklet_kill(&host->finish_tasklet); @@ -1121,8 +1144,6 @@ static void sdhci_remove_slot(struct pci pci_release_region(pdev, host->bar); - free_irq(host->irq, host); - mmc_free_host(mmc); } @@ -1152,7 +1173,7 @@ static int __devinit sdhci_probe(struct return ret; chip = kzalloc(sizeof(struct sdhci_chip) + - sizeof(sdhci_host_p) * slots, GFP_KERNEL); + sizeof(struct sdhci_host*) * slots, GFP_KERNEL); if (!chip) { ret = -ENOMEM; goto err; diff -puN drivers/mmc/sdhci.h~mmc-secure-digital-host-controller-interface-driver-fix drivers/mmc/sdhci.h --- devel/drivers/mmc/sdhci.h~mmc-secure-digital-host-controller-interface-driver-fix 2006-02-19 20:51:29.000000000 -0800 +++ devel-akpm/drivers/mmc/sdhci.h 2006-02-19 20:51:29.000000000 -0800 @@ -9,6 +9,14 @@ */ /* + * PCI registers + */ + +#define PCI_SLOT_INFO 0x40 /* 8 bits */ +#define PCI_SLOT_INFO_SLOTS(x) ((x >> 4) & 7) +#define PCI_SLOT_INFO_FIRST_BAR_MASK 0x07 + +/* * Controller registers */ @@ -169,11 +177,9 @@ struct sdhci_host { struct timer_list timer; /* Timer for timeouts */ }; -typedef struct sdhci_host *sdhci_host_p; - struct sdhci_chip { struct pci_dev *pdev; int num_slots; /* Slots on controller */ - sdhci_host_p hosts[0]; /* Pointers to hosts */ + struct sdhci_host *hosts[0]; /* Pointers to hosts */ }; _