diff --git a/[refs] b/[refs] index 753fea0728f2..4fc91a5f6201 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 0169e284f6b6b263cc7c2ed25986b96cd6fda610 +refs/heads/master: 930fc45a49ddebe7555cc5c837d82b9c27e65ff4 diff --git a/trunk/drivers/scsi/ahci.c b/trunk/drivers/scsi/ahci.c index 03829aedfd39..fe8187d6f58b 100644 --- a/trunk/drivers/scsi/ahci.c +++ b/trunk/drivers/scsi/ahci.c @@ -192,6 +192,7 @@ static void ahci_port_stop(struct ata_port *ap); static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf); static void ahci_qc_prep(struct ata_queued_cmd *qc); static u8 ahci_check_status(struct ata_port *ap); +static u8 ahci_check_err(struct ata_port *ap); static inline int ahci_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc); static void ahci_remove_one (struct pci_dev *pdev); @@ -220,6 +221,7 @@ static const struct ata_port_operations ahci_ops = { .check_status = ahci_check_status, .check_altstatus = ahci_check_status, + .check_err = ahci_check_err, .dev_select = ata_noop_dev_select, .tf_read = ahci_tf_read, @@ -456,6 +458,13 @@ static u8 ahci_check_status(struct ata_port *ap) return readl(mmio + PORT_TFDATA) & 0xFF; } +static u8 ahci_check_err(struct ata_port *ap) +{ + void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr; + + return (readl(mmio + PORT_TFDATA) >> 8) & 0xFF; +} + static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf) { struct ahci_port_priv *pp = ap->private_data; diff --git a/trunk/drivers/scsi/libata-core.c b/trunk/drivers/scsi/libata-core.c index d2f71a2331bb..b1b1c6f01419 100644 --- a/trunk/drivers/scsi/libata-core.c +++ b/trunk/drivers/scsi/libata-core.c @@ -371,7 +371,7 @@ static void ata_tf_read_pio(struct ata_port *ap, struct ata_taskfile *tf) struct ata_ioports *ioaddr = &ap->ioaddr; tf->command = ata_check_status(ap); - tf->feature = inb(ioaddr->error_addr); + tf->feature = ata_chk_err(ap); tf->nsect = inb(ioaddr->nsect_addr); tf->lbal = inb(ioaddr->lbal_addr); tf->lbam = inb(ioaddr->lbam_addr); @@ -405,7 +405,7 @@ static void ata_tf_read_mmio(struct ata_port *ap, struct ata_taskfile *tf) struct ata_ioports *ioaddr = &ap->ioaddr; tf->command = ata_check_status(ap); - tf->feature = readb((void __iomem *)ioaddr->error_addr); + tf->feature = ata_chk_err(ap); tf->nsect = readb((void __iomem *)ioaddr->nsect_addr); tf->lbal = readb((void __iomem *)ioaddr->lbal_addr); tf->lbam = readb((void __iomem *)ioaddr->lbam_addr); @@ -525,6 +525,30 @@ u8 ata_altstatus(struct ata_port *ap) } +/** + * ata_chk_err - Read device error reg + * @ap: port where the device is + * + * Reads ATA taskfile error register for + * currently-selected device and return its value. + * + * Note: may NOT be used as the check_err() entry in + * ata_port_operations. + * + * LOCKING: + * Inherited from caller. + */ +u8 ata_chk_err(struct ata_port *ap) +{ + if (ap->ops->check_err) + return ap->ops->check_err(ap); + + if (ap->flags & ATA_FLAG_MMIO) { + return readb((void __iomem *) ap->ioaddr.error_addr); + } + return inb(ap->ioaddr.error_addr); +} + /** * ata_tf_to_fis - Convert ATA taskfile to SATA FIS structure * @tf: Taskfile to convert @@ -877,8 +901,8 @@ static u8 ata_dev_try_classify(struct ata_port *ap, unsigned int device) memset(&tf, 0, sizeof(tf)); + err = ata_chk_err(ap); ap->ops->tf_read(ap, &tf); - err = tf.feature; dev->class = ATA_DEV_NONE; @@ -1115,6 +1139,7 @@ static void ata_dev_identify(struct ata_port *ap, unsigned int device) unsigned int major_version; u16 tmp; unsigned long xfer_modes; + u8 status; unsigned int using_edd; DECLARE_COMPLETION(wait); struct ata_queued_cmd *qc; @@ -1168,11 +1193,8 @@ static void ata_dev_identify(struct ata_port *ap, unsigned int device) else wait_for_completion(&wait); - spin_lock_irqsave(&ap->host_set->lock, flags); - ap->ops->tf_read(ap, &qc->tf); - spin_unlock_irqrestore(&ap->host_set->lock, flags); - - if (qc->tf.command & ATA_ERR) { + status = ata_chk_status(ap); + if (status & ATA_ERR) { /* * arg! EDD works for all test cases, but seems to return * the ATA signature for some ATAPI devices. Until the @@ -1185,7 +1207,7 @@ static void ata_dev_identify(struct ata_port *ap, unsigned int device) * to have this problem. */ if ((using_edd) && (qc->tf.command == ATA_CMD_ID_ATA)) { - u8 err = qc->tf.feature; + u8 err = ata_chk_err(ap); if (err & ATA_ABORTED) { dev->class = ATA_DEV_ATAPI; qc->cursg = 0; @@ -4851,6 +4873,7 @@ EXPORT_SYMBOL_GPL(ata_tf_to_fis); EXPORT_SYMBOL_GPL(ata_tf_from_fis); EXPORT_SYMBOL_GPL(ata_check_status); EXPORT_SYMBOL_GPL(ata_altstatus); +EXPORT_SYMBOL_GPL(ata_chk_err); EXPORT_SYMBOL_GPL(ata_exec_command); EXPORT_SYMBOL_GPL(ata_port_start); EXPORT_SYMBOL_GPL(ata_port_stop); diff --git a/trunk/drivers/scsi/sata_mv.c b/trunk/drivers/scsi/sata_mv.c index dcef5fe8600b..422e0b6f603a 100644 --- a/trunk/drivers/scsi/sata_mv.c +++ b/trunk/drivers/scsi/sata_mv.c @@ -258,6 +258,7 @@ struct mv_host_priv { static void mv_irq_clear(struct ata_port *ap); static u32 mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in); static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val); +static u8 mv_check_err(struct ata_port *ap); static void mv_phy_reset(struct ata_port *ap); static void mv_host_stop(struct ata_host_set *host_set); static int mv_port_start(struct ata_port *ap); @@ -295,6 +296,7 @@ static const struct ata_port_operations mv_ops = { .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, + .check_err = mv_check_err, .exec_command = ata_exec_command, .dev_select = ata_std_dev_select, @@ -1182,6 +1184,22 @@ static irqreturn_t mv_interrupt(int irq, void *dev_instance, return IRQ_RETVAL(handled); } +/** + * mv_check_err - Return the error shadow register to caller. + * @ap: ATA channel to manipulate + * + * Marvell requires DMA to be stopped before accessing shadow + * registers. So we do that, then return the needed register. + * + * LOCKING: + * Inherited from caller. FIXME: protect mv_stop_dma with lock? + */ +static u8 mv_check_err(struct ata_port *ap) +{ + mv_stop_dma(ap); /* can't read shadow regs if DMA on */ + return readb((void __iomem *) ap->ioaddr.error_addr); +} + /** * mv_phy_reset - Perform eDMA reset followed by COMRESET * @ap: ATA channel to manipulate diff --git a/trunk/drivers/scsi/sata_sil24.c b/trunk/drivers/scsi/sata_sil24.c index e18a1e2bb65e..51855d3bac64 100644 --- a/trunk/drivers/scsi/sata_sil24.c +++ b/trunk/drivers/scsi/sata_sil24.c @@ -225,6 +225,7 @@ struct sil24_host_priv { }; static u8 sil24_check_status(struct ata_port *ap); +static u8 sil24_check_err(struct ata_port *ap); static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg); static void sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val); static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf); @@ -279,6 +280,7 @@ static const struct ata_port_operations sil24_ops = { .check_status = sil24_check_status, .check_altstatus = sil24_check_status, + .check_err = sil24_check_err, .dev_select = ata_noop_dev_select, .tf_read = sil24_tf_read, @@ -361,6 +363,12 @@ static u8 sil24_check_status(struct ata_port *ap) return pp->tf.command; } +static u8 sil24_check_err(struct ata_port *ap) +{ + struct sil24_port_priv *pp = ap->private_data; + return pp->tf.feature; +} + static int sil24_scr_map[] = { [SCR_CONTROL] = 0, [SCR_STATUS] = 1, diff --git a/trunk/include/linux/libata.h b/trunk/include/linux/libata.h index a4cce9936a80..00a8a5738858 100644 --- a/trunk/include/linux/libata.h +++ b/trunk/include/linux/libata.h @@ -347,6 +347,7 @@ struct ata_port_operations { void (*exec_command)(struct ata_port *ap, const struct ata_taskfile *tf); u8 (*check_status)(struct ata_port *ap); u8 (*check_altstatus)(struct ata_port *ap); + u8 (*check_err)(struct ata_port *ap); void (*dev_select)(struct ata_port *ap, unsigned int device); void (*phy_reset) (struct ata_port *ap); @@ -433,6 +434,7 @@ extern void ata_noop_dev_select (struct ata_port *ap, unsigned int device); extern void ata_std_dev_select (struct ata_port *ap, unsigned int device); extern u8 ata_check_status(struct ata_port *ap); extern u8 ata_altstatus(struct ata_port *ap); +extern u8 ata_chk_err(struct ata_port *ap); extern void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf); extern int ata_port_start (struct ata_port *ap); extern void ata_port_stop (struct ata_port *ap); diff --git a/trunk/include/linux/vmalloc.h b/trunk/include/linux/vmalloc.h index 3701a0673d2c..1d5577b2b752 100644 --- a/trunk/include/linux/vmalloc.h +++ b/trunk/include/linux/vmalloc.h @@ -32,10 +32,14 @@ struct vm_struct { * Highlevel APIs for driver use */ extern void *vmalloc(unsigned long size); +extern void *vmalloc_node(unsigned long size, int node); extern void *vmalloc_exec(unsigned long size); extern void *vmalloc_32(unsigned long size); extern void *__vmalloc(unsigned long size, gfp_t gfp_mask, pgprot_t prot); -extern void *__vmalloc_area(struct vm_struct *area, gfp_t gfp_mask, pgprot_t prot); +extern void *__vmalloc_area(struct vm_struct *area, gfp_t gfp_mask, + pgprot_t prot); +extern void *__vmalloc_node(unsigned long size, gfp_t gfp_mask, + pgprot_t prot, int node); extern void vfree(void *addr); extern void *vmap(struct page **pages, unsigned int count, @@ -48,6 +52,8 @@ extern void vunmap(void *addr); extern struct vm_struct *get_vm_area(unsigned long size, unsigned long flags); extern struct vm_struct *__get_vm_area(unsigned long size, unsigned long flags, unsigned long start, unsigned long end); +extern struct vm_struct *get_vm_area_node(unsigned long size, + unsigned long flags, int node); extern struct vm_struct *remove_vm_area(void *addr); extern struct vm_struct *__remove_vm_area(void *addr); extern int map_vm_area(struct vm_struct *area, pgprot_t prot, diff --git a/trunk/mm/vmalloc.c b/trunk/mm/vmalloc.c index 1150229b6366..5e9120598799 100644 --- a/trunk/mm/vmalloc.c +++ b/trunk/mm/vmalloc.c @@ -5,6 +5,7 @@ * Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999 * SMP-safe vmalloc/vfree/ioremap, Tigran Aivazian , May 2000 * Major rework to support vmap/vunmap, Christoph Hellwig, SGI, August 2002 + * Numa awareness, Christoph Lameter, SGI, June 2005 */ #include @@ -158,8 +159,8 @@ int map_vm_area(struct vm_struct *area, pgprot_t prot, struct page ***pages) return err; } -struct vm_struct *__get_vm_area(unsigned long size, unsigned long flags, - unsigned long start, unsigned long end) +struct vm_struct *__get_vm_area_node(unsigned long size, unsigned long flags, + unsigned long start, unsigned long end, int node) { struct vm_struct **p, *tmp, *area; unsigned long align = 1; @@ -178,7 +179,7 @@ struct vm_struct *__get_vm_area(unsigned long size, unsigned long flags, addr = ALIGN(start, align); size = PAGE_ALIGN(size); - area = kmalloc(sizeof(*area), GFP_KERNEL); + area = kmalloc_node(sizeof(*area), GFP_KERNEL, node); if (unlikely(!area)) return NULL; @@ -231,6 +232,12 @@ struct vm_struct *__get_vm_area(unsigned long size, unsigned long flags, return NULL; } +struct vm_struct *__get_vm_area(unsigned long size, unsigned long flags, + unsigned long start, unsigned long end) +{ + return __get_vm_area_node(size, flags, start, end, -1); +} + /** * get_vm_area - reserve a contingous kernel virtual area * @@ -246,6 +253,11 @@ struct vm_struct *get_vm_area(unsigned long size, unsigned long flags) return __get_vm_area(size, flags, VMALLOC_START, VMALLOC_END); } +struct vm_struct *get_vm_area_node(unsigned long size, unsigned long flags, int node) +{ + return __get_vm_area_node(size, flags, VMALLOC_START, VMALLOC_END, node); +} + /* Caller must hold vmlist_lock */ struct vm_struct *__remove_vm_area(void *addr) { @@ -342,7 +354,6 @@ void vfree(void *addr) BUG_ON(in_interrupt()); __vunmap(addr, 1); } - EXPORT_SYMBOL(vfree); /** @@ -360,7 +371,6 @@ void vunmap(void *addr) BUG_ON(in_interrupt()); __vunmap(addr, 0); } - EXPORT_SYMBOL(vunmap); /** @@ -392,10 +402,10 @@ void *vmap(struct page **pages, unsigned int count, return area->addr; } - EXPORT_SYMBOL(vmap); -void *__vmalloc_area(struct vm_struct *area, gfp_t gfp_mask, pgprot_t prot) +void *__vmalloc_area_node(struct vm_struct *area, gfp_t gfp_mask, + pgprot_t prot, int node) { struct page **pages; unsigned int nr_pages, array_size, i; @@ -406,9 +416,9 @@ void *__vmalloc_area(struct vm_struct *area, gfp_t gfp_mask, pgprot_t prot) area->nr_pages = nr_pages; /* Please note that the recursion is strictly bounded. */ if (array_size > PAGE_SIZE) - pages = __vmalloc(array_size, gfp_mask, PAGE_KERNEL); + pages = __vmalloc_node(array_size, gfp_mask, PAGE_KERNEL, node); else - pages = kmalloc(array_size, (gfp_mask & ~__GFP_HIGHMEM)); + pages = kmalloc_node(array_size, (gfp_mask & ~__GFP_HIGHMEM), node); area->pages = pages; if (!area->pages) { remove_vm_area(area->addr); @@ -418,7 +428,10 @@ void *__vmalloc_area(struct vm_struct *area, gfp_t gfp_mask, pgprot_t prot) memset(area->pages, 0, array_size); for (i = 0; i < area->nr_pages; i++) { - area->pages[i] = alloc_page(gfp_mask); + if (node < 0) + area->pages[i] = alloc_page(gfp_mask); + else + area->pages[i] = alloc_pages_node(node, gfp_mask, 0); if (unlikely(!area->pages[i])) { /* Successfully allocated i pages, free them in __vunmap() */ area->nr_pages = i; @@ -435,18 +448,25 @@ void *__vmalloc_area(struct vm_struct *area, gfp_t gfp_mask, pgprot_t prot) return NULL; } +void *__vmalloc_area(struct vm_struct *area, gfp_t gfp_mask, pgprot_t prot) +{ + return __vmalloc_area_node(area, gfp_mask, prot, -1); +} + /** - * __vmalloc - allocate virtually contiguous memory + * __vmalloc_node - allocate virtually contiguous memory * * @size: allocation size * @gfp_mask: flags for the page level allocator * @prot: protection mask for the allocated pages + * @node node to use for allocation or -1 * * Allocate enough pages to cover @size from the page level * allocator with @gfp_mask flags. Map them into contiguous * kernel virtual space, using a pagetable protection of @prot. */ -void *__vmalloc(unsigned long size, gfp_t gfp_mask, pgprot_t prot) +void *__vmalloc_node(unsigned long size, gfp_t gfp_mask, pgprot_t prot, + int node) { struct vm_struct *area; @@ -454,13 +474,18 @@ void *__vmalloc(unsigned long size, gfp_t gfp_mask, pgprot_t prot) if (!size || (size >> PAGE_SHIFT) > num_physpages) return NULL; - area = get_vm_area(size, VM_ALLOC); + area = get_vm_area_node(size, VM_ALLOC, node); if (!area) return NULL; - return __vmalloc_area(area, gfp_mask, prot); + return __vmalloc_area_node(area, gfp_mask, prot, node); } +EXPORT_SYMBOL(__vmalloc_node); +void *__vmalloc(unsigned long size, gfp_t gfp_mask, pgprot_t prot) +{ + return __vmalloc_node(size, gfp_mask, prot, -1); +} EXPORT_SYMBOL(__vmalloc); /** @@ -478,9 +503,26 @@ void *vmalloc(unsigned long size) { return __vmalloc(size, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL); } - EXPORT_SYMBOL(vmalloc); +/** + * vmalloc_node - allocate memory on a specific node + * + * @size: allocation size + * @node; numa node + * + * Allocate enough pages to cover @size from the page level + * allocator and map them into contiguous kernel virtual space. + * + * For tight cotrol over page level allocator and protection flags + * use __vmalloc() instead. + */ +void *vmalloc_node(unsigned long size, int node) +{ + return __vmalloc_node(size, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL, node); +} +EXPORT_SYMBOL(vmalloc_node); + #ifndef PAGE_KERNEL_EXEC # define PAGE_KERNEL_EXEC PAGE_KERNEL #endif @@ -515,7 +557,6 @@ void *vmalloc_32(unsigned long size) { return __vmalloc(size, GFP_KERNEL, PAGE_KERNEL); } - EXPORT_SYMBOL(vmalloc_32); long vread(char *buf, char *addr, unsigned long count)