Commit 0202b160 authored by Jeff Garzik's avatar Jeff Garzik

Merge pobox.com:/garz/repo/netdev-2.6/r8169

into pobox.com:/garz/repo/net-drivers-2.6
parents 3cbae07b f5f23ec8
...@@ -107,8 +107,11 @@ pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address) ...@@ -107,8 +107,11 @@ pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
ptepage->mapping = (void *) mm; ptepage->mapping = (void *) mm;
ptepage->index = address & PMD_MASK; ptepage->index = address & PMD_MASK;
} }
} else } else {
pte = (pte_t *)early_get_page(); pte = (pte_t *)early_get_page();
if (pte)
clear_page(pte);
}
return pte; return pte;
} }
......
...@@ -62,7 +62,7 @@ void flush_hash_one_pte(pte_t *ptep) ...@@ -62,7 +62,7 @@ void flush_hash_one_pte(pte_t *ptep)
ptepage = virt_to_page(ptep); ptepage = virt_to_page(ptep);
mm = (struct mm_struct *) ptepage->mapping; mm = (struct mm_struct *) ptepage->mapping;
ptephys = __pa(ptep) & PAGE_MASK; ptephys = __pa(ptep) & PAGE_MASK;
addr = ptepage->index + (((unsigned long)ptep & ~PAGE_MASK) << 9); addr = ptepage->index + (((unsigned long)ptep & ~PAGE_MASK) << 10);
flush_hash_pages(mm->context, addr, ptephys, 1); flush_hash_pages(mm->context, addr, ptephys, 1);
} }
......
...@@ -628,11 +628,13 @@ int xmon_fault_handler(struct pt_regs *regs) ...@@ -628,11 +628,13 @@ int xmon_fault_handler(struct pt_regs *regs)
(data address breakpoint register) directly. */ (data address breakpoint register) directly. */
static void set_controlled_dabr(unsigned long val) static void set_controlled_dabr(unsigned long val)
{ {
#ifdef CONFIG_PPC_PSERIES
if (systemcfg->platform == PLATFORM_PSERIES_LPAR) { if (systemcfg->platform == PLATFORM_PSERIES_LPAR) {
int rc = plpar_hcall_norets(H_SET_DABR, val); int rc = plpar_hcall_norets(H_SET_DABR, val);
if (rc != H_Success) if (rc != H_Success)
xmon_printf("Warning: setting DABR failed (%d)\n", rc); xmon_printf("Warning: setting DABR failed (%d)\n", rc);
} else } else
#endif
set_dabr(val); set_dabr(val);
} }
......
...@@ -34,7 +34,7 @@ struct alps_model_info { ...@@ -34,7 +34,7 @@ struct alps_model_info {
unsigned char signature[3]; unsigned char signature[3];
unsigned char model; unsigned char model;
} alps_model_data[] = { } alps_model_data[] = {
{ { 0x33, 0x02, 0x0a }, ALPS_MODEL_GLIDEPOINT }, /* { { 0x33, 0x02, 0x0a }, ALPS_MODEL_GLIDEPOINT }, */
{ { 0x53, 0x02, 0x0a }, ALPS_MODEL_GLIDEPOINT }, { { 0x53, 0x02, 0x0a }, ALPS_MODEL_GLIDEPOINT },
{ { 0x53, 0x02, 0x14 }, ALPS_MODEL_GLIDEPOINT }, { { 0x53, 0x02, 0x14 }, ALPS_MODEL_GLIDEPOINT },
{ { 0x63, 0x02, 0x0a }, ALPS_MODEL_GLIDEPOINT }, { { 0x63, 0x02, 0x0a }, ALPS_MODEL_GLIDEPOINT },
...@@ -42,8 +42,8 @@ struct alps_model_info { ...@@ -42,8 +42,8 @@ struct alps_model_info {
{ { 0x73, 0x02, 0x0a }, ALPS_MODEL_GLIDEPOINT }, { { 0x73, 0x02, 0x0a }, ALPS_MODEL_GLIDEPOINT },
{ { 0x73, 0x02, 0x14 }, ALPS_MODEL_GLIDEPOINT }, { { 0x73, 0x02, 0x14 }, ALPS_MODEL_GLIDEPOINT },
{ { 0x63, 0x02, 0x28 }, ALPS_MODEL_GLIDEPOINT }, { { 0x63, 0x02, 0x28 }, ALPS_MODEL_GLIDEPOINT },
{ { 0x63, 0x02, 0x3c }, ALPS_MODEL_GLIDEPOINT }, /* { { 0x63, 0x02, 0x3c }, ALPS_MODEL_GLIDEPOINT }, */
{ { 0x63, 0x02, 0x50 }, ALPS_MODEL_GLIDEPOINT }, /* { { 0x63, 0x02, 0x50 }, ALPS_MODEL_GLIDEPOINT }, */
{ { 0x63, 0x02, 0x64 }, ALPS_MODEL_GLIDEPOINT }, { { 0x63, 0x02, 0x64 }, ALPS_MODEL_GLIDEPOINT },
{ { 0x20, 0x02, 0x0e }, ALPS_MODEL_DUALPOINT }, { { 0x20, 0x02, 0x0e }, ALPS_MODEL_DUALPOINT },
{ { 0x22, 0x02, 0x0a }, ALPS_MODEL_DUALPOINT }, { { 0x22, 0x02, 0x0a }, ALPS_MODEL_DUALPOINT },
......
...@@ -253,9 +253,9 @@ static struct region *__rh_alloc(struct region_hash *rh, region_t region) ...@@ -253,9 +253,9 @@ static struct region *__rh_alloc(struct region_hash *rh, region_t region)
else { else {
__rh_insert(rh, nreg); __rh_insert(rh, nreg);
if (nreg->state == RH_CLEAN) { if (nreg->state == RH_CLEAN) {
spin_lock_irq(&rh->region_lock); spin_lock(&rh->region_lock);
list_add(&nreg->list, &rh->clean_regions); list_add(&nreg->list, &rh->clean_regions);
spin_unlock_irq(&rh->region_lock); spin_unlock(&rh->region_lock);
} }
reg = nreg; reg = nreg;
} }
......
...@@ -457,6 +457,14 @@ config SCSI_SATA_PROMISE ...@@ -457,6 +457,14 @@ config SCSI_SATA_PROMISE
If unsure, say N. If unsure, say N.
config SCSI_SATA_QSTOR
tristate "Pacific Digital SATA QStor support"
depends on SCSI_SATA && PCI
help
This option enables support for Pacific Digital Serial ATA QStor.
If unsure, say N.
config SCSI_SATA_SX4 config SCSI_SATA_SX4
tristate "Promise SATA SX4 support" tristate "Promise SATA SX4 support"
depends on SCSI_SATA && PCI && EXPERIMENTAL depends on SCSI_SATA && PCI && EXPERIMENTAL
......
...@@ -125,6 +125,7 @@ obj-$(CONFIG_SCSI_SATA_AHCI) += libata.o ahci.o ...@@ -125,6 +125,7 @@ obj-$(CONFIG_SCSI_SATA_AHCI) += libata.o ahci.o
obj-$(CONFIG_SCSI_SATA_SVW) += libata.o sata_svw.o obj-$(CONFIG_SCSI_SATA_SVW) += libata.o sata_svw.o
obj-$(CONFIG_SCSI_ATA_PIIX) += libata.o ata_piix.o obj-$(CONFIG_SCSI_ATA_PIIX) += libata.o ata_piix.o
obj-$(CONFIG_SCSI_SATA_PROMISE) += libata.o sata_promise.o obj-$(CONFIG_SCSI_SATA_PROMISE) += libata.o sata_promise.o
obj-$(CONFIG_SCSI_SATA_QSTOR) += libata.o sata_qstor.o
obj-$(CONFIG_SCSI_SATA_SIL) += libata.o sata_sil.o obj-$(CONFIG_SCSI_SATA_SIL) += libata.o sata_sil.o
obj-$(CONFIG_SCSI_SATA_VIA) += libata.o sata_via.o obj-$(CONFIG_SCSI_SATA_VIA) += libata.o sata_via.o
obj-$(CONFIG_SCSI_SATA_VITESSE) += libata.o sata_vsc.o obj-$(CONFIG_SCSI_SATA_VITESSE) += libata.o sata_vsc.o
......
...@@ -179,6 +179,7 @@ static void ahci_port_stop(struct ata_port *ap); ...@@ -179,6 +179,7 @@ static void ahci_port_stop(struct ata_port *ap);
static void ahci_host_stop(struct ata_host_set *host_set); static void ahci_host_stop(struct ata_host_set *host_set);
static void ahci_qc_prep(struct ata_queued_cmd *qc); static void ahci_qc_prep(struct ata_queued_cmd *qc);
static u8 ahci_check_status(struct ata_port *ap); static u8 ahci_check_status(struct ata_port *ap);
static u8 ahci_check_err(struct ata_port *ap);
static inline int ahci_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc); static inline int ahci_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc);
static Scsi_Host_Template ahci_sht = { static Scsi_Host_Template ahci_sht = {
...@@ -204,6 +205,8 @@ static struct ata_port_operations ahci_ops = { ...@@ -204,6 +205,8 @@ static struct ata_port_operations ahci_ops = {
.port_disable = ata_port_disable, .port_disable = ata_port_disable,
.check_status = ahci_check_status, .check_status = ahci_check_status,
.check_altstatus = ahci_check_status,
.check_err = ahci_check_err,
.dev_select = ata_noop_dev_select, .dev_select = ata_noop_dev_select,
.phy_reset = ahci_phy_reset, .phy_reset = ahci_phy_reset,
...@@ -452,6 +455,13 @@ static u8 ahci_check_status(struct ata_port *ap) ...@@ -452,6 +455,13 @@ static u8 ahci_check_status(struct ata_port *ap)
return readl(mmio + PORT_TFDATA) & 0xFF; return readl(mmio + PORT_TFDATA) & 0xFF;
} }
static u8 ahci_check_err(struct ata_port *ap)
{
void *mmio = (void *) ap->ioaddr.cmd_addr;
return (readl(mmio + PORT_TFDATA) >> 8) & 0xFF;
}
static void ahci_fill_sg(struct ata_queued_cmd *qc) static void ahci_fill_sg(struct ata_queued_cmd *qc)
{ {
struct ahci_port_priv *pp = qc->ap->private_data; struct ahci_port_priv *pp = qc->ap->private_data;
...@@ -940,6 +950,7 @@ static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -940,6 +950,7 @@ static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
unsigned long base; unsigned long base;
void *mmio_base; void *mmio_base;
unsigned int board_idx = (unsigned int) ent->driver_data; unsigned int board_idx = (unsigned int) ent->driver_data;
int pci_dev_busy = 0;
int rc; int rc;
VPRINTK("ENTER\n"); VPRINTK("ENTER\n");
...@@ -952,8 +963,10 @@ static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -952,8 +963,10 @@ static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
return rc; return rc;
rc = pci_request_regions(pdev, DRV_NAME); rc = pci_request_regions(pdev, DRV_NAME);
if (rc) if (rc) {
pci_dev_busy = 1;
goto err_out; goto err_out;
}
pci_enable_intx(pdev); pci_enable_intx(pdev);
...@@ -1015,7 +1028,8 @@ static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -1015,7 +1028,8 @@ static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
err_out_regions: err_out_regions:
pci_release_regions(pdev); pci_release_regions(pdev);
err_out: err_out:
pci_disable_device(pdev); if (!pci_dev_busy)
pci_disable_device(pdev);
return rc; return rc;
} }
......
...@@ -138,6 +138,8 @@ static struct ata_port_operations piix_pata_ops = { ...@@ -138,6 +138,8 @@ static struct ata_port_operations piix_pata_ops = {
.bmdma_setup = ata_bmdma_setup, .bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start, .bmdma_start = ata_bmdma_start,
.bmdma_stop = ata_bmdma_stop,
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep, .qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot, .qc_issue = ata_qc_issue_prot,
...@@ -163,6 +165,8 @@ static struct ata_port_operations piix_sata_ops = { ...@@ -163,6 +165,8 @@ static struct ata_port_operations piix_sata_ops = {
.bmdma_setup = ata_bmdma_setup, .bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start, .bmdma_start = ata_bmdma_start,
.bmdma_stop = ata_bmdma_stop,
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep, .qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot, .qc_issue = ata_qc_issue_prot,
......
...@@ -377,7 +377,7 @@ void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf) ...@@ -377,7 +377,7 @@ void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
} }
/** /**
* ata_check_status - Read device status reg & clear interrupt * ata_check_status_pio - Read device status reg & clear interrupt
* @ap: port where the device is * @ap: port where the device is
* *
* Reads ATA taskfile status register for currently-selected device * Reads ATA taskfile status register for currently-selected device
...@@ -415,6 +415,27 @@ u8 ata_check_status(struct ata_port *ap) ...@@ -415,6 +415,27 @@ u8 ata_check_status(struct ata_port *ap)
return ata_check_status_pio(ap); return ata_check_status_pio(ap);
} }
u8 ata_altstatus(struct ata_port *ap)
{
if (ap->ops->check_altstatus)
return ap->ops->check_altstatus(ap);
if (ap->flags & ATA_FLAG_MMIO)
return readb((void __iomem *)ap->ioaddr.altstatus_addr);
return inb(ap->ioaddr.altstatus_addr);
}
u8 ata_chk_err(struct ata_port *ap)
{
if (ap->ops->check_err)
return ap->ops->check_err(ap);
if (ap->flags & ATA_FLAG_MMIO) {
return readb((void __iomem *) ap->ioaddr.error_addr);
}
return inb(ap->ioaddr.error_addr);
}
/** /**
* ata_tf_to_fis - Convert ATA taskfile to SATA FIS structure * ata_tf_to_fis - Convert ATA taskfile to SATA FIS structure
* @tf: Taskfile to convert * @tf: Taskfile to convert
...@@ -1161,7 +1182,6 @@ static void ata_dev_identify(struct ata_port *ap, unsigned int device) ...@@ -1161,7 +1182,6 @@ static void ata_dev_identify(struct ata_port *ap, unsigned int device)
printk(KERN_WARNING "ata%u: dev %u not supported, ignoring\n", printk(KERN_WARNING "ata%u: dev %u not supported, ignoring\n",
ap->id, device); ap->id, device);
err_out: err_out:
ata_irq_on(ap); /* re-enable interrupts */
dev->class++; /* converts ATA_DEV_xxx into ATA_DEV_xxx_UNSUP */ dev->class++; /* converts ATA_DEV_xxx into ATA_DEV_xxx_UNSUP */
DPRINTK("EXIT, err\n"); DPRINTK("EXIT, err\n");
} }
...@@ -1669,7 +1689,8 @@ void ata_bus_reset(struct ata_port *ap) ...@@ -1669,7 +1689,8 @@ void ata_bus_reset(struct ata_port *ap)
ata_dev_try_classify(ap, 1); ata_dev_try_classify(ap, 1);
/* re-enable interrupts */ /* re-enable interrupts */
ata_irq_on(ap); if (ap->ioaddr.ctl_addr) /* FIXME: hack. create a hook instead */
ata_irq_on(ap);
/* is double-select really necessary? */ /* is double-select really necessary? */
if (ap->device[1].class != ATA_DEV_NONE) if (ap->device[1].class != ATA_DEV_NONE)
...@@ -2601,10 +2622,10 @@ static void ata_qc_timeout(struct ata_queued_cmd *qc) ...@@ -2601,10 +2622,10 @@ static void ata_qc_timeout(struct ata_queued_cmd *qc)
case ATA_PROT_DMA: case ATA_PROT_DMA:
case ATA_PROT_ATAPI_DMA: case ATA_PROT_ATAPI_DMA:
host_stat = ata_bmdma_status(ap); host_stat = ap->ops->bmdma_status(ap);
/* before we do anything else, clear DMA-Start bit */ /* before we do anything else, clear DMA-Start bit */
ata_bmdma_stop(ap); ap->ops->bmdma_stop(ap);
/* fall through */ /* fall through */
...@@ -2613,7 +2634,7 @@ static void ata_qc_timeout(struct ata_queued_cmd *qc) ...@@ -2613,7 +2634,7 @@ static void ata_qc_timeout(struct ata_queued_cmd *qc)
drv_stat = ata_chk_status(ap); drv_stat = ata_chk_status(ap);
/* ack bmdma irq events */ /* ack bmdma irq events */
ata_bmdma_ack_irq(ap); ap->ops->irq_clear(ap);
printk(KERN_ERR "ata%u: command 0x%x timeout, stat 0x%x host_stat 0x%x\n", printk(KERN_ERR "ata%u: command 0x%x timeout, stat 0x%x host_stat 0x%x\n",
ap->id, qc->tf.command, drv_stat, host_stat); ap->id, qc->tf.command, drv_stat, host_stat);
...@@ -2751,6 +2772,24 @@ static void __ata_qc_complete(struct ata_queued_cmd *qc) ...@@ -2751,6 +2772,24 @@ static void __ata_qc_complete(struct ata_queued_cmd *qc)
clear_bit(tag, &ap->qactive); clear_bit(tag, &ap->qactive);
} }
/**
* ata_qc_free - free unused ata_queued_cmd
* @qc: Command to complete
*
* Designed to free unused ata_queued_cmd object
* in case something prevents using it.
*
* LOCKING:
*
*/
void ata_qc_free(struct ata_queued_cmd *qc)
{
assert(qc != NULL); /* ata_qc_from_tag _might_ return NULL */
assert(qc->waiting == NULL); /* nothing should be waiting */
__ata_qc_complete(qc);
}
/** /**
* ata_qc_complete - Complete an active ATA command * ata_qc_complete - Complete an active ATA command
* @qc: Command to complete * @qc: Command to complete
...@@ -3042,7 +3081,43 @@ void ata_bmdma_setup(struct ata_queued_cmd *qc) ...@@ -3042,7 +3081,43 @@ void ata_bmdma_setup(struct ata_queued_cmd *qc)
void ata_bmdma_irq_clear(struct ata_port *ap) void ata_bmdma_irq_clear(struct ata_port *ap)
{ {
ata_bmdma_ack_irq(ap); if (ap->flags & ATA_FLAG_MMIO) {
void __iomem *mmio = ((void __iomem *) ap->ioaddr.bmdma_addr) + ATA_DMA_STATUS;
writeb(readb(mmio), mmio);
} else {
unsigned long addr = ap->ioaddr.bmdma_addr + ATA_DMA_STATUS;
outb(inb(addr), addr);
}
}
u8 ata_bmdma_status(struct ata_port *ap)
{
u8 host_stat;
if (ap->flags & ATA_FLAG_MMIO) {
void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr;
host_stat = readb(mmio + ATA_DMA_STATUS);
} else
host_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
return host_stat;
}
void ata_bmdma_stop(struct ata_port *ap)
{
if (ap->flags & ATA_FLAG_MMIO) {
void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr;
/* clear start/stop bit */
writeb(readb(mmio + ATA_DMA_CMD) & ~ATA_DMA_START,
mmio + ATA_DMA_CMD);
} else {
/* clear start/stop bit */
outb(inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD) & ~ATA_DMA_START,
ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
}
/* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */
ata_altstatus(ap); /* dummy read */
} }
/** /**
...@@ -3072,7 +3147,7 @@ inline unsigned int ata_host_intr (struct ata_port *ap, ...@@ -3072,7 +3147,7 @@ inline unsigned int ata_host_intr (struct ata_port *ap,
case ATA_PROT_ATAPI_DMA: case ATA_PROT_ATAPI_DMA:
case ATA_PROT_ATAPI: case ATA_PROT_ATAPI:
/* check status of DMA engine */ /* check status of DMA engine */
host_stat = ata_bmdma_status(ap); host_stat = ap->ops->bmdma_status(ap);
VPRINTK("ata%u: host_stat 0x%X\n", ap->id, host_stat); VPRINTK("ata%u: host_stat 0x%X\n", ap->id, host_stat);
/* if it's not our irq... */ /* if it's not our irq... */
...@@ -3080,7 +3155,7 @@ inline unsigned int ata_host_intr (struct ata_port *ap, ...@@ -3080,7 +3155,7 @@ inline unsigned int ata_host_intr (struct ata_port *ap,
goto idle_irq; goto idle_irq;
/* before we do anything else, clear DMA-Start bit */ /* before we do anything else, clear DMA-Start bit */
ata_bmdma_stop(ap); ap->ops->bmdma_stop(ap);
/* fall through */ /* fall through */
...@@ -3099,7 +3174,7 @@ inline unsigned int ata_host_intr (struct ata_port *ap, ...@@ -3099,7 +3174,7 @@ inline unsigned int ata_host_intr (struct ata_port *ap,
ap->id, qc->tf.protocol, status); ap->id, qc->tf.protocol, status);
/* ack bmdma irq events */ /* ack bmdma irq events */
ata_bmdma_ack_irq(ap); ap->ops->irq_clear(ap);
/* complete taskfile transaction */ /* complete taskfile transaction */
ata_qc_complete(qc, status); ata_qc_complete(qc, status);
...@@ -3656,6 +3731,7 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info, ...@@ -3656,6 +3731,7 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
struct ata_port_info *port[2]; struct ata_port_info *port[2];
u8 tmp8, mask; u8 tmp8, mask;
unsigned int legacy_mode = 0; unsigned int legacy_mode = 0;
int disable_dev_on_err = 1;
int rc; int rc;
DPRINTK("ENTER\n"); DPRINTK("ENTER\n");
...@@ -3686,8 +3762,10 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info, ...@@ -3686,8 +3762,10 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
return rc; return rc;
rc = pci_request_regions(pdev, DRV_NAME); rc = pci_request_regions(pdev, DRV_NAME);
if (rc) if (rc) {
disable_dev_on_err = 0;
goto err_out; goto err_out;
}
if (legacy_mode) { if (legacy_mode) {
if (!request_region(0x1f0, 8, "libata")) { if (!request_region(0x1f0, 8, "libata")) {
...@@ -3697,8 +3775,10 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info, ...@@ -3697,8 +3775,10 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
conflict = ____request_resource(&ioport_resource, &res); conflict = ____request_resource(&ioport_resource, &res);
if (!strcmp(conflict->name, "libata")) if (!strcmp(conflict->name, "libata"))
legacy_mode |= (1 << 0); legacy_mode |= (1 << 0);
else else {
disable_dev_on_err = 0;
printk(KERN_WARNING "ata: 0x1f0 IDE port busy\n"); printk(KERN_WARNING "ata: 0x1f0 IDE port busy\n");
}
} else } else
legacy_mode |= (1 << 0); legacy_mode |= (1 << 0);
...@@ -3709,8 +3789,10 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info, ...@@ -3709,8 +3789,10 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
conflict = ____request_resource(&ioport_resource, &res); conflict = ____request_resource(&ioport_resource, &res);
if (!strcmp(conflict->name, "libata")) if (!strcmp(conflict->name, "libata"))
legacy_mode |= (1 << 1); legacy_mode |= (1 << 1);
else else {
disable_dev_on_err = 0;
printk(KERN_WARNING "ata: 0x170 IDE port busy\n"); printk(KERN_WARNING "ata: 0x170 IDE port busy\n");
}
} else } else
legacy_mode |= (1 << 1); legacy_mode |= (1 << 1);
} }
...@@ -3760,7 +3842,8 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info, ...@@ -3760,7 +3842,8 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
release_region(0x170, 8); release_region(0x170, 8);
pci_release_regions(pdev); pci_release_regions(pdev);
err_out: err_out:
pci_disable_device(pdev); if (disable_dev_on_err)
pci_disable_device(pdev);
return rc; return rc;
} }
...@@ -3910,6 +3993,8 @@ EXPORT_SYMBOL_GPL(ata_std_dev_select); ...@@ -3910,6 +3993,8 @@ EXPORT_SYMBOL_GPL(ata_std_dev_select);
EXPORT_SYMBOL_GPL(ata_tf_to_fis); EXPORT_SYMBOL_GPL(ata_tf_to_fis);
EXPORT_SYMBOL_GPL(ata_tf_from_fis); EXPORT_SYMBOL_GPL(ata_tf_from_fis);
EXPORT_SYMBOL_GPL(ata_check_status); EXPORT_SYMBOL_GPL(ata_check_status);
EXPORT_SYMBOL_GPL(ata_altstatus);
EXPORT_SYMBOL_GPL(ata_chk_err);
EXPORT_SYMBOL_GPL(ata_exec_command); EXPORT_SYMBOL_GPL(ata_exec_command);
EXPORT_SYMBOL_GPL(ata_port_start); EXPORT_SYMBOL_GPL(ata_port_start);
EXPORT_SYMBOL_GPL(ata_port_stop); EXPORT_SYMBOL_GPL(ata_port_stop);
...@@ -3918,6 +4003,8 @@ EXPORT_SYMBOL_GPL(ata_qc_prep); ...@@ -3918,6 +4003,8 @@ EXPORT_SYMBOL_GPL(ata_qc_prep);
EXPORT_SYMBOL_GPL(ata_bmdma_setup); EXPORT_SYMBOL_GPL(ata_bmdma_setup);
EXPORT_SYMBOL_GPL(ata_bmdma_start); EXPORT_SYMBOL_GPL(ata_bmdma_start);
EXPORT_SYMBOL_GPL(ata_bmdma_irq_clear); EXPORT_SYMBOL_GPL(ata_bmdma_irq_clear);
EXPORT_SYMBOL_GPL(ata_bmdma_status);
EXPORT_SYMBOL_GPL(ata_bmdma_stop);
EXPORT_SYMBOL_GPL(ata_port_probe); EXPORT_SYMBOL_GPL(ata_port_probe);
EXPORT_SYMBOL_GPL(sata_phy_reset); EXPORT_SYMBOL_GPL(sata_phy_reset);
EXPORT_SYMBOL_GPL(__sata_phy_reset); EXPORT_SYMBOL_GPL(__sata_phy_reset);
......
...@@ -701,6 +701,7 @@ static void ata_scsi_translate(struct ata_port *ap, struct ata_device *dev, ...@@ -701,6 +701,7 @@ static void ata_scsi_translate(struct ata_port *ap, struct ata_device *dev,
return; return;
err_out: err_out:
ata_qc_free(qc);
ata_bad_cdb(cmd, done); ata_bad_cdb(cmd, done);
DPRINTK("EXIT - badcmd\n"); DPRINTK("EXIT - badcmd\n");
} }
......
...@@ -37,6 +37,7 @@ struct ata_scsi_args { ...@@ -37,6 +37,7 @@ struct ata_scsi_args {
/* libata-core.c */ /* libata-core.c */
extern struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap, extern struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap,
struct ata_device *dev); struct ata_device *dev);
extern void ata_qc_free(struct ata_queued_cmd *qc);
extern int ata_qc_issue(struct ata_queued_cmd *qc); extern int ata_qc_issue(struct ata_queued_cmd *qc);
extern int ata_check_atapi_dma(struct ata_queued_cmd *qc); extern int ata_check_atapi_dma(struct ata_queued_cmd *qc);
extern void ata_dev_select(struct ata_port *ap, unsigned int device, extern void ata_dev_select(struct ata_port *ap, unsigned int device,
......
...@@ -217,6 +217,8 @@ static struct ata_port_operations nv_ops = { ...@@ -217,6 +217,8 @@ static struct ata_port_operations nv_ops = {
.phy_reset = sata_phy_reset, .phy_reset = sata_phy_reset,
.bmdma_setup = ata_bmdma_setup, .bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start, .bmdma_start = ata_bmdma_start,
.bmdma_stop = ata_bmdma_stop,
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep, .qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot, .qc_issue = ata_qc_issue_prot,
.eng_timeout = ata_eng_timeout, .eng_timeout = ata_eng_timeout,
...@@ -332,6 +334,7 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -332,6 +334,7 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
struct nv_host *host; struct nv_host *host;
struct ata_port_info *ppi; struct ata_port_info *ppi;
struct ata_probe_ent *probe_ent; struct ata_probe_ent *probe_ent;
int pci_dev_busy = 0;
int rc; int rc;
u32 bar; u32 bar;
...@@ -350,8 +353,10 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -350,8 +353,10 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
goto err_out; goto err_out;
rc = pci_request_regions(pdev, DRV_NAME); rc = pci_request_regions(pdev, DRV_NAME);
if (rc) if (rc) {
pci_dev_busy = 1;
goto err_out_disable; goto err_out_disable;
}
rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
if (rc) if (rc)
...@@ -427,7 +432,8 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -427,7 +432,8 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
err_out_regions: err_out_regions:
pci_release_regions(pdev); pci_release_regions(pdev);
err_out_disable: err_out_disable:
pci_disable_device(pdev); if (!pci_dev_busy)
pci_disable_device(pdev);
err_out: err_out:
return rc; return rc;
} }
......
...@@ -556,6 +556,7 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e ...@@ -556,6 +556,7 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
unsigned long base; unsigned long base;
void *mmio_base; void *mmio_base;
unsigned int board_idx = (unsigned int) ent->driver_data; unsigned int board_idx = (unsigned int) ent->driver_data;
int pci_dev_busy = 0;
int rc; int rc;
if (!printed_version++) if (!printed_version++)
...@@ -570,8 +571,10 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e ...@@ -570,8 +571,10 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
return rc; return rc;
rc = pci_request_regions(pdev, DRV_NAME); rc = pci_request_regions(pdev, DRV_NAME);
if (rc) if (rc) {
pci_dev_busy = 1;
goto err_out; goto err_out;
}
rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
if (rc) if (rc)
...@@ -650,7 +653,8 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e ...@@ -650,7 +653,8 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
err_out_regions: err_out_regions:
pci_release_regions(pdev); pci_release_regions(pdev);
err_out: err_out:
pci_disable_device(pdev); if (!pci_dev_busy)
pci_disable_device(pdev);
return rc; return rc;
} }
......
/*
* sata_qstor.c - Pacific Digital Corporation QStor SATA
*
* Maintained by: Mark Lord <mlord@pobox.com>
*
* Copyright 2005 Pacific Digital Corporation.
* (OSL/GPL code release authorized by Jalil Fadavi).
*
* The contents of this file are subject to the Open
* Software License version 1.1 that can be found at
* http://www.opensource.org/licenses/osl-1.1.txt and is included herein
* by reference.
*
* Alternatively, the contents of this file may be used under the terms
* of the GNU General Public License version 2 (the "GPL") as distributed
* in the kernel source COPYING file, in which case the provisions of
* the GPL are applicable instead of the above. If you wish to allow
* the use of your version of this file only under the terms of the
* GPL and not to allow others to use your version of this file under
* the OSL, indicate your decision by deleting the provisions above and
* replace them with the notice and other provisions required by the GPL.
* If you do not delete the provisions above, a recipient may use your
* version of this file under either the OSL or the GPL.
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include "scsi.h"
#include <scsi/scsi_host.h>
#include <asm/io.h>
#include <linux/libata.h>
#define DRV_NAME "sata_qstor"
#define DRV_VERSION "0.03"
enum {
QS_PORTS = 4,
QS_MAX_PRD = LIBATA_MAX_PRD,
QS_CPB_ORDER = 6,
QS_CPB_BYTES = (1 << QS_CPB_ORDER),
QS_PRD_BYTES = QS_MAX_PRD * 16,
QS_PKT_BYTES = QS_CPB_BYTES + QS_PRD_BYTES,
QS_DMA_BOUNDARY = ~0UL,
/* global register offsets */
QS_HCF_CNFG3 = 0x0003, /* host configuration offset */
QS_HID_HPHY = 0x0004, /* host physical interface info */
QS_HCT_CTRL = 0x00e4, /* global interrupt mask offset */
QS_HST_SFF = 0x0100, /* host status fifo offset */
QS_HVS_SERD3 = 0x0393, /* PHY enable offset */
/* global control bits */
QS_HPHY_64BIT = (1 << 1), /* 64-bit bus detected */
QS_CNFG3_GSRST = 0x01, /* global chip reset */
QS_SERD3_PHY_ENA = 0xf0, /* PHY detection ENAble*/
/* per-channel register offsets */
QS_CCF_CPBA = 0x0710, /* chan CPB base address */
QS_CCF_CSEP = 0x0718, /* chan CPB separation factor */
QS_CFC_HUFT = 0x0800, /* host upstream fifo threshold */
QS_CFC_HDFT = 0x0804, /* host downstream fifo threshold */
QS_CFC_DUFT = 0x0808, /* dev upstream fifo threshold */
QS_CFC_DDFT = 0x080c, /* dev downstream fifo threshold */
QS_CCT_CTR0 = 0x0900, /* chan control-0 offset */
QS_CCT_CTR1 = 0x0901, /* chan control-1 offset */
QS_CCT_CFF = 0x0a00, /* chan command fifo offset */
/* channel control bits */
QS_CTR0_REG = (1 << 1), /* register mode (vs. pkt mode) */
QS_CTR0_CLER = (1 << 2), /* clear channel errors */
QS_CTR1_RDEV = (1 << 1), /* sata phy/comms reset */
QS_CTR1_RCHN = (1 << 4), /* reset channel logic */
QS_CCF_RUN_PKT = 0x107, /* RUN a new dma PKT */
/* pkt sub-field headers */
QS_HCB_HDR = 0x01, /* Host Control Block header */
QS_DCB_HDR = 0x02, /* Device Control Block header */
/* pkt HCB flag bits */
QS_HF_DIRO = (1 << 0), /* data DIRection Out */
QS_HF_DAT = (1 << 3), /* DATa pkt */
QS_HF_IEN = (1 << 4), /* Interrupt ENable */
QS_HF_VLD = (1 << 5), /* VaLiD pkt */
/* pkt DCB flag bits */
QS_DF_PORD = (1 << 2), /* Pio OR Dma */
QS_DF_ELBA = (1 << 3), /* Extended LBA (lba48) */
/* PCI device IDs */
board_2068_idx = 0, /* QStor 4-port SATA/RAID */
};
typedef enum { qs_state_idle, qs_state_pkt, qs_state_mmio } qs_state_t;
struct qs_port_priv {
u8 *pkt;
dma_addr_t pkt_dma;
qs_state_t state;
};
static u32 qs_scr_read (struct ata_port *ap, unsigned int sc_reg);
static void qs_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
static int qs_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
static irqreturn_t qs_intr (int irq, void *dev_instance, struct pt_regs *regs);
static int qs_port_start(struct ata_port *ap);
static void qs_host_stop(struct ata_host_set *host_set);
static void qs_port_stop(struct ata_port *ap);
static void qs_phy_reset(struct ata_port *ap);
static void qs_qc_prep(struct ata_queued_cmd *qc);
static int qs_qc_issue(struct ata_queued_cmd *qc);
static int qs_check_atapi_dma(struct ata_queued_cmd *qc);
static void qs_bmdma_stop(struct ata_port *ap);
static u8 qs_bmdma_status(struct ata_port *ap);
static void qs_irq_clear(struct ata_port *ap);
static Scsi_Host_Template qs_ata_sht = {
.module = THIS_MODULE,
.name = DRV_NAME,
.ioctl = ata_scsi_ioctl,
.queuecommand = ata_scsi_queuecmd,
.eh_strategy_handler = ata_scsi_error,
.can_queue = ATA_DEF_QUEUE,
.this_id = ATA_SHT_THIS_ID,
.sg_tablesize = QS_MAX_PRD,
.max_sectors = ATA_MAX_SECTORS,
.cmd_per_lun = ATA_SHT_CMD_PER_LUN,
.emulated = ATA_SHT_EMULATED,
//FIXME .use_clustering = ATA_SHT_USE_CLUSTERING,
.use_clustering = ENABLE_CLUSTERING,
.proc_name = DRV_NAME,
.dma_boundary = QS_DMA_BOUNDARY,
.slave_configure = ata_scsi_slave_config,
.bios_param = ata_std_bios_param,
};
static struct ata_port_operations qs_ata_ops = {
.port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
.check_atapi_dma = qs_check_atapi_dma,
.exec_command = ata_exec_command,
.dev_select = ata_std_dev_select,
.phy_reset = qs_phy_reset,
.qc_prep = qs_qc_prep,
.qc_issue = qs_qc_issue,
.eng_timeout = ata_eng_timeout,
.irq_handler = qs_intr,
.irq_clear = qs_irq_clear,
.scr_read = qs_scr_read,
.scr_write = qs_scr_write,
.port_start = qs_port_start,
.port_stop = qs_port_stop,
.host_stop = qs_host_stop,
.bmdma_stop = qs_bmdma_stop,
.bmdma_status = qs_bmdma_status,
};
static struct ata_port_info qs_port_info[] = {
/* board_2068_idx */
{
.sht = &qs_ata_sht,
.host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
ATA_FLAG_SATA_RESET |
//FIXME ATA_FLAG_SRST |
ATA_FLAG_MMIO,
.pio_mask = 0x10, /* pio4 */
.udma_mask = 0x7f, /* udma0-6 */
.port_ops = &qs_ata_ops,
},
};
static struct pci_device_id qs_ata_pci_tbl[] = {
{ PCI_VENDOR_ID_PDC, 0x2068, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
board_2068_idx },
{ } /* terminate list */
};
static struct pci_driver qs_ata_pci_driver = {
.name = DRV_NAME,
.id_table = qs_ata_pci_tbl,
.probe = qs_ata_init_one,
.remove = ata_pci_remove_one,
};
static int qs_check_atapi_dma(struct ata_queued_cmd *qc)
{
return 1; /* ATAPI DMA not supported */
}
static void qs_bmdma_stop(struct ata_port *ap)
{
/* nothing */
}
static u8 qs_bmdma_status(struct ata_port *ap)
{
return 0;
}
static void qs_irq_clear(struct ata_port *ap)
{
/* nothing */
}
static void qs_enter_reg_mode(struct ata_port *ap)
{
u8 __iomem *chan = ap->host_set->mmio_base + (ap->port_no * 0x4000);
writeb(QS_CTR0_REG, chan + QS_CCT_CTR0);
readb(chan + QS_CCT_CTR0); /* flush */
}
static void qs_phy_reset(struct ata_port *ap)
{
u8 __iomem *chan = ap->host_set->mmio_base + (ap->port_no * 0x4000);
struct qs_port_priv *pp = ap->private_data;
pp->state = qs_state_idle;
writeb(QS_CTR1_RCHN, chan + QS_CCT_CTR1);
qs_enter_reg_mode(ap);
sata_phy_reset(ap);
}
static u32 qs_scr_read (struct ata_port *ap, unsigned int sc_reg)
{
if (sc_reg > SCR_CONTROL)
return ~0U;
return readl((void __iomem *)(ap->ioaddr.scr_addr + (sc_reg * 8)));
}
static void qs_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
{
if (sc_reg > SCR_CONTROL)
return;
writel(val, (void __iomem *)(ap->ioaddr.scr_addr + (sc_reg * 8)));
}
static void qs_fill_sg(struct ata_queued_cmd *qc)
{
struct scatterlist *sg = qc->sg;
struct ata_port *ap = qc->ap;
struct qs_port_priv *pp = ap->private_data;
unsigned int nelem;
u8 *prd = pp->pkt + QS_CPB_BYTES;
assert(sg != NULL);
assert(qc->n_elem > 0);
for (nelem = 0; nelem < qc->n_elem; nelem++,sg++) {
u64 addr;
u32 len;
addr = sg_dma_address(sg);
*(u64 *)prd = cpu_to_le64(addr);
prd += sizeof(u64);
len = sg_dma_len(sg);
*(u32 *)prd = cpu_to_le32(len);
prd += sizeof(u64);
VPRINTK("PRD[%u] = (0x%llX, 0x%X)\n", nelem,
(unsigned long long)addr, len);
}
}
static void qs_qc_prep(struct ata_queued_cmd *qc)
{
struct qs_port_priv *pp = qc->ap->private_data;
u8 dflags = QS_DF_PORD, *buf = pp->pkt;
u8 hflags = QS_HF_DAT | QS_HF_IEN | QS_HF_VLD;
u64 addr;
VPRINTK("ENTER\n");
qs_enter_reg_mode(qc->ap);
if (qc->tf.protocol != ATA_PROT_DMA) {
ata_qc_prep(qc);
return;
}
qs_fill_sg(qc);
if ((qc->tf.flags & ATA_TFLAG_WRITE))
hflags |= QS_HF_DIRO;
if ((qc->tf.flags & ATA_TFLAG_LBA48))
dflags |= QS_DF_ELBA;
/* host control block (HCB) */
buf[ 0] = QS_HCB_HDR;
buf[ 1] = hflags;
*(u32 *)(&buf[ 4]) = cpu_to_le32(qc->nsect * ATA_SECT_SIZE);
*(u32 *)(&buf[ 8]) = cpu_to_le32(qc->n_elem);
addr = ((u64)pp->pkt_dma) + QS_CPB_BYTES;
*(u64 *)(&buf[16]) = cpu_to_le64(addr);
/* device control block (DCB) */
buf[24] = QS_DCB_HDR;
buf[28] = dflags;
/* frame information structure (FIS) */
ata_tf_to_fis(&qc->tf, &buf[32], 0);
}
static inline void qs_packet_start(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
u8 __iomem *chan = ap->host_set->mmio_base + (ap->port_no * 0x4000);
VPRINTK("ENTER, ap %p\n", ap);
writeb(QS_CTR0_CLER, chan + QS_CCT_CTR0);
wmb(); /* flush PRDs and pkt to memory */
writel(QS_CCF_RUN_PKT, chan + QS_CCT_CFF);
readl(chan + QS_CCT_CFF); /* flush */
}
static int qs_qc_issue(struct ata_queued_cmd *qc)
{
struct qs_port_priv *pp = qc->ap->private_data;
switch (qc->tf.protocol) {
case ATA_PROT_DMA:
pp->state = qs_state_pkt;
qs_packet_start(qc);
return 0;
case ATA_PROT_ATAPI_DMA:
BUG();
break;
default:
break;
}
pp->state = qs_state_mmio;
return ata_qc_issue_prot(qc);
}
static inline unsigned int qs_intr_pkt(struct ata_host_set *host_set)
{
unsigned int handled = 0;
u8 sFFE;
u8 __iomem *mmio_base = host_set->mmio_base;
do {
u32 sff0 = readl(mmio_base + QS_HST_SFF);
u32 sff1 = readl(mmio_base + QS_HST_SFF + 4);
u8 sEVLD = (sff1 >> 30) & 0x01; /* valid flag */
sFFE = sff1 >> 31; /* empty flag */
if (sEVLD) {
u8 sDST = sff0 >> 16; /* dev status */
u8 sHST = sff1 & 0x3f; /* host status */
unsigned int port_no = (sff1 >> 8) & 0x03;
struct ata_port *ap = host_set->ports[port_no];
DPRINTK("SFF=%08x%08x: sCHAN=%u sHST=%d sDST=%02x\n",
sff1, sff0, port_no, sHST, sDST);
handled = 1;
if (ap && (!(ap->flags & ATA_FLAG_PORT_DISABLED))) {
struct ata_queued_cmd *qc;
struct qs_port_priv *pp = ap->private_data;
if (!pp || pp->state != qs_state_pkt)
continue;
qc = ata_qc_from_tag(ap, ap->active_tag);
if (qc && (!(qc->tf.ctl & ATA_NIEN))) {
switch (sHST) {
case 0: /* sucessful CPB */
case 3: /* device error */
pp->state = qs_state_idle;
qs_enter_reg_mode(qc->ap);
ata_qc_complete(qc, sDST);
break;
default:
break;
}
}
}
}
} while (!sFFE);
return handled;
}
static inline unsigned int qs_intr_mmio(struct ata_host_set *host_set)
{
unsigned int handled = 0, port_no;
for (port_no = 0; port_no < host_set->n_ports; ++port_no) {
struct ata_port *ap;
ap = host_set->ports[port_no];
if (ap && (!(ap->flags & ATA_FLAG_PORT_DISABLED))) {
struct ata_queued_cmd *qc;
struct qs_port_priv *pp = ap->private_data;
if (!pp || pp->state != qs_state_mmio)
continue;
qc = ata_qc_from_tag(ap, ap->active_tag);
if (qc && (!(qc->tf.ctl & ATA_NIEN))) {
/* check main status, clearing INTRQ */
u8 status = ata_chk_status(ap);
if ((status & ATA_BUSY))
continue;
DPRINTK("ata%u: protocol %d (dev_stat 0x%X)\n",
ap->id, qc->tf.protocol, status);
/* complete taskfile transaction */
pp->state = qs_state_idle;
ata_qc_complete(qc, status);
handled = 1;
}
}
}
return handled;
}
static irqreturn_t qs_intr(int irq, void *dev_instance, struct pt_regs *regs)
{
struct ata_host_set *host_set = dev_instance;
unsigned int handled = 0;
VPRINTK("ENTER\n");
spin_lock(&host_set->lock);
handled = qs_intr_pkt(host_set) | qs_intr_mmio(host_set);
spin_unlock(&host_set->lock);
VPRINTK("EXIT\n");
return IRQ_RETVAL(handled);
}
static void qs_ata_setup_port(struct ata_ioports *port, unsigned long base)
{
port->cmd_addr =
port->data_addr = base + 0x400;
port->error_addr =
port->feature_addr = base + 0x408; /* hob_feature = 0x409 */
port->nsect_addr = base + 0x410; /* hob_nsect = 0x411 */
port->lbal_addr = base + 0x418; /* hob_lbal = 0x419 */
port->lbam_addr = base + 0x420; /* hob_lbam = 0x421 */
port->lbah_addr = base + 0x428; /* hob_lbah = 0x429 */
port->device_addr = base + 0x430;
port->status_addr =
port->command_addr = base + 0x438;
port->altstatus_addr =
port->ctl_addr = base + 0x440;
port->scr_addr = base + 0xc00;
}
static int qs_port_start(struct ata_port *ap)
{
struct device *dev = ap->host_set->dev;
struct qs_port_priv *pp;
void __iomem *mmio_base = ap->host_set->mmio_base;
void __iomem *chan = mmio_base + (ap->port_no * 0x4000);
u64 addr;
int rc;
rc = ata_port_start(ap);
if (rc)
return rc;
qs_enter_reg_mode(ap);
pp = kcalloc(1, sizeof(*pp), GFP_KERNEL);
if (!pp) {
rc = -ENOMEM;
goto err_out;
}
pp->pkt = dma_alloc_coherent(dev, QS_PKT_BYTES, &pp->pkt_dma,
GFP_KERNEL);
if (!pp->pkt) {
rc = -ENOMEM;
goto err_out_kfree;
}
memset(pp->pkt, 0, QS_PKT_BYTES);
ap->private_data = pp;
addr = (u64)pp->pkt_dma;
writel((u32) addr, chan + QS_CCF_CPBA);
writel((u32)(addr >> 32), chan + QS_CCF_CPBA + 4);
return 0;
err_out_kfree:
kfree(pp);
err_out:
ata_port_stop(ap);
return rc;
}
static void qs_port_stop(struct ata_port *ap)
{
struct device *dev = ap->host_set->dev;
struct qs_port_priv *pp = ap->private_data;
if (pp != NULL) {
ap->private_data = NULL;
if (pp->pkt != NULL)
dma_free_coherent(dev, QS_PKT_BYTES, pp->pkt,
pp->pkt_dma);
kfree(pp);
}
ata_port_stop(ap);
}
static void qs_host_stop(struct ata_host_set *host_set)
{
void __iomem *mmio_base = host_set->mmio_base;
writeb(0, mmio_base + QS_HCT_CTRL); /* disable host interrupts */
writeb(QS_CNFG3_GSRST, mmio_base + QS_HCF_CNFG3); /* global reset */
}
static void qs_host_init(unsigned int chip_id, struct ata_probe_ent *pe)
{
void __iomem *mmio_base = pe->mmio_base;
unsigned int port_no;
writeb(0, mmio_base + QS_HCT_CTRL); /* disable host interrupts */
writeb(QS_CNFG3_GSRST, mmio_base + QS_HCF_CNFG3); /* global reset */
/* reset each channel in turn */
for (port_no = 0; port_no < pe->n_ports; ++port_no) {
u8 __iomem *chan = mmio_base + (port_no * 0x4000);
writeb(QS_CTR1_RDEV|QS_CTR1_RCHN, chan + QS_CCT_CTR1);
writeb(QS_CTR0_REG, chan + QS_CCT_CTR0);
readb(chan + QS_CCT_CTR0); /* flush */
}
writeb(QS_SERD3_PHY_ENA, mmio_base + QS_HVS_SERD3); /* enable phy */
for (port_no = 0; port_no < pe->n_ports; ++port_no) {
u8 __iomem *chan = mmio_base + (port_no * 0x4000);
/* set FIFO depths to same settings as Windows driver */
writew(32, chan + QS_CFC_HUFT);
writew(32, chan + QS_CFC_HDFT);
writew(10, chan + QS_CFC_DUFT);
writew( 8, chan + QS_CFC_DDFT);
/* set CPB size in bytes, as a power of two */
writeb(QS_CPB_ORDER, chan + QS_CCF_CSEP);
}
writeb(1, mmio_base + QS_HCT_CTRL); /* enable host interrupts */
}
/*
* The QStor understands 64-bit buses, and uses 64-bit fields
* for DMA pointers regardless of bus width. We just have to
* make sure our DMA masks are set appropriately for whatever
* bridge lies between us and the QStor, and then the DMA mapping
* code will ensure we only ever "see" appropriate buffer addresses.
* If we're 32-bit limited somewhere, then our 64-bit fields will
* just end up with zeros in the upper 32-bits, without any special
* logic required outside of this routine (below).
*/
static int qs_set_dma_masks(struct pci_dev *pdev, void __iomem *mmio_base)
{
u32 bus_info = readl(mmio_base + QS_HID_HPHY);
int rc, have_64bit_bus = (bus_info & QS_HPHY_64BIT);
if (have_64bit_bus &&
!pci_set_dma_mask(pdev, 0xffffffffffffffffULL)) {
rc = pci_set_consistent_dma_mask(pdev, 0xffffffffffffffffULL);
if (rc) {
rc = pci_set_consistent_dma_mask(pdev, 0xffffffffULL);
if (rc) {
printk(KERN_ERR DRV_NAME
"(%s): 64-bit DMA enable failed\n",
pci_name(pdev));
return rc;
}
}
} else {
rc = pci_set_dma_mask(pdev, 0xffffffffULL);
if (rc) {
printk(KERN_ERR DRV_NAME
"(%s): 32-bit DMA enable failed\n",
pci_name(pdev));
return rc;
}
rc = pci_set_consistent_dma_mask(pdev, 0xffffffffULL);
if (rc) {
printk(KERN_ERR DRV_NAME
"(%s): 32-bit consistent DMA enable failed\n",
pci_name(pdev));
return rc;
}
}
return 0;
}
static int qs_ata_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
static int printed_version;
struct ata_probe_ent *probe_ent = NULL;
void __iomem *mmio_base;
unsigned int board_idx = (unsigned int) ent->driver_data;
int rc, port_no;
if (!printed_version++)
printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n");
rc = pci_enable_device(pdev);
if (rc)
return rc;
rc = pci_request_regions(pdev, DRV_NAME);
if (rc)
goto err_out;
if ((pci_resource_flags(pdev, 4) & IORESOURCE_MEM) == 0) {
rc = -ENODEV;
goto err_out_regions;
}
mmio_base = ioremap(pci_resource_start(pdev, 4),
pci_resource_len(pdev, 4));
if (mmio_base == NULL) {
rc = -ENOMEM;
goto err_out_regions;
}
rc = qs_set_dma_masks(pdev, mmio_base);
if (rc)
goto err_out_iounmap;
probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
if (probe_ent == NULL) {
rc = -ENOMEM;
goto err_out_iounmap;
}
memset(probe_ent, 0, sizeof(*probe_ent));
probe_ent->dev = pci_dev_to_dev(pdev);
INIT_LIST_HEAD(&probe_ent->node);
probe_ent->sht = qs_port_info[board_idx].sht;
probe_ent->host_flags = qs_port_info[board_idx].host_flags;
probe_ent->pio_mask = qs_port_info[board_idx].pio_mask;
probe_ent->mwdma_mask = qs_port_info[board_idx].mwdma_mask;
probe_ent->udma_mask = qs_port_info[board_idx].udma_mask;
probe_ent->port_ops = qs_port_info[board_idx].port_ops;
probe_ent->irq = pdev->irq;
probe_ent->irq_flags = SA_SHIRQ;
probe_ent->mmio_base = mmio_base;
probe_ent->n_ports = QS_PORTS;
for (port_no = 0; port_no < probe_ent->n_ports; ++port_no) {
unsigned long chan = (unsigned long)mmio_base +
(port_no * 0x4000);
qs_ata_setup_port(&probe_ent->port[port_no], chan);
}
pci_set_master(pdev);
/* initialize adapter */
qs_host_init(board_idx, probe_ent);
rc = ata_device_add(probe_ent);
kfree(probe_ent);
if (rc != QS_PORTS)
goto err_out_iounmap;
return 0;
err_out_iounmap:
iounmap(mmio_base);
err_out_regions:
pci_release_regions(pdev);
err_out:
pci_disable_device(pdev);
return rc;
}
static int __init qs_ata_init(void)
{
return pci_module_init(&qs_ata_pci_driver);
}
static void __exit qs_ata_exit(void)
{
pci_unregister_driver(&qs_ata_pci_driver);
}
MODULE_AUTHOR("Mark Lord");
MODULE_DESCRIPTION("Pacific Digital Corporation QStor SATA low-level driver");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, qs_ata_pci_tbl);
MODULE_VERSION(DRV_VERSION);
module_init(qs_ata_init);
module_exit(qs_ata_exit);
...@@ -139,6 +139,8 @@ static struct ata_port_operations sil_ops = { ...@@ -139,6 +139,8 @@ static struct ata_port_operations sil_ops = {
.post_set_mode = sil_post_set_mode, .post_set_mode = sil_post_set_mode,
.bmdma_setup = ata_bmdma_setup, .bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start, .bmdma_start = ata_bmdma_start,
.bmdma_stop = ata_bmdma_stop,
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep, .qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot, .qc_issue = ata_qc_issue_prot,
.eng_timeout = ata_eng_timeout, .eng_timeout = ata_eng_timeout,
...@@ -336,6 +338,7 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -336,6 +338,7 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
void *mmio_base; void *mmio_base;
int rc; int rc;
unsigned int i; unsigned int i;
int pci_dev_busy = 0;
u32 tmp, irq_mask; u32 tmp, irq_mask;
if (!printed_version++) if (!printed_version++)
...@@ -350,8 +353,10 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -350,8 +353,10 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
return rc; return rc;
rc = pci_request_regions(pdev, DRV_NAME); rc = pci_request_regions(pdev, DRV_NAME);
if (rc) if (rc) {
pci_dev_busy = 1;
goto err_out; goto err_out;
}
rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
if (rc) if (rc)
...@@ -438,7 +443,8 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -438,7 +443,8 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
err_out_regions: err_out_regions:
pci_release_regions(pdev); pci_release_regions(pdev);
err_out: err_out:
pci_disable_device(pdev); if (!pci_dev_busy)
pci_disable_device(pdev);
return rc; return rc;
} }
......
...@@ -102,6 +102,8 @@ static struct ata_port_operations sis_ops = { ...@@ -102,6 +102,8 @@ static struct ata_port_operations sis_ops = {
.phy_reset = sata_phy_reset, .phy_reset = sata_phy_reset,
.bmdma_setup = ata_bmdma_setup, .bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start, .bmdma_start = ata_bmdma_start,
.bmdma_stop = ata_bmdma_stop,
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep, .qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot, .qc_issue = ata_qc_issue_prot,
.eng_timeout = ata_eng_timeout, .eng_timeout = ata_eng_timeout,
...@@ -200,14 +202,17 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -200,14 +202,17 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
int rc; int rc;
u32 genctl; u32 genctl;
struct ata_port_info *ppi; struct ata_port_info *ppi;
int pci_dev_busy = 0;
rc = pci_enable_device(pdev); rc = pci_enable_device(pdev);
if (rc) if (rc)
return rc; return rc;
rc = pci_request_regions(pdev, DRV_NAME); rc = pci_request_regions(pdev, DRV_NAME);
if (rc) if (rc) {
pci_dev_busy = 1;
goto err_out; goto err_out;
}
rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
if (rc) if (rc)
...@@ -259,7 +264,8 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -259,7 +264,8 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
pci_release_regions(pdev); pci_release_regions(pdev);
err_out: err_out:
pci_disable_device(pdev); if (!pci_dev_busy)
pci_disable_device(pdev);
return rc; return rc;
} }
......
...@@ -301,6 +301,8 @@ static struct ata_port_operations k2_sata_ops = { ...@@ -301,6 +301,8 @@ static struct ata_port_operations k2_sata_ops = {
.phy_reset = sata_phy_reset, .phy_reset = sata_phy_reset,
.bmdma_setup = k2_bmdma_setup_mmio, .bmdma_setup = k2_bmdma_setup_mmio,
.bmdma_start = k2_bmdma_start_mmio, .bmdma_start = k2_bmdma_start_mmio,
.bmdma_stop = ata_bmdma_stop,
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep, .qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot, .qc_issue = ata_qc_issue_prot,
.eng_timeout = ata_eng_timeout, .eng_timeout = ata_eng_timeout,
...@@ -338,6 +340,7 @@ static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *e ...@@ -338,6 +340,7 @@ static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
struct ata_probe_ent *probe_ent = NULL; struct ata_probe_ent *probe_ent = NULL;
unsigned long base; unsigned long base;
void *mmio_base; void *mmio_base;
int pci_dev_busy = 0;
int rc; int rc;
if (!printed_version++) if (!printed_version++)
...@@ -359,8 +362,10 @@ static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *e ...@@ -359,8 +362,10 @@ static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
/* Request PCI regions */ /* Request PCI regions */
rc = pci_request_regions(pdev, DRV_NAME); rc = pci_request_regions(pdev, DRV_NAME);
if (rc) if (rc) {
pci_dev_busy = 1;
goto err_out; goto err_out;
}
rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
if (rc) if (rc)
...@@ -433,7 +438,8 @@ static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *e ...@@ -433,7 +438,8 @@ static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
err_out_regions: err_out_regions:
pci_release_regions(pdev); pci_release_regions(pdev);
err_out: err_out:
pci_disable_device(pdev); if (!pci_dev_busy)
pci_disable_device(pdev);
return rc; return rc;
} }
......
...@@ -1366,6 +1366,7 @@ static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id * ...@@ -1366,6 +1366,7 @@ static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *
void *mmio_base, *dimm_mmio = NULL; void *mmio_base, *dimm_mmio = NULL;
struct pdc_host_priv *hpriv = NULL; struct pdc_host_priv *hpriv = NULL;
unsigned int board_idx = (unsigned int) ent->driver_data; unsigned int board_idx = (unsigned int) ent->driver_data;
int pci_dev_busy = 0;
int rc; int rc;
if (!printed_version++) if (!printed_version++)
...@@ -1380,8 +1381,10 @@ static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id * ...@@ -1380,8 +1381,10 @@ static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *
return rc; return rc;
rc = pci_request_regions(pdev, DRV_NAME); rc = pci_request_regions(pdev, DRV_NAME);
if (rc) if (rc) {
pci_dev_busy = 1;
goto err_out; goto err_out;
}
rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
if (rc) if (rc)
...@@ -1471,7 +1474,8 @@ static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id * ...@@ -1471,7 +1474,8 @@ static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *
err_out_regions: err_out_regions:
pci_release_regions(pdev); pci_release_regions(pdev);
err_out: err_out:
pci_disable_device(pdev); if (!pci_dev_busy)
pci_disable_device(pdev);
return rc; return rc;
} }
......
...@@ -97,6 +97,8 @@ static struct ata_port_operations uli_ops = { ...@@ -97,6 +97,8 @@ static struct ata_port_operations uli_ops = {
.bmdma_setup = ata_bmdma_setup, .bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start, .bmdma_start = ata_bmdma_start,
.bmdma_stop = ata_bmdma_stop,
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep, .qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot, .qc_issue = ata_qc_issue_prot,
...@@ -185,14 +187,17 @@ static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -185,14 +187,17 @@ static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
struct ata_port_info *ppi; struct ata_port_info *ppi;
int rc; int rc;
unsigned int board_idx = (unsigned int) ent->driver_data; unsigned int board_idx = (unsigned int) ent->driver_data;
int pci_dev_busy = 0;
rc = pci_enable_device(pdev); rc = pci_enable_device(pdev);
if (rc) if (rc)
return rc; return rc;
rc = pci_request_regions(pdev, DRV_NAME); rc = pci_request_regions(pdev, DRV_NAME);
if (rc) if (rc) {
pci_dev_busy = 1;
goto err_out; goto err_out;
}
rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
if (rc) if (rc)
...@@ -260,7 +265,8 @@ static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -260,7 +265,8 @@ static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
pci_release_regions(pdev); pci_release_regions(pdev);
err_out: err_out:
pci_disable_device(pdev); if (!pci_dev_busy)
pci_disable_device(pdev);
return rc; return rc;
} }
......
...@@ -24,6 +24,11 @@ ...@@ -24,6 +24,11 @@
If you do not delete the provisions above, a recipient may use your If you do not delete the provisions above, a recipient may use your
version of this file under either the OSL or the GPL. version of this file under either the OSL or the GPL.
----------------------------------------------------------------------
To-do list:
* VT6421 PATA support
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -38,11 +43,14 @@ ...@@ -38,11 +43,14 @@
#include <asm/io.h> #include <asm/io.h>
#define DRV_NAME "sata_via" #define DRV_NAME "sata_via"
#define DRV_VERSION "1.0" #define DRV_VERSION "1.1"
enum { enum board_ids_enum {
via_sata = 0, vt6420,
vt6421,
};
enum {
SATA_CHAN_ENAB = 0x40, /* SATA channel enable */ SATA_CHAN_ENAB = 0x40, /* SATA channel enable */
SATA_INT_GATE = 0x41, /* SATA interrupt gating */ SATA_INT_GATE = 0x41, /* SATA interrupt gating */
SATA_NATIVE_MODE = 0x42, /* Native mode enable */ SATA_NATIVE_MODE = 0x42, /* Native mode enable */
...@@ -50,10 +58,8 @@ enum { ...@@ -50,10 +58,8 @@ enum {
PORT0 = (1 << 1), PORT0 = (1 << 1),
PORT1 = (1 << 0), PORT1 = (1 << 0),
ALL_PORTS = PORT0 | PORT1,
ENAB_ALL = PORT0 | PORT1, N_PORTS = 2,
INT_GATE_ALL = PORT0 | PORT1,
NATIVE_MODE_ALL = (1 << 7) | (1 << 6) | (1 << 5) | (1 << 4), NATIVE_MODE_ALL = (1 << 7) | (1 << 6) | (1 << 5) | (1 << 4),
...@@ -66,7 +72,8 @@ static u32 svia_scr_read (struct ata_port *ap, unsigned int sc_reg); ...@@ -66,7 +72,8 @@ static u32 svia_scr_read (struct ata_port *ap, unsigned int sc_reg);
static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
static struct pci_device_id svia_pci_tbl[] = { static struct pci_device_id svia_pci_tbl[] = {
{ 0x1106, 0x3149, PCI_ANY_ID, PCI_ANY_ID, 0, 0, via_sata }, { 0x1106, 0x3149, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt6420 },
{ 0x1106, 0x3249, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt6421 },
{ } /* terminate list */ { } /* terminate list */
}; };
...@@ -110,6 +117,9 @@ static struct ata_port_operations svia_sata_ops = { ...@@ -110,6 +117,9 @@ static struct ata_port_operations svia_sata_ops = {
.bmdma_setup = ata_bmdma_setup, .bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start, .bmdma_start = ata_bmdma_start,
.bmdma_stop = ata_bmdma_stop,
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep, .qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot, .qc_issue = ata_qc_issue_prot,
...@@ -158,18 +168,132 @@ static const unsigned int svia_bar_sizes[] = { ...@@ -158,18 +168,132 @@ static const unsigned int svia_bar_sizes[] = {
8, 4, 8, 4, 16, 256 8, 4, 8, 4, 16, 256
}; };
static const unsigned int vt6421_bar_sizes[] = {
16, 16, 16, 16, 32, 128
};
static unsigned long svia_scr_addr(unsigned long addr, unsigned int port) static unsigned long svia_scr_addr(unsigned long addr, unsigned int port)
{ {
return addr + (port * 128); return addr + (port * 128);
} }
static unsigned long vt6421_scr_addr(unsigned long addr, unsigned int port)
{
return addr + (port * 64);
}
static void vt6421_init_addrs(struct ata_probe_ent *probe_ent,
struct pci_dev *pdev,
unsigned int port)
{
unsigned long reg_addr = pci_resource_start(pdev, port);
unsigned long bmdma_addr = pci_resource_start(pdev, 4) + (port * 8);
unsigned long scr_addr;
probe_ent->port[port].cmd_addr = reg_addr;
probe_ent->port[port].altstatus_addr =
probe_ent->port[port].ctl_addr = (reg_addr + 8) | ATA_PCI_CTL_OFS;
probe_ent->port[port].bmdma_addr = bmdma_addr;
scr_addr = vt6421_scr_addr(pci_resource_start(pdev, 5), port);
probe_ent->port[port].scr_addr = scr_addr;
ata_std_ports(&probe_ent->port[port]);
}
static struct ata_probe_ent *vt6420_init_probe_ent(struct pci_dev *pdev)
{
struct ata_probe_ent *probe_ent;
struct ata_port_info *ppi = &svia_port_info;
probe_ent = ata_pci_init_native_mode(pdev, &ppi);
if (!probe_ent)
return NULL;
probe_ent->port[0].scr_addr =
svia_scr_addr(pci_resource_start(pdev, 5), 0);
probe_ent->port[1].scr_addr =
svia_scr_addr(pci_resource_start(pdev, 5), 1);
return probe_ent;
}
static struct ata_probe_ent *vt6421_init_probe_ent(struct pci_dev *pdev)
{
struct ata_probe_ent *probe_ent;
unsigned int i;
probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
if (!probe_ent)
return NULL;
memset(probe_ent, 0, sizeof(*probe_ent));
probe_ent->dev = pci_dev_to_dev(pdev);
INIT_LIST_HEAD(&probe_ent->node);
probe_ent->sht = &svia_sht;
probe_ent->host_flags = ATA_FLAG_SATA | ATA_FLAG_SATA_RESET |
ATA_FLAG_NO_LEGACY;
probe_ent->port_ops = &svia_sata_ops;
probe_ent->n_ports = N_PORTS;
probe_ent->irq = pdev->irq;
probe_ent->irq_flags = SA_SHIRQ;
probe_ent->pio_mask = 0x1f;
probe_ent->mwdma_mask = 0x07;
probe_ent->udma_mask = 0x7f;
for (i = 0; i < N_PORTS; i++)
vt6421_init_addrs(probe_ent, pdev, i);
return probe_ent;
}
static void svia_configure(struct pci_dev *pdev)
{
u8 tmp8;
pci_read_config_byte(pdev, PCI_INTERRUPT_LINE, &tmp8);
printk(KERN_INFO DRV_NAME "(%s): routed to hard irq line %d\n",
pci_name(pdev),
(int) (tmp8 & 0xf0) == 0xf0 ? 0 : tmp8 & 0x0f);
/* make sure SATA channels are enabled */
pci_read_config_byte(pdev, SATA_CHAN_ENAB, &tmp8);
if ((tmp8 & ALL_PORTS) != ALL_PORTS) {
printk(KERN_DEBUG DRV_NAME "(%s): enabling SATA channels (0x%x)\n",
pci_name(pdev), (int) tmp8);
tmp8 |= ALL_PORTS;
pci_write_config_byte(pdev, SATA_CHAN_ENAB, tmp8);
}
/* make sure interrupts for each channel sent to us */
pci_read_config_byte(pdev, SATA_INT_GATE, &tmp8);
if ((tmp8 & ALL_PORTS) != ALL_PORTS) {
printk(KERN_DEBUG DRV_NAME "(%s): enabling SATA channel interrupts (0x%x)\n",
pci_name(pdev), (int) tmp8);
tmp8 |= ALL_PORTS;
pci_write_config_byte(pdev, SATA_INT_GATE, tmp8);
}
/* make sure native mode is enabled */
pci_read_config_byte(pdev, SATA_NATIVE_MODE, &tmp8);
if ((tmp8 & NATIVE_MODE_ALL) != NATIVE_MODE_ALL) {
printk(KERN_DEBUG DRV_NAME "(%s): enabling SATA channel native mode (0x%x)\n",
pci_name(pdev), (int) tmp8);
tmp8 |= NATIVE_MODE_ALL;
pci_write_config_byte(pdev, SATA_NATIVE_MODE, tmp8);
}
}
static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{ {
static int printed_version; static int printed_version;
unsigned int i; unsigned int i;
int rc; int rc;
struct ata_port_info *ppi;
struct ata_probe_ent *probe_ent; struct ata_probe_ent *probe_ent;
int board_id = (int) ent->driver_data;
const int *bar_sizes;
int pci_dev_busy = 0;
u8 tmp8; u8 tmp8;
if (!printed_version++) if (!printed_version++)
...@@ -180,20 +304,28 @@ static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -180,20 +304,28 @@ static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
return rc; return rc;
rc = pci_request_regions(pdev, DRV_NAME); rc = pci_request_regions(pdev, DRV_NAME);
if (rc) if (rc) {
pci_dev_busy = 1;
goto err_out; goto err_out;
}
pci_read_config_byte(pdev, SATA_PATA_SHARING, &tmp8); if (board_id == vt6420) {
if (tmp8 & SATA_2DEV) { pci_read_config_byte(pdev, SATA_PATA_SHARING, &tmp8);
printk(KERN_ERR DRV_NAME "(%s): SATA master/slave not supported (0x%x)\n", if (tmp8 & SATA_2DEV) {
pci_name(pdev), (int) tmp8); printk(KERN_ERR DRV_NAME "(%s): SATA master/slave not supported (0x%x)\n",
rc = -EIO; pci_name(pdev), (int) tmp8);
goto err_out_regions; rc = -EIO;
goto err_out_regions;
}
bar_sizes = &svia_bar_sizes[0];
} else {
bar_sizes = &vt6421_bar_sizes[0];
} }
for (i = 0; i < ARRAY_SIZE(svia_bar_sizes); i++) for (i = 0; i < ARRAY_SIZE(svia_bar_sizes); i++)
if ((pci_resource_start(pdev, i) == 0) || if ((pci_resource_start(pdev, i) == 0) ||
(pci_resource_len(pdev, i) < svia_bar_sizes[i])) { (pci_resource_len(pdev, i) < bar_sizes[i])) {
printk(KERN_ERR DRV_NAME "(%s): invalid PCI BAR %u (sz 0x%lx, val 0x%lx)\n", printk(KERN_ERR DRV_NAME "(%s): invalid PCI BAR %u (sz 0x%lx, val 0x%lx)\n",
pci_name(pdev), i, pci_name(pdev), i,
pci_resource_start(pdev, i), pci_resource_start(pdev, i),
...@@ -209,8 +341,11 @@ static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -209,8 +341,11 @@ static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
if (rc) if (rc)
goto err_out_regions; goto err_out_regions;
ppi = &svia_port_info; if (board_id == vt6420)
probe_ent = ata_pci_init_native_mode(pdev, &ppi); probe_ent = vt6420_init_probe_ent(pdev);
else
probe_ent = vt6421_init_probe_ent(pdev);
if (!probe_ent) { if (!probe_ent) {
printk(KERN_ERR DRV_NAME "(%s): out of memory\n", printk(KERN_ERR DRV_NAME "(%s): out of memory\n",
pci_name(pdev)); pci_name(pdev));
...@@ -218,42 +353,7 @@ static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -218,42 +353,7 @@ static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
goto err_out_regions; goto err_out_regions;
} }
probe_ent->port[0].scr_addr = svia_configure(pdev);
svia_scr_addr(pci_resource_start(pdev, 5), 0);
probe_ent->port[1].scr_addr =
svia_scr_addr(pci_resource_start(pdev, 5), 1);
pci_read_config_byte(pdev, PCI_INTERRUPT_LINE, &tmp8);
printk(KERN_INFO DRV_NAME "(%s): routed to hard irq line %d\n",
pci_name(pdev),
(int) (tmp8 & 0xf0) == 0xf0 ? 0 : tmp8 & 0x0f);
/* make sure SATA channels are enabled */
pci_read_config_byte(pdev, SATA_CHAN_ENAB, &tmp8);
if ((tmp8 & ENAB_ALL) != ENAB_ALL) {
printk(KERN_DEBUG DRV_NAME "(%s): enabling SATA channels (0x%x)\n",
pci_name(pdev), (int) tmp8);
tmp8 |= ENAB_ALL;
pci_write_config_byte(pdev, SATA_CHAN_ENAB, tmp8);
}
/* make sure interrupts for each channel sent to us */
pci_read_config_byte(pdev, SATA_INT_GATE, &tmp8);
if ((tmp8 & INT_GATE_ALL) != INT_GATE_ALL) {
printk(KERN_DEBUG DRV_NAME "(%s): enabling SATA channel interrupts (0x%x)\n",
pci_name(pdev), (int) tmp8);
tmp8 |= INT_GATE_ALL;
pci_write_config_byte(pdev, SATA_INT_GATE, tmp8);
}
/* make sure native mode is enabled */
pci_read_config_byte(pdev, SATA_NATIVE_MODE, &tmp8);
if ((tmp8 & NATIVE_MODE_ALL) != NATIVE_MODE_ALL) {
printk(KERN_DEBUG DRV_NAME "(%s): enabling SATA channel native mode (0x%x)\n",
pci_name(pdev), (int) tmp8);
tmp8 |= NATIVE_MODE_ALL;
pci_write_config_byte(pdev, SATA_NATIVE_MODE, tmp8);
}
pci_set_master(pdev); pci_set_master(pdev);
...@@ -266,7 +366,8 @@ static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -266,7 +366,8 @@ static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
err_out_regions: err_out_regions:
pci_release_regions(pdev); pci_release_regions(pdev);
err_out: err_out:
pci_disable_device(pdev); if (!pci_dev_busy)
pci_disable_device(pdev);
return rc; return rc;
} }
......
...@@ -217,6 +217,8 @@ static struct ata_port_operations vsc_sata_ops = { ...@@ -217,6 +217,8 @@ static struct ata_port_operations vsc_sata_ops = {
.phy_reset = sata_phy_reset, .phy_reset = sata_phy_reset,
.bmdma_setup = ata_bmdma_setup, .bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start, .bmdma_start = ata_bmdma_start,
.bmdma_stop = ata_bmdma_stop,
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep, .qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot, .qc_issue = ata_qc_issue_prot,
.eng_timeout = ata_eng_timeout, .eng_timeout = ata_eng_timeout,
...@@ -255,6 +257,7 @@ static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_d ...@@ -255,6 +257,7 @@ static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_d
static int printed_version; static int printed_version;
struct ata_probe_ent *probe_ent = NULL; struct ata_probe_ent *probe_ent = NULL;
unsigned long base; unsigned long base;
int pci_dev_busy = 0;
void *mmio_base; void *mmio_base;
int rc; int rc;
...@@ -274,8 +277,10 @@ static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_d ...@@ -274,8 +277,10 @@ static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_d
} }
rc = pci_request_regions(pdev, DRV_NAME); rc = pci_request_regions(pdev, DRV_NAME);
if (rc) if (rc) {
pci_dev_busy = 1;
goto err_out; goto err_out;
}
/* /*
* Use 32 bit DMA mask, because 64 bit address support is poor. * Use 32 bit DMA mask, because 64 bit address support is poor.
...@@ -352,7 +357,8 @@ static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_d ...@@ -352,7 +357,8 @@ static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_d
err_out_regions: err_out_regions:
pci_release_regions(pdev); pci_release_regions(pdev);
err_out: err_out:
pci_disable_device(pdev); if (!pci_dev_busy)
pci_disable_device(pdev);
return rc; return rc;
} }
......
...@@ -303,10 +303,10 @@ static int do_getlk(struct file *filp, int cmd, struct file_lock *fl) ...@@ -303,10 +303,10 @@ static int do_getlk(struct file *filp, int cmd, struct file_lock *fl)
status = NFS_PROTO(inode)->lock(filp, cmd, fl); status = NFS_PROTO(inode)->lock(filp, cmd, fl);
else { else {
struct file_lock *cfl = posix_test_lock(filp, fl); struct file_lock *cfl = posix_test_lock(filp, fl);
if (cfl != NULL) {
fl->fl_type = F_UNLCK;
if (cfl != NULL)
memcpy(fl, cfl, sizeof(*fl)); memcpy(fl, cfl, sizeof(*fl));
fl->fl_type = F_UNLCK;
}
} }
unlock_kernel(); unlock_kernel();
return status; return status;
......
...@@ -54,7 +54,7 @@ struct agp_kern_info { ...@@ -54,7 +54,7 @@ struct agp_kern_info {
struct pci_dev *device; struct pci_dev *device;
enum chipset_type chipset; enum chipset_type chipset;
unsigned long mode; unsigned long mode;
off_t aper_base; unsigned long aper_base;
size_t aper_size; size_t aper_size;
int max_memory; /* In pages */ int max_memory; /* In pages */
int current_memory; int current_memory;
......
...@@ -64,7 +64,7 @@ typedef struct _agp_info { ...@@ -64,7 +64,7 @@ typedef struct _agp_info {
struct agp_version version; /* version of the driver */ struct agp_version version; /* version of the driver */
__u32 bridge_id; /* bridge vendor/device */ __u32 bridge_id; /* bridge vendor/device */
__u32 agp_mode; /* mode info of bridge */ __u32 agp_mode; /* mode info of bridge */
off_t aper_base; /* base of aperture */ unsigned long aper_base;/* base of aperture */
size_t aper_size; /* size of aperture */ size_t aper_size; /* size of aperture */
size_t pg_total; /* max pages (swap + system) */ size_t pg_total; /* max pages (swap + system) */
size_t pg_system; /* max pages (system) */ size_t pg_system; /* max pages (system) */
...@@ -118,7 +118,7 @@ struct agp_info { ...@@ -118,7 +118,7 @@ struct agp_info {
struct agp_version version; /* version of the driver */ struct agp_version version; /* version of the driver */
u32 bridge_id; /* bridge vendor/device */ u32 bridge_id; /* bridge vendor/device */
u32 agp_mode; /* mode info of bridge */ u32 agp_mode; /* mode info of bridge */
off_t aper_base; /* base of aperture */ unsigned long aper_base;/* base of aperture */
size_t aper_size; /* size of aperture */ size_t aper_size; /* size of aperture */
size_t pg_total; /* max pages (swap + system) */ size_t pg_total; /* max pages (swap + system) */
size_t pg_system; /* max pages (system) */ size_t pg_system; /* max pages (system) */
......
...@@ -334,6 +334,8 @@ struct ata_port_operations { ...@@ -334,6 +334,8 @@ struct ata_port_operations {
void (*exec_command)(struct ata_port *ap, struct ata_taskfile *tf); void (*exec_command)(struct ata_port *ap, struct ata_taskfile *tf);
u8 (*check_status)(struct ata_port *ap); u8 (*check_status)(struct ata_port *ap);
u8 (*check_altstatus)(struct ata_port *ap);
u8 (*check_err)(struct ata_port *ap);
void (*dev_select)(struct ata_port *ap, unsigned int device); void (*dev_select)(struct ata_port *ap, unsigned int device);
void (*phy_reset) (struct ata_port *ap); void (*phy_reset) (struct ata_port *ap);
...@@ -360,6 +362,9 @@ struct ata_port_operations { ...@@ -360,6 +362,9 @@ struct ata_port_operations {
void (*port_stop) (struct ata_port *ap); void (*port_stop) (struct ata_port *ap);
void (*host_stop) (struct ata_host_set *host_set); void (*host_stop) (struct ata_host_set *host_set);
void (*bmdma_stop) (struct ata_port *ap);
u8 (*bmdma_status) (struct ata_port *ap);
}; };
struct ata_port_info { struct ata_port_info {
...@@ -400,6 +405,8 @@ extern void ata_tf_from_fis(u8 *fis, struct ata_taskfile *tf); ...@@ -400,6 +405,8 @@ extern void ata_tf_from_fis(u8 *fis, struct ata_taskfile *tf);
extern void ata_noop_dev_select (struct ata_port *ap, unsigned int device); extern void ata_noop_dev_select (struct ata_port *ap, unsigned int device);
extern void ata_std_dev_select (struct ata_port *ap, unsigned int device); extern void ata_std_dev_select (struct ata_port *ap, unsigned int device);
extern u8 ata_check_status(struct ata_port *ap); extern u8 ata_check_status(struct ata_port *ap);
extern u8 ata_altstatus(struct ata_port *ap);
extern u8 ata_chk_err(struct ata_port *ap);
extern void ata_exec_command(struct ata_port *ap, struct ata_taskfile *tf); extern void ata_exec_command(struct ata_port *ap, struct ata_taskfile *tf);
extern int ata_port_start (struct ata_port *ap); extern int ata_port_start (struct ata_port *ap);
extern void ata_port_stop (struct ata_port *ap); extern void ata_port_stop (struct ata_port *ap);
...@@ -415,6 +422,8 @@ extern void ata_dev_id_string(u16 *id, unsigned char *s, ...@@ -415,6 +422,8 @@ extern void ata_dev_id_string(u16 *id, unsigned char *s,
unsigned int ofs, unsigned int len); unsigned int ofs, unsigned int len);
extern void ata_bmdma_setup (struct ata_queued_cmd *qc); extern void ata_bmdma_setup (struct ata_queued_cmd *qc);
extern void ata_bmdma_start (struct ata_queued_cmd *qc); extern void ata_bmdma_start (struct ata_queued_cmd *qc);
extern void ata_bmdma_stop(struct ata_port *ap);
extern u8 ata_bmdma_status(struct ata_port *ap);
extern void ata_bmdma_irq_clear(struct ata_port *ap); extern void ata_bmdma_irq_clear(struct ata_port *ap);
extern void ata_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat); extern void ata_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat);
extern void ata_eng_timeout(struct ata_port *ap); extern void ata_eng_timeout(struct ata_port *ap);
...@@ -452,26 +461,11 @@ static inline unsigned int ata_dev_present(struct ata_device *dev) ...@@ -452,26 +461,11 @@ static inline unsigned int ata_dev_present(struct ata_device *dev)
(dev->class == ATA_DEV_ATAPI)); (dev->class == ATA_DEV_ATAPI));
} }
static inline u8 ata_chk_err(struct ata_port *ap)
{
if (ap->flags & ATA_FLAG_MMIO) {
return readb((void __iomem *) ap->ioaddr.error_addr);
}
return inb(ap->ioaddr.error_addr);
}
static inline u8 ata_chk_status(struct ata_port *ap) static inline u8 ata_chk_status(struct ata_port *ap)
{ {
return ap->ops->check_status(ap); return ap->ops->check_status(ap);
} }
static inline u8 ata_altstatus(struct ata_port *ap)
{
if (ap->flags & ATA_FLAG_MMIO)
return readb((void __iomem *)ap->ioaddr.altstatus_addr);
return inb(ap->ioaddr.altstatus_addr);
}
static inline void ata_pause(struct ata_port *ap) static inline void ata_pause(struct ata_port *ap)
{ {
ata_altstatus(ap); ata_altstatus(ap);
...@@ -595,46 +589,6 @@ static inline unsigned int sata_dev_present(struct ata_port *ap) ...@@ -595,46 +589,6 @@ static inline unsigned int sata_dev_present(struct ata_port *ap)
return ((scr_read(ap, SCR_STATUS) & 0xf) == 0x3) ? 1 : 0; return ((scr_read(ap, SCR_STATUS) & 0xf) == 0x3) ? 1 : 0;
} }
static inline void ata_bmdma_stop(struct ata_port *ap)
{
if (ap->flags & ATA_FLAG_MMIO) {
void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr;
/* clear start/stop bit */
writeb(readb(mmio + ATA_DMA_CMD) & ~ATA_DMA_START,
mmio + ATA_DMA_CMD);
} else {
/* clear start/stop bit */
outb(inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD) & ~ATA_DMA_START,
ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
}
/* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */
ata_altstatus(ap); /* dummy read */
}
static inline void ata_bmdma_ack_irq(struct ata_port *ap)
{
if (ap->flags & ATA_FLAG_MMIO) {
void __iomem *mmio = ((void __iomem *) ap->ioaddr.bmdma_addr) + ATA_DMA_STATUS;
writeb(readb(mmio), mmio);
} else {
unsigned long addr = ap->ioaddr.bmdma_addr + ATA_DMA_STATUS;
outb(inb(addr), addr);
}
}
static inline u8 ata_bmdma_status(struct ata_port *ap)
{
u8 host_stat;
if (ap->flags & ATA_FLAG_MMIO) {
void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr;
host_stat = readb(mmio + ATA_DMA_STATUS);
} else
host_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
return host_stat;
}
static inline int ata_try_flush_cache(struct ata_device *dev) static inline int ata_try_flush_cache(struct ata_device *dev)
{ {
return ata_id_wcache_enabled(dev->id) || return ata_id_wcache_enabled(dev->id) ||
......
...@@ -258,6 +258,18 @@ static void drop_key_refs(union futex_key *key) ...@@ -258,6 +258,18 @@ static void drop_key_refs(union futex_key *key)
} }
} }
static inline int get_futex_value_locked(int *dest, int __user *from)
{
int ret;
inc_preempt_count();
ret = __copy_from_user_inatomic(dest, from, sizeof(int));
dec_preempt_count();
preempt_check_resched();
return ret ? -EFAULT : 0;
}
/* /*
* The hash bucket lock must be held when this is called. * The hash bucket lock must be held when this is called.
* Afterwards, the futex_q must not be accessed. * Afterwards, the futex_q must not be accessed.
...@@ -329,6 +341,7 @@ static int futex_requeue(unsigned long uaddr1, unsigned long uaddr2, ...@@ -329,6 +341,7 @@ static int futex_requeue(unsigned long uaddr1, unsigned long uaddr2,
int ret, drop_count = 0; int ret, drop_count = 0;
unsigned int nqueued; unsigned int nqueued;
retry:
down_read(&current->mm->mmap_sem); down_read(&current->mm->mmap_sem);
ret = get_futex_key(uaddr1, &key1); ret = get_futex_key(uaddr1, &key1);
...@@ -355,9 +368,20 @@ static int futex_requeue(unsigned long uaddr1, unsigned long uaddr2, ...@@ -355,9 +368,20 @@ static int futex_requeue(unsigned long uaddr1, unsigned long uaddr2,
before *uaddr1. */ before *uaddr1. */
smp_mb(); smp_mb();
if (get_user(curval, (int __user *)uaddr1) != 0) { ret = get_futex_value_locked(&curval, (int __user *)uaddr1);
ret = -EFAULT;
goto out; if (unlikely(ret)) {
/* If we would have faulted, release mmap_sem, fault
* it in and start all over again.
*/
up_read(&current->mm->mmap_sem);
ret = get_user(curval, (int __user *)uaddr1);
if (!ret)
goto retry;
return ret;
} }
if (curval != *valp) { if (curval != *valp) {
ret = -EAGAIN; ret = -EAGAIN;
...@@ -480,6 +504,7 @@ static int futex_wait(unsigned long uaddr, int val, unsigned long time) ...@@ -480,6 +504,7 @@ static int futex_wait(unsigned long uaddr, int val, unsigned long time)
int ret, curval; int ret, curval;
struct futex_q q; struct futex_q q;
retry:
down_read(&current->mm->mmap_sem); down_read(&current->mm->mmap_sem);
ret = get_futex_key(uaddr, &q.key); ret = get_futex_key(uaddr, &q.key);
...@@ -508,9 +533,23 @@ static int futex_wait(unsigned long uaddr, int val, unsigned long time) ...@@ -508,9 +533,23 @@ static int futex_wait(unsigned long uaddr, int val, unsigned long time)
* We hold the mmap semaphore, so the mapping cannot have changed * We hold the mmap semaphore, so the mapping cannot have changed
* since we looked it up in get_futex_key. * since we looked it up in get_futex_key.
*/ */
if (get_user(curval, (int __user *)uaddr) != 0) {
ret = -EFAULT; ret = get_futex_value_locked(&curval, (int __user *)uaddr);
goto out_unqueue;
if (unlikely(ret)) {
/* If we would have faulted, release mmap_sem, fault it in and
* start all over again.
*/
up_read(&current->mm->mmap_sem);
if (!unqueue_me(&q)) /* There's a chance we got woken already */
return 0;
ret = get_user(curval, (int __user *)uaddr);
if (!ret)
goto retry;
return ret;
} }
if (curval != val) { if (curval != val) {
ret = -EWOULDBLOCK; ret = -EWOULDBLOCK;
......
...@@ -524,9 +524,13 @@ asmlinkage long sys_get_mempolicy(int __user *policy, ...@@ -524,9 +524,13 @@ asmlinkage long sys_get_mempolicy(int __user *policy,
} else } else
pval = pol->policy; pval = pol->policy;
err = -EFAULT; if (vma) {
up_read(&current->mm->mmap_sem);
vma = NULL;
}
if (policy && put_user(pval, policy)) if (policy && put_user(pval, policy))
goto out; return -EFAULT;
err = 0; err = 0;
if (nmask) { if (nmask) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment