Merge branch 'master' into upstream

This commit is contained in:
Jeff Garzik 2006-07-06 13:07:32 -04:00
commit 70f05366b7
35 changed files with 1371 additions and 672 deletions

View File

@ -1,7 +1,7 @@
VERSION = 2
PATCHLEVEL = 6
SUBLEVEL = 17
EXTRAVERSION =
SUBLEVEL = 18
EXTRAVERSION = -rc1
NAME=Crazed Snow-Weasel
# *DOCUMENTATION*
@ -528,7 +528,7 @@ export MODLIB
ifdef INSTALL_MOD_STRIP
ifeq ($(INSTALL_MOD_STRIP),1)
mod_strip_cmd = $STRIP) --strip-debug
mod_strip_cmd = $(STRIP) --strip-debug
else
mod_strip_cmd = $(STRIP) $(INSTALL_MOD_STRIP)
endif # INSTALL_MOD_STRIP=1

View File

@ -107,3 +107,48 @@ void __init at91rm9200_map_io(void)
iotable_init(at91rm9200_io_desc, ARRAY_SIZE(at91rm9200_io_desc));
}
/*
* The default interrupt priority levels (0 = lowest, 7 = highest).
*/
static unsigned int at91rm9200_default_irq_priority[NR_AIC_IRQS] __initdata = {
7, /* Advanced Interrupt Controller (FIQ) */
7, /* System Peripherals */
0, /* Parallel IO Controller A */
0, /* Parallel IO Controller B */
0, /* Parallel IO Controller C */
0, /* Parallel IO Controller D */
6, /* USART 0 */
6, /* USART 1 */
6, /* USART 2 */
6, /* USART 3 */
0, /* Multimedia Card Interface */
4, /* USB Device Port */
0, /* Two-Wire Interface */
6, /* Serial Peripheral Interface */
5, /* Serial Synchronous Controller 0 */
5, /* Serial Synchronous Controller 1 */
5, /* Serial Synchronous Controller 2 */
0, /* Timer Counter 0 */
0, /* Timer Counter 1 */
0, /* Timer Counter 2 */
0, /* Timer Counter 3 */
0, /* Timer Counter 4 */
0, /* Timer Counter 5 */
3, /* USB Host port */
3, /* Ethernet MAC */
0, /* Advanced Interrupt Controller (IRQ0) */
0, /* Advanced Interrupt Controller (IRQ1) */
0, /* Advanced Interrupt Controller (IRQ2) */
0, /* Advanced Interrupt Controller (IRQ3) */
0, /* Advanced Interrupt Controller (IRQ4) */
0, /* Advanced Interrupt Controller (IRQ5) */
0 /* Advanced Interrupt Controller (IRQ6) */
};
void __init at91rm9200_init_irq(unsigned int priority[NR_AIC_IRQS])
{
if (!priority)
priority = at91rm9200_default_irq_priority;
at91_aic_init(priority);
}

View File

@ -8,13 +8,19 @@
* published by the Free Software Foundation.
*/
void at91_gpio_irq_setup(unsigned banks);
/* Interrupts */
extern void __init at91rm9200_init_irq(unsigned int priority[]);
extern void __init at91_aic_init(unsigned int priority[]);
extern void __init at91_gpio_irq_setup(unsigned banks);
/* Timer */
struct sys_timer;
extern struct sys_timer at91rm9200_timer;
/* Memory Map */
extern void __init at91rm9200_map_io(void);
/* Clocks */
extern int __init at91_clock_init(unsigned long main_clock);
struct device;
extern void __init at91_clock_associate(const char *id, struct device *dev, const char *func);

View File

@ -36,58 +36,20 @@
#include "generic.h"
/*
* The default interrupt priority levels (0 = lowest, 7 = highest).
*/
static unsigned int at91rm9200_default_irq_priority[NR_AIC_IRQS] __initdata = {
7, /* Advanced Interrupt Controller */
7, /* System Peripheral */
0, /* Parallel IO Controller A */
0, /* Parallel IO Controller B */
0, /* Parallel IO Controller C */
0, /* Parallel IO Controller D */
6, /* USART 0 */
6, /* USART 1 */
6, /* USART 2 */
6, /* USART 3 */
0, /* Multimedia Card Interface */
4, /* USB Device Port */
0, /* Two-Wire Interface */
6, /* Serial Peripheral Interface */
5, /* Serial Synchronous Controller */
5, /* Serial Synchronous Controller */
5, /* Serial Synchronous Controller */
0, /* Timer Counter 0 */
0, /* Timer Counter 1 */
0, /* Timer Counter 2 */
0, /* Timer Counter 3 */
0, /* Timer Counter 4 */
0, /* Timer Counter 5 */
3, /* USB Host port */
3, /* Ethernet MAC */
0, /* Advanced Interrupt Controller */
0, /* Advanced Interrupt Controller */
0, /* Advanced Interrupt Controller */
0, /* Advanced Interrupt Controller */
0, /* Advanced Interrupt Controller */
0, /* Advanced Interrupt Controller */
0 /* Advanced Interrupt Controller */
};
static void at91rm9200_mask_irq(unsigned int irq)
static void at91_aic_mask_irq(unsigned int irq)
{
/* Disable interrupt on AIC */
at91_sys_write(AT91_AIC_IDCR, 1 << irq);
}
static void at91rm9200_unmask_irq(unsigned int irq)
static void at91_aic_unmask_irq(unsigned int irq)
{
/* Enable interrupt on AIC */
at91_sys_write(AT91_AIC_IECR, 1 << irq);
}
static int at91rm9200_irq_type(unsigned irq, unsigned type)
static int at91_aic_set_type(unsigned irq, unsigned type)
{
unsigned int smr, srctype;
@ -122,7 +84,7 @@ static int at91rm9200_irq_type(unsigned irq, unsigned type)
static u32 wakeups;
static u32 backups;
static int at91rm9200_irq_set_wake(unsigned irq, unsigned value)
static int at91_aic_set_wake(unsigned irq, unsigned value)
{
if (unlikely(irq >= 32))
return -EINVAL;
@ -149,28 +111,24 @@ void at91_irq_resume(void)
}
#else
#define at91rm9200_irq_set_wake NULL
#define at91_aic_set_wake NULL
#endif
static struct irqchip at91rm9200_irq_chip = {
.ack = at91rm9200_mask_irq,
.mask = at91rm9200_mask_irq,
.unmask = at91rm9200_unmask_irq,
.set_type = at91rm9200_irq_type,
.set_wake = at91rm9200_irq_set_wake,
static struct irqchip at91_aic_chip = {
.ack = at91_aic_mask_irq,
.mask = at91_aic_mask_irq,
.unmask = at91_aic_unmask_irq,
.set_type = at91_aic_set_type,
.set_wake = at91_aic_set_wake,
};
/*
* Initialize the AIC interrupt controller.
*/
void __init at91rm9200_init_irq(unsigned int priority[NR_AIC_IRQS])
void __init at91_aic_init(unsigned int priority[NR_AIC_IRQS])
{
unsigned int i;
/* No priority list specified for this board -> use defaults */
if (priority == NULL)
priority = at91rm9200_default_irq_priority;
/*
* The IVR is used by macro get_irqnr_and_base to read and verify.
* The irq number is NR_AIC_IRQS when a spurious interrupt has occurred.
@ -178,10 +136,10 @@ void __init at91rm9200_init_irq(unsigned int priority[NR_AIC_IRQS])
for (i = 0; i < NR_AIC_IRQS; i++) {
/* Put irq number in Source Vector Register: */
at91_sys_write(AT91_AIC_SVR(i), i);
/* Store the Source Mode Register as defined in table above */
/* Active Low interrupt, with the specified priority */
at91_sys_write(AT91_AIC_SMR(i), AT91_AIC_SRCTYPE_LOW | priority[i]);
set_irq_chip(i, &at91rm9200_irq_chip);
set_irq_chip(i, &at91_aic_chip);
set_irq_handler(i, do_level_IRQ);
set_irq_flags(i, IRQF_VALID | IRQF_PROBE);

View File

@ -27,7 +27,6 @@
#include <linux/spi/spi.h>
#include <asm/hardware.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/setup.h>
#include <asm/mach-types.h>
@ -36,7 +35,6 @@
#include <asm/system.h>
#include <asm/mach/arch.h>
#include <asm/mach/irq.h>
#include <asm/mach/map.h>
#include <asm/mach/time.h>

View File

@ -23,7 +23,6 @@
#include <linux/clk.h>
#include <asm/system.h>
#include <asm/irq.h>
#include <asm/hardware.h>
#include <asm/dma.h>
#include <asm/dma-mapping.h>

View File

@ -22,8 +22,8 @@
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/device.h>
#include <linux/irq.h>
#include <asm/hardware.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/setup.h>
#include <asm/mach-types.h>
@ -96,26 +96,24 @@ void __init pnx4008_init_irq(void)
{
unsigned int i;
/* configure and enable IRQ 0,1,30,31 (cascade interrupts) mask all others */
/* configure IRQ's */
for (i = 0; i < NR_IRQS; i++) {
set_irq_flags(i, IRQF_VALID);
set_irq_chip(i, &pnx4008_irq_chip);
pnx4008_set_irq_type(i, pnx4008_irq_type[i]);
}
/* configure and enable IRQ 0,1,30,31 (cascade interrupts) */
pnx4008_set_irq_type(SUB1_IRQ_N, pnx4008_irq_type[SUB1_IRQ_N]);
pnx4008_set_irq_type(SUB2_IRQ_N, pnx4008_irq_type[SUB2_IRQ_N]);
pnx4008_set_irq_type(SUB1_FIQ_N, pnx4008_irq_type[SUB1_FIQ_N]);
pnx4008_set_irq_type(SUB2_FIQ_N, pnx4008_irq_type[SUB2_FIQ_N]);
/* mask all others */
__raw_writel((1 << SUB2_FIQ_N) | (1 << SUB1_FIQ_N) |
(1 << SUB2_IRQ_N) | (1 << SUB1_IRQ_N),
INTC_ER(MAIN_BASE_INT));
__raw_writel(0, INTC_ER(SIC1_BASE_INT));
__raw_writel(0, INTC_ER(SIC2_BASE_INT));
/* configure all other IRQ's */
for (i = 0; i < NR_IRQS; i++) {
if (i == SUB2_FIQ_N || i == SUB1_FIQ_N ||
i == SUB2_IRQ_N || i == SUB1_IRQ_N)
continue;
set_irq_flags(i, IRQF_VALID);
set_irq_chip(i, &pnx4008_irq_chip);
pnx4008_set_irq_type(i, pnx4008_irq_type[i]);
}
}

View File

@ -20,17 +20,15 @@
#include <linux/spinlock.h>
#include <linux/module.h>
#include <linux/kallsyms.h>
#include <linux/time.h>
#include <linux/timex.h>
#include <linux/irq.h>
#include <asm/system.h>
#include <asm/hardware.h>
#include <asm/io.h>
#include <asm/leds.h>
#include <asm/irq.h>
#include <asm/mach/irq.h>
#include <asm/mach/time.h>
#include <linux/time.h>
#include <linux/timex.h>
#include <asm/errno.h>
/*! Note: all timers are UPCOUNTING */

View File

@ -405,20 +405,22 @@ static void mpic_unmask_irq(unsigned int irq)
unsigned int loops = 100000;
struct mpic *mpic = mpic_from_irq(irq);
unsigned int src = mpic_irq_to_hw(irq);
unsigned long flags;
DBG("%p: %s: enable_irq: %d (src %d)\n", mpic, mpic->name, irq, src);
spin_lock_irqsave(&mpic_lock, flags);
mpic_irq_write(src, MPIC_IRQ_VECTOR_PRI,
mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) &
~MPIC_VECPRI_MASK);
/* make sure mask gets to controller before we return to user */
do {
if (!loops--) {
printk(KERN_ERR "mpic_enable_irq timeout\n");
break;
}
} while(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK);
} while(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK);
spin_unlock_irqrestore(&mpic_lock, flags);
}
static void mpic_mask_irq(unsigned int irq)
@ -426,9 +428,11 @@ static void mpic_mask_irq(unsigned int irq)
unsigned int loops = 100000;
struct mpic *mpic = mpic_from_irq(irq);
unsigned int src = mpic_irq_to_hw(irq);
unsigned long flags;
DBG("%s: disable_irq: %d (src %d)\n", mpic->name, irq, src);
spin_lock_irqsave(&mpic_lock, flags);
mpic_irq_write(src, MPIC_IRQ_VECTOR_PRI,
mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) |
MPIC_VECPRI_MASK);
@ -440,6 +444,7 @@ static void mpic_mask_irq(unsigned int irq)
break;
}
} while(!(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK));
spin_unlock_irqrestore(&mpic_lock, flags);
}
static void mpic_end_irq(unsigned int irq)
@ -624,9 +629,10 @@ static int mpic_host_map(struct irq_host *h, unsigned int virq,
struct irq_desc *desc = get_irq_desc(virq);
struct irq_chip *chip;
struct mpic *mpic = h->host_data;
unsigned int vecpri = MPIC_VECPRI_SENSE_LEVEL |
u32 v, vecpri = MPIC_VECPRI_SENSE_LEVEL |
MPIC_VECPRI_POLARITY_NEGATIVE;
int level;
unsigned long iflags;
pr_debug("mpic: map virq %d, hwirq 0x%lx, flags: 0x%x\n",
virq, hw, flags);
@ -668,11 +674,21 @@ static int mpic_host_map(struct irq_host *h, unsigned int virq,
}
#endif
/* Reconfigure irq */
vecpri |= MPIC_VECPRI_MASK | hw | (8 << MPIC_VECPRI_PRIORITY_SHIFT);
mpic_irq_write(hw, MPIC_IRQ_VECTOR_PRI, vecpri);
/* Reconfigure irq. We must preserve the mask bit as we can be called
* while the interrupt is still active (This may change in the future
* but for now, it is the case).
*/
spin_lock_irqsave(&mpic_lock, iflags);
v = mpic_irq_read(hw, MPIC_IRQ_VECTOR_PRI);
vecpri = (v &
~(MPIC_VECPRI_POLARITY_MASK | MPIC_VECPRI_SENSE_MASK)) |
vecpri;
if (vecpri != v)
mpic_irq_write(hw, MPIC_IRQ_VECTOR_PRI, vecpri);
spin_unlock_irqrestore(&mpic_lock, iflags);
pr_debug("mpic: mapping as IRQ\n");
pr_debug("mpic: mapping as IRQ, vecpri = 0x%08x (was 0x%08x)\n",
vecpri, v);
set_irq_chip_data(virq, mpic);
set_irq_chip_and_handler(virq, chip, handle_fasteoi_irq);
@ -904,8 +920,8 @@ void __init mpic_init(struct mpic *mpic)
/* do senses munging */
if (mpic->senses && i < mpic->senses_count)
vecpri = mpic_flags_to_vecpri(mpic->senses[i],
&level);
vecpri |= mpic_flags_to_vecpri(mpic->senses[i],
&level);
else
vecpri |= MPIC_VECPRI_SENSE_LEVEL;
@ -955,14 +971,17 @@ void __init mpic_set_clk_ratio(struct mpic *mpic, u32 clock_ratio)
void __init mpic_set_serial_int(struct mpic *mpic, int enable)
{
unsigned long flags;
u32 v;
spin_lock_irqsave(&mpic_lock, flags);
v = mpic_read(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1);
if (enable)
v |= MPIC_GREG_GLOBAL_CONF_1_SIE;
else
v &= ~MPIC_GREG_GLOBAL_CONF_1_SIE;
mpic_write(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1, v);
spin_unlock_irqrestore(&mpic_lock, flags);
}
void mpic_irq_set_priority(unsigned int irq, unsigned int pri)

View File

@ -1032,7 +1032,9 @@ static void sun4v_vdev_irq_trans_init(struct device_node *dp)
static void irq_trans_init(struct device_node *dp)
{
const char *model;
#ifdef CONFIG_PCI
int i;
#endif
model = of_get_property(dp, "model", NULL);
if (!model)

View File

@ -124,11 +124,6 @@ EXPORT_SYMBOL(__write_lock);
EXPORT_SYMBOL(__write_unlock);
EXPORT_SYMBOL(__write_trylock);
#if defined(CONFIG_MCOUNT)
extern void _mcount(void);
EXPORT_SYMBOL(_mcount);
#endif
/* CPU online map and active count. */
EXPORT_SYMBOL(cpu_online_map);
EXPORT_SYMBOL(phys_cpu_present_map);
@ -136,6 +131,11 @@ EXPORT_SYMBOL(phys_cpu_present_map);
EXPORT_SYMBOL(smp_call_function);
#endif /* CONFIG_SMP */
#if defined(CONFIG_MCOUNT)
extern void _mcount(void);
EXPORT_SYMBOL(_mcount);
#endif
EXPORT_SYMBOL(sparc64_get_clock_tick);
/* semaphores */

View File

@ -788,12 +788,15 @@ static int __devinit clock_probe(struct of_device *op, const struct of_device_id
if (!regs)
return -ENOMEM;
#ifdef CONFIG_PCI
if (!strcmp(model, "ds1287") ||
!strcmp(model, "m5819") ||
!strcmp(model, "m5819p") ||
!strcmp(model, "m5823")) {
ds1287_regs = (unsigned long) regs;
} else if (model[5] == '0' && model[6] == '2') {
} else
#endif
if (model[5] == '0' && model[6] == '2') {
mstk48t02_regs = regs;
} else if(model[5] == '0' && model[6] == '8') {
mstk48t08_regs = regs;

View File

@ -1052,7 +1052,7 @@ static void ahci_thaw(struct ata_port *ap)
static void ahci_error_handler(struct ata_port *ap)
{
if (!(ap->flags & ATA_FLAG_FROZEN)) {
if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
/* restart engine */
ahci_stop_engine(ap);
ahci_start_engine(ap);
@ -1323,6 +1323,17 @@ static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
/* JMicron-specific fixup: make sure we're in AHCI mode */
/* This is protected from races with ata_jmicron by the pci probe
locking */
if (pdev->vendor == PCI_VENDOR_ID_JMICRON) {
/* AHCI enable, AHCI on function 0 */
pci_write_config_byte(pdev, 0x41, 0xa1);
/* Function 1 is the PATA controller */
if (PCI_FUNC(pdev->devfn))
return -ENODEV;
}
rc = pci_enable_device(pdev);
if (rc)
return rc;
@ -1378,10 +1389,6 @@ static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
if (have_msi)
hpriv->flags |= AHCI_FLAG_MSI;
/* JMicron-specific fixup: make sure we're in AHCI mode */
if (pdev->vendor == 0x197b)
pci_write_config_byte(pdev, 0x41, 0xa1);
/* initialize adapter */
rc = ahci_host_init(probe_ent);
if (rc)

View File

@ -61,9 +61,9 @@
#include "libata.h"
/* debounce timing parameters in msecs { interval, duration, timeout } */
const unsigned long sata_deb_timing_boot[] = { 5, 100, 2000 };
const unsigned long sata_deb_timing_eh[] = { 25, 500, 2000 };
const unsigned long sata_deb_timing_before_fsrst[] = { 100, 2000, 5000 };
const unsigned long sata_deb_timing_normal[] = { 5, 100, 2000 };
const unsigned long sata_deb_timing_hotplug[] = { 25, 500, 2000 };
const unsigned long sata_deb_timing_long[] = { 100, 2000, 5000 };
static unsigned int ata_dev_init_params(struct ata_device *dev,
u16 heads, u16 sectors);
@ -907,7 +907,7 @@ void ata_port_queue_task(struct ata_port *ap, void (*fn)(void *), void *data,
{
int rc;
if (ap->flags & ATA_FLAG_FLUSH_PORT_TASK)
if (ap->pflags & ATA_PFLAG_FLUSH_PORT_TASK)
return;
PREPARE_WORK(&ap->port_task, fn, data);
@ -938,7 +938,7 @@ void ata_port_flush_task(struct ata_port *ap)
DPRINTK("ENTER\n");
spin_lock_irqsave(ap->lock, flags);
ap->flags |= ATA_FLAG_FLUSH_PORT_TASK;
ap->pflags |= ATA_PFLAG_FLUSH_PORT_TASK;
spin_unlock_irqrestore(ap->lock, flags);
DPRINTK("flush #1\n");
@ -957,7 +957,7 @@ void ata_port_flush_task(struct ata_port *ap)
}
spin_lock_irqsave(ap->lock, flags);
ap->flags &= ~ATA_FLAG_FLUSH_PORT_TASK;
ap->pflags &= ~ATA_PFLAG_FLUSH_PORT_TASK;
spin_unlock_irqrestore(ap->lock, flags);
if (ata_msg_ctl(ap))
@ -1009,7 +1009,7 @@ unsigned ata_exec_internal(struct ata_device *dev,
spin_lock_irqsave(ap->lock, flags);
/* no internal command while frozen */
if (ap->flags & ATA_FLAG_FROZEN) {
if (ap->pflags & ATA_PFLAG_FROZEN) {
spin_unlock_irqrestore(ap->lock, flags);
return AC_ERR_SYSTEM;
}
@ -1325,6 +1325,19 @@ static void ata_dev_config_ncq(struct ata_device *dev,
snprintf(desc, desc_sz, "NCQ (depth %d/%d)", hdepth, ddepth);
}
static void ata_set_port_max_cmd_len(struct ata_port *ap)
{
int i;
if (ap->host) {
ap->host->max_cmd_len = 0;
for (i = 0; i < ATA_MAX_DEVICES; i++)
ap->host->max_cmd_len = max_t(unsigned int,
ap->host->max_cmd_len,
ap->device[i].cdb_len);
}
}
/**
* ata_dev_configure - Configure the specified ATA/ATAPI device
* @dev: Target device to configure
@ -1344,7 +1357,7 @@ int ata_dev_configure(struct ata_device *dev, int print_info)
struct ata_port *ap = dev->ap;
const u16 *id = dev->id;
unsigned int xfer_mask;
int i, rc;
int rc;
if (!ata_dev_enabled(dev) && ata_msg_info(ap)) {
ata_dev_printk(dev, KERN_INFO,
@ -1404,7 +1417,7 @@ int ata_dev_configure(struct ata_device *dev, int print_info)
ata_dev_config_ncq(dev, ncq_desc, sizeof(ncq_desc));
/* print device info to dmesg */
if (ata_msg_info(ap))
if (ata_msg_drv(ap) && print_info)
ata_dev_printk(dev, KERN_INFO, "ATA-%d, "
"max %s, %Lu sectors: %s %s\n",
ata_id_major_version(id),
@ -1427,7 +1440,7 @@ int ata_dev_configure(struct ata_device *dev, int print_info)
}
/* print device info to dmesg */
if (ata_msg_info(ap))
if (ata_msg_drv(ap) && print_info)
ata_dev_printk(dev, KERN_INFO, "ATA-%d, "
"max %s, %Lu sectors: CHS %u/%u/%u\n",
ata_id_major_version(id),
@ -1439,7 +1452,7 @@ int ata_dev_configure(struct ata_device *dev, int print_info)
if (dev->id[59] & 0x100) {
dev->multi_count = dev->id[59] & 0xff;
if (ata_msg_info(ap))
if (ata_msg_drv(ap) && print_info)
ata_dev_printk(dev, KERN_INFO,
"ata%u: dev %u multi count %u\n",
ap->id, dev->devno, dev->multi_count);
@ -1468,21 +1481,17 @@ int ata_dev_configure(struct ata_device *dev, int print_info)
}
/* print device info to dmesg */
if (ata_msg_info(ap))
if (ata_msg_drv(ap) && print_info)
ata_dev_printk(dev, KERN_INFO, "ATAPI, max %s%s\n",
ata_mode_string(xfer_mask),
cdb_intr_string);
}
ap->host->max_cmd_len = 0;
for (i = 0; i < ATA_MAX_DEVICES; i++)
ap->host->max_cmd_len = max_t(unsigned int,
ap->host->max_cmd_len,
ap->device[i].cdb_len);
ata_set_port_max_cmd_len(ap);
/* limit bridge transfers to udma5, 200 sectors */
if (ata_dev_knobble(dev)) {
if (ata_msg_info(ap))
if (ata_msg_drv(ap) && print_info)
ata_dev_printk(dev, KERN_INFO,
"applying bridge limits\n");
dev->udma_mask &= ATA_UDMA5;
@ -2137,7 +2146,7 @@ int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
* return error code and failing device on failure.
*/
for (i = 0; i < ATA_MAX_DEVICES; i++) {
if (ata_dev_enabled(&ap->device[i])) {
if (ata_dev_ready(&ap->device[i])) {
ap->ops->set_mode(ap);
break;
}
@ -2203,7 +2212,8 @@ int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
for (i = 0; i < ATA_MAX_DEVICES; i++) {
dev = &ap->device[i];
if (!ata_dev_enabled(dev))
/* don't udpate suspended devices' xfer mode */
if (!ata_dev_ready(dev))
continue;
rc = ata_dev_set_mode(dev);
@ -2579,7 +2589,7 @@ static void ata_wait_spinup(struct ata_port *ap)
/* first, debounce phy if SATA */
if (ap->cbl == ATA_CBL_SATA) {
rc = sata_phy_debounce(ap, sata_deb_timing_eh);
rc = sata_phy_debounce(ap, sata_deb_timing_hotplug);
/* if debounced successfully and offline, no need to wait */
if ((rc == 0 || rc == -EOPNOTSUPP) && ata_port_offline(ap))
@ -2615,16 +2625,17 @@ static void ata_wait_spinup(struct ata_port *ap)
int ata_std_prereset(struct ata_port *ap)
{
struct ata_eh_context *ehc = &ap->eh_context;
const unsigned long *timing;
const unsigned long *timing = sata_ehc_deb_timing(ehc);
int rc;
/* hotplug? */
if (ehc->i.flags & ATA_EHI_HOTPLUGGED) {
if (ap->flags & ATA_FLAG_HRST_TO_RESUME)
ehc->i.action |= ATA_EH_HARDRESET;
if (ap->flags & ATA_FLAG_SKIP_D2H_BSY)
ata_wait_spinup(ap);
}
/* handle link resume & hotplug spinup */
if ((ehc->i.flags & ATA_EHI_RESUME_LINK) &&
(ap->flags & ATA_FLAG_HRST_TO_RESUME))
ehc->i.action |= ATA_EH_HARDRESET;
if ((ehc->i.flags & ATA_EHI_HOTPLUGGED) &&
(ap->flags & ATA_FLAG_SKIP_D2H_BSY))
ata_wait_spinup(ap);
/* if we're about to do hardreset, nothing more to do */
if (ehc->i.action & ATA_EH_HARDRESET)
@ -2632,11 +2643,6 @@ int ata_std_prereset(struct ata_port *ap)
/* if SATA, resume phy */
if (ap->cbl == ATA_CBL_SATA) {
if (ap->flags & ATA_FLAG_LOADING)
timing = sata_deb_timing_boot;
else
timing = sata_deb_timing_eh;
rc = sata_phy_resume(ap, timing);
if (rc && rc != -EOPNOTSUPP) {
/* phy resume failed */
@ -2724,6 +2730,8 @@ int ata_std_softreset(struct ata_port *ap, unsigned int *classes)
*/
int sata_std_hardreset(struct ata_port *ap, unsigned int *class)
{
struct ata_eh_context *ehc = &ap->eh_context;
const unsigned long *timing = sata_ehc_deb_timing(ehc);
u32 scontrol;
int rc;
@ -2761,7 +2769,7 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class)
msleep(1);
/* bring phy back */
sata_phy_resume(ap, sata_deb_timing_eh);
sata_phy_resume(ap, timing);
/* TODO: phy layer with polling, timeouts, etc. */
if (ata_port_offline(ap)) {
@ -4285,7 +4293,7 @@ static struct ata_queued_cmd *ata_qc_new(struct ata_port *ap)
unsigned int i;
/* no command while frozen */
if (unlikely(ap->flags & ATA_FLAG_FROZEN))
if (unlikely(ap->pflags & ATA_PFLAG_FROZEN))
return NULL;
/* the last tag is reserved for internal command. */
@ -4407,7 +4415,7 @@ void ata_qc_complete(struct ata_queued_cmd *qc)
* taken care of.
*/
if (ap->ops->error_handler) {
WARN_ON(ap->flags & ATA_FLAG_FROZEN);
WARN_ON(ap->pflags & ATA_PFLAG_FROZEN);
if (unlikely(qc->err_mask))
qc->flags |= ATA_QCFLAG_FAILED;
@ -5001,86 +5009,120 @@ int ata_flush_cache(struct ata_device *dev)
return 0;
}
static int ata_standby_drive(struct ata_device *dev)
static int ata_host_set_request_pm(struct ata_host_set *host_set,
pm_message_t mesg, unsigned int action,
unsigned int ehi_flags, int wait)
{
unsigned int err_mask;
unsigned long flags;
int i, rc;
err_mask = ata_do_simple_cmd(dev, ATA_CMD_STANDBYNOW1);
if (err_mask) {
ata_dev_printk(dev, KERN_ERR, "failed to standby drive "
"(err_mask=0x%x)\n", err_mask);
return -EIO;
}
for (i = 0; i < host_set->n_ports; i++) {
struct ata_port *ap = host_set->ports[i];
return 0;
}
/* Previous resume operation might still be in
* progress. Wait for PM_PENDING to clear.
*/
if (ap->pflags & ATA_PFLAG_PM_PENDING) {
ata_port_wait_eh(ap);
WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
}
static int ata_start_drive(struct ata_device *dev)
{
unsigned int err_mask;
/* request PM ops to EH */
spin_lock_irqsave(ap->lock, flags);
err_mask = ata_do_simple_cmd(dev, ATA_CMD_IDLEIMMEDIATE);
if (err_mask) {
ata_dev_printk(dev, KERN_ERR, "failed to start drive "
"(err_mask=0x%x)\n", err_mask);
return -EIO;
ap->pm_mesg = mesg;
if (wait) {
rc = 0;
ap->pm_result = &rc;
}
ap->pflags |= ATA_PFLAG_PM_PENDING;
ap->eh_info.action |= action;
ap->eh_info.flags |= ehi_flags;
ata_port_schedule_eh(ap);
spin_unlock_irqrestore(ap->lock, flags);
/* wait and check result */
if (wait) {
ata_port_wait_eh(ap);
WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
if (rc)
return rc;
}
}
return 0;
}
/**
* ata_device_resume - wakeup a previously suspended devices
* @dev: the device to resume
* ata_host_set_suspend - suspend host_set
* @host_set: host_set to suspend
* @mesg: PM message
*
* Kick the drive back into action, by sending it an idle immediate
* command and making sure its transfer mode matches between drive
* and host.
* Suspend @host_set. Actual operation is performed by EH. This
* function requests EH to perform PM operations and waits for EH
* to finish.
*
* LOCKING:
* Kernel thread context (may sleep).
*
* RETURNS:
* 0 on success, -errno on failure.
*/
int ata_device_resume(struct ata_device *dev)
int ata_host_set_suspend(struct ata_host_set *host_set, pm_message_t mesg)
{
struct ata_port *ap = dev->ap;
int i, j, rc;
if (ap->flags & ATA_FLAG_SUSPENDED) {
struct ata_device *failed_dev;
rc = ata_host_set_request_pm(host_set, mesg, 0, ATA_EHI_QUIET, 1);
if (rc)
goto fail;
ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 200000);
/* EH is quiescent now. Fail if we have any ready device.
* This happens if hotplug occurs between completion of device
* suspension and here.
*/
for (i = 0; i < host_set->n_ports; i++) {
struct ata_port *ap = host_set->ports[i];
ap->flags &= ~ATA_FLAG_SUSPENDED;
while (ata_set_mode(ap, &failed_dev))
ata_dev_disable(failed_dev);
for (j = 0; j < ATA_MAX_DEVICES; j++) {
struct ata_device *dev = &ap->device[j];
if (ata_dev_ready(dev)) {
ata_port_printk(ap, KERN_WARNING,
"suspend failed, device %d "
"still active\n", dev->devno);
rc = -EBUSY;
goto fail;
}
}
}
if (!ata_dev_enabled(dev))
return 0;
if (dev->class == ATA_DEV_ATA)
ata_start_drive(dev);
host_set->dev->power.power_state = mesg;
return 0;
fail:
ata_host_set_resume(host_set);
return rc;
}
/**
* ata_device_suspend - prepare a device for suspend
* @dev: the device to suspend
* @state: target power management state
* ata_host_set_resume - resume host_set
* @host_set: host_set to resume
*
* Flush the cache on the drive, if appropriate, then issue a
* standbynow command.
* Resume @host_set. Actual operation is performed by EH. This
* function requests EH to perform PM operations and returns.
* Note that all resume operations are performed parallely.
*
* LOCKING:
* Kernel thread context (may sleep).
*/
int ata_device_suspend(struct ata_device *dev, pm_message_t state)
void ata_host_set_resume(struct ata_host_set *host_set)
{
struct ata_port *ap = dev->ap;
if (!ata_dev_enabled(dev))
return 0;
if (dev->class == ATA_DEV_ATA)
ata_flush_cache(dev);
if (state.event != PM_EVENT_FREEZE)
ata_standby_drive(dev);
ap->flags |= ATA_FLAG_SUSPENDED;
return 0;
ata_host_set_request_pm(host_set, PMSG_ON, ATA_EH_SOFTRESET,
ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, 0);
host_set->dev->power.power_state = PMSG_ON;
}
/**
@ -5440,6 +5482,7 @@ int ata_device_add(const struct ata_probe_ent *ent)
}
if (ap->ops->error_handler) {
struct ata_eh_info *ehi = &ap->eh_info;
unsigned long flags;
ata_port_probe(ap);
@ -5447,10 +5490,11 @@ int ata_device_add(const struct ata_probe_ent *ent)
/* kick EH for boot probing */
spin_lock_irqsave(ap->lock, flags);
ap->eh_info.probe_mask = (1 << ATA_MAX_DEVICES) - 1;
ap->eh_info.action |= ATA_EH_SOFTRESET;
ehi->probe_mask = (1 << ATA_MAX_DEVICES) - 1;
ehi->action |= ATA_EH_SOFTRESET;
ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET;
ap->flags |= ATA_FLAG_LOADING;
ap->pflags |= ATA_PFLAG_LOADING;
ata_port_schedule_eh(ap);
spin_unlock_irqrestore(ap->lock, flags);
@ -5518,7 +5562,7 @@ void ata_port_detach(struct ata_port *ap)
/* tell EH we're leaving & flush EH */
spin_lock_irqsave(ap->lock, flags);
ap->flags |= ATA_FLAG_UNLOADING;
ap->pflags |= ATA_PFLAG_UNLOADING;
spin_unlock_irqrestore(ap->lock, flags);
ata_port_wait_eh(ap);
@ -5723,20 +5767,55 @@ int pci_test_config_bits(struct pci_dev *pdev, const struct pci_bits *bits)
return (tmp == bits->val) ? 1 : 0;
}
int ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t state)
void ata_pci_device_do_suspend(struct pci_dev *pdev, pm_message_t state)
{
pci_save_state(pdev);
pci_disable_device(pdev);
pci_set_power_state(pdev, PCI_D3hot);
return 0;
if (state.event == PM_EVENT_SUSPEND) {
pci_disable_device(pdev);
pci_set_power_state(pdev, PCI_D3hot);
}
}
int ata_pci_device_resume(struct pci_dev *pdev)
void ata_pci_device_do_resume(struct pci_dev *pdev)
{
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
pci_enable_device(pdev);
pci_set_master(pdev);
}
int ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t state)
{
struct ata_host_set *host_set = dev_get_drvdata(&pdev->dev);
int rc = 0;
rc = ata_host_set_suspend(host_set, state);
if (rc)
return rc;
if (host_set->next) {
rc = ata_host_set_suspend(host_set->next, state);
if (rc) {
ata_host_set_resume(host_set);
return rc;
}
}
ata_pci_device_do_suspend(pdev, state);
return 0;
}
int ata_pci_device_resume(struct pci_dev *pdev)
{
struct ata_host_set *host_set = dev_get_drvdata(&pdev->dev);
ata_pci_device_do_resume(pdev);
ata_host_set_resume(host_set);
if (host_set->next)
ata_host_set_resume(host_set->next);
return 0;
}
#endif /* CONFIG_PCI */
@ -5842,9 +5921,9 @@ u32 ata_wait_register(void __iomem *reg, u32 mask, u32 val,
* Do not depend on ABI/API stability.
*/
EXPORT_SYMBOL_GPL(sata_deb_timing_boot);
EXPORT_SYMBOL_GPL(sata_deb_timing_eh);
EXPORT_SYMBOL_GPL(sata_deb_timing_before_fsrst);
EXPORT_SYMBOL_GPL(sata_deb_timing_normal);
EXPORT_SYMBOL_GPL(sata_deb_timing_hotplug);
EXPORT_SYMBOL_GPL(sata_deb_timing_long);
EXPORT_SYMBOL_GPL(ata_std_bios_param);
EXPORT_SYMBOL_GPL(ata_std_ports);
EXPORT_SYMBOL_GPL(ata_device_add);
@ -5916,6 +5995,8 @@ EXPORT_SYMBOL_GPL(sata_scr_write);
EXPORT_SYMBOL_GPL(sata_scr_write_flush);
EXPORT_SYMBOL_GPL(ata_port_online);
EXPORT_SYMBOL_GPL(ata_port_offline);
EXPORT_SYMBOL_GPL(ata_host_set_suspend);
EXPORT_SYMBOL_GPL(ata_host_set_resume);
EXPORT_SYMBOL_GPL(ata_id_string);
EXPORT_SYMBOL_GPL(ata_id_c_string);
EXPORT_SYMBOL_GPL(ata_scsi_simulate);
@ -5930,14 +6011,14 @@ EXPORT_SYMBOL_GPL(ata_pci_host_stop);
EXPORT_SYMBOL_GPL(ata_pci_init_native_mode);
EXPORT_SYMBOL_GPL(ata_pci_init_one);
EXPORT_SYMBOL_GPL(ata_pci_remove_one);
EXPORT_SYMBOL_GPL(ata_pci_device_do_suspend);
EXPORT_SYMBOL_GPL(ata_pci_device_do_resume);
EXPORT_SYMBOL_GPL(ata_pci_device_suspend);
EXPORT_SYMBOL_GPL(ata_pci_device_resume);
EXPORT_SYMBOL_GPL(ata_pci_default_filter);
EXPORT_SYMBOL_GPL(ata_pci_clear_simplex);
#endif /* CONFIG_PCI */
EXPORT_SYMBOL_GPL(ata_device_suspend);
EXPORT_SYMBOL_GPL(ata_device_resume);
EXPORT_SYMBOL_GPL(ata_scsi_device_suspend);
EXPORT_SYMBOL_GPL(ata_scsi_device_resume);

View File

@ -47,6 +47,8 @@
static void __ata_port_freeze(struct ata_port *ap);
static void ata_eh_finish(struct ata_port *ap);
static void ata_eh_handle_port_suspend(struct ata_port *ap);
static void ata_eh_handle_port_resume(struct ata_port *ap);
static void ata_ering_record(struct ata_ering *ering, int is_io,
unsigned int err_mask)
@ -190,7 +192,6 @@ enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd)
void ata_scsi_error(struct Scsi_Host *host)
{
struct ata_port *ap = ata_shost_to_port(host);
spinlock_t *ap_lock = ap->lock;
int i, repeat_cnt = ATA_EH_MAX_REPEAT;
unsigned long flags;
@ -217,7 +218,7 @@ void ata_scsi_error(struct Scsi_Host *host)
struct scsi_cmnd *scmd, *tmp;
int nr_timedout = 0;
spin_lock_irqsave(ap_lock, flags);
spin_lock_irqsave(ap->lock, flags);
list_for_each_entry_safe(scmd, tmp, &host->eh_cmd_q, eh_entry) {
struct ata_queued_cmd *qc;
@ -256,43 +257,49 @@ void ata_scsi_error(struct Scsi_Host *host)
if (nr_timedout)
__ata_port_freeze(ap);
spin_unlock_irqrestore(ap_lock, flags);
spin_unlock_irqrestore(ap->lock, flags);
} else
spin_unlock_wait(ap_lock);
spin_unlock_wait(ap->lock);
repeat:
/* invoke error handler */
if (ap->ops->error_handler) {
/* process port resume request */
ata_eh_handle_port_resume(ap);
/* fetch & clear EH info */
spin_lock_irqsave(ap_lock, flags);
spin_lock_irqsave(ap->lock, flags);
memset(&ap->eh_context, 0, sizeof(ap->eh_context));
ap->eh_context.i = ap->eh_info;
memset(&ap->eh_info, 0, sizeof(ap->eh_info));
ap->flags |= ATA_FLAG_EH_IN_PROGRESS;
ap->flags &= ~ATA_FLAG_EH_PENDING;
ap->pflags |= ATA_PFLAG_EH_IN_PROGRESS;
ap->pflags &= ~ATA_PFLAG_EH_PENDING;
spin_unlock_irqrestore(ap_lock, flags);
spin_unlock_irqrestore(ap->lock, flags);
/* invoke EH. if unloading, just finish failed qcs */
if (!(ap->flags & ATA_FLAG_UNLOADING))
/* invoke EH, skip if unloading or suspended */
if (!(ap->pflags & (ATA_PFLAG_UNLOADING | ATA_PFLAG_SUSPENDED)))
ap->ops->error_handler(ap);
else
ata_eh_finish(ap);
/* process port suspend request */
ata_eh_handle_port_suspend(ap);
/* Exception might have happend after ->error_handler
* recovered the port but before this point. Repeat
* EH in such case.
*/
spin_lock_irqsave(ap_lock, flags);
spin_lock_irqsave(ap->lock, flags);
if (ap->flags & ATA_FLAG_EH_PENDING) {
if (ap->pflags & ATA_PFLAG_EH_PENDING) {
if (--repeat_cnt) {
ata_port_printk(ap, KERN_INFO,
"EH pending after completion, "
"repeating EH (cnt=%d)\n", repeat_cnt);
spin_unlock_irqrestore(ap_lock, flags);
spin_unlock_irqrestore(ap->lock, flags);
goto repeat;
}
ata_port_printk(ap, KERN_ERR, "EH pending after %d "
@ -302,14 +309,14 @@ void ata_scsi_error(struct Scsi_Host *host)
/* this run is complete, make sure EH info is clear */
memset(&ap->eh_info, 0, sizeof(ap->eh_info));
/* Clear host_eh_scheduled while holding ap_lock such
/* Clear host_eh_scheduled while holding ap->lock such
* that if exception occurs after this point but
* before EH completion, SCSI midlayer will
* re-initiate EH.
*/
host->host_eh_scheduled = 0;
spin_unlock_irqrestore(ap_lock, flags);
spin_unlock_irqrestore(ap->lock, flags);
} else {
WARN_ON(ata_qc_from_tag(ap, ap->active_tag) == NULL);
ap->ops->eng_timeout(ap);
@ -321,24 +328,23 @@ void ata_scsi_error(struct Scsi_Host *host)
scsi_eh_flush_done_q(&ap->eh_done_q);
/* clean up */
spin_lock_irqsave(ap_lock, flags);
spin_lock_irqsave(ap->lock, flags);
if (ap->flags & ATA_FLAG_LOADING) {
ap->flags &= ~ATA_FLAG_LOADING;
} else {
if (ap->flags & ATA_FLAG_SCSI_HOTPLUG)
queue_work(ata_aux_wq, &ap->hotplug_task);
if (ap->flags & ATA_FLAG_RECOVERED)
ata_port_printk(ap, KERN_INFO, "EH complete\n");
}
if (ap->pflags & ATA_PFLAG_LOADING)
ap->pflags &= ~ATA_PFLAG_LOADING;
else if (ap->pflags & ATA_PFLAG_SCSI_HOTPLUG)
queue_work(ata_aux_wq, &ap->hotplug_task);
ap->flags &= ~(ATA_FLAG_SCSI_HOTPLUG | ATA_FLAG_RECOVERED);
if (ap->pflags & ATA_PFLAG_RECOVERED)
ata_port_printk(ap, KERN_INFO, "EH complete\n");
ap->pflags &= ~(ATA_PFLAG_SCSI_HOTPLUG | ATA_PFLAG_RECOVERED);
/* tell wait_eh that we're done */
ap->flags &= ~ATA_FLAG_EH_IN_PROGRESS;
ap->pflags &= ~ATA_PFLAG_EH_IN_PROGRESS;
wake_up_all(&ap->eh_wait_q);
spin_unlock_irqrestore(ap_lock, flags);
spin_unlock_irqrestore(ap->lock, flags);
DPRINTK("EXIT\n");
}
@ -360,7 +366,7 @@ void ata_port_wait_eh(struct ata_port *ap)
retry:
spin_lock_irqsave(ap->lock, flags);
while (ap->flags & (ATA_FLAG_EH_PENDING | ATA_FLAG_EH_IN_PROGRESS)) {
while (ap->pflags & (ATA_PFLAG_EH_PENDING | ATA_PFLAG_EH_IN_PROGRESS)) {
prepare_to_wait(&ap->eh_wait_q, &wait, TASK_UNINTERRUPTIBLE);
spin_unlock_irqrestore(ap->lock, flags);
schedule();
@ -489,7 +495,7 @@ void ata_qc_schedule_eh(struct ata_queued_cmd *qc)
WARN_ON(!ap->ops->error_handler);
qc->flags |= ATA_QCFLAG_FAILED;
qc->ap->flags |= ATA_FLAG_EH_PENDING;
qc->ap->pflags |= ATA_PFLAG_EH_PENDING;
/* The following will fail if timeout has already expired.
* ata_scsi_error() takes care of such scmds on EH entry.
@ -513,7 +519,7 @@ void ata_port_schedule_eh(struct ata_port *ap)
{
WARN_ON(!ap->ops->error_handler);
ap->flags |= ATA_FLAG_EH_PENDING;
ap->pflags |= ATA_PFLAG_EH_PENDING;
scsi_schedule_eh(ap->host);
DPRINTK("port EH scheduled\n");
@ -578,7 +584,7 @@ static void __ata_port_freeze(struct ata_port *ap)
if (ap->ops->freeze)
ap->ops->freeze(ap);
ap->flags |= ATA_FLAG_FROZEN;
ap->pflags |= ATA_PFLAG_FROZEN;
DPRINTK("ata%u port frozen\n", ap->id);
}
@ -646,7 +652,7 @@ void ata_eh_thaw_port(struct ata_port *ap)
spin_lock_irqsave(ap->lock, flags);
ap->flags &= ~ATA_FLAG_FROZEN;
ap->pflags &= ~ATA_PFLAG_FROZEN;
if (ap->ops->thaw)
ap->ops->thaw(ap);
@ -731,7 +737,7 @@ static void ata_eh_detach_dev(struct ata_device *dev)
if (ata_scsi_offline_dev(dev)) {
dev->flags |= ATA_DFLAG_DETACHED;
ap->flags |= ATA_FLAG_SCSI_HOTPLUG;
ap->pflags |= ATA_PFLAG_SCSI_HOTPLUG;
}
/* clear per-dev EH actions */
@ -760,8 +766,12 @@ static void ata_eh_about_to_do(struct ata_port *ap, struct ata_device *dev,
unsigned long flags;
spin_lock_irqsave(ap->lock, flags);
ata_eh_clear_action(dev, &ap->eh_info, action);
ap->flags |= ATA_FLAG_RECOVERED;
if (!(ap->eh_context.i.flags & ATA_EHI_QUIET))
ap->pflags |= ATA_PFLAG_RECOVERED;
spin_unlock_irqrestore(ap->lock, flags);
}
@ -1027,7 +1037,7 @@ static void ata_eh_analyze_ncq_error(struct ata_port *ap)
int tag, rc;
/* if frozen, we can't do much */
if (ap->flags & ATA_FLAG_FROZEN)
if (ap->pflags & ATA_PFLAG_FROZEN)
return;
/* is it NCQ device error? */
@ -1275,6 +1285,9 @@ static void ata_eh_autopsy(struct ata_port *ap)
DPRINTK("ENTER\n");
if (ehc->i.flags & ATA_EHI_NO_AUTOPSY)
return;
/* obtain and analyze SError */
rc = sata_scr_read(ap, SCR_ERROR, &serror);
if (rc == 0) {
@ -1327,7 +1340,7 @@ static void ata_eh_autopsy(struct ata_port *ap)
}
/* enforce default EH actions */
if (ap->flags & ATA_FLAG_FROZEN ||
if (ap->pflags & ATA_PFLAG_FROZEN ||
all_err_mask & (AC_ERR_HSM | AC_ERR_TIMEOUT))
action |= ATA_EH_SOFTRESET;
else if (all_err_mask)
@ -1346,7 +1359,7 @@ static void ata_eh_autopsy(struct ata_port *ap)
/* record autopsy result */
ehc->i.dev = failed_dev;
ehc->i.action = action;
ehc->i.action |= action;
DPRINTK("EXIT\n");
}
@ -1385,7 +1398,7 @@ static void ata_eh_report(struct ata_port *ap)
return;
frozen = "";
if (ap->flags & ATA_FLAG_FROZEN)
if (ap->pflags & ATA_PFLAG_FROZEN)
frozen = " frozen";
if (ehc->i.dev) {
@ -1465,7 +1478,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
struct ata_eh_context *ehc = &ap->eh_context;
unsigned int *classes = ehc->classes;
int tries = ATA_EH_RESET_TRIES;
int verbose = !(ap->flags & ATA_FLAG_LOADING);
int verbose = !(ehc->i.flags & ATA_EHI_QUIET);
unsigned int action;
ata_reset_fn_t reset;
int i, did_followup_srst, rc;
@ -1605,7 +1618,7 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap,
dev = &ap->device[i];
action = ata_eh_dev_action(dev);
if (action & ATA_EH_REVALIDATE && ata_dev_enabled(dev)) {
if (action & ATA_EH_REVALIDATE && ata_dev_ready(dev)) {
if (ata_port_offline(ap)) {
rc = -EIO;
break;
@ -1636,7 +1649,7 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap,
}
spin_lock_irqsave(ap->lock, flags);
ap->flags |= ATA_FLAG_SCSI_HOTPLUG;
ap->pflags |= ATA_PFLAG_SCSI_HOTPLUG;
spin_unlock_irqrestore(ap->lock, flags);
}
}
@ -1648,6 +1661,164 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap,
return rc;
}
/**
* ata_eh_suspend - handle suspend EH action
* @ap: target host port
* @r_failed_dev: result parameter to indicate failing device
*
* Handle suspend EH action. Disk devices are spinned down and
* other types of devices are just marked suspended. Once
* suspended, no EH action to the device is allowed until it is
* resumed.
*
* LOCKING:
* Kernel thread context (may sleep).
*
* RETURNS:
* 0 on success, -errno otherwise
*/
static int ata_eh_suspend(struct ata_port *ap, struct ata_device **r_failed_dev)
{
struct ata_device *dev;
int i, rc = 0;
DPRINTK("ENTER\n");
for (i = 0; i < ATA_MAX_DEVICES; i++) {
unsigned long flags;
unsigned int action, err_mask;
dev = &ap->device[i];
action = ata_eh_dev_action(dev);
if (!ata_dev_enabled(dev) || !(action & ATA_EH_SUSPEND))
continue;
WARN_ON(dev->flags & ATA_DFLAG_SUSPENDED);
ata_eh_about_to_do(ap, dev, ATA_EH_SUSPEND);
if (dev->class == ATA_DEV_ATA && !(action & ATA_EH_PM_FREEZE)) {
/* flush cache */
rc = ata_flush_cache(dev);
if (rc)
break;
/* spin down */
err_mask = ata_do_simple_cmd(dev, ATA_CMD_STANDBYNOW1);
if (err_mask) {
ata_dev_printk(dev, KERN_ERR, "failed to "
"spin down (err_mask=0x%x)\n",
err_mask);
rc = -EIO;
break;
}
}
spin_lock_irqsave(ap->lock, flags);
dev->flags |= ATA_DFLAG_SUSPENDED;
spin_unlock_irqrestore(ap->lock, flags);
ata_eh_done(ap, dev, ATA_EH_SUSPEND);
}
if (rc)
*r_failed_dev = dev;
DPRINTK("EXIT\n");
return 0;
}
/**
* ata_eh_prep_resume - prep for resume EH action
* @ap: target host port
*
* Clear SUSPENDED in preparation for scheduled resume actions.
* This allows other parts of EH to access the devices being
* resumed.
*
* LOCKING:
* Kernel thread context (may sleep).
*/
static void ata_eh_prep_resume(struct ata_port *ap)
{
struct ata_device *dev;
unsigned long flags;
int i;
DPRINTK("ENTER\n");
for (i = 0; i < ATA_MAX_DEVICES; i++) {
unsigned int action;
dev = &ap->device[i];
action = ata_eh_dev_action(dev);
if (!ata_dev_enabled(dev) || !(action & ATA_EH_RESUME))
continue;
spin_lock_irqsave(ap->lock, flags);
dev->flags &= ~ATA_DFLAG_SUSPENDED;
spin_unlock_irqrestore(ap->lock, flags);
}
DPRINTK("EXIT\n");
}
/**
* ata_eh_resume - handle resume EH action
* @ap: target host port
* @r_failed_dev: result parameter to indicate failing device
*
* Handle resume EH action. Target devices are already reset and
* revalidated. Spinning up is the only operation left.
*
* LOCKING:
* Kernel thread context (may sleep).
*
* RETURNS:
* 0 on success, -errno otherwise
*/
static int ata_eh_resume(struct ata_port *ap, struct ata_device **r_failed_dev)
{
struct ata_device *dev;
int i, rc = 0;
DPRINTK("ENTER\n");
for (i = 0; i < ATA_MAX_DEVICES; i++) {
unsigned int action, err_mask;
dev = &ap->device[i];
action = ata_eh_dev_action(dev);
if (!ata_dev_enabled(dev) || !(action & ATA_EH_RESUME))
continue;
ata_eh_about_to_do(ap, dev, ATA_EH_RESUME);
if (dev->class == ATA_DEV_ATA && !(action & ATA_EH_PM_FREEZE)) {
err_mask = ata_do_simple_cmd(dev,
ATA_CMD_IDLEIMMEDIATE);
if (err_mask) {
ata_dev_printk(dev, KERN_ERR, "failed to "
"spin up (err_mask=0x%x)\n",
err_mask);
rc = -EIO;
break;
}
}
ata_eh_done(ap, dev, ATA_EH_RESUME);
}
if (rc)
*r_failed_dev = dev;
DPRINTK("EXIT\n");
return 0;
}
static int ata_port_nr_enabled(struct ata_port *ap)
{
int i, cnt = 0;
@ -1673,7 +1844,19 @@ static int ata_eh_skip_recovery(struct ata_port *ap)
struct ata_eh_context *ehc = &ap->eh_context;
int i;
if (ap->flags & ATA_FLAG_FROZEN || ata_port_nr_enabled(ap))
/* skip if all possible devices are suspended */
for (i = 0; i < ata_port_max_devices(ap); i++) {
struct ata_device *dev = &ap->device[i];
if (ata_dev_absent(dev) || ata_dev_ready(dev))
break;
}
if (i == ata_port_max_devices(ap))
return 1;
/* always thaw frozen port and recover failed devices */
if (ap->pflags & ATA_PFLAG_FROZEN || ata_port_nr_enabled(ap))
return 0;
/* skip if class codes for all vacant slots are ATA_DEV_NONE */
@ -1744,9 +1927,12 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
rc = 0;
/* if UNLOADING, finish immediately */
if (ap->flags & ATA_FLAG_UNLOADING)
if (ap->pflags & ATA_PFLAG_UNLOADING)
goto out;
/* prep for resume */
ata_eh_prep_resume(ap);
/* skip EH if possible. */
if (ata_eh_skip_recovery(ap))
ehc->i.action = 0;
@ -1774,6 +1960,11 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
if (rc)
goto dev_fail;
/* resume devices */
rc = ata_eh_resume(ap, &dev);
if (rc)
goto dev_fail;
/* configure transfer mode if the port has been reset */
if (ehc->i.flags & ATA_EHI_DID_RESET) {
rc = ata_set_mode(ap, &dev);
@ -1783,6 +1974,11 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
}
}
/* suspend devices */
rc = ata_eh_suspend(ap, &dev);
if (rc)
goto dev_fail;
goto out;
dev_fail:
@ -1908,11 +2104,124 @@ void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset,
ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
ata_postreset_fn_t postreset)
{
if (!(ap->flags & ATA_FLAG_LOADING)) {
ata_eh_autopsy(ap);
ata_eh_report(ap);
}
ata_eh_autopsy(ap);
ata_eh_report(ap);
ata_eh_recover(ap, prereset, softreset, hardreset, postreset);
ata_eh_finish(ap);
}
/**
* ata_eh_handle_port_suspend - perform port suspend operation
* @ap: port to suspend
*
* Suspend @ap.
*
* LOCKING:
* Kernel thread context (may sleep).
*/
static void ata_eh_handle_port_suspend(struct ata_port *ap)
{
unsigned long flags;
int rc = 0;
/* are we suspending? */
spin_lock_irqsave(ap->lock, flags);
if (!(ap->pflags & ATA_PFLAG_PM_PENDING) ||
ap->pm_mesg.event == PM_EVENT_ON) {
spin_unlock_irqrestore(ap->lock, flags);
return;
}
spin_unlock_irqrestore(ap->lock, flags);
WARN_ON(ap->pflags & ATA_PFLAG_SUSPENDED);
/* suspend */
ata_eh_freeze_port(ap);
if (ap->ops->port_suspend)
rc = ap->ops->port_suspend(ap, ap->pm_mesg);
/* report result */
spin_lock_irqsave(ap->lock, flags);
ap->pflags &= ~ATA_PFLAG_PM_PENDING;
if (rc == 0)
ap->pflags |= ATA_PFLAG_SUSPENDED;
else
ata_port_schedule_eh(ap);
if (ap->pm_result) {
*ap->pm_result = rc;
ap->pm_result = NULL;
}
spin_unlock_irqrestore(ap->lock, flags);
return;
}
/**
* ata_eh_handle_port_resume - perform port resume operation
* @ap: port to resume
*
* Resume @ap.
*
* This function also waits upto one second until all devices
* hanging off this port requests resume EH action. This is to
* prevent invoking EH and thus reset multiple times on resume.
*
* On DPM resume, where some of devices might not be resumed
* together, this may delay port resume upto one second, but such
* DPM resumes are rare and 1 sec delay isn't too bad.
*
* LOCKING:
* Kernel thread context (may sleep).
*/
static void ata_eh_handle_port_resume(struct ata_port *ap)
{
unsigned long timeout;
unsigned long flags;
int i, rc = 0;
/* are we resuming? */
spin_lock_irqsave(ap->lock, flags);
if (!(ap->pflags & ATA_PFLAG_PM_PENDING) ||
ap->pm_mesg.event != PM_EVENT_ON) {
spin_unlock_irqrestore(ap->lock, flags);
return;
}
spin_unlock_irqrestore(ap->lock, flags);
/* spurious? */
if (!(ap->pflags & ATA_PFLAG_SUSPENDED))
goto done;
if (ap->ops->port_resume)
rc = ap->ops->port_resume(ap);
/* give devices time to request EH */
timeout = jiffies + HZ; /* 1s max */
while (1) {
for (i = 0; i < ATA_MAX_DEVICES; i++) {
struct ata_device *dev = &ap->device[i];
unsigned int action = ata_eh_dev_action(dev);
if ((dev->flags & ATA_DFLAG_SUSPENDED) &&
!(action & ATA_EH_RESUME))
break;
}
if (i == ATA_MAX_DEVICES || time_after(jiffies, timeout))
break;
msleep(10);
}
done:
spin_lock_irqsave(ap->lock, flags);
ap->pflags &= ~(ATA_PFLAG_PM_PENDING | ATA_PFLAG_SUSPENDED);
if (ap->pm_result) {
*ap->pm_result = rc;
ap->pm_result = NULL;
}
spin_unlock_irqrestore(ap->lock, flags);
}

View File

@ -397,20 +397,129 @@ void ata_dump_status(unsigned id, struct ata_taskfile *tf)
}
}
int ata_scsi_device_resume(struct scsi_device *sdev)
{
struct ata_port *ap = ata_shost_to_port(sdev->host);
struct ata_device *dev = __ata_scsi_find_dev(ap, sdev);
return ata_device_resume(dev);
}
/**
* ata_scsi_device_suspend - suspend ATA device associated with sdev
* @sdev: the SCSI device to suspend
* @state: target power management state
*
* Request suspend EH action on the ATA device associated with
* @sdev and wait for the operation to complete.
*
* LOCKING:
* Kernel thread context (may sleep).
*
* RETURNS:
* 0 on success, -errno otherwise.
*/
int ata_scsi_device_suspend(struct scsi_device *sdev, pm_message_t state)
{
struct ata_port *ap = ata_shost_to_port(sdev->host);
struct ata_device *dev = __ata_scsi_find_dev(ap, sdev);
struct ata_device *dev = ata_scsi_find_dev(ap, sdev);
unsigned long flags;
unsigned int action;
int rc = 0;
return ata_device_suspend(dev, state);
if (!dev)
goto out;
spin_lock_irqsave(ap->lock, flags);
/* wait for the previous resume to complete */
while (dev->flags & ATA_DFLAG_SUSPENDED) {
spin_unlock_irqrestore(ap->lock, flags);
ata_port_wait_eh(ap);
spin_lock_irqsave(ap->lock, flags);
}
/* if @sdev is already detached, nothing to do */
if (sdev->sdev_state == SDEV_OFFLINE ||
sdev->sdev_state == SDEV_CANCEL || sdev->sdev_state == SDEV_DEL)
goto out_unlock;
/* request suspend */
action = ATA_EH_SUSPEND;
if (state.event != PM_EVENT_SUSPEND)
action |= ATA_EH_PM_FREEZE;
ap->eh_info.dev_action[dev->devno] |= action;
ap->eh_info.flags |= ATA_EHI_QUIET;
ata_port_schedule_eh(ap);
spin_unlock_irqrestore(ap->lock, flags);
/* wait for EH to do the job */
ata_port_wait_eh(ap);
spin_lock_irqsave(ap->lock, flags);
/* If @sdev is still attached but the associated ATA device
* isn't suspended, the operation failed.
*/
if (sdev->sdev_state != SDEV_OFFLINE &&
sdev->sdev_state != SDEV_CANCEL && sdev->sdev_state != SDEV_DEL &&
!(dev->flags & ATA_DFLAG_SUSPENDED))
rc = -EIO;
out_unlock:
spin_unlock_irqrestore(ap->lock, flags);
out:
if (rc == 0)
sdev->sdev_gendev.power.power_state = state;
return rc;
}
/**
* ata_scsi_device_resume - resume ATA device associated with sdev
* @sdev: the SCSI device to resume
*
* Request resume EH action on the ATA device associated with
* @sdev and return immediately. This enables parallel
* wakeup/spinup of devices.
*
* LOCKING:
* Kernel thread context (may sleep).
*
* RETURNS:
* 0.
*/
int ata_scsi_device_resume(struct scsi_device *sdev)
{
struct ata_port *ap = ata_shost_to_port(sdev->host);
struct ata_device *dev = ata_scsi_find_dev(ap, sdev);
struct ata_eh_info *ehi = &ap->eh_info;
unsigned long flags;
unsigned int action;
if (!dev)
goto out;
spin_lock_irqsave(ap->lock, flags);
/* if @sdev is already detached, nothing to do */
if (sdev->sdev_state == SDEV_OFFLINE ||
sdev->sdev_state == SDEV_CANCEL || sdev->sdev_state == SDEV_DEL)
goto out_unlock;
/* request resume */
action = ATA_EH_RESUME;
if (sdev->sdev_gendev.power.power_state.event == PM_EVENT_SUSPEND)
__ata_ehi_hotplugged(ehi);
else
action |= ATA_EH_PM_FREEZE | ATA_EH_SOFTRESET;
ehi->dev_action[dev->devno] |= action;
/* We don't want autopsy and verbose EH messages. Disable
* those if we're the only device on this link.
*/
if (ata_port_max_devices(ap) == 1)
ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET;
ata_port_schedule_eh(ap);
out_unlock:
spin_unlock_irqrestore(ap->lock, flags);
out:
sdev->sdev_gendev.power.power_state = PMSG_ON;
return 0;
}
/**
@ -2930,7 +3039,7 @@ void ata_scsi_hotplug(void *data)
struct ata_port *ap = data;
int i;
if (ap->flags & ATA_FLAG_UNLOADING) {
if (ap->pflags & ATA_PFLAG_UNLOADING) {
DPRINTK("ENTER/EXIT - unloading\n");
return;
}
@ -3011,6 +3120,7 @@ static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,
if (dev) {
ap->eh_info.probe_mask |= 1 << dev->devno;
ap->eh_info.action |= ATA_EH_SOFTRESET;
ap->eh_info.flags |= ATA_EHI_RESUME_LINK;
} else
rc = -EINVAL;
}

View File

@ -109,6 +109,7 @@ enum {
};
static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
static int sil_pci_device_resume(struct pci_dev *pdev);
static void sil_dev_config(struct ata_port *ap, struct ata_device *dev);
static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg);
static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
@ -160,6 +161,8 @@ static struct pci_driver sil_pci_driver = {
.id_table = sil_pci_tbl,
.probe = sil_init_one,
.remove = ata_pci_remove_one,
.suspend = ata_pci_device_suspend,
.resume = sil_pci_device_resume,
};
static struct scsi_host_template sil_sht = {
@ -178,6 +181,8 @@ static struct scsi_host_template sil_sht = {
.slave_configure = ata_scsi_slave_config,
.slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
.suspend = ata_scsi_device_suspend,
.resume = ata_scsi_device_resume,
};
static const struct ata_port_operations sil_ops = {
@ -370,7 +375,7 @@ static void sil_host_intr(struct ata_port *ap, u32 bmdma2)
* during hardreset makes controllers with broken SIEN
* repeat probing needlessly.
*/
if (!(ap->flags & ATA_FLAG_FROZEN)) {
if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
ata_ehi_hotplugged(&ap->eh_info);
ap->eh_info.serror |= serror;
}
@ -561,6 +566,52 @@ static void sil_dev_config(struct ata_port *ap, struct ata_device *dev)
}
}
static void sil_init_controller(struct pci_dev *pdev,
int n_ports, unsigned long host_flags,
void __iomem *mmio_base)
{
u8 cls;
u32 tmp;
int i;
/* Initialize FIFO PCI bus arbitration */
cls = sil_get_device_cache_line(pdev);
if (cls) {
cls >>= 3;
cls++; /* cls = (line_size/8)+1 */
for (i = 0; i < n_ports; i++)
writew(cls << 8 | cls,
mmio_base + sil_port[i].fifo_cfg);
} else
dev_printk(KERN_WARNING, &pdev->dev,
"cache line size not set. Driver may not function\n");
/* Apply R_ERR on DMA activate FIS errata workaround */
if (host_flags & SIL_FLAG_RERR_ON_DMA_ACT) {
int cnt;
for (i = 0, cnt = 0; i < n_ports; i++) {
tmp = readl(mmio_base + sil_port[i].sfis_cfg);
if ((tmp & 0x3) != 0x01)
continue;
if (!cnt)
dev_printk(KERN_INFO, &pdev->dev,
"Applying R_ERR on DMA activate "
"FIS errata fix\n");
writel(tmp & ~0x3, mmio_base + sil_port[i].sfis_cfg);
cnt++;
}
}
if (n_ports == 4) {
/* flip the magic "make 4 ports work" bit */
tmp = readl(mmio_base + sil_port[2].bmdma);
if ((tmp & SIL_INTR_STEERING) == 0)
writel(tmp | SIL_INTR_STEERING,
mmio_base + sil_port[2].bmdma);
}
}
static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version;
@ -570,8 +621,6 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
int rc;
unsigned int i;
int pci_dev_busy = 0;
u32 tmp;
u8 cls;
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
@ -630,42 +679,8 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
ata_std_ports(&probe_ent->port[i]);
}
/* Initialize FIFO PCI bus arbitration */
cls = sil_get_device_cache_line(pdev);
if (cls) {
cls >>= 3;
cls++; /* cls = (line_size/8)+1 */
for (i = 0; i < probe_ent->n_ports; i++)
writew(cls << 8 | cls,
mmio_base + sil_port[i].fifo_cfg);
} else
dev_printk(KERN_WARNING, &pdev->dev,
"cache line size not set. Driver may not function\n");
/* Apply R_ERR on DMA activate FIS errata workaround */
if (probe_ent->host_flags & SIL_FLAG_RERR_ON_DMA_ACT) {
int cnt;
for (i = 0, cnt = 0; i < probe_ent->n_ports; i++) {
tmp = readl(mmio_base + sil_port[i].sfis_cfg);
if ((tmp & 0x3) != 0x01)
continue;
if (!cnt)
dev_printk(KERN_INFO, &pdev->dev,
"Applying R_ERR on DMA activate "
"FIS errata fix\n");
writel(tmp & ~0x3, mmio_base + sil_port[i].sfis_cfg);
cnt++;
}
}
if (ent->driver_data == sil_3114) {
/* flip the magic "make 4 ports work" bit */
tmp = readl(mmio_base + sil_port[2].bmdma);
if ((tmp & SIL_INTR_STEERING) == 0)
writel(tmp | SIL_INTR_STEERING,
mmio_base + sil_port[2].bmdma);
}
sil_init_controller(pdev, probe_ent->n_ports, probe_ent->host_flags,
mmio_base);
pci_set_master(pdev);
@ -685,6 +700,18 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
return rc;
}
static int sil_pci_device_resume(struct pci_dev *pdev)
{
struct ata_host_set *host_set = dev_get_drvdata(&pdev->dev);
ata_pci_device_do_resume(pdev);
sil_init_controller(pdev, host_set->n_ports, host_set->ports[0]->flags,
host_set->mmio_base);
ata_host_set_resume(host_set);
return 0;
}
static int __init sil_init(void)
{
return pci_module_init(&sil_pci_driver);

View File

@ -92,6 +92,7 @@ enum {
HOST_CTRL_STOP = (1 << 18), /* latched PCI STOP */
HOST_CTRL_DEVSEL = (1 << 19), /* latched PCI DEVSEL */
HOST_CTRL_REQ64 = (1 << 20), /* latched PCI REQ64 */
HOST_CTRL_GLOBAL_RST = (1 << 31), /* global reset */
/*
* Port registers
@ -338,6 +339,7 @@ static int sil24_port_start(struct ata_port *ap);
static void sil24_port_stop(struct ata_port *ap);
static void sil24_host_stop(struct ata_host_set *host_set);
static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
static int sil24_pci_device_resume(struct pci_dev *pdev);
static const struct pci_device_id sil24_pci_tbl[] = {
{ 0x1095, 0x3124, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3124 },
@ -353,6 +355,8 @@ static struct pci_driver sil24_pci_driver = {
.id_table = sil24_pci_tbl,
.probe = sil24_init_one,
.remove = ata_pci_remove_one, /* safe? */
.suspend = ata_pci_device_suspend,
.resume = sil24_pci_device_resume,
};
static struct scsi_host_template sil24_sht = {
@ -372,6 +376,8 @@ static struct scsi_host_template sil24_sht = {
.slave_configure = ata_scsi_slave_config,
.slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
.suspend = ata_scsi_device_suspend,
.resume = ata_scsi_device_resume,
};
static const struct ata_port_operations sil24_ops = {
@ -607,7 +613,7 @@ static int sil24_hardreset(struct ata_port *ap, unsigned int *class)
/* SStatus oscillates between zero and valid status after
* DEV_RST, debounce it.
*/
rc = sata_phy_debounce(ap, sata_deb_timing_before_fsrst);
rc = sata_phy_debounce(ap, sata_deb_timing_long);
if (rc) {
reason = "PHY debouncing failed";
goto err;
@ -988,6 +994,64 @@ static void sil24_host_stop(struct ata_host_set *host_set)
kfree(hpriv);
}
static void sil24_init_controller(struct pci_dev *pdev, int n_ports,
unsigned long host_flags,
void __iomem *host_base,
void __iomem *port_base)
{
u32 tmp;
int i;
/* GPIO off */
writel(0, host_base + HOST_FLASH_CMD);
/* clear global reset & mask interrupts during initialization */
writel(0, host_base + HOST_CTRL);
/* init ports */
for (i = 0; i < n_ports; i++) {
void __iomem *port = port_base + i * PORT_REGS_SIZE;
/* Initial PHY setting */
writel(0x20c, port + PORT_PHY_CFG);
/* Clear port RST */
tmp = readl(port + PORT_CTRL_STAT);
if (tmp & PORT_CS_PORT_RST) {
writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR);
tmp = ata_wait_register(port + PORT_CTRL_STAT,
PORT_CS_PORT_RST,
PORT_CS_PORT_RST, 10, 100);
if (tmp & PORT_CS_PORT_RST)
dev_printk(KERN_ERR, &pdev->dev,
"failed to clear port RST\n");
}
/* Configure IRQ WoC */
if (host_flags & SIL24_FLAG_PCIX_IRQ_WOC)
writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_STAT);
else
writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR);
/* Zero error counters. */
writel(0x8000, port + PORT_DECODE_ERR_THRESH);
writel(0x8000, port + PORT_CRC_ERR_THRESH);
writel(0x8000, port + PORT_HSHK_ERR_THRESH);
writel(0x0000, port + PORT_DECODE_ERR_CNT);
writel(0x0000, port + PORT_CRC_ERR_CNT);
writel(0x0000, port + PORT_HSHK_ERR_CNT);
/* Always use 64bit activation */
writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR);
/* Clear port multiplier enable and resume bits */
writel(PORT_CS_PM_EN | PORT_CS_RESUME, port + PORT_CTRL_CLR);
}
/* Turn on interrupts */
writel(IRQ_STAT_4PORTS, host_base + HOST_CTRL);
}
static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version = 0;
@ -1076,9 +1140,6 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
}
}
/* GPIO off */
writel(0, host_base + HOST_FLASH_CMD);
/* Apply workaround for completion IRQ loss on PCI-X errata */
if (probe_ent->host_flags & SIL24_FLAG_PCIX_IRQ_WOC) {
tmp = readl(host_base + HOST_CTRL);
@ -1090,56 +1151,18 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
probe_ent->host_flags &= ~SIL24_FLAG_PCIX_IRQ_WOC;
}
/* clear global reset & mask interrupts during initialization */
writel(0, host_base + HOST_CTRL);
for (i = 0; i < probe_ent->n_ports; i++) {
void __iomem *port = port_base + i * PORT_REGS_SIZE;
unsigned long portu = (unsigned long)port;
unsigned long portu =
(unsigned long)port_base + i * PORT_REGS_SIZE;
probe_ent->port[i].cmd_addr = portu;
probe_ent->port[i].scr_addr = portu + PORT_SCONTROL;
ata_std_ports(&probe_ent->port[i]);
/* Initial PHY setting */
writel(0x20c, port + PORT_PHY_CFG);
/* Clear port RST */
tmp = readl(port + PORT_CTRL_STAT);
if (tmp & PORT_CS_PORT_RST) {
writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR);
tmp = ata_wait_register(port + PORT_CTRL_STAT,
PORT_CS_PORT_RST,
PORT_CS_PORT_RST, 10, 100);
if (tmp & PORT_CS_PORT_RST)
dev_printk(KERN_ERR, &pdev->dev,
"failed to clear port RST\n");
}
/* Configure IRQ WoC */
if (probe_ent->host_flags & SIL24_FLAG_PCIX_IRQ_WOC)
writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_STAT);
else
writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR);
/* Zero error counters. */
writel(0x8000, port + PORT_DECODE_ERR_THRESH);
writel(0x8000, port + PORT_CRC_ERR_THRESH);
writel(0x8000, port + PORT_HSHK_ERR_THRESH);
writel(0x0000, port + PORT_DECODE_ERR_CNT);
writel(0x0000, port + PORT_CRC_ERR_CNT);
writel(0x0000, port + PORT_HSHK_ERR_CNT);
/* Always use 64bit activation */
writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR);
/* Clear port multiplier enable and resume bits */
writel(PORT_CS_PM_EN | PORT_CS_RESUME, port + PORT_CTRL_CLR);
}
/* Turn on interrupts */
writel(IRQ_STAT_4PORTS, host_base + HOST_CTRL);
sil24_init_controller(pdev, probe_ent->n_ports, probe_ent->host_flags,
host_base, port_base);
pci_set_master(pdev);
@ -1162,6 +1185,25 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
return rc;
}
static int sil24_pci_device_resume(struct pci_dev *pdev)
{
struct ata_host_set *host_set = dev_get_drvdata(&pdev->dev);
struct sil24_host_priv *hpriv = host_set->private_data;
ata_pci_device_do_resume(pdev);
if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND)
writel(HOST_CTRL_GLOBAL_RST, hpriv->host_base + HOST_CTRL);
sil24_init_controller(pdev, host_set->n_ports,
host_set->ports[0]->flags,
hpriv->host_base, hpriv->port_base);
ata_host_set_resume(host_set);
return 0;
}
static int __init sil24_init(void)
{
return pci_module_init(&sil24_pci_driver);

View File

@ -297,7 +297,7 @@ static const struct ata_port_operations vsc_sata_ops = {
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
.data_xfer = ata_pio_data_xfer,
.data_xfer = ata_mmio_data_xfer,
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
.error_handler = ata_bmdma_error_handler,

View File

@ -41,6 +41,7 @@
#include <asm/mach/serial_at91.h>
#include <asm/arch/board.h>
#include <asm/arch/system.h>
#include <asm/arch/gpio.h>
#if defined(CONFIG_SERIAL_AT91_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
@ -140,9 +141,9 @@ static void at91_set_mctrl(struct uart_port *port, u_int mctrl)
*/
if (port->mapbase == AT91_BASE_US0) {
if (mctrl & TIOCM_RTS)
at91_sys_write(AT91_PIOA + PIO_CODR, AT91_PA21_RTS0);
at91_set_gpio_value(AT91_PIN_PA21, 0);
else
at91_sys_write(AT91_PIOA + PIO_SODR, AT91_PA21_RTS0);
at91_set_gpio_value(AT91_PIN_PA21, 1);
}
}

View File

@ -454,7 +454,7 @@ static void nlmclnt_locks_init_private(struct file_lock *fl, struct nlm_host *ho
fl->fl_ops = &nlmclnt_lock_ops;
}
static void do_vfs_lock(struct file_lock *fl)
static int do_vfs_lock(struct file_lock *fl)
{
int res = 0;
switch (fl->fl_flags & (FL_POSIX|FL_FLOCK)) {
@ -467,9 +467,7 @@ static void do_vfs_lock(struct file_lock *fl)
default:
BUG();
}
if (res < 0)
printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n",
__FUNCTION__);
return res;
}
/*
@ -498,6 +496,7 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
struct nlm_host *host = req->a_host;
struct nlm_res *resp = &req->a_res;
struct nlm_wait *block = NULL;
unsigned char fl_flags = fl->fl_flags;
int status = -ENOLCK;
if (!host->h_monitored && nsm_monitor(host) < 0) {
@ -505,6 +504,10 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
host->h_name);
goto out;
}
fl->fl_flags |= FL_ACCESS;
status = do_vfs_lock(fl);
if (status < 0)
goto out;
block = nlmclnt_prepare_block(host, fl);
again:
@ -539,9 +542,10 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
up_read(&host->h_rwsem);
goto again;
}
fl->fl_flags |= FL_SLEEP;
/* Ensure the resulting lock will get added to granted list */
do_vfs_lock(fl);
fl->fl_flags = fl_flags | FL_SLEEP;
if (do_vfs_lock(fl) < 0)
printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __FUNCTION__);
up_read(&host->h_rwsem);
}
status = nlm_stat_to_errno(resp->status);
@ -552,6 +556,7 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
nlmclnt_cancel(host, req->a_args.block, fl);
out:
nlm_release_call(req);
fl->fl_flags = fl_flags;
return status;
}
@ -606,15 +611,19 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl)
{
struct nlm_host *host = req->a_host;
struct nlm_res *resp = &req->a_res;
int status;
int status = 0;
/*
* Note: the server is supposed to either grant us the unlock
* request, or to deny it with NLM_LCK_DENIED_GRACE_PERIOD. In either
* case, we want to unlock.
*/
fl->fl_flags |= FL_EXISTS;
down_read(&host->h_rwsem);
do_vfs_lock(fl);
if (do_vfs_lock(fl) == -ENOENT) {
up_read(&host->h_rwsem);
goto out;
}
up_read(&host->h_rwsem);
if (req->a_flags & RPC_TASK_ASYNC)
@ -624,7 +633,6 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl)
if (status < 0)
goto out;
status = 0;
if (resp->status == NLM_LCK_GRANTED)
goto out;

View File

@ -725,6 +725,10 @@ static int posix_locks_deadlock(struct file_lock *caller_fl,
/* Try to create a FLOCK lock on filp. We always insert new FLOCK locks
* at the head of the list, but that's secret knowledge known only to
* flock_lock_file and posix_lock_file.
*
* Note that if called with an FL_EXISTS argument, the caller may determine
* whether or not a lock was successfully freed by testing the return
* value for -ENOENT.
*/
static int flock_lock_file(struct file *filp, struct file_lock *request)
{
@ -735,6 +739,8 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)
int found = 0;
lock_kernel();
if (request->fl_flags & FL_ACCESS)
goto find_conflict;
for_each_lock(inode, before) {
struct file_lock *fl = *before;
if (IS_POSIX(fl))
@ -750,8 +756,11 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)
break;
}
if (request->fl_type == F_UNLCK)
if (request->fl_type == F_UNLCK) {
if ((request->fl_flags & FL_EXISTS) && !found)
error = -ENOENT;
goto out;
}
error = -ENOMEM;
new_fl = locks_alloc_lock();
@ -764,6 +773,7 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)
if (found)
cond_resched();
find_conflict:
for_each_lock(inode, before) {
struct file_lock *fl = *before;
if (IS_POSIX(fl))
@ -777,6 +787,8 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)
locks_insert_block(fl, request);
goto out;
}
if (request->fl_flags & FL_ACCESS)
goto out;
locks_copy_lock(new_fl, request);
locks_insert_lock(&inode->i_flock, new_fl);
new_fl = NULL;
@ -948,8 +960,11 @@ static int __posix_lock_file_conf(struct inode *inode, struct file_lock *request
error = 0;
if (!added) {
if (request->fl_type == F_UNLCK)
if (request->fl_type == F_UNLCK) {
if (request->fl_flags & FL_EXISTS)
error = -ENOENT;
goto out;
}
if (!new_fl) {
error = -ENOLCK;
@ -996,6 +1011,10 @@ static int __posix_lock_file_conf(struct inode *inode, struct file_lock *request
* Add a POSIX style lock to a file.
* We merge adjacent & overlapping locks whenever possible.
* POSIX locks are sorted by owner task, then by starting address
*
* Note that if called with an FL_EXISTS argument, the caller may determine
* whether or not a lock was successfully freed by testing the return
* value for -ENOENT.
*/
int posix_lock_file(struct file *filp, struct file_lock *fl)
{

View File

@ -690,7 +690,9 @@ int nfs_lookup_verify_inode(struct inode *inode, struct nameidata *nd)
goto out_force;
/* This is an open(2) */
if (nfs_lookup_check_intent(nd, LOOKUP_OPEN) != 0 &&
!(server->flags & NFS_MOUNT_NOCTO))
!(server->flags & NFS_MOUNT_NOCTO) &&
(S_ISREG(inode->i_mode) ||
S_ISDIR(inode->i_mode)))
goto out_force;
}
return nfs_revalidate_inode(server, inode);

View File

@ -67,25 +67,19 @@ struct nfs_direct_req {
struct kref kref; /* release manager */
/* I/O parameters */
struct list_head list, /* nfs_read/write_data structs */
rewrite_list; /* saved nfs_write_data structs */
struct nfs_open_context *ctx; /* file open context info */
struct kiocb * iocb; /* controlling i/o request */
struct inode * inode; /* target file of i/o */
unsigned long user_addr; /* location of user's buffer */
size_t user_count; /* total bytes to move */
loff_t pos; /* starting offset in file */
struct page ** pages; /* pages in our buffer */
unsigned int npages; /* count of pages */
/* completion state */
atomic_t io_count; /* i/os we're waiting for */
spinlock_t lock; /* protect completion state */
int outstanding; /* i/os we're waiting for */
ssize_t count, /* bytes actually processed */
error; /* any reported error */
struct completion completion; /* wait for i/o completion */
/* commit state */
struct list_head rewrite_list; /* saved nfs_write_data structs */
struct nfs_write_data * commit_data; /* special write_data for commits */
int flags;
#define NFS_ODIRECT_DO_COMMIT (1) /* an unstable reply was received */
@ -93,8 +87,37 @@ struct nfs_direct_req {
struct nfs_writeverf verf; /* unstable write verifier */
};
static void nfs_direct_write_schedule(struct nfs_direct_req *dreq, int sync);
static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode *inode);
static const struct rpc_call_ops nfs_write_direct_ops;
static inline void get_dreq(struct nfs_direct_req *dreq)
{
atomic_inc(&dreq->io_count);
}
static inline int put_dreq(struct nfs_direct_req *dreq)
{
return atomic_dec_and_test(&dreq->io_count);
}
/*
* "size" is never larger than rsize or wsize.
*/
static inline int nfs_direct_count_pages(unsigned long user_addr, size_t size)
{
int page_count;
page_count = (user_addr + size + PAGE_SIZE - 1) >> PAGE_SHIFT;
page_count -= user_addr >> PAGE_SHIFT;
BUG_ON(page_count < 0);
return page_count;
}
static inline unsigned int nfs_max_pages(unsigned int size)
{
return (size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
}
/**
* nfs_direct_IO - NFS address space operation for direct I/O
@ -118,50 +141,21 @@ ssize_t nfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, loff_
return -EINVAL;
}
static void nfs_free_user_pages(struct page **pages, int npages, int do_dirty)
static void nfs_direct_dirty_pages(struct page **pages, int npages)
{
int i;
for (i = 0; i < npages; i++) {
struct page *page = pages[i];
if (do_dirty && !PageCompound(page))
if (!PageCompound(page))
set_page_dirty_lock(page);
page_cache_release(page);
}
kfree(pages);
}
static inline int nfs_get_user_pages(int rw, unsigned long user_addr, size_t size, struct page ***pages)
static void nfs_direct_release_pages(struct page **pages, int npages)
{
int result = -ENOMEM;
unsigned long page_count;
size_t array_size;
page_count = (user_addr + size + PAGE_SIZE - 1) >> PAGE_SHIFT;
page_count -= user_addr >> PAGE_SHIFT;
array_size = (page_count * sizeof(struct page *));
*pages = kmalloc(array_size, GFP_KERNEL);
if (*pages) {
down_read(&current->mm->mmap_sem);
result = get_user_pages(current, current->mm, user_addr,
page_count, (rw == READ), 0,
*pages, NULL);
up_read(&current->mm->mmap_sem);
if (result != page_count) {
/*
* If we got fewer pages than expected from
* get_user_pages(), the user buffer runs off the
* end of a mapping; return EFAULT.
*/
if (result >= 0) {
nfs_free_user_pages(*pages, result, 0);
result = -EFAULT;
} else
kfree(*pages);
*pages = NULL;
}
}
return result;
int i;
for (i = 0; i < npages; i++)
page_cache_release(pages[i]);
}
static inline struct nfs_direct_req *nfs_direct_req_alloc(void)
@ -173,13 +167,13 @@ static inline struct nfs_direct_req *nfs_direct_req_alloc(void)
return NULL;
kref_init(&dreq->kref);
kref_get(&dreq->kref);
init_completion(&dreq->completion);
INIT_LIST_HEAD(&dreq->list);
INIT_LIST_HEAD(&dreq->rewrite_list);
dreq->iocb = NULL;
dreq->ctx = NULL;
spin_lock_init(&dreq->lock);
dreq->outstanding = 0;
atomic_set(&dreq->io_count, 0);
dreq->count = 0;
dreq->error = 0;
dreq->flags = 0;
@ -220,18 +214,11 @@ static ssize_t nfs_direct_wait(struct nfs_direct_req *dreq)
}
/*
* We must hold a reference to all the pages in this direct read request
* until the RPCs complete. This could be long *after* we are woken up in
* nfs_direct_wait (for instance, if someone hits ^C on a slow server).
*
* In addition, synchronous I/O uses a stack-allocated iocb. Thus we
* can't trust the iocb is still valid here if this is a synchronous
* request. If the waiter is woken prematurely, the iocb is long gone.
* Synchronous I/O uses a stack-allocated iocb. Thus we can't trust
* the iocb is still valid here if this is a synchronous request.
*/
static void nfs_direct_complete(struct nfs_direct_req *dreq)
{
nfs_free_user_pages(dreq->pages, dreq->npages, 1);
if (dreq->iocb) {
long res = (long) dreq->error;
if (!res)
@ -244,48 +231,10 @@ static void nfs_direct_complete(struct nfs_direct_req *dreq)
}
/*
* Note we also set the number of requests we have in the dreq when we are
* done. This prevents races with I/O completion so we will always wait
* until all requests have been dispatched and completed.
* We must hold a reference to all the pages in this direct read request
* until the RPCs complete. This could be long *after* we are woken up in
* nfs_direct_wait (for instance, if someone hits ^C on a slow server).
*/
static struct nfs_direct_req *nfs_direct_read_alloc(size_t nbytes, size_t rsize)
{
struct list_head *list;
struct nfs_direct_req *dreq;
unsigned int rpages = (rsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
dreq = nfs_direct_req_alloc();
if (!dreq)
return NULL;
list = &dreq->list;
for(;;) {
struct nfs_read_data *data = nfs_readdata_alloc(rpages);
if (unlikely(!data)) {
while (!list_empty(list)) {
data = list_entry(list->next,
struct nfs_read_data, pages);
list_del(&data->pages);
nfs_readdata_free(data);
}
kref_put(&dreq->kref, nfs_direct_req_release);
return NULL;
}
INIT_LIST_HEAD(&data->pages);
list_add(&data->pages, list);
data->req = (struct nfs_page *) dreq;
dreq->outstanding++;
if (nbytes <= rsize)
break;
nbytes -= rsize;
}
kref_get(&dreq->kref);
return dreq;
}
static void nfs_direct_read_result(struct rpc_task *task, void *calldata)
{
struct nfs_read_data *data = calldata;
@ -294,6 +243,9 @@ static void nfs_direct_read_result(struct rpc_task *task, void *calldata)
if (nfs_readpage_result(task, data) != 0)
return;
nfs_direct_dirty_pages(data->pagevec, data->npages);
nfs_direct_release_pages(data->pagevec, data->npages);
spin_lock(&dreq->lock);
if (likely(task->tk_status >= 0))
@ -301,13 +253,10 @@ static void nfs_direct_read_result(struct rpc_task *task, void *calldata)
else
dreq->error = task->tk_status;
if (--dreq->outstanding) {
spin_unlock(&dreq->lock);
return;
}
spin_unlock(&dreq->lock);
nfs_direct_complete(dreq);
if (put_dreq(dreq))
nfs_direct_complete(dreq);
}
static const struct rpc_call_ops nfs_read_direct_ops = {
@ -316,41 +265,60 @@ static const struct rpc_call_ops nfs_read_direct_ops = {
};
/*
* For each nfs_read_data struct that was allocated on the list, dispatch
* an NFS READ operation
* For each rsize'd chunk of the user's buffer, dispatch an NFS READ
* operation. If nfs_readdata_alloc() or get_user_pages() fails,
* bail and stop sending more reads. Read length accounting is
* handled automatically by nfs_direct_read_result(). Otherwise, if
* no requests have been sent, just return an error.
*/
static void nfs_direct_read_schedule(struct nfs_direct_req *dreq)
static ssize_t nfs_direct_read_schedule(struct nfs_direct_req *dreq, unsigned long user_addr, size_t count, loff_t pos)
{
struct nfs_open_context *ctx = dreq->ctx;
struct inode *inode = ctx->dentry->d_inode;
struct list_head *list = &dreq->list;
struct page **pages = dreq->pages;
size_t count = dreq->user_count;
loff_t pos = dreq->pos;
size_t rsize = NFS_SERVER(inode)->rsize;
unsigned int curpage, pgbase;
unsigned int rpages = nfs_max_pages(rsize);
unsigned int pgbase;
int result;
ssize_t started = 0;
curpage = 0;
pgbase = dreq->user_addr & ~PAGE_MASK;
get_dreq(dreq);
pgbase = user_addr & ~PAGE_MASK;
do {
struct nfs_read_data *data;
size_t bytes;
result = -ENOMEM;
data = nfs_readdata_alloc(rpages);
if (unlikely(!data))
break;
bytes = rsize;
if (count < rsize)
bytes = count;
BUG_ON(list_empty(list));
data = list_entry(list->next, struct nfs_read_data, pages);
list_del_init(&data->pages);
data->npages = nfs_direct_count_pages(user_addr, bytes);
down_read(&current->mm->mmap_sem);
result = get_user_pages(current, current->mm, user_addr,
data->npages, 1, 0, data->pagevec, NULL);
up_read(&current->mm->mmap_sem);
if (unlikely(result < data->npages)) {
if (result > 0)
nfs_direct_release_pages(data->pagevec, result);
nfs_readdata_release(data);
break;
}
get_dreq(dreq);
data->req = (struct nfs_page *) dreq;
data->inode = inode;
data->cred = ctx->cred;
data->args.fh = NFS_FH(inode);
data->args.context = ctx;
data->args.offset = pos;
data->args.pgbase = pgbase;
data->args.pages = &pages[curpage];
data->args.pages = data->pagevec;
data->args.count = bytes;
data->res.fattr = &data->fattr;
data->res.eof = 0;
@ -373,33 +341,35 @@ static void nfs_direct_read_schedule(struct nfs_direct_req *dreq)
bytes,
(unsigned long long)data->args.offset);
started += bytes;
user_addr += bytes;
pos += bytes;
pgbase += bytes;
curpage += pgbase >> PAGE_SHIFT;
pgbase &= ~PAGE_MASK;
count -= bytes;
} while (count != 0);
BUG_ON(!list_empty(list));
if (put_dreq(dreq))
nfs_direct_complete(dreq);
if (started)
return 0;
return result < 0 ? (ssize_t) result : -EFAULT;
}
static ssize_t nfs_direct_read(struct kiocb *iocb, unsigned long user_addr, size_t count, loff_t pos, struct page **pages, unsigned int nr_pages)
static ssize_t nfs_direct_read(struct kiocb *iocb, unsigned long user_addr, size_t count, loff_t pos)
{
ssize_t result;
ssize_t result = 0;
sigset_t oldset;
struct inode *inode = iocb->ki_filp->f_mapping->host;
struct rpc_clnt *clnt = NFS_CLIENT(inode);
struct nfs_direct_req *dreq;
dreq = nfs_direct_read_alloc(count, NFS_SERVER(inode)->rsize);
dreq = nfs_direct_req_alloc();
if (!dreq)
return -ENOMEM;
dreq->user_addr = user_addr;
dreq->user_count = count;
dreq->pos = pos;
dreq->pages = pages;
dreq->npages = nr_pages;
dreq->inode = inode;
dreq->ctx = get_nfs_open_context((struct nfs_open_context *)iocb->ki_filp->private_data);
if (!is_sync_kiocb(iocb))
@ -407,8 +377,9 @@ static ssize_t nfs_direct_read(struct kiocb *iocb, unsigned long user_addr, size
nfs_add_stats(inode, NFSIOS_DIRECTREADBYTES, count);
rpc_clnt_sigmask(clnt, &oldset);
nfs_direct_read_schedule(dreq);
result = nfs_direct_wait(dreq);
result = nfs_direct_read_schedule(dreq, user_addr, count, pos);
if (!result)
result = nfs_direct_wait(dreq);
rpc_clnt_sigunmask(clnt, &oldset);
return result;
@ -416,10 +387,10 @@ static ssize_t nfs_direct_read(struct kiocb *iocb, unsigned long user_addr, size
static void nfs_direct_free_writedata(struct nfs_direct_req *dreq)
{
list_splice_init(&dreq->rewrite_list, &dreq->list);
while (!list_empty(&dreq->list)) {
struct nfs_write_data *data = list_entry(dreq->list.next, struct nfs_write_data, pages);
while (!list_empty(&dreq->rewrite_list)) {
struct nfs_write_data *data = list_entry(dreq->rewrite_list.next, struct nfs_write_data, pages);
list_del(&data->pages);
nfs_direct_release_pages(data->pagevec, data->npages);
nfs_writedata_release(data);
}
}
@ -427,14 +398,51 @@ static void nfs_direct_free_writedata(struct nfs_direct_req *dreq)
#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq)
{
struct list_head *pos;
struct inode *inode = dreq->inode;
struct list_head *p;
struct nfs_write_data *data;
list_splice_init(&dreq->rewrite_list, &dreq->list);
list_for_each(pos, &dreq->list)
dreq->outstanding++;
dreq->count = 0;
get_dreq(dreq);
nfs_direct_write_schedule(dreq, FLUSH_STABLE);
list_for_each(p, &dreq->rewrite_list) {
data = list_entry(p, struct nfs_write_data, pages);
get_dreq(dreq);
/*
* Reset data->res.
*/
nfs_fattr_init(&data->fattr);
data->res.count = data->args.count;
memset(&data->verf, 0, sizeof(data->verf));
/*
* Reuse data->task; data->args should not have changed
* since the original request was sent.
*/
rpc_init_task(&data->task, NFS_CLIENT(inode), RPC_TASK_ASYNC,
&nfs_write_direct_ops, data);
NFS_PROTO(inode)->write_setup(data, FLUSH_STABLE);
data->task.tk_priority = RPC_PRIORITY_NORMAL;
data->task.tk_cookie = (unsigned long) inode;
/*
* We're called via an RPC callback, so BKL is already held.
*/
rpc_execute(&data->task);
dprintk("NFS: %5u rescheduled direct write call (req %s/%Ld, %u bytes @ offset %Lu)\n",
data->task.tk_pid,
inode->i_sb->s_id,
(long long)NFS_FILEID(inode),
data->args.count,
(unsigned long long)data->args.offset);
}
if (put_dreq(dreq))
nfs_direct_write_complete(dreq, inode);
}
static void nfs_direct_commit_result(struct rpc_task *task, void *calldata)
@ -471,8 +479,8 @@ static void nfs_direct_commit_schedule(struct nfs_direct_req *dreq)
data->cred = dreq->ctx->cred;
data->args.fh = NFS_FH(data->inode);
data->args.offset = dreq->pos;
data->args.count = dreq->user_count;
data->args.offset = 0;
data->args.count = 0;
data->res.count = 0;
data->res.fattr = &data->fattr;
data->res.verf = &data->verf;
@ -534,47 +542,6 @@ static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode
}
#endif
static struct nfs_direct_req *nfs_direct_write_alloc(size_t nbytes, size_t wsize)
{
struct list_head *list;
struct nfs_direct_req *dreq;
unsigned int wpages = (wsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
dreq = nfs_direct_req_alloc();
if (!dreq)
return NULL;
list = &dreq->list;
for(;;) {
struct nfs_write_data *data = nfs_writedata_alloc(wpages);
if (unlikely(!data)) {
while (!list_empty(list)) {
data = list_entry(list->next,
struct nfs_write_data, pages);
list_del(&data->pages);
nfs_writedata_free(data);
}
kref_put(&dreq->kref, nfs_direct_req_release);
return NULL;
}
INIT_LIST_HEAD(&data->pages);
list_add(&data->pages, list);
data->req = (struct nfs_page *) dreq;
dreq->outstanding++;
if (nbytes <= wsize)
break;
nbytes -= wsize;
}
nfs_alloc_commit_data(dreq);
kref_get(&dreq->kref);
return dreq;
}
static void nfs_direct_write_result(struct rpc_task *task, void *calldata)
{
struct nfs_write_data *data = calldata;
@ -604,8 +571,6 @@ static void nfs_direct_write_result(struct rpc_task *task, void *calldata)
}
}
}
/* In case we have to resend */
data->args.stable = NFS_FILE_SYNC;
spin_unlock(&dreq->lock);
}
@ -619,14 +584,8 @@ static void nfs_direct_write_release(void *calldata)
struct nfs_write_data *data = calldata;
struct nfs_direct_req *dreq = (struct nfs_direct_req *) data->req;
spin_lock(&dreq->lock);
if (--dreq->outstanding) {
spin_unlock(&dreq->lock);
return;
}
spin_unlock(&dreq->lock);
nfs_direct_write_complete(dreq, data->inode);
if (put_dreq(dreq))
nfs_direct_write_complete(dreq, data->inode);
}
static const struct rpc_call_ops nfs_write_direct_ops = {
@ -635,41 +594,62 @@ static const struct rpc_call_ops nfs_write_direct_ops = {
};
/*
* For each nfs_write_data struct that was allocated on the list, dispatch
* an NFS WRITE operation
* For each wsize'd chunk of the user's buffer, dispatch an NFS WRITE
* operation. If nfs_writedata_alloc() or get_user_pages() fails,
* bail and stop sending more writes. Write length accounting is
* handled automatically by nfs_direct_write_result(). Otherwise, if
* no requests have been sent, just return an error.
*/
static void nfs_direct_write_schedule(struct nfs_direct_req *dreq, int sync)
static ssize_t nfs_direct_write_schedule(struct nfs_direct_req *dreq, unsigned long user_addr, size_t count, loff_t pos, int sync)
{
struct nfs_open_context *ctx = dreq->ctx;
struct inode *inode = ctx->dentry->d_inode;
struct list_head *list = &dreq->list;
struct page **pages = dreq->pages;
size_t count = dreq->user_count;
loff_t pos = dreq->pos;
size_t wsize = NFS_SERVER(inode)->wsize;
unsigned int curpage, pgbase;
unsigned int wpages = nfs_max_pages(wsize);
unsigned int pgbase;
int result;
ssize_t started = 0;
curpage = 0;
pgbase = dreq->user_addr & ~PAGE_MASK;
get_dreq(dreq);
pgbase = user_addr & ~PAGE_MASK;
do {
struct nfs_write_data *data;
size_t bytes;
result = -ENOMEM;
data = nfs_writedata_alloc(wpages);
if (unlikely(!data))
break;
bytes = wsize;
if (count < wsize)
bytes = count;
BUG_ON(list_empty(list));
data = list_entry(list->next, struct nfs_write_data, pages);
data->npages = nfs_direct_count_pages(user_addr, bytes);
down_read(&current->mm->mmap_sem);
result = get_user_pages(current, current->mm, user_addr,
data->npages, 0, 0, data->pagevec, NULL);
up_read(&current->mm->mmap_sem);
if (unlikely(result < data->npages)) {
if (result > 0)
nfs_direct_release_pages(data->pagevec, result);
nfs_writedata_release(data);
break;
}
get_dreq(dreq);
list_move_tail(&data->pages, &dreq->rewrite_list);
data->req = (struct nfs_page *) dreq;
data->inode = inode;
data->cred = ctx->cred;
data->args.fh = NFS_FH(inode);
data->args.context = ctx;
data->args.offset = pos;
data->args.pgbase = pgbase;
data->args.pages = &pages[curpage];
data->args.pages = data->pagevec;
data->args.count = bytes;
data->res.fattr = &data->fattr;
data->res.count = bytes;
@ -693,19 +673,26 @@ static void nfs_direct_write_schedule(struct nfs_direct_req *dreq, int sync)
bytes,
(unsigned long long)data->args.offset);
started += bytes;
user_addr += bytes;
pos += bytes;
pgbase += bytes;
curpage += pgbase >> PAGE_SHIFT;
pgbase &= ~PAGE_MASK;
count -= bytes;
} while (count != 0);
BUG_ON(!list_empty(list));
if (put_dreq(dreq))
nfs_direct_write_complete(dreq, inode);
if (started)
return 0;
return result < 0 ? (ssize_t) result : -EFAULT;
}
static ssize_t nfs_direct_write(struct kiocb *iocb, unsigned long user_addr, size_t count, loff_t pos, struct page **pages, int nr_pages)
static ssize_t nfs_direct_write(struct kiocb *iocb, unsigned long user_addr, size_t count, loff_t pos)
{
ssize_t result;
ssize_t result = 0;
sigset_t oldset;
struct inode *inode = iocb->ki_filp->f_mapping->host;
struct rpc_clnt *clnt = NFS_CLIENT(inode);
@ -713,17 +700,14 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, unsigned long user_addr, siz
size_t wsize = NFS_SERVER(inode)->wsize;
int sync = 0;
dreq = nfs_direct_write_alloc(count, wsize);
dreq = nfs_direct_req_alloc();
if (!dreq)
return -ENOMEM;
nfs_alloc_commit_data(dreq);
if (dreq->commit_data == NULL || count < wsize)
sync = FLUSH_STABLE;
dreq->user_addr = user_addr;
dreq->user_count = count;
dreq->pos = pos;
dreq->pages = pages;
dreq->npages = nr_pages;
dreq->inode = inode;
dreq->ctx = get_nfs_open_context((struct nfs_open_context *)iocb->ki_filp->private_data);
if (!is_sync_kiocb(iocb))
@ -734,8 +718,9 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, unsigned long user_addr, siz
nfs_begin_data_update(inode);
rpc_clnt_sigmask(clnt, &oldset);
nfs_direct_write_schedule(dreq, sync);
result = nfs_direct_wait(dreq);
result = nfs_direct_write_schedule(dreq, user_addr, count, pos, sync);
if (!result)
result = nfs_direct_wait(dreq);
rpc_clnt_sigunmask(clnt, &oldset);
return result;
@ -765,8 +750,6 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, unsigned long user_addr, siz
ssize_t nfs_file_direct_read(struct kiocb *iocb, char __user *buf, size_t count, loff_t pos)
{
ssize_t retval = -EINVAL;
int page_count;
struct page **pages;
struct file *file = iocb->ki_filp;
struct address_space *mapping = file->f_mapping;
@ -788,14 +771,7 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, char __user *buf, size_t count,
if (retval)
goto out;
retval = nfs_get_user_pages(READ, (unsigned long) buf,
count, &pages);
if (retval < 0)
goto out;
page_count = retval;
retval = nfs_direct_read(iocb, (unsigned long) buf, count, pos,
pages, page_count);
retval = nfs_direct_read(iocb, (unsigned long) buf, count, pos);
if (retval > 0)
iocb->ki_pos = pos + retval;
@ -831,8 +807,6 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, char __user *buf, size_t count,
ssize_t nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t pos)
{
ssize_t retval;
int page_count;
struct page **pages;
struct file *file = iocb->ki_filp;
struct address_space *mapping = file->f_mapping;
@ -860,14 +834,7 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t
if (retval)
goto out;
retval = nfs_get_user_pages(WRITE, (unsigned long) buf,
count, &pages);
if (retval < 0)
goto out;
page_count = retval;
retval = nfs_direct_write(iocb, (unsigned long) buf, count,
pos, pages, page_count);
retval = nfs_direct_write(iocb, (unsigned long) buf, count, pos);
/*
* XXX: nfs_end_data_update() already ensures this file's

View File

@ -3144,9 +3144,6 @@ static int do_vfs_lock(struct file *file, struct file_lock *fl)
default:
BUG();
}
if (res < 0)
printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n",
__FUNCTION__);
return res;
}
@ -3258,8 +3255,6 @@ static struct rpc_task *nfs4_do_unlck(struct file_lock *fl,
return ERR_PTR(-ENOMEM);
}
/* Unlock _before_ we do the RPC call */
do_vfs_lock(fl->fl_file, fl);
return rpc_run_task(NFS_CLIENT(lsp->ls_state->inode), RPC_TASK_ASYNC, &nfs4_locku_ops, data);
}
@ -3270,30 +3265,28 @@ static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *
struct rpc_task *task;
int status = 0;
status = nfs4_set_lock_state(state, request);
/* Unlock _before_ we do the RPC call */
request->fl_flags |= FL_EXISTS;
if (do_vfs_lock(request->fl_file, request) == -ENOENT)
goto out;
if (status != 0)
goto out;
/* Is this a delegated lock? */
if (test_bit(NFS_DELEGATED_STATE, &state->flags))
goto out_unlock;
/* Is this open_owner holding any locks on the server? */
if (test_bit(LK_STATE_IN_USE, &state->flags) == 0)
goto out_unlock;
status = nfs4_set_lock_state(state, request);
if (status != 0)
goto out_unlock;
goto out;
lsp = request->fl_u.nfs4_fl.owner;
status = -ENOMEM;
seqid = nfs_alloc_seqid(&lsp->ls_seqid);
status = -ENOMEM;
if (seqid == NULL)
goto out_unlock;
goto out;
task = nfs4_do_unlck(request, request->fl_file->private_data, lsp, seqid);
status = PTR_ERR(task);
if (IS_ERR(task))
goto out_unlock;
goto out;
status = nfs4_wait_for_completion_rpc_task(task);
rpc_release_task(task);
return status;
out_unlock:
do_vfs_lock(request->fl_file, request);
out:
return status;
}
@ -3461,10 +3454,10 @@ static int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request
struct nfs4_exception exception = { };
int err;
/* Cache the lock if possible... */
if (test_bit(NFS_DELEGATED_STATE, &state->flags))
return 0;
do {
/* Cache the lock if possible... */
if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0)
return 0;
err = _nfs4_do_setlk(state, F_SETLK, request, 1);
if (err != -NFS4ERR_DELAY)
break;
@ -3483,6 +3476,8 @@ static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request
if (err != 0)
return err;
do {
if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0)
return 0;
err = _nfs4_do_setlk(state, F_SETLK, request, 0);
if (err != -NFS4ERR_DELAY)
break;
@ -3494,29 +3489,42 @@ static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request
static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request)
{
struct nfs4_client *clp = state->owner->so_client;
unsigned char fl_flags = request->fl_flags;
int status;
/* Is this a delegated open? */
if (NFS_I(state->inode)->delegation_state != 0) {
/* Yes: cache locks! */
status = do_vfs_lock(request->fl_file, request);
/* ...but avoid races with delegation recall... */
if (status < 0 || test_bit(NFS_DELEGATED_STATE, &state->flags))
return status;
}
down_read(&clp->cl_sem);
status = nfs4_set_lock_state(state, request);
if (status != 0)
goto out;
request->fl_flags |= FL_ACCESS;
status = do_vfs_lock(request->fl_file, request);
if (status < 0)
goto out;
down_read(&clp->cl_sem);
if (test_bit(NFS_DELEGATED_STATE, &state->flags)) {
struct nfs_inode *nfsi = NFS_I(state->inode);
/* Yes: cache locks! */
down_read(&nfsi->rwsem);
/* ...but avoid races with delegation recall... */
if (test_bit(NFS_DELEGATED_STATE, &state->flags)) {
request->fl_flags = fl_flags & ~FL_SLEEP;
status = do_vfs_lock(request->fl_file, request);
up_read(&nfsi->rwsem);
goto out_unlock;
}
up_read(&nfsi->rwsem);
}
status = _nfs4_do_setlk(state, cmd, request, 0);
if (status != 0)
goto out;
goto out_unlock;
/* Note: we always want to sleep here! */
request->fl_flags |= FL_SLEEP;
request->fl_flags = fl_flags | FL_SLEEP;
if (do_vfs_lock(request->fl_file, request) < 0)
printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __FUNCTION__);
out:
out_unlock:
up_read(&clp->cl_sem);
out:
request->fl_flags = fl_flags;
return status;
}

View File

@ -578,7 +578,7 @@ static int nfs_wait_on_requests(struct inode *inode, unsigned long idx_start, un
return ret;
}
static void nfs_cancel_requests(struct list_head *head)
static void nfs_cancel_dirty_list(struct list_head *head)
{
struct nfs_page *req;
while(!list_empty(head)) {
@ -589,6 +589,19 @@ static void nfs_cancel_requests(struct list_head *head)
}
}
static void nfs_cancel_commit_list(struct list_head *head)
{
struct nfs_page *req;
while(!list_empty(head)) {
req = nfs_list_entry(head->next);
nfs_list_remove_request(req);
nfs_inode_remove_request(req);
nfs_clear_page_writeback(req);
dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
}
}
/*
* nfs_scan_dirty - Scan an inode for dirty requests
* @inode: NFS inode to scan
@ -1381,6 +1394,7 @@ nfs_commit_list(struct inode *inode, struct list_head *head, int how)
nfs_list_remove_request(req);
nfs_mark_request_commit(req);
nfs_clear_page_writeback(req);
dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
}
return -ENOMEM;
}
@ -1499,7 +1513,7 @@ int nfs_sync_inode_wait(struct inode *inode, unsigned long idx_start,
if (pages != 0) {
spin_unlock(&nfsi->req_lock);
if (how & FLUSH_INVALIDATE)
nfs_cancel_requests(&head);
nfs_cancel_dirty_list(&head);
else
ret = nfs_flush_list(inode, &head, pages, how);
spin_lock(&nfsi->req_lock);
@ -1512,7 +1526,7 @@ int nfs_sync_inode_wait(struct inode *inode, unsigned long idx_start,
break;
if (how & FLUSH_INVALIDATE) {
spin_unlock(&nfsi->req_lock);
nfs_cancel_requests(&head);
nfs_cancel_commit_list(&head);
spin_lock(&nfsi->req_lock);
continue;
}

View File

@ -39,12 +39,4 @@
*/
#define NR_IRQS (NR_AIC_IRQS + (4 * 32))
#ifndef __ASSEMBLY__
/*
* Initialize the IRQ controller.
*/
extern void at91rm9200_init_irq(unsigned int priority[]);
#endif
#endif

View File

@ -43,6 +43,7 @@ typedef u64 cputime64_t;
#define cputime64_zero ((cputime64_t)0)
#define cputime64_add(__a, __b) ((__a) + (__b))
#define cputime64_sub(__a, __b) ((__a) - (__b))
#define cputime_to_cputime64(__ct) (__ct)
#ifdef __KERNEL__
@ -74,6 +75,23 @@ static inline cputime_t jiffies_to_cputime(const unsigned long jif)
return ct;
}
static inline cputime64_t jiffies64_to_cputime64(const u64 jif)
{
cputime_t ct;
u64 sec;
/* have to be a little careful about overflow */
ct = jif % HZ;
sec = jif / HZ;
if (ct) {
ct *= tb_ticks_per_sec;
do_div(ct, HZ);
}
if (sec)
ct += (cputime_t) sec * tb_ticks_per_sec;
return ct;
}
static inline u64 cputime64_to_jiffies64(const cputime_t ct)
{
return mulhdu(ct, __cputime_jiffies_factor);

View File

@ -160,6 +160,20 @@ static inline void dma_free_coherent(struct device *dev, size_t size,
BUG();
}
static inline void
dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size,
enum dma_data_direction direction)
{
BUG();
}
static inline void
dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size,
enum dma_data_direction direction)
{
BUG();
}
#endif /* PCI */

View File

@ -716,6 +716,7 @@ extern spinlock_t files_lock;
#define FL_POSIX 1
#define FL_FLOCK 2
#define FL_ACCESS 8 /* not trying to lock, just looking */
#define FL_EXISTS 16 /* when unlocking, test for existence */
#define FL_LEASE 32 /* lease held on this file */
#define FL_CLOSE 64 /* unlock on close */
#define FL_SLEEP 128 /* A blocking lock */

View File

@ -131,6 +131,7 @@ enum {
ATA_DFLAG_CFG_MASK = (1 << 8) - 1,
ATA_DFLAG_PIO = (1 << 8), /* device currently in PIO mode */
ATA_DFLAG_SUSPENDED = (1 << 9), /* device suspended */
ATA_DFLAG_INIT_MASK = (1 << 16) - 1,
ATA_DFLAG_DETACH = (1 << 16),
@ -160,22 +161,28 @@ enum {
ATA_FLAG_HRST_TO_RESUME = (1 << 11), /* hardreset to resume phy */
ATA_FLAG_SKIP_D2H_BSY = (1 << 12), /* can't wait for the first D2H
* Register FIS clearing BSY */
ATA_FLAG_DEBUGMSG = (1 << 13),
ATA_FLAG_FLUSH_PORT_TASK = (1 << 14), /* flush port task */
ATA_FLAG_EH_PENDING = (1 << 15), /* EH pending */
ATA_FLAG_EH_IN_PROGRESS = (1 << 16), /* EH in progress */
ATA_FLAG_FROZEN = (1 << 17), /* port is frozen */
ATA_FLAG_RECOVERED = (1 << 18), /* recovery action performed */
ATA_FLAG_LOADING = (1 << 19), /* boot/loading probe */
ATA_FLAG_UNLOADING = (1 << 20), /* module is unloading */
ATA_FLAG_SCSI_HOTPLUG = (1 << 21), /* SCSI hotplug scheduled */
/* The following flag belongs to ap->pflags but is kept in
* ap->flags because it's referenced in many LLDs and will be
* removed in not-too-distant future.
*/
ATA_FLAG_DISABLED = (1 << 23), /* port is disabled, ignore it */
ATA_FLAG_DISABLED = (1 << 22), /* port is disabled, ignore it */
ATA_FLAG_SUSPENDED = (1 << 23), /* port is suspended (power) */
/* bits 24:31 of ap->flags are reserved for LLD specific flags */
/* bits 24:31 of ap->flags are reserved for LLDD specific flags */
/* struct ata_port pflags */
ATA_PFLAG_EH_PENDING = (1 << 0), /* EH pending */
ATA_PFLAG_EH_IN_PROGRESS = (1 << 1), /* EH in progress */
ATA_PFLAG_FROZEN = (1 << 2), /* port is frozen */
ATA_PFLAG_RECOVERED = (1 << 3), /* recovery action performed */
ATA_PFLAG_LOADING = (1 << 4), /* boot/loading probe */
ATA_PFLAG_UNLOADING = (1 << 5), /* module is unloading */
ATA_PFLAG_SCSI_HOTPLUG = (1 << 6), /* SCSI hotplug scheduled */
ATA_PFLAG_FLUSH_PORT_TASK = (1 << 16), /* flush port task */
ATA_PFLAG_SUSPENDED = (1 << 17), /* port is suspended (power) */
ATA_PFLAG_PM_PENDING = (1 << 18), /* PM operation pending */
/* struct ata_queued_cmd flags */
ATA_QCFLAG_ACTIVE = (1 << 0), /* cmd not yet ack'd to scsi lyer */
@ -248,12 +255,19 @@ enum {
ATA_EH_REVALIDATE = (1 << 0),
ATA_EH_SOFTRESET = (1 << 1),
ATA_EH_HARDRESET = (1 << 2),
ATA_EH_SUSPEND = (1 << 3),
ATA_EH_RESUME = (1 << 4),
ATA_EH_PM_FREEZE = (1 << 5),
ATA_EH_RESET_MASK = ATA_EH_SOFTRESET | ATA_EH_HARDRESET,
ATA_EH_PERDEV_MASK = ATA_EH_REVALIDATE,
ATA_EH_PERDEV_MASK = ATA_EH_REVALIDATE | ATA_EH_SUSPEND |
ATA_EH_RESUME | ATA_EH_PM_FREEZE,
/* ata_eh_info->flags */
ATA_EHI_HOTPLUGGED = (1 << 0), /* could have been hotplugged */
ATA_EHI_RESUME_LINK = (1 << 1), /* need to resume link */
ATA_EHI_NO_AUTOPSY = (1 << 2), /* no autopsy */
ATA_EHI_QUIET = (1 << 3), /* be quiet */
ATA_EHI_DID_RESET = (1 << 16), /* already reset this port */
@ -486,6 +500,7 @@ struct ata_port {
const struct ata_port_operations *ops;
spinlock_t *lock;
unsigned long flags; /* ATA_FLAG_xxx */
unsigned int pflags; /* ATA_PFLAG_xxx */
unsigned int id; /* unique id req'd by scsi midlyr */
unsigned int port_no; /* unique port #; from zero */
unsigned int hard_port_no; /* hardware port #; from zero */
@ -535,6 +550,9 @@ struct ata_port {
struct list_head eh_done_q;
wait_queue_head_t eh_wait_q;
pm_message_t pm_mesg;
int *pm_result;
void *private_data;
u8 sector_buf[ATA_SECT_SIZE]; /* owned by EH */
@ -589,6 +607,9 @@ struct ata_port_operations {
void (*scr_write) (struct ata_port *ap, unsigned int sc_reg,
u32 val);
int (*port_suspend) (struct ata_port *ap, pm_message_t mesg);
int (*port_resume) (struct ata_port *ap);
int (*port_start) (struct ata_port *ap);
void (*port_stop) (struct ata_port *ap);
@ -622,9 +643,18 @@ struct ata_timing {
#define FIT(v,vmin,vmax) max_t(short,min_t(short,v,vmax),vmin)
extern const unsigned long sata_deb_timing_boot[];
extern const unsigned long sata_deb_timing_eh[];
extern const unsigned long sata_deb_timing_before_fsrst[];
extern const unsigned long sata_deb_timing_normal[];
extern const unsigned long sata_deb_timing_hotplug[];
extern const unsigned long sata_deb_timing_long[];
static inline const unsigned long *
sata_ehc_deb_timing(struct ata_eh_context *ehc)
{
if (ehc->i.flags & ATA_EHI_HOTPLUGGED)
return sata_deb_timing_hotplug;
else
return sata_deb_timing_normal;
}
extern void ata_port_probe(struct ata_port *);
extern void __sata_phy_reset(struct ata_port *ap);
@ -644,6 +674,8 @@ extern void ata_std_ports(struct ata_ioports *ioaddr);
extern int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
unsigned int n_ports);
extern void ata_pci_remove_one (struct pci_dev *pdev);
extern void ata_pci_device_do_suspend(struct pci_dev *pdev, pm_message_t state);
extern void ata_pci_device_do_resume(struct pci_dev *pdev);
extern int ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t state);
extern int ata_pci_device_resume(struct pci_dev *pdev);
extern int ata_pci_clear_simplex(struct pci_dev *pdev);
@ -664,8 +696,9 @@ extern int ata_port_online(struct ata_port *ap);
extern int ata_port_offline(struct ata_port *ap);
extern int ata_scsi_device_resume(struct scsi_device *);
extern int ata_scsi_device_suspend(struct scsi_device *, pm_message_t state);
extern int ata_device_resume(struct ata_device *);
extern int ata_device_suspend(struct ata_device *, pm_message_t state);
extern int ata_host_set_suspend(struct ata_host_set *host_set,
pm_message_t mesg);
extern void ata_host_set_resume(struct ata_host_set *host_set);
extern int ata_ratelimit(void);
extern unsigned int ata_busy_sleep(struct ata_port *ap,
unsigned long timeout_pat,
@ -825,19 +858,24 @@ extern void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset,
(ehi)->desc_len = 0; \
} while (0)
static inline void ata_ehi_hotplugged(struct ata_eh_info *ehi)
static inline void __ata_ehi_hotplugged(struct ata_eh_info *ehi)
{
if (ehi->flags & ATA_EHI_HOTPLUGGED)
return;
ehi->flags |= ATA_EHI_HOTPLUGGED;
ehi->flags |= ATA_EHI_HOTPLUGGED | ATA_EHI_RESUME_LINK;
ehi->hotplug_timestamp = jiffies;
ehi->err_mask |= AC_ERR_ATA_BUS;
ehi->action |= ATA_EH_SOFTRESET;
ehi->probe_mask |= (1 << ATA_MAX_DEVICES) - 1;
}
static inline void ata_ehi_hotplugged(struct ata_eh_info *ehi)
{
__ata_ehi_hotplugged(ehi);
ehi->err_mask |= AC_ERR_ATA_BUS;
}
/*
* qc helpers
*/
@ -921,6 +959,11 @@ static inline unsigned int ata_dev_absent(const struct ata_device *dev)
return ata_class_absent(dev->class);
}
static inline unsigned int ata_dev_ready(const struct ata_device *dev)
{
return ata_dev_enabled(dev) && !(dev->flags & ATA_DFLAG_SUSPENDED);
}
/*
* port helpers
*/

View File

@ -729,6 +729,7 @@ struct nfs_read_data {
struct list_head pages; /* Coalesced read requests */
struct nfs_page *req; /* multi ops per nfs_page */
struct page **pagevec;
unsigned int npages; /* active pages in pagevec */
struct nfs_readargs args;
struct nfs_readres res;
#ifdef CONFIG_NFS_V4
@ -747,6 +748,7 @@ struct nfs_write_data {
struct list_head pages; /* Coalesced requests we wish to flush */
struct nfs_page *req; /* multi ops per nfs_page */
struct page **pagevec;
unsigned int npages; /* active pages in pagevec */
struct nfs_writeargs args; /* argument struct */
struct nfs_writeres res; /* result struct */
#ifdef CONFIG_NFS_V4

View File

@ -2019,6 +2019,13 @@
#define PCI_VENDOR_ID_TDI 0x192E
#define PCI_DEVICE_ID_TDI_EHCI 0x0101
#define PCI_VENDOR_ID_JMICRON 0x197B
#define PCI_DEVICE_ID_JMICRON_JMB360 0x2360
#define PCI_DEVICE_ID_JMICRON_JMB361 0x2361
#define PCI_DEVICE_ID_JMICRON_JMB363 0x2363
#define PCI_DEVICE_ID_JMICRON_JMB365 0x2365
#define PCI_DEVICE_ID_JMICRON_JMB366 0x2366
#define PCI_DEVICE_ID_JMICRON_JMB368 0x2368
#define PCI_VENDOR_ID_TEKRAM 0x1de1
#define PCI_DEVICE_ID_TEKRAM_DC290 0xdc29

View File

@ -250,15 +250,17 @@ tcf_action_dump(struct sk_buff *skb, struct tc_action *act, int bind, int ref)
RTA_PUT(skb, a->order, 0, NULL);
err = tcf_action_dump_1(skb, a, bind, ref);
if (err < 0)
goto rtattr_failure;
goto errout;
r->rta_len = skb->tail - (u8*)r;
}
return 0;
rtattr_failure:
err = -EINVAL;
errout:
skb_trim(skb, b - skb->data);
return -err;
return err;
}
struct tc_action *tcf_action_init_1(struct rtattr *rta, struct rtattr *est,
@ -305,6 +307,7 @@ struct tc_action *tcf_action_init_1(struct rtattr *rta, struct rtattr *est,
goto err_mod;
}
#endif
*err = -ENOENT;
goto err_out;
}
@ -776,7 +779,7 @@ static int tc_ctl_action(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
return ret;
}
static char *
static struct rtattr *
find_dump_kind(struct nlmsghdr *n)
{
struct rtattr *tb1, *tb2[TCA_ACT_MAX+1];
@ -804,7 +807,7 @@ find_dump_kind(struct nlmsghdr *n)
return NULL;
kind = tb2[TCA_ACT_KIND-1];
return (char *) RTA_DATA(kind);
return kind;
}
static int
@ -817,16 +820,15 @@ tc_dump_action(struct sk_buff *skb, struct netlink_callback *cb)
struct tc_action a;
int ret = 0;
struct tcamsg *t = (struct tcamsg *) NLMSG_DATA(cb->nlh);
char *kind = find_dump_kind(cb->nlh);
struct rtattr *kind = find_dump_kind(cb->nlh);
if (kind == NULL) {
printk("tc_dump_action: action bad kind\n");
return 0;
}
a_o = tc_lookup_action_n(kind);
a_o = tc_lookup_action(kind);
if (a_o == NULL) {
printk("failed to find %s\n", kind);
return 0;
}
@ -834,7 +836,7 @@ tc_dump_action(struct sk_buff *skb, struct netlink_callback *cb)
a.ops = a_o;
if (a_o->walk == NULL) {
printk("tc_dump_action: %s !capable of dumping table\n", kind);
printk("tc_dump_action: %s !capable of dumping table\n", a_o->kind);
goto rtattr_failure;
}

View File

@ -191,7 +191,6 @@ _shift_data_right_pages(struct page **pages, size_t pgto_base,
do {
/* Are any pointers crossing a page boundary? */
if (pgto_base == 0) {
flush_dcache_page(*pgto);
pgto_base = PAGE_CACHE_SIZE;
pgto--;
}
@ -211,11 +210,11 @@ _shift_data_right_pages(struct page **pages, size_t pgto_base,
vto = kmap_atomic(*pgto, KM_USER0);
vfrom = kmap_atomic(*pgfrom, KM_USER1);
memmove(vto + pgto_base, vfrom + pgfrom_base, copy);
flush_dcache_page(*pgto);
kunmap_atomic(vfrom, KM_USER1);
kunmap_atomic(vto, KM_USER0);
} while ((len -= copy) != 0);
flush_dcache_page(*pgto);
}
/*