diff options
Diffstat (limited to 'drivers')
401 files changed, 6552 insertions, 3760 deletions
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 8a5bf3b356f..55b5b90c2a4 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -395,7 +395,7 @@ struct pci_dev *acpi_get_pci_dev(acpi_handle handle) fn = adr & 0xffff; pdev = pci_get_slot(pbus, PCI_DEVFN(dev, fn)); - if (hnd == handle) + if (!pdev || hnd == handle) break; pbus = pdev->subordinate; diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index c7a527c08a0..65a0655e7fc 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -226,8 +226,18 @@ static inline void addQ(struct hlist_head *list, CommandList_struct *c) static inline void removeQ(CommandList_struct *c) { - if (WARN_ON(hlist_unhashed(&c->list))) + /* + * After kexec/dump some commands might still + * be in flight, which the firmware will try + * to complete. Resetting the firmware doesn't work + * with old fw revisions, so we have to mark + * them off as 'stale' to prevent the driver from + * falling over. + */ + if (WARN_ON(hlist_unhashed(&c->list))) { + c->cmd_type = CMD_MSG_STALE; return; + } hlist_del_init(&c->list); } @@ -4246,7 +4256,8 @@ static void fail_all_cmds(unsigned long ctlr) while (!hlist_empty(&h->cmpQ)) { c = hlist_entry(h->cmpQ.first, CommandList_struct, list); removeQ(c); - c->err_info->CommandStatus = CMD_HARDWARE_ERR; + if (c->cmd_type != CMD_MSG_STALE) + c->err_info->CommandStatus = CMD_HARDWARE_ERR; if (c->cmd_type == CMD_RWREQ) { complete_command(h, c, 0); } else if (c->cmd_type == CMD_IOCTL_PEND) diff --git a/drivers/block/cciss_cmd.h b/drivers/block/cciss_cmd.h index cd665b00c7c..dbaed1ea0da 100644 --- a/drivers/block/cciss_cmd.h +++ b/drivers/block/cciss_cmd.h @@ -274,6 +274,7 @@ typedef struct _ErrorInfo_struct { #define CMD_SCSI 0x03 #define CMD_MSG_DONE 0x04 #define CMD_MSG_TIMEOUT 0x05 +#define CMD_MSG_STALE 0xff /* This structure needs to be divisible by 8 for new * indexing method. diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 862b40c9018..91b75301378 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -3327,7 +3327,10 @@ static inline int set_geometry(unsigned int cmd, struct floppy_struct *g, if (!capable(CAP_SYS_ADMIN)) return -EPERM; mutex_lock(&open_lock); - LOCK_FDC(drive, 1); + if (lock_fdc(drive, 1)) { + mutex_unlock(&open_lock); + return -EINTR; + } floppy_type[type] = *g; floppy_type[type].name = "user format"; for (cnt = type << 2; cnt < (type << 2) + 4; cnt++) diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 0bd01f49cfd..6a06913b01d 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -1029,10 +1029,6 @@ config CS5535_GPIO If compiled as a module, it will be called cs5535_gpio. -config GPIO_VR41XX - tristate "NEC VR4100 series General-purpose I/O Unit support" - depends on CPU_VR41XX - config RAW_DRIVER tristate "RAW driver (/dev/raw/rawN)" depends on BLOCK diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 189efcff08c..66f779ad4f4 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -95,7 +95,6 @@ obj-$(CONFIG_SCx200_GPIO) += scx200_gpio.o obj-$(CONFIG_PC8736x_GPIO) += pc8736x_gpio.o obj-$(CONFIG_NSC_GPIO) += nsc_gpio.o obj-$(CONFIG_CS5535_GPIO) += cs5535_gpio.o -obj-$(CONFIG_GPIO_VR41XX) += vr41xx_giu.o obj-$(CONFIG_GPIO_TB0219) += tb0219.o obj-$(CONFIG_TELCLOCK) += tlclk.o diff --git a/drivers/char/bsr.c b/drivers/char/bsr.c index 140ea10ecb8..c02db01f736 100644 --- a/drivers/char/bsr.c +++ b/drivers/char/bsr.c @@ -27,6 +27,7 @@ #include <linux/cdev.h> #include <linux/list.h> #include <linux/mm.h> +#include <asm/pgtable.h> #include <asm/io.h> /* @@ -75,12 +76,13 @@ static struct class *bsr_class; static int bsr_major; enum { - BSR_8 = 0, - BSR_16 = 1, - BSR_64 = 2, - BSR_128 = 3, - BSR_UNKNOWN = 4, - BSR_MAX = 5, + BSR_8 = 0, + BSR_16 = 1, + BSR_64 = 2, + BSR_128 = 3, + BSR_4096 = 4, + BSR_UNKNOWN = 5, + BSR_MAX = 6, }; static unsigned bsr_types[BSR_MAX]; @@ -117,15 +119,22 @@ static int bsr_mmap(struct file *filp, struct vm_area_struct *vma) { unsigned long size = vma->vm_end - vma->vm_start; struct bsr_dev *dev = filp->private_data; + int ret; - if (size > dev->bsr_len || (size & (PAGE_SIZE-1))) - return -EINVAL; - - vma->vm_flags |= (VM_IO | VM_DONTEXPAND); vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); - if (io_remap_pfn_range(vma, vma->vm_start, dev->bsr_addr >> PAGE_SHIFT, - size, vma->vm_page_prot)) + /* check for the case of a small BSR device and map one 4k page for it*/ + if (dev->bsr_len < PAGE_SIZE && size == PAGE_SIZE) + ret = remap_4k_pfn(vma, vma->vm_start, dev->bsr_addr >> 12, + vma->vm_page_prot); + else if (size <= dev->bsr_len) + ret = io_remap_pfn_range(vma, vma->vm_start, + dev->bsr_addr >> PAGE_SHIFT, + size, vma->vm_page_prot); + else + return -EINVAL; + + if (ret) return -EAGAIN; return 0; @@ -205,6 +214,11 @@ static int bsr_add_node(struct device_node *bn) cur->bsr_stride = bsr_stride[i]; cur->bsr_dev = MKDEV(bsr_major, i + total_bsr_devs); + /* if we have a bsr_len of > 4k and less then PAGE_SIZE (64k pages) */ + /* we can only map 4k of it, so only advertise the 4k in sysfs */ + if (cur->bsr_len > 4096 && cur->bsr_len < PAGE_SIZE) + cur->bsr_len = 4096; + switch(cur->bsr_bytes) { case 8: cur->bsr_type = BSR_8; @@ -218,9 +232,11 @@ static int bsr_add_node(struct device_node *bn) case 128: cur->bsr_type = BSR_128; break; + case 4096: + cur->bsr_type = BSR_4096; + break; default: cur->bsr_type = BSR_UNKNOWN; - printk(KERN_INFO "unknown BSR size %d\n",cur->bsr_bytes); } cur->bsr_num = bsr_types[cur->bsr_type]; diff --git a/drivers/char/tb0219.c b/drivers/char/tb0219.c index 6062b62800f..b3ec9b10e29 100644 --- a/drivers/char/tb0219.c +++ b/drivers/char/tb0219.c @@ -1,7 +1,7 @@ /* * Driver for TANBAC TB0219 base board. * - * Copyright (C) 2005 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp> + * Copyright (C) 2005 Yoichi Yuasa <yuasa@linux-mips.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,7 +28,7 @@ #include <asm/vr41xx/giu.h> #include <asm/vr41xx/tb0219.h> -MODULE_AUTHOR("Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>"); +MODULE_AUTHOR("Yoichi Yuasa <yuasa@linux-mips.org>"); MODULE_DESCRIPTION("TANBAC TB0219 base board driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/char/tty_ldisc.c b/drivers/char/tty_ldisc.c index a19e935847b..913aa8d3f1c 100644 --- a/drivers/char/tty_ldisc.c +++ b/drivers/char/tty_ldisc.c @@ -867,15 +867,22 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty) tty_ldisc_wait_idle(tty); /* - * Shutdown the current line discipline, and reset it to N_TTY. - * - * FIXME: this MUST get fixed for the new reflocking + * Now kill off the ldisc */ + tty_ldisc_close(tty, tty->ldisc); + tty_ldisc_put(tty->ldisc); + /* Force an oops if we mess this up */ + tty->ldisc = NULL; + + /* Ensure the next open requests the N_TTY ldisc */ + tty_set_termios_ldisc(tty, N_TTY); - tty_ldisc_reinit(tty); /* This will need doing differently if we need to lock */ if (o_tty) tty_ldisc_release(o_tty, NULL); + + /* And the memory resources remaining (buffers, termios) will be + disposed of when the kref hits zero */ } /** diff --git a/drivers/char/vr41xx_giu.c b/drivers/char/vr41xx_giu.c index 54c837288d1..e69de29bb2d 100644 --- a/drivers/char/vr41xx_giu.c +++ b/drivers/char/vr41xx_giu.c @@ -1,680 +0,0 @@ -/* - * Driver for NEC VR4100 series General-purpose I/O Unit. - * - * Copyright (C) 2002 MontaVista Software Inc. - * Author: Yoichi Yuasa <yyuasa@mvista.com or source@mvista.com> - * Copyright (C) 2003-2007 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include <linux/errno.h> -#include <linux/fs.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/irq.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/smp_lock.h> -#include <linux/spinlock.h> -#include <linux/types.h> - -#include <asm/io.h> -#include <asm/vr41xx/giu.h> -#include <asm/vr41xx/irq.h> -#include <asm/vr41xx/vr41xx.h> - -MODULE_AUTHOR("Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>"); -MODULE_DESCRIPTION("NEC VR4100 series General-purpose I/O Unit driver"); -MODULE_LICENSE("GPL"); - -static int major; /* default is dynamic major device number */ -module_param(major, int, 0); -MODULE_PARM_DESC(major, "Major device number"); - -#define GIUIOSELL 0x00 -#define GIUIOSELH 0x02 -#define GIUPIODL 0x04 -#define GIUPIODH 0x06 -#define GIUINTSTATL 0x08 -#define GIUINTSTATH 0x0a -#define GIUINTENL 0x0c -#define GIUINTENH 0x0e -#define GIUINTTYPL 0x10 -#define GIUINTTYPH 0x12 -#define GIUINTALSELL 0x14 -#define GIUINTALSELH 0x16 -#define GIUINTHTSELL 0x18 -#define GIUINTHTSELH 0x1a -#define GIUPODATL 0x1c -#define GIUPODATEN 0x1c -#define GIUPODATH 0x1e - #define PIOEN0 0x0100 - #define PIOEN1 0x0200 -#define GIUPODAT 0x1e -#define GIUFEDGEINHL 0x20 -#define GIUFEDGEINHH 0x22 -#define GIUREDGEINHL 0x24 -#define GIUREDGEINHH 0x26 - -#define GIUUSEUPDN 0x1e0 -#define GIUTERMUPDN 0x1e2 - -#define GPIO_HAS_PULLUPDOWN_IO 0x0001 -#define GPIO_HAS_OUTPUT_ENABLE 0x0002 -#define GPIO_HAS_INTERRUPT_EDGE_SELECT 0x0100 - -static spinlock_t giu_lock; -static unsigned long giu_flags; -static unsigned int giu_nr_pins; - -static void __iomem *giu_base; - -#define giu_read(offset) readw(giu_base + (offset)) -#define giu_write(offset, value) writew((value), giu_base + (offset)) - -#define GPIO_PIN_OF_IRQ(irq) ((irq) - GIU_IRQ_BASE) -#define GIUINT_HIGH_OFFSET 16 -#define GIUINT_HIGH_MAX 32 - -static inline uint16_t giu_set(uint16_t offset, uint16_t set) -{ - uint16_t data; - - data = giu_read(offset); - data |= set; - giu_write(offset, data); - - return data; -} - -static inline uint16_t giu_clear(uint16_t offset, uint16_t clear) -{ - uint16_t data; - - data = giu_read(offset); - data &= ~clear; - giu_write(offset, data); - - return data; -} - -static void ack_giuint_low(unsigned int irq) -{ - giu_write(GIUINTSTATL, 1 << GPIO_PIN_OF_IRQ(irq)); -} - -static void mask_giuint_low(unsigned int irq) -{ - giu_clear(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(irq)); -} - -static void mask_ack_giuint_low(unsigned int irq) -{ - unsigned int pin; - - pin = GPIO_PIN_OF_IRQ(irq); - giu_clear(GIUINTENL, 1 << pin); - giu_write(GIUINTSTATL, 1 << pin); -} - -static void unmask_giuint_low(unsigned int irq) -{ - giu_set(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(irq)); -} - -static struct irq_chip giuint_low_irq_chip = { - .name = "GIUINTL", - .ack = ack_giuint_low, - .mask = mask_giuint_low, - .mask_ack = mask_ack_giuint_low, - .unmask = unmask_giuint_low, -}; - -static void ack_giuint_high(unsigned int irq) -{ - giu_write(GIUINTSTATH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET)); -} - -static void mask_giuint_high(unsigned int irq) -{ - giu_clear(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET)); -} - -static void mask_ack_giuint_high(unsigned int irq) -{ - unsigned int pin; - - pin = GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET; - giu_clear(GIUINTENH, 1 << pin); - giu_write(GIUINTSTATH, 1 << pin); -} - -static void unmask_giuint_high(unsigned int irq) -{ - giu_set(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET)); -} - -static struct irq_chip giuint_high_irq_chip = { - .name = "GIUINTH", - .ack = ack_giuint_high, - .mask = mask_giuint_high, - .mask_ack = mask_ack_giuint_high, - .unmask = unmask_giuint_high, -}; - -static int giu_get_irq(unsigned int irq) -{ - uint16_t pendl, pendh, maskl, maskh; - int i; - - pendl = giu_read(GIUINTSTATL); - pendh = giu_read(GIUINTSTATH); - maskl = giu_read(GIUINTENL); - maskh = giu_read(GIUINTENH); - - maskl &= pendl; - maskh &= pendh; - - if (maskl) { - for (i = 0; i < 16; i++) { - if (maskl & (1 << i)) - return GIU_IRQ(i); - } - } else if (maskh) { - for (i = 0; i < 16; i++) { - if (maskh & (1 << i)) - return GIU_IRQ(i + GIUINT_HIGH_OFFSET); - } - } - - printk(KERN_ERR "spurious GIU interrupt: %04x(%04x),%04x(%04x)\n", - maskl, pendl, maskh, pendh); - - atomic_inc(&irq_err_count); - - return -EINVAL; -} - -void vr41xx_set_irq_trigger(unsigned int pin, irq_trigger_t trigger, irq_signal_t signal) -{ - uint16_t mask; - - if (pin < GIUINT_HIGH_OFFSET) { - mask = 1 << pin; - if (trigger != IRQ_TRIGGER_LEVEL) { - giu_set(GIUINTTYPL, mask); - if (signal == IRQ_SIGNAL_HOLD) - giu_set(GIUINTHTSELL, mask); - else - giu_clear(GIUINTHTSELL, mask); - if (giu_flags & GPIO_HAS_INTERRUPT_EDGE_SELECT) { - switch (trigger) { - case IRQ_TRIGGER_EDGE_FALLING: - giu_set(GIUFEDGEINHL, mask); - giu_clear(GIUREDGEINHL, mask); - break; - case IRQ_TRIGGER_EDGE_RISING: - giu_clear(GIUFEDGEINHL, mask); - giu_set(GIUREDGEINHL, mask); - break; - default: - giu_set(GIUFEDGEINHL, mask); - giu_set(GIUREDGEINHL, mask); - break; - } - } - set_irq_chip_and_handler(GIU_IRQ(pin), - &giuint_low_irq_chip, - handle_edge_irq); - } else { - giu_clear(GIUINTTYPL, mask); - giu_clear(GIUINTHTSELL, mask); - set_irq_chip_and_handler(GIU_IRQ(pin), - &giuint_low_irq_chip, - handle_level_irq); - } - giu_write(GIUINTSTATL, mask); - } else if (pin < GIUINT_HIGH_MAX) { - mask = 1 << (pin - GIUINT_HIGH_OFFSET); - if (trigger != IRQ_TRIGGER_LEVEL) { - giu_set(GIUINTTYPH, mask); - if (signal == IRQ_SIGNAL_HOLD) - giu_set(GIUINTHTSELH, mask); - else - giu_clear(GIUINTHTSELH, mask); - if (giu_flags & GPIO_HAS_INTERRUPT_EDGE_SELECT) { - switch (trigger) { - case IRQ_TRIGGER_EDGE_FALLING: - giu_set(GIUFEDGEINHH, mask); - giu_clear(GIUREDGEINHH, mask); - break; - case IRQ_TRIGGER_EDGE_RISING: - giu_clear(GIUFEDGEINHH, mask); - giu_set(GIUREDGEINHH, mask); - break; - default: - giu_set(GIUFEDGEINHH, mask); - giu_set(GIUREDGEINHH, mask); - break; - } - } - set_irq_chip_and_handler(GIU_IRQ(pin), - &giuint_high_irq_chip, - handle_edge_irq); - } else { - giu_clear(GIUINTTYPH, mask); - giu_clear(GIUINTHTSELH, mask); - set_irq_chip_and_handler(GIU_IRQ(pin), - &giuint_high_irq_chip, - handle_level_irq); - } - giu_write(GIUINTSTATH, mask); - } -} -EXPORT_SYMBOL_GPL(vr41xx_set_irq_trigger); - -void vr41xx_set_irq_level(unsigned int pin, irq_level_t level) -{ - uint16_t mask; - - if (pin < GIUINT_HIGH_OFFSET) { - mask = 1 << pin; - if (level == IRQ_LEVEL_HIGH) - giu_set(GIUINTALSELL, mask); - else - giu_clear(GIUINTALSELL, mask); - giu_write(GIUINTSTATL, mask); - } else if (pin < GIUINT_HIGH_MAX) { - mask = 1 << (pin - GIUINT_HIGH_OFFSET); - if (level == IRQ_LEVEL_HIGH) - giu_set(GIUINTALSELH, mask); - else - giu_clear(GIUINTALSELH, mask); - giu_write(GIUINTSTATH, mask); - } -} -EXPORT_SYMBOL_GPL(vr41xx_set_irq_level); - -gpio_data_t vr41xx_gpio_get_pin(unsigned int pin) -{ - uint16_t reg, mask; - - if (pin >= giu_nr_pins) - return GPIO_DATA_INVAL; - - if (pin < 16) { - reg = giu_read(GIUPIODL); - mask = (uint16_t)1 << pin; - } else if (pin < 32) { - reg = giu_read(GIUPIODH); - mask = (uint16_t)1 << (pin - 16); - } else if (pin < 48) { - reg = giu_read(GIUPODATL); - mask = (uint16_t)1 << (pin - 32); - } else { - reg = giu_read(GIUPODATH); - mask = (uint16_t)1 << (pin - 48); - } - - if (reg & mask) - return GPIO_DATA_HIGH; - - return GPIO_DATA_LOW; -} -EXPORT_SYMBOL_GPL(vr41xx_gpio_get_pin); - -int vr41xx_gpio_set_pin(unsigned int pin, gpio_data_t data) -{ - uint16_t offset, mask, reg; - unsigned long flags; - - if (pin >= giu_nr_pins) - return -EINVAL; - - if (pin < 16) { - offset = GIUPIODL; - mask = (uint16_t)1 << pin; - } else if (pin < 32) { - offset = GIUPIODH; - mask = (uint16_t)1 << (pin - 16); - } else if (pin < 48) { - offset = GIUPODATL; - mask = (uint16_t)1 << (pin - 32); - } else { - offset = GIUPODATH; - mask = (uint16_t)1 << (pin - 48); - } - - spin_lock_irqsave(&giu_lock, flags); - - reg = giu_read(offset); - if (data == GPIO_DATA_HIGH) - reg |= mask; - else - reg &= ~mask; - giu_write(offset, reg); - - spin_unlock_irqrestore(&giu_lock, flags); - - return 0; -} -EXPORT_SYMBOL_GPL(vr41xx_gpio_set_pin); - -int vr41xx_gpio_set_direction(unsigned int pin, gpio_direction_t dir) -{ - uint16_t offset, mask, reg; - unsigned long flags; - - if (pin >= giu_nr_pins) - return -EINVAL; - - if (pin < 16) { - offset = GIUIOSELL; - mask = (uint16_t)1 << pin; - } else if (pin < 32) { - offset = GIUIOSELH; - mask = (uint16_t)1 << (pin - 16); - } else { - if (giu_flags & GPIO_HAS_OUTPUT_ENABLE) { - offset = GIUPODATEN; - mask = (uint16_t)1 << (pin - 32); - } else { - switch (pin) { - case 48: - offset = GIUPODATH; - mask = PIOEN0; - break; - case 49: - offset = GIUPODATH; - mask = PIOEN1; - break; - default: - return -EINVAL; - } - } - } - - spin_lock_irqsave(&giu_lock, flags); - - reg = giu_read(offset); - if (dir == GPIO_OUTPUT) - reg |= mask; - else - reg &= ~mask; - giu_write(offset, reg); - - spin_unlock_irqrestore(&giu_lock, flags); - - return 0; -} -EXPORT_SYMBOL_GPL(vr41xx_gpio_set_direction); - -int vr41xx_gpio_pullupdown(unsigned int pin, gpio_pull_t pull) -{ - uint16_t reg, mask; - unsigned long flags; - - if ((giu_flags & GPIO_HAS_PULLUPDOWN_IO) != GPIO_HAS_PULLUPDOWN_IO) - return -EPERM; - - if (pin >= 15) - return -EINVAL; - - mask = (uint16_t)1 << pin; - - spin_lock_irqsave(&giu_lock, flags); - - if (pull == GPIO_PULL_UP || pull == GPIO_PULL_DOWN) { - reg = giu_read(GIUTERMUPDN); - if (pull == GPIO_PULL_UP) - reg |= mask; - else - reg &= ~mask; - giu_write(GIUTERMUPDN, reg); - - reg = giu_read(GIUUSEUPDN); - reg |= mask; - giu_write(GIUUSEUPDN, reg); - } else { - reg = giu_read(GIUUSEUPDN); - reg &= ~mask; - giu_write(GIUUSEUPDN, reg); - } - - spin_unlock_irqrestore(&giu_lock, flags); - - return 0; -} -EXPORT_SYMBOL_GPL(vr41xx_gpio_pullupdown); - -static ssize_t gpio_read(struct file *file, char __user *buf, size_t len, - loff_t *ppos) -{ - unsigned int pin; - char value = '0'; - - pin = iminor(file->f_path.dentry->d_inode); - if (pin >= giu_nr_pins) - return -EBADF; - - if (vr41xx_gpio_get_pin(pin) == GPIO_DATA_HIGH) - value = '1'; - - if (len <= 0) - return -EFAULT; - - if (put_user(value, buf)) - return -EFAULT; - - return 1; -} - -static ssize_t gpio_write(struct file *file, const char __user *data, - size_t len, loff_t *ppos) -{ - unsigned int pin; - size_t i; - char c; - int retval = 0; - - pin = iminor(file->f_path.dentry->d_inode); - if (pin >= giu_nr_pins) - return -EBADF; - - for (i = 0; i < len; i++) { - if (get_user(c, data + i)) - return -EFAULT; - - switch (c) { - case '0': - retval = vr41xx_gpio_set_pin(pin, GPIO_DATA_LOW); - break; - case '1': - retval = vr41xx_gpio_set_pin(pin, GPIO_DATA_HIGH); - break; - case 'D': - printk(KERN_INFO "GPIO%d: pull down\n", pin); - retval = vr41xx_gpio_pullupdown(pin, GPIO_PULL_DOWN); - break; - case 'd': - printk(KERN_INFO "GPIO%d: pull up/down disable\n", pin); - retval = vr41xx_gpio_pullupdown(pin, GPIO_PULL_DISABLE); - break; - case 'I': - printk(KERN_INFO "GPIO%d: input\n", pin); - retval = vr41xx_gpio_set_direction(pin, GPIO_INPUT); - break; - case 'O': - printk(KERN_INFO "GPIO%d: output\n", pin); - retval = vr41xx_gpio_set_direction(pin, GPIO_OUTPUT); - break; - case 'o': - printk(KERN_INFO "GPIO%d: output disable\n", pin); - retval = vr41xx_gpio_set_direction(pin, GPIO_OUTPUT_DISABLE); - break; - case 'P': - printk(KERN_INFO "GPIO%d: pull up\n", pin); - retval = vr41xx_gpio_pullupdown(pin, GPIO_PULL_UP); - break; - case 'p': - printk(KERN_INFO "GPIO%d: pull up/down disable\n", pin); - retval = vr41xx_gpio_pullupdown(pin, GPIO_PULL_DISABLE); - break; - default: - break; - } - - if (retval < 0) - break; - } - - return i; -} - -static int gpio_open(struct inode *inode, struct file *file) -{ - unsigned int pin; - - cycle_kernel_lock(); - pin = iminor(inode); - if (pin >= giu_nr_pins) - return -EBADF; - - return nonseekable_open(inode, file); -} - -static int gpio_release(struct inode *inode, struct file *file) -{ - unsigned int pin; - - pin = iminor(inode); - if (pin >= giu_nr_pins) - return -EBADF; - - return 0; -} - -static const struct file_operations gpio_fops = { - .owner = THIS_MODULE, - .read = gpio_read, - .write = gpio_write, - .open = gpio_open, - .release = gpio_release, -}; - -static int __devinit giu_probe(struct platform_device *dev) -{ - struct resource *res; - unsigned int trigger, i, pin; - struct irq_chip *chip; - int irq, retval; - - switch (dev->id) { - case GPIO_50PINS_PULLUPDOWN: - giu_flags = GPIO_HAS_PULLUPDOWN_IO; - giu_nr_pins = 50; - break; - case GPIO_36PINS: - giu_nr_pins = 36; - break; - case GPIO_48PINS_EDGE_SELECT: - giu_flags = GPIO_HAS_INTERRUPT_EDGE_SELECT; - giu_nr_pins = 48; - break; - default: - printk(KERN_ERR "GIU: unknown ID %d\n", dev->id); - return -ENODEV; - } - - res = platform_get_resource(dev, IORESOURCE_MEM, 0); - if (!res) - return -EBUSY; - - giu_base = ioremap(res->start, res->end - res->start + 1); - if (!giu_base) - return -ENOMEM; - - retval = register_chrdev(major, "GIU", &gpio_fops); - if (retval < 0) { - iounmap(giu_base); - giu_base = NULL; - return retval; - } - - if (major == 0) { - major = retval; - printk(KERN_INFO "GIU: major number %d\n", major); - } - - spin_lock_init(&giu_lock); - - giu_write(GIUINTENL, 0); - giu_write(GIUINTENH, 0); - - trigger = giu_read(GIUINTTYPH) << 16; - trigger |= giu_read(GIUINTTYPL); - for (i = GIU_IRQ_BASE; i <= GIU_IRQ_LAST; i++) { - pin = GPIO_PIN_OF_IRQ(i); - if (pin < GIUINT_HIGH_OFFSET) - chip = &giuint_low_irq_chip; - else - chip = &giuint_high_irq_chip; - - if (trigger & (1 << pin)) - set_irq_chip_and_handler(i, chip, handle_edge_irq); - else - set_irq_chip_and_handler(i, chip, handle_level_irq); - - } - - irq = platform_get_irq(dev, 0); - if (irq < 0 || irq >= nr_irqs) - return -EBUSY; - - return cascade_irq(irq, giu_get_irq); -} - -static int __devexit giu_remove(struct platform_device *dev) -{ - if (giu_base) { - iounmap(giu_base); - giu_base = NULL; - } - - return 0; -} - -static struct platform_driver giu_device_driver = { - .probe = giu_probe, - .remove = __devexit_p(giu_remove), - .driver = { - .name = "GIU", - .owner = THIS_MODULE, - }, -}; - -static int __init vr41xx_giu_init(void) -{ - return platform_driver_register(&giu_device_driver); -} - -static void __exit vr41xx_giu_exit(void) -{ - platform_driver_unregister(&giu_device_driver); -} - -module_init(vr41xx_giu_init); -module_exit(vr41xx_giu_exit); diff --git a/drivers/clocksource/sh_tmu.c b/drivers/clocksource/sh_tmu.c index 9ffb05f4095..93c2322feab 100644 --- a/drivers/clocksource/sh_tmu.c +++ b/drivers/clocksource/sh_tmu.c @@ -161,7 +161,7 @@ static void sh_tmu_set_next(struct sh_tmu_priv *p, unsigned long delta, if (periodic) sh_tmu_write(p, TCOR, delta); else - sh_tmu_write(p, TCOR, 0); + sh_tmu_write(p, TCOR, 0xffffffff); sh_tmu_write(p, TCNT, delta); diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index c36bf40568c..858fe603722 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -754,13 +754,13 @@ static void amd64_cpu_display_info(struct amd64_pvt *pvt) static enum edac_type amd64_determine_edac_cap(struct amd64_pvt *pvt) { int bit; - enum dev_type edac_cap = EDAC_NONE; + enum dev_type edac_cap = EDAC_FLAG_NONE; bit = (boot_cpu_data.x86 > 0xf || pvt->ext_model >= OPTERON_CPU_REV_F) ? 19 : 17; - if (pvt->dclr0 >> BIT(bit)) + if (pvt->dclr0 & BIT(bit)) edac_cap = EDAC_FLAG_SECDED; return edac_cap; @@ -1269,7 +1269,7 @@ static int f10_early_channel_count(struct amd64_pvt *pvt) if (channels == 0) channels = 1; - debugf0("DIMM count= %d\n", channels); + debugf0("MCT channel count: %d\n", channels); return channels; @@ -2966,7 +2966,12 @@ static int amd64_check_ecc_enabled(struct amd64_pvt *pvt) " Use of the override can cause " "unknown side effects.\n"); ret = -ENODEV; - } + } else + /* + * enable further driver loading if ECC enable is + * overridden. + */ + ret = 0; } else { amd64_printk(KERN_INFO, "ECC is enabled by BIOS, Proceeding " @@ -3006,7 +3011,6 @@ static void amd64_setup_mci_misc_attributes(struct mem_ctl_info *mci) mci->mtype_cap = MEM_FLAG_DDR2 | MEM_FLAG_RDDR2; mci->edac_ctl_cap = EDAC_FLAG_NONE; - mci->edac_cap = EDAC_FLAG_NONE; if (pvt->nbcap & K8_NBCAP_SECDED) mci->edac_ctl_cap |= EDAC_FLAG_SECDED; @@ -3052,7 +3056,7 @@ static int amd64_probe_one_instance(struct pci_dev *dram_f2_ctl, if (!pvt) goto err_exit; - pvt->mc_node_id = get_mc_node_id_from_pdev(dram_f2_ctl); + pvt->mc_node_id = get_node_id(dram_f2_ctl); pvt->dram_f2_ctl = dram_f2_ctl; pvt->ext_model = boot_cpu_data.x86_model >> 4; @@ -3179,8 +3183,7 @@ static int __devinit amd64_init_one_instance(struct pci_dev *pdev, { int ret = 0; - debugf0("(MC node=%d,mc_type='%s')\n", - get_mc_node_id_from_pdev(pdev), + debugf0("(MC node=%d,mc_type='%s')\n", get_node_id(pdev), get_amd_family_name(mc_type->driver_data)); ret = pci_enable_device(pdev); @@ -3319,15 +3322,17 @@ static int __init amd64_edac_init(void) err = amd64_init_2nd_stage(pvt_lookup[nb]); if (err) - goto err_exit; + goto err_2nd_stage; } amd64_setup_pci_device(); return 0; +err_2nd_stage: + debugf0("2nd stage failed\n"); + err_exit: - debugf0("'finish_setup' stage failed\n"); pci_unregister_driver(&amd64_pci_driver); return err; diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h index a159957e167..ba73015af8e 100644 --- a/drivers/edac/amd64_edac.h +++ b/drivers/edac/amd64_edac.h @@ -444,7 +444,7 @@ enum { #define K8_MSR_MC4ADDR 0x0412 /* AMD sets the first MC device at device ID 0x18. */ -static inline int get_mc_node_id_from_pdev(struct pci_dev *pdev) +static inline int get_node_id(struct pci_dev *pdev) { return PCI_SLOT(pdev->devfn) - 0x18; } diff --git a/drivers/edac/edac_core.h b/drivers/edac/edac_core.h index 3493c6bdb82..871c13b4c14 100644 --- a/drivers/edac/edac_core.h +++ b/drivers/edac/edac_core.h @@ -150,6 +150,8 @@ enum mem_type { MEM_FB_DDR2, /* fully buffered DDR2 */ MEM_RDDR2, /* Registered DDR2 RAM */ MEM_XDR, /* Rambus XDR */ + MEM_DDR3, /* DDR3 RAM */ + MEM_RDDR3, /* Registered DDR3 RAM */ }; #define MEM_FLAG_EMPTY BIT(MEM_EMPTY) @@ -167,6 +169,8 @@ enum mem_type { #define MEM_FLAG_FB_DDR2 BIT(MEM_FB_DDR2) #define MEM_FLAG_RDDR2 BIT(MEM_RDDR2) #define MEM_FLAG_XDR BIT(MEM_XDR) +#define MEM_FLAG_DDR3 BIT(MEM_DDR3) +#define MEM_FLAG_RDDR3 BIT(MEM_RDDR3) /* chipset Error Detection and Correction capabilities and mode */ enum edac_type { diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c index ad218fe4942..e1d4ce08348 100644 --- a/drivers/edac/edac_mc_sysfs.c +++ b/drivers/edac/edac_mc_sysfs.c @@ -94,7 +94,9 @@ static const char *mem_types[] = { [MEM_DDR2] = "Unbuffered-DDR2", [MEM_FB_DDR2] = "FullyBuffered-DDR2", [MEM_RDDR2] = "Registered-DDR2", - [MEM_XDR] = "XDR" + [MEM_XDR] = "XDR", + [MEM_DDR3] = "Unbuffered-DDR3", + [MEM_RDDR3] = "Registered-DDR3" }; static const char *dev_types[] = { diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c index 7c8c2d72916..3f2ccfc6407 100644 --- a/drivers/edac/mpc85xx_edac.c +++ b/drivers/edac/mpc85xx_edac.c @@ -757,6 +757,9 @@ static void __devinit mpc85xx_init_csrows(struct mem_ctl_info *mci) case DSC_SDTYPE_DDR2: mtype = MEM_RDDR2; break; + case DSC_SDTYPE_DDR3: + mtype = MEM_RDDR3; + break; default: mtype = MEM_UNKNOWN; break; @@ -769,6 +772,9 @@ static void __devinit mpc85xx_init_csrows(struct mem_ctl_info *mci) case DSC_SDTYPE_DDR2: mtype = MEM_DDR2; break; + case DSC_SDTYPE_DDR3: + mtype = MEM_DDR3; + break; default: mtype = MEM_UNKNOWN; break; diff --git a/drivers/edac/mpc85xx_edac.h b/drivers/edac/mpc85xx_edac.h index 135b3539a03..52432ee7c4b 100644 --- a/drivers/edac/mpc85xx_edac.h +++ b/drivers/edac/mpc85xx_edac.h @@ -53,6 +53,7 @@ #define DSC_SDTYPE_DDR 0x02000000 #define DSC_SDTYPE_DDR2 0x03000000 +#define DSC_SDTYPE_DDR3 0x07000000 #define DSC_X32_EN 0x00000020 /* Err_Int_En */ diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 3582c39f972..96dda81c922 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -79,6 +79,12 @@ config GPIO_XILINX help Say yes here to support the Xilinx FPGA GPIO device +config GPIO_VR41XX + tristate "NEC VR4100 series General-purpose I/O Uint support" + depends on CPU_VR41XX + help + Say yes here to support the NEC VR4100 series General-purpose I/O Uint + comment "I2C GPIO expanders:" config GPIO_MAX732X diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index ef90203e8f3..9244c6fcd8b 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -13,3 +13,4 @@ obj-$(CONFIG_GPIO_PL061) += pl061.o obj-$(CONFIG_GPIO_TWL4030) += twl4030-gpio.o obj-$(CONFIG_GPIO_XILINX) += xilinx_gpio.o obj-$(CONFIG_GPIO_BT8XX) += bt8xxgpio.o +obj-$(CONFIG_GPIO_VR41XX) += vr41xx_giu.o diff --git a/drivers/gpio/pl061.c b/drivers/gpio/pl061.c index aa8e7cb020d..4ee4c8367a3 100644 --- a/drivers/gpio/pl061.c +++ b/drivers/gpio/pl061.c @@ -109,6 +109,16 @@ static void pl061_set_value(struct gpio_chip *gc, unsigned offset, int value) writeb(!!value << offset, chip->base + (1 << (offset + 2))); } +static int pl061_to_irq(struct gpio_chip *gc, unsigned offset) +{ + struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc); + + if (chip->irq_base == (unsigned) -1) + return -EINVAL; + + return chip->irq_base + offset; +} + /* * PL061 GPIO IRQ */ @@ -200,7 +210,7 @@ static void pl061_irq_handler(unsigned irq, struct irq_desc *desc) desc->chip->ack(irq); list_for_each(ptr, chip_list) { unsigned long pending; - int gpio; + int offset; chip = list_entry(ptr, struct pl061_gpio, list); pending = readb(chip->base + GPIOMIS); @@ -209,8 +219,8 @@ static void pl061_irq_handler(unsigned irq, struct irq_desc *desc) if (pending == 0) continue; - for_each_bit(gpio, &pending, PL061_GPIO_NR) - generic_handle_irq(gpio_to_irq(gpio)); + for_each_bit(offset, &pending, PL061_GPIO_NR) + generic_handle_irq(pl061_to_irq(&chip->gc, offset)); } desc->chip->unmask(irq); } @@ -221,7 +231,7 @@ static int __init pl061_probe(struct amba_device *dev, struct amba_id *id) struct pl061_gpio *chip; struct list_head *chip_list; int ret, irq, i; - static unsigned long init_irq[BITS_TO_LONGS(NR_IRQS)]; + static DECLARE_BITMAP(init_irq, NR_IRQS); pdata = dev->dev.platform_data; if (pdata == NULL) @@ -251,6 +261,7 @@ static int __init pl061_probe(struct amba_device *dev, struct amba_id *id) chip->gc.direction_output = pl061_direction_output; chip->gc.get = pl061_get_value; chip->gc.set = pl061_set_value; + chip->gc.to_irq = pl061_to_irq; chip->gc.base = pdata->gpio_base; chip->gc.ngpio = PL061_GPIO_NR; chip->gc.label = dev_name(&dev->dev); @@ -280,6 +291,7 @@ static int __init pl061_probe(struct amba_device *dev, struct amba_id *id) if (!test_and_set_bit(irq, init_irq)) { /* list initialized? */ chip_list = kmalloc(sizeof(*chip_list), GFP_KERNEL); if (chip_list == NULL) { + clear_bit(irq, init_irq); ret = -ENOMEM; goto iounmap; } diff --git a/drivers/gpio/vr41xx_giu.c b/drivers/gpio/vr41xx_giu.c new file mode 100644 index 00000000000..b70e06133e7 --- /dev/null +++ b/drivers/gpio/vr41xx_giu.c @@ -0,0 +1,586 @@ +/* + * Driver for NEC VR4100 series General-purpose I/O Unit. + * + * Copyright (C) 2002 MontaVista Software Inc. + * Author: Yoichi Yuasa <source@mvista.com> + * Copyright (C) 2003-2009 Yoichi Yuasa <yuasa@linux-mips.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <linux/errno.h> +#include <linux/fs.h> +#include <linux/gpio.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/smp_lock.h> +#include <linux/spinlock.h> +#include <linux/types.h> + +#include <asm/vr41xx/giu.h> +#include <asm/vr41xx/irq.h> +#include <asm/vr41xx/vr41xx.h> + +MODULE_AUTHOR("Yoichi Yuasa <yuasa@linux-mips.org>"); +MODULE_DESCRIPTION("NEC VR4100 series General-purpose I/O Unit driver"); +MODULE_LICENSE("GPL"); + +#define GIUIOSELL 0x00 +#define GIUIOSELH 0x02 +#define GIUPIODL 0x04 +#define GIUPIODH 0x06 +#define GIUINTSTATL 0x08 +#define GIUINTSTATH 0x0a +#define GIUINTENL 0x0c +#define GIUINTENH 0x0e +#define GIUINTTYPL 0x10 +#define GIUINTTYPH 0x12 +#define GIUINTALSELL 0x14 +#define GIUINTALSELH 0x16 +#define GIUINTHTSELL 0x18 +#define GIUINTHTSELH 0x1a +#define GIUPODATL 0x1c +#define GIUPODATEN 0x1c +#define GIUPODATH 0x1e + #define PIOEN0 0x0100 + #define PIOEN1 0x0200 +#define GIUPODAT 0x1e +#define GIUFEDGEINHL 0x20 +#define GIUFEDGEINHH 0x22 +#define GIUREDGEINHL 0x24 +#define GIUREDGEINHH 0x26 + +#define GIUUSEUPDN 0x1e0 +#define GIUTERMUPDN 0x1e2 + +#define GPIO_HAS_PULLUPDOWN_IO 0x0001 +#define GPIO_HAS_OUTPUT_ENABLE 0x0002 +#define GPIO_HAS_INTERRUPT_EDGE_SELECT 0x0100 + +enum { + GPIO_INPUT, + GPIO_OUTPUT, +}; + +static DEFINE_SPINLOCK(giu_lock); +static unsigned long giu_flags; + +static void __iomem *giu_base; + +#define giu_read(offset) readw(giu_base + (offset)) +#define giu_write(offset, value) writew((value), giu_base + (offset)) + +#define GPIO_PIN_OF_IRQ(irq) ((irq) - GIU_IRQ_BASE) +#define GIUINT_HIGH_OFFSET 16 +#define GIUINT_HIGH_MAX 32 + +static inline u16 giu_set(u16 offset, u16 set) +{ + u16 data; + + data = giu_read(offset); + data |= set; + giu_write(offset, data); + + return data; +} + +static inline u16 giu_clear(u16 offset, u16 clear) +{ + u16 data; + + data = giu_read(offset); + data &= ~clear; + giu_write(offset, data); + + return data; +} + +static void ack_giuint_low(unsigned int irq) +{ + giu_write(GIUINTSTATL, 1 << GPIO_PIN_OF_IRQ(irq)); +} + +static void mask_giuint_low(unsigned int irq) +{ + giu_clear(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(irq)); +} + +static void mask_ack_giuint_low(unsigned int irq) +{ + unsigned int pin; + + pin = GPIO_PIN_OF_IRQ(irq); + giu_clear(GIUINTENL, 1 << pin); + giu_write(GIUINTSTATL, 1 << pin); +} + +static void unmask_giuint_low(unsigned int irq) +{ + giu_set(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(irq)); +} + +static struct irq_chip giuint_low_irq_chip = { + .name = "GIUINTL", + .ack = ack_giuint_low, + .mask = mask_giuint_low, + .mask_ack = mask_ack_giuint_low, + .unmask = unmask_giuint_low, +}; + +static void ack_giuint_high(unsigned int irq) +{ + giu_write(GIUINTSTATH, + 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET)); +} + +static void mask_giuint_high(unsigned int irq) +{ + giu_clear(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET)); +} + +static void mask_ack_giuint_high(unsigned int irq) +{ + unsigned int pin; + + pin = GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET; + giu_clear(GIUINTENH, 1 << pin); + giu_write(GIUINTSTATH, 1 << pin); +} + +static void unmask_giuint_high(unsigned int irq) +{ + giu_set(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET)); +} + +static struct irq_chip giuint_high_irq_chip = { + .name = "GIUINTH", + .ack = ack_giuint_high, + .mask = mask_giuint_high, + .mask_ack = mask_ack_giuint_high, + .unmask = unmask_giuint_high, +}; + +static int giu_get_irq(unsigned int irq) +{ + u16 pendl, pendh, maskl, maskh; + int i; + + pendl = giu_read(GIUINTSTATL); + pendh = giu_read(GIUINTSTATH); + maskl = giu_read(GIUINTENL); + maskh = giu_read(GIUINTENH); + + maskl &= pendl; + maskh &= pendh; + + if (maskl) { + for (i = 0; i < 16; i++) { + if (maskl & (1 << i)) + return GIU_IRQ(i); + } + } else if (maskh) { + for (i = 0; i < 16; i++) { + if (maskh & (1 << i)) + return GIU_IRQ(i + GIUINT_HIGH_OFFSET); + } + } + + printk(KERN_ERR "spurious GIU interrupt: %04x(%04x),%04x(%04x)\n", + maskl, pendl, maskh, pendh); + + atomic_inc(&irq_err_count); + + return -EINVAL; +} + +void vr41xx_set_irq_trigger(unsigned int pin, irq_trigger_t trigger, + irq_signal_t signal) +{ + u16 mask; + + if (pin < GIUINT_HIGH_OFFSET) { + mask = 1 << pin; + if (trigger != IRQ_TRIGGER_LEVEL) { + giu_set(GIUINTTYPL, mask); + if (signal == IRQ_SIGNAL_HOLD) + giu_set(GIUINTHTSELL, mask); + else + giu_clear(GIUINTHTSELL, mask); + if (giu_flags & GPIO_HAS_INTERRUPT_EDGE_SELECT) { + switch (trigger) { + case IRQ_TRIGGER_EDGE_FALLING: + giu_set(GIUFEDGEINHL, mask); + giu_clear(GIUREDGEINHL, mask); + break; + case IRQ_TRIGGER_EDGE_RISING: + giu_clear(GIUFEDGEINHL, mask); + giu_set(GIUREDGEINHL, mask); + break; + default: + giu_set(GIUFEDGEINHL, mask); + giu_set(GIUREDGEINHL, mask); + break; + } + } + set_irq_chip_and_handler(GIU_IRQ(pin), + &giuint_low_irq_chip, + handle_edge_irq); + } else { + giu_clear(GIUINTTYPL, mask); + giu_clear(GIUINTHTSELL, mask); + set_irq_chip_and_handler(GIU_IRQ(pin), + &giuint_low_irq_chip, + handle_level_irq); + } + giu_write(GIUINTSTATL, mask); + } else if (pin < GIUINT_HIGH_MAX) { + mask = 1 << (pin - GIUINT_HIGH_OFFSET); + if (trigger != IRQ_TRIGGER_LEVEL) { + giu_set(GIUINTTYPH, mask); + if (signal == IRQ_SIGNAL_HOLD) + giu_set(GIUINTHTSELH, mask); + else + giu_clear(GIUINTHTSELH, mask); + if (giu_flags & GPIO_HAS_INTERRUPT_EDGE_SELECT) { + switch (trigger) { + case IRQ_TRIGGER_EDGE_FALLING: + giu_set(GIUFEDGEINHH, mask); + giu_clear(GIUREDGEINHH, mask); + break; + case IRQ_TRIGGER_EDGE_RISING: + giu_clear(GIUFEDGEINHH, mask); + giu_set(GIUREDGEINHH, mask); + break; + default: + giu_set(GIUFEDGEINHH, mask); + giu_set(GIUREDGEINHH, mask); + break; + } + } + set_irq_chip_and_handler(GIU_IRQ(pin), + &giuint_high_irq_chip, + handle_edge_irq); + } else { + giu_clear(GIUINTTYPH, mask); + giu_clear(GIUINTHTSELH, mask); + set_irq_chip_and_handler(GIU_IRQ(pin), + &giuint_high_irq_chip, + handle_level_irq); + } + giu_write(GIUINTSTATH, mask); + } +} +EXPORT_SYMBOL_GPL(vr41xx_set_irq_trigger); + +void vr41xx_set_irq_level(unsigned int pin, irq_level_t level) +{ + u16 mask; + + if (pin < GIUINT_HIGH_OFFSET) { + mask = 1 << pin; + if (level == IRQ_LEVEL_HIGH) + giu_set(GIUINTALSELL, mask); + else + giu_clear(GIUINTALSELL, mask); + giu_write(GIUINTSTATL, mask); + } else if (pin < GIUINT_HIGH_MAX) { + mask = 1 << (pin - GIUINT_HIGH_OFFSET); + if (level == IRQ_LEVEL_HIGH) + giu_set(GIUINTALSELH, mask); + else + giu_clear(GIUINTALSELH, mask); + giu_write(GIUINTSTATH, mask); + } +} +EXPORT_SYMBOL_GPL(vr41xx_set_irq_level); + +static int giu_set_direction(struct gpio_chip *chip, unsigned pin, int dir) +{ + u16 offset, mask, reg; + unsigned long flags; + + if (pin >= chip->ngpio) + return -EINVAL; + + if (pin < 16) { + offset = GIUIOSELL; + mask = 1 << pin; + } else if (pin < 32) { + offset = GIUIOSELH; + mask = 1 << (pin - 16); + } else { + if (giu_flags & GPIO_HAS_OUTPUT_ENABLE) { + offset = GIUPODATEN; + mask = 1 << (pin - 32); + } else { + switch (pin) { + case 48: + offset = GIUPODATH; + mask = PIOEN0; + break; + case 49: + offset = GIUPODATH; + mask = PIOEN1; + break; + default: + return -EINVAL; + } + } + } + + spin_lock_irqsave(&giu_lock, flags); + + reg = giu_read(offset); + if (dir == GPIO_OUTPUT) + reg |= mask; + else + reg &= ~mask; + giu_write(offset, reg); + + spin_unlock_irqrestore(&giu_lock, flags); + + return 0; +} + +int vr41xx_gpio_pullupdown(unsigned int pin, gpio_pull_t pull) +{ + u16 reg, mask; + unsigned long flags; + + if ((giu_flags & GPIO_HAS_PULLUPDOWN_IO) != GPIO_HAS_PULLUPDOWN_IO) + return -EPERM; + + if (pin >= 15) + return -EINVAL; + + mask = 1 << pin; + + spin_lock_irqsave(&giu_lock, flags); + + if (pull == GPIO_PULL_UP || pull == GPIO_PULL_DOWN) { + reg = giu_read(GIUTERMUPDN); + if (pull == GPIO_PULL_UP) + reg |= mask; + else + reg &= ~mask; + giu_write(GIUTERMUPDN, reg); + + reg = giu_read(GIUUSEUPDN); + reg |= mask; + giu_write(GIUUSEUPDN, reg); + } else { + reg = giu_read(GIUUSEUPDN); + reg &= ~mask; + giu_write(GIUUSEUPDN, reg); + } + + spin_unlock_irqrestore(&giu_lock, flags); + + return 0; +} +EXPORT_SYMBOL_GPL(vr41xx_gpio_pullupdown); + +static int vr41xx_gpio_get(struct gpio_chip *chip, unsigned pin) +{ + u16 reg, mask; + + if (pin >= chip->ngpio) + return -EINVAL; + + if (pin < 16) { + reg = giu_read(GIUPIODL); + mask = 1 << pin; + } else if (pin < 32) { + reg = giu_read(GIUPIODH); + mask = 1 << (pin - 16); + } else if (pin < 48) { + reg = giu_read(GIUPODATL); + mask = 1 << (pin - 32); + } else { + reg = giu_read(GIUPODATH); + mask = 1 << (pin - 48); + } + + if (reg & mask) + return 1; + + return 0; +} + +static void vr41xx_gpio_set(struct gpio_chip *chip, unsigned pin, + int value) +{ + u16 offset, mask, reg; + unsigned long flags; + + if (pin >= chip->ngpio) + return; + + if (pin < 16) { + offset = GIUPIODL; + mask = 1 << pin; + } else if (pin < 32) { + offset = GIUPIODH; + mask = 1 << (pin - 16); + } else if (pin < 48) { + offset = GIUPODATL; + mask = 1 << (pin - 32); + } else { + offset = GIUPODATH; + mask = 1 << (pin - 48); + } + + spin_lock_irqsave(&giu_lock, flags); + + reg = giu_read(offset); + if (value) + reg |= mask; + else + reg &= ~mask; + giu_write(offset, reg); + + spin_unlock_irqrestore(&giu_lock, flags); +} + + +static int vr41xx_gpio_direction_input(struct gpio_chip *chip, unsigned offset) +{ + return giu_set_direction(chip, offset, GPIO_INPUT); +} + +static int vr41xx_gpio_direction_output(struct gpio_chip *chip, unsigned offset, + int value) +{ + vr41xx_gpio_set(chip, offset, value); + + return giu_set_direction(chip, offset, GPIO_OUTPUT); +} + +static int vr41xx_gpio_to_irq(struct gpio_chip *chip, unsigned offset) +{ + if (offset >= chip->ngpio) + return -EINVAL; + + return GIU_IRQ_BASE + offset; +} + +static struct gpio_chip vr41xx_gpio_chip = { + .label = "vr41xx", + .owner = THIS_MODULE, + .direction_input = vr41xx_gpio_direction_input, + .get = vr41xx_gpio_get, + .direction_output = vr41xx_gpio_direction_output, + .set = vr41xx_gpio_set, + .to_irq = vr41xx_gpio_to_irq, +}; + +static int __devinit giu_probe(struct platform_device *pdev) +{ + struct resource *res; + unsigned int trigger, i, pin; + struct irq_chip *chip; + int irq, retval; + + switch (pdev->id) { + case GPIO_50PINS_PULLUPDOWN: + giu_flags = GPIO_HAS_PULLUPDOWN_IO; + vr41xx_gpio_chip.ngpio = 50; + break; + case GPIO_36PINS: + vr41xx_gpio_chip.ngpio = 36; + break; + case GPIO_48PINS_EDGE_SELECT: + giu_flags = GPIO_HAS_INTERRUPT_EDGE_SELECT; + vr41xx_gpio_chip.ngpio = 48; + break; + default: + dev_err(&pdev->dev, "GIU: unknown ID %d\n", pdev->id); + return -ENODEV; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -EBUSY; + + giu_base = ioremap(res->start, res->end - res->start + 1); + if (!giu_base) + return -ENOMEM; + + vr41xx_gpio_chip.dev = &pdev->dev; + + retval = gpiochip_add(&vr41xx_gpio_chip); + + giu_write(GIUINTENL, 0); + giu_write(GIUINTENH, 0); + + trigger = giu_read(GIUINTTYPH) << 16; + trigger |= giu_read(GIUINTTYPL); + for (i = GIU_IRQ_BASE; i <= GIU_IRQ_LAST; i++) { + pin = GPIO_PIN_OF_IRQ(i); + if (pin < GIUINT_HIGH_OFFSET) + chip = &giuint_low_irq_chip; + else + chip = &giuint_high_irq_chip; + + if (trigger & (1 << pin)) + set_irq_chip_and_handler(i, chip, handle_edge_irq); + else + set_irq_chip_and_handler(i, chip, handle_level_irq); + + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0 || irq >= nr_irqs) + return -EBUSY; + + return cascade_irq(irq, giu_get_irq); +} + +static int __devexit giu_remove(struct platform_device *pdev) +{ + if (giu_base) { + iounmap(giu_base); + giu_base = NULL; + } + + return 0; +} + +static struct platform_driver giu_device_driver = { + .probe = giu_probe, + .remove = __devexit_p(giu_remove), + .driver = { + .name = "GIU", + .owner = THIS_MODULE, + }, +}; + +static int __init vr41xx_giu_init(void) +{ + return platform_driver_register(&giu_device_driver); +} + +static void __exit vr41xx_giu_exit(void) +{ + platform_driver_unregister(&giu_device_driver); +} + +module_init(vr41xx_giu_init); +module_exit(vr41xx_giu_exit); diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index c961fe415ae..39b393d38bb 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -81,6 +81,7 @@ config DRM_I830 config DRM_I915 tristate "i915 driver" + depends on AGP_INTEL select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 4e89ab08b7b..fe23f29f7cb 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -16,6 +16,7 @@ drm-y := drm_auth.o drm_bufs.o drm_cache.o \ drm-$(CONFIG_COMPAT) += drm_ioc32.o obj-$(CONFIG_DRM) += drm.o +obj-$(CONFIG_DRM_TTM) += ttm/ obj-$(CONFIG_DRM_TDFX) += tdfx/ obj-$(CONFIG_DRM_R128) += r128/ obj-$(CONFIG_DRM_RADEON)+= radeon/ @@ -26,4 +27,3 @@ obj-$(CONFIG_DRM_I915) += i915/ obj-$(CONFIG_DRM_SIS) += sis/ obj-$(CONFIG_DRM_SAVAGE)+= savage/ obj-$(CONFIG_DRM_VIA) +=via/ -obj-$(CONFIG_DRM_TTM) += ttm/ diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 7d0835226f6..80cc6d06d61 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -294,10 +294,10 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev, unsigned vactive = (pt->vactive_vblank_hi & 0xf0) << 4 | pt->vactive_lo; unsigned hblank = (pt->hactive_hblank_hi & 0xf) << 8 | pt->hblank_lo; unsigned vblank = (pt->vactive_vblank_hi & 0xf) << 8 | pt->vblank_lo; - unsigned hsync_offset = (pt->hsync_vsync_offset_pulse_width_hi & 0x3) << 8 | pt->hsync_offset_lo; - unsigned hsync_pulse_width = (pt->hsync_vsync_offset_pulse_width_hi & 0xc) << 6 | pt->hsync_pulse_width_lo; - unsigned vsync_offset = (pt->hsync_vsync_offset_pulse_width_hi & 0x30) | (pt->vsync_offset_pulse_width_lo & 0xf); - unsigned vsync_pulse_width = (pt->hsync_vsync_offset_pulse_width_hi & 0xc0) >> 2 | pt->vsync_offset_pulse_width_lo >> 4; + unsigned hsync_offset = (pt->hsync_vsync_offset_pulse_width_hi & 0xc0) << 2 | pt->hsync_offset_lo; + unsigned hsync_pulse_width = (pt->hsync_vsync_offset_pulse_width_hi & 0x30) << 4 | pt->hsync_pulse_width_lo; + unsigned vsync_offset = (pt->hsync_vsync_offset_pulse_width_hi & 0xc) >> 2 | pt->vsync_offset_pulse_width_lo >> 4; + unsigned vsync_pulse_width = (pt->hsync_vsync_offset_pulse_width_hi & 0x3) << 4 | (pt->vsync_offset_pulse_width_lo & 0xf); /* ignore tiny modes */ if (hactive < 64 || vactive < 64) @@ -347,8 +347,8 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev, mode->flags |= (pt->misc & DRM_EDID_PT_VSYNC_POSITIVE) ? DRM_MODE_FLAG_PVSYNC : DRM_MODE_FLAG_NVSYNC; - mode->width_mm = pt->width_mm_lo | (pt->width_height_mm_hi & 0xf) << 8; - mode->height_mm = pt->height_mm_lo | (pt->width_height_mm_hi & 0xf0) << 4; + mode->width_mm = pt->width_mm_lo | (pt->width_height_mm_hi & 0xf0) << 4; + mode->height_mm = pt->height_mm_lo | (pt->width_height_mm_hi & 0xf) << 8; if (quirks & EDID_QUIRK_DETAILED_IN_CM) { mode->width_mm *= 10; diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 51c5a050aa7..30d6b99fb30 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -13,6 +13,8 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o \ intel_crt.o \ intel_lvds.o \ intel_bios.o \ + intel_dp.o \ + intel_dp_i2c.o \ intel_hdmi.o \ intel_sdvo.o \ intel_modes.o \ diff --git a/drivers/gpu/drm/i915/dvo.h b/drivers/gpu/drm/i915/dvo.h index e747ac42fe3..288fc50627e 100644 --- a/drivers/gpu/drm/i915/dvo.h +++ b/drivers/gpu/drm/i915/dvo.h @@ -37,7 +37,7 @@ struct intel_dvo_device { /* GPIO register used for i2c bus to control this device */ u32 gpio; int slave_addr; - struct intel_i2c_chan *i2c_bus; + struct i2c_adapter *i2c_bus; const struct intel_dvo_dev_ops *dev_ops; void *dev_priv; @@ -52,7 +52,7 @@ struct intel_dvo_dev_ops { * Returns NULL if the device does not exist. */ bool (*init)(struct intel_dvo_device *dvo, - struct intel_i2c_chan *i2cbus); + struct i2c_adapter *i2cbus); /* * Called to allow the output a chance to create properties after the diff --git a/drivers/gpu/drm/i915/dvo_ch7017.c b/drivers/gpu/drm/i915/dvo_ch7017.c index 03d4b4973b0..621815b531d 100644 --- a/drivers/gpu/drm/i915/dvo_ch7017.c +++ b/drivers/gpu/drm/i915/dvo_ch7017.c @@ -176,19 +176,20 @@ static void ch7017_dpms(struct intel_dvo_device *dvo, int mode); static bool ch7017_read(struct intel_dvo_device *dvo, int addr, uint8_t *val) { - struct intel_i2c_chan *i2cbus = dvo->i2c_bus; + struct i2c_adapter *adapter = dvo->i2c_bus; + struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter); u8 out_buf[2]; u8 in_buf[2]; struct i2c_msg msgs[] = { { - .addr = i2cbus->slave_addr, + .addr = dvo->slave_addr, .flags = 0, .len = 1, .buf = out_buf, }, { - .addr = i2cbus->slave_addr, + .addr = dvo->slave_addr, .flags = I2C_M_RD, .len = 1, .buf = in_buf, @@ -208,10 +209,11 @@ static bool ch7017_read(struct intel_dvo_device *dvo, int addr, uint8_t *val) static bool ch7017_write(struct intel_dvo_device *dvo, int addr, uint8_t val) { - struct intel_i2c_chan *i2cbus = dvo->i2c_bus; + struct i2c_adapter *adapter = dvo->i2c_bus; + struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter); uint8_t out_buf[2]; struct i2c_msg msg = { - .addr = i2cbus->slave_addr, + .addr = dvo->slave_addr, .flags = 0, .len = 2, .buf = out_buf, @@ -228,8 +230,9 @@ static bool ch7017_write(struct intel_dvo_device *dvo, int addr, uint8_t val) /** Probes for a CH7017 on the given bus and slave address. */ static bool ch7017_init(struct intel_dvo_device *dvo, - struct intel_i2c_chan *i2cbus) + struct i2c_adapter *adapter) { + struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter); struct ch7017_priv *priv; uint8_t val; @@ -237,8 +240,7 @@ static bool ch7017_init(struct intel_dvo_device *dvo, if (priv == NULL) return false; - dvo->i2c_bus = i2cbus; - dvo->i2c_bus->slave_addr = dvo->slave_addr; + dvo->i2c_bus = adapter; dvo->dev_priv = priv; if (!ch7017_read(dvo, CH7017_DEVICE_ID, &val)) @@ -248,7 +250,7 @@ static bool ch7017_init(struct intel_dvo_device *dvo, val != CH7018_DEVICE_ID_VALUE && val != CH7019_DEVICE_ID_VALUE) { DRM_DEBUG("ch701x not detected, got %d: from %s Slave %d.\n", - val, i2cbus->adapter.name,i2cbus->slave_addr); + val, i2cbus->adapter.name,dvo->slave_addr); goto fail; } diff --git a/drivers/gpu/drm/i915/dvo_ch7xxx.c b/drivers/gpu/drm/i915/dvo_ch7xxx.c index d2fd95dbd03..a9b89628968 100644 --- a/drivers/gpu/drm/i915/dvo_ch7xxx.c +++ b/drivers/gpu/drm/i915/dvo_ch7xxx.c @@ -123,19 +123,20 @@ static char *ch7xxx_get_id(uint8_t vid) static bool ch7xxx_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch) { struct ch7xxx_priv *ch7xxx= dvo->dev_priv; - struct intel_i2c_chan *i2cbus = dvo->i2c_bus; + struct i2c_adapter *adapter = dvo->i2c_bus; + struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter); u8 out_buf[2]; u8 in_buf[2]; struct i2c_msg msgs[] = { { - .addr = i2cbus->slave_addr, + .addr = dvo->slave_addr, .flags = 0, .len = 1, .buf = out_buf, }, { - .addr = i2cbus->slave_addr, + .addr = dvo->slave_addr, .flags = I2C_M_RD, .len = 1, .buf = in_buf, @@ -152,7 +153,7 @@ static bool ch7xxx_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch) if (!ch7xxx->quiet) { DRM_DEBUG("Unable to read register 0x%02x from %s:%02x.\n", - addr, i2cbus->adapter.name, i2cbus->slave_addr); + addr, i2cbus->adapter.name, dvo->slave_addr); } return false; } @@ -161,10 +162,11 @@ static bool ch7xxx_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch) static bool ch7xxx_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch) { struct ch7xxx_priv *ch7xxx = dvo->dev_priv; - struct intel_i2c_chan *i2cbus = dvo->i2c_bus; + struct i2c_adapter *adapter = dvo->i2c_bus; + struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter); uint8_t out_buf[2]; struct i2c_msg msg = { - .addr = i2cbus->slave_addr, + .addr = dvo->slave_addr, .flags = 0, .len = 2, .buf = out_buf, @@ -178,14 +180,14 @@ static bool ch7xxx_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch) if (!ch7xxx->quiet) { DRM_DEBUG("Unable to write register 0x%02x to %s:%d.\n", - addr, i2cbus->adapter.name, i2cbus->slave_addr); + addr, i2cbus->adapter.name, dvo->slave_addr); } return false; } static bool ch7xxx_init(struct intel_dvo_device *dvo, - struct intel_i2c_chan *i2cbus) + struct i2c_adapter *adapter) { /* this will detect the CH7xxx chip on the specified i2c bus */ struct ch7xxx_priv *ch7xxx; @@ -196,8 +198,7 @@ static bool ch7xxx_init(struct intel_dvo_device *dvo, if (ch7xxx == NULL) return false; - dvo->i2c_bus = i2cbus; - dvo->i2c_bus->slave_addr = dvo->slave_addr; + dvo->i2c_bus = adapter; dvo->dev_priv = ch7xxx; ch7xxx->quiet = true; @@ -207,7 +208,7 @@ static bool ch7xxx_init(struct intel_dvo_device *dvo, name = ch7xxx_get_id(vendor); if (!name) { DRM_DEBUG("ch7xxx not detected; got 0x%02x from %s slave %d.\n", - vendor, i2cbus->adapter.name, i2cbus->slave_addr); + vendor, adapter->name, dvo->slave_addr); goto out; } @@ -217,7 +218,7 @@ static bool ch7xxx_init(struct intel_dvo_device *dvo, if (device != CH7xxx_DID) { DRM_DEBUG("ch7xxx not detected; got 0x%02x from %s slave %d.\n", - vendor, i2cbus->adapter.name, i2cbus->slave_addr); + vendor, adapter->name, dvo->slave_addr); goto out; } diff --git a/drivers/gpu/drm/i915/dvo_ivch.c b/drivers/gpu/drm/i915/dvo_ivch.c index 0c8d375e8e3..aa176f9921f 100644 --- a/drivers/gpu/drm/i915/dvo_ivch.c +++ b/drivers/gpu/drm/i915/dvo_ivch.c @@ -169,13 +169,14 @@ static void ivch_dump_regs(struct intel_dvo_device *dvo); static bool ivch_read(struct intel_dvo_device *dvo, int addr, uint16_t *data) { struct ivch_priv *priv = dvo->dev_priv; - struct intel_i2c_chan *i2cbus = dvo->i2c_bus; + struct i2c_adapter *adapter = dvo->i2c_bus; + struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter); u8 out_buf[1]; u8 in_buf[2]; struct i2c_msg msgs[] = { { - .addr = i2cbus->slave_addr, + .addr = dvo->slave_addr, .flags = I2C_M_RD, .len = 0, }, @@ -186,7 +187,7 @@ static bool ivch_read(struct intel_dvo_device *dvo, int addr, uint16_t *data) .buf = out_buf, }, { - .addr = i2cbus->slave_addr, + .addr = dvo->slave_addr, .flags = I2C_M_RD | I2C_M_NOSTART, .len = 2, .buf = in_buf, @@ -202,7 +203,7 @@ static bool ivch_read(struct intel_dvo_device *dvo, int addr, uint16_t *data) if (!priv->quiet) { DRM_DEBUG("Unable to read register 0x%02x from %s:%02x.\n", - addr, i2cbus->adapter.name, i2cbus->slave_addr); + addr, i2cbus->adapter.name, dvo->slave_addr); } return false; } @@ -211,10 +212,11 @@ static bool ivch_read(struct intel_dvo_device *dvo, int addr, uint16_t *data) static bool ivch_write(struct intel_dvo_device *dvo, int addr, uint16_t data) { struct ivch_priv *priv = dvo->dev_priv; - struct intel_i2c_chan *i2cbus = dvo->i2c_bus; + struct i2c_adapter *adapter = dvo->i2c_bus; + struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter); u8 out_buf[3]; struct i2c_msg msg = { - .addr = i2cbus->slave_addr, + .addr = dvo->slave_addr, .flags = 0, .len = 3, .buf = out_buf, @@ -229,7 +231,7 @@ static bool ivch_write(struct intel_dvo_device *dvo, int addr, uint16_t data) if (!priv->quiet) { DRM_DEBUG("Unable to write register 0x%02x to %s:%d.\n", - addr, i2cbus->adapter.name, i2cbus->slave_addr); + addr, i2cbus->adapter.name, dvo->slave_addr); } return false; @@ -237,7 +239,7 @@ static bool ivch_write(struct intel_dvo_device *dvo, int addr, uint16_t data) /** Probes the given bus and slave address for an ivch */ static bool ivch_init(struct intel_dvo_device *dvo, - struct intel_i2c_chan *i2cbus) + struct i2c_adapter *adapter) { struct ivch_priv *priv; uint16_t temp; @@ -246,8 +248,7 @@ static bool ivch_init(struct intel_dvo_device *dvo, if (priv == NULL) return false; - dvo->i2c_bus = i2cbus; - dvo->i2c_bus->slave_addr = dvo->slave_addr; + dvo->i2c_bus = adapter; dvo->dev_priv = priv; priv->quiet = true; diff --git a/drivers/gpu/drm/i915/dvo_sil164.c b/drivers/gpu/drm/i915/dvo_sil164.c index 033a4bb070b..e1c1f7341e5 100644 --- a/drivers/gpu/drm/i915/dvo_sil164.c +++ b/drivers/gpu/drm/i915/dvo_sil164.c @@ -76,19 +76,20 @@ struct sil164_priv { static bool sil164_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch) { struct sil164_priv *sil = dvo->dev_priv; - struct intel_i2c_chan *i2cbus = dvo->i2c_bus; + struct i2c_adapter *adapter = dvo->i2c_bus; + struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter); u8 out_buf[2]; u8 in_buf[2]; struct i2c_msg msgs[] = { { - .addr = i2cbus->slave_addr, + .addr = dvo->slave_addr, .flags = 0, .len = 1, .buf = out_buf, }, { - .addr = i2cbus->slave_addr, + .addr = dvo->slave_addr, .flags = I2C_M_RD, .len = 1, .buf = in_buf, @@ -105,7 +106,7 @@ static bool sil164_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch) if (!sil->quiet) { DRM_DEBUG("Unable to read register 0x%02x from %s:%02x.\n", - addr, i2cbus->adapter.name, i2cbus->slave_addr); + addr, i2cbus->adapter.name, dvo->slave_addr); } return false; } @@ -113,10 +114,11 @@ static bool sil164_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch) static bool sil164_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch) { struct sil164_priv *sil= dvo->dev_priv; - struct intel_i2c_chan *i2cbus = dvo->i2c_bus; + struct i2c_adapter *adapter = dvo->i2c_bus; + struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter); uint8_t out_buf[2]; struct i2c_msg msg = { - .addr = i2cbus->slave_addr, + .addr = dvo->slave_addr, .flags = 0, .len = 2, .buf = out_buf, @@ -130,7 +132,7 @@ static bool sil164_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch) if (!sil->quiet) { DRM_DEBUG("Unable to write register 0x%02x to %s:%d.\n", - addr, i2cbus->adapter.name, i2cbus->slave_addr); + addr, i2cbus->adapter.name, dvo->slave_addr); } return false; @@ -138,7 +140,7 @@ static bool sil164_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch) /* Silicon Image 164 driver for chip on i2c bus */ static bool sil164_init(struct intel_dvo_device *dvo, - struct intel_i2c_chan *i2cbus) + struct i2c_adapter *adapter) { /* this will detect the SIL164 chip on the specified i2c bus */ struct sil164_priv *sil; @@ -148,8 +150,7 @@ static bool sil164_init(struct intel_dvo_device *dvo, if (sil == NULL) return false; - dvo->i2c_bus = i2cbus; - dvo->i2c_bus->slave_addr = dvo->slave_addr; + dvo->i2c_bus = adapter; dvo->dev_priv = sil; sil->quiet = true; @@ -158,7 +159,7 @@ static bool sil164_init(struct intel_dvo_device *dvo, if (ch != (SIL164_VID & 0xff)) { DRM_DEBUG("sil164 not detected got %d: from %s Slave %d.\n", - ch, i2cbus->adapter.name, i2cbus->slave_addr); + ch, adapter->name, dvo->slave_addr); goto out; } @@ -167,7 +168,7 @@ static bool sil164_init(struct intel_dvo_device *dvo, if (ch != (SIL164_DID & 0xff)) { DRM_DEBUG("sil164 not detected got %d: from %s Slave %d.\n", - ch, i2cbus->adapter.name, i2cbus->slave_addr); + ch, adapter->name, dvo->slave_addr); goto out; } sil->quiet = false; diff --git a/drivers/gpu/drm/i915/dvo_tfp410.c b/drivers/gpu/drm/i915/dvo_tfp410.c index 207fda806eb..9ecc907384e 100644 --- a/drivers/gpu/drm/i915/dvo_tfp410.c +++ b/drivers/gpu/drm/i915/dvo_tfp410.c @@ -101,19 +101,20 @@ struct tfp410_priv { static bool tfp410_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch) { struct tfp410_priv *tfp = dvo->dev_priv; - struct intel_i2c_chan *i2cbus = dvo->i2c_bus; + struct i2c_adapter *adapter = dvo->i2c_bus; + struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter); u8 out_buf[2]; u8 in_buf[2]; struct i2c_msg msgs[] = { { - .addr = i2cbus->slave_addr, + .addr = dvo->slave_addr, .flags = 0, .len = 1, .buf = out_buf, }, { - .addr = i2cbus->slave_addr, + .addr = dvo->slave_addr, .flags = I2C_M_RD, .len = 1, .buf = in_buf, @@ -130,7 +131,7 @@ static bool tfp410_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch) if (!tfp->quiet) { DRM_DEBUG("Unable to read register 0x%02x from %s:%02x.\n", - addr, i2cbus->adapter.name, i2cbus->slave_addr); + addr, i2cbus->adapter.name, dvo->slave_addr); } return false; } @@ -138,10 +139,11 @@ static bool tfp410_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch) static bool tfp410_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch) { struct tfp410_priv *tfp = dvo->dev_priv; - struct intel_i2c_chan *i2cbus = dvo->i2c_bus; + struct i2c_adapter *adapter = dvo->i2c_bus; + struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter); uint8_t out_buf[2]; struct i2c_msg msg = { - .addr = i2cbus->slave_addr, + .addr = dvo->slave_addr, .flags = 0, .len = 2, .buf = out_buf, @@ -155,7 +157,7 @@ static bool tfp410_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch) if (!tfp->quiet) { DRM_DEBUG("Unable to write register 0x%02x to %s:%d.\n", - addr, i2cbus->adapter.name, i2cbus->slave_addr); + addr, i2cbus->adapter.name, dvo->slave_addr); } return false; @@ -174,7 +176,7 @@ static int tfp410_getid(struct intel_dvo_device *dvo, int addr) /* Ti TFP410 driver for chip on i2c bus */ static bool tfp410_init(struct intel_dvo_device *dvo, - struct intel_i2c_chan *i2cbus) + struct i2c_adapter *adapter) { /* this will detect the tfp410 chip on the specified i2c bus */ struct tfp410_priv *tfp; @@ -184,20 +186,19 @@ static bool tfp410_init(struct intel_dvo_device *dvo, if (tfp == NULL) return false; - dvo->i2c_bus = i2cbus; - dvo->i2c_bus->slave_addr = dvo->slave_addr; + dvo->i2c_bus = adapter; dvo->dev_priv = tfp; tfp->quiet = true; if ((id = tfp410_getid(dvo, TFP410_VID_LO)) != TFP410_VID) { DRM_DEBUG("tfp410 not detected got VID %X: from %s Slave %d.\n", - id, i2cbus->adapter.name, i2cbus->slave_addr); + id, adapter->name, dvo->slave_addr); goto out; } if ((id = tfp410_getid(dvo, TFP410_DID_LO)) != TFP410_DID) { DRM_DEBUG("tfp410 not detected got DID %X: from %s Slave %d.\n", - id, i2cbus->adapter.name, i2cbus->slave_addr); + id, adapter->name, dvo->slave_addr); goto out; } tfp->quiet = false; diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 98560e1e899..e3cb4025e32 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -67,8 +67,6 @@ static int i915_suspend(struct drm_device *dev, pm_message_t state) pci_save_state(dev->pdev); - i915_save_state(dev); - /* If KMS is active, we do the leavevt stuff here */ if (drm_core_check_feature(dev, DRIVER_MODESET)) { if (i915_gem_idle(dev)) @@ -77,6 +75,8 @@ static int i915_suspend(struct drm_device *dev, pm_message_t state) drm_irq_uninstall(dev); } + i915_save_state(dev); + intel_opregion_free(dev, 1); if (state.event == PM_EVENT_SUSPEND) { diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 7a84f04e843..bb4c2d387b6 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -306,6 +306,17 @@ typedef struct drm_i915_private { u32 saveCURBPOS; u32 saveCURBBASE; u32 saveCURSIZE; + u32 saveDP_B; + u32 saveDP_C; + u32 saveDP_D; + u32 savePIPEA_GMCH_DATA_M; + u32 savePIPEB_GMCH_DATA_M; + u32 savePIPEA_GMCH_DATA_N; + u32 savePIPEB_GMCH_DATA_N; + u32 savePIPEA_DP_LINK_M; + u32 savePIPEB_DP_LINK_M; + u32 savePIPEA_DP_LINK_N; + u32 savePIPEB_DP_LINK_N; struct { struct drm_mm gtt_space; @@ -857,6 +868,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); #define HAS_128_BYTE_Y_TILING(dev) (IS_I9XX(dev) && !(IS_I915G(dev) || \ IS_I915GM(dev))) #define SUPPORTS_INTEGRATED_HDMI(dev) (IS_G4X(dev) || IS_IGDNG(dev)) +#define SUPPORTS_INTEGRATED_DP(dev) (IS_G4X(dev) || IS_IGDNG(dev)) #define I915_HAS_HOTPLUG(dev) (IS_I945G(dev) || IS_I945GM(dev) || IS_I965G(dev)) #define PRIMARY_RINGBUFFER_SIZE (128*1024) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index fd2b8bdffe3..876b65cb762 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1006,7 +1006,7 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data, mutex_lock(&dev->struct_mutex); #if WATCH_BUF - DRM_INFO("set_domain_ioctl %p(%d), %08x %08x\n", + DRM_INFO("set_domain_ioctl %p(%zd), %08x %08x\n", obj, obj->size, read_domains, write_domain); #endif if (read_domains & I915_GEM_DOMAIN_GTT) { @@ -1050,7 +1050,7 @@ i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data, } #if WATCH_BUF - DRM_INFO("%s: sw_finish %d (%p %d)\n", + DRM_INFO("%s: sw_finish %d (%p %zd)\n", __func__, args->handle, obj, obj->size); #endif obj_priv = obj->driver_private; @@ -2423,7 +2423,7 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment) } #if WATCH_BUF - DRM_INFO("Binding object of size %d at 0x%08x\n", + DRM_INFO("Binding object of size %zd at 0x%08x\n", obj->size, obj_priv->gtt_offset); #endif ret = i915_gem_object_get_pages(obj); @@ -4227,6 +4227,7 @@ i915_gem_lastclose(struct drm_device *dev) void i915_gem_load(struct drm_device *dev) { + int i; drm_i915_private_t *dev_priv = dev->dev_private; spin_lock_init(&dev_priv->mm.active_list_lock); @@ -4246,6 +4247,18 @@ i915_gem_load(struct drm_device *dev) else dev_priv->num_fence_regs = 8; + /* Initialize fence registers to zero */ + if (IS_I965G(dev)) { + for (i = 0; i < 16; i++) + I915_WRITE64(FENCE_REG_965_0 + (i * 8), 0); + } else { + for (i = 0; i < 8; i++) + I915_WRITE(FENCE_REG_830_0 + (i * 4), 0); + if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) + for (i = 0; i < 8; i++) + I915_WRITE(FENCE_REG_945_8 + (i * 4), 0); + } + i915_gem_detect_bit_6_swizzle(dev); } diff --git a/drivers/gpu/drm/i915/i915_gem_debug.c b/drivers/gpu/drm/i915/i915_gem_debug.c index 8d0b943e2c5..e602614bd3f 100644 --- a/drivers/gpu/drm/i915/i915_gem_debug.c +++ b/drivers/gpu/drm/i915/i915_gem_debug.c @@ -87,7 +87,7 @@ i915_gem_dump_object(struct drm_gem_object *obj, int len, chunk_len = page_len - chunk; if (chunk_len > 128) chunk_len = 128; - i915_gem_dump_page(obj_priv->page_list[page], + i915_gem_dump_page(obj_priv->pages[page], chunk, chunk + chunk_len, obj_priv->gtt_offset + page * PAGE_SIZE, @@ -143,7 +143,7 @@ i915_gem_object_check_coherency(struct drm_gem_object *obj, int handle) uint32_t *backing_map = NULL; int bad_count = 0; - DRM_INFO("%s: checking coherency of object %p@0x%08x (%d, %dkb):\n", + DRM_INFO("%s: checking coherency of object %p@0x%08x (%d, %zdkb):\n", __func__, obj, obj_priv->gtt_offset, handle, obj->size / 1024); @@ -157,7 +157,7 @@ i915_gem_object_check_coherency(struct drm_gem_object *obj, int handle) for (page = 0; page < obj->size / PAGE_SIZE; page++) { int i; - backing_map = kmap_atomic(obj_priv->page_list[page], KM_USER0); + backing_map = kmap_atomic(obj_priv->pages[page], KM_USER0); if (backing_map == NULL) { DRM_ERROR("failed to map backing page\n"); diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c index 5c1ceec49f5..daeae62e1c2 100644 --- a/drivers/gpu/drm/i915/i915_gem_tiling.c +++ b/drivers/gpu/drm/i915/i915_gem_tiling.c @@ -114,11 +114,13 @@ intel_alloc_mchbar_resource(struct drm_device *dev) mchbar_addr = ((u64)temp_hi << 32) | temp_lo; /* If ACPI doesn't have it, assume we need to allocate it ourselves */ +#ifdef CONFIG_PNP if (mchbar_addr && pnp_range_reserved(mchbar_addr, mchbar_addr + MCHBAR_SIZE)) { ret = 0; goto out_put; } +#endif /* Get some space for it */ ret = pci_bus_alloc_resource(bridge_dev->bus, &dev_priv->mch_res, diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index b86b7b7130c..228546f6eaa 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -232,7 +232,17 @@ static void i915_hotplug_work_func(struct work_struct *work) drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t, hotplug_work); struct drm_device *dev = dev_priv->dev; - + struct drm_mode_config *mode_config = &dev->mode_config; + struct drm_connector *connector; + + if (mode_config->num_connector) { + list_for_each_entry(connector, &mode_config->connector_list, head) { + struct intel_output *intel_output = to_intel_output(connector); + + if (intel_output->hot_plug) + (*intel_output->hot_plug) (intel_output); + } + } /* Just fire off a uevent and let userspace tell us what to do */ drm_sysfs_hotplug_event(dev); } diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index f6237a0b113..88bf7521405 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -569,6 +569,19 @@ #define C0DRB3 0x10206 #define C1DRB3 0x10606 +/* Clocking configuration register */ +#define CLKCFG 0x10c00 +#define CLKCFG_FSB_400 (0 << 0) /* hrawclk 100 */ +#define CLKCFG_FSB_533 (1 << 0) /* hrawclk 133 */ +#define CLKCFG_FSB_667 (3 << 0) /* hrawclk 166 */ +#define CLKCFG_FSB_800 (2 << 0) /* hrawclk 200 */ +#define CLKCFG_FSB_1067 (6 << 0) /* hrawclk 266 */ +#define CLKCFG_FSB_1333 (7 << 0) /* hrawclk 333 */ +/* this is a guess, could be 5 as well */ +#define CLKCFG_FSB_1600 (4 << 0) /* hrawclk 400 */ +#define CLKCFG_FSB_1600_ALT (5 << 0) /* hrawclk 400 */ +#define CLKCFG_FSB_MASK (7 << 0) + /** GM965 GM45 render standby register */ #define MCHBAR_RENDER_STANDBY 0x111B8 @@ -834,9 +847,25 @@ #define HORIZ_INTERP_MASK (3 << 6) #define HORIZ_AUTO_SCALE (1 << 5) #define PANEL_8TO6_DITHER_ENABLE (1 << 3) +#define PFIT_FILTER_FUZZY (0 << 24) +#define PFIT_SCALING_AUTO (0 << 26) +#define PFIT_SCALING_PROGRAMMED (1 << 26) +#define PFIT_SCALING_PILLAR (2 << 26) +#define PFIT_SCALING_LETTER (3 << 26) #define PFIT_PGM_RATIOS 0x61234 #define PFIT_VERT_SCALE_MASK 0xfff00000 #define PFIT_HORIZ_SCALE_MASK 0x0000fff0 +/* Pre-965 */ +#define PFIT_VERT_SCALE_SHIFT 20 +#define PFIT_VERT_SCALE_MASK 0xfff00000 +#define PFIT_HORIZ_SCALE_SHIFT 4 +#define PFIT_HORIZ_SCALE_MASK 0x0000fff0 +/* 965+ */ +#define PFIT_VERT_SCALE_SHIFT_965 16 +#define PFIT_VERT_SCALE_MASK_965 0x1fff0000 +#define PFIT_HORIZ_SCALE_SHIFT_965 0 +#define PFIT_HORIZ_SCALE_MASK_965 0x00001fff + #define PFIT_AUTO_RATIOS 0x61238 /* Backlight control */ diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index a98e2831ed3..8d8e083d14a 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -322,6 +322,20 @@ int i915_save_state(struct drm_device *dev) dev_priv->savePP_OFF_DELAYS = I915_READ(PP_OFF_DELAYS); dev_priv->savePP_DIVISOR = I915_READ(PP_DIVISOR); + /* Display Port state */ + if (SUPPORTS_INTEGRATED_DP(dev)) { + dev_priv->saveDP_B = I915_READ(DP_B); + dev_priv->saveDP_C = I915_READ(DP_C); + dev_priv->saveDP_D = I915_READ(DP_D); + dev_priv->savePIPEA_GMCH_DATA_M = I915_READ(PIPEA_GMCH_DATA_M); + dev_priv->savePIPEB_GMCH_DATA_M = I915_READ(PIPEB_GMCH_DATA_M); + dev_priv->savePIPEA_GMCH_DATA_N = I915_READ(PIPEA_GMCH_DATA_N); + dev_priv->savePIPEB_GMCH_DATA_N = I915_READ(PIPEB_GMCH_DATA_N); + dev_priv->savePIPEA_DP_LINK_M = I915_READ(PIPEA_DP_LINK_M); + dev_priv->savePIPEB_DP_LINK_M = I915_READ(PIPEB_DP_LINK_M); + dev_priv->savePIPEA_DP_LINK_N = I915_READ(PIPEA_DP_LINK_N); + dev_priv->savePIPEB_DP_LINK_N = I915_READ(PIPEB_DP_LINK_N); + } /* FIXME: save TV & SDVO state */ /* FBC state */ @@ -404,7 +418,19 @@ int i915_restore_state(struct drm_device *dev) for (i = 0; i < 8; i++) I915_WRITE(FENCE_REG_945_8 + (i * 4), dev_priv->saveFENCE[i+8]); } - + + /* Display port ratios (must be done before clock is set) */ + if (SUPPORTS_INTEGRATED_DP(dev)) { + I915_WRITE(PIPEA_GMCH_DATA_M, dev_priv->savePIPEA_GMCH_DATA_M); + I915_WRITE(PIPEB_GMCH_DATA_M, dev_priv->savePIPEB_GMCH_DATA_M); + I915_WRITE(PIPEA_GMCH_DATA_N, dev_priv->savePIPEA_GMCH_DATA_N); + I915_WRITE(PIPEB_GMCH_DATA_N, dev_priv->savePIPEB_GMCH_DATA_N); + I915_WRITE(PIPEA_DP_LINK_M, dev_priv->savePIPEA_DP_LINK_M); + I915_WRITE(PIPEB_DP_LINK_M, dev_priv->savePIPEB_DP_LINK_M); + I915_WRITE(PIPEA_DP_LINK_N, dev_priv->savePIPEA_DP_LINK_N); + I915_WRITE(PIPEB_DP_LINK_N, dev_priv->savePIPEB_DP_LINK_N); + } + /* Pipe & plane A info */ /* Prime the clock */ if (dev_priv->saveDPLL_A & DPLL_VCO_ENABLE) { @@ -518,6 +544,12 @@ int i915_restore_state(struct drm_device *dev) I915_WRITE(PP_DIVISOR, dev_priv->savePP_DIVISOR); I915_WRITE(PP_CONTROL, dev_priv->savePP_CONTROL); + /* Display Port state */ + if (SUPPORTS_INTEGRATED_DP(dev)) { + I915_WRITE(DP_B, dev_priv->saveDP_B); + I915_WRITE(DP_C, dev_priv->saveDP_C); + I915_WRITE(DP_D, dev_priv->saveDP_D); + } /* FIXME: restore TV & SDVO state */ /* FBC info */ diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index cdd126d068a..716409a5724 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -99,9 +99,11 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv, { struct bdb_lvds_options *lvds_options; struct bdb_lvds_lfp_data *lvds_lfp_data; + struct bdb_lvds_lfp_data_ptrs *lvds_lfp_data_ptrs; struct bdb_lvds_lfp_data_entry *entry; struct lvds_dvo_timing *dvo_timing; struct drm_display_mode *panel_fixed_mode; + int lfp_data_size; /* Defaults if we can't find VBT info */ dev_priv->lvds_dither = 0; @@ -119,9 +121,17 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv, if (!lvds_lfp_data) return; + lvds_lfp_data_ptrs = find_section(bdb, BDB_LVDS_LFP_DATA_PTRS); + if (!lvds_lfp_data_ptrs) + return; + dev_priv->lvds_vbt = 1; - entry = &lvds_lfp_data->data[lvds_options->panel_type]; + lfp_data_size = lvds_lfp_data_ptrs->ptr[1].dvo_timing_offset - + lvds_lfp_data_ptrs->ptr[0].dvo_timing_offset; + entry = (struct bdb_lvds_lfp_data_entry *) + ((uint8_t *)lvds_lfp_data->data + (lfp_data_size * + lvds_options->panel_type)); dvo_timing = &entry->dvo_timing; panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), GFP_KERNEL); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3e1c7816211..73e7b9cecac 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -29,6 +29,7 @@ #include "intel_drv.h" #include "i915_drm.h" #include "i915_drv.h" +#include "intel_dp.h" #include "drm_crtc_helper.h" @@ -127,19 +128,6 @@ struct intel_limit { #define I9XX_P2_LVDS_FAST 7 #define I9XX_P2_LVDS_SLOW_LIMIT 112000 -#define INTEL_LIMIT_I8XX_DVO_DAC 0 -#define INTEL_LIMIT_I8XX_LVDS 1 -#define INTEL_LIMIT_I9XX_SDVO_DAC 2 -#define INTEL_LIMIT_I9XX_LVDS 3 -#define INTEL_LIMIT_G4X_SDVO 4 -#define INTEL_LIMIT_G4X_HDMI_DAC 5 -#define INTEL_LIMIT_G4X_SINGLE_CHANNEL_LVDS 6 -#define INTEL_LIMIT_G4X_DUAL_CHANNEL_LVDS 7 -#define INTEL_LIMIT_IGD_SDVO_DAC 8 -#define INTEL_LIMIT_IGD_LVDS 9 -#define INTEL_LIMIT_IGDNG_SDVO_DAC 10 -#define INTEL_LIMIT_IGDNG_LVDS 11 - /*The parameter is for SDVO on G4x platform*/ #define G4X_DOT_SDVO_MIN 25000 #define G4X_DOT_SDVO_MAX 270000 @@ -218,6 +206,25 @@ struct intel_limit { #define G4X_P2_DUAL_CHANNEL_LVDS_FAST 7 #define G4X_P2_DUAL_CHANNEL_LVDS_LIMIT 0 +/*The parameter is for DISPLAY PORT on G4x platform*/ +#define G4X_DOT_DISPLAY_PORT_MIN 161670 +#define G4X_DOT_DISPLAY_PORT_MAX 227000 +#define G4X_N_DISPLAY_PORT_MIN 1 +#define G4X_N_DISPLAY_PORT_MAX 2 +#define G4X_M_DISPLAY_PORT_MIN 97 +#define G4X_M_DISPLAY_PORT_MAX 108 +#define G4X_M1_DISPLAY_PORT_MIN 0x10 +#define G4X_M1_DISPLAY_PORT_MAX 0x12 +#define G4X_M2_DISPLAY_PORT_MIN 0x05 +#define G4X_M2_DISPLAY_PORT_MAX 0x06 +#define G4X_P_DISPLAY_PORT_MIN 10 +#define G4X_P_DISPLAY_PORT_MAX 20 +#define G4X_P1_DISPLAY_PORT_MIN 1 +#define G4X_P1_DISPLAY_PORT_MAX 2 +#define G4X_P2_DISPLAY_PORT_SLOW 10 +#define G4X_P2_DISPLAY_PORT_FAST 10 +#define G4X_P2_DISPLAY_PORT_LIMIT 0 + /* IGDNG */ /* as we calculate clock using (register_value + 2) for N/M1/M2, so here the range value for them is (actual_value-2). @@ -256,8 +263,11 @@ static bool intel_igdng_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, int target, int refclk, intel_clock_t *best_clock); -static const intel_limit_t intel_limits[] = { - { /* INTEL_LIMIT_I8XX_DVO_DAC */ +static bool +intel_find_pll_g4x_dp(const intel_limit_t *, struct drm_crtc *crtc, + int target, int refclk, intel_clock_t *best_clock); + +static const intel_limit_t intel_limits_i8xx_dvo = { .dot = { .min = I8XX_DOT_MIN, .max = I8XX_DOT_MAX }, .vco = { .min = I8XX_VCO_MIN, .max = I8XX_VCO_MAX }, .n = { .min = I8XX_N_MIN, .max = I8XX_N_MAX }, @@ -269,8 +279,9 @@ static const intel_limit_t intel_limits[] = { .p2 = { .dot_limit = I8XX_P2_SLOW_LIMIT, .p2_slow = I8XX_P2_SLOW, .p2_fast = I8XX_P2_FAST }, .find_pll = intel_find_best_PLL, - }, - { /* INTEL_LIMIT_I8XX_LVDS */ +}; + +static const intel_limit_t intel_limits_i8xx_lvds = { .dot = { .min = I8XX_DOT_MIN, .max = I8XX_DOT_MAX }, .vco = { .min = I8XX_VCO_MIN, .max = I8XX_VCO_MAX }, .n = { .min = I8XX_N_MIN, .max = I8XX_N_MAX }, @@ -282,8 +293,9 @@ static const intel_limit_t intel_limits[] = { .p2 = { .dot_limit = I8XX_P2_SLOW_LIMIT, .p2_slow = I8XX_P2_LVDS_SLOW, .p2_fast = I8XX_P2_LVDS_FAST }, .find_pll = intel_find_best_PLL, - }, - { /* INTEL_LIMIT_I9XX_SDVO_DAC */ +}; + +static const intel_limit_t intel_limits_i9xx_sdvo = { .dot = { .min = I9XX_DOT_MIN, .max = I9XX_DOT_MAX }, .vco = { .min = I9XX_VCO_MIN, .max = I9XX_VCO_MAX }, .n = { .min = I9XX_N_MIN, .max = I9XX_N_MAX }, @@ -295,8 +307,9 @@ static const intel_limit_t intel_limits[] = { .p2 = { .dot_limit = I9XX_P2_SDVO_DAC_SLOW_LIMIT, .p2_slow = I9XX_P2_SDVO_DAC_SLOW, .p2_fast = I9XX_P2_SDVO_DAC_FAST }, .find_pll = intel_find_best_PLL, - }, - { /* INTEL_LIMIT_I9XX_LVDS */ +}; + +static const intel_limit_t intel_limits_i9xx_lvds = { .dot = { .min = I9XX_DOT_MIN, .max = I9XX_DOT_MAX }, .vco = { .min = I9XX_VCO_MIN, .max = I9XX_VCO_MAX }, .n = { .min = I9XX_N_MIN, .max = I9XX_N_MAX }, @@ -311,9 +324,10 @@ static const intel_limit_t intel_limits[] = { .p2 = { .dot_limit = I9XX_P2_LVDS_SLOW_LIMIT, .p2_slow = I9XX_P2_LVDS_SLOW, .p2_fast = I9XX_P2_LVDS_FAST }, .find_pll = intel_find_best_PLL, - }, +}; + /* below parameter and function is for G4X Chipset Family*/ - { /* INTEL_LIMIT_G4X_SDVO */ +static const intel_limit_t intel_limits_g4x_sdvo = { .dot = { .min = G4X_DOT_SDVO_MIN, .max = G4X_DOT_SDVO_MAX }, .vco = { .min = G4X_VCO_MIN, .max = G4X_VCO_MAX}, .n = { .min = G4X_N_SDVO_MIN, .max = G4X_N_SDVO_MAX }, @@ -327,8 +341,9 @@ static const intel_limit_t intel_limits[] = { .p2_fast = G4X_P2_SDVO_FAST }, .find_pll = intel_g4x_find_best_PLL, - }, - { /* INTEL_LIMIT_G4X_HDMI_DAC */ +}; + +static const intel_limit_t intel_limits_g4x_hdmi = { .dot = { .min = G4X_DOT_HDMI_DAC_MIN, .max = G4X_DOT_HDMI_DAC_MAX }, .vco = { .min = G4X_VCO_MIN, .max = G4X_VCO_MAX}, .n = { .min = G4X_N_HDMI_DAC_MIN, .max = G4X_N_HDMI_DAC_MAX }, @@ -342,8 +357,9 @@ static const intel_limit_t intel_limits[] = { .p2_fast = G4X_P2_HDMI_DAC_FAST }, .find_pll = intel_g4x_find_best_PLL, - }, - { /* INTEL_LIMIT_G4X_SINGLE_CHANNEL_LVDS */ +}; + +static const intel_limit_t intel_limits_g4x_single_channel_lvds = { .dot = { .min = G4X_DOT_SINGLE_CHANNEL_LVDS_MIN, .max = G4X_DOT_SINGLE_CHANNEL_LVDS_MAX }, .vco = { .min = G4X_VCO_MIN, @@ -365,8 +381,9 @@ static const intel_limit_t intel_limits[] = { .p2_fast = G4X_P2_SINGLE_CHANNEL_LVDS_FAST }, .find_pll = intel_g4x_find_best_PLL, - }, - { /* INTEL_LIMIT_G4X_DUAL_CHANNEL_LVDS */ +}; + +static const intel_limit_t intel_limits_g4x_dual_channel_lvds = { .dot = { .min = G4X_DOT_DUAL_CHANNEL_LVDS_MIN, .max = G4X_DOT_DUAL_CHANNEL_LVDS_MAX }, .vco = { .min = G4X_VCO_MIN, @@ -388,8 +405,32 @@ static const intel_limit_t intel_limits[] = { .p2_fast = G4X_P2_DUAL_CHANNEL_LVDS_FAST }, .find_pll = intel_g4x_find_best_PLL, - }, - { /* INTEL_LIMIT_IGD_SDVO */ +}; + +static const intel_limit_t intel_limits_g4x_display_port = { + .dot = { .min = G4X_DOT_DISPLAY_PORT_MIN, + .max = G4X_DOT_DISPLAY_PORT_MAX }, + .vco = { .min = G4X_VCO_MIN, + .max = G4X_VCO_MAX}, + .n = { .min = G4X_N_DISPLAY_PORT_MIN, + .max = G4X_N_DISPLAY_PORT_MAX }, + .m = { .min = G4X_M_DISPLAY_PORT_MIN, + .max = G4X_M_DISPLAY_PORT_MAX }, + .m1 = { .min = G4X_M1_DISPLAY_PORT_MIN, + .max = G4X_M1_DISPLAY_PORT_MAX }, + .m2 = { .min = G4X_M2_DISPLAY_PORT_MIN, + .max = G4X_M2_DISPLAY_PORT_MAX }, + .p = { .min = G4X_P_DISPLAY_PORT_MIN, + .max = G4X_P_DISPLAY_PORT_MAX }, + .p1 = { .min = G4X_P1_DISPLAY_PORT_MIN, + .max = G4X_P1_DISPLAY_PORT_MAX}, + .p2 = { .dot_limit = G4X_P2_DISPLAY_PORT_LIMIT, + .p2_slow = G4X_P2_DISPLAY_PORT_SLOW, + .p2_fast = G4X_P2_DISPLAY_PORT_FAST }, + .find_pll = intel_find_pll_g4x_dp, +}; + +static const intel_limit_t intel_limits_igd_sdvo = { .dot = { .min = I9XX_DOT_MIN, .max = I9XX_DOT_MAX}, .vco = { .min = IGD_VCO_MIN, .max = IGD_VCO_MAX }, .n = { .min = IGD_N_MIN, .max = IGD_N_MAX }, @@ -401,8 +442,9 @@ static const intel_limit_t intel_limits[] = { .p2 = { .dot_limit = I9XX_P2_SDVO_DAC_SLOW_LIMIT, .p2_slow = I9XX_P2_SDVO_DAC_SLOW, .p2_fast = I9XX_P2_SDVO_DAC_FAST }, .find_pll = intel_find_best_PLL, - }, - { /* INTEL_LIMIT_IGD_LVDS */ +}; + +static const intel_limit_t intel_limits_igd_lvds = { .dot = { .min = I9XX_DOT_MIN, .max = I9XX_DOT_MAX }, .vco = { .min = IGD_VCO_MIN, .max = IGD_VCO_MAX }, .n = { .min = IGD_N_MIN, .max = IGD_N_MAX }, @@ -415,8 +457,9 @@ static const intel_limit_t intel_limits[] = { .p2 = { .dot_limit = I9XX_P2_LVDS_SLOW_LIMIT, .p2_slow = I9XX_P2_LVDS_SLOW, .p2_fast = I9XX_P2_LVDS_SLOW }, .find_pll = intel_find_best_PLL, - }, - { /* INTEL_LIMIT_IGDNG_SDVO_DAC */ +}; + +static const intel_limit_t intel_limits_igdng_sdvo = { .dot = { .min = IGDNG_DOT_MIN, .max = IGDNG_DOT_MAX }, .vco = { .min = IGDNG_VCO_MIN, .max = IGDNG_VCO_MAX }, .n = { .min = IGDNG_N_MIN, .max = IGDNG_N_MAX }, @@ -429,8 +472,9 @@ static const intel_limit_t intel_limits[] = { .p2_slow = IGDNG_P2_SDVO_DAC_SLOW, .p2_fast = IGDNG_P2_SDVO_DAC_FAST }, .find_pll = intel_igdng_find_best_PLL, - }, - { /* INTEL_LIMIT_IGDNG_LVDS */ +}; + +static const intel_limit_t intel_limits_igdng_lvds = { .dot = { .min = IGDNG_DOT_MIN, .max = IGDNG_DOT_MAX }, .vco = { .min = IGDNG_VCO_MIN, .max = IGDNG_VCO_MAX }, .n = { .min = IGDNG_N_MIN, .max = IGDNG_N_MAX }, @@ -443,16 +487,15 @@ static const intel_limit_t intel_limits[] = { .p2_slow = IGDNG_P2_LVDS_SLOW, .p2_fast = IGDNG_P2_LVDS_FAST }, .find_pll = intel_igdng_find_best_PLL, - }, }; static const intel_limit_t *intel_igdng_limit(struct drm_crtc *crtc) { const intel_limit_t *limit; if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) - limit = &intel_limits[INTEL_LIMIT_IGDNG_LVDS]; + limit = &intel_limits_igdng_lvds; else - limit = &intel_limits[INTEL_LIMIT_IGDNG_SDVO_DAC]; + limit = &intel_limits_igdng_sdvo; return limit; } @@ -467,19 +510,19 @@ static const intel_limit_t *intel_g4x_limit(struct drm_crtc *crtc) if ((I915_READ(LVDS) & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP) /* LVDS with dual channel */ - limit = &intel_limits - [INTEL_LIMIT_G4X_DUAL_CHANNEL_LVDS]; + limit = &intel_limits_g4x_dual_channel_lvds; else /* LVDS with dual channel */ - limit = &intel_limits - [INTEL_LIMIT_G4X_SINGLE_CHANNEL_LVDS]; + limit = &intel_limits_g4x_single_channel_lvds; } else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_HDMI) || intel_pipe_has_type(crtc, INTEL_OUTPUT_ANALOG)) { - limit = &intel_limits[INTEL_LIMIT_G4X_HDMI_DAC]; + limit = &intel_limits_g4x_hdmi; } else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_SDVO)) { - limit = &intel_limits[INTEL_LIMIT_G4X_SDVO]; + limit = &intel_limits_g4x_sdvo; + } else if (intel_pipe_has_type (crtc, INTEL_OUTPUT_DISPLAYPORT)) { + limit = &intel_limits_g4x_display_port; } else /* The option is for other outputs */ - limit = &intel_limits[INTEL_LIMIT_I9XX_SDVO_DAC]; + limit = &intel_limits_i9xx_sdvo; return limit; } @@ -495,19 +538,19 @@ static const intel_limit_t *intel_limit(struct drm_crtc *crtc) limit = intel_g4x_limit(crtc); } else if (IS_I9XX(dev) && !IS_IGD(dev)) { if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) - limit = &intel_limits[INTEL_LIMIT_I9XX_LVDS]; + limit = &intel_limits_i9xx_lvds; else - limit = &intel_limits[INTEL_LIMIT_I9XX_SDVO_DAC]; + limit = &intel_limits_i9xx_sdvo; } else if (IS_IGD(dev)) { if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) - limit = &intel_limits[INTEL_LIMIT_IGD_LVDS]; + limit = &intel_limits_igd_lvds; else - limit = &intel_limits[INTEL_LIMIT_IGD_SDVO_DAC]; + limit = &intel_limits_igd_sdvo; } else { if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) - limit = &intel_limits[INTEL_LIMIT_I8XX_LVDS]; + limit = &intel_limits_i8xx_lvds; else - limit = &intel_limits[INTEL_LIMIT_I8XX_DVO_DAC]; + limit = &intel_limits_i8xx_dvo; } return limit; } @@ -764,6 +807,35 @@ out: return found; } +/* DisplayPort has only two frequencies, 162MHz and 270MHz */ +static bool +intel_find_pll_g4x_dp(const intel_limit_t *limit, struct drm_crtc *crtc, + int target, int refclk, intel_clock_t *best_clock) +{ + intel_clock_t clock; + if (target < 200000) { + clock.dot = 161670; + clock.p = 20; + clock.p1 = 2; + clock.p2 = 10; + clock.n = 0x01; + clock.m = 97; + clock.m1 = 0x10; + clock.m2 = 0x05; + } else { + clock.dot = 270000; + clock.p = 10; + clock.p1 = 1; + clock.p2 = 10; + clock.n = 0x02; + clock.m = 108; + clock.m1 = 0x12; + clock.m2 = 0x06; + } + memcpy(best_clock, &clock, sizeof(intel_clock_t)); + return true; +} + void intel_wait_for_vblank(struct drm_device *dev) { @@ -1541,7 +1613,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, intel_clock_t clock; u32 dpll = 0, fp = 0, dspcntr, pipeconf; bool ok, is_sdvo = false, is_dvo = false; - bool is_crt = false, is_lvds = false, is_tv = false; + bool is_crt = false, is_lvds = false, is_tv = false, is_dp = false; struct drm_mode_config *mode_config = &dev->mode_config; struct drm_connector *connector; const intel_limit_t *limit; @@ -1585,6 +1657,9 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, case INTEL_OUTPUT_ANALOG: is_crt = true; break; + case INTEL_OUTPUT_DISPLAYPORT: + is_dp = true; + break; } num_outputs++; @@ -1600,6 +1675,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, } else { refclk = 48000; } + /* * Returns a set of divisors for the desired target clock with the given @@ -1662,6 +1738,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, else if (IS_IGDNG(dev)) dpll |= (sdvo_pixel_multiply - 1) << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT; } + if (is_dp) + dpll |= DPLL_DVO_HIGH_SPEED; /* compute bitmask from p1 value */ if (IS_IGD(dev)) @@ -1809,6 +1887,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, I915_WRITE(lvds_reg, lvds); I915_READ(lvds_reg); } + if (is_dp) + intel_dp_set_m_n(crtc, mode, adjusted_mode); I915_WRITE(fp_reg, fp); I915_WRITE(dpll_reg, dpll); @@ -2475,6 +2555,8 @@ static void intel_setup_outputs(struct drm_device *dev) found = intel_sdvo_init(dev, SDVOB); if (!found && SUPPORTS_INTEGRATED_HDMI(dev)) intel_hdmi_init(dev, SDVOB); + if (!found && SUPPORTS_INTEGRATED_DP(dev)) + intel_dp_init(dev, DP_B); } /* Before G4X SDVOC doesn't have its own detect register */ @@ -2487,7 +2569,11 @@ static void intel_setup_outputs(struct drm_device *dev) found = intel_sdvo_init(dev, SDVOC); if (!found && SUPPORTS_INTEGRATED_HDMI(dev)) intel_hdmi_init(dev, SDVOC); + if (!found && SUPPORTS_INTEGRATED_DP(dev)) + intel_dp_init(dev, DP_C); } + if (SUPPORTS_INTEGRATED_DP(dev) && (I915_READ(DP_D) & DP_DETECTED)) + intel_dp_init(dev, DP_D); } else intel_dvo_init(dev); @@ -2530,6 +2616,11 @@ static void intel_setup_outputs(struct drm_device *dev) (1 << 1)); clone_mask = (1 << INTEL_OUTPUT_TVOUT); break; + case INTEL_OUTPUT_DISPLAYPORT: + crtc_mask = ((1 << 0) | + (1 << 1)); + clone_mask = (1 << INTEL_OUTPUT_DISPLAYPORT); + break; } encoder->possible_crtcs = crtc_mask; encoder->possible_clones = intel_connector_clones(dev, clone_mask); diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c new file mode 100644 index 00000000000..8f8d37d5663 --- /dev/null +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -0,0 +1,1153 @@ +/* + * Copyright © 2008 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Authors: + * Keith Packard <keithp@keithp.com> + * + */ + +#include <linux/i2c.h> +#include "drmP.h" +#include "drm.h" +#include "drm_crtc.h" +#include "drm_crtc_helper.h" +#include "intel_drv.h" +#include "i915_drm.h" +#include "i915_drv.h" +#include "intel_dp.h" + +#define DP_LINK_STATUS_SIZE 6 +#define DP_LINK_CHECK_TIMEOUT (10 * 1000) + +#define DP_LINK_CONFIGURATION_SIZE 9 + +struct intel_dp_priv { + uint32_t output_reg; + uint32_t DP; + uint8_t link_configuration[DP_LINK_CONFIGURATION_SIZE]; + uint32_t save_DP; + uint8_t save_link_configuration[DP_LINK_CONFIGURATION_SIZE]; + bool has_audio; + int dpms_mode; + uint8_t link_bw; + uint8_t lane_count; + uint8_t dpcd[4]; + struct intel_output *intel_output; + struct i2c_adapter adapter; + struct i2c_algo_dp_aux_data algo; +}; + +static void +intel_dp_link_train(struct intel_output *intel_output, uint32_t DP, + uint8_t link_configuration[DP_LINK_CONFIGURATION_SIZE]); + +static void +intel_dp_link_down(struct intel_output *intel_output, uint32_t DP); + +static int +intel_dp_max_lane_count(struct intel_output *intel_output) +{ + struct intel_dp_priv *dp_priv = intel_output->dev_priv; + int max_lane_count = 4; + + if (dp_priv->dpcd[0] >= 0x11) { + max_lane_count = dp_priv->dpcd[2] & 0x1f; + switch (max_lane_count) { + case 1: case 2: case 4: + break; + default: + max_lane_count = 4; + } + } + return max_lane_count; +} + +static int +intel_dp_max_link_bw(struct intel_output *intel_output) +{ + struct intel_dp_priv *dp_priv = intel_output->dev_priv; + int max_link_bw = dp_priv->dpcd[1]; + + switch (max_link_bw) { + case DP_LINK_BW_1_62: + case DP_LINK_BW_2_7: + break; + default: + max_link_bw = DP_LINK_BW_1_62; + break; + } + return max_link_bw; +} + +static int +intel_dp_link_clock(uint8_t link_bw) +{ + if (link_bw == DP_LINK_BW_2_7) + return 270000; + else + return 162000; +} + +/* I think this is a fiction */ +static int +intel_dp_link_required(int pixel_clock) +{ + return pixel_clock * 3; +} + +static int +intel_dp_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) +{ + struct intel_output *intel_output = to_intel_output(connector); + int max_link_clock = intel_dp_link_clock(intel_dp_max_link_bw(intel_output)); + int max_lanes = intel_dp_max_lane_count(intel_output); + + if (intel_dp_link_required(mode->clock) > max_link_clock * max_lanes) + return MODE_CLOCK_HIGH; + + if (mode->clock < 10000) + return MODE_CLOCK_LOW; + + return MODE_OK; +} + +static uint32_t +pack_aux(uint8_t *src, int src_bytes) +{ + int i; + uint32_t v = 0; + + if (src_bytes > 4) + src_bytes = 4; + for (i = 0; i < src_bytes; i++) + v |= ((uint32_t) src[i]) << ((3-i) * 8); + return v; +} + +static void +unpack_aux(uint32_t src, uint8_t *dst, int dst_bytes) +{ + int i; + if (dst_bytes > 4) + dst_bytes = 4; + for (i = 0; i < dst_bytes; i++) + dst[i] = src >> ((3-i) * 8); +} + +/* hrawclock is 1/4 the FSB frequency */ +static int +intel_hrawclk(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t clkcfg; + + clkcfg = I915_READ(CLKCFG); + switch (clkcfg & CLKCFG_FSB_MASK) { + case CLKCFG_FSB_400: + return 100; + case CLKCFG_FSB_533: + return 133; + case CLKCFG_FSB_667: + return 166; + case CLKCFG_FSB_800: + return 200; + case CLKCFG_FSB_1067: + return 266; + case CLKCFG_FSB_1333: + return 333; + /* these two are just a guess; one of them might be right */ + case CLKCFG_FSB_1600: + case CLKCFG_FSB_1600_ALT: + return 400; + default: + return 133; + } +} + +static int +intel_dp_aux_ch(struct intel_output *intel_output, + uint8_t *send, int send_bytes, + uint8_t *recv, int recv_size) +{ + struct intel_dp_priv *dp_priv = intel_output->dev_priv; + uint32_t output_reg = dp_priv->output_reg; + struct drm_device *dev = intel_output->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t ch_ctl = output_reg + 0x10; + uint32_t ch_data = ch_ctl + 4; + int i; + int recv_bytes; + uint32_t ctl; + uint32_t status; + uint32_t aux_clock_divider; + int try; + + /* The clock divider is based off the hrawclk, + * and would like to run at 2MHz. So, take the + * hrawclk value and divide by 2 and use that + */ + aux_clock_divider = intel_hrawclk(dev) / 2; + /* Must try at least 3 times according to DP spec */ + for (try = 0; try < 5; try++) { + /* Load the send data into the aux channel data registers */ + for (i = 0; i < send_bytes; i += 4) { + uint32_t d = pack_aux(send + i, send_bytes - i);; + + I915_WRITE(ch_data + i, d); + } + + ctl = (DP_AUX_CH_CTL_SEND_BUSY | + DP_AUX_CH_CTL_TIME_OUT_400us | + (send_bytes << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) | + (5 << DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT) | + (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT) | + DP_AUX_CH_CTL_DONE | + DP_AUX_CH_CTL_TIME_OUT_ERROR | + DP_AUX_CH_CTL_RECEIVE_ERROR); + + /* Send the command and wait for it to complete */ + I915_WRITE(ch_ctl, ctl); + (void) I915_READ(ch_ctl); + for (;;) { + udelay(100); + status = I915_READ(ch_ctl); + if ((status & DP_AUX_CH_CTL_SEND_BUSY) == 0) + break; + } + + /* Clear done status and any errors */ + I915_WRITE(ch_ctl, (ctl | + DP_AUX_CH_CTL_DONE | + DP_AUX_CH_CTL_TIME_OUT_ERROR | + DP_AUX_CH_CTL_RECEIVE_ERROR)); + (void) I915_READ(ch_ctl); + if ((status & DP_AUX_CH_CTL_TIME_OUT_ERROR) == 0) + break; + } + + if ((status & DP_AUX_CH_CTL_DONE) == 0) { + printk(KERN_ERR "dp_aux_ch not done status 0x%08x\n", status); + return -EBUSY; + } + + /* Check for timeout or receive error. + * Timeouts occur when the sink is not connected + */ + if (status & DP_AUX_CH_CTL_RECEIVE_ERROR) { + printk(KERN_ERR "dp_aux_ch receive error status 0x%08x\n", status); + return -EIO; + } + if (status & DP_AUX_CH_CTL_TIME_OUT_ERROR) { + printk(KERN_ERR "dp_aux_ch timeout status 0x%08x\n", status); + return -ETIMEDOUT; + } + + /* Unload any bytes sent back from the other side */ + recv_bytes = ((status & DP_AUX_CH_CTL_MESSAGE_SIZE_MASK) >> + DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT); + + if (recv_bytes > recv_size) + recv_bytes = recv_size; + + for (i = 0; i < recv_bytes; i += 4) { + uint32_t d = I915_READ(ch_data + i); + + unpack_aux(d, recv + i, recv_bytes - i); + } + + return recv_bytes; +} + +/* Write data to the aux channel in native mode */ +static int +intel_dp_aux_native_write(struct intel_output *intel_output, + uint16_t address, uint8_t *send, int send_bytes) +{ + int ret; + uint8_t msg[20]; + int msg_bytes; + uint8_t ack; + + if (send_bytes > 16) + return -1; + msg[0] = AUX_NATIVE_WRITE << 4; + msg[1] = address >> 8; + msg[2] = address; + msg[3] = send_bytes - 1; + memcpy(&msg[4], send, send_bytes); + msg_bytes = send_bytes + 4; + for (;;) { + ret = intel_dp_aux_ch(intel_output, msg, msg_bytes, &ack, 1); + if (ret < 0) + return ret; + if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_ACK) + break; + else if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_DEFER) + udelay(100); + else + return -EIO; + } + return send_bytes; +} + +/* Write a single byte to the aux channel in native mode */ +static int +intel_dp_aux_native_write_1(struct intel_output *intel_output, + uint16_t address, uint8_t byte) +{ + return intel_dp_aux_native_write(intel_output, address, &byte, 1); +} + +/* read bytes from a native aux channel */ +static int +intel_dp_aux_native_read(struct intel_output *intel_output, + uint16_t address, uint8_t *recv, int recv_bytes) +{ + uint8_t msg[4]; + int msg_bytes; + uint8_t reply[20]; + int reply_bytes; + uint8_t ack; + int ret; + + msg[0] = AUX_NATIVE_READ << 4; + msg[1] = address >> 8; + msg[2] = address & 0xff; + msg[3] = recv_bytes - 1; + + msg_bytes = 4; + reply_bytes = recv_bytes + 1; + + for (;;) { + ret = intel_dp_aux_ch(intel_output, msg, msg_bytes, + reply, reply_bytes); + if (ret == 0) + return -EPROTO; + if (ret < 0) + return ret; + ack = reply[0]; + if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_ACK) { + memcpy(recv, reply + 1, ret - 1); + return ret - 1; + } + else if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_DEFER) + udelay(100); + else + return -EIO; + } +} + +static int +intel_dp_i2c_aux_ch(struct i2c_adapter *adapter, + uint8_t *send, int send_bytes, + uint8_t *recv, int recv_bytes) +{ + struct intel_dp_priv *dp_priv = container_of(adapter, + struct intel_dp_priv, + adapter); + struct intel_output *intel_output = dp_priv->intel_output; + + return intel_dp_aux_ch(intel_output, + send, send_bytes, recv, recv_bytes); +} + +static int +intel_dp_i2c_init(struct intel_output *intel_output, const char *name) +{ + struct intel_dp_priv *dp_priv = intel_output->dev_priv; + + DRM_ERROR("i2c_init %s\n", name); + dp_priv->algo.running = false; + dp_priv->algo.address = 0; + dp_priv->algo.aux_ch = intel_dp_i2c_aux_ch; + + memset(&dp_priv->adapter, '\0', sizeof (dp_priv->adapter)); + dp_priv->adapter.owner = THIS_MODULE; + dp_priv->adapter.class = I2C_CLASS_DDC; + strncpy (dp_priv->adapter.name, name, sizeof dp_priv->adapter.name - 1); + dp_priv->adapter.name[sizeof dp_priv->adapter.name - 1] = '\0'; + dp_priv->adapter.algo_data = &dp_priv->algo; + dp_priv->adapter.dev.parent = &intel_output->base.kdev; + + return i2c_dp_aux_add_bus(&dp_priv->adapter); +} + +static bool +intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct intel_output *intel_output = enc_to_intel_output(encoder); + struct intel_dp_priv *dp_priv = intel_output->dev_priv; + int lane_count, clock; + int max_lane_count = intel_dp_max_lane_count(intel_output); + int max_clock = intel_dp_max_link_bw(intel_output) == DP_LINK_BW_2_7 ? 1 : 0; + static int bws[2] = { DP_LINK_BW_1_62, DP_LINK_BW_2_7 }; + + for (lane_count = 1; lane_count <= max_lane_count; lane_count <<= 1) { + for (clock = 0; clock <= max_clock; clock++) { + int link_avail = intel_dp_link_clock(bws[clock]) * lane_count; + + if (intel_dp_link_required(mode->clock) <= link_avail) { + dp_priv->link_bw = bws[clock]; + dp_priv->lane_count = lane_count; + adjusted_mode->clock = intel_dp_link_clock(dp_priv->link_bw); + printk(KERN_ERR "link bw %02x lane count %d clock %d\n", + dp_priv->link_bw, dp_priv->lane_count, + adjusted_mode->clock); + return true; + } + } + } + return false; +} + +struct intel_dp_m_n { + uint32_t tu; + uint32_t gmch_m; + uint32_t gmch_n; + uint32_t link_m; + uint32_t link_n; +}; + +static void +intel_reduce_ratio(uint32_t *num, uint32_t *den) +{ + while (*num > 0xffffff || *den > 0xffffff) { + *num >>= 1; + *den >>= 1; + } +} + +static void +intel_dp_compute_m_n(int bytes_per_pixel, + int nlanes, + int pixel_clock, + int link_clock, + struct intel_dp_m_n *m_n) +{ + m_n->tu = 64; + m_n->gmch_m = pixel_clock * bytes_per_pixel; + m_n->gmch_n = link_clock * nlanes; + intel_reduce_ratio(&m_n->gmch_m, &m_n->gmch_n); + m_n->link_m = pixel_clock; + m_n->link_n = link_clock; + intel_reduce_ratio(&m_n->link_m, &m_n->link_n); +} + +void +intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct drm_device *dev = crtc->dev; + struct drm_mode_config *mode_config = &dev->mode_config; + struct drm_connector *connector; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int lane_count = 4; + struct intel_dp_m_n m_n; + + /* + * Find the lane count in the intel_output private + */ + list_for_each_entry(connector, &mode_config->connector_list, head) { + struct intel_output *intel_output = to_intel_output(connector); + struct intel_dp_priv *dp_priv = intel_output->dev_priv; + + if (!connector->encoder || connector->encoder->crtc != crtc) + continue; + + if (intel_output->type == INTEL_OUTPUT_DISPLAYPORT) { + lane_count = dp_priv->lane_count; + break; + } + } + + /* + * Compute the GMCH and Link ratios. The '3' here is + * the number of bytes_per_pixel post-LUT, which we always + * set up for 8-bits of R/G/B, or 3 bytes total. + */ + intel_dp_compute_m_n(3, lane_count, + mode->clock, adjusted_mode->clock, &m_n); + + if (intel_crtc->pipe == 0) { + I915_WRITE(PIPEA_GMCH_DATA_M, + ((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) | + m_n.gmch_m); + I915_WRITE(PIPEA_GMCH_DATA_N, + m_n.gmch_n); + I915_WRITE(PIPEA_DP_LINK_M, m_n.link_m); + I915_WRITE(PIPEA_DP_LINK_N, m_n.link_n); + } else { + I915_WRITE(PIPEB_GMCH_DATA_M, + ((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) | + m_n.gmch_m); + I915_WRITE(PIPEB_GMCH_DATA_N, + m_n.gmch_n); + I915_WRITE(PIPEB_DP_LINK_M, m_n.link_m); + I915_WRITE(PIPEB_DP_LINK_N, m_n.link_n); + } +} + +static void +intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct intel_output *intel_output = enc_to_intel_output(encoder); + struct intel_dp_priv *dp_priv = intel_output->dev_priv; + struct drm_crtc *crtc = intel_output->enc.crtc; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + + dp_priv->DP = (DP_LINK_TRAIN_OFF | + DP_VOLTAGE_0_4 | + DP_PRE_EMPHASIS_0 | + DP_SYNC_VS_HIGH | + DP_SYNC_HS_HIGH); + + switch (dp_priv->lane_count) { + case 1: + dp_priv->DP |= DP_PORT_WIDTH_1; + break; + case 2: + dp_priv->DP |= DP_PORT_WIDTH_2; + break; + case 4: + dp_priv->DP |= DP_PORT_WIDTH_4; + break; + } + if (dp_priv->has_audio) + dp_priv->DP |= DP_AUDIO_OUTPUT_ENABLE; + + memset(dp_priv->link_configuration, 0, DP_LINK_CONFIGURATION_SIZE); + dp_priv->link_configuration[0] = dp_priv->link_bw; + dp_priv->link_configuration[1] = dp_priv->lane_count; + + /* + * Check for DPCD version > 1.1, + * enable enahanced frame stuff in that case + */ + if (dp_priv->dpcd[0] >= 0x11) { + dp_priv->link_configuration[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN; + dp_priv->DP |= DP_ENHANCED_FRAMING; + } + + if (intel_crtc->pipe == 1) + dp_priv->DP |= DP_PIPEB_SELECT; +} + + +static void +intel_dp_dpms(struct drm_encoder *encoder, int mode) +{ + struct intel_output *intel_output = enc_to_intel_output(encoder); + struct intel_dp_priv *dp_priv = intel_output->dev_priv; + struct drm_device *dev = intel_output->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t dp_reg = I915_READ(dp_priv->output_reg); + + if (mode != DRM_MODE_DPMS_ON) { + if (dp_reg & DP_PORT_EN) + intel_dp_link_down(intel_output, dp_priv->DP); + } else { + if (!(dp_reg & DP_PORT_EN)) + intel_dp_link_train(intel_output, dp_priv->DP, dp_priv->link_configuration); + } + dp_priv->dpms_mode = mode; +} + +/* + * Fetch AUX CH registers 0x202 - 0x207 which contain + * link status information + */ +static bool +intel_dp_get_link_status(struct intel_output *intel_output, + uint8_t link_status[DP_LINK_STATUS_SIZE]) +{ + int ret; + + ret = intel_dp_aux_native_read(intel_output, + DP_LANE0_1_STATUS, + link_status, DP_LINK_STATUS_SIZE); + if (ret != DP_LINK_STATUS_SIZE) + return false; + return true; +} + +static uint8_t +intel_dp_link_status(uint8_t link_status[DP_LINK_STATUS_SIZE], + int r) +{ + return link_status[r - DP_LANE0_1_STATUS]; +} + +static void +intel_dp_save(struct drm_connector *connector) +{ + struct intel_output *intel_output = to_intel_output(connector); + struct drm_device *dev = intel_output->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_dp_priv *dp_priv = intel_output->dev_priv; + + dp_priv->save_DP = I915_READ(dp_priv->output_reg); + intel_dp_aux_native_read(intel_output, DP_LINK_BW_SET, + dp_priv->save_link_configuration, + sizeof (dp_priv->save_link_configuration)); +} + +static uint8_t +intel_get_adjust_request_voltage(uint8_t link_status[DP_LINK_STATUS_SIZE], + int lane) +{ + int i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1); + int s = ((lane & 1) ? + DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT : + DP_ADJUST_VOLTAGE_SWING_LANE0_SHIFT); + uint8_t l = intel_dp_link_status(link_status, i); + + return ((l >> s) & 3) << DP_TRAIN_VOLTAGE_SWING_SHIFT; +} + +static uint8_t +intel_get_adjust_request_pre_emphasis(uint8_t link_status[DP_LINK_STATUS_SIZE], + int lane) +{ + int i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1); + int s = ((lane & 1) ? + DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT : + DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT); + uint8_t l = intel_dp_link_status(link_status, i); + + return ((l >> s) & 3) << DP_TRAIN_PRE_EMPHASIS_SHIFT; +} + + +#if 0 +static char *voltage_names[] = { + "0.4V", "0.6V", "0.8V", "1.2V" +}; +static char *pre_emph_names[] = { + "0dB", "3.5dB", "6dB", "9.5dB" +}; +static char *link_train_names[] = { + "pattern 1", "pattern 2", "idle", "off" +}; +#endif + +/* + * These are source-specific values; current Intel hardware supports + * a maximum voltage of 800mV and a maximum pre-emphasis of 6dB + */ +#define I830_DP_VOLTAGE_MAX DP_TRAIN_VOLTAGE_SWING_800 + +static uint8_t +intel_dp_pre_emphasis_max(uint8_t voltage_swing) +{ + switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) { + case DP_TRAIN_VOLTAGE_SWING_400: + return DP_TRAIN_PRE_EMPHASIS_6; + case DP_TRAIN_VOLTAGE_SWING_600: + return DP_TRAIN_PRE_EMPHASIS_6; + case DP_TRAIN_VOLTAGE_SWING_800: + return DP_TRAIN_PRE_EMPHASIS_3_5; + case DP_TRAIN_VOLTAGE_SWING_1200: + default: + return DP_TRAIN_PRE_EMPHASIS_0; + } +} + +static void +intel_get_adjust_train(struct intel_output *intel_output, + uint8_t link_status[DP_LINK_STATUS_SIZE], + int lane_count, + uint8_t train_set[4]) +{ + uint8_t v = 0; + uint8_t p = 0; + int lane; + + for (lane = 0; lane < lane_count; lane++) { + uint8_t this_v = intel_get_adjust_request_voltage(link_status, lane); + uint8_t this_p = intel_get_adjust_request_pre_emphasis(link_status, lane); + + if (this_v > v) + v = this_v; + if (this_p > p) + p = this_p; + } + + if (v >= I830_DP_VOLTAGE_MAX) + v = I830_DP_VOLTAGE_MAX | DP_TRAIN_MAX_SWING_REACHED; + + if (p >= intel_dp_pre_emphasis_max(v)) + p = intel_dp_pre_emphasis_max(v) | DP_TRAIN_MAX_PRE_EMPHASIS_REACHED; + + for (lane = 0; lane < 4; lane++) + train_set[lane] = v | p; +} + +static uint32_t +intel_dp_signal_levels(uint8_t train_set, int lane_count) +{ + uint32_t signal_levels = 0; + + switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) { + case DP_TRAIN_VOLTAGE_SWING_400: + default: + signal_levels |= DP_VOLTAGE_0_4; + break; + case DP_TRAIN_VOLTAGE_SWING_600: + signal_levels |= DP_VOLTAGE_0_6; + break; + case DP_TRAIN_VOLTAGE_SWING_800: + signal_levels |= DP_VOLTAGE_0_8; + break; + case DP_TRAIN_VOLTAGE_SWING_1200: + signal_levels |= DP_VOLTAGE_1_2; + break; + } + switch (train_set & DP_TRAIN_PRE_EMPHASIS_MASK) { + case DP_TRAIN_PRE_EMPHASIS_0: + default: + signal_levels |= DP_PRE_EMPHASIS_0; + break; + case DP_TRAIN_PRE_EMPHASIS_3_5: + signal_levels |= DP_PRE_EMPHASIS_3_5; + break; + case DP_TRAIN_PRE_EMPHASIS_6: + signal_levels |= DP_PRE_EMPHASIS_6; + break; + case DP_TRAIN_PRE_EMPHASIS_9_5: + signal_levels |= DP_PRE_EMPHASIS_9_5; + break; + } + return signal_levels; +} + +static uint8_t +intel_get_lane_status(uint8_t link_status[DP_LINK_STATUS_SIZE], + int lane) +{ + int i = DP_LANE0_1_STATUS + (lane >> 1); + int s = (lane & 1) * 4; + uint8_t l = intel_dp_link_status(link_status, i); + + return (l >> s) & 0xf; +} + +/* Check for clock recovery is done on all channels */ +static bool +intel_clock_recovery_ok(uint8_t link_status[DP_LINK_STATUS_SIZE], int lane_count) +{ + int lane; + uint8_t lane_status; + + for (lane = 0; lane < lane_count; lane++) { + lane_status = intel_get_lane_status(link_status, lane); + if ((lane_status & DP_LANE_CR_DONE) == 0) + return false; + } + return true; +} + +/* Check to see if channel eq is done on all channels */ +#define CHANNEL_EQ_BITS (DP_LANE_CR_DONE|\ + DP_LANE_CHANNEL_EQ_DONE|\ + DP_LANE_SYMBOL_LOCKED) +static bool +intel_channel_eq_ok(uint8_t link_status[DP_LINK_STATUS_SIZE], int lane_count) +{ + uint8_t lane_align; + uint8_t lane_status; + int lane; + + lane_align = intel_dp_link_status(link_status, + DP_LANE_ALIGN_STATUS_UPDATED); + if ((lane_align & DP_INTERLANE_ALIGN_DONE) == 0) + return false; + for (lane = 0; lane < lane_count; lane++) { + lane_status = intel_get_lane_status(link_status, lane); + if ((lane_status & CHANNEL_EQ_BITS) != CHANNEL_EQ_BITS) + return false; + } + return true; +} + +static bool +intel_dp_set_link_train(struct intel_output *intel_output, + uint32_t dp_reg_value, + uint8_t dp_train_pat, + uint8_t train_set[4], + bool first) +{ + struct drm_device *dev = intel_output->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_dp_priv *dp_priv = intel_output->dev_priv; + int ret; + + I915_WRITE(dp_priv->output_reg, dp_reg_value); + POSTING_READ(dp_priv->output_reg); + if (first) + intel_wait_for_vblank(dev); + + intel_dp_aux_native_write_1(intel_output, + DP_TRAINING_PATTERN_SET, + dp_train_pat); + + ret = intel_dp_aux_native_write(intel_output, + DP_TRAINING_LANE0_SET, train_set, 4); + if (ret != 4) + return false; + + return true; +} + +static void +intel_dp_link_train(struct intel_output *intel_output, uint32_t DP, + uint8_t link_configuration[DP_LINK_CONFIGURATION_SIZE]) +{ + struct drm_device *dev = intel_output->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_dp_priv *dp_priv = intel_output->dev_priv; + uint8_t train_set[4]; + uint8_t link_status[DP_LINK_STATUS_SIZE]; + int i; + uint8_t voltage; + bool clock_recovery = false; + bool channel_eq = false; + bool first = true; + int tries; + + /* Write the link configuration data */ + intel_dp_aux_native_write(intel_output, 0x100, + link_configuration, DP_LINK_CONFIGURATION_SIZE); + + DP |= DP_PORT_EN; + DP &= ~DP_LINK_TRAIN_MASK; + memset(train_set, 0, 4); + voltage = 0xff; + tries = 0; + clock_recovery = false; + for (;;) { + /* Use train_set[0] to set the voltage and pre emphasis values */ + uint32_t signal_levels = intel_dp_signal_levels(train_set[0], dp_priv->lane_count); + DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels; + + if (!intel_dp_set_link_train(intel_output, DP | DP_LINK_TRAIN_PAT_1, + DP_TRAINING_PATTERN_1, train_set, first)) + break; + first = false; + /* Set training pattern 1 */ + + udelay(100); + if (!intel_dp_get_link_status(intel_output, link_status)) + break; + + if (intel_clock_recovery_ok(link_status, dp_priv->lane_count)) { + clock_recovery = true; + break; + } + + /* Check to see if we've tried the max voltage */ + for (i = 0; i < dp_priv->lane_count; i++) + if ((train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0) + break; + if (i == dp_priv->lane_count) + break; + + /* Check to see if we've tried the same voltage 5 times */ + if ((train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) { + ++tries; + if (tries == 5) + break; + } else + tries = 0; + voltage = train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK; + + /* Compute new train_set as requested by target */ + intel_get_adjust_train(intel_output, link_status, dp_priv->lane_count, train_set); + } + + /* channel equalization */ + tries = 0; + channel_eq = false; + for (;;) { + /* Use train_set[0] to set the voltage and pre emphasis values */ + uint32_t signal_levels = intel_dp_signal_levels(train_set[0], dp_priv->lane_count); + DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels; + + /* channel eq pattern */ + if (!intel_dp_set_link_train(intel_output, DP | DP_LINK_TRAIN_PAT_2, + DP_TRAINING_PATTERN_2, train_set, + false)) + break; + + udelay(400); + if (!intel_dp_get_link_status(intel_output, link_status)) + break; + + if (intel_channel_eq_ok(link_status, dp_priv->lane_count)) { + channel_eq = true; + break; + } + + /* Try 5 times */ + if (tries > 5) + break; + + /* Compute new train_set as requested by target */ + intel_get_adjust_train(intel_output, link_status, dp_priv->lane_count, train_set); + ++tries; + } + + I915_WRITE(dp_priv->output_reg, DP | DP_LINK_TRAIN_OFF); + POSTING_READ(dp_priv->output_reg); + intel_dp_aux_native_write_1(intel_output, + DP_TRAINING_PATTERN_SET, DP_TRAINING_PATTERN_DISABLE); +} + +static void +intel_dp_link_down(struct intel_output *intel_output, uint32_t DP) +{ + struct drm_device *dev = intel_output->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_dp_priv *dp_priv = intel_output->dev_priv; + + I915_WRITE(dp_priv->output_reg, DP & ~DP_PORT_EN); + POSTING_READ(dp_priv->output_reg); +} + +static void +intel_dp_restore(struct drm_connector *connector) +{ + struct intel_output *intel_output = to_intel_output(connector); + struct intel_dp_priv *dp_priv = intel_output->dev_priv; + + if (dp_priv->save_DP & DP_PORT_EN) + intel_dp_link_train(intel_output, dp_priv->save_DP, dp_priv->save_link_configuration); + else + intel_dp_link_down(intel_output, dp_priv->save_DP); +} + +/* + * According to DP spec + * 5.1.2: + * 1. Read DPCD + * 2. Configure link according to Receiver Capabilities + * 3. Use Link Training from 2.5.3.3 and 3.5.1.3 + * 4. Check link status on receipt of hot-plug interrupt + */ + +static void +intel_dp_check_link_status(struct intel_output *intel_output) +{ + struct intel_dp_priv *dp_priv = intel_output->dev_priv; + uint8_t link_status[DP_LINK_STATUS_SIZE]; + + if (!intel_output->enc.crtc) + return; + + if (!intel_dp_get_link_status(intel_output, link_status)) { + intel_dp_link_down(intel_output, dp_priv->DP); + return; + } + + if (!intel_channel_eq_ok(link_status, dp_priv->lane_count)) + intel_dp_link_train(intel_output, dp_priv->DP, dp_priv->link_configuration); +} + +/** + * Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect DP connection. + * + * \return true if DP port is connected. + * \return false if DP port is disconnected. + */ +static enum drm_connector_status +intel_dp_detect(struct drm_connector *connector) +{ + struct intel_output *intel_output = to_intel_output(connector); + struct drm_device *dev = intel_output->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_dp_priv *dp_priv = intel_output->dev_priv; + uint32_t temp, bit; + enum drm_connector_status status; + + dp_priv->has_audio = false; + + temp = I915_READ(PORT_HOTPLUG_EN); + + I915_WRITE(PORT_HOTPLUG_EN, + temp | + DPB_HOTPLUG_INT_EN | + DPC_HOTPLUG_INT_EN | + DPD_HOTPLUG_INT_EN); + + POSTING_READ(PORT_HOTPLUG_EN); + + switch (dp_priv->output_reg) { + case DP_B: + bit = DPB_HOTPLUG_INT_STATUS; + break; + case DP_C: + bit = DPC_HOTPLUG_INT_STATUS; + break; + case DP_D: + bit = DPD_HOTPLUG_INT_STATUS; + break; + default: + return connector_status_unknown; + } + + temp = I915_READ(PORT_HOTPLUG_STAT); + + if ((temp & bit) == 0) + return connector_status_disconnected; + + status = connector_status_disconnected; + if (intel_dp_aux_native_read(intel_output, + 0x000, dp_priv->dpcd, + sizeof (dp_priv->dpcd)) == sizeof (dp_priv->dpcd)) + { + if (dp_priv->dpcd[0] != 0) + status = connector_status_connected; + } + return status; +} + +static int intel_dp_get_modes(struct drm_connector *connector) +{ + struct intel_output *intel_output = to_intel_output(connector); + + /* We should parse the EDID data and find out if it has an audio sink + */ + + return intel_ddc_get_modes(intel_output); +} + +static void +intel_dp_destroy (struct drm_connector *connector) +{ + struct intel_output *intel_output = to_intel_output(connector); + + if (intel_output->i2c_bus) + intel_i2c_destroy(intel_output->i2c_bus); + drm_sysfs_connector_remove(connector); + drm_connector_cleanup(connector); + kfree(intel_output); +} + +static const struct drm_encoder_helper_funcs intel_dp_helper_funcs = { + .dpms = intel_dp_dpms, + .mode_fixup = intel_dp_mode_fixup, + .prepare = intel_encoder_prepare, + .mode_set = intel_dp_mode_set, + .commit = intel_encoder_commit, +}; + +static const struct drm_connector_funcs intel_dp_connector_funcs = { + .dpms = drm_helper_connector_dpms, + .save = intel_dp_save, + .restore = intel_dp_restore, + .detect = intel_dp_detect, + .fill_modes = drm_helper_probe_single_connector_modes, + .destroy = intel_dp_destroy, +}; + +static const struct drm_connector_helper_funcs intel_dp_connector_helper_funcs = { + .get_modes = intel_dp_get_modes, + .mode_valid = intel_dp_mode_valid, + .best_encoder = intel_best_encoder, +}; + +static void intel_dp_enc_destroy(struct drm_encoder *encoder) +{ + drm_encoder_cleanup(encoder); +} + +static const struct drm_encoder_funcs intel_dp_enc_funcs = { + .destroy = intel_dp_enc_destroy, +}; + +void +intel_dp_hot_plug(struct intel_output *intel_output) +{ + struct intel_dp_priv *dp_priv = intel_output->dev_priv; + + if (dp_priv->dpms_mode == DRM_MODE_DPMS_ON) + intel_dp_check_link_status(intel_output); +} + +void +intel_dp_init(struct drm_device *dev, int output_reg) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_connector *connector; + struct intel_output *intel_output; + struct intel_dp_priv *dp_priv; + + intel_output = kcalloc(sizeof(struct intel_output) + + sizeof(struct intel_dp_priv), 1, GFP_KERNEL); + if (!intel_output) + return; + + dp_priv = (struct intel_dp_priv *)(intel_output + 1); + + connector = &intel_output->base; + drm_connector_init(dev, connector, &intel_dp_connector_funcs, + DRM_MODE_CONNECTOR_DisplayPort); + drm_connector_helper_add(connector, &intel_dp_connector_helper_funcs); + + intel_output->type = INTEL_OUTPUT_DISPLAYPORT; + + connector->interlace_allowed = true; + connector->doublescan_allowed = 0; + + dp_priv->intel_output = intel_output; + dp_priv->output_reg = output_reg; + dp_priv->has_audio = false; + dp_priv->dpms_mode = DRM_MODE_DPMS_ON; + intel_output->dev_priv = dp_priv; + + drm_encoder_init(dev, &intel_output->enc, &intel_dp_enc_funcs, + DRM_MODE_ENCODER_TMDS); + drm_encoder_helper_add(&intel_output->enc, &intel_dp_helper_funcs); + + drm_mode_connector_attach_encoder(&intel_output->base, + &intel_output->enc); + drm_sysfs_connector_add(connector); + + /* Set up the DDC bus. */ + intel_dp_i2c_init(intel_output, + (output_reg == DP_B) ? "DPDDC-B" : + (output_reg == DP_C) ? "DPDDC-C" : "DPDDC-D"); + intel_output->ddc_bus = &dp_priv->adapter; + intel_output->hot_plug = intel_dp_hot_plug; + + /* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written + * 0xd. Failure to do so will result in spurious interrupts being + * generated on the port when a cable is not attached. + */ + if (IS_G4X(dev) && !IS_GM45(dev)) { + u32 temp = I915_READ(PEG_BAND_GAP_DATA); + I915_WRITE(PEG_BAND_GAP_DATA, (temp & ~0xf) | 0xd); + } +} diff --git a/drivers/gpu/drm/i915/intel_dp.h b/drivers/gpu/drm/i915/intel_dp.h new file mode 100644 index 00000000000..2b38054d3b6 --- /dev/null +++ b/drivers/gpu/drm/i915/intel_dp.h @@ -0,0 +1,144 @@ +/* + * Copyright © 2008 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifndef _INTEL_DP_H_ +#define _INTEL_DP_H_ + +/* From the VESA DisplayPort spec */ + +#define AUX_NATIVE_WRITE 0x8 +#define AUX_NATIVE_READ 0x9 +#define AUX_I2C_WRITE 0x0 +#define AUX_I2C_READ 0x1 +#define AUX_I2C_STATUS 0x2 +#define AUX_I2C_MOT 0x4 + +#define AUX_NATIVE_REPLY_ACK (0x0 << 4) +#define AUX_NATIVE_REPLY_NACK (0x1 << 4) +#define AUX_NATIVE_REPLY_DEFER (0x2 << 4) +#define AUX_NATIVE_REPLY_MASK (0x3 << 4) + +#define AUX_I2C_REPLY_ACK (0x0 << 6) +#define AUX_I2C_REPLY_NACK (0x1 << 6) +#define AUX_I2C_REPLY_DEFER (0x2 << 6) +#define AUX_I2C_REPLY_MASK (0x3 << 6) + +/* AUX CH addresses */ +#define DP_LINK_BW_SET 0x100 +# define DP_LINK_BW_1_62 0x06 +# define DP_LINK_BW_2_7 0x0a + +#define DP_LANE_COUNT_SET 0x101 +# define DP_LANE_COUNT_MASK 0x0f +# define DP_LANE_COUNT_ENHANCED_FRAME_EN (1 << 7) + +#define DP_TRAINING_PATTERN_SET 0x102 + +# define DP_TRAINING_PATTERN_DISABLE 0 +# define DP_TRAINING_PATTERN_1 1 +# define DP_TRAINING_PATTERN_2 2 +# define DP_TRAINING_PATTERN_MASK 0x3 + +# define DP_LINK_QUAL_PATTERN_DISABLE (0 << 2) +# define DP_LINK_QUAL_PATTERN_D10_2 (1 << 2) +# define DP_LINK_QUAL_PATTERN_ERROR_RATE (2 << 2) +# define DP_LINK_QUAL_PATTERN_PRBS7 (3 << 2) +# define DP_LINK_QUAL_PATTERN_MASK (3 << 2) + +# define DP_RECOVERED_CLOCK_OUT_EN (1 << 4) +# define DP_LINK_SCRAMBLING_DISABLE (1 << 5) + +# define DP_SYMBOL_ERROR_COUNT_BOTH (0 << 6) +# define DP_SYMBOL_ERROR_COUNT_DISPARITY (1 << 6) +# define DP_SYMBOL_ERROR_COUNT_SYMBOL (2 << 6) +# define DP_SYMBOL_ERROR_COUNT_MASK (3 << 6) + +#define DP_TRAINING_LANE0_SET 0x103 +#define DP_TRAINING_LANE1_SET 0x104 +#define DP_TRAINING_LANE2_SET 0x105 +#define DP_TRAINING_LANE3_SET 0x106 + +# define DP_TRAIN_VOLTAGE_SWING_MASK 0x3 +# define DP_TRAIN_VOLTAGE_SWING_SHIFT 0 +# define DP_TRAIN_MAX_SWING_REACHED (1 << 2) +# define DP_TRAIN_VOLTAGE_SWING_400 (0 << 0) +# define DP_TRAIN_VOLTAGE_SWING_600 (1 << 0) +# define DP_TRAIN_VOLTAGE_SWING_800 (2 << 0) +# define DP_TRAIN_VOLTAGE_SWING_1200 (3 << 0) + +# define DP_TRAIN_PRE_EMPHASIS_MASK (3 << 3) +# define DP_TRAIN_PRE_EMPHASIS_0 (0 << 3) +# define DP_TRAIN_PRE_EMPHASIS_3_5 (1 << 3) +# define DP_TRAIN_PRE_EMPHASIS_6 (2 << 3) +# define DP_TRAIN_PRE_EMPHASIS_9_5 (3 << 3) + +# define DP_TRAIN_PRE_EMPHASIS_SHIFT 3 +# define DP_TRAIN_MAX_PRE_EMPHASIS_REACHED (1 << 5) + +#define DP_DOWNSPREAD_CTRL 0x107 +# define DP_SPREAD_AMP_0_5 (1 << 4) + +#define DP_MAIN_LINK_CHANNEL_CODING_SET 0x108 +# define DP_SET_ANSI_8B10B (1 << 0) + +#define DP_LANE0_1_STATUS 0x202 +#define DP_LANE2_3_STATUS 0x203 + +# define DP_LANE_CR_DONE (1 << 0) +# define DP_LANE_CHANNEL_EQ_DONE (1 << 1) +# define DP_LANE_SYMBOL_LOCKED (1 << 2) + +#define DP_LANE_ALIGN_STATUS_UPDATED 0x204 + +#define DP_INTERLANE_ALIGN_DONE (1 << 0) +#define DP_DOWNSTREAM_PORT_STATUS_CHANGED (1 << 6) +#define DP_LINK_STATUS_UPDATED (1 << 7) + +#define DP_SINK_STATUS 0x205 + +#define DP_RECEIVE_PORT_0_STATUS (1 << 0) +#define DP_RECEIVE_PORT_1_STATUS (1 << 1) + +#define DP_ADJUST_REQUEST_LANE0_1 0x206 +#define DP_ADJUST_REQUEST_LANE2_3 0x207 + +#define DP_ADJUST_VOLTAGE_SWING_LANE0_MASK 0x03 +#define DP_ADJUST_VOLTAGE_SWING_LANE0_SHIFT 0 +#define DP_ADJUST_PRE_EMPHASIS_LANE0_MASK 0x0c +#define DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT 2 +#define DP_ADJUST_VOLTAGE_SWING_LANE1_MASK 0x30 +#define DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT 4 +#define DP_ADJUST_PRE_EMPHASIS_LANE1_MASK 0xc0 +#define DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT 6 + +struct i2c_algo_dp_aux_data { + bool running; + u16 address; + int (*aux_ch) (struct i2c_adapter *adapter, + uint8_t *send, int send_bytes, + uint8_t *recv, int recv_bytes); +}; + +int +i2c_dp_aux_add_bus(struct i2c_adapter *adapter); + +#endif /* _INTEL_DP_H_ */ diff --git a/drivers/gpu/drm/i915/intel_dp_i2c.c b/drivers/gpu/drm/i915/intel_dp_i2c.c new file mode 100644 index 00000000000..4e60f14b1a6 --- /dev/null +++ b/drivers/gpu/drm/i915/intel_dp_i2c.c @@ -0,0 +1,272 @@ +/* + * Copyright © 2009 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/sched.h> +#include <linux/i2c.h> +#include "intel_dp.h" + +/* Run a single AUX_CH I2C transaction, writing/reading data as necessary */ + +#define MODE_I2C_START 1 +#define MODE_I2C_WRITE 2 +#define MODE_I2C_READ 4 +#define MODE_I2C_STOP 8 + +static int +i2c_algo_dp_aux_transaction(struct i2c_adapter *adapter, int mode, + uint8_t write_byte, uint8_t *read_byte) +{ + struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data; + uint16_t address = algo_data->address; + uint8_t msg[5]; + uint8_t reply[2]; + int msg_bytes; + int reply_bytes; + int ret; + + /* Set up the command byte */ + if (mode & MODE_I2C_READ) + msg[0] = AUX_I2C_READ << 4; + else + msg[0] = AUX_I2C_WRITE << 4; + + if (!(mode & MODE_I2C_STOP)) + msg[0] |= AUX_I2C_MOT << 4; + + msg[1] = address >> 8; + msg[2] = address; + + switch (mode) { + case MODE_I2C_WRITE: + msg[3] = 0; + msg[4] = write_byte; + msg_bytes = 5; + reply_bytes = 1; + break; + case MODE_I2C_READ: + msg[3] = 0; + msg_bytes = 4; + reply_bytes = 2; + break; + default: + msg_bytes = 3; + reply_bytes = 1; + break; + } + + for (;;) { + ret = (*algo_data->aux_ch)(adapter, + msg, msg_bytes, + reply, reply_bytes); + if (ret < 0) { + printk(KERN_ERR "aux_ch failed %d\n", ret); + return ret; + } + switch (reply[0] & AUX_I2C_REPLY_MASK) { + case AUX_I2C_REPLY_ACK: + if (mode == MODE_I2C_READ) { + *read_byte = reply[1]; + } + return reply_bytes - 1; + case AUX_I2C_REPLY_NACK: + printk(KERN_ERR "aux_ch nack\n"); + return -EREMOTEIO; + case AUX_I2C_REPLY_DEFER: + printk(KERN_ERR "aux_ch defer\n"); + udelay(100); + break; + default: + printk(KERN_ERR "aux_ch invalid reply 0x%02x\n", reply[0]); + return -EREMOTEIO; + } + } +} + +/* + * I2C over AUX CH + */ + +/* + * Send the address. If the I2C link is running, this 'restarts' + * the connection with the new address, this is used for doing + * a write followed by a read (as needed for DDC) + */ +static int +i2c_algo_dp_aux_address(struct i2c_adapter *adapter, u16 address, bool reading) +{ + struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data; + int mode = MODE_I2C_START; + int ret; + + if (reading) + mode |= MODE_I2C_READ; + else + mode |= MODE_I2C_WRITE; + algo_data->address = address; + algo_data->running = true; + ret = i2c_algo_dp_aux_transaction(adapter, mode, 0, NULL); + return ret; +} + +/* + * Stop the I2C transaction. This closes out the link, sending + * a bare address packet with the MOT bit turned off + */ +static void +i2c_algo_dp_aux_stop(struct i2c_adapter *adapter, bool reading) +{ + struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data; + int mode = MODE_I2C_STOP; + + if (reading) + mode |= MODE_I2C_READ; + else + mode |= MODE_I2C_WRITE; + if (algo_data->running) { + (void) i2c_algo_dp_aux_transaction(adapter, mode, 0, NULL); + algo_data->running = false; + } +} + +/* + * Write a single byte to the current I2C address, the + * the I2C link must be running or this returns -EIO + */ +static int +i2c_algo_dp_aux_put_byte(struct i2c_adapter *adapter, u8 byte) +{ + struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data; + int ret; + + if (!algo_data->running) + return -EIO; + + ret = i2c_algo_dp_aux_transaction(adapter, MODE_I2C_WRITE, byte, NULL); + return ret; +} + +/* + * Read a single byte from the current I2C address, the + * I2C link must be running or this returns -EIO + */ +static int +i2c_algo_dp_aux_get_byte(struct i2c_adapter *adapter, u8 *byte_ret) +{ + struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data; + int ret; + + if (!algo_data->running) + return -EIO; + + ret = i2c_algo_dp_aux_transaction(adapter, MODE_I2C_READ, 0, byte_ret); + return ret; +} + +static int +i2c_algo_dp_aux_xfer(struct i2c_adapter *adapter, + struct i2c_msg *msgs, + int num) +{ + int ret = 0; + bool reading = false; + int m; + int b; + + for (m = 0; m < num; m++) { + u16 len = msgs[m].len; + u8 *buf = msgs[m].buf; + reading = (msgs[m].flags & I2C_M_RD) != 0; + ret = i2c_algo_dp_aux_address(adapter, msgs[m].addr, reading); + if (ret < 0) + break; + if (reading) { + for (b = 0; b < len; b++) { + ret = i2c_algo_dp_aux_get_byte(adapter, &buf[b]); + if (ret < 0) + break; + } + } else { + for (b = 0; b < len; b++) { + ret = i2c_algo_dp_aux_put_byte(adapter, buf[b]); + if (ret < 0) + break; + } + } + if (ret < 0) + break; + } + if (ret >= 0) + ret = num; + i2c_algo_dp_aux_stop(adapter, reading); + printk(KERN_ERR "dp_aux_xfer return %d\n", ret); + return ret; +} + +static u32 +i2c_algo_dp_aux_functionality(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | + I2C_FUNC_SMBUS_READ_BLOCK_DATA | + I2C_FUNC_SMBUS_BLOCK_PROC_CALL | + I2C_FUNC_10BIT_ADDR; +} + +static const struct i2c_algorithm i2c_dp_aux_algo = { + .master_xfer = i2c_algo_dp_aux_xfer, + .functionality = i2c_algo_dp_aux_functionality, +}; + +static void +i2c_dp_aux_reset_bus(struct i2c_adapter *adapter) +{ + (void) i2c_algo_dp_aux_address(adapter, 0, false); + (void) i2c_algo_dp_aux_stop(adapter, false); + +} + +static int +i2c_dp_aux_prepare_bus(struct i2c_adapter *adapter) +{ + adapter->algo = &i2c_dp_aux_algo; + adapter->retries = 3; + i2c_dp_aux_reset_bus(adapter); + return 0; +} + +int +i2c_dp_aux_add_bus(struct i2c_adapter *adapter) +{ + int error; + + error = i2c_dp_aux_prepare_bus(adapter); + if (error) + return error; + error = i2c_add_adapter(adapter); + return error; +} +EXPORT_SYMBOL(i2c_dp_aux_add_bus); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index cd4b9c5f715..004541c935a 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -54,6 +54,7 @@ #define INTEL_OUTPUT_LVDS 4 #define INTEL_OUTPUT_TVOUT 5 #define INTEL_OUTPUT_HDMI 6 +#define INTEL_OUTPUT_DISPLAYPORT 7 #define INTEL_DVO_CHIP_NONE 0 #define INTEL_DVO_CHIP_LVDS 1 @@ -65,7 +66,6 @@ struct intel_i2c_chan { u32 reg; /* GPIO reg */ struct i2c_adapter adapter; struct i2c_algo_bit_data algo; - u8 slave_addr; }; struct intel_framebuffer { @@ -79,11 +79,12 @@ struct intel_output { struct drm_encoder enc; int type; - struct intel_i2c_chan *i2c_bus; /* for control functions */ - struct intel_i2c_chan *ddc_bus; /* for DDC only stuff */ + struct i2c_adapter *i2c_bus; + struct i2c_adapter *ddc_bus; bool load_detect_temp; bool needs_tv_clock; void *dev_priv; + void (*hot_plug)(struct intel_output *); }; struct intel_crtc { @@ -104,9 +105,9 @@ struct intel_crtc { #define enc_to_intel_output(x) container_of(x, struct intel_output, enc) #define to_intel_framebuffer(x) container_of(x, struct intel_framebuffer, base) -struct intel_i2c_chan *intel_i2c_create(struct drm_device *dev, const u32 reg, - const char *name); -void intel_i2c_destroy(struct intel_i2c_chan *chan); +struct i2c_adapter *intel_i2c_create(struct drm_device *dev, const u32 reg, + const char *name); +void intel_i2c_destroy(struct i2c_adapter *adapter); int intel_ddc_get_modes(struct intel_output *intel_output); extern bool intel_ddc_probe(struct intel_output *intel_output); void intel_i2c_quirk_set(struct drm_device *dev, bool enable); @@ -116,6 +117,10 @@ extern bool intel_sdvo_init(struct drm_device *dev, int output_device); extern void intel_dvo_init(struct drm_device *dev); extern void intel_tv_init(struct drm_device *dev); extern void intel_lvds_init(struct drm_device *dev); +extern void intel_dp_init(struct drm_device *dev, int dp_reg); +void +intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); extern void intel_crtc_load_lut(struct drm_crtc *crtc); extern void intel_encoder_prepare (struct drm_encoder *encoder); diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c index 1ee3007d6ec..13bff20930e 100644 --- a/drivers/gpu/drm/i915/intel_dvo.c +++ b/drivers/gpu/drm/i915/intel_dvo.c @@ -384,10 +384,9 @@ void intel_dvo_init(struct drm_device *dev) { struct intel_output *intel_output; struct intel_dvo_device *dvo; - struct intel_i2c_chan *i2cbus = NULL; + struct i2c_adapter *i2cbus = NULL; int ret = 0; int i; - int gpio_inited = 0; int encoder_type = DRM_MODE_ENCODER_NONE; intel_output = kzalloc (sizeof(struct intel_output), GFP_KERNEL); if (!intel_output) @@ -420,14 +419,11 @@ void intel_dvo_init(struct drm_device *dev) * It appears that everything is on GPIOE except for panels * on i830 laptops, which are on GPIOB (DVOA). */ - if (gpio_inited != gpio) { - if (i2cbus != NULL) - intel_i2c_destroy(i2cbus); - if (!(i2cbus = intel_i2c_create(dev, gpio, - gpio == GPIOB ? "DVOI2C_B" : "DVOI2C_E"))) { - continue; - } - gpio_inited = gpio; + if (i2cbus != NULL) + intel_i2c_destroy(i2cbus); + if (!(i2cbus = intel_i2c_create(dev, gpio, + gpio == GPIOB ? "DVOI2C_B" : "DVOI2C_E"))) { + continue; } if (dvo->dev_ops!= NULL) diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 4ea2a651b92..9e30daae37d 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -31,6 +31,7 @@ #include "drmP.h" #include "drm.h" #include "drm_crtc.h" +#include "drm_edid.h" #include "intel_drv.h" #include "i915_drm.h" #include "i915_drv.h" @@ -56,8 +57,7 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder, sdvox = SDVO_ENCODING_HDMI | SDVO_BORDER_ENABLE | SDVO_VSYNC_ACTIVE_HIGH | - SDVO_HSYNC_ACTIVE_HIGH | - SDVO_NULL_PACKETS_DURING_VSYNC; + SDVO_HSYNC_ACTIVE_HIGH; if (hdmi_priv->has_hdmi_sink) sdvox |= SDVO_AUDIO_ENABLE; @@ -129,20 +129,26 @@ static bool intel_hdmi_mode_fixup(struct drm_encoder *encoder, return true; } -static void -intel_hdmi_sink_detect(struct drm_connector *connector) +static enum drm_connector_status +intel_hdmi_edid_detect(struct drm_connector *connector) { struct intel_output *intel_output = to_intel_output(connector); struct intel_hdmi_priv *hdmi_priv = intel_output->dev_priv; struct edid *edid = NULL; + enum drm_connector_status status = connector_status_disconnected; edid = drm_get_edid(&intel_output->base, - &intel_output->ddc_bus->adapter); - if (edid != NULL) { - hdmi_priv->has_hdmi_sink = drm_detect_hdmi_monitor(edid); - kfree(edid); + intel_output->ddc_bus); + hdmi_priv->has_hdmi_sink = false; + if (edid) { + if (edid->input & DRM_EDID_INPUT_DIGITAL) { + status = connector_status_connected; + hdmi_priv->has_hdmi_sink = drm_detect_hdmi_monitor(edid); + } intel_output->base.display_info.raw_edid = NULL; + kfree(edid); } + return status; } static enum drm_connector_status @@ -154,11 +160,7 @@ igdng_hdmi_detect(struct drm_connector *connector) /* FIXME hotplug detect */ hdmi_priv->has_hdmi_sink = false; - intel_hdmi_sink_detect(connector); - if (hdmi_priv->has_hdmi_sink) - return connector_status_connected; - else - return connector_status_disconnected; + return intel_hdmi_edid_detect(connector); } static enum drm_connector_status @@ -201,10 +203,9 @@ intel_hdmi_detect(struct drm_connector *connector) return connector_status_unknown; } - if ((I915_READ(PORT_HOTPLUG_STAT) & bit) != 0) { - intel_hdmi_sink_detect(connector); - return connector_status_connected; - } else + if ((I915_READ(PORT_HOTPLUG_STAT) & bit) != 0) + return intel_hdmi_edid_detect(connector); + else return connector_status_disconnected; } diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index f7061f68d05..62b8bead765 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -124,6 +124,7 @@ static void set_data(void *data, int state_high) * @output: driver specific output device * @reg: GPIO reg to use * @name: name for this bus + * @slave_addr: slave address (if fixed) * * Creates and registers a new i2c bus with the Linux i2c layer, for use * in output probing and control (e.g. DDC or SDVO control functions). @@ -139,8 +140,8 @@ static void set_data(void *data, int state_high) * %GPIOH * see PRM for details on how these different busses are used. */ -struct intel_i2c_chan *intel_i2c_create(struct drm_device *dev, const u32 reg, - const char *name) +struct i2c_adapter *intel_i2c_create(struct drm_device *dev, const u32 reg, + const char *name) { struct intel_i2c_chan *chan; @@ -174,7 +175,7 @@ struct intel_i2c_chan *intel_i2c_create(struct drm_device *dev, const u32 reg, intel_i2c_quirk_set(dev, false); udelay(20); - return chan; + return &chan->adapter; out_free: kfree(chan); @@ -187,11 +188,16 @@ out_free: * * Unregister the adapter from the i2c layer, then free the structure. */ -void intel_i2c_destroy(struct intel_i2c_chan *chan) +void intel_i2c_destroy(struct i2c_adapter *adapter) { - if (!chan) + struct intel_i2c_chan *chan; + + if (!adapter) return; + chan = container_of(adapter, + struct intel_i2c_chan, + adapter); i2c_del_adapter(&chan->adapter); kfree(chan); } diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index f073ed8432e..9564ca44a97 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -39,6 +39,21 @@ #define I915_LVDS "i915_lvds" +/* + * the following four scaling options are defined. + * #define DRM_MODE_SCALE_NON_GPU 0 + * #define DRM_MODE_SCALE_FULLSCREEN 1 + * #define DRM_MODE_SCALE_NO_SCALE 2 + * #define DRM_MODE_SCALE_ASPECT 3 + */ + +/* Private structure for the integrated LVDS support */ +struct intel_lvds_priv { + int fitting_mode; + u32 pfit_control; + u32 pfit_pgm_ratios; +}; + /** * Sets the backlight level. * @@ -213,10 +228,27 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { + /* + * float point operation is not supported . So the PANEL_RATIO_FACTOR + * is defined, which can avoid the float point computation when + * calculating the panel ratio. + */ +#define PANEL_RATIO_FACTOR 8192 struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); struct drm_encoder *tmp_encoder; + struct intel_output *intel_output = enc_to_intel_output(encoder); + struct intel_lvds_priv *lvds_priv = intel_output->dev_priv; + u32 pfit_control = 0, pfit_pgm_ratios = 0; + int left_border = 0, right_border = 0, top_border = 0; + int bottom_border = 0; + bool border = 0; + int panel_ratio, desired_ratio, vert_scale, horiz_scale; + int horiz_ratio, vert_ratio; + u32 hsync_width, vsync_width; + u32 hblank_width, vblank_width; + u32 hsync_pos, vsync_pos; /* Should never happen!! */ if (!IS_I965G(dev) && intel_crtc->pipe == 0) { @@ -232,7 +264,9 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, return false; } } - + /* If we don't have a panel mode, there is nothing we can do */ + if (dev_priv->panel_fixed_mode == NULL) + return true; /* * If we have timings from the BIOS for the panel, put them in * to the adjusted mode. The CRTC will be set up for this mode, @@ -256,6 +290,243 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V); } + /* Make sure pre-965s set dither correctly */ + if (!IS_I965G(dev)) { + if (dev_priv->panel_wants_dither || dev_priv->lvds_dither) + pfit_control |= PANEL_8TO6_DITHER_ENABLE; + } + + /* Native modes don't need fitting */ + if (adjusted_mode->hdisplay == mode->hdisplay && + adjusted_mode->vdisplay == mode->vdisplay) { + pfit_pgm_ratios = 0; + border = 0; + goto out; + } + + /* 965+ wants fuzzy fitting */ + if (IS_I965G(dev)) + pfit_control |= (intel_crtc->pipe << PFIT_PIPE_SHIFT) | + PFIT_FILTER_FUZZY; + + hsync_width = adjusted_mode->crtc_hsync_end - + adjusted_mode->crtc_hsync_start; + vsync_width = adjusted_mode->crtc_vsync_end - + adjusted_mode->crtc_vsync_start; + hblank_width = adjusted_mode->crtc_hblank_end - + adjusted_mode->crtc_hblank_start; + vblank_width = adjusted_mode->crtc_vblank_end - + adjusted_mode->crtc_vblank_start; + /* + * Deal with panel fitting options. Figure out how to stretch the + * image based on its aspect ratio & the current panel fitting mode. + */ + panel_ratio = adjusted_mode->hdisplay * PANEL_RATIO_FACTOR / + adjusted_mode->vdisplay; + desired_ratio = mode->hdisplay * PANEL_RATIO_FACTOR / + mode->vdisplay; + /* + * Enable automatic panel scaling for non-native modes so that they fill + * the screen. Should be enabled before the pipe is enabled, according + * to register description and PRM. + * Change the value here to see the borders for debugging + */ + I915_WRITE(BCLRPAT_A, 0); + I915_WRITE(BCLRPAT_B, 0); + + switch (lvds_priv->fitting_mode) { + case DRM_MODE_SCALE_NO_SCALE: + /* + * For centered modes, we have to calculate border widths & + * heights and modify the values programmed into the CRTC. + */ + left_border = (adjusted_mode->hdisplay - mode->hdisplay) / 2; + right_border = left_border; + if (mode->hdisplay & 1) + right_border++; + top_border = (adjusted_mode->vdisplay - mode->vdisplay) / 2; + bottom_border = top_border; + if (mode->vdisplay & 1) + bottom_border++; + /* Set active & border values */ + adjusted_mode->crtc_hdisplay = mode->hdisplay; + /* Keep the boder be even */ + if (right_border & 1) + right_border++; + /* use the border directly instead of border minuse one */ + adjusted_mode->crtc_hblank_start = mode->hdisplay + + right_border; + /* keep the blank width constant */ + adjusted_mode->crtc_hblank_end = + adjusted_mode->crtc_hblank_start + hblank_width; + /* get the hsync pos relative to hblank start */ + hsync_pos = (hblank_width - hsync_width) / 2; + /* keep the hsync pos be even */ + if (hsync_pos & 1) + hsync_pos++; + adjusted_mode->crtc_hsync_start = + adjusted_mode->crtc_hblank_start + hsync_pos; + /* keep the hsync width constant */ + adjusted_mode->crtc_hsync_end = + adjusted_mode->crtc_hsync_start + hsync_width; + adjusted_mode->crtc_vdisplay = mode->vdisplay; + /* use the border instead of border minus one */ + adjusted_mode->crtc_vblank_start = mode->vdisplay + + bottom_border; + /* keep the vblank width constant */ + adjusted_mode->crtc_vblank_end = + adjusted_mode->crtc_vblank_start + vblank_width; + /* get the vsync start postion relative to vblank start */ + vsync_pos = (vblank_width - vsync_width) / 2; + adjusted_mode->crtc_vsync_start = + adjusted_mode->crtc_vblank_start + vsync_pos; + /* keep the vsync width constant */ + adjusted_mode->crtc_vsync_end = + adjusted_mode->crtc_vblank_start + vsync_width; + border = 1; + break; + case DRM_MODE_SCALE_ASPECT: + /* Scale but preserve the spect ratio */ + pfit_control |= PFIT_ENABLE; + if (IS_I965G(dev)) { + /* 965+ is easy, it does everything in hw */ + if (panel_ratio > desired_ratio) + pfit_control |= PFIT_SCALING_PILLAR; + else if (panel_ratio < desired_ratio) + pfit_control |= PFIT_SCALING_LETTER; + else + pfit_control |= PFIT_SCALING_AUTO; + } else { + /* + * For earlier chips we have to calculate the scaling + * ratio by hand and program it into the + * PFIT_PGM_RATIO register + */ + u32 horiz_bits, vert_bits, bits = 12; + horiz_ratio = mode->hdisplay * PANEL_RATIO_FACTOR/ + adjusted_mode->hdisplay; + vert_ratio = mode->vdisplay * PANEL_RATIO_FACTOR/ + adjusted_mode->vdisplay; + horiz_scale = adjusted_mode->hdisplay * + PANEL_RATIO_FACTOR / mode->hdisplay; + vert_scale = adjusted_mode->vdisplay * + PANEL_RATIO_FACTOR / mode->vdisplay; + + /* retain aspect ratio */ + if (panel_ratio > desired_ratio) { /* Pillar */ + u32 scaled_width; + scaled_width = mode->hdisplay * vert_scale / + PANEL_RATIO_FACTOR; + horiz_ratio = vert_ratio; + pfit_control |= (VERT_AUTO_SCALE | + VERT_INTERP_BILINEAR | + HORIZ_INTERP_BILINEAR); + /* Pillar will have left/right borders */ + left_border = (adjusted_mode->hdisplay - + scaled_width) / 2; + right_border = left_border; + if (mode->hdisplay & 1) /* odd resolutions */ + right_border++; + /* keep the border be even */ + if (right_border & 1) + right_border++; + adjusted_mode->crtc_hdisplay = scaled_width; + /* use border instead of border minus one */ + adjusted_mode->crtc_hblank_start = + scaled_width + right_border; + /* keep the hblank width constant */ + adjusted_mode->crtc_hblank_end = + adjusted_mode->crtc_hblank_start + + hblank_width; + /* + * get the hsync start pos relative to + * hblank start + */ + hsync_pos = (hblank_width - hsync_width) / 2; + /* keep the hsync_pos be even */ + if (hsync_pos & 1) + hsync_pos++; + adjusted_mode->crtc_hsync_start = + adjusted_mode->crtc_hblank_start + + hsync_pos; + /* keept hsync width constant */ + adjusted_mode->crtc_hsync_end = + adjusted_mode->crtc_hsync_start + + hsync_width; + border = 1; + } else if (panel_ratio < desired_ratio) { /* letter */ + u32 scaled_height = mode->vdisplay * + horiz_scale / PANEL_RATIO_FACTOR; + vert_ratio = horiz_ratio; + pfit_control |= (HORIZ_AUTO_SCALE | + VERT_INTERP_BILINEAR | + HORIZ_INTERP_BILINEAR); + /* Letterbox will have top/bottom border */ + top_border = (adjusted_mode->vdisplay - + scaled_height) / 2; + bottom_border = top_border; + if (mode->vdisplay & 1) + bottom_border++; + adjusted_mode->crtc_vdisplay = scaled_height; + /* use border instead of border minus one */ + adjusted_mode->crtc_vblank_start = + scaled_height + bottom_border; + /* keep the vblank width constant */ + adjusted_mode->crtc_vblank_end = + adjusted_mode->crtc_vblank_start + + vblank_width; + /* + * get the vsync start pos relative to + * vblank start + */ + vsync_pos = (vblank_width - vsync_width) / 2; + adjusted_mode->crtc_vsync_start = + adjusted_mode->crtc_vblank_start + + vsync_pos; + /* keep the vsync width constant */ + adjusted_mode->crtc_vsync_end = + adjusted_mode->crtc_vsync_start + + vsync_width; + border = 1; + } else { + /* Aspects match, Let hw scale both directions */ + pfit_control |= (VERT_AUTO_SCALE | + HORIZ_AUTO_SCALE | + VERT_INTERP_BILINEAR | + HORIZ_INTERP_BILINEAR); + } + horiz_bits = (1 << bits) * horiz_ratio / + PANEL_RATIO_FACTOR; + vert_bits = (1 << bits) * vert_ratio / + PANEL_RATIO_FACTOR; + pfit_pgm_ratios = + ((vert_bits << PFIT_VERT_SCALE_SHIFT) & + PFIT_VERT_SCALE_MASK) | + ((horiz_bits << PFIT_HORIZ_SCALE_SHIFT) & + PFIT_HORIZ_SCALE_MASK); + } + break; + + case DRM_MODE_SCALE_FULLSCREEN: + /* + * Full scaling, even if it changes the aspect ratio. + * Fortunately this is all done for us in hw. + */ + pfit_control |= PFIT_ENABLE; + if (IS_I965G(dev)) + pfit_control |= PFIT_SCALING_AUTO; + else + pfit_control |= (VERT_AUTO_SCALE | HORIZ_AUTO_SCALE | + VERT_INTERP_BILINEAR | + HORIZ_INTERP_BILINEAR); + break; + default: + break; + } + +out: + lvds_priv->pfit_control = pfit_control; + lvds_priv->pfit_pgm_ratios = pfit_pgm_ratios; /* * XXX: It would be nice to support lower refresh rates on the * panels to reduce power consumption, and perhaps match the @@ -301,8 +572,8 @@ static void intel_lvds_mode_set(struct drm_encoder *encoder, { struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); - u32 pfit_control; + struct intel_output *intel_output = enc_to_intel_output(encoder); + struct intel_lvds_priv *lvds_priv = intel_output->dev_priv; /* * The LVDS pin pair will already have been turned on in the @@ -319,22 +590,8 @@ static void intel_lvds_mode_set(struct drm_encoder *encoder, * screen. Should be enabled before the pipe is enabled, according to * register description and PRM. */ - if (mode->hdisplay != adjusted_mode->hdisplay || - mode->vdisplay != adjusted_mode->vdisplay) - pfit_control = (PFIT_ENABLE | VERT_AUTO_SCALE | - HORIZ_AUTO_SCALE | VERT_INTERP_BILINEAR | - HORIZ_INTERP_BILINEAR); - else - pfit_control = 0; - - if (!IS_I965G(dev)) { - if (dev_priv->panel_wants_dither || dev_priv->lvds_dither) - pfit_control |= PANEL_8TO6_DITHER_ENABLE; - } - else - pfit_control |= intel_crtc->pipe << PFIT_PIPE_SHIFT; - - I915_WRITE(PFIT_CONTROL, pfit_control); + I915_WRITE(PFIT_PGM_RATIOS, lvds_priv->pfit_pgm_ratios); + I915_WRITE(PFIT_CONTROL, lvds_priv->pfit_control); } /** @@ -406,6 +663,34 @@ static int intel_lvds_set_property(struct drm_connector *connector, struct drm_property *property, uint64_t value) { + struct drm_device *dev = connector->dev; + struct intel_output *intel_output = + to_intel_output(connector); + + if (property == dev->mode_config.scaling_mode_property && + connector->encoder) { + struct drm_crtc *crtc = connector->encoder->crtc; + struct intel_lvds_priv *lvds_priv = intel_output->dev_priv; + if (value == DRM_MODE_SCALE_NON_GPU) { + DRM_DEBUG_KMS(I915_LVDS, + "non_GPU property is unsupported\n"); + return 0; + } + if (lvds_priv->fitting_mode == value) { + /* the LVDS scaling property is not changed */ + return 0; + } + lvds_priv->fitting_mode = value; + if (crtc && crtc->enabled) { + /* + * If the CRTC is enabled, the display will be changed + * according to the new panel fitting mode. + */ + drm_crtc_helper_set_mode(crtc, &crtc->mode, + crtc->x, crtc->y, crtc->fb); + } + } + return 0; } @@ -456,7 +741,7 @@ static const struct dmi_system_id intel_no_lvds[] = { .callback = intel_no_lvds_dmi_callback, .ident = "Apple Mac Mini (Core series)", .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), + DMI_MATCH(DMI_SYS_VENDOR, "Apple"), DMI_MATCH(DMI_PRODUCT_NAME, "Macmini1,1"), }, }, @@ -464,7 +749,7 @@ static const struct dmi_system_id intel_no_lvds[] = { .callback = intel_no_lvds_dmi_callback, .ident = "Apple Mac Mini (Core 2 series)", .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), + DMI_MATCH(DMI_SYS_VENDOR, "Apple"), DMI_MATCH(DMI_PRODUCT_NAME, "Macmini2,1"), }, }, @@ -518,6 +803,7 @@ void intel_lvds_init(struct drm_device *dev) struct drm_encoder *encoder; struct drm_display_mode *scan; /* *modes, *bios_mode; */ struct drm_crtc *crtc; + struct intel_lvds_priv *lvds_priv; u32 lvds; int pipe, gpio = GPIOC; @@ -531,7 +817,8 @@ void intel_lvds_init(struct drm_device *dev) gpio = PCH_GPIOC; } - intel_output = kzalloc(sizeof(struct intel_output), GFP_KERNEL); + intel_output = kzalloc(sizeof(struct intel_output) + + sizeof(struct intel_lvds_priv), GFP_KERNEL); if (!intel_output) { return; } @@ -553,7 +840,18 @@ void intel_lvds_init(struct drm_device *dev) connector->interlace_allowed = false; connector->doublescan_allowed = false; + lvds_priv = (struct intel_lvds_priv *)(intel_output + 1); + intel_output->dev_priv = lvds_priv; + /* create the scaling mode property */ + drm_mode_create_scaling_mode_property(dev); + /* + * the initial panel fitting mode will be FULL_SCREEN. + */ + drm_connector_attach_property(&intel_output->base, + dev->mode_config.scaling_mode_property, + DRM_MODE_SCALE_FULLSCREEN); + lvds_priv->fitting_mode = DRM_MODE_SCALE_FULLSCREEN; /* * LVDS discovery: * 1) check for EDID on DDC @@ -649,5 +947,5 @@ failed: if (intel_output->ddc_bus) intel_i2c_destroy(intel_output->ddc_bus); drm_connector_cleanup(connector); - kfree(connector); + kfree(intel_output); } diff --git a/drivers/gpu/drm/i915/intel_modes.c b/drivers/gpu/drm/i915/intel_modes.c index e0910fefce8..67e2f4632a2 100644 --- a/drivers/gpu/drm/i915/intel_modes.c +++ b/drivers/gpu/drm/i915/intel_modes.c @@ -53,10 +53,9 @@ bool intel_ddc_probe(struct intel_output *intel_output) } }; - intel_i2c_quirk_set(intel_output->ddc_bus->drm_dev, true); - ret = i2c_transfer(&intel_output->ddc_bus->adapter, msgs, 2); - intel_i2c_quirk_set(intel_output->ddc_bus->drm_dev, false); - + intel_i2c_quirk_set(intel_output->base.dev, true); + ret = i2c_transfer(intel_output->ddc_bus, msgs, 2); + intel_i2c_quirk_set(intel_output->base.dev, false); if (ret == 2) return true; @@ -74,10 +73,9 @@ int intel_ddc_get_modes(struct intel_output *intel_output) struct edid *edid; int ret = 0; - intel_i2c_quirk_set(intel_output->ddc_bus->drm_dev, true); - edid = drm_get_edid(&intel_output->base, - &intel_output->ddc_bus->adapter); - intel_i2c_quirk_set(intel_output->ddc_bus->drm_dev, false); + intel_i2c_quirk_set(intel_output->base.dev, true); + edid = drm_get_edid(&intel_output->base, intel_output->ddc_bus); + intel_i2c_quirk_set(intel_output->base.dev, false); if (edid) { drm_mode_connector_update_edid_property(&intel_output->base, edid); diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 9a00adb3a50..f03473779fe 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -38,8 +38,7 @@ #undef SDVO_DEBUG #define I915_SDVO "i915_sdvo" struct intel_sdvo_priv { - struct intel_i2c_chan *i2c_bus; - int slaveaddr; + u8 slave_addr; /* Register for the SDVO device: SDVOB or SDVOC */ int output_device; @@ -146,13 +145,13 @@ static bool intel_sdvo_read_byte(struct intel_output *intel_output, u8 addr, struct i2c_msg msgs[] = { { - .addr = sdvo_priv->i2c_bus->slave_addr, + .addr = sdvo_priv->slave_addr >> 1, .flags = 0, .len = 1, .buf = out_buf, }, { - .addr = sdvo_priv->i2c_bus->slave_addr, + .addr = sdvo_priv->slave_addr >> 1, .flags = I2C_M_RD, .len = 1, .buf = buf, @@ -162,7 +161,7 @@ static bool intel_sdvo_read_byte(struct intel_output *intel_output, u8 addr, out_buf[0] = addr; out_buf[1] = 0; - if ((ret = i2c_transfer(&sdvo_priv->i2c_bus->adapter, msgs, 2)) == 2) + if ((ret = i2c_transfer(intel_output->i2c_bus, msgs, 2)) == 2) { *ch = buf[0]; return true; @@ -175,10 +174,11 @@ static bool intel_sdvo_read_byte(struct intel_output *intel_output, u8 addr, static bool intel_sdvo_write_byte(struct intel_output *intel_output, int addr, u8 ch) { + struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; u8 out_buf[2]; struct i2c_msg msgs[] = { { - .addr = intel_output->i2c_bus->slave_addr, + .addr = sdvo_priv->slave_addr >> 1, .flags = 0, .len = 2, .buf = out_buf, @@ -188,7 +188,7 @@ static bool intel_sdvo_write_byte(struct intel_output *intel_output, int addr, out_buf[0] = addr; out_buf[1] = ch; - if (i2c_transfer(&intel_output->i2c_bus->adapter, msgs, 1) == 1) + if (i2c_transfer(intel_output->i2c_bus, msgs, 1) == 1) { return true; } @@ -1369,9 +1369,8 @@ intel_sdvo_hdmi_sink_detect(struct drm_connector *connector) struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; struct edid *edid = NULL; - intel_sdvo_set_control_bus_switch(intel_output, sdvo_priv->ddc_bus); edid = drm_get_edid(&intel_output->base, - &intel_output->ddc_bus->adapter); + intel_output->ddc_bus); if (edid != NULL) { sdvo_priv->is_hdmi = drm_detect_hdmi_monitor(edid); kfree(edid); @@ -1549,7 +1548,6 @@ static void intel_sdvo_get_tv_modes(struct drm_connector *connector) static void intel_sdvo_get_lvds_modes(struct drm_connector *connector) { struct intel_output *intel_output = to_intel_output(connector); - struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; struct drm_i915_private *dev_priv = connector->dev->dev_private; /* @@ -1557,8 +1555,6 @@ static void intel_sdvo_get_lvds_modes(struct drm_connector *connector) * Assume that the preferred modes are * arranged in priority order. */ - /* set the bus switch and get the modes */ - intel_sdvo_set_control_bus_switch(intel_output, sdvo_priv->ddc_bus); intel_ddc_get_modes(intel_output); if (list_empty(&connector->probed_modes) == false) return; @@ -1709,7 +1705,7 @@ intel_sdvo_chan_to_intel_output(struct intel_i2c_chan *chan) list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - if (to_intel_output(connector)->ddc_bus == chan) { + if (to_intel_output(connector)->ddc_bus == &chan->adapter) { intel_output = to_intel_output(connector); break; } @@ -1723,7 +1719,7 @@ static int intel_sdvo_master_xfer(struct i2c_adapter *i2c_adap, struct intel_output *intel_output; struct intel_sdvo_priv *sdvo_priv; struct i2c_algo_bit_data *algo_data; - struct i2c_algorithm *algo; + const struct i2c_algorithm *algo; algo_data = (struct i2c_algo_bit_data *)i2c_adap->algo_data; intel_output = @@ -1733,7 +1729,7 @@ static int intel_sdvo_master_xfer(struct i2c_adapter *i2c_adap, return -EINVAL; sdvo_priv = intel_output->dev_priv; - algo = (struct i2c_algorithm *)intel_output->i2c_bus->adapter.algo; + algo = intel_output->i2c_bus->algo; intel_sdvo_set_control_bus_switch(intel_output, sdvo_priv->ddc_bus); return algo->master_xfer(i2c_adap, msgs, num); @@ -1785,13 +1781,11 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device) struct drm_connector *connector; struct intel_output *intel_output; struct intel_sdvo_priv *sdvo_priv; - struct intel_i2c_chan *i2cbus = NULL; - struct intel_i2c_chan *ddcbus = NULL; + int connector_type; u8 ch[0x40]; int i; - int encoder_type, output_id; - u8 slave_addr; + int encoder_type; intel_output = kcalloc(sizeof(struct intel_output)+sizeof(struct intel_sdvo_priv), 1, GFP_KERNEL); if (!intel_output) { @@ -1799,29 +1793,24 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device) } sdvo_priv = (struct intel_sdvo_priv *)(intel_output + 1); + sdvo_priv->output_device = output_device; + + intel_output->dev_priv = sdvo_priv; intel_output->type = INTEL_OUTPUT_SDVO; /* setup the DDC bus. */ if (output_device == SDVOB) - i2cbus = intel_i2c_create(dev, GPIOE, "SDVOCTRL_E for SDVOB"); + intel_output->i2c_bus = intel_i2c_create(dev, GPIOE, "SDVOCTRL_E for SDVOB"); else - i2cbus = intel_i2c_create(dev, GPIOE, "SDVOCTRL_E for SDVOC"); + intel_output->i2c_bus = intel_i2c_create(dev, GPIOE, "SDVOCTRL_E for SDVOC"); - if (!i2cbus) + if (!intel_output->i2c_bus) goto err_inteloutput; - slave_addr = intel_sdvo_get_slave_addr(dev, output_device); - sdvo_priv->i2c_bus = i2cbus; + sdvo_priv->slave_addr = intel_sdvo_get_slave_addr(dev, output_device); - if (output_device == SDVOB) { - output_id = 1; - } else { - output_id = 2; - } - sdvo_priv->i2c_bus->slave_addr = slave_addr >> 1; - sdvo_priv->output_device = output_device; - intel_output->i2c_bus = i2cbus; - intel_output->dev_priv = sdvo_priv; + /* Save the bit-banging i2c functionality for use by the DDC wrapper */ + intel_sdvo_i2c_bit_algo.functionality = intel_output->i2c_bus->algo->functionality; /* Read the regs to test if we can talk to the device */ for (i = 0; i < 0x40; i++) { @@ -1835,17 +1824,15 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device) /* setup the DDC bus. */ if (output_device == SDVOB) - ddcbus = intel_i2c_create(dev, GPIOE, "SDVOB DDC BUS"); + intel_output->ddc_bus = intel_i2c_create(dev, GPIOE, "SDVOB DDC BUS"); else - ddcbus = intel_i2c_create(dev, GPIOE, "SDVOC DDC BUS"); + intel_output->ddc_bus = intel_i2c_create(dev, GPIOE, "SDVOC DDC BUS"); - if (ddcbus == NULL) + if (intel_output->ddc_bus == NULL) goto err_i2c; - intel_sdvo_i2c_bit_algo.functionality = - intel_output->i2c_bus->adapter.algo->functionality; - ddcbus->adapter.algo = &intel_sdvo_i2c_bit_algo; - intel_output->ddc_bus = ddcbus; + /* Wrap with our custom algo which switches to DDC mode */ + intel_output->ddc_bus->algo = &intel_sdvo_i2c_bit_algo; /* In defaut case sdvo lvds is false */ sdvo_priv->is_lvds = false; @@ -1965,9 +1952,10 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device) return true; err_i2c: - if (ddcbus != NULL) + if (intel_output->ddc_bus != NULL) intel_i2c_destroy(intel_output->ddc_bus); - intel_i2c_destroy(intel_output->i2c_bus); + if (intel_output->i2c_bus != NULL) + intel_i2c_destroy(intel_output->i2c_bus); err_inteloutput: kfree(intel_output); diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index ea68992e441..a43c98e3f07 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -1383,34 +1383,31 @@ intel_tv_detect_type (struct drm_crtc *crtc, struct intel_output *intel_output) /* * Detect TV by polling) */ - if (intel_output->load_detect_temp) { - /* TV not currently running, prod it with destructive detect */ - save_tv_dac = tv_dac; - tv_ctl = I915_READ(TV_CTL); - save_tv_ctl = tv_ctl; - tv_ctl &= ~TV_ENC_ENABLE; - tv_ctl &= ~TV_TEST_MODE_MASK; - tv_ctl |= TV_TEST_MODE_MONITOR_DETECT; - tv_dac &= ~TVDAC_SENSE_MASK; - tv_dac &= ~DAC_A_MASK; - tv_dac &= ~DAC_B_MASK; - tv_dac &= ~DAC_C_MASK; - tv_dac |= (TVDAC_STATE_CHG_EN | - TVDAC_A_SENSE_CTL | - TVDAC_B_SENSE_CTL | - TVDAC_C_SENSE_CTL | - DAC_CTL_OVERRIDE | - DAC_A_0_7_V | - DAC_B_0_7_V | - DAC_C_0_7_V); - I915_WRITE(TV_CTL, tv_ctl); - I915_WRITE(TV_DAC, tv_dac); - intel_wait_for_vblank(dev); - tv_dac = I915_READ(TV_DAC); - I915_WRITE(TV_DAC, save_tv_dac); - I915_WRITE(TV_CTL, save_tv_ctl); - intel_wait_for_vblank(dev); - } + save_tv_dac = tv_dac; + tv_ctl = I915_READ(TV_CTL); + save_tv_ctl = tv_ctl; + tv_ctl &= ~TV_ENC_ENABLE; + tv_ctl &= ~TV_TEST_MODE_MASK; + tv_ctl |= TV_TEST_MODE_MONITOR_DETECT; + tv_dac &= ~TVDAC_SENSE_MASK; + tv_dac &= ~DAC_A_MASK; + tv_dac &= ~DAC_B_MASK; + tv_dac &= ~DAC_C_MASK; + tv_dac |= (TVDAC_STATE_CHG_EN | + TVDAC_A_SENSE_CTL | + TVDAC_B_SENSE_CTL | + TVDAC_C_SENSE_CTL | + DAC_CTL_OVERRIDE | + DAC_A_0_7_V | + DAC_B_0_7_V | + DAC_C_0_7_V); + I915_WRITE(TV_CTL, tv_ctl); + I915_WRITE(TV_DAC, tv_dac); + intel_wait_for_vblank(dev); + tv_dac = I915_READ(TV_DAC); + I915_WRITE(TV_DAC, save_tv_dac); + I915_WRITE(TV_CTL, save_tv_ctl); + intel_wait_for_vblank(dev); /* * A B C * 0 1 1 Composite diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index f30aa7274a5..f97563db4e5 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -35,6 +35,23 @@ #include "atom.h" /* + * Clear GPU surface registers. + */ +static void radeon_surface_init(struct radeon_device *rdev) +{ + /* FIXME: check this out */ + if (rdev->family < CHIP_R600) { + int i; + + for (i = 0; i < 8; i++) { + WREG32(RADEON_SURFACE0_INFO + + i * (RADEON_SURFACE1_INFO - RADEON_SURFACE0_INFO), + 0); + } + } +} + +/* * GPU scratch registers helpers function. */ static void radeon_scratch_init(struct radeon_device *rdev) @@ -496,6 +513,8 @@ int radeon_device_init(struct radeon_device *rdev, radeon_errata(rdev); /* Initialize scratch registers */ radeon_scratch_init(rdev); + /* Initialize surface registers */ + radeon_surface_init(rdev); /* TODO: disable VGA need to use VGA request */ /* BIOS*/ @@ -604,9 +623,6 @@ int radeon_device_init(struct radeon_device *rdev, if (r) { return r; } - if (rdev->fbdev_rfb && rdev->fbdev_rfb->obj) { - rdev->fbdev_robj = rdev->fbdev_rfb->obj->driver_private; - } if (!ret) { DRM_INFO("radeon: kernel modesetting successfully initialized.\n"); } diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index 09c9fb9f621..84ba69f4878 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -345,7 +345,7 @@ static void __exit radeon_exit(void) drm_exit(driver); } -late_initcall(radeon_init); +module_init(radeon_init); module_exit(radeon_exit); MODULE_AUTHOR(DRIVER_AUTHOR); diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c index fa86d398945..9e8f191eb64 100644 --- a/drivers/gpu/drm/radeon/radeon_fb.c +++ b/drivers/gpu/drm/radeon/radeon_fb.c @@ -478,14 +478,16 @@ int radeonfb_create(struct radeon_device *rdev, { struct fb_info *info; struct radeon_fb_device *rfbdev; - struct drm_framebuffer *fb; + struct drm_framebuffer *fb = NULL; struct radeon_framebuffer *rfb; struct drm_mode_fb_cmd mode_cmd; struct drm_gem_object *gobj = NULL; struct radeon_object *robj = NULL; struct device *device = &rdev->pdev->dev; int size, aligned_size, ret; + u64 fb_gpuaddr; void *fbptr = NULL; + unsigned long tmp; mode_cmd.width = surface_width; mode_cmd.height = surface_height; @@ -498,11 +500,12 @@ int radeonfb_create(struct radeon_device *rdev, aligned_size = ALIGN(size, PAGE_SIZE); ret = radeon_gem_object_create(rdev, aligned_size, 0, - RADEON_GEM_DOMAIN_VRAM, - false, ttm_bo_type_kernel, - false, &gobj); + RADEON_GEM_DOMAIN_VRAM, + false, ttm_bo_type_kernel, + false, &gobj); if (ret) { - printk(KERN_ERR "failed to allocate framebuffer\n"); + printk(KERN_ERR "failed to allocate framebuffer (%d %d)\n", + surface_width, surface_height); ret = -ENOMEM; goto out; } @@ -515,12 +518,19 @@ int radeonfb_create(struct radeon_device *rdev, ret = -ENOMEM; goto out_unref; } + ret = radeon_object_pin(robj, RADEON_GEM_DOMAIN_VRAM, &fb_gpuaddr); + if (ret) { + printk(KERN_ERR "failed to pin framebuffer\n"); + ret = -ENOMEM; + goto out_unref; + } list_add(&fb->filp_head, &rdev->ddev->mode_config.fb_kernel_list); rfb = to_radeon_framebuffer(fb); *rfb_p = rfb; rdev->fbdev_rfb = rfb; + rdev->fbdev_robj = robj; info = framebuffer_alloc(sizeof(struct radeon_fb_device), device); if (info == NULL) { @@ -541,13 +551,13 @@ int radeonfb_create(struct radeon_device *rdev, info->fix.xpanstep = 1; /* doing it in hw */ info->fix.ypanstep = 1; /* doing it in hw */ info->fix.ywrapstep = 0; - info->fix.accel = FB_ACCEL_I830; + info->fix.accel = FB_ACCEL_NONE; info->fix.type_aux = 0; info->flags = FBINFO_DEFAULT; info->fbops = &radeonfb_ops; info->fix.line_length = fb->pitch; - info->screen_base = fbptr; - info->fix.smem_start = (unsigned long)fbptr; + tmp = fb_gpuaddr - rdev->mc.vram_location; + info->fix.smem_start = rdev->mc.aper_base + tmp; info->fix.smem_len = size; info->screen_base = fbptr; info->screen_size = size; @@ -562,8 +572,8 @@ int radeonfb_create(struct radeon_device *rdev, info->var.width = -1; info->var.xres = fb_width; info->var.yres = fb_height; - info->fix.mmio_start = pci_resource_start(rdev->pdev, 2); - info->fix.mmio_len = pci_resource_len(rdev->pdev, 2); + info->fix.mmio_start = 0; + info->fix.mmio_len = 0; info->pixmap.size = 64*1024; info->pixmap.buf_align = 8; info->pixmap.access_align = 32; @@ -644,7 +654,7 @@ out_unref: if (robj) { radeon_object_kunmap(robj); } - if (ret) { + if (fb && ret) { list_del(&fb->filp_head); drm_gem_object_unreference(gobj); drm_framebuffer_cleanup(fb); @@ -813,6 +823,7 @@ int radeonfb_remove(struct drm_device *dev, struct drm_framebuffer *fb) robj = rfb->obj->driver_private; unregister_framebuffer(info); radeon_object_kunmap(robj); + radeon_object_unpin(robj); framebuffer_release(info); } diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index 983e8df5e00..bac0d06c52a 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -223,7 +223,6 @@ int radeon_object_pin(struct radeon_object *robj, uint32_t domain, { uint32_t flags; uint32_t tmp; - void *fbptr; int r; flags = radeon_object_flags_from_domain(domain); @@ -242,10 +241,6 @@ int radeon_object_pin(struct radeon_object *robj, uint32_t domain, DRM_ERROR("radeon: failed to reserve object for pinning it.\n"); return r; } - if (robj->rdev->fbdev_robj == robj) { - mutex_lock(&robj->rdev->fbdev_info->lock); - radeon_object_kunmap(robj); - } tmp = robj->tobj.mem.placement; ttm_flag_masked(&tmp, flags, TTM_PL_MASK_MEM); robj->tobj.proposed_placement = tmp | TTM_PL_FLAG_NO_EVICT | TTM_PL_MASK_CACHING; @@ -261,23 +256,12 @@ int radeon_object_pin(struct radeon_object *robj, uint32_t domain, DRM_ERROR("radeon: failed to pin object.\n"); } radeon_object_unreserve(robj); - if (robj->rdev->fbdev_robj == robj) { - if (!r) { - r = radeon_object_kmap(robj, &fbptr); - } - if (!r) { - robj->rdev->fbdev_info->screen_base = fbptr; - robj->rdev->fbdev_info->fix.smem_start = (unsigned long)fbptr; - } - mutex_unlock(&robj->rdev->fbdev_info->lock); - } return r; } void radeon_object_unpin(struct radeon_object *robj) { uint32_t flags; - void *fbptr; int r; spin_lock(&robj->tobj.lock); @@ -297,10 +281,6 @@ void radeon_object_unpin(struct radeon_object *robj) DRM_ERROR("radeon: failed to reserve object for unpinning it.\n"); return; } - if (robj->rdev->fbdev_robj == robj) { - mutex_lock(&robj->rdev->fbdev_info->lock); - radeon_object_kunmap(robj); - } flags = robj->tobj.mem.placement; robj->tobj.proposed_placement = flags & ~TTM_PL_FLAG_NO_EVICT; r = ttm_buffer_object_validate(&robj->tobj, @@ -310,16 +290,6 @@ void radeon_object_unpin(struct radeon_object *robj) DRM_ERROR("radeon: failed to unpin buffer.\n"); } radeon_object_unreserve(robj); - if (robj->rdev->fbdev_robj == robj) { - if (!r) { - r = radeon_object_kmap(robj, &fbptr); - } - if (!r) { - robj->rdev->fbdev_info->screen_base = fbptr; - robj->rdev->fbdev_info->fix.smem_start = (unsigned long)fbptr; - } - mutex_unlock(&robj->rdev->fbdev_info->lock); - } } int radeon_object_wait(struct radeon_object *robj) diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c index 517c8455963..bdec583901e 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_util.c +++ b/drivers/gpu/drm/ttm/ttm_bo_util.c @@ -34,7 +34,6 @@ #include <linux/highmem.h> #include <linux/wait.h> #include <linux/vmalloc.h> -#include <linux/version.h> #include <linux/module.h> void ttm_bo_free_old_node(struct ttm_buffer_object *bo) diff --git a/drivers/gpu/drm/ttm/ttm_bo_vm.c b/drivers/gpu/drm/ttm/ttm_bo_vm.c index 27b146c54fb..40b75032ea4 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_vm.c +++ b/drivers/gpu/drm/ttm/ttm_bo_vm.c @@ -32,7 +32,6 @@ #include <ttm/ttm_bo_driver.h> #include <ttm/ttm_placement.h> #include <linux/mm.h> -#include <linux/version.h> #include <linux/rbtree.h> #include <linux/module.h> #include <linux/uaccess.h> diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c index 0331fa74cd3..75dc8bd2459 100644 --- a/drivers/gpu/drm/ttm/ttm_tt.c +++ b/drivers/gpu/drm/ttm/ttm_tt.c @@ -28,7 +28,6 @@ * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com> */ -#include <linux/version.h> #include <linux/vmalloc.h> #include <linux/sched.h> #include <linux/highmem.h> diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index aa87b6a3bbe..8206442fbab 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -328,6 +328,7 @@ config I2C_DAVINCI config I2C_DESIGNWARE tristate "Synopsys DesignWare" + depends on HAVE_CLK help If you say yes to this option, support will be included for the Synopsys DesignWare I2C adapter. Only master mode is supported. diff --git a/drivers/ide/cs5520.c b/drivers/ide/cs5520.c index bd066bb9d61..09f98ed0731 100644 --- a/drivers/ide/cs5520.c +++ b/drivers/ide/cs5520.c @@ -135,6 +135,7 @@ static int __devinit cs5520_init_one(struct pci_dev *dev, const struct pci_devic ide_pci_setup_ports(dev, d, &hw[0], &hws[0]); hw[0].irq = 14; + hw[1].irq = 15; return ide_host_add(d, hws, 2, NULL); } diff --git a/drivers/ide/ide-acpi.c b/drivers/ide/ide-acpi.c index 77f79d26b26..c509c991646 100644 --- a/drivers/ide/ide-acpi.c +++ b/drivers/ide/ide-acpi.c @@ -92,6 +92,11 @@ int ide_acpi_init(void) return 0; } +bool ide_port_acpi(ide_hwif_t *hwif) +{ + return ide_noacpi == 0 && hwif->acpidata; +} + /** * ide_get_dev_handle - finds acpi_handle and PCI device.function * @dev: device to locate @@ -352,9 +357,6 @@ int ide_acpi_exec_tfs(ide_drive_t *drive) unsigned long gtf_address; unsigned long obj_loc; - if (ide_noacpi) - return 0; - DEBPRINT("call get_GTF, drive=%s port=%d\n", drive->name, drive->dn); ret = do_drive_get_GTF(drive, >f_length, >f_address, &obj_loc); @@ -389,16 +391,6 @@ void ide_acpi_get_timing(ide_hwif_t *hwif) struct acpi_buffer output; union acpi_object *out_obj; - if (ide_noacpi) - return; - - DEBPRINT("ENTER:\n"); - - if (!hwif->acpidata) { - DEBPRINT("no ACPI data for %s\n", hwif->name); - return; - } - /* Setting up output buffer for _GTM */ output.length = ACPI_ALLOCATE_BUFFER; output.pointer = NULL; /* ACPI-CA sets this; save/free it later */ @@ -479,16 +471,6 @@ void ide_acpi_push_timing(ide_hwif_t *hwif) struct ide_acpi_drive_link *master = &hwif->acpidata->master; struct ide_acpi_drive_link *slave = &hwif->acpidata->slave; - if (ide_noacpi) - return; - - DEBPRINT("ENTER:\n"); - - if (!hwif->acpidata) { - DEBPRINT("no ACPI data for %s\n", hwif->name); - return; - } - /* Give the GTM buffer + drive Identify data to the channel via the * _STM method: */ /* setup input parameters buffer for _STM */ @@ -527,16 +509,11 @@ void ide_acpi_set_state(ide_hwif_t *hwif, int on) ide_drive_t *drive; int i; - if (ide_noacpi || ide_noacpi_psx) + if (ide_noacpi_psx) return; DEBPRINT("ENTER:\n"); - if (!hwif->acpidata) { - DEBPRINT("no ACPI data for %s\n", hwif->name); - return; - } - /* channel first and then drives for power on and verse versa for power off */ if (on) acpi_bus_set_power(hwif->acpidata->obj_handle, ACPI_STATE_D0); @@ -616,7 +593,7 @@ void ide_acpi_port_init_devices(ide_hwif_t *hwif) drive->name, err); } - if (!ide_acpionboot) { + if (ide_noacpi || ide_acpionboot == 0) { DEBPRINT("ACPI methods disabled on boot\n"); return; } diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index 4a19686fcfe..6a9a769bffc 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -592,9 +592,19 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive) } } else if (!blk_pc_request(rq)) { ide_cd_request_sense_fixup(drive, cmd); - /* complain if we still have data left to transfer */ + uptodate = cmd->nleft ? 0 : 1; - if (uptodate == 0) + + /* + * suck out the remaining bytes from the drive in an + * attempt to complete the data xfer. (see BZ#13399) + */ + if (!(stat & ATA_ERR) && !uptodate && thislen) { + ide_pio_bytes(drive, cmd, write, thislen); + uptodate = cmd->nleft ? 0 : 1; + } + + if (!uptodate) rq->cmd_flags |= REQ_FAILED; } goto out_end; @@ -876,9 +886,12 @@ static int cdrom_read_capacity(ide_drive_t *drive, unsigned long *capacity, return stat; /* - * Sanity check the given block size + * Sanity check the given block size, in so far as making + * sure the sectors_per_frame we give to the caller won't + * end up being bogus. */ blocklen = be32_to_cpu(capbuf.blocklen); + blocklen = (blocklen >> SECTOR_BITS) << SECTOR_BITS; switch (blocklen) { case 512: case 1024: @@ -886,10 +899,9 @@ static int cdrom_read_capacity(ide_drive_t *drive, unsigned long *capacity, case 4096: break; default: - printk(KERN_ERR PFX "%s: weird block size %u\n", + printk_once(KERN_ERR PFX "%s: weird block size %u; " + "setting default block size to 2048\n", drive->name, blocklen); - printk(KERN_ERR PFX "%s: default to 2kb block size\n", - drive->name); blocklen = 2048; break; } diff --git a/drivers/ide/ide-devsets.c b/drivers/ide/ide-devsets.c index 5bf958e5b1d..1099bf7cf96 100644 --- a/drivers/ide/ide-devsets.c +++ b/drivers/ide/ide-devsets.c @@ -183,6 +183,6 @@ ide_startstop_t ide_do_devset(ide_drive_t *drive, struct request *rq) err = setfunc(drive, *(int *)&rq->cmd[1]); if (err) rq->errors = err; - ide_complete_rq(drive, err, ide_rq_bytes(rq)); + ide_complete_rq(drive, err, blk_rq_bytes(rq)); return ide_stopped; } diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c index 219e6fb78dc..ee58c88dee5 100644 --- a/drivers/ide/ide-dma.c +++ b/drivers/ide/ide-dma.c @@ -361,9 +361,6 @@ static int ide_tune_dma(ide_drive_t *drive) if (__ide_dma_bad_drive(drive)) return 0; - if (ide_id_dma_bug(drive)) - return 0; - if (hwif->host_flags & IDE_HFLAG_TRUST_BIOS_FOR_DMA) return config_drive_for_dma(drive); @@ -394,24 +391,6 @@ static int ide_dma_check(ide_drive_t *drive) return -1; } -int ide_id_dma_bug(ide_drive_t *drive) -{ - u16 *id = drive->id; - - if (id[ATA_ID_FIELD_VALID] & 4) { - if ((id[ATA_ID_UDMA_MODES] >> 8) && - (id[ATA_ID_MWDMA_MODES] >> 8)) - goto err_out; - } else if ((id[ATA_ID_MWDMA_MODES] >> 8) && - (id[ATA_ID_SWDMA_MODES] >> 8)) - goto err_out; - - return 0; -err_out: - printk(KERN_ERR "%s: bad DMA info in identify block\n", drive->name); - return 1; -} - int ide_set_dma(ide_drive_t *drive) { int rc; diff --git a/drivers/ide/ide-eh.c b/drivers/ide/ide-eh.c index 2b914197961..e9abf2c3c33 100644 --- a/drivers/ide/ide-eh.c +++ b/drivers/ide/ide-eh.c @@ -149,7 +149,7 @@ static inline void ide_complete_drive_reset(ide_drive_t *drive, int err) if (rq && blk_special_request(rq) && rq->cmd[0] == REQ_DRIVE_RESET) { if (err <= 0 && rq->errors == 0) rq->errors = -EIO; - ide_complete_rq(drive, err ? err : 0, ide_rq_bytes(rq)); + ide_complete_rq(drive, err ? err : 0, blk_rq_bytes(rq)); } } diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c index 8b3f204f7d7..fefbdfc8db0 100644 --- a/drivers/ide/ide-floppy.c +++ b/drivers/ide/ide-floppy.c @@ -293,7 +293,7 @@ out_end: drive->failed_pc = NULL; if (blk_fs_request(rq) == 0 && rq->errors == 0) rq->errors = -EIO; - ide_complete_rq(drive, -EIO, ide_rq_bytes(rq)); + ide_complete_rq(drive, -EIO, blk_rq_bytes(rq)); return ide_stopped; } diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index 1059f809b80..d5f3c77bead 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c @@ -112,16 +112,6 @@ void ide_complete_cmd(ide_drive_t *drive, struct ide_cmd *cmd, u8 stat, u8 err) } } -/* obsolete, blk_rq_bytes() should be used instead */ -unsigned int ide_rq_bytes(struct request *rq) -{ - if (blk_pc_request(rq)) - return blk_rq_bytes(rq); - else - return blk_rq_cur_sectors(rq) << 9; -} -EXPORT_SYMBOL_GPL(ide_rq_bytes); - int ide_complete_rq(ide_drive_t *drive, int error, unsigned int nr_bytes) { ide_hwif_t *hwif = drive->hwif; @@ -152,14 +142,14 @@ void ide_kill_rq(ide_drive_t *drive, struct request *rq) if ((media == ide_floppy || media == ide_tape) && drv_req) { rq->errors = 0; - ide_complete_rq(drive, 0, blk_rq_bytes(rq)); } else { if (media == ide_tape) rq->errors = IDE_DRV_ERROR_GENERAL; else if (blk_fs_request(rq) == 0 && rq->errors == 0) rq->errors = -EIO; - ide_complete_rq(drive, -EIO, ide_rq_bytes(rq)); } + + ide_complete_rq(drive, -EIO, blk_rq_bytes(rq)); } static void ide_tf_set_specify_cmd(ide_drive_t *drive, struct ide_taskfile *tf) @@ -476,10 +466,14 @@ void do_ide_request(struct request_queue *q) if (!ide_lock_port(hwif)) { ide_hwif_t *prev_port; - - WARN_ON_ONCE(hwif->rq); repeat: prev_port = hwif->host->cur_port; + + if (drive->dev_flags & IDE_DFLAG_BLOCKED) + rq = hwif->rq; + else + WARN_ON_ONCE(hwif->rq); + if (drive->dev_flags & IDE_DFLAG_SLEEPING && time_after(drive->sleep, jiffies)) { ide_unlock_port(hwif); @@ -506,43 +500,29 @@ repeat: hwif->cur_dev = drive; drive->dev_flags &= ~(IDE_DFLAG_SLEEPING | IDE_DFLAG_PARKED); - spin_unlock_irq(&hwif->lock); - spin_lock_irq(q->queue_lock); - /* - * we know that the queue isn't empty, but this can happen - * if the q->prep_rq_fn() decides to kill a request - */ - if (!rq) + if (rq == NULL) { + spin_unlock_irq(&hwif->lock); + spin_lock_irq(q->queue_lock); + /* + * we know that the queue isn't empty, but this can + * happen if ->prep_rq_fn() decides to kill a request + */ rq = blk_fetch_request(drive->queue); + spin_unlock_irq(q->queue_lock); + spin_lock_irq(&hwif->lock); - spin_unlock_irq(q->queue_lock); - spin_lock_irq(&hwif->lock); - - if (!rq) { - ide_unlock_port(hwif); - goto out; + if (rq == NULL) { + ide_unlock_port(hwif); + goto out; + } } /* * Sanity: don't accept a request that isn't a PM request - * if we are currently power managed. This is very important as - * blk_stop_queue() doesn't prevent the blk_fetch_request() - * above to return us whatever is in the queue. Since we call - * ide_do_request() ourselves, we end up taking requests while - * the queue is blocked... - * - * We let requests forced at head of queue with ide-preempt - * though. I hope that doesn't happen too much, hopefully not - * unless the subdriver triggers such a thing in its own PM - * state machine. + * if we are currently power managed. */ - if ((drive->dev_flags & IDE_DFLAG_BLOCKED) && - blk_pm_request(rq) == 0 && - (rq->cmd_flags & REQ_PREEMPT) == 0) { - /* there should be no pending command at this point */ - ide_unlock_port(hwif); - goto plug_device; - } + BUG_ON((drive->dev_flags & IDE_DFLAG_BLOCKED) && + blk_pm_request(rq) == 0); hwif->rq = rq; diff --git a/drivers/ide/ide-ioctls.c b/drivers/ide/ide-ioctls.c index 82f252c3ee6..e246d3d3fbc 100644 --- a/drivers/ide/ide-ioctls.c +++ b/drivers/ide/ide-ioctls.c @@ -64,7 +64,8 @@ static int ide_get_identity_ioctl(ide_drive_t *drive, unsigned int cmd, goto out; } - id = kmalloc(size, GFP_KERNEL); + /* ata_id_to_hd_driveid() relies on 'id' to be fully allocated. */ + id = kmalloc(ATA_ID_WORDS * 2, GFP_KERNEL); if (id == NULL) { rc = -ENOMEM; goto out; diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c index fa047150a1c..2892b242bbe 100644 --- a/drivers/ide/ide-iops.c +++ b/drivers/ide/ide-iops.c @@ -210,6 +210,7 @@ EXPORT_SYMBOL_GPL(ide_in_drive_list); */ static const struct drive_list_entry ivb_list[] = { { "QUANTUM FIREBALLlct10 05" , "A03.0900" }, + { "QUANTUM FIREBALLlct20 30" , "APL.0900" }, { "TSSTcorp CDDVDW SH-S202J" , "SB00" }, { "TSSTcorp CDDVDW SH-S202J" , "SB01" }, { "TSSTcorp CDDVDW SH-S202N" , "SB00" }, @@ -329,9 +330,6 @@ int ide_driveid_update(ide_drive_t *drive) kfree(id); - if ((drive->dev_flags & IDE_DFLAG_USING_DMA) && ide_id_dma_bug(drive)) - ide_dma_off(drive); - return 1; out_err: if (rc == 2) diff --git a/drivers/ide/ide-pm.c b/drivers/ide/ide-pm.c index c14ca144cff..ad7be2669dc 100644 --- a/drivers/ide/ide-pm.c +++ b/drivers/ide/ide-pm.c @@ -10,9 +10,11 @@ int generic_ide_suspend(struct device *dev, pm_message_t mesg) struct request_pm_state rqpm; int ret; - /* call ACPI _GTM only once */ - if ((drive->dn & 1) == 0 || pair == NULL) - ide_acpi_get_timing(hwif); + if (ide_port_acpi(hwif)) { + /* call ACPI _GTM only once */ + if ((drive->dn & 1) == 0 || pair == NULL) + ide_acpi_get_timing(hwif); + } memset(&rqpm, 0, sizeof(rqpm)); rq = blk_get_request(drive->queue, READ, __GFP_WAIT); @@ -26,9 +28,11 @@ int generic_ide_suspend(struct device *dev, pm_message_t mesg) ret = blk_execute_rq(drive->queue, NULL, rq, 0); blk_put_request(rq); - /* call ACPI _PS3 only after both devices are suspended */ - if (ret == 0 && ((drive->dn & 1) || pair == NULL)) - ide_acpi_set_state(hwif, 0); + if (ret == 0 && ide_port_acpi(hwif)) { + /* call ACPI _PS3 only after both devices are suspended */ + if ((drive->dn & 1) || pair == NULL) + ide_acpi_set_state(hwif, 0); + } return ret; } @@ -42,13 +46,15 @@ int generic_ide_resume(struct device *dev) struct request_pm_state rqpm; int err; - /* call ACPI _PS0 / _STM only once */ - if ((drive->dn & 1) == 0 || pair == NULL) { - ide_acpi_set_state(hwif, 1); - ide_acpi_push_timing(hwif); - } + if (ide_port_acpi(hwif)) { + /* call ACPI _PS0 / _STM only once */ + if ((drive->dn & 1) == 0 || pair == NULL) { + ide_acpi_set_state(hwif, 1); + ide_acpi_push_timing(hwif); + } - ide_acpi_exec_tfs(drive); + ide_acpi_exec_tfs(drive); + } memset(&rqpm, 0, sizeof(rqpm)); rq = blk_get_request(drive->queue, READ, __GFP_WAIT); diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index 51af4eea0d3..1bb106f6221 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -818,6 +818,24 @@ static int ide_port_setup_devices(ide_hwif_t *hwif) return j; } +static void ide_host_enable_irqs(struct ide_host *host) +{ + ide_hwif_t *hwif; + int i; + + ide_host_for_each_port(i, hwif, host) { + if (hwif == NULL) + continue; + + /* clear any pending IRQs */ + hwif->tp_ops->read_status(hwif); + + /* unmask IRQs */ + if (hwif->io_ports.ctl_addr) + hwif->tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS); + } +} + /* * This routine sets up the IRQ for an IDE interface. */ @@ -831,9 +849,6 @@ static int init_irq (ide_hwif_t *hwif) if (irq_handler == NULL) irq_handler = ide_intr; - if (io_ports->ctl_addr) - hwif->tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS); - if (request_irq(hwif->irq, irq_handler, sa, hwif->name, hwif)) goto out_up; @@ -1404,6 +1419,8 @@ int ide_host_register(struct ide_host *host, const struct ide_port_info *d, ide_port_tune_devices(hwif); } + ide_host_enable_irqs(host); + ide_host_for_each_port(i, hwif, host) { if (hwif == NULL) continue; diff --git a/drivers/ieee802154/fakehard.c b/drivers/ieee802154/fakehard.c index 0384144c0b3..14045a7ba38 100644 --- a/drivers/ieee802154/fakehard.c +++ b/drivers/ieee802154/fakehard.c @@ -132,7 +132,7 @@ static int ieee802154_fake_xmit(struct sk_buff *skb, struct net_device *dev) /* FIXME: do hardware work here ... */ - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/input/misc/cobalt_btns.c b/drivers/input/misc/cobalt_btns.c index 2adf9cb265d..d114d3a9e1e 100644 --- a/drivers/input/misc/cobalt_btns.c +++ b/drivers/input/misc/cobalt_btns.c @@ -1,7 +1,7 @@ /* * Cobalt button interface driver. * - * Copyright (C) 2007-2008 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp> + * Copyright (C) 2007-2008 Yoichi Yuasa <yuasa@linux-mips.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -148,7 +148,7 @@ static int __devexit cobalt_buttons_remove(struct platform_device *pdev) return 0; } -MODULE_AUTHOR("Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>"); +MODULE_AUTHOR("Yoichi Yuasa <yuasa@linux-mips.org>"); MODULE_DESCRIPTION("Cobalt button interface driver"); MODULE_LICENSE("GPL"); /* work with hotplug and coldplug */ diff --git a/drivers/isdn/hysdn/hysdn_net.c b/drivers/isdn/hysdn/hysdn_net.c index 579974cf4c9..c73004b3b2a 100644 --- a/drivers/isdn/hysdn/hysdn_net.c +++ b/drivers/isdn/hysdn/hysdn_net.c @@ -148,7 +148,7 @@ net_send_packet(struct sk_buff *skb, struct net_device *dev) if (lp->sk_count <= 3) { schedule_work(&((hysdn_card *) dev->ml_priv)->irq_queue); } - return (0); /* success */ + return NETDEV_TX_OK; /* success */ } /* net_send_packet */ diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c index de4aad076eb..57bf4bf5027 100644 --- a/drivers/isdn/i4l/isdn_net.c +++ b/drivers/isdn/i4l/isdn_net.c @@ -1051,12 +1051,12 @@ isdn_net_xmit(struct net_device *ndev, struct sk_buff *skb) isdn_net_dev *nd; isdn_net_local *slp; isdn_net_local *lp = (isdn_net_local *) netdev_priv(ndev); - int retv = 0; + int retv = NETDEV_TX_OK; if (((isdn_net_local *) netdev_priv(ndev))->master) { printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* For the other encaps the header has already been built */ @@ -1202,7 +1202,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev) if (!(ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_AUTO)) { isdn_net_unreachable(ndev, skb, "dial rejected: interface not in dialmode `auto'"); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } if (lp->phone[1]) { ulong flags; @@ -1215,7 +1215,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev) if(time_before(jiffies, lp->dialwait_timer)) { isdn_net_unreachable(ndev, skb, "dial rejected: retry-time not reached"); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } else lp->dialwait_timer = 0; } @@ -1243,7 +1243,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev) isdn_net_unreachable(ndev, skb, "No channel"); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* Log packet, which triggered dialing */ if (dev->net_verbose) @@ -1258,7 +1258,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev) dev_kfree_skb(skb); isdn_net_unbind_channel(lp); spin_unlock_irqrestore(&dev->lock, flags); - return 0; /* STN (skb to nirvana) ;) */ + return NETDEV_TX_OK; /* STN (skb to nirvana) ;) */ } #ifdef CONFIG_IPPP_FILTER if (isdn_ppp_autodial_filter(skb, lp)) { @@ -1267,7 +1267,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev) spin_unlock_irqrestore(&dev->lock, flags); isdn_net_unreachable(ndev, skb, "dial rejected: packet filtered"); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } #endif spin_unlock_irqrestore(&dev->lock, flags); @@ -1285,7 +1285,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev) isdn_net_unreachable(ndev, skb, "No phone number"); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } } else { /* Device is connected to an ISDN channel */ diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c index aa30b5cb351..2d14b64202a 100644 --- a/drivers/isdn/i4l/isdn_ppp.c +++ b/drivers/isdn/i4l/isdn_ppp.c @@ -1223,7 +1223,7 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev) isdn_net_dev *nd; unsigned int proto = PPP_IP; /* 0x21 */ struct ippp_struct *ipt,*ipts; - int slot, retval = 0; + int slot, retval = NETDEV_TX_OK; mlp = (isdn_net_local *) netdev_priv(netdev); nd = mlp->netdev; /* get master lp */ @@ -1240,7 +1240,7 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev) if (!(ipts->pppcfg & SC_ENABLE_IP)) { /* PPP connected ? */ if (ipts->debug & 0x1) printk(KERN_INFO "%s: IP frame delayed.\n", netdev->name); - retval = 1; + retval = NETDEV_TX_BUSY; goto out; } @@ -1261,7 +1261,7 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev) lp = isdn_net_get_locked_lp(nd); if (!lp) { printk(KERN_WARNING "%s: all channels busy - requeuing!\n", netdev->name); - retval = 1; + retval = NETDEV_TX_BUSY; goto out; } /* we have our lp locked from now on */ diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 9b60b6b684d..7c8e7122aaa 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -75,6 +75,7 @@ config LEDS_ALIX2 depends on LEDS_CLASS && X86 && EXPERIMENTAL help This option enables support for the PCEngines ALIX.2 and ALIX.3 LEDs. + You have to set leds-alix2.force=1 for boards with Award BIOS. config LEDS_H1940 tristate "LED Support for iPAQ H1940 device" @@ -145,15 +146,16 @@ config LEDS_GPIO_OF of_platform devices. For instance, LEDs which are listed in a "dts" file. -config LEDS_LP5521 - tristate "LED Support for the LP5521 LEDs" +config LEDS_LP3944 + tristate "LED Support for N.S. LP3944 (Fun Light) I2C chip" depends on LEDS_CLASS && I2C help - If you say 'Y' here you get support for the National Semiconductor - LP5521 LED driver used in n8x0 boards. + This option enables support for LEDs connected to the National + Semiconductor LP3944 Lighting Management Unit (LMU) also known as + Fun Light Chip. - This driver can be built as a module by choosing 'M'. The module - will be called leds-lp5521. + To compile this driver as a module, choose M here: the + module will be called leds-lp3944. config LEDS_CLEVO_MAIL tristate "Mail LED on Clevo notebook" diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index 2d41c4dcf92..e8cdcf77a4c 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_LEDS_COBALT_RAQ) += leds-cobalt-raq.o obj-$(CONFIG_LEDS_SUNFIRE) += leds-sunfire.o obj-$(CONFIG_LEDS_PCA9532) += leds-pca9532.o obj-$(CONFIG_LEDS_GPIO) += leds-gpio.o +obj-$(CONFIG_LEDS_LP3944) += leds-lp3944.o obj-$(CONFIG_LEDS_CLEVO_MAIL) += leds-clevo-mail.o obj-$(CONFIG_LEDS_HP6XX) += leds-hp6xx.o obj-$(CONFIG_LEDS_FSG) += leds-fsg.o diff --git a/drivers/leds/leds-alix2.c b/drivers/leds/leds-alix2.c index ddbd7730dfc..731d4eef342 100644 --- a/drivers/leds/leds-alix2.c +++ b/drivers/leds/leds-alix2.c @@ -14,7 +14,7 @@ static int force = 0; module_param(force, bool, 0444); -MODULE_PARM_DESC(force, "Assume system has ALIX.2 style LEDs"); +MODULE_PARM_DESC(force, "Assume system has ALIX.2/ALIX.3 style LEDs"); struct alix_led { struct led_classdev cdev; @@ -155,6 +155,11 @@ static int __init alix_led_init(void) goto out; } + /* enable output on GPIO for LED 1,2,3 */ + outl(1 << 6, 0x6104); + outl(1 << 9, 0x6184); + outl(1 << 11, 0x6184); + pdev = platform_device_register_simple(KBUILD_MODNAME, -1, NULL, 0); if (!IS_ERR(pdev)) { ret = platform_driver_probe(&alix_led_driver, alix_led_probe); diff --git a/drivers/leds/leds-bd2802.c b/drivers/leds/leds-bd2802.c index 4149ecb3a9b..779d7f262c0 100644 --- a/drivers/leds/leds-bd2802.c +++ b/drivers/leds/leds-bd2802.c @@ -97,6 +97,10 @@ struct bd2802_led { enum led_ids led_id; enum led_colors color; enum led_bits state; + + /* General attributes of RGB LEDs */ + int wave_pattern; + int rgb_current; }; @@ -254,7 +258,7 @@ static void bd2802_set_on(struct bd2802_led *led, enum led_ids id, bd2802_reset_cancel(led); reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT1SETUP); - bd2802_write_byte(led->client, reg, BD2802_CURRENT_032); + bd2802_write_byte(led->client, reg, led->rgb_current); reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT2SETUP); bd2802_write_byte(led->client, reg, BD2802_CURRENT_000); reg = bd2802_get_reg_addr(id, color, BD2802_REG_WAVEPATTERN); @@ -275,9 +279,9 @@ static void bd2802_set_blink(struct bd2802_led *led, enum led_ids id, reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT1SETUP); bd2802_write_byte(led->client, reg, BD2802_CURRENT_000); reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT2SETUP); - bd2802_write_byte(led->client, reg, BD2802_CURRENT_032); + bd2802_write_byte(led->client, reg, led->rgb_current); reg = bd2802_get_reg_addr(id, color, BD2802_REG_WAVEPATTERN); - bd2802_write_byte(led->client, reg, BD2802_PATTERN_HALF); + bd2802_write_byte(led->client, reg, led->wave_pattern); bd2802_enable(led, id); bd2802_update_state(led, id, color, BD2802_BLINK); @@ -406,7 +410,7 @@ static void bd2802_enable_adv_conf(struct bd2802_led *led) ret = device_create_file(&led->client->dev, bd2802_addr_attributes[i]); if (ret) { - dev_err(&led->client->dev, "failed to sysfs file %s\n", + dev_err(&led->client->dev, "failed: sysfs file %s\n", bd2802_addr_attributes[i]->attr.name); goto failed_remove_files; } @@ -483,6 +487,52 @@ static struct device_attribute bd2802_adv_conf_attr = { .store = bd2802_store_adv_conf, }; +#define BD2802_CONTROL_ATTR(attr_name, name_str) \ +static ssize_t bd2802_show_##attr_name(struct device *dev, \ + struct device_attribute *attr, char *buf) \ +{ \ + struct bd2802_led *led = i2c_get_clientdata(to_i2c_client(dev));\ + ssize_t ret; \ + down_read(&led->rwsem); \ + ret = sprintf(buf, "0x%02x\n", led->attr_name); \ + up_read(&led->rwsem); \ + return ret; \ +} \ +static ssize_t bd2802_store_##attr_name(struct device *dev, \ + struct device_attribute *attr, const char *buf, size_t count) \ +{ \ + struct bd2802_led *led = i2c_get_clientdata(to_i2c_client(dev));\ + unsigned long val; \ + int ret; \ + if (!count) \ + return -EINVAL; \ + ret = strict_strtoul(buf, 16, &val); \ + if (ret) \ + return ret; \ + down_write(&led->rwsem); \ + led->attr_name = val; \ + up_write(&led->rwsem); \ + return count; \ +} \ +static struct device_attribute bd2802_##attr_name##_attr = { \ + .attr = { \ + .name = name_str, \ + .mode = 0644, \ + .owner = THIS_MODULE \ + }, \ + .show = bd2802_show_##attr_name, \ + .store = bd2802_store_##attr_name, \ +}; + +BD2802_CONTROL_ATTR(wave_pattern, "wave_pattern"); +BD2802_CONTROL_ATTR(rgb_current, "rgb_current"); + +static struct device_attribute *bd2802_attributes[] = { + &bd2802_adv_conf_attr, + &bd2802_wave_pattern_attr, + &bd2802_rgb_current_attr, +}; + static void bd2802_led_work(struct work_struct *work) { struct bd2802_led *led = container_of(work, struct bd2802_led, work); @@ -538,7 +588,6 @@ static int bd2802_register_led_classdev(struct bd2802_led *led) led->cdev_led1r.brightness = LED_OFF; led->cdev_led1r.brightness_set = bd2802_set_led1r_brightness; led->cdev_led1r.blink_set = bd2802_set_led1r_blink; - led->cdev_led1r.flags |= LED_CORE_SUSPENDRESUME; ret = led_classdev_register(&led->client->dev, &led->cdev_led1r); if (ret < 0) { @@ -551,7 +600,6 @@ static int bd2802_register_led_classdev(struct bd2802_led *led) led->cdev_led1g.brightness = LED_OFF; led->cdev_led1g.brightness_set = bd2802_set_led1g_brightness; led->cdev_led1g.blink_set = bd2802_set_led1g_blink; - led->cdev_led1g.flags |= LED_CORE_SUSPENDRESUME; ret = led_classdev_register(&led->client->dev, &led->cdev_led1g); if (ret < 0) { @@ -564,7 +612,6 @@ static int bd2802_register_led_classdev(struct bd2802_led *led) led->cdev_led1b.brightness = LED_OFF; led->cdev_led1b.brightness_set = bd2802_set_led1b_brightness; led->cdev_led1b.blink_set = bd2802_set_led1b_blink; - led->cdev_led1b.flags |= LED_CORE_SUSPENDRESUME; ret = led_classdev_register(&led->client->dev, &led->cdev_led1b); if (ret < 0) { @@ -577,7 +624,6 @@ static int bd2802_register_led_classdev(struct bd2802_led *led) led->cdev_led2r.brightness = LED_OFF; led->cdev_led2r.brightness_set = bd2802_set_led2r_brightness; led->cdev_led2r.blink_set = bd2802_set_led2r_blink; - led->cdev_led2r.flags |= LED_CORE_SUSPENDRESUME; ret = led_classdev_register(&led->client->dev, &led->cdev_led2r); if (ret < 0) { @@ -590,7 +636,6 @@ static int bd2802_register_led_classdev(struct bd2802_led *led) led->cdev_led2g.brightness = LED_OFF; led->cdev_led2g.brightness_set = bd2802_set_led2g_brightness; led->cdev_led2g.blink_set = bd2802_set_led2g_blink; - led->cdev_led2g.flags |= LED_CORE_SUSPENDRESUME; ret = led_classdev_register(&led->client->dev, &led->cdev_led2g); if (ret < 0) { @@ -640,7 +685,7 @@ static int __devinit bd2802_probe(struct i2c_client *client, { struct bd2802_led *led; struct bd2802_led_platform_data *pdata; - int ret; + int ret, i; led = kzalloc(sizeof(struct bd2802_led), GFP_KERNEL); if (!led) { @@ -670,13 +715,20 @@ static int __devinit bd2802_probe(struct i2c_client *client, /* To save the power, reset BD2802 after detecting */ gpio_set_value(led->pdata->reset_gpio, 0); + /* Default attributes */ + led->wave_pattern = BD2802_PATTERN_HALF; + led->rgb_current = BD2802_CURRENT_032; + init_rwsem(&led->rwsem); - ret = device_create_file(&client->dev, &bd2802_adv_conf_attr); - if (ret) { - dev_err(&client->dev, "failed to create sysfs file %s\n", - bd2802_adv_conf_attr.attr.name); - goto failed_free; + for (i = 0; i < ARRAY_SIZE(bd2802_attributes); i++) { + ret = device_create_file(&led->client->dev, + bd2802_attributes[i]); + if (ret) { + dev_err(&led->client->dev, "failed: sysfs file %s\n", + bd2802_attributes[i]->attr.name); + goto failed_unregister_dev_file; + } } ret = bd2802_register_led_classdev(led); @@ -686,7 +738,8 @@ static int __devinit bd2802_probe(struct i2c_client *client, return 0; failed_unregister_dev_file: - device_remove_file(&client->dev, &bd2802_adv_conf_attr); + for (i--; i >= 0; i--) + device_remove_file(&led->client->dev, bd2802_attributes[i]); failed_free: i2c_set_clientdata(client, NULL); kfree(led); @@ -697,12 +750,14 @@ failed_free: static int __exit bd2802_remove(struct i2c_client *client) { struct bd2802_led *led = i2c_get_clientdata(client); + int i; - bd2802_unregister_led_classdev(led); gpio_set_value(led->pdata->reset_gpio, 0); + bd2802_unregister_led_classdev(led); if (led->adf_on) bd2802_disable_adv_conf(led); - device_remove_file(&client->dev, &bd2802_adv_conf_attr); + for (i = 0; i < ARRAY_SIZE(bd2802_attributes); i++) + device_remove_file(&led->client->dev, bd2802_attributes[i]); i2c_set_clientdata(client, NULL); kfree(led); @@ -723,8 +778,7 @@ static int bd2802_resume(struct i2c_client *client) struct bd2802_led *led = i2c_get_clientdata(client); if (!bd2802_is_all_off(led) || led->adf_on) { - gpio_set_value(led->pdata->reset_gpio, 1); - udelay(100); + bd2802_reset_cancel(led); bd2802_restore_state(led); } @@ -762,4 +816,4 @@ module_exit(bd2802_exit); MODULE_AUTHOR("Kim Kyuwon <q1.kim@samsung.com>"); MODULE_DESCRIPTION("BD2802 LED driver"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/leds/leds-cobalt-raq.c b/drivers/leds/leds-cobalt-raq.c index ff0e8c3fbf9..5f1ce810815 100644 --- a/drivers/leds/leds-cobalt-raq.c +++ b/drivers/leds/leds-cobalt-raq.c @@ -1,7 +1,7 @@ /* * LEDs driver for the Cobalt Raq series. * - * Copyright (C) 2007 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp> + * Copyright (C) 2007 Yoichi Yuasa <yuasa@linux-mips.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c index d2109054de8..6b06638eb5b 100644 --- a/drivers/leds/leds-gpio.c +++ b/drivers/leds/leds-gpio.c @@ -76,7 +76,7 @@ static int __devinit create_gpio_led(const struct gpio_led *template, struct gpio_led_data *led_dat, struct device *parent, int (*blink_set)(unsigned, unsigned long *, unsigned long *)) { - int ret; + int ret, state; /* skip leds that aren't available */ if (!gpio_is_valid(template->gpio)) { @@ -99,11 +99,15 @@ static int __devinit create_gpio_led(const struct gpio_led *template, led_dat->cdev.blink_set = gpio_blink_set; } led_dat->cdev.brightness_set = gpio_led_set; - led_dat->cdev.brightness = LED_OFF; + if (template->default_state == LEDS_GPIO_DEFSTATE_KEEP) + state = !!gpio_get_value(led_dat->gpio) ^ led_dat->active_low; + else + state = (template->default_state == LEDS_GPIO_DEFSTATE_ON); + led_dat->cdev.brightness = state ? LED_FULL : LED_OFF; if (!template->retain_state_suspended) led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME; - ret = gpio_direction_output(led_dat->gpio, led_dat->active_low); + ret = gpio_direction_output(led_dat->gpio, led_dat->active_low ^ state); if (ret < 0) goto err; @@ -129,7 +133,7 @@ static void delete_gpio_led(struct gpio_led_data *led) } #ifdef CONFIG_LEDS_GPIO_PLATFORM -static int gpio_led_probe(struct platform_device *pdev) +static int __devinit gpio_led_probe(struct platform_device *pdev) { struct gpio_led_platform_data *pdata = pdev->dev.platform_data; struct gpio_led_data *leds_data; @@ -223,12 +227,22 @@ static int __devinit of_gpio_leds_probe(struct of_device *ofdev, memset(&led, 0, sizeof(led)); for_each_child_of_node(np, child) { enum of_gpio_flags flags; + const char *state; led.gpio = of_get_gpio_flags(child, 0, &flags); led.active_low = flags & OF_GPIO_ACTIVE_LOW; led.name = of_get_property(child, "label", NULL) ? : child->name; led.default_trigger = of_get_property(child, "linux,default-trigger", NULL); + state = of_get_property(child, "default-state", NULL); + if (state) { + if (!strcmp(state, "keep")) + led.default_state = LEDS_GPIO_DEFSTATE_KEEP; + else if(!strcmp(state, "on")) + led.default_state = LEDS_GPIO_DEFSTATE_ON; + else + led.default_state = LEDS_GPIO_DEFSTATE_OFF; + } ret = create_gpio_led(&led, &pdata->led_data[pdata->num_leds++], &ofdev->dev, NULL); diff --git a/drivers/leds/leds-lp3944.c b/drivers/leds/leds-lp3944.c new file mode 100644 index 00000000000..5946208ba26 --- /dev/null +++ b/drivers/leds/leds-lp3944.c @@ -0,0 +1,466 @@ +/* + * leds-lp3944.c - driver for National Semiconductor LP3944 Funlight Chip + * + * Copyright (C) 2009 Antonio Ospite <ospite@studenti.unina.it> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +/* + * I2C driver for National Semiconductor LP3944 Funlight Chip + * http://www.national.com/pf/LP/LP3944.html + * + * This helper chip can drive up to 8 leds, with two programmable DIM modes; + * it could even be used as a gpio expander but this driver assumes it is used + * as a led controller. + * + * The DIM modes are used to set _blink_ patterns for leds, the pattern is + * specified supplying two parameters: + * - period: from 0s to 1.6s + * - duty cycle: percentage of the period the led is on, from 0 to 100 + * + * LP3944 can be found on Motorola A910 smartphone, where it drives the rgb + * leds, the camera flash light and the displays backlights. + */ + +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/leds.h> +#include <linux/mutex.h> +#include <linux/workqueue.h> +#include <linux/leds-lp3944.h> + +/* Read Only Registers */ +#define LP3944_REG_INPUT1 0x00 /* LEDs 0-7 InputRegister (Read Only) */ +#define LP3944_REG_REGISTER1 0x01 /* None (Read Only) */ + +#define LP3944_REG_PSC0 0x02 /* Frequency Prescaler 0 (R/W) */ +#define LP3944_REG_PWM0 0x03 /* PWM Register 0 (R/W) */ +#define LP3944_REG_PSC1 0x04 /* Frequency Prescaler 1 (R/W) */ +#define LP3944_REG_PWM1 0x05 /* PWM Register 1 (R/W) */ +#define LP3944_REG_LS0 0x06 /* LEDs 0-3 Selector (R/W) */ +#define LP3944_REG_LS1 0x07 /* LEDs 4-7 Selector (R/W) */ + +/* These registers are not used to control leds in LP3944, they can store + * arbitrary values which the chip will ignore. + */ +#define LP3944_REG_REGISTER8 0x08 +#define LP3944_REG_REGISTER9 0x09 + +#define LP3944_DIM0 0 +#define LP3944_DIM1 1 + +/* period in ms */ +#define LP3944_PERIOD_MIN 0 +#define LP3944_PERIOD_MAX 1600 + +/* duty cycle is a percentage */ +#define LP3944_DUTY_CYCLE_MIN 0 +#define LP3944_DUTY_CYCLE_MAX 100 + +#define ldev_to_led(c) container_of(c, struct lp3944_led_data, ldev) + +/* Saved data */ +struct lp3944_led_data { + u8 id; + enum lp3944_type type; + enum lp3944_status status; + struct led_classdev ldev; + struct i2c_client *client; + struct work_struct work; +}; + +struct lp3944_data { + struct mutex lock; + struct i2c_client *client; + struct lp3944_led_data leds[LP3944_LEDS_MAX]; +}; + +static int lp3944_reg_read(struct i2c_client *client, u8 reg, u8 *value) +{ + int tmp; + + tmp = i2c_smbus_read_byte_data(client, reg); + if (tmp < 0) + return -EINVAL; + + *value = tmp; + + return 0; +} + +static int lp3944_reg_write(struct i2c_client *client, u8 reg, u8 value) +{ + return i2c_smbus_write_byte_data(client, reg, value); +} + +/** + * Set the period for DIM status + * + * @client: the i2c client + * @dim: either LP3944_DIM0 or LP3944_DIM1 + * @period: period of a blink, that is a on/off cycle, expressed in ms. + */ +static int lp3944_dim_set_period(struct i2c_client *client, u8 dim, u16 period) +{ + u8 psc_reg; + u8 psc_value; + int err; + + if (dim == LP3944_DIM0) + psc_reg = LP3944_REG_PSC0; + else if (dim == LP3944_DIM1) + psc_reg = LP3944_REG_PSC1; + else + return -EINVAL; + + /* Convert period to Prescaler value */ + if (period > LP3944_PERIOD_MAX) + return -EINVAL; + + psc_value = (period * 255) / LP3944_PERIOD_MAX; + + err = lp3944_reg_write(client, psc_reg, psc_value); + + return err; +} + +/** + * Set the duty cycle for DIM status + * + * @client: the i2c client + * @dim: either LP3944_DIM0 or LP3944_DIM1 + * @duty_cycle: percentage of a period during which a led is ON + */ +static int lp3944_dim_set_dutycycle(struct i2c_client *client, u8 dim, + u8 duty_cycle) +{ + u8 pwm_reg; + u8 pwm_value; + int err; + + if (dim == LP3944_DIM0) + pwm_reg = LP3944_REG_PWM0; + else if (dim == LP3944_DIM1) + pwm_reg = LP3944_REG_PWM1; + else + return -EINVAL; + + /* Convert duty cycle to PWM value */ + if (duty_cycle > LP3944_DUTY_CYCLE_MAX) + return -EINVAL; + + pwm_value = (duty_cycle * 255) / LP3944_DUTY_CYCLE_MAX; + + err = lp3944_reg_write(client, pwm_reg, pwm_value); + + return err; +} + +/** + * Set the led status + * + * @led: a lp3944_led_data structure + * @status: one of LP3944_LED_STATUS_OFF + * LP3944_LED_STATUS_ON + * LP3944_LED_STATUS_DIM0 + * LP3944_LED_STATUS_DIM1 + */ +static int lp3944_led_set(struct lp3944_led_data *led, u8 status) +{ + struct lp3944_data *data = i2c_get_clientdata(led->client); + u8 id = led->id; + u8 reg; + u8 val = 0; + int err; + + dev_dbg(&led->client->dev, "%s: %s, status before normalization:%d\n", + __func__, led->ldev.name, status); + + switch (id) { + case LP3944_LED0: + case LP3944_LED1: + case LP3944_LED2: + case LP3944_LED3: + reg = LP3944_REG_LS0; + break; + case LP3944_LED4: + case LP3944_LED5: + case LP3944_LED6: + case LP3944_LED7: + id -= LP3944_LED4; + reg = LP3944_REG_LS1; + break; + default: + return -EINVAL; + } + + if (status > LP3944_LED_STATUS_DIM1) + return -EINVAL; + + /* invert only 0 and 1, leave unchanged the other values, + * remember we are abusing status to set blink patterns + */ + if (led->type == LP3944_LED_TYPE_LED_INVERTED && status < 2) + status = 1 - status; + + mutex_lock(&data->lock); + lp3944_reg_read(led->client, reg, &val); + + val &= ~(LP3944_LED_STATUS_MASK << (id << 1)); + val |= (status << (id << 1)); + + dev_dbg(&led->client->dev, "%s: %s, reg:%d id:%d status:%d val:%#x\n", + __func__, led->ldev.name, reg, id, status, val); + + /* set led status */ + err = lp3944_reg_write(led->client, reg, val); + mutex_unlock(&data->lock); + + return err; +} + +static int lp3944_led_set_blink(struct led_classdev *led_cdev, + unsigned long *delay_on, + unsigned long *delay_off) +{ + struct lp3944_led_data *led = ldev_to_led(led_cdev); + u16 period; + u8 duty_cycle; + int err; + + /* units are in ms */ + if (*delay_on + *delay_off > LP3944_PERIOD_MAX) + return -EINVAL; + + if (*delay_on == 0 && *delay_off == 0) { + /* Special case: the leds subsystem requires a default user + * friendly blink pattern for the LED. Let's blink the led + * slowly (1Hz). + */ + *delay_on = 500; + *delay_off = 500; + } + + period = (*delay_on) + (*delay_off); + + /* duty_cycle is the percentage of period during which the led is ON */ + duty_cycle = 100 * (*delay_on) / period; + + /* invert duty cycle for inverted leds, this has the same effect of + * swapping delay_on and delay_off + */ + if (led->type == LP3944_LED_TYPE_LED_INVERTED) + duty_cycle = 100 - duty_cycle; + + /* NOTE: using always the first DIM mode, this means that all leds + * will have the same blinking pattern. + * + * We could find a way later to have two leds blinking in hardware + * with different patterns at the same time, falling back to software + * control for the other ones. + */ + err = lp3944_dim_set_period(led->client, LP3944_DIM0, period); + if (err) + return err; + + err = lp3944_dim_set_dutycycle(led->client, LP3944_DIM0, duty_cycle); + if (err) + return err; + + dev_dbg(&led->client->dev, "%s: OK hardware accelerated blink!\n", + __func__); + + led->status = LP3944_LED_STATUS_DIM0; + schedule_work(&led->work); + + return 0; +} + +static void lp3944_led_set_brightness(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct lp3944_led_data *led = ldev_to_led(led_cdev); + + dev_dbg(&led->client->dev, "%s: %s, %d\n", + __func__, led_cdev->name, brightness); + + led->status = brightness; + schedule_work(&led->work); +} + +static void lp3944_led_work(struct work_struct *work) +{ + struct lp3944_led_data *led; + + led = container_of(work, struct lp3944_led_data, work); + lp3944_led_set(led, led->status); +} + +static int lp3944_configure(struct i2c_client *client, + struct lp3944_data *data, + struct lp3944_platform_data *pdata) +{ + int i, err = 0; + + for (i = 0; i < pdata->leds_size; i++) { + struct lp3944_led *pled = &pdata->leds[i]; + struct lp3944_led_data *led = &data->leds[i]; + led->client = client; + led->id = i; + + switch (pled->type) { + + case LP3944_LED_TYPE_LED: + case LP3944_LED_TYPE_LED_INVERTED: + led->type = pled->type; + led->status = pled->status; + led->ldev.name = pled->name; + led->ldev.max_brightness = 1; + led->ldev.brightness_set = lp3944_led_set_brightness; + led->ldev.blink_set = lp3944_led_set_blink; + led->ldev.flags = LED_CORE_SUSPENDRESUME; + + INIT_WORK(&led->work, lp3944_led_work); + err = led_classdev_register(&client->dev, &led->ldev); + if (err < 0) { + dev_err(&client->dev, + "couldn't register LED %s\n", + led->ldev.name); + goto exit; + } + + /* to expose the default value to userspace */ + led->ldev.brightness = led->status; + + /* Set the default led status */ + err = lp3944_led_set(led, led->status); + if (err < 0) { + dev_err(&client->dev, + "%s couldn't set STATUS %d\n", + led->ldev.name, led->status); + goto exit; + } + break; + + case LP3944_LED_TYPE_NONE: + default: + break; + + } + } + return 0; + +exit: + if (i > 0) + for (i = i - 1; i >= 0; i--) + switch (pdata->leds[i].type) { + + case LP3944_LED_TYPE_LED: + case LP3944_LED_TYPE_LED_INVERTED: + led_classdev_unregister(&data->leds[i].ldev); + cancel_work_sync(&data->leds[i].work); + break; + + case LP3944_LED_TYPE_NONE: + default: + break; + } + + return err; +} + +static int __devinit lp3944_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct lp3944_platform_data *lp3944_pdata = client->dev.platform_data; + struct lp3944_data *data; + + if (lp3944_pdata == NULL) { + dev_err(&client->dev, "no platform data\n"); + return -EINVAL; + } + + /* Let's see whether this adapter can support what we need. */ + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_BYTE_DATA)) { + dev_err(&client->dev, "insufficient functionality!\n"); + return -ENODEV; + } + + data = kzalloc(sizeof(struct lp3944_data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->client = client; + i2c_set_clientdata(client, data); + + mutex_init(&data->lock); + + dev_info(&client->dev, "lp3944 enabled\n"); + + lp3944_configure(client, data, lp3944_pdata); + return 0; +} + +static int __devexit lp3944_remove(struct i2c_client *client) +{ + struct lp3944_platform_data *pdata = client->dev.platform_data; + struct lp3944_data *data = i2c_get_clientdata(client); + int i; + + for (i = 0; i < pdata->leds_size; i++) + switch (data->leds[i].type) { + case LP3944_LED_TYPE_LED: + case LP3944_LED_TYPE_LED_INVERTED: + led_classdev_unregister(&data->leds[i].ldev); + cancel_work_sync(&data->leds[i].work); + break; + + case LP3944_LED_TYPE_NONE: + default: + break; + } + + kfree(data); + i2c_set_clientdata(client, NULL); + + return 0; +} + +/* lp3944 i2c driver struct */ +static const struct i2c_device_id lp3944_id[] = { + {"lp3944", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, lp3944_id); + +static struct i2c_driver lp3944_driver = { + .driver = { + .name = "lp3944", + }, + .probe = lp3944_probe, + .remove = __devexit_p(lp3944_remove), + .id_table = lp3944_id, +}; + +static int __init lp3944_module_init(void) +{ + return i2c_add_driver(&lp3944_driver); +} + +static void __exit lp3944_module_exit(void) +{ + i2c_del_driver(&lp3944_driver); +} + +module_init(lp3944_module_init); +module_exit(lp3944_module_exit); + +MODULE_AUTHOR("Antonio Ospite <ospite@studenti.unina.it>"); +MODULE_DESCRIPTION("LP3944 Fun Light Chip"); +MODULE_LICENSE("GPL"); diff --git a/drivers/leds/leds-pca9532.c b/drivers/leds/leds-pca9532.c index 3937244fdca..dba8921240f 100644 --- a/drivers/leds/leds-pca9532.c +++ b/drivers/leds/leds-pca9532.c @@ -35,7 +35,7 @@ struct pca9532_data { struct pca9532_led leds[16]; struct mutex update_lock; struct input_dev *idev; - struct work_struct work; + struct work_struct work; u8 pwm[2]; u8 psc[2]; }; @@ -87,14 +87,14 @@ static int pca9532_calcpwm(struct i2c_client *client, int pwm, int blink, if (b > 0xFF) return -EINVAL; data->pwm[pwm] = b; - data->psc[pwm] = blink; - return 0; + data->psc[pwm] = blink; + return 0; } static int pca9532_setpwm(struct i2c_client *client, int pwm) { - struct pca9532_data *data = i2c_get_clientdata(client); - mutex_lock(&data->update_lock); + struct pca9532_data *data = i2c_get_clientdata(client); + mutex_lock(&data->update_lock); i2c_smbus_write_byte_data(client, PCA9532_REG_PWM(pwm), data->pwm[pwm]); i2c_smbus_write_byte_data(client, PCA9532_REG_PSC(pwm), @@ -132,11 +132,11 @@ static void pca9532_set_brightness(struct led_classdev *led_cdev, led->state = PCA9532_ON; else { led->state = PCA9532_PWM0; /* Thecus: hardcode one pwm */ - err = pca9532_calcpwm(led->client, 0, 0, value); + err = pca9532_calcpwm(led->client, 0, 0, value); if (err) return; /* XXX: led api doesn't allow error code? */ } - schedule_work(&led->work); + schedule_work(&led->work); } static int pca9532_set_blink(struct led_classdev *led_cdev, @@ -145,7 +145,7 @@ static int pca9532_set_blink(struct led_classdev *led_cdev, struct pca9532_led *led = ldev_to_led(led_cdev); struct i2c_client *client = led->client; int psc; - int err = 0; + int err = 0; if (*delay_on == 0 && *delay_off == 0) { /* led subsystem ask us for a blink rate */ @@ -157,11 +157,11 @@ static int pca9532_set_blink(struct led_classdev *led_cdev, /* Thecus specific: only use PSC/PWM 0 */ psc = (*delay_on * 152-1)/1000; - err = pca9532_calcpwm(client, 0, psc, led_cdev->brightness); - if (err) - return err; - schedule_work(&led->work); - return 0; + err = pca9532_calcpwm(client, 0, psc, led_cdev->brightness); + if (err) + return err; + schedule_work(&led->work); + return 0; } static int pca9532_event(struct input_dev *dev, unsigned int type, @@ -178,15 +178,15 @@ static int pca9532_event(struct input_dev *dev, unsigned int type, else data->pwm[1] = 0; - schedule_work(&data->work); + schedule_work(&data->work); - return 0; + return 0; } static void pca9532_input_work(struct work_struct *work) { - struct pca9532_data *data; - data = container_of(work, struct pca9532_data, work); + struct pca9532_data *data; + data = container_of(work, struct pca9532_data, work); mutex_lock(&data->update_lock); i2c_smbus_write_byte_data(data->client, PCA9532_REG_PWM(1), data->pwm[1]); @@ -195,11 +195,11 @@ static void pca9532_input_work(struct work_struct *work) static void pca9532_led_work(struct work_struct *work) { - struct pca9532_led *led; - led = container_of(work, struct pca9532_led, work); - if (led->state == PCA9532_PWM0) - pca9532_setpwm(led->client, 0); - pca9532_setled(led); + struct pca9532_led *led; + led = container_of(work, struct pca9532_led, work); + if (led->state == PCA9532_PWM0) + pca9532_setpwm(led->client, 0); + pca9532_setled(led); } static int pca9532_configure(struct i2c_client *client, @@ -232,7 +232,7 @@ static int pca9532_configure(struct i2c_client *client, led->ldev.brightness = LED_OFF; led->ldev.brightness_set = pca9532_set_brightness; led->ldev.blink_set = pca9532_set_blink; - INIT_WORK(&led->work, pca9532_led_work); + INIT_WORK(&led->work, pca9532_led_work); err = led_classdev_register(&client->dev, &led->ldev); if (err < 0) { dev_err(&client->dev, @@ -262,11 +262,11 @@ static int pca9532_configure(struct i2c_client *client, BIT_MASK(SND_TONE); data->idev->event = pca9532_event; input_set_drvdata(data->idev, data); - INIT_WORK(&data->work, pca9532_input_work); + INIT_WORK(&data->work, pca9532_input_work); err = input_register_device(data->idev); if (err) { input_free_device(data->idev); - cancel_work_sync(&data->work); + cancel_work_sync(&data->work); data->idev = NULL; goto exit; } @@ -283,13 +283,13 @@ exit: break; case PCA9532_TYPE_LED: led_classdev_unregister(&data->leds[i].ldev); - cancel_work_sync(&data->leds[i].work); + cancel_work_sync(&data->leds[i].work); break; case PCA9532_TYPE_N2100_BEEP: if (data->idev != NULL) { input_unregister_device(data->idev); input_free_device(data->idev); - cancel_work_sync(&data->work); + cancel_work_sync(&data->work); data->idev = NULL; } break; @@ -340,13 +340,13 @@ static int pca9532_remove(struct i2c_client *client) break; case PCA9532_TYPE_LED: led_classdev_unregister(&data->leds[i].ldev); - cancel_work_sync(&data->leds[i].work); + cancel_work_sync(&data->leds[i].work); break; case PCA9532_TYPE_N2100_BEEP: if (data->idev != NULL) { input_unregister_device(data->idev); input_free_device(data->idev); - cancel_work_sync(&data->work); + cancel_work_sync(&data->work); data->idev = NULL; } break; diff --git a/drivers/lguest/lg.h b/drivers/lguest/lg.h index d4e8979735c..9c3138265f8 100644 --- a/drivers/lguest/lg.h +++ b/drivers/lguest/lg.h @@ -82,7 +82,7 @@ struct lg_cpu { struct lg_eventfd { unsigned long addr; - struct file *event; + struct eventfd_ctx *event; }; struct lg_eventfd_map { diff --git a/drivers/lguest/lguest_user.c b/drivers/lguest/lguest_user.c index 32e29712105..9f9a2953b38 100644 --- a/drivers/lguest/lguest_user.c +++ b/drivers/lguest/lguest_user.c @@ -50,7 +50,7 @@ static int add_eventfd(struct lguest *lg, unsigned long addr, int fd) /* Now append new entry. */ new->map[new->num].addr = addr; - new->map[new->num].event = eventfd_fget(fd); + new->map[new->num].event = eventfd_ctx_fdget(fd); if (IS_ERR(new->map[new->num].event)) { kfree(new); return PTR_ERR(new->map[new->num].event); @@ -357,7 +357,7 @@ static int close(struct inode *inode, struct file *file) /* Release any eventfds they registered. */ for (i = 0; i < lg->eventfds->num; i++) - fput(lg->eventfds->map[i].event); + eventfd_ctx_put(lg->eventfds->map[i].event); kfree(lg->eventfds); /* If lg->dead doesn't contain an error code it will be NULL or a diff --git a/drivers/macintosh/macio_asic.c b/drivers/macintosh/macio_asic.c index 6e149f4a1ff..a0f68386c12 100644 --- a/drivers/macintosh/macio_asic.c +++ b/drivers/macintosh/macio_asic.c @@ -378,6 +378,17 @@ static struct macio_dev * macio_add_one_device(struct macio_chip *chip, dev->ofdev.dev.bus = &macio_bus_type; dev->ofdev.dev.release = macio_release_dev; +#ifdef CONFIG_PCI + /* Set the DMA ops to the ones from the PCI device, this could be + * fishy if we didn't know that on PowerMac it's always direct ops + * or iommu ops that will work fine + */ + dev->ofdev.dev.archdata.dma_ops = + chip->lbus.pdev->dev.archdata.dma_ops; + dev->ofdev.dev.archdata.dma_data = + chip->lbus.pdev->dev.archdata.dma_data; +#endif /* CONFIG_PCI */ + #ifdef DEBUG printk("preparing mdev @%p, ofdev @%p, dev @%p, kobj @%p\n", dev, &dev->ofdev, &dev->ofdev.dev, &dev->ofdev.dev.kobj); diff --git a/drivers/md/dm-exception-store.c b/drivers/md/dm-exception-store.c index c3ae51584b1..3710ff88fc1 100644 --- a/drivers/md/dm-exception-store.c +++ b/drivers/md/dm-exception-store.c @@ -195,7 +195,7 @@ int dm_exception_store_create(struct dm_target *ti, int argc, char **argv, struct dm_exception_store **store) { int r = 0; - struct dm_exception_store_type *type; + struct dm_exception_store_type *type = NULL; struct dm_exception_store *tmp_store; char persistent; @@ -211,12 +211,15 @@ int dm_exception_store_create(struct dm_target *ti, int argc, char **argv, } persistent = toupper(*argv[1]); - if (persistent != 'P' && persistent != 'N') { + if (persistent == 'P') + type = get_type("P"); + else if (persistent == 'N') + type = get_type("N"); + else { ti->error = "Persistent flag is not P or N"; return -EINVAL; } - type = get_type(&persistent); if (!type) { ti->error = "Exception store type not recognised"; r = -EINVAL; diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 4899ebe767c..2cba557d9e6 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -495,7 +495,7 @@ int dm_set_device_limits(struct dm_target *ti, struct dm_dev *dev, return 0; } - if (blk_stack_limits(limits, &q->limits, start) < 0) + if (blk_stack_limits(limits, &q->limits, start << 9) < 0) DMWARN("%s: target device %s is misaligned", dm_device_name(ti->table->md), bdevname(bdev, b)); diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 3c6d4ee8921..9acd54a5cff 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -1017,7 +1017,7 @@ static struct bio *split_bvec(struct bio *bio, sector_t sector, clone->bi_flags |= 1 << BIO_CLONED; if (bio_integrity(bio)) { - bio_integrity_clone(clone, bio, GFP_NOIO); + bio_integrity_clone(clone, bio, GFP_NOIO, bs); bio_integrity_trim(clone, bio_sector_offset(bio, idx, offset), len); } @@ -1045,7 +1045,7 @@ static struct bio *clone_bio(struct bio *bio, sector_t sector, clone->bi_flags &= ~(1 << BIO_SEG_VALID); if (bio_integrity(bio)) { - bio_integrity_clone(clone, bio, GFP_NOIO); + bio_integrity_clone(clone, bio, GFP_NOIO, bs); if (idx != bio->bi_idx || clone->bi_size < bio->bi_size) bio_integrity_trim(clone, diff --git a/drivers/md/linear.c b/drivers/md/linear.c index 15c8b7b25a9..5810fa906af 100644 --- a/drivers/md/linear.c +++ b/drivers/md/linear.c @@ -166,8 +166,8 @@ static linear_conf_t *linear_conf(mddev_t *mddev, int raid_disks) rdev->sectors = sectors * mddev->chunk_sectors; } - blk_queue_stack_limits(mddev->queue, - rdev->bdev->bd_disk->queue); + disk_stack_limits(mddev->gendisk, rdev->bdev, + rdev->data_offset << 9); /* as we don't honour merge_bvec_fn, we must never risk * violating it, so limit ->max_sector to one PAGE, as * a one page request is never in violation. diff --git a/drivers/md/md.c b/drivers/md/md.c index 09be637d52c..0f4a70c43ff 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -3573,7 +3573,8 @@ suspend_lo_store(mddev_t *mddev, const char *buf, size_t len) char *e; unsigned long long new = simple_strtoull(buf, &e, 10); - if (mddev->pers->quiesce == NULL) + if (mddev->pers == NULL || + mddev->pers->quiesce == NULL) return -EINVAL; if (buf == e || (*e && *e != '\n')) return -EINVAL; @@ -3601,7 +3602,8 @@ suspend_hi_store(mddev_t *mddev, const char *buf, size_t len) char *e; unsigned long long new = simple_strtoull(buf, &e, 10); - if (mddev->pers->quiesce == NULL) + if (mddev->pers == NULL || + mddev->pers->quiesce == NULL) return -EINVAL; if (buf == e || (*e && *e != '\n')) return -EINVAL; @@ -3844,11 +3846,9 @@ static int md_alloc(dev_t dev, char *name) flush_scheduled_work(); mutex_lock(&disks_mutex); - if (mddev->gendisk) { - mutex_unlock(&disks_mutex); - mddev_put(mddev); - return -EEXIST; - } + error = -EEXIST; + if (mddev->gendisk) + goto abort; if (name) { /* Need to ensure that 'name' is not a duplicate. @@ -3860,17 +3860,15 @@ static int md_alloc(dev_t dev, char *name) if (mddev2->gendisk && strcmp(mddev2->gendisk->disk_name, name) == 0) { spin_unlock(&all_mddevs_lock); - return -EEXIST; + goto abort; } spin_unlock(&all_mddevs_lock); } + error = -ENOMEM; mddev->queue = blk_alloc_queue(GFP_KERNEL); - if (!mddev->queue) { - mutex_unlock(&disks_mutex); - mddev_put(mddev); - return -ENOMEM; - } + if (!mddev->queue) + goto abort; mddev->queue->queuedata = mddev; /* Can be unlocked because the queue is new: no concurrency */ @@ -3880,11 +3878,9 @@ static int md_alloc(dev_t dev, char *name) disk = alloc_disk(1 << shift); if (!disk) { - mutex_unlock(&disks_mutex); blk_cleanup_queue(mddev->queue); mddev->queue = NULL; - mddev_put(mddev); - return -ENOMEM; + goto abort; } disk->major = MAJOR(mddev->unit); disk->first_minor = unit << shift; @@ -3906,16 +3902,22 @@ static int md_alloc(dev_t dev, char *name) mddev->gendisk = disk; error = kobject_init_and_add(&mddev->kobj, &md_ktype, &disk_to_dev(disk)->kobj, "%s", "md"); - mutex_unlock(&disks_mutex); - if (error) + if (error) { + /* This isn't possible, but as kobject_init_and_add is marked + * __must_check, we must do something with the result + */ printk(KERN_WARNING "md: cannot register %s/md - name in use\n", disk->disk_name); - else { + error = 0; + } + abort: + mutex_unlock(&disks_mutex); + if (!error) { kobject_uevent(&mddev->kobj, KOBJ_ADD); mddev->sysfs_state = sysfs_get_dirent(mddev->kobj.sd, "array_state"); } mddev_put(mddev); - return 0; + return error; } static struct kobject *md_probe(dev_t dev, int *part, void *data) @@ -6334,10 +6336,16 @@ void md_do_sync(mddev_t *mddev) sysfs_notify(&mddev->kobj, NULL, "sync_completed"); } - if (j >= mddev->resync_max) - wait_event(mddev->recovery_wait, - mddev->resync_max > j - || kthread_should_stop()); + while (j >= mddev->resync_max && !kthread_should_stop()) { + /* As this condition is controlled by user-space, + * we can block indefinitely, so use '_interruptible' + * to avoid triggering warnings. + */ + flush_signals(current); /* just in case */ + wait_event_interruptible(mddev->recovery_wait, + mddev->resync_max > j + || kthread_should_stop()); + } if (kthread_should_stop()) goto interrupted; diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c index cbe368fa659..237fe3fd235 100644 --- a/drivers/md/multipath.c +++ b/drivers/md/multipath.c @@ -294,7 +294,8 @@ static int multipath_add_disk(mddev_t *mddev, mdk_rdev_t *rdev) for (path = first; path <= last; path++) if ((p=conf->multipaths+path)->rdev == NULL) { q = rdev->bdev->bd_disk->queue; - blk_queue_stack_limits(mddev->queue, q); + disk_stack_limits(mddev->gendisk, rdev->bdev, + rdev->data_offset << 9); /* as we don't honour merge_bvec_fn, we must never risk * violating it, so limit ->max_sector to one PAGE, as @@ -463,9 +464,9 @@ static int multipath_run (mddev_t *mddev) disk = conf->multipaths + disk_idx; disk->rdev = rdev; + disk_stack_limits(mddev->gendisk, rdev->bdev, + rdev->data_offset << 9); - blk_queue_stack_limits(mddev->queue, - rdev->bdev->bd_disk->queue); /* as we don't honour merge_bvec_fn, we must never risk * violating it, not that we ever expect a device with * a merge_bvec_fn to be involved in multipath */ diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c index ab4a489d869..335f490dcad 100644 --- a/drivers/md/raid0.c +++ b/drivers/md/raid0.c @@ -170,8 +170,8 @@ static int create_strip_zones(mddev_t *mddev) } dev[j] = rdev1; - blk_queue_stack_limits(mddev->queue, - rdev1->bdev->bd_disk->queue); + disk_stack_limits(mddev->gendisk, rdev1->bdev, + rdev1->data_offset << 9); /* as we don't honour merge_bvec_fn, we must never risk * violating it, so limit ->max_sector to one PAGE, as * a one page request is never in violation. @@ -250,6 +250,11 @@ static int create_strip_zones(mddev_t *mddev) mddev->chunk_sectors << 9); goto abort; } + + blk_queue_io_min(mddev->queue, mddev->chunk_sectors << 9); + blk_queue_io_opt(mddev->queue, + (mddev->chunk_sectors << 9) * mddev->raid_disks); + printk(KERN_INFO "raid0: done.\n"); mddev->private = conf; return 0; diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 89939a7aef5..0569efba0c0 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -1123,8 +1123,8 @@ static int raid1_add_disk(mddev_t *mddev, mdk_rdev_t *rdev) for (mirror = first; mirror <= last; mirror++) if ( !(p=conf->mirrors+mirror)->rdev) { - blk_queue_stack_limits(mddev->queue, - rdev->bdev->bd_disk->queue); + disk_stack_limits(mddev->gendisk, rdev->bdev, + rdev->data_offset << 9); /* as we don't honour merge_bvec_fn, we must never risk * violating it, so limit ->max_sector to one PAGE, as * a one page request is never in violation. @@ -1988,9 +1988,8 @@ static int run(mddev_t *mddev) disk = conf->mirrors + disk_idx; disk->rdev = rdev; - - blk_queue_stack_limits(mddev->queue, - rdev->bdev->bd_disk->queue); + disk_stack_limits(mddev->gendisk, rdev->bdev, + rdev->data_offset << 9); /* as we don't honour merge_bvec_fn, we must never risk * violating it, so limit ->max_sector to one PAGE, as * a one page request is never in violation. diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index ae12ceafe10..7298a5e5a18 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -1151,8 +1151,8 @@ static int raid10_add_disk(mddev_t *mddev, mdk_rdev_t *rdev) for ( ; mirror <= last ; mirror++) if ( !(p=conf->mirrors+mirror)->rdev) { - blk_queue_stack_limits(mddev->queue, - rdev->bdev->bd_disk->queue); + disk_stack_limits(mddev->gendisk, rdev->bdev, + rdev->data_offset << 9); /* as we don't honour merge_bvec_fn, we must never risk * violating it, so limit ->max_sector to one PAGE, as * a one page request is never in violation. @@ -2044,7 +2044,7 @@ raid10_size(mddev_t *mddev, sector_t sectors, int raid_disks) static int run(mddev_t *mddev) { conf_t *conf; - int i, disk_idx; + int i, disk_idx, chunk_size; mirror_info_t *disk; mdk_rdev_t *rdev; int nc, fc, fo; @@ -2130,6 +2130,14 @@ static int run(mddev_t *mddev) spin_lock_init(&conf->device_lock); mddev->queue->queue_lock = &conf->device_lock; + chunk_size = mddev->chunk_sectors << 9; + blk_queue_io_min(mddev->queue, chunk_size); + if (conf->raid_disks % conf->near_copies) + blk_queue_io_opt(mddev->queue, chunk_size * conf->raid_disks); + else + blk_queue_io_opt(mddev->queue, chunk_size * + (conf->raid_disks / conf->near_copies)); + list_for_each_entry(rdev, &mddev->disks, same_set) { disk_idx = rdev->raid_disk; if (disk_idx >= mddev->raid_disks @@ -2138,9 +2146,8 @@ static int run(mddev_t *mddev) disk = conf->mirrors + disk_idx; disk->rdev = rdev; - - blk_queue_stack_limits(mddev->queue, - rdev->bdev->bd_disk->queue); + disk_stack_limits(mddev->gendisk, rdev->bdev, + rdev->data_offset << 9); /* as we don't honour merge_bvec_fn, we must never risk * violating it, so limit ->max_sector to one PAGE, as * a one page request is never in violation. diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index f9f991e6e13..37835538b58 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -3699,13 +3699,21 @@ static int make_request(struct request_queue *q, struct bio * bi) goto retry; } } - /* FIXME what if we get a false positive because these - * are being updated. - */ - if (logical_sector >= mddev->suspend_lo && + + if (bio_data_dir(bi) == WRITE && + logical_sector >= mddev->suspend_lo && logical_sector < mddev->suspend_hi) { release_stripe(sh); - schedule(); + /* As the suspend_* range is controlled by + * userspace, we want an interruptible + * wait. + */ + flush_signals(current); + prepare_to_wait(&conf->wait_for_overlap, + &w, TASK_INTERRUPTIBLE); + if (logical_sector >= mddev->suspend_lo && + logical_sector < mddev->suspend_hi) + schedule(); goto retry; } @@ -4452,7 +4460,7 @@ static raid5_conf_t *setup_conf(mddev_t *mddev) static int run(mddev_t *mddev) { raid5_conf_t *conf; - int working_disks = 0; + int working_disks = 0, chunk_size; mdk_rdev_t *rdev; if (mddev->recovery_cp != MaxSector) @@ -4607,6 +4615,14 @@ static int run(mddev_t *mddev) md_set_array_sectors(mddev, raid5_size(mddev, 0, 0)); blk_queue_merge_bvec(mddev->queue, raid5_mergeable_bvec); + chunk_size = mddev->chunk_sectors << 9; + blk_queue_io_min(mddev->queue, chunk_size); + blk_queue_io_opt(mddev->queue, chunk_size * + (conf->raid_disks - conf->max_degraded)); + + list_for_each_entry(rdev, &mddev->disks, same_set) + disk_stack_limits(mddev->gendisk, rdev->bdev, + rdev->data_offset << 9); return 0; abort: diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c index 8280f8d66a3..8c9ae0a3a27 100644 --- a/drivers/media/dvb/dvb-core/dvb_net.c +++ b/drivers/media/dvb/dvb-core/dvb_net.c @@ -904,7 +904,7 @@ static int dvb_net_sec_callback(const u8 *buffer1, size_t buffer1_len, static int dvb_net_tx(struct sk_buff *skb, struct net_device *dev) { dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } static u8 mask_normal[6]={0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; diff --git a/drivers/message/fusion/mptlan.c b/drivers/message/fusion/mptlan.c index a9e48e28b1d..bc2ec2182c0 100644 --- a/drivers/message/fusion/mptlan.c +++ b/drivers/message/fusion/mptlan.c @@ -795,7 +795,7 @@ mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev) IOC_AND_NETDEV_NAMES_s_s(dev), le32_to_cpu(pSimple->FlagsLength))); - return 0; + return NETDEV_TX_OK; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ diff --git a/drivers/mfd/ezx-pcap.c b/drivers/mfd/ezx-pcap.c index 671a7efe86a..c1de4afa89a 100644 --- a/drivers/mfd/ezx-pcap.c +++ b/drivers/mfd/ezx-pcap.c @@ -238,8 +238,10 @@ static irqreturn_t pcap_adc_irq(int irq, void *_pcap) mutex_lock(&pcap->adc_mutex); req = pcap->adc_queue[pcap->adc_head]; - if (WARN(!req, KERN_WARNING "adc irq without pending request\n")) + if (WARN(!req, KERN_WARNING "adc irq without pending request\n")) { + mutex_unlock(&pcap->adc_mutex); return IRQ_HANDLED; + } /* read requested channels results */ ezx_pcap_read(pcap, PCAP_REG_ADC, &tmp); diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c index 4c7b7962f6b..0cc5eeff5ee 100644 --- a/drivers/mfd/sm501.c +++ b/drivers/mfd/sm501.c @@ -367,7 +367,8 @@ int sm501_unit_power(struct device *dev, unsigned int unit, unsigned int to) break; default: - return -1; + gate = -1; + goto already; } writel(mode, sm->regs + SM501_POWER_MODE_CONTROL); diff --git a/drivers/misc/sgi-xp/xpnet.c b/drivers/misc/sgi-xp/xpnet.c index 8d1c60a3f0d..b681bf8abdc 100644 --- a/drivers/misc/sgi-xp/xpnet.c +++ b/drivers/misc/sgi-xp/xpnet.c @@ -436,7 +436,7 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) if (skb->data[0] == 0x33) { dev_kfree_skb(skb); - return 0; /* nothing needed to be done */ + return NETDEV_TX_OK; /* nothing needed to be done */ } /* @@ -503,7 +503,7 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->stats.tx_packets++; dev->stats.tx_bytes += skb->len; - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c index 240608cc7ae..a461017ce5c 100644 --- a/drivers/mmc/host/mmc_spi.c +++ b/drivers/mmc/host/mmc_spi.c @@ -1313,6 +1313,12 @@ static int mmc_spi_probe(struct spi_device *spi) struct mmc_spi_host *host; int status; + /* We rely on full duplex transfers, mostly to reduce + * per-transfer overheads (by making fewer transfers). + */ + if (spi->master->flags & SPI_MASTER_HALF_DUPLEX) + return -EINVAL; + /* MMC and SD specs only seem to care that sampling is on the * rising edge ... meaning SPI modes 0 or 3. So either SPI mode * should be legit. We'll use mode 0 since the steady state is 0, diff --git a/drivers/mtd/cmdlinepart.c b/drivers/mtd/cmdlinepart.c index 5011fa73f91..1479da6d3aa 100644 --- a/drivers/mtd/cmdlinepart.c +++ b/drivers/mtd/cmdlinepart.c @@ -194,7 +194,7 @@ static struct mtd_partition * newpart(char *s, parts[this_part].name = extra_mem; extra_mem += name_len + 1; - dbg(("partition %d: name <%s>, offset %x, size %x, mask flags %x\n", + dbg(("partition %d: name <%s>, offset %llx, size %llx, mask flags %x\n", this_part, parts[this_part].name, parts[this_part].offset, diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 59c46126a5c..ae5fe91867e 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -54,7 +54,7 @@ #define SR_SRWD 0x80 /* SR write protect */ /* Define max times to check status register before we give up. */ -#define MAX_READY_WAIT_JIFFIES (10 * HZ) /* eg. M25P128 specs 6s max sector erase */ +#define MAX_READY_WAIT_JIFFIES (40 * HZ) /* M25P16 specs 40s max chip erase */ #define CMD_SIZE 4 #ifdef CONFIG_M25PXX_USE_FAST_READ diff --git a/drivers/mtd/inftlcore.c b/drivers/mtd/inftlcore.c index 73f05227dc8..d8cf29c01cc 100644 --- a/drivers/mtd/inftlcore.c +++ b/drivers/mtd/inftlcore.c @@ -226,7 +226,7 @@ static u16 INFTL_findfreeblock(struct INFTLrecord *inftl, int desperate) if (!desperate && inftl->numfreeEUNs < 2) { DEBUG(MTD_DEBUG_LEVEL1, "INFTL: there are too few free " "EUNs (%d)\n", inftl->numfreeEUNs); - return 0xffff; + return BLOCK_NIL; } /* Scan for a free block */ @@ -281,7 +281,8 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned silly = MAX_LOOPS; while (thisEUN < inftl->nb_blocks) { for (block = 0; block < inftl->EraseSize/SECTORSIZE; block ++) { - if ((BlockMap[block] != 0xffff) || BlockDeleted[block]) + if ((BlockMap[block] != BLOCK_NIL) || + BlockDeleted[block]) continue; if (inftl_read_oob(mtd, (thisEUN * inftl->EraseSize) @@ -525,7 +526,7 @@ static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block) if (!silly--) { printk(KERN_WARNING "INFTL: infinite loop in " "Virtual Unit Chain 0x%x\n", thisVUC); - return 0xffff; + return BLOCK_NIL; } /* Skip to next block in chain */ @@ -549,7 +550,7 @@ hitused: * waiting to be picked up. We're going to have to fold * a chain to make room. */ - thisEUN = INFTL_makefreeblock(inftl, 0xffff); + thisEUN = INFTL_makefreeblock(inftl, BLOCK_NIL); /* * Hopefully we free something, lets try again. @@ -631,7 +632,7 @@ hitused: printk(KERN_WARNING "INFTL: error folding to make room for Virtual " "Unit Chain 0x%x\n", thisVUC); - return 0xffff; + return BLOCK_NIL; } /* diff --git a/drivers/mtd/maps/integrator-flash.c b/drivers/mtd/maps/integrator-flash.c index b08a798ee25..2aac41bde8b 100644 --- a/drivers/mtd/maps/integrator-flash.c +++ b/drivers/mtd/maps/integrator-flash.c @@ -42,10 +42,8 @@ #include <mach/hardware.h> #include <asm/system.h> -#define SUBDEV_NAME_SIZE (BUS_ID_SIZE + 2) - struct armflash_subdev_info { - char name[SUBDEV_NAME_SIZE]; + char *name; struct mtd_info *mtd; struct map_info map; struct flash_platform_data *plat; @@ -134,6 +132,8 @@ static void armflash_subdev_remove(struct armflash_subdev_info *subdev) map_destroy(subdev->mtd); if (subdev->map.virt) iounmap(subdev->map.virt); + kfree(subdev->name); + subdev->name = NULL; release_mem_region(subdev->map.phys, subdev->map.size); } @@ -177,16 +177,22 @@ static int armflash_probe(struct platform_device *dev) if (nr == 1) /* No MTD concatenation, just use the default name */ - snprintf(subdev->name, SUBDEV_NAME_SIZE, "%s", - dev_name(&dev->dev)); + subdev->name = kstrdup(dev_name(&dev->dev), GFP_KERNEL); else - snprintf(subdev->name, SUBDEV_NAME_SIZE, "%s-%d", - dev_name(&dev->dev), i); + subdev->name = kasprintf(GFP_KERNEL, "%s-%d", + dev_name(&dev->dev), i); + if (!subdev->name) { + err = -ENOMEM; + break; + } subdev->plat = plat; err = armflash_subdev_probe(subdev, res); - if (err) + if (err) { + kfree(subdev->name); + subdev->name = NULL; break; + } } info->nr_subdev = i; diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 2802992b39d..20c828ba940 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -534,7 +534,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev) &num_partitions); if ((!partitions) || (num_partitions == 0)) { - printk(KERN_ERR "atmel_nand: No parititions defined, or unsupported device.\n"); + printk(KERN_ERR "atmel_nand: No partitions defined, or unsupported device.\n"); res = ENXIO; goto err_no_partitions; } diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index 0cd76f89f4b..ebd07e95b81 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -11,6 +11,8 @@ #include <linux/platform_device.h> #include <linux/dma-mapping.h> #include <linux/delay.h> +#include <linux/jiffies.h> +#include <linux/sched.h> #include <linux/mtd/mtd.h> #include <linux/mtd/nand.h> #include <linux/mtd/partitions.h> @@ -541,7 +543,7 @@ static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip) struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, mtd); unsigned long timeo = jiffies; - int status, state = this->state; + int status = NAND_STATUS_FAIL, state = this->state; if (state == FL_ERASING) timeo += (HZ * 400) / 1000; @@ -556,8 +558,9 @@ static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip) while (time_before(jiffies, timeo)) { status = __raw_readb(this->IO_ADDR_R); - if (!(status & 0x40)) + if (status & NAND_STATUS_READY) break; + cond_resched(); } return status; } diff --git a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c index e3f8495a94c..fb86cacd5bd 100644 --- a/drivers/mtd/nftlcore.c +++ b/drivers/mtd/nftlcore.c @@ -208,7 +208,7 @@ static u16 NFTL_findfreeblock(struct NFTLrecord *nftl, int desperate ) /* Normally, we force a fold to happen before we run out of free blocks completely */ if (!desperate && nftl->numfreeEUNs < 2) { DEBUG(MTD_DEBUG_LEVEL1, "NFTL_findfreeblock: there are too few free EUNs\n"); - return 0xffff; + return BLOCK_NIL; } /* Scan for a free block */ @@ -230,11 +230,11 @@ static u16 NFTL_findfreeblock(struct NFTLrecord *nftl, int desperate ) printk("Argh! No free blocks found! LastFreeEUN = %d, " "FirstEUN = %d\n", nftl->LastFreeEUN, le16_to_cpu(nftl->MediaHdr.FirstPhysicalEUN)); - return 0xffff; + return BLOCK_NIL; } } while (pot != nftl->LastFreeEUN); - return 0xffff; + return BLOCK_NIL; } static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned pendingblock ) @@ -431,7 +431,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p /* add the header so that it is now a valid chain */ oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum = cpu_to_le16(thisVUC); - oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum = 0xffff; + oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum = BLOCK_NIL; nftl_write_oob(mtd, (nftl->EraseSize * targetEUN) + 8, 8, &retlen, (char *)&oob.u); @@ -515,7 +515,7 @@ static u16 NFTL_makefreeblock( struct NFTLrecord *nftl , unsigned pendingblock) if (ChainLength < 2) { printk(KERN_WARNING "No Virtual Unit Chains available for folding. " "Failing request\n"); - return 0xffff; + return BLOCK_NIL; } return NFTL_foldchain (nftl, LongestChain, pendingblock); @@ -578,7 +578,7 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block) printk(KERN_WARNING "Infinite loop in Virtual Unit Chain 0x%x\n", thisVUC); - return 0xffff; + return BLOCK_NIL; } /* Skip to next block in chain */ @@ -601,7 +601,7 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block) //u16 startEUN = nftl->EUNtable[thisVUC]; //printk("Write to VirtualUnitChain %d, calling makefreeblock()\n", thisVUC); - writeEUN = NFTL_makefreeblock(nftl, 0xffff); + writeEUN = NFTL_makefreeblock(nftl, BLOCK_NIL); if (writeEUN == BLOCK_NIL) { /* OK, we accept that the above comment is @@ -673,7 +673,7 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block) printk(KERN_WARNING "Error folding to make room for Virtual Unit Chain 0x%x\n", thisVUC); - return 0xffff; + return BLOCK_NIL; } static int nftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block, diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c index 367bec63620..e29fb1a4a61 100644 --- a/drivers/net/3c501.c +++ b/drivers/net/3c501.c @@ -485,7 +485,7 @@ static int el_start_xmit(struct sk_buff *skb, struct net_device *dev) if (el_debug > 2) pr_debug(" queued xmit.\n"); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* A receive upset our load, despite our best efforts */ if (el_debug > 2) diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c index f71b3540275..7bba480d722 100644 --- a/drivers/net/3c505.c +++ b/drivers/net/3c505.c @@ -1101,7 +1101,7 @@ static int elp_start_xmit(struct sk_buff *skb, struct net_device *dev) prime_rx(dev); spin_unlock_irqrestore(&adapter->lock, flags); netif_start_queue(dev); - return 0; + return NETDEV_TX_OK; } /****************************************************** diff --git a/drivers/net/3c507.c b/drivers/net/3c507.c index 96b86659381..9e93a0b39b6 100644 --- a/drivers/net/3c507.c +++ b/drivers/net/3c507.c @@ -537,7 +537,7 @@ static int el16_send_packet (struct sk_buff *skb, struct net_device *dev) /* You might need to clean up and record Tx statistics here. */ - return 0; + return NETDEV_TX_OK; } /* The typical workload of the driver: diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c index d2137efbd45..d2515d840c0 100644 --- a/drivers/net/3c509.c +++ b/drivers/net/3c509.c @@ -892,7 +892,7 @@ el3_start_xmit(struct sk_buff *skb, struct net_device *dev) outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */ } } - return 0; + return NETDEV_TX_OK; } /* The EL3 interrupt handler. */ diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c index 3e00fa8ea65..85ffd132bad 100644 --- a/drivers/net/3c515.c +++ b/drivers/net/3c515.c @@ -1054,7 +1054,7 @@ static int corkscrew_start_xmit(struct sk_buff *skb, netif_wake_queue(dev); } dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } /* Put out the doubleword header... */ outl(skb->len, ioaddr + TX_FIFO); @@ -1117,7 +1117,7 @@ static int corkscrew_start_xmit(struct sk_buff *skb, outb(0x00, ioaddr + TxStatus); /* Pop the status stack. */ } } - return 0; + return NETDEV_TX_OK; } /* The interrupt handler does all of the Rx thread work and cleans up diff --git a/drivers/net/3c523.c b/drivers/net/3c523.c index cdd955c4014..70c701b80d9 100644 --- a/drivers/net/3c523.c +++ b/drivers/net/3c523.c @@ -1198,7 +1198,7 @@ static int elmc_send_packet(struct sk_buff *skb, struct net_device *dev) netif_wake_queue(dev); dev_kfree_skb(skb); #endif - return 0; + return NETDEV_TX_OK; } /******************************************* diff --git a/drivers/net/3c527.c b/drivers/net/3c527.c index aaa8a9f405d..72b9ed7f464 100644 --- a/drivers/net/3c527.c +++ b/drivers/net/3c527.c @@ -1035,7 +1035,7 @@ static int mc32_send_packet(struct sk_buff *skb, struct net_device *dev) if (skb_padto(skb, ETH_ZLEN)) { netif_wake_queue(dev); - return 0; + return NETDEV_TX_OK; } atomic_dec(&lp->tx_count); @@ -1066,7 +1066,7 @@ static int mc32_send_packet(struct sk_buff *skb, struct net_device *dev) p->control &= ~CONTROL_EOL; netif_wake_queue(dev); - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index c34aee91250..202048450ee 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -2083,7 +2083,7 @@ vortex_start_xmit(struct sk_buff *skb, struct net_device *dev) iowrite8(0x00, ioaddr + TxStatus); /* Pop the status stack. */ } } - return 0; + return NETDEV_TX_OK; } static int @@ -2173,7 +2173,7 @@ boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev) iowrite16(DownUnstall, ioaddr + EL3_CMD); spin_unlock_irqrestore(&vp->lock, flags); dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } /* The interrupt handler does all of the Rx thread work and cleans up diff --git a/drivers/net/7990.c b/drivers/net/7990.c index 69f5b7d298a..b1e5764628c 100644 --- a/drivers/net/7990.c +++ b/drivers/net/7990.c @@ -585,7 +585,7 @@ int lance_start_xmit (struct sk_buff *skb, struct net_device *dev) lp->tx_full = 1; spin_unlock_irqrestore (&lp->devlock, flags); - return 0; + return NETDEV_TX_OK; } EXPORT_SYMBOL_GPL(lance_start_xmit); diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index 50efde11ea6..07919d0877e 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -891,7 +891,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev) cpw8(TxPoll, NormalTxPoll); dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } /* Set or clear the multicast filter for this adaptor. diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index 8ae72ec1445..1a223cd1933 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -1706,7 +1706,7 @@ static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev) } else { dev_kfree_skb(skb); dev->stats.tx_dropped++; - return 0; + return NETDEV_TX_OK; } spin_lock_irqsave(&tp->lock, flags); @@ -1731,7 +1731,7 @@ static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev) pr_debug("%s: Queued Tx packet size %u to slot %d.\n", dev->name, len, entry); - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/82596.c b/drivers/net/82596.c index 77547545509..996cc910221 100644 --- a/drivers/net/82596.c +++ b/drivers/net/82596.c @@ -1068,7 +1068,7 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev) if (skb->len < ETH_ZLEN) { if (skb_padto(skb, ETH_ZLEN)) - return 0; + return NETDEV_TX_OK; length = ETH_ZLEN; } netif_stop_queue(dev); @@ -1110,7 +1110,7 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev) netif_start_queue(dev); - return 0; + return NETDEV_TX_OK; } static void print_eth(unsigned char *add, char *str) diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c index 85a18175730..7302e4385bc 100644 --- a/drivers/net/a2065.c +++ b/drivers/net/a2065.c @@ -553,11 +553,11 @@ static int lance_start_xmit (struct sk_buff *skb, struct net_device *dev) volatile struct lance_regs *ll = lp->ll; volatile struct lance_init_block *ib = lp->init_block; int entry, skblen; - int status = 0; + int status = NETDEV_TX_OK; unsigned long flags; if (skb_padto(skb, ETH_ZLEN)) - return 0; + return NETDEV_TX_OK; skblen = max_t(unsigned, skb->len, ETH_ZLEN); local_irq_save(flags); diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c index 19831bd6401..61ac671f97b 100644 --- a/drivers/net/amd8111e.c +++ b/drivers/net/amd8111e.c @@ -1346,7 +1346,7 @@ static int amd8111e_start_xmit(struct sk_buff *skb, struct net_device * dev) netif_stop_queue(dev); } spin_unlock_irqrestore(&lp->lock, flags); - return 0; + return NETDEV_TX_OK; } /* This function returns all the memory mapped registers of the device. diff --git a/drivers/net/appletalk/cops.c b/drivers/net/appletalk/cops.c index 7f832541980..29b279f88ef 100644 --- a/drivers/net/appletalk/cops.c +++ b/drivers/net/appletalk/cops.c @@ -920,7 +920,7 @@ static int cops_send_packet(struct sk_buff *skb, struct net_device *dev) dev->stats.tx_bytes += skb->len; dev->trans_start = jiffies; dev_kfree_skb (skb); - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/appletalk/ipddp.c b/drivers/net/appletalk/ipddp.c index 78cea5e80b1..6cfd961bb8d 100644 --- a/drivers/net/appletalk/ipddp.c +++ b/drivers/net/appletalk/ipddp.c @@ -132,7 +132,7 @@ static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev) } if(rt == NULL) { spin_unlock(&ipddp_route_lock); - return 0; + return NETDEV_TX_OK; } our_addr = atalk_find_dev_addr(rt->dev); @@ -181,7 +181,7 @@ static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock(&ipddp_route_lock); - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/appletalk/ltpc.c b/drivers/net/appletalk/ltpc.c index b642647170b..c80fb9cf8ff 100644 --- a/drivers/net/appletalk/ltpc.c +++ b/drivers/net/appletalk/ltpc.c @@ -932,7 +932,7 @@ static int ltpc_xmit(struct sk_buff *skb, struct net_device *dev) dev->stats.tx_bytes += skb->len; dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* initialization stuff */ diff --git a/drivers/net/ariadne.c b/drivers/net/ariadne.c index 58e8d522e5b..47d976cc3d7 100644 --- a/drivers/net/ariadne.c +++ b/drivers/net/ariadne.c @@ -610,7 +610,7 @@ static int ariadne_start_xmit(struct sk_buff *skb, struct net_device *dev) if (skb->len < ETH_ZLEN) { if (skb_padto(skb, ETH_ZLEN)) - return 0; + return NETDEV_TX_OK; len = ETH_ZLEN; } @@ -685,7 +685,7 @@ static int ariadne_start_xmit(struct sk_buff *skb, struct net_device *dev) } local_irq_restore(flags); - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/arm/am79c961a.c b/drivers/net/arm/am79c961a.c index 627bc75da17..164b37e85ee 100644 --- a/drivers/net/arm/am79c961a.c +++ b/drivers/net/arm/am79c961a.c @@ -482,7 +482,7 @@ am79c961_sendpacket(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/arm/at91_ether.c b/drivers/net/arm/at91_ether.c index 2e7419a6119..d46a06e20db 100644 --- a/drivers/net/arm/at91_ether.c +++ b/drivers/net/arm/at91_ether.c @@ -834,7 +834,7 @@ static int at91ether_start_xmit(struct sk_buff *skb, struct net_device *dev) we free and return(0) or don't free and return 1 */ } - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/arm/ether1.c b/drivers/net/arm/ether1.c index edf770f639f..e47c0d96285 100644 --- a/drivers/net/arm/ether1.c +++ b/drivers/net/arm/ether1.c @@ -748,7 +748,7 @@ ether1_sendpacket (struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); out: - return 0; + return NETDEV_TX_OK; } static void diff --git a/drivers/net/arm/ether3.c b/drivers/net/arm/ether3.c index 455037134aa..1f7a69c929a 100644 --- a/drivers/net/arm/ether3.c +++ b/drivers/net/arm/ether3.c @@ -511,7 +511,7 @@ ether3_sendpacket(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb(skb); priv(dev)->stats.tx_dropped ++; netif_start_queue(dev); - return 0; + return NETDEV_TX_OK; } length = (length + 1) & ~1; @@ -562,7 +562,7 @@ ether3_sendpacket(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); out: - return 0; + return NETDEV_TX_OK; } static irqreturn_t diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c index 18b566ad4fd..c2227d79673 100644 --- a/drivers/net/at1700.c +++ b/drivers/net/at1700.c @@ -643,7 +643,7 @@ static int net_send_packet (struct sk_buff *skb, struct net_device *dev) netif_start_queue (dev); dev_kfree_skb (skb); - return 0; + return NETDEV_TX_OK; } /* The typical workload of the driver: diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c index 5425ab0c38c..0c0deceb693 100644 --- a/drivers/net/atarilance.c +++ b/drivers/net/atarilance.c @@ -796,7 +796,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ) if (len > skb->len) { if (skb_padto(skb, len)) - return 0; + return NETDEV_TX_OK; } netif_stop_queue (dev); @@ -846,7 +846,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ) lp->tx_full = 1; spin_unlock_irqrestore (&lp->devlock, flags); - return 0; + return NETDEV_TX_OK; } /* The LANCE interrupt handler. */ diff --git a/drivers/net/atp.c b/drivers/net/atp.c index 4317b3edb3d..4beacc9c909 100644 --- a/drivers/net/atp.c +++ b/drivers/net/atp.c @@ -587,7 +587,7 @@ static int atp_send_packet(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; dev_kfree_skb (skb); - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c index d3c734f4d67..2aab1ebc6cd 100644 --- a/drivers/net/au1000_eth.c +++ b/drivers/net/au1000_eth.c @@ -988,7 +988,7 @@ static int au1000_tx(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb(skb); aup->tx_head = (aup->tx_head + 1) & (NUM_TX_DMA - 1); dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c index c15fc281f79..f580b21eabd 100644 --- a/drivers/net/bfin_mac.c +++ b/drivers/net/bfin_mac.c @@ -656,7 +656,7 @@ out: dev->trans_start = jiffies; dev->stats.tx_packets++; dev->stats.tx_bytes += (skb->len); - return 0; + return NETDEV_TX_OK; } static void bfin_mac_rx(struct net_device *dev) diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c index 9578a3dfac0..41600011cfd 100644 --- a/drivers/net/bmac.c +++ b/drivers/net/bmac.c @@ -1488,7 +1488,7 @@ bmac_output(struct sk_buff *skb, struct net_device *dev) struct bmac_data *bp = netdev_priv(dev); skb_queue_tail(bp->queue, skb); bmac_start(dev); - return 0; + return NETDEV_TX_OK; } static void bmac_tx_timeout(unsigned long data) diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index d4b570886c6..0e7dfe0981d 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -2431,7 +2431,7 @@ out: dev_kfree_skb(skb); } read_unlock(&bond->lock); - return 0; + return NETDEV_TX_OK; } int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type* ptype, struct net_device *orig_dev) diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index 46d312bedfb..bf45d200292 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -1413,7 +1413,7 @@ out: } read_unlock(&bond->curr_slave_lock); read_unlock(&bond->lock); - return 0; + return NETDEV_TX_OK; } void bond_alb_monitor(struct work_struct *work) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index d927f71af8a..66596d80b50 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -4277,7 +4277,7 @@ out: dev_kfree_skb(skb); } read_unlock(&bond->lock); - return 0; + return NETDEV_TX_OK; } @@ -4308,7 +4308,7 @@ out: read_unlock(&bond->curr_slave_lock); read_unlock(&bond->lock); - return 0; + return NETDEV_TX_OK; } /* @@ -4354,7 +4354,7 @@ out: dev_kfree_skb(skb); } read_unlock(&bond->lock); - return 0; + return NETDEV_TX_OK; } /* @@ -4414,7 +4414,7 @@ out: /* frame sent to all suitable interfaces */ read_unlock(&bond->lock); - return 0; + return NETDEV_TX_OK; } /*------------------------- Device initialization ---------------------------*/ diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c index 571f133a8fe..1c30dbec195 100644 --- a/drivers/net/can/sja1000/sja1000.c +++ b/drivers/net/can/sja1000/sja1000.c @@ -283,7 +283,7 @@ static int sja1000_start_xmit(struct sk_buff *skb, struct net_device *dev) priv->write_reg(priv, REG_CMR, CMD_TR); - return 0; + return NETDEV_TX_OK; } static void sja1000_rx(struct net_device *dev) diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c index eb066673c2a..299a33b914f 100644 --- a/drivers/net/cassini.c +++ b/drivers/net/cassini.c @@ -2928,7 +2928,7 @@ static int cas_start_xmit(struct sk_buff *skb, struct net_device *dev) static int ring; if (skb_padto(skb, cp->min_frame_size)) - return 0; + return NETDEV_TX_OK; /* XXX: we need some higher-level QoS hooks to steer packets to * individual queues. @@ -2936,7 +2936,7 @@ static int cas_start_xmit(struct sk_buff *skb, struct net_device *dev) if (cas_xmit_tx_ringN(cp, ring++ & N_TX_RINGS_MASK, skb)) return NETDEV_TX_BUSY; dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } static void cas_init_tx_dma(struct cas *cp) diff --git a/drivers/net/cris/eth_v10.c b/drivers/net/cris/eth_v10.c index 7a18dc7e5c7..15c0195ebd3 100644 --- a/drivers/net/cris/eth_v10.c +++ b/drivers/net/cris/eth_v10.c @@ -1108,7 +1108,7 @@ e100_send_packet(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&np->lock, flags); - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c index 3eee666a9cd..e5948970a42 100644 --- a/drivers/net/cs89x0.c +++ b/drivers/net/cs89x0.c @@ -1367,7 +1367,7 @@ net_open(struct net_device *dev) spin_lock_irqsave(&lp->lock, flags); disable_dma(dev->dma); clear_dma_ff(dev->dma); - set_dma_mode(dev->dma, 0x14); /* auto_init as well */ + set_dma_mode(dev->dma, DMA_RX_MODE); /* auto_init as well */ set_dma_addr(dev->dma, isa_virt_to_bus(lp->dma_buff)); set_dma_count(dev->dma, lp->dmasize*1024); enable_dma(dev->dma); @@ -1571,7 +1571,7 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev) * to restart the netdevice layer */ - return 0; + return NETDEV_TX_OK; } /* The typical workload of the driver: diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h index 1694fad3872..74723f2e743 100644 --- a/drivers/net/cxgb3/adapter.h +++ b/drivers/net/cxgb3/adapter.h @@ -276,6 +276,14 @@ static inline struct port_info *adap2pinfo(struct adapter *adap, int idx) return netdev_priv(adap->port[idx]); } +static inline int phy2portid(struct cphy *phy) +{ + struct adapter *adap = phy->adapter; + struct port_info *port0 = adap2pinfo(adap, 0); + + return &port0->phy == phy ? 0 : 1; +} + #define OFFLOAD_DEVMAP_BIT 15 #define tdev2adap(d) container_of(d, struct adapter, tdev) @@ -312,4 +320,6 @@ int t3_get_desc(const struct sge_qset *qs, unsigned int qnum, unsigned int idx, unsigned char *data); irqreturn_t t3_sge_intr_msix(int irq, void *cookie); +int t3_get_edc_fw(struct cphy *phy, int edc_idx, int size); + #endif /* __T3_ADAPTER_H__ */ diff --git a/drivers/net/cxgb3/ael1002.c b/drivers/net/cxgb3/ael1002.c index 9fe008ec9ba..5248f9e0b2f 100644 --- a/drivers/net/cxgb3/ael1002.c +++ b/drivers/net/cxgb3/ael1002.c @@ -224,12 +224,6 @@ static int ael1006_reset(struct cphy *phy, int wait) return t3_phy_reset(phy, MDIO_MMD_PMAPMD, wait); } -static int ael1006_power_down(struct cphy *phy, int enable) -{ - return mdio_set_flag(&phy->mdio, phy->mdio.prtad, MDIO_MMD_PMAPMD, - MDIO_CTRL1, MDIO_CTRL1_LPOWER, enable); -} - static struct cphy_ops ael1006_ops = { .reset = ael1006_reset, .intr_enable = t3_phy_lasi_intr_enable, @@ -237,7 +231,7 @@ static struct cphy_ops ael1006_ops = { .intr_clear = t3_phy_lasi_intr_clear, .intr_handler = t3_phy_lasi_intr_handler, .get_link_status = get_link_status_r, - .power_down = ael1006_power_down, + .power_down = ael1002_power_down, .mmds = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS, }; @@ -304,279 +298,7 @@ static int ael2005_setup_sr_edc(struct cphy *phy) { MDIO_MMD_PMAPMD, 0xc04a, 0xffff, 0x5200 }, { 0, 0, 0, 0 } }; - static u16 sr_edc[] = { - 0xcc00, 0x2ff4, - 0xcc01, 0x3cd4, - 0xcc02, 0x2015, - 0xcc03, 0x3105, - 0xcc04, 0x6524, - 0xcc05, 0x27ff, - 0xcc06, 0x300f, - 0xcc07, 0x2c8b, - 0xcc08, 0x300b, - 0xcc09, 0x4009, - 0xcc0a, 0x400e, - 0xcc0b, 0x2f72, - 0xcc0c, 0x3002, - 0xcc0d, 0x1002, - 0xcc0e, 0x2172, - 0xcc0f, 0x3012, - 0xcc10, 0x1002, - 0xcc11, 0x25d2, - 0xcc12, 0x3012, - 0xcc13, 0x1002, - 0xcc14, 0xd01e, - 0xcc15, 0x27d2, - 0xcc16, 0x3012, - 0xcc17, 0x1002, - 0xcc18, 0x2004, - 0xcc19, 0x3c84, - 0xcc1a, 0x6436, - 0xcc1b, 0x2007, - 0xcc1c, 0x3f87, - 0xcc1d, 0x8676, - 0xcc1e, 0x40b7, - 0xcc1f, 0xa746, - 0xcc20, 0x4047, - 0xcc21, 0x5673, - 0xcc22, 0x2982, - 0xcc23, 0x3002, - 0xcc24, 0x13d2, - 0xcc25, 0x8bbd, - 0xcc26, 0x2862, - 0xcc27, 0x3012, - 0xcc28, 0x1002, - 0xcc29, 0x2092, - 0xcc2a, 0x3012, - 0xcc2b, 0x1002, - 0xcc2c, 0x5cc3, - 0xcc2d, 0x314, - 0xcc2e, 0x2942, - 0xcc2f, 0x3002, - 0xcc30, 0x1002, - 0xcc31, 0xd019, - 0xcc32, 0x2032, - 0xcc33, 0x3012, - 0xcc34, 0x1002, - 0xcc35, 0x2a04, - 0xcc36, 0x3c74, - 0xcc37, 0x6435, - 0xcc38, 0x2fa4, - 0xcc39, 0x3cd4, - 0xcc3a, 0x6624, - 0xcc3b, 0x5563, - 0xcc3c, 0x2d42, - 0xcc3d, 0x3002, - 0xcc3e, 0x13d2, - 0xcc3f, 0x464d, - 0xcc40, 0x2862, - 0xcc41, 0x3012, - 0xcc42, 0x1002, - 0xcc43, 0x2032, - 0xcc44, 0x3012, - 0xcc45, 0x1002, - 0xcc46, 0x2fb4, - 0xcc47, 0x3cd4, - 0xcc48, 0x6624, - 0xcc49, 0x5563, - 0xcc4a, 0x2d42, - 0xcc4b, 0x3002, - 0xcc4c, 0x13d2, - 0xcc4d, 0x2ed2, - 0xcc4e, 0x3002, - 0xcc4f, 0x1002, - 0xcc50, 0x2fd2, - 0xcc51, 0x3002, - 0xcc52, 0x1002, - 0xcc53, 0x004, - 0xcc54, 0x2942, - 0xcc55, 0x3002, - 0xcc56, 0x1002, - 0xcc57, 0x2092, - 0xcc58, 0x3012, - 0xcc59, 0x1002, - 0xcc5a, 0x5cc3, - 0xcc5b, 0x317, - 0xcc5c, 0x2f72, - 0xcc5d, 0x3002, - 0xcc5e, 0x1002, - 0xcc5f, 0x2942, - 0xcc60, 0x3002, - 0xcc61, 0x1002, - 0xcc62, 0x22cd, - 0xcc63, 0x301d, - 0xcc64, 0x2862, - 0xcc65, 0x3012, - 0xcc66, 0x1002, - 0xcc67, 0x2ed2, - 0xcc68, 0x3002, - 0xcc69, 0x1002, - 0xcc6a, 0x2d72, - 0xcc6b, 0x3002, - 0xcc6c, 0x1002, - 0xcc6d, 0x628f, - 0xcc6e, 0x2112, - 0xcc6f, 0x3012, - 0xcc70, 0x1002, - 0xcc71, 0x5aa3, - 0xcc72, 0x2dc2, - 0xcc73, 0x3002, - 0xcc74, 0x1312, - 0xcc75, 0x6f72, - 0xcc76, 0x1002, - 0xcc77, 0x2807, - 0xcc78, 0x31a7, - 0xcc79, 0x20c4, - 0xcc7a, 0x3c24, - 0xcc7b, 0x6724, - 0xcc7c, 0x1002, - 0xcc7d, 0x2807, - 0xcc7e, 0x3187, - 0xcc7f, 0x20c4, - 0xcc80, 0x3c24, - 0xcc81, 0x6724, - 0xcc82, 0x1002, - 0xcc83, 0x2514, - 0xcc84, 0x3c64, - 0xcc85, 0x6436, - 0xcc86, 0xdff4, - 0xcc87, 0x6436, - 0xcc88, 0x1002, - 0xcc89, 0x40a4, - 0xcc8a, 0x643c, - 0xcc8b, 0x4016, - 0xcc8c, 0x8c6c, - 0xcc8d, 0x2b24, - 0xcc8e, 0x3c24, - 0xcc8f, 0x6435, - 0xcc90, 0x1002, - 0xcc91, 0x2b24, - 0xcc92, 0x3c24, - 0xcc93, 0x643a, - 0xcc94, 0x4025, - 0xcc95, 0x8a5a, - 0xcc96, 0x1002, - 0xcc97, 0x2731, - 0xcc98, 0x3011, - 0xcc99, 0x1001, - 0xcc9a, 0xc7a0, - 0xcc9b, 0x100, - 0xcc9c, 0xc502, - 0xcc9d, 0x53ac, - 0xcc9e, 0xc503, - 0xcc9f, 0xd5d5, - 0xcca0, 0xc600, - 0xcca1, 0x2a6d, - 0xcca2, 0xc601, - 0xcca3, 0x2a4c, - 0xcca4, 0xc602, - 0xcca5, 0x111, - 0xcca6, 0xc60c, - 0xcca7, 0x5900, - 0xcca8, 0xc710, - 0xcca9, 0x700, - 0xccaa, 0xc718, - 0xccab, 0x700, - 0xccac, 0xc720, - 0xccad, 0x4700, - 0xccae, 0xc801, - 0xccaf, 0x7f50, - 0xccb0, 0xc802, - 0xccb1, 0x7760, - 0xccb2, 0xc803, - 0xccb3, 0x7fce, - 0xccb4, 0xc804, - 0xccb5, 0x5700, - 0xccb6, 0xc805, - 0xccb7, 0x5f11, - 0xccb8, 0xc806, - 0xccb9, 0x4751, - 0xccba, 0xc807, - 0xccbb, 0x57e1, - 0xccbc, 0xc808, - 0xccbd, 0x2700, - 0xccbe, 0xc809, - 0xccbf, 0x000, - 0xccc0, 0xc821, - 0xccc1, 0x002, - 0xccc2, 0xc822, - 0xccc3, 0x014, - 0xccc4, 0xc832, - 0xccc5, 0x1186, - 0xccc6, 0xc847, - 0xccc7, 0x1e02, - 0xccc8, 0xc013, - 0xccc9, 0xf341, - 0xccca, 0xc01a, - 0xcccb, 0x446, - 0xcccc, 0xc024, - 0xcccd, 0x1000, - 0xccce, 0xc025, - 0xcccf, 0xa00, - 0xccd0, 0xc026, - 0xccd1, 0xc0c, - 0xccd2, 0xc027, - 0xccd3, 0xc0c, - 0xccd4, 0xc029, - 0xccd5, 0x0a0, - 0xccd6, 0xc030, - 0xccd7, 0xa00, - 0xccd8, 0xc03c, - 0xccd9, 0x01c, - 0xccda, 0xc005, - 0xccdb, 0x7a06, - 0xccdc, 0x000, - 0xccdd, 0x2731, - 0xccde, 0x3011, - 0xccdf, 0x1001, - 0xcce0, 0xc620, - 0xcce1, 0x000, - 0xcce2, 0xc621, - 0xcce3, 0x03f, - 0xcce4, 0xc622, - 0xcce5, 0x000, - 0xcce6, 0xc623, - 0xcce7, 0x000, - 0xcce8, 0xc624, - 0xcce9, 0x000, - 0xccea, 0xc625, - 0xcceb, 0x000, - 0xccec, 0xc627, - 0xcced, 0x000, - 0xccee, 0xc628, - 0xccef, 0x000, - 0xccf0, 0xc62c, - 0xccf1, 0x000, - 0xccf2, 0x000, - 0xccf3, 0x2806, - 0xccf4, 0x3cb6, - 0xccf5, 0xc161, - 0xccf6, 0x6134, - 0xccf7, 0x6135, - 0xccf8, 0x5443, - 0xccf9, 0x303, - 0xccfa, 0x6524, - 0xccfb, 0x00b, - 0xccfc, 0x1002, - 0xccfd, 0x2104, - 0xccfe, 0x3c24, - 0xccff, 0x2105, - 0xcd00, 0x3805, - 0xcd01, 0x6524, - 0xcd02, 0xdff4, - 0xcd03, 0x4005, - 0xcd04, 0x6524, - 0xcd05, 0x1002, - 0xcd06, 0x5dd3, - 0xcd07, 0x306, - 0xcd08, 0x2ff7, - 0xcd09, 0x38f7, - 0xcd0a, 0x60b7, - 0xcd0b, 0xdffd, - 0xcd0c, 0x00a, - 0xcd0d, 0x1002, - 0xcd0e, 0 - }; + int i, err; err = set_phy_regs(phy, regs); @@ -585,9 +307,16 @@ static int ael2005_setup_sr_edc(struct cphy *phy) msleep(50); - for (i = 0; i < ARRAY_SIZE(sr_edc) && !err; i += 2) - err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, sr_edc[i], - sr_edc[i + 1]); + if (phy->priv != edc_sr) + err = t3_get_edc_fw(phy, EDC_OPT_AEL2005, + EDC_OPT_AEL2005_SIZE); + if (err) + return err; + + for (i = 0; i < EDC_OPT_AEL2005_SIZE / sizeof(u16) && !err; i += 2) + err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, + phy->phy_cache[i], + phy->phy_cache[i + 1]); if (!err) phy->priv = edc_sr; return err; @@ -604,374 +333,6 @@ static int ael2005_setup_twinax_edc(struct cphy *phy, int modtype) { MDIO_MMD_PMAPMD, 0xc015, 0xffff, 0xa000 }, { 0, 0, 0, 0 } }; - static u16 twinax_edc[] = { - 0xcc00, 0x4009, - 0xcc01, 0x27ff, - 0xcc02, 0x300f, - 0xcc03, 0x40aa, - 0xcc04, 0x401c, - 0xcc05, 0x401e, - 0xcc06, 0x2ff4, - 0xcc07, 0x3cd4, - 0xcc08, 0x2035, - 0xcc09, 0x3145, - 0xcc0a, 0x6524, - 0xcc0b, 0x26a2, - 0xcc0c, 0x3012, - 0xcc0d, 0x1002, - 0xcc0e, 0x29c2, - 0xcc0f, 0x3002, - 0xcc10, 0x1002, - 0xcc11, 0x2072, - 0xcc12, 0x3012, - 0xcc13, 0x1002, - 0xcc14, 0x22cd, - 0xcc15, 0x301d, - 0xcc16, 0x2e52, - 0xcc17, 0x3012, - 0xcc18, 0x1002, - 0xcc19, 0x28e2, - 0xcc1a, 0x3002, - 0xcc1b, 0x1002, - 0xcc1c, 0x628f, - 0xcc1d, 0x2ac2, - 0xcc1e, 0x3012, - 0xcc1f, 0x1002, - 0xcc20, 0x5553, - 0xcc21, 0x2ae2, - 0xcc22, 0x3002, - 0xcc23, 0x1302, - 0xcc24, 0x401e, - 0xcc25, 0x2be2, - 0xcc26, 0x3012, - 0xcc27, 0x1002, - 0xcc28, 0x2da2, - 0xcc29, 0x3012, - 0xcc2a, 0x1002, - 0xcc2b, 0x2ba2, - 0xcc2c, 0x3002, - 0xcc2d, 0x1002, - 0xcc2e, 0x5ee3, - 0xcc2f, 0x305, - 0xcc30, 0x400e, - 0xcc31, 0x2bc2, - 0xcc32, 0x3002, - 0xcc33, 0x1002, - 0xcc34, 0x2b82, - 0xcc35, 0x3012, - 0xcc36, 0x1002, - 0xcc37, 0x5663, - 0xcc38, 0x302, - 0xcc39, 0x401e, - 0xcc3a, 0x6f72, - 0xcc3b, 0x1002, - 0xcc3c, 0x628f, - 0xcc3d, 0x2be2, - 0xcc3e, 0x3012, - 0xcc3f, 0x1002, - 0xcc40, 0x22cd, - 0xcc41, 0x301d, - 0xcc42, 0x2e52, - 0xcc43, 0x3012, - 0xcc44, 0x1002, - 0xcc45, 0x2522, - 0xcc46, 0x3012, - 0xcc47, 0x1002, - 0xcc48, 0x2da2, - 0xcc49, 0x3012, - 0xcc4a, 0x1002, - 0xcc4b, 0x2ca2, - 0xcc4c, 0x3012, - 0xcc4d, 0x1002, - 0xcc4e, 0x2fa4, - 0xcc4f, 0x3cd4, - 0xcc50, 0x6624, - 0xcc51, 0x410b, - 0xcc52, 0x56b3, - 0xcc53, 0x3c4, - 0xcc54, 0x2fb2, - 0xcc55, 0x3002, - 0xcc56, 0x1002, - 0xcc57, 0x220b, - 0xcc58, 0x303b, - 0xcc59, 0x56b3, - 0xcc5a, 0x3c3, - 0xcc5b, 0x866b, - 0xcc5c, 0x400c, - 0xcc5d, 0x23a2, - 0xcc5e, 0x3012, - 0xcc5f, 0x1002, - 0xcc60, 0x2da2, - 0xcc61, 0x3012, - 0xcc62, 0x1002, - 0xcc63, 0x2ca2, - 0xcc64, 0x3012, - 0xcc65, 0x1002, - 0xcc66, 0x2fb4, - 0xcc67, 0x3cd4, - 0xcc68, 0x6624, - 0xcc69, 0x56b3, - 0xcc6a, 0x3c3, - 0xcc6b, 0x866b, - 0xcc6c, 0x401c, - 0xcc6d, 0x2205, - 0xcc6e, 0x3035, - 0xcc6f, 0x5b53, - 0xcc70, 0x2c52, - 0xcc71, 0x3002, - 0xcc72, 0x13c2, - 0xcc73, 0x5cc3, - 0xcc74, 0x317, - 0xcc75, 0x2522, - 0xcc76, 0x3012, - 0xcc77, 0x1002, - 0xcc78, 0x2da2, - 0xcc79, 0x3012, - 0xcc7a, 0x1002, - 0xcc7b, 0x2b82, - 0xcc7c, 0x3012, - 0xcc7d, 0x1002, - 0xcc7e, 0x5663, - 0xcc7f, 0x303, - 0xcc80, 0x401e, - 0xcc81, 0x004, - 0xcc82, 0x2c42, - 0xcc83, 0x3012, - 0xcc84, 0x1002, - 0xcc85, 0x6f72, - 0xcc86, 0x1002, - 0xcc87, 0x628f, - 0xcc88, 0x2304, - 0xcc89, 0x3c84, - 0xcc8a, 0x6436, - 0xcc8b, 0xdff4, - 0xcc8c, 0x6436, - 0xcc8d, 0x2ff5, - 0xcc8e, 0x3005, - 0xcc8f, 0x8656, - 0xcc90, 0xdfba, - 0xcc91, 0x56a3, - 0xcc92, 0xd05a, - 0xcc93, 0x21c2, - 0xcc94, 0x3012, - 0xcc95, 0x1392, - 0xcc96, 0xd05a, - 0xcc97, 0x56a3, - 0xcc98, 0xdfba, - 0xcc99, 0x383, - 0xcc9a, 0x6f72, - 0xcc9b, 0x1002, - 0xcc9c, 0x28c5, - 0xcc9d, 0x3005, - 0xcc9e, 0x4178, - 0xcc9f, 0x5653, - 0xcca0, 0x384, - 0xcca1, 0x22b2, - 0xcca2, 0x3012, - 0xcca3, 0x1002, - 0xcca4, 0x2be5, - 0xcca5, 0x3005, - 0xcca6, 0x41e8, - 0xcca7, 0x5653, - 0xcca8, 0x382, - 0xcca9, 0x002, - 0xccaa, 0x4258, - 0xccab, 0x2474, - 0xccac, 0x3c84, - 0xccad, 0x6437, - 0xccae, 0xdff4, - 0xccaf, 0x6437, - 0xccb0, 0x2ff5, - 0xccb1, 0x3c05, - 0xccb2, 0x8757, - 0xccb3, 0xb888, - 0xccb4, 0x9787, - 0xccb5, 0xdff4, - 0xccb6, 0x6724, - 0xccb7, 0x866a, - 0xccb8, 0x6f72, - 0xccb9, 0x1002, - 0xccba, 0x2d01, - 0xccbb, 0x3011, - 0xccbc, 0x1001, - 0xccbd, 0xc620, - 0xccbe, 0x14e5, - 0xccbf, 0xc621, - 0xccc0, 0xc53d, - 0xccc1, 0xc622, - 0xccc2, 0x3cbe, - 0xccc3, 0xc623, - 0xccc4, 0x4452, - 0xccc5, 0xc624, - 0xccc6, 0xc5c5, - 0xccc7, 0xc625, - 0xccc8, 0xe01e, - 0xccc9, 0xc627, - 0xccca, 0x000, - 0xcccb, 0xc628, - 0xcccc, 0x000, - 0xcccd, 0xc62b, - 0xccce, 0x000, - 0xcccf, 0xc62c, - 0xccd0, 0x000, - 0xccd1, 0x000, - 0xccd2, 0x2d01, - 0xccd3, 0x3011, - 0xccd4, 0x1001, - 0xccd5, 0xc620, - 0xccd6, 0x000, - 0xccd7, 0xc621, - 0xccd8, 0x000, - 0xccd9, 0xc622, - 0xccda, 0x0ce, - 0xccdb, 0xc623, - 0xccdc, 0x07f, - 0xccdd, 0xc624, - 0xccde, 0x032, - 0xccdf, 0xc625, - 0xcce0, 0x000, - 0xcce1, 0xc627, - 0xcce2, 0x000, - 0xcce3, 0xc628, - 0xcce4, 0x000, - 0xcce5, 0xc62b, - 0xcce6, 0x000, - 0xcce7, 0xc62c, - 0xcce8, 0x000, - 0xcce9, 0x000, - 0xccea, 0x2d01, - 0xcceb, 0x3011, - 0xccec, 0x1001, - 0xcced, 0xc502, - 0xccee, 0x609f, - 0xccef, 0xc600, - 0xccf0, 0x2a6e, - 0xccf1, 0xc601, - 0xccf2, 0x2a2c, - 0xccf3, 0xc60c, - 0xccf4, 0x5400, - 0xccf5, 0xc710, - 0xccf6, 0x700, - 0xccf7, 0xc718, - 0xccf8, 0x700, - 0xccf9, 0xc720, - 0xccfa, 0x4700, - 0xccfb, 0xc728, - 0xccfc, 0x700, - 0xccfd, 0xc729, - 0xccfe, 0x1207, - 0xccff, 0xc801, - 0xcd00, 0x7f50, - 0xcd01, 0xc802, - 0xcd02, 0x7760, - 0xcd03, 0xc803, - 0xcd04, 0x7fce, - 0xcd05, 0xc804, - 0xcd06, 0x520e, - 0xcd07, 0xc805, - 0xcd08, 0x5c11, - 0xcd09, 0xc806, - 0xcd0a, 0x3c51, - 0xcd0b, 0xc807, - 0xcd0c, 0x4061, - 0xcd0d, 0xc808, - 0xcd0e, 0x49c1, - 0xcd0f, 0xc809, - 0xcd10, 0x3840, - 0xcd11, 0xc80a, - 0xcd12, 0x000, - 0xcd13, 0xc821, - 0xcd14, 0x002, - 0xcd15, 0xc822, - 0xcd16, 0x046, - 0xcd17, 0xc844, - 0xcd18, 0x182f, - 0xcd19, 0xc013, - 0xcd1a, 0xf341, - 0xcd1b, 0xc01a, - 0xcd1c, 0x446, - 0xcd1d, 0xc024, - 0xcd1e, 0x1000, - 0xcd1f, 0xc025, - 0xcd20, 0xa00, - 0xcd21, 0xc026, - 0xcd22, 0xc0c, - 0xcd23, 0xc027, - 0xcd24, 0xc0c, - 0xcd25, 0xc029, - 0xcd26, 0x0a0, - 0xcd27, 0xc030, - 0xcd28, 0xa00, - 0xcd29, 0xc03c, - 0xcd2a, 0x01c, - 0xcd2b, 0x000, - 0xcd2c, 0x2b84, - 0xcd2d, 0x3c74, - 0xcd2e, 0x6435, - 0xcd2f, 0xdff4, - 0xcd30, 0x6435, - 0xcd31, 0x2806, - 0xcd32, 0x3006, - 0xcd33, 0x8565, - 0xcd34, 0x2b24, - 0xcd35, 0x3c24, - 0xcd36, 0x6436, - 0xcd37, 0x1002, - 0xcd38, 0x2b24, - 0xcd39, 0x3c24, - 0xcd3a, 0x6436, - 0xcd3b, 0x4045, - 0xcd3c, 0x8656, - 0xcd3d, 0x1002, - 0xcd3e, 0x2807, - 0xcd3f, 0x31a7, - 0xcd40, 0x20c4, - 0xcd41, 0x3c24, - 0xcd42, 0x6724, - 0xcd43, 0x1002, - 0xcd44, 0x2807, - 0xcd45, 0x3187, - 0xcd46, 0x20c4, - 0xcd47, 0x3c24, - 0xcd48, 0x6724, - 0xcd49, 0x1002, - 0xcd4a, 0x2514, - 0xcd4b, 0x3c64, - 0xcd4c, 0x6436, - 0xcd4d, 0xdff4, - 0xcd4e, 0x6436, - 0xcd4f, 0x1002, - 0xcd50, 0x2806, - 0xcd51, 0x3cb6, - 0xcd52, 0xc161, - 0xcd53, 0x6134, - 0xcd54, 0x6135, - 0xcd55, 0x5443, - 0xcd56, 0x303, - 0xcd57, 0x6524, - 0xcd58, 0x00b, - 0xcd59, 0x1002, - 0xcd5a, 0xd019, - 0xcd5b, 0x2104, - 0xcd5c, 0x3c24, - 0xcd5d, 0x2105, - 0xcd5e, 0x3805, - 0xcd5f, 0x6524, - 0xcd60, 0xdff4, - 0xcd61, 0x4005, - 0xcd62, 0x6524, - 0xcd63, 0x2e8d, - 0xcd64, 0x303d, - 0xcd65, 0x5dd3, - 0xcd66, 0x306, - 0xcd67, 0x2ff7, - 0xcd68, 0x38f7, - 0xcd69, 0x60b7, - 0xcd6a, 0xdffd, - 0xcd6b, 0x00a, - 0xcd6c, 0x1002, - 0xcd6d, 0 - }; int i, err; err = set_phy_regs(phy, regs); @@ -982,9 +343,16 @@ static int ael2005_setup_twinax_edc(struct cphy *phy, int modtype) msleep(50); - for (i = 0; i < ARRAY_SIZE(twinax_edc) && !err; i += 2) - err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, twinax_edc[i], - twinax_edc[i + 1]); + if (phy->priv != edc_twinax) + err = t3_get_edc_fw(phy, EDC_TWX_AEL2005, + EDC_TWX_AEL2005_SIZE); + if (err) + return err; + + for (i = 0; i < EDC_TWX_AEL2005_SIZE / sizeof(u16) && !err; i += 2) + err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, + phy->phy_cache[i], + phy->phy_cache[i + 1]); if (!err) phy->priv = edc_twinax; return err; @@ -1201,405 +569,6 @@ static int ael2020_setup_twinax_edc(struct cphy *phy, int modtype) { MDIO_MMD_PMAPMD, 0xd092, 0xffff, 0x0000 }, { 0, 0, 0, 0 } }; - - /* TWINAX EDC firmware */ - static u16 twinax_edc[] = { - 0xd800, 0x4009, - 0xd801, 0x2fff, - 0xd802, 0x300f, - 0xd803, 0x40aa, - 0xd804, 0x401c, - 0xd805, 0x401e, - 0xd806, 0x2ff4, - 0xd807, 0x3dc4, - 0xd808, 0x2035, - 0xd809, 0x3035, - 0xd80a, 0x6524, - 0xd80b, 0x2cb2, - 0xd80c, 0x3012, - 0xd80d, 0x1002, - 0xd80e, 0x26e2, - 0xd80f, 0x3022, - 0xd810, 0x1002, - 0xd811, 0x27d2, - 0xd812, 0x3022, - 0xd813, 0x1002, - 0xd814, 0x2822, - 0xd815, 0x3012, - 0xd816, 0x1002, - 0xd817, 0x2492, - 0xd818, 0x3022, - 0xd819, 0x1002, - 0xd81a, 0x2772, - 0xd81b, 0x3012, - 0xd81c, 0x1002, - 0xd81d, 0x23d2, - 0xd81e, 0x3022, - 0xd81f, 0x1002, - 0xd820, 0x22cd, - 0xd821, 0x301d, - 0xd822, 0x27f2, - 0xd823, 0x3022, - 0xd824, 0x1002, - 0xd825, 0x5553, - 0xd826, 0x0307, - 0xd827, 0x2522, - 0xd828, 0x3022, - 0xd829, 0x1002, - 0xd82a, 0x2142, - 0xd82b, 0x3012, - 0xd82c, 0x1002, - 0xd82d, 0x4016, - 0xd82e, 0x5e63, - 0xd82f, 0x0344, - 0xd830, 0x2142, - 0xd831, 0x3012, - 0xd832, 0x1002, - 0xd833, 0x400e, - 0xd834, 0x2522, - 0xd835, 0x3022, - 0xd836, 0x1002, - 0xd837, 0x2b52, - 0xd838, 0x3012, - 0xd839, 0x1002, - 0xd83a, 0x2742, - 0xd83b, 0x3022, - 0xd83c, 0x1002, - 0xd83d, 0x25e2, - 0xd83e, 0x3022, - 0xd83f, 0x1002, - 0xd840, 0x2fa4, - 0xd841, 0x3dc4, - 0xd842, 0x6624, - 0xd843, 0x414b, - 0xd844, 0x56b3, - 0xd845, 0x03c6, - 0xd846, 0x866b, - 0xd847, 0x400c, - 0xd848, 0x2712, - 0xd849, 0x3012, - 0xd84a, 0x1002, - 0xd84b, 0x2c4b, - 0xd84c, 0x309b, - 0xd84d, 0x56b3, - 0xd84e, 0x03c3, - 0xd84f, 0x866b, - 0xd850, 0x400c, - 0xd851, 0x2272, - 0xd852, 0x3022, - 0xd853, 0x1002, - 0xd854, 0x2742, - 0xd855, 0x3022, - 0xd856, 0x1002, - 0xd857, 0x25e2, - 0xd858, 0x3022, - 0xd859, 0x1002, - 0xd85a, 0x2fb4, - 0xd85b, 0x3dc4, - 0xd85c, 0x6624, - 0xd85d, 0x56b3, - 0xd85e, 0x03c3, - 0xd85f, 0x866b, - 0xd860, 0x401c, - 0xd861, 0x2c45, - 0xd862, 0x3095, - 0xd863, 0x5b53, - 0xd864, 0x2372, - 0xd865, 0x3012, - 0xd866, 0x13c2, - 0xd867, 0x5cc3, - 0xd868, 0x2712, - 0xd869, 0x3012, - 0xd86a, 0x1312, - 0xd86b, 0x2b52, - 0xd86c, 0x3012, - 0xd86d, 0x1002, - 0xd86e, 0x2742, - 0xd86f, 0x3022, - 0xd870, 0x1002, - 0xd871, 0x2582, - 0xd872, 0x3022, - 0xd873, 0x1002, - 0xd874, 0x2142, - 0xd875, 0x3012, - 0xd876, 0x1002, - 0xd877, 0x628f, - 0xd878, 0x2985, - 0xd879, 0x33a5, - 0xd87a, 0x25e2, - 0xd87b, 0x3022, - 0xd87c, 0x1002, - 0xd87d, 0x5653, - 0xd87e, 0x03d2, - 0xd87f, 0x401e, - 0xd880, 0x6f72, - 0xd881, 0x1002, - 0xd882, 0x628f, - 0xd883, 0x2304, - 0xd884, 0x3c84, - 0xd885, 0x6436, - 0xd886, 0xdff4, - 0xd887, 0x6436, - 0xd888, 0x2ff5, - 0xd889, 0x3005, - 0xd88a, 0x8656, - 0xd88b, 0xdfba, - 0xd88c, 0x56a3, - 0xd88d, 0xd05a, - 0xd88e, 0x2972, - 0xd88f, 0x3012, - 0xd890, 0x1392, - 0xd891, 0xd05a, - 0xd892, 0x56a3, - 0xd893, 0xdfba, - 0xd894, 0x0383, - 0xd895, 0x6f72, - 0xd896, 0x1002, - 0xd897, 0x2b45, - 0xd898, 0x3005, - 0xd899, 0x4178, - 0xd89a, 0x5653, - 0xd89b, 0x0384, - 0xd89c, 0x2a62, - 0xd89d, 0x3012, - 0xd89e, 0x1002, - 0xd89f, 0x2f05, - 0xd8a0, 0x3005, - 0xd8a1, 0x41c8, - 0xd8a2, 0x5653, - 0xd8a3, 0x0382, - 0xd8a4, 0x0002, - 0xd8a5, 0x4218, - 0xd8a6, 0x2474, - 0xd8a7, 0x3c84, - 0xd8a8, 0x6437, - 0xd8a9, 0xdff4, - 0xd8aa, 0x6437, - 0xd8ab, 0x2ff5, - 0xd8ac, 0x3c05, - 0xd8ad, 0x8757, - 0xd8ae, 0xb888, - 0xd8af, 0x9787, - 0xd8b0, 0xdff4, - 0xd8b1, 0x6724, - 0xd8b2, 0x866a, - 0xd8b3, 0x6f72, - 0xd8b4, 0x1002, - 0xd8b5, 0x2641, - 0xd8b6, 0x3021, - 0xd8b7, 0x1001, - 0xd8b8, 0xc620, - 0xd8b9, 0x0000, - 0xd8ba, 0xc621, - 0xd8bb, 0x0000, - 0xd8bc, 0xc622, - 0xd8bd, 0x00ce, - 0xd8be, 0xc623, - 0xd8bf, 0x007f, - 0xd8c0, 0xc624, - 0xd8c1, 0x0032, - 0xd8c2, 0xc625, - 0xd8c3, 0x0000, - 0xd8c4, 0xc627, - 0xd8c5, 0x0000, - 0xd8c6, 0xc628, - 0xd8c7, 0x0000, - 0xd8c8, 0xc62c, - 0xd8c9, 0x0000, - 0xd8ca, 0x0000, - 0xd8cb, 0x2641, - 0xd8cc, 0x3021, - 0xd8cd, 0x1001, - 0xd8ce, 0xc502, - 0xd8cf, 0x53ac, - 0xd8d0, 0xc503, - 0xd8d1, 0x2cd3, - 0xd8d2, 0xc600, - 0xd8d3, 0x2a6e, - 0xd8d4, 0xc601, - 0xd8d5, 0x2a2c, - 0xd8d6, 0xc605, - 0xd8d7, 0x5557, - 0xd8d8, 0xc60c, - 0xd8d9, 0x5400, - 0xd8da, 0xc710, - 0xd8db, 0x0700, - 0xd8dc, 0xc711, - 0xd8dd, 0x0f06, - 0xd8de, 0xc718, - 0xd8df, 0x0700, - 0xd8e0, 0xc719, - 0xd8e1, 0x0f06, - 0xd8e2, 0xc720, - 0xd8e3, 0x4700, - 0xd8e4, 0xc721, - 0xd8e5, 0x0f06, - 0xd8e6, 0xc728, - 0xd8e7, 0x0700, - 0xd8e8, 0xc729, - 0xd8e9, 0x1207, - 0xd8ea, 0xc801, - 0xd8eb, 0x7f50, - 0xd8ec, 0xc802, - 0xd8ed, 0x7760, - 0xd8ee, 0xc803, - 0xd8ef, 0x7fce, - 0xd8f0, 0xc804, - 0xd8f1, 0x520e, - 0xd8f2, 0xc805, - 0xd8f3, 0x5c11, - 0xd8f4, 0xc806, - 0xd8f5, 0x3c51, - 0xd8f6, 0xc807, - 0xd8f7, 0x4061, - 0xd8f8, 0xc808, - 0xd8f9, 0x49c1, - 0xd8fa, 0xc809, - 0xd8fb, 0x3840, - 0xd8fc, 0xc80a, - 0xd8fd, 0x0000, - 0xd8fe, 0xc821, - 0xd8ff, 0x0002, - 0xd900, 0xc822, - 0xd901, 0x0046, - 0xd902, 0xc844, - 0xd903, 0x182f, - 0xd904, 0xc013, - 0xd905, 0xf341, - 0xd906, 0xc084, - 0xd907, 0x0030, - 0xd908, 0xc904, - 0xd909, 0x1401, - 0xd90a, 0xcb0c, - 0xd90b, 0x0004, - 0xd90c, 0xcb0e, - 0xd90d, 0xa00a, - 0xd90e, 0xcb0f, - 0xd90f, 0xc0c0, - 0xd910, 0xcb10, - 0xd911, 0xc0c0, - 0xd912, 0xcb11, - 0xd913, 0x00a0, - 0xd914, 0xcb12, - 0xd915, 0x0007, - 0xd916, 0xc241, - 0xd917, 0xa000, - 0xd918, 0xc243, - 0xd919, 0x7fe0, - 0xd91a, 0xc604, - 0xd91b, 0x000e, - 0xd91c, 0xc609, - 0xd91d, 0x00f5, - 0xd91e, 0xc611, - 0xd91f, 0x000e, - 0xd920, 0xc660, - 0xd921, 0x9600, - 0xd922, 0xc687, - 0xd923, 0x0004, - 0xd924, 0xc60a, - 0xd925, 0x04f5, - 0xd926, 0x0000, - 0xd927, 0x2641, - 0xd928, 0x3021, - 0xd929, 0x1001, - 0xd92a, 0xc620, - 0xd92b, 0x14e5, - 0xd92c, 0xc621, - 0xd92d, 0xc53d, - 0xd92e, 0xc622, - 0xd92f, 0x3cbe, - 0xd930, 0xc623, - 0xd931, 0x4452, - 0xd932, 0xc624, - 0xd933, 0xc5c5, - 0xd934, 0xc625, - 0xd935, 0xe01e, - 0xd936, 0xc627, - 0xd937, 0x0000, - 0xd938, 0xc628, - 0xd939, 0x0000, - 0xd93a, 0xc62c, - 0xd93b, 0x0000, - 0xd93c, 0x0000, - 0xd93d, 0x2b84, - 0xd93e, 0x3c74, - 0xd93f, 0x6435, - 0xd940, 0xdff4, - 0xd941, 0x6435, - 0xd942, 0x2806, - 0xd943, 0x3006, - 0xd944, 0x8565, - 0xd945, 0x2b24, - 0xd946, 0x3c24, - 0xd947, 0x6436, - 0xd948, 0x1002, - 0xd949, 0x2b24, - 0xd94a, 0x3c24, - 0xd94b, 0x6436, - 0xd94c, 0x4045, - 0xd94d, 0x8656, - 0xd94e, 0x5663, - 0xd94f, 0x0302, - 0xd950, 0x401e, - 0xd951, 0x1002, - 0xd952, 0x2807, - 0xd953, 0x31a7, - 0xd954, 0x20c4, - 0xd955, 0x3c24, - 0xd956, 0x6724, - 0xd957, 0x1002, - 0xd958, 0x2807, - 0xd959, 0x3187, - 0xd95a, 0x20c4, - 0xd95b, 0x3c24, - 0xd95c, 0x6724, - 0xd95d, 0x1002, - 0xd95e, 0x24f4, - 0xd95f, 0x3c64, - 0xd960, 0x6436, - 0xd961, 0xdff4, - 0xd962, 0x6436, - 0xd963, 0x1002, - 0xd964, 0x2006, - 0xd965, 0x3d76, - 0xd966, 0xc161, - 0xd967, 0x6134, - 0xd968, 0x6135, - 0xd969, 0x5443, - 0xd96a, 0x0303, - 0xd96b, 0x6524, - 0xd96c, 0x00fb, - 0xd96d, 0x1002, - 0xd96e, 0x20d4, - 0xd96f, 0x3c24, - 0xd970, 0x2025, - 0xd971, 0x3005, - 0xd972, 0x6524, - 0xd973, 0x1002, - 0xd974, 0xd019, - 0xd975, 0x2104, - 0xd976, 0x3c24, - 0xd977, 0x2105, - 0xd978, 0x3805, - 0xd979, 0x6524, - 0xd97a, 0xdff4, - 0xd97b, 0x4005, - 0xd97c, 0x6524, - 0xd97d, 0x2e8d, - 0xd97e, 0x303d, - 0xd97f, 0x2408, - 0xd980, 0x35d8, - 0xd981, 0x5dd3, - 0xd982, 0x0307, - 0xd983, 0x8887, - 0xd984, 0x63a7, - 0xd985, 0x8887, - 0xd986, 0x63a7, - 0xd987, 0xdffd, - 0xd988, 0x00f9, - 0xd989, 0x1002, - 0xd98a, 0x0000, - }; int i, err; /* set uC clock and activate it */ @@ -1612,10 +581,16 @@ static int ael2020_setup_twinax_edc(struct cphy *phy, int modtype) if (err) return err; - /* write TWINAX EDC firmware into PHY */ - for (i = 0; i < ARRAY_SIZE(twinax_edc) && !err; i += 2) - err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, twinax_edc[i], - twinax_edc[i + 1]); + if (phy->priv != edc_twinax) + err = t3_get_edc_fw(phy, EDC_TWX_AEL2020, + EDC_TWX_AEL2020_SIZE); + if (err) + return err; + + for (i = 0; i < EDC_TWX_AEL2020_SIZE / sizeof(u16) && !err; i += 2) + err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, + phy->phy_cache[i], + phy->phy_cache[i + 1]); /* activate uC */ err = set_phy_regs(phy, uCactivate); if (!err) @@ -1649,9 +624,39 @@ static int ael2020_get_module_type(struct cphy *phy, int delay_ms) */ static int ael2020_intr_enable(struct cphy *phy) { - int err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL, - 0x2 << (AEL2020_GPIO_MODDET*4)); - return err ? err : t3_phy_lasi_intr_enable(phy); + struct reg_val regs[] = { + /* output Module's Loss Of Signal (LOS) to LED */ + { MDIO_MMD_PMAPMD, AEL2020_GPIO_CFG+AEL2020_GPIO_LSTAT, + 0xffff, 0x4 }, + { MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL, + 0xffff, 0x8 << (AEL2020_GPIO_LSTAT*4) }, + + /* enable module detect status change interrupts */ + { MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL, + 0xffff, 0x2 << (AEL2020_GPIO_MODDET*4) }, + + /* end */ + { 0, 0, 0, 0 } + }; + int err, link_ok = 0; + + /* set up "link status" LED and enable module change interrupts */ + err = set_phy_regs(phy, regs); + if (err) + return err; + + err = get_link_status_r(phy, &link_ok, NULL, NULL, NULL); + if (err) + return err; + if (link_ok) + t3_link_changed(phy->adapter, + phy2portid(phy)); + + err = t3_phy_lasi_intr_enable(phy); + if (err) + return err; + + return 0; } /* @@ -1659,9 +664,26 @@ static int ael2020_intr_enable(struct cphy *phy) */ static int ael2020_intr_disable(struct cphy *phy) { - int err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL, - 0x1 << (AEL2020_GPIO_MODDET*4)); - return err ? err : t3_phy_lasi_intr_disable(phy); + struct reg_val regs[] = { + /* reset "link status" LED to "off" */ + { MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL, + 0xffff, 0xb << (AEL2020_GPIO_LSTAT*4) }, + + /* disable module detect status change interrupts */ + { MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL, + 0xffff, 0x1 << (AEL2020_GPIO_MODDET*4) }, + + /* end */ + { 0, 0, 0, 0 } + }; + int err; + + /* turn off "link status" LED and disable module change interrupts */ + err = set_phy_regs(phy, regs); + if (err) + return err; + + return t3_phy_lasi_intr_disable(phy); } /* @@ -1679,31 +701,26 @@ static int ael2020_intr_clear(struct cphy *phy) return err ? err : t3_phy_lasi_intr_clear(phy); } +static struct reg_val ael2020_reset_regs[] = { + /* Erratum #2: CDRLOL asserted, causing PMA link down status */ + { MDIO_MMD_PMAPMD, 0xc003, 0xffff, 0x3101 }, + + /* force XAUI to send LF when RX_LOS is asserted */ + { MDIO_MMD_PMAPMD, 0xcd40, 0xffff, 0x0001 }, + + /* allow writes to transceiver module EEPROM on i2c bus */ + { MDIO_MMD_PMAPMD, 0xff02, 0xffff, 0x0023 }, + { MDIO_MMD_PMAPMD, 0xff03, 0xffff, 0x0000 }, + { MDIO_MMD_PMAPMD, 0xff04, 0xffff, 0x0000 }, + + /* end */ + { 0, 0, 0, 0 } +}; /* * Reset the PHY and put it into a canonical operating state. */ static int ael2020_reset(struct cphy *phy, int wait) { - static struct reg_val regs0[] = { - /* Erratum #2: CDRLOL asserted, causing PMA link down status */ - { MDIO_MMD_PMAPMD, 0xc003, 0xffff, 0x3101 }, - - /* force XAUI to send LF when RX_LOS is asserted */ - { MDIO_MMD_PMAPMD, 0xcd40, 0xffff, 0x0001 }, - - /* RX_LOS pin is active high */ - { MDIO_MMD_PMAPMD, AEL_OPT_SETTINGS, - 0x0020, 0x0020 }, - - /* output Module's Loss Of Signal (LOS) to LED */ - { MDIO_MMD_PMAPMD, AEL2020_GPIO_CFG+AEL2020_GPIO_LSTAT, - 0xffff, 0x0004 }, - { MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL, - 0xffff, 0x8 << (AEL2020_GPIO_LSTAT*4) }, - - /* end */ - { 0, 0, 0, 0 } - }; int err; unsigned int lasi_ctrl; @@ -1720,7 +737,7 @@ static int ael2020_reset(struct cphy *phy, int wait) /* basic initialization for all module types */ phy->priv = edc_none; - err = set_phy_regs(phy, regs0); + err = set_phy_regs(phy, ael2020_reset_regs); if (err) return err; @@ -1798,10 +815,16 @@ static struct cphy_ops ael2020_ops = { int t3_ael2020_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr, const struct mdio_ops *mdio_ops) { + int err; + cphy_init(phy, adapter, phy_addr, &ael2020_ops, mdio_ops, SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE | SUPPORTED_IRQ, "10GBASE-R"); msleep(125); + + err = set_phy_regs(phy, ael2020_reset_regs); + if (err) + return err; return 0; } @@ -1840,7 +863,7 @@ static struct cphy_ops qt2045_ops = { .intr_clear = t3_phy_lasi_intr_clear, .intr_handler = t3_phy_lasi_intr_handler, .get_link_status = get_link_status_x, - .power_down = ael1006_power_down, + .power_down = ael1002_power_down, .mmds = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS, }; diff --git a/drivers/net/cxgb3/aq100x.c b/drivers/net/cxgb3/aq100x.c index b1fd5bf836e..341b7ef1508 100644 --- a/drivers/net/cxgb3/aq100x.c +++ b/drivers/net/cxgb3/aq100x.c @@ -271,7 +271,8 @@ int t3_aq100x_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr, cphy_init(phy, adapter, phy_addr, &aq100x_ops, mdio_ops, SUPPORTED_1000baseT_Full | SUPPORTED_10000baseT_Full | - SUPPORTED_Autoneg | SUPPORTED_AUI, "1000/10GBASE-T"); + SUPPORTED_TP | SUPPORTED_Autoneg | SUPPORTED_AUI, + "1000/10GBASE-T"); /* * The PHY has been out of reset ever since the system powered up. So @@ -316,11 +317,9 @@ int t3_aq100x_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr, /* Firmware version check. */ t3_mdio_read(phy, MDIO_MMD_VEND1, AQ_FW_VERSION, &v); - if (v != 30) { + if (v != 101) CH_WARN(adapter, "PHY%d: unsupported firmware %d\n", phy_addr, v); - return 0; /* allow t3_prep_adapter to succeed */ - } /* * The PHY should start in really-low-power mode. Prepare it for normal diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h index d21b705501a..1b2c305fb82 100644 --- a/drivers/net/cxgb3/common.h +++ b/drivers/net/cxgb3/common.h @@ -566,6 +566,15 @@ struct cphy_ops { u32 mmds; }; +enum { + EDC_OPT_AEL2005 = 0, + EDC_OPT_AEL2005_SIZE = 1084, + EDC_TWX_AEL2005 = 1, + EDC_TWX_AEL2005_SIZE = 1464, + EDC_TWX_AEL2020 = 2, + EDC_TWX_AEL2020_SIZE = 1628, + EDC_MAX_SIZE = EDC_TWX_AEL2020_SIZE, /* Max cache size */ +}; /* A PHY instance */ struct cphy { @@ -577,6 +586,7 @@ struct cphy { unsigned long fifo_errors; /* FIFO over/under-flows */ const struct cphy_ops *ops; /* PHY operations */ struct mdio_if_info mdio; + u16 phy_cache[EDC_MAX_SIZE]; /* EDC cache */ }; /* Convenience MDIO read/write wrappers */ diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index fb5df5c6203..ec05149a906 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -172,6 +172,23 @@ static void link_report(struct net_device *dev) } } +static void enable_tx_fifo_drain(struct adapter *adapter, + struct port_info *pi) +{ + t3_set_reg_field(adapter, A_XGM_TXFIFO_CFG + pi->mac.offset, 0, + F_ENDROPPKT); + t3_write_reg(adapter, A_XGM_RX_CTRL + pi->mac.offset, 0); + t3_write_reg(adapter, A_XGM_TX_CTRL + pi->mac.offset, F_TXEN); + t3_write_reg(adapter, A_XGM_RX_CTRL + pi->mac.offset, F_RXEN); +} + +static void disable_tx_fifo_drain(struct adapter *adapter, + struct port_info *pi) +{ + t3_set_reg_field(adapter, A_XGM_TXFIFO_CFG + pi->mac.offset, + F_ENDROPPKT, 0); +} + void t3_os_link_fault(struct adapter *adap, int port_id, int state) { struct net_device *dev = adap->port[port_id]; @@ -185,6 +202,8 @@ void t3_os_link_fault(struct adapter *adap, int port_id, int state) netif_carrier_on(dev); + disable_tx_fifo_drain(adap, pi); + /* Clear local faults */ t3_xgm_intr_disable(adap, pi->port_id); t3_read_reg(adap, A_XGM_INT_STATUS + @@ -200,9 +219,12 @@ void t3_os_link_fault(struct adapter *adap, int port_id, int state) t3_xgm_intr_enable(adap, pi->port_id); t3_mac_enable(mac, MAC_DIRECTION_TX); - } else + } else { netif_carrier_off(dev); + /* Flush TX FIFO */ + enable_tx_fifo_drain(adap, pi); + } link_report(dev); } @@ -232,6 +254,8 @@ void t3_os_link_changed(struct adapter *adapter, int port_id, int link_stat, if (link_stat != netif_carrier_ok(dev)) { if (link_stat) { + disable_tx_fifo_drain(adapter, pi); + t3_mac_enable(mac, MAC_DIRECTION_RX); /* Clear local faults */ @@ -263,6 +287,9 @@ void t3_os_link_changed(struct adapter *adapter, int port_id, int link_stat, t3_read_reg(adapter, A_XGM_INT_STATUS + pi->mac.offset); t3_mac_disable(mac, MAC_DIRECTION_RX); t3_link_start(&pi->phy, mac, &pi->link_config); + + /* Flush TX FIFO */ + enable_tx_fifo_drain(adapter, pi); } link_report(dev); @@ -443,6 +470,7 @@ static int init_tp_parity(struct adapter *adap) memset(req, 0, sizeof(*req)); req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, i)); + req->mtu_idx = NMTUS - 1; req->iff = i; t3_mgmt_tx(adap, skb); if (skb == adap->nofail_skb) { @@ -963,6 +991,75 @@ static int bind_qsets(struct adapter *adap) #define FW_FNAME "cxgb3/t3fw-%d.%d.%d.bin" #define TPSRAM_NAME "cxgb3/t3%c_psram-%d.%d.%d.bin" +#define AEL2005_OPT_EDC_NAME "cxgb3/ael2005_opt_edc.bin" +#define AEL2005_TWX_EDC_NAME "cxgb3/ael2005_twx_edc.bin" +#define AEL2020_TWX_EDC_NAME "cxgb3/ael2005_twx_edc.bin" + +static inline const char *get_edc_fw_name(int edc_idx) +{ + const char *fw_name = NULL; + + switch (edc_idx) { + case EDC_OPT_AEL2005: + fw_name = AEL2005_OPT_EDC_NAME; + break; + case EDC_TWX_AEL2005: + fw_name = AEL2005_TWX_EDC_NAME; + break; + case EDC_TWX_AEL2020: + fw_name = AEL2020_TWX_EDC_NAME; + break; + } + return fw_name; +} + +int t3_get_edc_fw(struct cphy *phy, int edc_idx, int size) +{ + struct adapter *adapter = phy->adapter; + const struct firmware *fw; + char buf[64]; + u32 csum; + const __be32 *p; + u16 *cache = phy->phy_cache; + int i, ret; + + snprintf(buf, sizeof(buf), get_edc_fw_name(edc_idx)); + + ret = request_firmware(&fw, buf, &adapter->pdev->dev); + if (ret < 0) { + dev_err(&adapter->pdev->dev, + "could not upgrade firmware: unable to load %s\n", + buf); + return ret; + } + + /* check size, take checksum in account */ + if (fw->size > size + 4) { + CH_ERR(adapter, "firmware image too large %u, expected %d\n", + (unsigned int)fw->size, size + 4); + ret = -EINVAL; + } + + /* compute checksum */ + p = (const __be32 *)fw->data; + for (csum = 0, i = 0; i < fw->size / sizeof(csum); i++) + csum += ntohl(p[i]); + + if (csum != 0xffffffff) { + CH_ERR(adapter, "corrupted firmware image, checksum %u\n", + csum); + ret = -EINVAL; + } + + for (i = 0; i < size / 4 ; i++) { + *cache++ = (be32_to_cpu(p[i]) & 0xffff0000) >> 16; + *cache++ = be32_to_cpu(p[i]) & 0xffff; + } + + release_firmware(fw); + + return ret; +} static int upgrade_fw(struct adapter *adap) { diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c index 870d44992c7..e78d341cbd6 100644 --- a/drivers/net/cxgb3/t3_hw.c +++ b/drivers/net/cxgb3/t3_hw.c @@ -3682,6 +3682,8 @@ static void mc7_prep(struct adapter *adapter, struct mc7 *mc7, void mac_prep(struct cmac *mac, struct adapter *adapter, int index) { mac->adapter = adapter; + if (!adapter->params.vpd.xauicfg[1]) + index = 0; mac->offset = (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR) * index; mac->nucast = 1; diff --git a/drivers/net/cxgb3/xgmac.c b/drivers/net/cxgb3/xgmac.c index f87f9435049..0109ee4f2f9 100644 --- a/drivers/net/cxgb3/xgmac.c +++ b/drivers/net/cxgb3/xgmac.c @@ -447,11 +447,12 @@ int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc) val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft); val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM); - if (fc & PAUSE_TX) - val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm( - t3_read_reg(adap, - A_XGM_RX_MAX_PKT_SIZE - + oft)) / 8); + if (fc & PAUSE_TX) { + u32 rx_max_pkt_size = + G_RXMAXPKTSIZE(t3_read_reg(adap, + A_XGM_RX_MAX_PKT_SIZE + oft)); + val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(rx_max_pkt_size) / 8); + } t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val); t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN, diff --git a/drivers/net/de600.c b/drivers/net/de600.c index e1af089064b..6b13f4fd2e9 100644 --- a/drivers/net/de600.c +++ b/drivers/net/de600.c @@ -226,7 +226,7 @@ static int de600_start_xmit(struct sk_buff *skb, struct net_device *dev) } spin_unlock_irqrestore(&de600_lock, flags); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/de620.c b/drivers/net/de620.c index 55d2bb67cff..45794f6cb0f 100644 --- a/drivers/net/de620.c +++ b/drivers/net/de620.c @@ -542,7 +542,7 @@ static int de620_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->stats.tx_packets++; spin_unlock_irqrestore(&de620_lock, flags); dev_kfree_skb (skb); - return 0; + return NETDEV_TX_OK; } /***************************************************** diff --git a/drivers/net/declance.c b/drivers/net/declance.c index 2b22e580c4d..a31696a3928 100644 --- a/drivers/net/declance.c +++ b/drivers/net/declance.c @@ -902,7 +902,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev) if (len < ETH_ZLEN) { if (skb_padto(skb, ETH_ZLEN)) - return 0; + return NETDEV_TX_OK; len = ETH_ZLEN; } @@ -933,7 +933,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } static void lance_load_multicast(struct net_device *dev) diff --git a/drivers/net/defxx.c b/drivers/net/defxx.c index 102b8d43971..b2e0a8fc21d 100644 --- a/drivers/net/defxx.c +++ b/drivers/net/defxx.c @@ -3218,7 +3218,7 @@ static int dfx_xmt_queue_pkt( bp->xmt_length_errors++; /* bump error counter */ netif_wake_queue(dev); dev_kfree_skb(skb); - return(0); /* return "success" */ + return NETDEV_TX_OK; /* return "success" */ } /* * See if adapter link is available, if not, free buffer @@ -3241,7 +3241,7 @@ static int dfx_xmt_queue_pkt( bp->xmt_discards++; /* bump error counter */ dev_kfree_skb(skb); /* free sk_buff now */ netif_wake_queue(dev); - return(0); /* return "success" */ + return NETDEV_TX_OK; /* return "success" */ } } @@ -3345,7 +3345,7 @@ static int dfx_xmt_queue_pkt( dfx_port_write_long(bp, PI_PDQ_K_REG_TYPE_2_PROD, bp->rcv_xmt_reg.lword); spin_unlock_irqrestore(&bp->lock, flags); netif_wake_queue(dev); - return(0); /* packet queued to adapter */ + return NETDEV_TX_OK; /* packet queued to adapter */ } diff --git a/drivers/net/depca.c b/drivers/net/depca.c index 97ea2d6d3fe..adb997c5bb5 100644 --- a/drivers/net/depca.c +++ b/drivers/net/depca.c @@ -1793,7 +1793,7 @@ static int __init get_hw_addr(struct net_device *dev) static int load_packet(struct net_device *dev, struct sk_buff *skb) { struct depca_private *lp = netdev_priv(dev); - int i, entry, end, len, status = 0; + int i, entry, end, len, status = NETDEV_TX_OK; entry = lp->tx_new; /* Ring around buffer number. */ end = (entry + (skb->len - 1) / TX_BUFF_SZ) & lp->txRingMask; diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c index dd771dea6ae..8603806be89 100644 --- a/drivers/net/dm9000.c +++ b/drivers/net/dm9000.c @@ -92,6 +92,7 @@ typedef struct board_info { u16 tx_pkt_cnt; u16 queue_pkt_len; u16 queue_start_addr; + u16 queue_ip_summed; u16 dbug_cnt; u8 io_mode; /* 0:word, 2:byte */ u8 phy_addr; @@ -124,6 +125,10 @@ typedef struct board_info { struct mii_if_info mii; u32 msg_enable; + + int rx_csum; + int can_csum; + int ip_summed; } board_info_t; /* debug code */ @@ -460,6 +465,40 @@ static int dm9000_nway_reset(struct net_device *dev) return mii_nway_restart(&dm->mii); } +static uint32_t dm9000_get_rx_csum(struct net_device *dev) +{ + board_info_t *dm = to_dm9000_board(dev); + return dm->rx_csum; +} + +static int dm9000_set_rx_csum(struct net_device *dev, uint32_t data) +{ + board_info_t *dm = to_dm9000_board(dev); + unsigned long flags; + + if (dm->can_csum) { + dm->rx_csum = data; + + spin_lock_irqsave(&dm->lock, flags); + iow(dm, DM9000_RCSR, dm->rx_csum ? RCSR_CSUM : 0); + spin_unlock_irqrestore(&dm->lock, flags); + + return 0; + } + + return -EOPNOTSUPP; +} + +static int dm9000_set_tx_csum(struct net_device *dev, uint32_t data) +{ + board_info_t *dm = to_dm9000_board(dev); + int ret = -EOPNOTSUPP; + + if (dm->can_csum) + ret = ethtool_op_set_tx_csum(dev, data); + return ret; +} + static u32 dm9000_get_link(struct net_device *dev) { board_info_t *dm = to_dm9000_board(dev); @@ -540,6 +579,10 @@ static const struct ethtool_ops dm9000_ethtool_ops = { .get_eeprom_len = dm9000_get_eeprom_len, .get_eeprom = dm9000_get_eeprom, .set_eeprom = dm9000_set_eeprom, + .get_rx_csum = dm9000_get_rx_csum, + .set_rx_csum = dm9000_set_rx_csum, + .get_tx_csum = ethtool_op_get_tx_csum, + .set_tx_csum = dm9000_set_tx_csum, }; static void dm9000_show_carrier(board_info_t *db, @@ -685,6 +728,9 @@ dm9000_init_dm9000(struct net_device *dev) /* I/O mode */ db->io_mode = ior(db, DM9000_ISR) >> 6; /* ISR bit7:6 keeps I/O mode */ + /* Checksum mode */ + dm9000_set_rx_csum(dev, db->rx_csum); + /* GPIO0 on pre-activate PHY */ iow(db, DM9000_GPR, 0); /* REG_1F bit0 activate phyxcer */ iow(db, DM9000_GPCR, GPCR_GEP_CNTL); /* Let GPIO0 output */ @@ -743,6 +789,29 @@ static void dm9000_timeout(struct net_device *dev) spin_unlock_irqrestore(&db->lock, flags); } +static void dm9000_send_packet(struct net_device *dev, + int ip_summed, + u16 pkt_len) +{ + board_info_t *dm = to_dm9000_board(dev); + + /* The DM9000 is not smart enough to leave fragmented packets alone. */ + if (dm->ip_summed != ip_summed) { + if (ip_summed == CHECKSUM_NONE) + iow(dm, DM9000_TCCR, 0); + else + iow(dm, DM9000_TCCR, TCCR_IP | TCCR_UDP | TCCR_TCP); + dm->ip_summed = ip_summed; + } + + /* Set TX length to DM9000 */ + iow(dm, DM9000_TXPLL, pkt_len); + iow(dm, DM9000_TXPLH, pkt_len >> 8); + + /* Issue TX polling command */ + iow(dm, DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */ +} + /* * Hardware start transmission. * Send a packet to media from the upper layer. @@ -769,17 +838,11 @@ dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev) db->tx_pkt_cnt++; /* TX control: First packet immediately send, second packet queue */ if (db->tx_pkt_cnt == 1) { - /* Set TX length to DM9000 */ - iow(db, DM9000_TXPLL, skb->len); - iow(db, DM9000_TXPLH, skb->len >> 8); - - /* Issue TX polling command */ - iow(db, DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */ - - dev->trans_start = jiffies; /* save the time stamp */ + dm9000_send_packet(dev, skb->ip_summed, skb->len); } else { /* Second packet */ db->queue_pkt_len = skb->len; + db->queue_ip_summed = skb->ip_summed; netif_stop_queue(dev); } @@ -788,7 +851,7 @@ dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev) /* free this SKB */ dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* @@ -809,12 +872,9 @@ static void dm9000_tx_done(struct net_device *dev, board_info_t *db) dev_dbg(db->dev, "tx done, NSR %02x\n", tx_status); /* Queue packet check & send */ - if (db->tx_pkt_cnt > 0) { - iow(db, DM9000_TXPLL, db->queue_pkt_len); - iow(db, DM9000_TXPLH, db->queue_pkt_len >> 8); - iow(db, DM9000_TCR, TCR_TXREQ); - dev->trans_start = jiffies; - } + if (db->tx_pkt_cnt > 0) + dm9000_send_packet(dev, db->queue_ip_summed, + db->queue_pkt_len); netif_wake_queue(dev); } } @@ -846,14 +906,14 @@ dm9000_rx(struct net_device *dev) rxbyte = readb(db->io_data); /* Status check: this byte must be 0 or 1 */ - if (rxbyte > DM9000_PKT_RDY) { + if (rxbyte & DM9000_PKT_ERR) { dev_warn(db->dev, "status check fail: %d\n", rxbyte); iow(db, DM9000_RCR, 0x00); /* Stop Device */ iow(db, DM9000_ISR, IMR_PAR); /* Stop INT request */ return; } - if (rxbyte != DM9000_PKT_RDY) + if (!(rxbyte & DM9000_PKT_RDY)) return; /* A packet ready now & Get status/length */ @@ -914,6 +974,12 @@ dm9000_rx(struct net_device *dev) /* Pass to upper layer */ skb->protocol = eth_type_trans(skb, dev); + if (db->rx_csum) { + if ((((rxbyte & 0x1c) << 3) & rxbyte) == 0) + skb->ip_summed = CHECKSUM_UNNECESSARY; + else + skb->ip_summed = CHECKSUM_NONE; + } netif_rx(skb); dev->stats.rx_packets++; @@ -922,7 +988,7 @@ dm9000_rx(struct net_device *dev) (db->dumpblk)(db->io_data, RxLen); } - } while (rxbyte == DM9000_PKT_RDY); + } while (rxbyte & DM9000_PKT_RDY); } static irqreturn_t dm9000_interrupt(int irq, void *dev_id) @@ -1349,6 +1415,13 @@ dm9000_probe(struct platform_device *pdev) db->type = TYPE_DM9000E; } + /* dm9000a/b are capable of hardware checksum offload */ + if (db->type == TYPE_DM9000A || db->type == TYPE_DM9000B) { + db->can_csum = 1; + db->rx_csum = 1; + ndev->features |= NETIF_F_IP_CSUM; + } + /* from this point we assume that we have found a DM9000 */ /* driver system function */ diff --git a/drivers/net/dm9000.h b/drivers/net/dm9000.h index ba25cf54142..80817c2edfb 100644 --- a/drivers/net/dm9000.h +++ b/drivers/net/dm9000.h @@ -45,6 +45,10 @@ #define DM9000_CHIPR 0x2C #define DM9000_SMCR 0x2F +#define DM9000_ETXCSR 0x30 +#define DM9000_TCCR 0x31 +#define DM9000_RCSR 0x32 + #define CHIPR_DM9000A 0x19 #define CHIPR_DM9000B 0x1B @@ -131,7 +135,21 @@ #define GPCR_GEP_CNTL (1<<0) +#define TCCR_IP (1<<0) +#define TCCR_TCP (1<<1) +#define TCCR_UDP (1<<2) + +#define RCSR_UDP_BAD (1<<7) +#define RCSR_TCP_BAD (1<<6) +#define RCSR_IP_BAD (1<<5) +#define RCSR_UDP (1<<4) +#define RCSR_TCP (1<<3) +#define RCSR_IP (1<<2) +#define RCSR_CSUM (1<<1) +#define RCSR_DISCARD (1<<0) + #define DM9000_PKT_RDY 0x01 /* Packet ready to receive */ +#define DM9000_PKT_ERR 0x02 #define DM9000_PKT_MAX 1536 /* Received packet max size */ /* DM9000A / DM9000B definitions */ diff --git a/drivers/net/dnet.c b/drivers/net/dnet.c index 33fa9eee4ca..2818d5de394 100644 --- a/drivers/net/dnet.c +++ b/drivers/net/dnet.c @@ -596,7 +596,7 @@ static int dnet_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } static void dnet_reset_hw(struct dnet *bp) diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c index 8ebd7d78940..713ce6c532c 100644 --- a/drivers/net/dummy.c +++ b/drivers/net/dummy.c @@ -85,7 +85,7 @@ static int dummy_xmit(struct sk_buff *skb, struct net_device *dev) dev->stats.tx_bytes += skb->len; dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } static int dummy_validate(struct nlattr *tb[], struct nlattr *data[]) diff --git a/drivers/net/e100.c b/drivers/net/e100.c index efa680f4b8d..a150d58ec60 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -1720,7 +1720,7 @@ static int e100_xmit_frame(struct sk_buff *skb, struct net_device *netdev) } netdev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } static int e100_tx_clean(struct nic *nic) diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h index e9a416f4016..1a4f89c66a2 100644 --- a/drivers/net/e1000/e1000.h +++ b/drivers/net/e1000/e1000.h @@ -111,6 +111,9 @@ do { \ #define E1000_MIN_RXD 80 #define E1000_MAX_82544_RXD 4096 +#define E1000_MIN_ITR_USECS 10 /* 100000 irq/sec */ +#define E1000_MAX_ITR_USECS 10000 /* 100 irq/sec */ + /* this is the size past which hardware will drop packets when setting LPE=0 */ #define MAXIMUM_ETHERNET_VLAN_SIZE 1522 @@ -137,7 +140,7 @@ do { \ #define E1000_FC_HIGH_DIFF 0x1638 /* High: 5688 bytes below Rx FIFO size */ #define E1000_FC_LOW_DIFF 0x1640 /* Low: 5696 bytes below Rx FIFO size */ -#define E1000_FC_PAUSE_TIME 0x0680 /* 858 usec */ +#define E1000_FC_PAUSE_TIME 0xFFFF /* pause for the max or until send xon */ /* How many Tx Descriptors do we need to call netif_wake_queue ? */ #define E1000_TX_QUEUE_WAKE 16 @@ -161,6 +164,7 @@ do { \ struct e1000_buffer { struct sk_buff *skb; dma_addr_t dma; + struct page *page; unsigned long time_stamp; u16 length; u16 next_to_watch; @@ -202,6 +206,7 @@ struct e1000_rx_ring { unsigned int next_to_clean; /* array of buffer information structs */ struct e1000_buffer *buffer_info; + struct sk_buff *rx_skb_top; /* cpu for rx queue */ int cpu; diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index c854c96f5ab..27f996a2010 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -1904,6 +1904,53 @@ static int e1000_phys_id(struct net_device *netdev, u32 data) return 0; } +static int e1000_get_coalesce(struct net_device *netdev, + struct ethtool_coalesce *ec) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + + if (adapter->hw.mac_type < e1000_82545) + return -EOPNOTSUPP; + + if (adapter->itr_setting <= 3) + ec->rx_coalesce_usecs = adapter->itr_setting; + else + ec->rx_coalesce_usecs = 1000000 / adapter->itr_setting; + + return 0; +} + +static int e1000_set_coalesce(struct net_device *netdev, + struct ethtool_coalesce *ec) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + + if (hw->mac_type < e1000_82545) + return -EOPNOTSUPP; + + if ((ec->rx_coalesce_usecs > E1000_MAX_ITR_USECS) || + ((ec->rx_coalesce_usecs > 3) && + (ec->rx_coalesce_usecs < E1000_MIN_ITR_USECS)) || + (ec->rx_coalesce_usecs == 2)) + return -EINVAL; + + if (ec->rx_coalesce_usecs <= 3) { + adapter->itr = 20000; + adapter->itr_setting = ec->rx_coalesce_usecs; + } else { + adapter->itr = (1000000 / ec->rx_coalesce_usecs); + adapter->itr_setting = adapter->itr & ~3; + } + + if (adapter->itr_setting != 0) + ew32(ITR, 1000000000 / (adapter->itr * 256)); + else + ew32(ITR, 0); + + return 0; +} + static int e1000_nway_reset(struct net_device *netdev) { struct e1000_adapter *adapter = netdev_priv(netdev); @@ -1978,7 +2025,9 @@ static const struct ethtool_ops e1000_ethtool_ops = { .get_strings = e1000_get_strings, .phys_id = e1000_phys_id, .get_ethtool_stats = e1000_get_ethtool_stats, - .get_sset_count = e1000_get_sset_count, + .get_sset_count = e1000_get_sset_count, + .get_coalesce = e1000_get_coalesce, + .set_coalesce = e1000_set_coalesce, }; void e1000_set_ethtool_ops(struct net_device *netdev) diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c index e1a3fc1303e..1e5ae112d57 100644 --- a/drivers/net/e1000/e1000_hw.c +++ b/drivers/net/e1000/e1000_hw.c @@ -1955,7 +1955,7 @@ static s32 e1000_setup_copper_link(struct e1000_hw *hw) s32 ret_val; u16 i; u16 phy_data; - u16 reg_data; + u16 reg_data = 0; DEBUGFUNC("e1000_setup_copper_link"); diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h index 99fce2c5dd2..a8866bdbb67 100644 --- a/drivers/net/e1000/e1000_hw.h +++ b/drivers/net/e1000/e1000_hw.h @@ -523,11 +523,8 @@ s32 e1000_check_phy_reset_block(struct e1000_hw *hw); /* The sizes (in bytes) of a ethernet packet */ #define ENET_HEADER_SIZE 14 -#define MAXIMUM_ETHERNET_FRAME_SIZE 1518 /* With FCS */ #define MINIMUM_ETHERNET_FRAME_SIZE 64 /* With FCS */ #define ETHERNET_FCS_SIZE 4 -#define MAXIMUM_ETHERNET_PACKET_SIZE \ - (MAXIMUM_ETHERNET_FRAME_SIZE - ETHERNET_FCS_SIZE) #define MINIMUM_ETHERNET_PACKET_SIZE \ (MINIMUM_ETHERNET_FRAME_SIZE - ETHERNET_FCS_SIZE) #define CRC_LENGTH ETHERNET_FCS_SIZE diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 5b8cbdb4b52..d7df00c2dbd 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -137,9 +137,15 @@ static int e1000_clean(struct napi_struct *napi, int budget); static bool e1000_clean_rx_irq(struct e1000_adapter *adapter, struct e1000_rx_ring *rx_ring, int *work_done, int work_to_do); +static bool e1000_clean_jumbo_rx_irq(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring, + int *work_done, int work_to_do); static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter, - struct e1000_rx_ring *rx_ring, + struct e1000_rx_ring *rx_ring, int cleaned_count); +static void e1000_alloc_jumbo_rx_buffers(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring, + int cleaned_count); static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd); static int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd); @@ -635,8 +641,8 @@ void e1000_reset(struct e1000_adapter *adapter) { struct e1000_hw *hw = &adapter->hw; u32 pba = 0, tx_space, min_tx_space, min_rx_space; - u16 fc_high_water_mark = E1000_FC_HIGH_DIFF; bool legacy_pba_adjust = false; + u16 hwm; /* Repartition Pba for greater than 9k mtu * To take effect CTRL.RST is required. @@ -680,7 +686,7 @@ void e1000_reset(struct e1000_adapter *adapter) } if (legacy_pba_adjust) { - if (adapter->netdev->mtu > E1000_RXBUFFER_8192) + if (hw->max_frame_size > E1000_RXBUFFER_8192) pba -= 8; /* allocate more FIFO for Tx */ if (hw->mac_type == e1000_82547) { @@ -690,14 +696,14 @@ void e1000_reset(struct e1000_adapter *adapter) (E1000_PBA_40K - pba) << E1000_PBA_BYTES_SHIFT; atomic_set(&adapter->tx_fifo_stall, 0); } - } else if (hw->max_frame_size > MAXIMUM_ETHERNET_FRAME_SIZE) { + } else if (hw->max_frame_size > ETH_FRAME_LEN + ETH_FCS_LEN) { /* adjust PBA for jumbo frames */ ew32(PBA, pba); /* To maintain wire speed transmits, the Tx FIFO should be - * large enough to accomodate two full transmit packets, + * large enough to accommodate two full transmit packets, * rounded up to the next 1KB and expressed in KB. Likewise, - * the Rx FIFO should be large enough to accomodate at least + * the Rx FIFO should be large enough to accommodate at least * one full receive packet and is similarly rounded up and * expressed in KB. */ pba = er32(PBA); @@ -705,13 +711,17 @@ void e1000_reset(struct e1000_adapter *adapter) tx_space = pba >> 16; /* lower 16 bits has Rx packet buffer allocation size in KB */ pba &= 0xffff; - /* don't include ethernet FCS because hardware appends/strips */ - min_rx_space = adapter->netdev->mtu + ENET_HEADER_SIZE + - VLAN_TAG_SIZE; - min_tx_space = min_rx_space; - min_tx_space *= 2; + /* + * the tx fifo also stores 16 bytes of information about the tx + * but don't include ethernet FCS because hardware appends it + */ + min_tx_space = (hw->max_frame_size + + sizeof(struct e1000_tx_desc) - + ETH_FCS_LEN) * 2; min_tx_space = ALIGN(min_tx_space, 1024); min_tx_space >>= 10; + /* software strips receive CRC, so leave room for it */ + min_rx_space = hw->max_frame_size; min_rx_space = ALIGN(min_rx_space, 1024); min_rx_space >>= 10; @@ -748,23 +758,22 @@ void e1000_reset(struct e1000_adapter *adapter) ew32(PBA, pba); - /* flow control settings */ - /* Set the FC high water mark to 90% of the FIFO size. - * Required to clear last 3 LSB */ - fc_high_water_mark = ((pba * 9216)/10) & 0xFFF8; - /* We can't use 90% on small FIFOs because the remainder - * would be less than 1 full frame. In this case, we size - * it to allow at least a full frame above the high water - * mark. */ - if (pba < E1000_PBA_16K) - fc_high_water_mark = (pba * 1024) - 1600; - - hw->fc_high_water = fc_high_water_mark; - hw->fc_low_water = fc_high_water_mark - 8; - if (hw->mac_type == e1000_80003es2lan) - hw->fc_pause_time = 0xFFFF; - else - hw->fc_pause_time = E1000_FC_PAUSE_TIME; + /* + * flow control settings: + * The high water mark must be low enough to fit one full frame + * (or the size used for early receive) above it in the Rx FIFO. + * Set it to the lower of: + * - 90% of the Rx FIFO size, and + * - the full Rx FIFO size minus the early receive size (for parts + * with ERT support assuming ERT set to E1000_ERT_2048), or + * - the full Rx FIFO size minus one full frame + */ + hwm = min(((pba << 10) * 9 / 10), + ((pba << 10) - hw->max_frame_size)); + + hw->fc_high_water = hwm & 0xFFF8; /* 8-byte granularity */ + hw->fc_low_water = hw->fc_high_water - 8; + hw->fc_pause_time = E1000_FC_PAUSE_TIME; hw->fc_send_xon = 1; hw->fc = hw->original_fc; @@ -1862,6 +1871,7 @@ setup_rx_desc_die: rxdr->next_to_clean = 0; rxdr->next_to_use = 0; + rxdr->rx_skb_top = NULL; return 0; } @@ -1968,10 +1978,17 @@ static void e1000_configure_rx(struct e1000_adapter *adapter) struct e1000_hw *hw = &adapter->hw; u32 rdlen, rctl, rxcsum, ctrl_ext; - rdlen = adapter->rx_ring[0].count * - sizeof(struct e1000_rx_desc); - adapter->clean_rx = e1000_clean_rx_irq; - adapter->alloc_rx_buf = e1000_alloc_rx_buffers; + if (adapter->netdev->mtu > ETH_DATA_LEN) { + rdlen = adapter->rx_ring[0].count * + sizeof(struct e1000_rx_desc); + adapter->clean_rx = e1000_clean_jumbo_rx_irq; + adapter->alloc_rx_buf = e1000_alloc_jumbo_rx_buffers; + } else { + rdlen = adapter->rx_ring[0].count * + sizeof(struct e1000_rx_desc); + adapter->clean_rx = e1000_clean_rx_irq; + adapter->alloc_rx_buf = e1000_alloc_rx_buffers; + } /* disable receives while setting up the descriptors */ rctl = er32(RCTL); @@ -2185,26 +2202,39 @@ static void e1000_clean_rx_ring(struct e1000_adapter *adapter, /* Free all the Rx ring sk_buffs */ for (i = 0; i < rx_ring->count; i++) { buffer_info = &rx_ring->buffer_info[i]; - if (buffer_info->dma) { - pci_unmap_single(pdev, - buffer_info->dma, - buffer_info->length, - PCI_DMA_FROMDEVICE); + if (buffer_info->dma && + adapter->clean_rx == e1000_clean_rx_irq) { + pci_unmap_single(pdev, buffer_info->dma, + buffer_info->length, + PCI_DMA_FROMDEVICE); + } else if (buffer_info->dma && + adapter->clean_rx == e1000_clean_jumbo_rx_irq) { + pci_unmap_page(pdev, buffer_info->dma, + buffer_info->length, + PCI_DMA_FROMDEVICE); } buffer_info->dma = 0; - + if (buffer_info->page) { + put_page(buffer_info->page); + buffer_info->page = NULL; + } if (buffer_info->skb) { dev_kfree_skb(buffer_info->skb); buffer_info->skb = NULL; } } + /* there also may be some cached data from a chained receive */ + if (rx_ring->rx_skb_top) { + dev_kfree_skb(rx_ring->rx_skb_top); + rx_ring->rx_skb_top = NULL; + } + size = sizeof(struct e1000_buffer) * rx_ring->count; memset(rx_ring->buffer_info, 0, size); /* Zero out the descriptor ring */ - memset(rx_ring->desc, 0, rx_ring->size); rx_ring->next_to_clean = 0; @@ -3450,7 +3480,7 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu) switch (hw->mac_type) { case e1000_undefined ... e1000_82542_rev2_1: case e1000_ich8lan: - if (max_frame > MAXIMUM_ETHERNET_FRAME_SIZE) { + if (max_frame > (ETH_FRAME_LEN + ETH_FCS_LEN)) { DPRINTK(PROBE, ERR, "Jumbo Frames not supported.\n"); return -EINVAL; } @@ -3463,7 +3493,7 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu) &eeprom_data); if ((hw->device_id != E1000_DEV_ID_82573L) || (eeprom_data & EEPROM_WORD1A_ASPM_MASK)) { - if (max_frame > MAXIMUM_ETHERNET_FRAME_SIZE) { + if (max_frame > (ETH_FRAME_LEN + ETH_FCS_LEN)) { DPRINTK(PROBE, ERR, "Jumbo Frames not supported.\n"); return -EINVAL; @@ -3489,8 +3519,10 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu) /* NOTE: netdev_alloc_skb reserves 16 bytes, and typically NET_IP_ALIGN * means we reserve 2 more, this pushes us to allocate from the next - * larger slab size - * i.e. RXBUFFER_2048 --> size-4096 slab */ + * larger slab size. + * i.e. RXBUFFER_2048 --> size-4096 slab + * however with the new *_jumbo_rx* routines, jumbo receives will use + * fragmented skbs */ if (max_frame <= E1000_RXBUFFER_256) adapter->rx_buffer_len = E1000_RXBUFFER_256; @@ -3500,16 +3532,16 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu) adapter->rx_buffer_len = E1000_RXBUFFER_1024; else if (max_frame <= E1000_RXBUFFER_2048) adapter->rx_buffer_len = E1000_RXBUFFER_2048; - else if (max_frame <= E1000_RXBUFFER_4096) - adapter->rx_buffer_len = E1000_RXBUFFER_4096; - else if (max_frame <= E1000_RXBUFFER_8192) - adapter->rx_buffer_len = E1000_RXBUFFER_8192; - else if (max_frame <= E1000_RXBUFFER_16384) + else +#if (PAGE_SIZE >= E1000_RXBUFFER_16384) adapter->rx_buffer_len = E1000_RXBUFFER_16384; +#elif (PAGE_SIZE >= E1000_RXBUFFER_4096) + adapter->rx_buffer_len = PAGE_SIZE; +#endif /* adjust allocation if LPE protects us, and we aren't using SBP */ if (!hw->tbi_compatibility_on && - ((max_frame == MAXIMUM_ETHERNET_FRAME_SIZE) || + ((max_frame == (ETH_FRAME_LEN + ETH_FCS_LEN)) || (max_frame == MAXIMUM_ETHERNET_VLAN_SIZE))) adapter->rx_buffer_len = MAXIMUM_ETHERNET_VLAN_SIZE; @@ -3987,9 +4019,227 @@ static void e1000_rx_checksum(struct e1000_adapter *adapter, u32 status_err, } /** + * e1000_consume_page - helper function + **/ +static void e1000_consume_page(struct e1000_buffer *bi, struct sk_buff *skb, + u16 length) +{ + bi->page = NULL; + skb->len += length; + skb->data_len += length; + skb->truesize += length; +} + +/** + * e1000_receive_skb - helper function to handle rx indications + * @adapter: board private structure + * @status: descriptor status field as written by hardware + * @vlan: descriptor vlan field as written by hardware (no le/be conversion) + * @skb: pointer to sk_buff to be indicated to stack + */ +static void e1000_receive_skb(struct e1000_adapter *adapter, u8 status, + __le16 vlan, struct sk_buff *skb) +{ + if (unlikely(adapter->vlgrp && (status & E1000_RXD_STAT_VP))) { + vlan_hwaccel_receive_skb(skb, adapter->vlgrp, + le16_to_cpu(vlan) & + E1000_RXD_SPC_VLAN_MASK); + } else { + netif_receive_skb(skb); + } +} + +/** + * e1000_clean_jumbo_rx_irq - Send received data up the network stack; legacy + * @adapter: board private structure + * @rx_ring: ring to clean + * @work_done: amount of napi work completed this call + * @work_to_do: max amount of work allowed for this call to do + * + * the return value indicates whether actual cleaning was done, there + * is no guarantee that everything was cleaned + */ +static bool e1000_clean_jumbo_rx_irq(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring, + int *work_done, int work_to_do) +{ + struct e1000_hw *hw = &adapter->hw; + struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; + struct e1000_rx_desc *rx_desc, *next_rxd; + struct e1000_buffer *buffer_info, *next_buffer; + unsigned long irq_flags; + u32 length; + unsigned int i; + int cleaned_count = 0; + bool cleaned = false; + unsigned int total_rx_bytes=0, total_rx_packets=0; + + i = rx_ring->next_to_clean; + rx_desc = E1000_RX_DESC(*rx_ring, i); + buffer_info = &rx_ring->buffer_info[i]; + + while (rx_desc->status & E1000_RXD_STAT_DD) { + struct sk_buff *skb; + u8 status; + + if (*work_done >= work_to_do) + break; + (*work_done)++; + + status = rx_desc->status; + skb = buffer_info->skb; + buffer_info->skb = NULL; + + if (++i == rx_ring->count) i = 0; + next_rxd = E1000_RX_DESC(*rx_ring, i); + prefetch(next_rxd); + + next_buffer = &rx_ring->buffer_info[i]; + + cleaned = true; + cleaned_count++; + pci_unmap_page(pdev, buffer_info->dma, buffer_info->length, + PCI_DMA_FROMDEVICE); + buffer_info->dma = 0; + + length = le16_to_cpu(rx_desc->length); + + /* errors is only valid for DD + EOP descriptors */ + if (unlikely((status & E1000_RXD_STAT_EOP) && + (rx_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK))) { + u8 last_byte = *(skb->data + length - 1); + if (TBI_ACCEPT(hw, status, rx_desc->errors, length, + last_byte)) { + spin_lock_irqsave(&adapter->stats_lock, + irq_flags); + e1000_tbi_adjust_stats(hw, &adapter->stats, + length, skb->data); + spin_unlock_irqrestore(&adapter->stats_lock, + irq_flags); + length--; + } else { + /* recycle both page and skb */ + buffer_info->skb = skb; + /* an error means any chain goes out the window + * too */ + if (rx_ring->rx_skb_top) + dev_kfree_skb(rx_ring->rx_skb_top); + rx_ring->rx_skb_top = NULL; + goto next_desc; + } + } + +#define rxtop rx_ring->rx_skb_top + if (!(status & E1000_RXD_STAT_EOP)) { + /* this descriptor is only the beginning (or middle) */ + if (!rxtop) { + /* this is the beginning of a chain */ + rxtop = skb; + skb_fill_page_desc(rxtop, 0, buffer_info->page, + 0, length); + } else { + /* this is the middle of a chain */ + skb_fill_page_desc(rxtop, + skb_shinfo(rxtop)->nr_frags, + buffer_info->page, 0, length); + /* re-use the skb, only consumed the page */ + buffer_info->skb = skb; + } + e1000_consume_page(buffer_info, rxtop, length); + goto next_desc; + } else { + if (rxtop) { + /* end of the chain */ + skb_fill_page_desc(rxtop, + skb_shinfo(rxtop)->nr_frags, + buffer_info->page, 0, length); + /* re-use the current skb, we only consumed the + * page */ + buffer_info->skb = skb; + skb = rxtop; + rxtop = NULL; + e1000_consume_page(buffer_info, skb, length); + } else { + /* no chain, got EOP, this buf is the packet + * copybreak to save the put_page/alloc_page */ + if (length <= copybreak && + skb_tailroom(skb) >= length) { + u8 *vaddr; + vaddr = kmap_atomic(buffer_info->page, + KM_SKB_DATA_SOFTIRQ); + memcpy(skb_tail_pointer(skb), vaddr, length); + kunmap_atomic(vaddr, + KM_SKB_DATA_SOFTIRQ); + /* re-use the page, so don't erase + * buffer_info->page */ + skb_put(skb, length); + } else { + skb_fill_page_desc(skb, 0, + buffer_info->page, 0, + length); + e1000_consume_page(buffer_info, skb, + length); + } + } + } + + /* Receive Checksum Offload XXX recompute due to CRC strip? */ + e1000_rx_checksum(adapter, + (u32)(status) | + ((u32)(rx_desc->errors) << 24), + le16_to_cpu(rx_desc->csum), skb); + + pskb_trim(skb, skb->len - 4); + + /* probably a little skewed due to removing CRC */ + total_rx_bytes += skb->len; + total_rx_packets++; + + /* eth type trans needs skb->data to point to something */ + if (!pskb_may_pull(skb, ETH_HLEN)) { + DPRINTK(DRV, ERR, "pskb_may_pull failed.\n"); + dev_kfree_skb(skb); + goto next_desc; + } + + skb->protocol = eth_type_trans(skb, netdev); + + e1000_receive_skb(adapter, status, rx_desc->special, skb); + +next_desc: + rx_desc->status = 0; + + /* return some buffers to hardware, one at a time is too slow */ + if (unlikely(cleaned_count >= E1000_RX_BUFFER_WRITE)) { + adapter->alloc_rx_buf(adapter, rx_ring, cleaned_count); + cleaned_count = 0; + } + + /* use prefetched values */ + rx_desc = next_rxd; + buffer_info = next_buffer; + } + rx_ring->next_to_clean = i; + + cleaned_count = E1000_DESC_UNUSED(rx_ring); + if (cleaned_count) + adapter->alloc_rx_buf(adapter, rx_ring, cleaned_count); + + adapter->total_rx_packets += total_rx_packets; + adapter->total_rx_bytes += total_rx_bytes; + adapter->net_stats.rx_bytes += total_rx_bytes; + adapter->net_stats.rx_packets += total_rx_packets; + return cleaned; +} + +/** * e1000_clean_rx_irq - Send received data up the network stack; legacy * @adapter: board private structure - **/ + * @rx_ring: ring to clean + * @work_done: amount of napi work completed this call + * @work_to_do: max amount of work allowed for this call to do + */ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter, struct e1000_rx_ring *rx_ring, int *work_done, int work_to_do) @@ -4001,7 +4251,6 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter, struct e1000_buffer *buffer_info, *next_buffer; unsigned long flags; u32 length; - u8 last_byte; unsigned int i; int cleaned_count = 0; bool cleaned = false; @@ -4033,9 +4282,7 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter, cleaned = true; cleaned_count++; - pci_unmap_single(pdev, - buffer_info->dma, - buffer_info->length, + pci_unmap_single(pdev, buffer_info->dma, buffer_info->length, PCI_DMA_FROMDEVICE); buffer_info->dma = 0; @@ -4052,7 +4299,7 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter, } if (unlikely(rx_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK)) { - last_byte = *(skb->data + length - 1); + u8 last_byte = *(skb->data + length - 1); if (TBI_ACCEPT(hw, status, rx_desc->errors, length, last_byte)) { spin_lock_irqsave(&adapter->stats_lock, flags); @@ -4107,13 +4354,7 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter, skb->protocol = eth_type_trans(skb, netdev); - if (unlikely(adapter->vlgrp && - (status & E1000_RXD_STAT_VP))) { - vlan_hwaccel_receive_skb(skb, adapter->vlgrp, - le16_to_cpu(rx_desc->special)); - } else { - netif_receive_skb(skb); - } + e1000_receive_skb(adapter, status, rx_desc->special, skb); next_desc: rx_desc->status = 0; @@ -4142,6 +4383,114 @@ next_desc: } /** + * e1000_alloc_jumbo_rx_buffers - Replace used jumbo receive buffers + * @adapter: address of board private structure + * @rx_ring: pointer to receive ring structure + * @cleaned_count: number of buffers to allocate this pass + **/ + +static void +e1000_alloc_jumbo_rx_buffers(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring, int cleaned_count) +{ + struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; + struct e1000_rx_desc *rx_desc; + struct e1000_buffer *buffer_info; + struct sk_buff *skb; + unsigned int i; + unsigned int bufsz = 256 - + 16 /*for skb_reserve */ - + NET_IP_ALIGN; + + i = rx_ring->next_to_use; + buffer_info = &rx_ring->buffer_info[i]; + + while (cleaned_count--) { + skb = buffer_info->skb; + if (skb) { + skb_trim(skb, 0); + goto check_page; + } + + skb = netdev_alloc_skb(netdev, bufsz); + if (unlikely(!skb)) { + /* Better luck next round */ + adapter->alloc_rx_buff_failed++; + break; + } + + /* Fix for errata 23, can't cross 64kB boundary */ + if (!e1000_check_64k_bound(adapter, skb->data, bufsz)) { + struct sk_buff *oldskb = skb; + DPRINTK(PROBE, ERR, "skb align check failed: %u bytes " + "at %p\n", bufsz, skb->data); + /* Try again, without freeing the previous */ + skb = netdev_alloc_skb(netdev, bufsz); + /* Failed allocation, critical failure */ + if (!skb) { + dev_kfree_skb(oldskb); + adapter->alloc_rx_buff_failed++; + break; + } + + if (!e1000_check_64k_bound(adapter, skb->data, bufsz)) { + /* give up */ + dev_kfree_skb(skb); + dev_kfree_skb(oldskb); + break; /* while (cleaned_count--) */ + } + + /* Use new allocation */ + dev_kfree_skb(oldskb); + } + /* Make buffer alignment 2 beyond a 16 byte boundary + * this will result in a 16 byte aligned IP header after + * the 14 byte MAC header is removed + */ + skb_reserve(skb, NET_IP_ALIGN); + + buffer_info->skb = skb; + buffer_info->length = adapter->rx_buffer_len; +check_page: + /* allocate a new page if necessary */ + if (!buffer_info->page) { + buffer_info->page = alloc_page(GFP_ATOMIC); + if (unlikely(!buffer_info->page)) { + adapter->alloc_rx_buff_failed++; + break; + } + } + + if (!buffer_info->dma) + buffer_info->dma = pci_map_page(pdev, + buffer_info->page, 0, + buffer_info->length, + PCI_DMA_FROMDEVICE); + + rx_desc = E1000_RX_DESC(*rx_ring, i); + rx_desc->buffer_addr = cpu_to_le64(buffer_info->dma); + + if (unlikely(++i == rx_ring->count)) + i = 0; + buffer_info = &rx_ring->buffer_info[i]; + } + + if (likely(rx_ring->next_to_use != i)) { + rx_ring->next_to_use = i; + if (unlikely(i-- == 0)) + i = (rx_ring->count - 1); + + /* Force memory writes to complete before letting h/w + * know there are new descriptors to fetch. (Only + * applicable for weak-ordered memory model archs, + * such as IA-64). */ + wmb(); + writel(i, adapter->hw.hw_addr + rx_ring->rdt); + } +} + +/** * e1000_alloc_rx_buffers - Replace used receive buffers; legacy & extended * @adapter: address of board private structure **/ @@ -4186,6 +4535,7 @@ static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter, /* Failed allocation, critical failure */ if (!skb) { dev_kfree_skb(oldskb); + adapter->alloc_rx_buff_failed++; break; } @@ -4193,6 +4543,7 @@ static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter, /* give up */ dev_kfree_skb(skb); dev_kfree_skb(oldskb); + adapter->alloc_rx_buff_failed++; break; /* while !buffer_info->skb */ } @@ -4210,9 +4561,14 @@ static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter, map_skb: buffer_info->dma = pci_map_single(pdev, skb->data, - adapter->rx_buffer_len, + buffer_info->length, PCI_DMA_FROMDEVICE); + /* + * XXX if it was allocated cleanly it will never map to a + * boundary crossing + */ + /* Fix for errata 23, can't cross 64kB boundary */ if (!e1000_check_64k_bound(adapter, (void *)(unsigned long)buffer_info->dma, @@ -4229,6 +4585,7 @@ map_skb: PCI_DMA_FROMDEVICE); buffer_info->dma = 0; + adapter->alloc_rx_buff_failed++; break; /* while !buffer_info->skb */ } rx_desc = E1000_RX_DESC(*rx_ring, i); diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c index cc2ab6412c7..71605d63708 100644 --- a/drivers/net/eepro.c +++ b/drivers/net/eepro.c @@ -1145,7 +1145,7 @@ static int eepro_send_packet(struct sk_buff *skb, struct net_device *dev) if (length < ETH_ZLEN) { if (skb_padto(skb, ETH_ZLEN)) - return 0; + return NETDEV_TX_OK; length = ETH_ZLEN; } netif_stop_queue (dev); @@ -1178,7 +1178,7 @@ static int eepro_send_packet(struct sk_buff *skb, struct net_device *dev) eepro_en_int(ioaddr); spin_unlock_irqrestore(&lp->lock, flags); - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c index 1686dca2874..8c44ef4ba35 100644 --- a/drivers/net/eexpress.c +++ b/drivers/net/eexpress.c @@ -664,7 +664,7 @@ static int eexp_xmit(struct sk_buff *buf, struct net_device *dev) if (buf->len < ETH_ZLEN) { if (skb_padto(buf, ETH_ZLEN)) - return 0; + return NETDEV_TX_OK; length = ETH_ZLEN; } @@ -691,7 +691,7 @@ static int eexp_xmit(struct sk_buff *buf, struct net_device *dev) spin_unlock_irqrestore(&lp->lock, flags); #endif enable_irq(dev->irq); - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/enc28j60.c b/drivers/net/enc28j60.c index fc6cc038c7b..372d6c6a4e7 100644 --- a/drivers/net/enc28j60.c +++ b/drivers/net/enc28j60.c @@ -1299,7 +1299,7 @@ static int enc28j60_send_packet(struct sk_buff *skb, struct net_device *dev) priv->tx_skb = skb; schedule_work(&priv->tx_work); - return 0; + return NETDEV_TX_OK; } static void enc28j60_tx_work_handler(struct work_struct *work) diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c index b60e27dfcfa..d6a7aa3142f 100644 --- a/drivers/net/epic100.c +++ b/drivers/net/epic100.c @@ -970,7 +970,7 @@ static int epic_start_xmit(struct sk_buff *skb, struct net_device *dev) unsigned long flags; if (skb_padto(skb, ETH_ZLEN)) - return 0; + return NETDEV_TX_OK; /* Caution: the write order is important here, set the field with the "ownership" bit last. */ @@ -1014,7 +1014,7 @@ static int epic_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->name, (int)skb->len, entry, ctrl_word, (int)inl(dev->base_addr + TxSTAT)); - return 0; + return NETDEV_TX_OK; } static void epic_tx_error(struct net_device *dev, struct epic_private *ep, diff --git a/drivers/net/eql.c b/drivers/net/eql.c index 19b7dd98394..c0e69c5cae8 100644 --- a/drivers/net/eql.c +++ b/drivers/net/eql.c @@ -348,7 +348,7 @@ static int eql_slave_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock(&eql->queue.lock); - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/eth16i.c b/drivers/net/eth16i.c index 0d8b6da046f..97d5205edc8 100644 --- a/drivers/net/eth16i.c +++ b/drivers/net/eth16i.c @@ -1064,7 +1064,7 @@ static int eth16i_tx(struct sk_buff *skb, struct net_device *dev) if (length < ETH_ZLEN) { if (skb_padto(skb, ETH_ZLEN)) - return 0; + return NETDEV_TX_OK; length = ETH_ZLEN; } buf = skb->data; @@ -1126,7 +1126,7 @@ static int eth16i_tx(struct sk_buff *skb, struct net_device *dev) /* outb(TX_INTR_DONE | TX_INTR_16_COL, ioaddr + TX_INTR_REG); */ status = 0; dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } static void eth16i_rx(struct net_device *dev) diff --git a/drivers/net/ewrk3.c b/drivers/net/ewrk3.c index 1e972328140..9c51bc813ad 100644 --- a/drivers/net/ewrk3.c +++ b/drivers/net/ewrk3.c @@ -868,7 +868,7 @@ static int ewrk3_queue_pkt (struct sk_buff *skb, struct net_device *dev) if (inb (EWRK3_FMQC) == 0) netif_stop_queue (dev); - return 0; + return NETDEV_TX_OK; err_out: ENABLE_IRQs; diff --git a/drivers/net/fealnx.c b/drivers/net/fealnx.c index 891be28a7d4..75e5fe5153d 100644 --- a/drivers/net/fealnx.c +++ b/drivers/net/fealnx.c @@ -1374,7 +1374,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; spin_unlock_irqrestore(&np->lock, flags); - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 0f19b743749..08f1edb83f2 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -366,7 +366,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&fep->hw_lock, flags); - return 0; + return NETDEV_TX_OK; } static void diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c index 9d5b62cb30f..4e8d3728e82 100644 --- a/drivers/net/hamachi.c +++ b/drivers/net/hamachi.c @@ -1369,7 +1369,7 @@ static int hamachi_start_xmit(struct sk_buff *skb, struct net_device *dev) printk(KERN_DEBUG "%s: Hamachi transmit frame #%d queued in slot %d.\n", dev->name, hmp->cur_tx, entry); } - return 0; + return NETDEV_TX_OK; } /* The interrupt handler does all of the Rx thread work and cleans up diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c index 155160052c8..e88209fc2a2 100644 --- a/drivers/net/hamradio/6pack.c +++ b/drivers/net/hamradio/6pack.c @@ -255,7 +255,7 @@ static int sp_xmit(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } static int sp_open_dev(struct net_device *dev) diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c index 5e4b7afd068..e229edf3261 100644 --- a/drivers/net/hamradio/baycom_epp.c +++ b/drivers/net/hamradio/baycom_epp.c @@ -774,18 +774,18 @@ static int baycom_send_packet(struct sk_buff *skb, struct net_device *dev) if (skb->data[0] != 0) { do_kiss_params(bc, skb->data, skb->len); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } if (bc->skb) return NETDEV_TX_LOCKED; /* strip KISS byte */ if (skb->len >= HDLCDRV_MAXFLEN+1 || skb->len < 3) { dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } netif_stop_queue(dev); bc->skb = skb; - return 0; + return NETDEV_TX_OK; } /* --------------------------------------------------------------------- */ diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c index abcd19a8bff..4c5f4dfbe05 100644 --- a/drivers/net/hamradio/bpqether.c +++ b/drivers/net/hamradio/bpqether.c @@ -305,7 +305,7 @@ static int bpq_xmit(struct sk_buff *skb, struct net_device *dev) dev_queue_xmit(skb); netif_wake_queue(dev); - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c index 7459b3ac77a..950f3bb21f9 100644 --- a/drivers/net/hamradio/dmascc.c +++ b/drivers/net/hamradio/dmascc.c @@ -959,7 +959,7 @@ static int scc_send_packet(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&priv->ring_lock, flags); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/hamradio/hdlcdrv.c b/drivers/net/hamradio/hdlcdrv.c index d034f8ca63c..16b060b9211 100644 --- a/drivers/net/hamradio/hdlcdrv.c +++ b/drivers/net/hamradio/hdlcdrv.c @@ -406,13 +406,13 @@ static int hdlcdrv_send_packet(struct sk_buff *skb, struct net_device *dev) if (skb->data[0] != 0) { do_kiss_params(sm, skb->data, skb->len); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } if (sm->skb) return NETDEV_TX_LOCKED; netif_stop_queue(dev); sm->skb = skb; - return 0; + return NETDEV_TX_OK; } /* --------------------------------------------------------------------- */ diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c index fda2fc83e9a..ac191ef2119 100644 --- a/drivers/net/hamradio/mkiss.c +++ b/drivers/net/hamradio/mkiss.c @@ -560,7 +560,7 @@ static int ax_xmit(struct sk_buff *skb, struct net_device *dev) kfree_skb(skb); } - return 0; + return NETDEV_TX_OK; } static int ax_open_dev(struct net_device *dev) diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c index d712e7af780..c5406525c1a 100644 --- a/drivers/net/hamradio/scc.c +++ b/drivers/net/hamradio/scc.c @@ -1643,7 +1643,7 @@ static int scc_net_tx(struct sk_buff *skb, struct net_device *dev) if (skb->len > scc->stat.bufsize || skb->len < 2) { scc->dev_stat.tx_dropped++; /* bogus frame */ dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } scc->dev_stat.tx_packets++; @@ -1656,7 +1656,7 @@ static int scc_net_tx(struct sk_buff *skb, struct net_device *dev) if (kisscmd) { scc_set_param(scc, kisscmd, *skb->data); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } spin_lock_irqsave(&scc->lock, flags); @@ -1684,7 +1684,7 @@ static int scc_net_tx(struct sk_buff *skb, struct net_device *dev) __scc_start_tx_timer(scc, t_dwait, 0); } spin_unlock_irqrestore(&scc->lock, flags); - return 0; + return NETDEV_TX_OK; } /* ----> ioctl functions <---- */ diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c index b06691937ce..b85aa162314 100644 --- a/drivers/net/hamradio/yam.c +++ b/drivers/net/hamradio/yam.c @@ -600,7 +600,7 @@ static int yam_send_packet(struct sk_buff *skb, struct net_device *dev) skb_queue_tail(&yp->send_queue, skb); dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } static void yam_start_tx(struct net_device *dev, struct yam_port *yp) diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c index 1d3429a415e..d1b63387e9b 100644 --- a/drivers/net/hp100.c +++ b/drivers/net/hp100.c @@ -1499,7 +1499,7 @@ static int hp100_start_xmit_bm(struct sk_buff *skb, struct net_device *dev) goto drop; if (lp->chip == HP100_CHIPID_SHASTA && skb_padto(skb, ETH_ZLEN)) - return 0; + return NETDEV_TX_OK; /* Get Tx ring tail pointer */ if (lp->txrtail->next == lp->txrhead) { @@ -1585,7 +1585,7 @@ static int hp100_start_xmit_bm(struct sk_buff *skb, struct net_device *dev) lp->stats.tx_bytes += skb->len; dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; drop: dev_kfree_skb(skb); @@ -1752,7 +1752,7 @@ static int hp100_start_xmit(struct sk_buff *skb, struct net_device *dev) printk("hp100: %s: start_xmit: end\n", dev->name); #endif - return 0; + return NETDEV_TX_OK; drop: dev_kfree_skb(skb); diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c index beb84213b67..5443558c439 100644 --- a/drivers/net/ibm_newemac/core.c +++ b/drivers/net/ibm_newemac/core.c @@ -1342,7 +1342,7 @@ static inline int emac_xmit_finish(struct emac_instance *dev, int len) ++dev->stats.tx_packets; dev->stats.tx_bytes += len; - return 0; + return NETDEV_TX_OK; } /* Tx lock BH */ diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 0995c438f28..76b295a1818 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -971,7 +971,7 @@ out: spin_lock_irqsave(&adapter->stats_lock, flags); spin_unlock_irqrestore(&adapter->stats_lock, flags); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } static int ibmveth_poll(struct napi_struct *napi, int budget) diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c index 96713ef0629..0a79b451780 100644 --- a/drivers/net/ifb.c +++ b/drivers/net/ifb.c @@ -164,7 +164,7 @@ static int ifb_xmit(struct sk_buff *skb, struct net_device *dev) { struct ifb_private *dp = netdev_priv(dev); struct net_device_stats *stats = &dev->stats; - int ret = 0; + int ret = NETDEV_TX_OK; u32 from = G_TC_FROM(skb->tc_verd); stats->rx_packets++; diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c index e3cfefab670..8ec15ab8c8c 100644 --- a/drivers/net/ioc3-eth.c +++ b/drivers/net/ioc3-eth.c @@ -1515,7 +1515,7 @@ static int ioc3_start_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock_irq(&ip->ioc3_lock); - return 0; + return NETDEV_TX_OK; } static void ioc3_timeout(struct net_device *dev) diff --git a/drivers/net/irda/ali-ircc.c b/drivers/net/irda/ali-ircc.c index ad179558002..f0d0cea6e32 100644 --- a/drivers/net/irda/ali-ircc.c +++ b/drivers/net/irda/ali-ircc.c @@ -1466,7 +1466,7 @@ static int ali_ircc_fir_hard_xmit(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; spin_unlock_irqrestore(&self->lock, flags); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } else self->new_speed = speed; } @@ -1577,7 +1577,7 @@ static int ali_ircc_fir_hard_xmit(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb(skb); IRDA_DEBUG(1, "%s(), ----------------- End ------------------\n", __func__ ); - return 0; + return NETDEV_TX_OK; } @@ -1966,10 +1966,10 @@ static int ali_ircc_sir_hard_xmit(struct sk_buff *skb, struct net_device *dev) IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __func__ ); - IRDA_ASSERT(dev != NULL, return 0;); + IRDA_ASSERT(dev != NULL, return NETDEV_TX_OK;); self = netdev_priv(dev); - IRDA_ASSERT(self != NULL, return 0;); + IRDA_ASSERT(self != NULL, return NETDEV_TX_OK;); iobase = self->io.sir_base; @@ -1991,7 +1991,7 @@ static int ali_ircc_sir_hard_xmit(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; spin_unlock_irqrestore(&self->lock, flags); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } else self->new_speed = speed; } @@ -2015,7 +2015,7 @@ static int ali_ircc_sir_hard_xmit(struct sk_buff *skb, struct net_device *dev) IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __func__ ); - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/irda/au1k_ir.c b/drivers/net/irda/au1k_ir.c index c4361d46659..22baf65e156 100644 --- a/drivers/net/irda/au1k_ir.c +++ b/drivers/net/irda/au1k_ir.c @@ -502,7 +502,7 @@ static int au1k_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev) aup->newspeed = 0; } dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } ptxd = aup->tx_ring[aup->tx_head]; @@ -555,7 +555,7 @@ static int au1k_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb(skb); aup->tx_head = (aup->tx_head + 1) & (NUM_IR_DESC - 1); dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/irda/donauboe.c b/drivers/net/irda/donauboe.c index 9a0346e751a..e4e905698dc 100644 --- a/drivers/net/irda/donauboe.c +++ b/drivers/net/irda/donauboe.c @@ -981,7 +981,7 @@ toshoboe_hard_xmit (struct sk_buff *skb, struct net_device *dev) self = netdev_priv(dev); - IRDA_ASSERT (self != NULL, return 0; ); + IRDA_ASSERT (self != NULL, return NETDEV_TX_OK; ); IRDA_DEBUG (1, "%s.tx:%x(%x)%x\n", __func__ ,skb->len,self->txpending,INB (OBOE_ENABLEH)); @@ -1021,7 +1021,7 @@ toshoboe_hard_xmit (struct sk_buff *skb, struct net_device *dev) { spin_unlock_irqrestore(&self->spinlock, flags); dev_kfree_skb (skb); - return 0; + return NETDEV_TX_OK; } /* True packet, go on, but */ /* do not accept anything before change speed execution */ @@ -1036,7 +1036,7 @@ toshoboe_hard_xmit (struct sk_buff *skb, struct net_device *dev) toshoboe_setbaud (self); spin_unlock_irqrestore(&self->spinlock, flags); dev_kfree_skb (skb); - return 0; + return NETDEV_TX_OK; } } @@ -1143,7 +1143,7 @@ dumpbufs(skb->data,skb->len,'>'); spin_unlock_irqrestore(&self->spinlock, flags); dev_kfree_skb (skb); - return 0; + return NETDEV_TX_OK; } /*interrupt handler */ diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c index 0c0831c03f6..6a1aa7a40fe 100644 --- a/drivers/net/irda/irda-usb.c +++ b/drivers/net/irda/irda-usb.c @@ -534,7 +534,7 @@ static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev) } spin_unlock_irqrestore(&self->lock, flags); - return 0; + return NETDEV_TX_OK; drop: /* Drop silently the skb and exit */ diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c index 45fd9c1eb34..51ca89c9a0b 100644 --- a/drivers/net/irda/nsc-ircc.c +++ b/drivers/net/irda/nsc-ircc.c @@ -1365,7 +1365,7 @@ static int nsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev) self = netdev_priv(dev); - IRDA_ASSERT(self != NULL, return 0;); + IRDA_ASSERT(self != NULL, return NETDEV_TX_OK;); iobase = self->io.fir_base; @@ -1397,7 +1397,7 @@ static int nsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; spin_unlock_irqrestore(&self->lock, flags); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } else self->new_speed = speed; } @@ -1424,7 +1424,7 @@ static int nsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } static int nsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev) @@ -1467,7 +1467,7 @@ static int nsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; spin_unlock_irqrestore(&self->lock, flags); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } else { /* Change speed after current frame */ self->new_speed = speed; @@ -1554,7 +1554,7 @@ static int nsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&self->lock, flags); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/irda/pxaficp_ir.c b/drivers/net/irda/pxaficp_ir.c index 3376a4f39e0..e76a083f901 100644 --- a/drivers/net/irda/pxaficp_ir.c +++ b/drivers/net/irda/pxaficp_ir.c @@ -504,7 +504,7 @@ static int pxa_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev) pxa_irda_set_speed(si, speed); } dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } netif_stop_queue(dev); @@ -539,7 +539,7 @@ static int pxa_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb(skb); dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } static int pxa_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd) diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c index 2aeb2e6aec1..70e6acc597b 100644 --- a/drivers/net/irda/sa1100_ir.c +++ b/drivers/net/irda/sa1100_ir.c @@ -667,7 +667,7 @@ static int sa1100_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev) sa1100_irda_set_speed(si, speed); } dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } if (!IS_FIR(si)) { @@ -715,7 +715,7 @@ static int sa1100_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } static int diff --git a/drivers/net/irda/sir_dev.c b/drivers/net/irda/sir_dev.c index fd0796c3db3..71dce20e62b 100644 --- a/drivers/net/irda/sir_dev.c +++ b/drivers/net/irda/sir_dev.c @@ -590,7 +590,7 @@ static int sirdev_hard_xmit(struct sk_buff *skb, struct net_device *ndev) int err; s32 speed; - IRDA_ASSERT(dev != NULL, return 0;); + IRDA_ASSERT(dev != NULL, return NETDEV_TX_OK;); netif_stop_queue(ndev); @@ -621,7 +621,7 @@ static int sirdev_hard_xmit(struct sk_buff *skb, struct net_device *ndev) */ dev_kfree_skb_any(skb); - return 0; + return NETDEV_TX_OK; } else dev->new_speed = speed; } @@ -668,7 +668,7 @@ static int sirdev_hard_xmit(struct sk_buff *skb, struct net_device *ndev) } spin_unlock_irqrestore(&dev->tx_lock, flags); - return 0; + return NETDEV_TX_OK; } /* called from network layer with rtnl hold */ diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c index d0797adb5f8..15f8a7f8160 100644 --- a/drivers/net/irda/smsc-ircc2.c +++ b/drivers/net/irda/smsc-ircc2.c @@ -886,10 +886,10 @@ static int smsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev) IRDA_DEBUG(1, "%s\n", __func__); - IRDA_ASSERT(dev != NULL, return 0;); + IRDA_ASSERT(dev != NULL, return NETDEV_TX_OK;); self = netdev_priv(dev); - IRDA_ASSERT(self != NULL, return 0;); + IRDA_ASSERT(self != NULL, return NETDEV_TX_OK;); netif_stop_queue(dev); @@ -914,7 +914,7 @@ static int smsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev) smsc_ircc_change_speed(self, speed); spin_unlock_irqrestore(&self->lock, flags); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } self->new_speed = speed; } @@ -935,7 +935,7 @@ static int smsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* @@ -1190,9 +1190,9 @@ static int smsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev) s32 speed; int mtt; - IRDA_ASSERT(dev != NULL, return 0;); + IRDA_ASSERT(dev != NULL, return NETDEV_TX_OK;); self = netdev_priv(dev); - IRDA_ASSERT(self != NULL, return 0;); + IRDA_ASSERT(self != NULL, return NETDEV_TX_OK;); netif_stop_queue(dev); @@ -1210,7 +1210,7 @@ static int smsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev) smsc_ircc_change_speed(self, speed); spin_unlock_irqrestore(&self->lock, flags); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } self->new_speed = speed; @@ -1242,7 +1242,7 @@ static int smsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&self->lock, flags); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c index 8e5e45caf2f..c475b23091b 100644 --- a/drivers/net/irda/stir4200.c +++ b/drivers/net/irda/stir4200.c @@ -578,7 +578,7 @@ static int stir_hard_xmit(struct sk_buff *skb, struct net_device *netdev) dev_kfree_skb(skb); } - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/irda/via-ircc.c b/drivers/net/irda/via-ircc.c index 864798502ff..36a60748447 100644 --- a/drivers/net/irda/via-ircc.c +++ b/drivers/net/irda/via-ircc.c @@ -832,7 +832,7 @@ static int via_ircc_hard_xmit_sir(struct sk_buff *skb, __u32 speed; self = netdev_priv(dev); - IRDA_ASSERT(self != NULL, return 0;); + IRDA_ASSERT(self != NULL, return NETDEV_TX_OK;); iobase = self->io.fir_base; netif_stop_queue(dev); @@ -844,7 +844,7 @@ static int via_ircc_hard_xmit_sir(struct sk_buff *skb, via_ircc_change_speed(self, speed); dev->trans_start = jiffies; dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } else self->new_speed = speed; } @@ -892,7 +892,7 @@ static int via_ircc_hard_xmit_sir(struct sk_buff *skb, dev->trans_start = jiffies; spin_unlock_irqrestore(&self->lock, flags); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } static int via_ircc_hard_xmit_fir(struct sk_buff *skb, @@ -907,7 +907,7 @@ static int via_ircc_hard_xmit_fir(struct sk_buff *skb, iobase = self->io.fir_base; if (self->st_fifo.len) - return 0; + return NETDEV_TX_OK; if (self->chip_id == 0x3076) iodelay(1500); else @@ -919,7 +919,7 @@ static int via_ircc_hard_xmit_fir(struct sk_buff *skb, via_ircc_change_speed(self, speed); dev->trans_start = jiffies; dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } else self->new_speed = speed; } @@ -940,7 +940,7 @@ static int via_ircc_hard_xmit_fir(struct sk_buff *skb, dev->trans_start = jiffies; dev_kfree_skb(skb); spin_unlock_irqrestore(&self->lock, flags); - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c index ac0e4b6b6b6..08e26f1297b 100644 --- a/drivers/net/irda/vlsi_ir.c +++ b/drivers/net/irda/vlsi_ir.c @@ -915,7 +915,7 @@ static int vlsi_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev) */ spin_unlock_irqrestore(&idev->lock, flags); dev_kfree_skb_any(skb); - return 0; + return NETDEV_TX_OK; } /* sanity checks - simply drop the packet */ @@ -1044,7 +1044,7 @@ static int vlsi_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev) } spin_unlock_irqrestore(&idev->lock, flags); - return 0; + return NETDEV_TX_OK; drop_unlock: spin_unlock_irqrestore(&idev->lock, flags); @@ -1058,7 +1058,7 @@ drop: * packet for later retry of transmission - which isn't exactly * what we want after we've just called dev_kfree_skb_any ;-) */ - return 0; + return NETDEV_TX_OK; } static void vlsi_tx_interrupt(struct net_device *ndev) diff --git a/drivers/net/irda/w83977af_ir.c b/drivers/net/irda/w83977af_ir.c index d0883835b0c..49ef76320f5 100644 --- a/drivers/net/irda/w83977af_ir.c +++ b/drivers/net/irda/w83977af_ir.c @@ -516,7 +516,7 @@ static int w83977af_hard_xmit(struct sk_buff *skb, struct net_device *dev) w83977af_change_speed(self, speed); dev->trans_start = jiffies; dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } else self->new_speed = speed; } @@ -576,7 +576,7 @@ static int w83977af_hard_xmit(struct sk_buff *skb, struct net_device *dev) /* Restore set register */ outb(set, iobase+SSR); - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/isa-skeleton.c b/drivers/net/isa-skeleton.c index 73585fd8f29..86d2300af37 100644 --- a/drivers/net/isa-skeleton.c +++ b/drivers/net/isa-skeleton.c @@ -467,7 +467,7 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb (skb); #endif - return 0; + return NETDEV_TX_OK; } #if TX_RING diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c index e44215cb188..e36e951cbc6 100644 --- a/drivers/net/iseries_veth.c +++ b/drivers/net/iseries_veth.c @@ -1205,7 +1205,7 @@ static int veth_start_xmit(struct sk_buff *skb, struct net_device *dev) if ( ! ((1 << rlp) & port->lpar_map) ) { dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } lpmask = 1 << rlp; @@ -1217,7 +1217,7 @@ static int veth_start_xmit(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* You must hold the connection's lock when you call this function. */ diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index 9c897cf86b9..eb917f16027 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -1459,7 +1459,7 @@ ixgb_xmit_frame(struct sk_buff *skb, struct net_device *netdev) if (skb->len <= 0) { dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } if (unlikely(ixgb_maybe_stop_tx(netdev, &adapter->tx_ring, diff --git a/drivers/net/ixp2000/ixpdev.c b/drivers/net/ixp2000/ixpdev.c index 2a0174b62e9..588b44d944c 100644 --- a/drivers/net/ixp2000/ixpdev.c +++ b/drivers/net/ixp2000/ixpdev.c @@ -45,7 +45,7 @@ static int ixpdev_xmit(struct sk_buff *skb, struct net_device *dev) if (unlikely(skb->len > PAGE_SIZE)) { /* @@@ Count drops. */ dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } entry = tx_pointer; @@ -69,7 +69,7 @@ static int ixpdev_xmit(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); local_irq_enable(); - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/jme.c b/drivers/net/jme.c index 1e3c63d67b9..e7068c7cd62 100644 --- a/drivers/net/jme.c +++ b/drivers/net/jme.c @@ -322,20 +322,6 @@ jme_stop_irq(struct jme_adapter *jme) jwrite32f(jme, JME_IENC, INTR_ENABLE); } -static inline void -jme_enable_shadow(struct jme_adapter *jme) -{ - jwrite32(jme, - JME_SHBA_LO, - ((u32)jme->shadow_dma & ~((u32)0x1F)) | SHBA_POSTEN); -} - -static inline void -jme_disable_shadow(struct jme_adapter *jme) -{ - jwrite32(jme, JME_SHBA_LO, 0x0); -} - static u32 jme_linkstat_from_phy(struct jme_adapter *jme) { @@ -522,12 +508,8 @@ jme_setup_tx_resources(struct jme_adapter *jme) &(txring->dmaalloc), GFP_ATOMIC); - if (!txring->alloc) { - txring->desc = NULL; - txring->dmaalloc = 0; - txring->dma = 0; - return -ENOMEM; - } + if (!txring->alloc) + goto err_set_null; /* * 16 Bytes align @@ -539,6 +521,11 @@ jme_setup_tx_resources(struct jme_adapter *jme) atomic_set(&txring->next_to_clean, 0); atomic_set(&txring->nr_free, jme->tx_ring_size); + txring->bufinf = kmalloc(sizeof(struct jme_buffer_info) * + jme->tx_ring_size, GFP_ATOMIC); + if (unlikely(!(txring->bufinf))) + goto err_free_txring; + /* * Initialize Transmit Descriptors */ @@ -547,6 +534,20 @@ jme_setup_tx_resources(struct jme_adapter *jme) sizeof(struct jme_buffer_info) * jme->tx_ring_size); return 0; + +err_free_txring: + dma_free_coherent(&(jme->pdev->dev), + TX_RING_ALLOC_SIZE(jme->tx_ring_size), + txring->alloc, + txring->dmaalloc); + +err_set_null: + txring->desc = NULL; + txring->dmaalloc = 0; + txring->dma = 0; + txring->bufinf = NULL; + + return -ENOMEM; } static void @@ -554,19 +555,22 @@ jme_free_tx_resources(struct jme_adapter *jme) { int i; struct jme_ring *txring = &(jme->txring[0]); - struct jme_buffer_info *txbi = txring->bufinf; + struct jme_buffer_info *txbi; if (txring->alloc) { - for (i = 0 ; i < jme->tx_ring_size ; ++i) { - txbi = txring->bufinf + i; - if (txbi->skb) { - dev_kfree_skb(txbi->skb); - txbi->skb = NULL; + if (txring->bufinf) { + for (i = 0 ; i < jme->tx_ring_size ; ++i) { + txbi = txring->bufinf + i; + if (txbi->skb) { + dev_kfree_skb(txbi->skb); + txbi->skb = NULL; + } + txbi->mapping = 0; + txbi->len = 0; + txbi->nr_desc = 0; + txbi->start_xmit = 0; } - txbi->mapping = 0; - txbi->len = 0; - txbi->nr_desc = 0; - txbi->start_xmit = 0; + kfree(txring->bufinf); } dma_free_coherent(&(jme->pdev->dev), @@ -578,11 +582,11 @@ jme_free_tx_resources(struct jme_adapter *jme) txring->desc = NULL; txring->dmaalloc = 0; txring->dma = 0; + txring->bufinf = NULL; } txring->next_to_use = 0; atomic_set(&txring->next_to_clean, 0); atomic_set(&txring->nr_free, 0); - } static inline void @@ -653,7 +657,7 @@ jme_disable_tx_engine(struct jme_adapter *jme) static void jme_set_clean_rxdesc(struct jme_adapter *jme, int i) { - struct jme_ring *rxring = jme->rxring; + struct jme_ring *rxring = &(jme->rxring[0]); register struct rxdesc *rxdesc = rxring->desc; struct jme_buffer_info *rxbi = rxring->bufinf; rxdesc += i; @@ -720,8 +724,11 @@ jme_free_rx_resources(struct jme_adapter *jme) struct jme_ring *rxring = &(jme->rxring[0]); if (rxring->alloc) { - for (i = 0 ; i < jme->rx_ring_size ; ++i) - jme_free_rx_buf(jme, i); + if (rxring->bufinf) { + for (i = 0 ; i < jme->rx_ring_size ; ++i) + jme_free_rx_buf(jme, i); + kfree(rxring->bufinf); + } dma_free_coherent(&(jme->pdev->dev), RX_RING_ALLOC_SIZE(jme->rx_ring_size), @@ -731,6 +738,7 @@ jme_free_rx_resources(struct jme_adapter *jme) rxring->desc = NULL; rxring->dmaalloc = 0; rxring->dma = 0; + rxring->bufinf = NULL; } rxring->next_to_use = 0; atomic_set(&rxring->next_to_clean, 0); @@ -746,12 +754,8 @@ jme_setup_rx_resources(struct jme_adapter *jme) RX_RING_ALLOC_SIZE(jme->rx_ring_size), &(rxring->dmaalloc), GFP_ATOMIC); - if (!rxring->alloc) { - rxring->desc = NULL; - rxring->dmaalloc = 0; - rxring->dma = 0; - return -ENOMEM; - } + if (!rxring->alloc) + goto err_set_null; /* * 16 Bytes align @@ -762,9 +766,16 @@ jme_setup_rx_resources(struct jme_adapter *jme) rxring->next_to_use = 0; atomic_set(&rxring->next_to_clean, 0); + rxring->bufinf = kmalloc(sizeof(struct jme_buffer_info) * + jme->rx_ring_size, GFP_ATOMIC); + if (unlikely(!(rxring->bufinf))) + goto err_free_rxring; + /* * Initiallize Receive Descriptors */ + memset(rxring->bufinf, 0, + sizeof(struct jme_buffer_info) * jme->rx_ring_size); for (i = 0 ; i < jme->rx_ring_size ; ++i) { if (unlikely(jme_make_new_rx_buf(jme, i))) { jme_free_rx_resources(jme); @@ -775,6 +786,19 @@ jme_setup_rx_resources(struct jme_adapter *jme) } return 0; + +err_free_rxring: + dma_free_coherent(&(jme->pdev->dev), + RX_RING_ALLOC_SIZE(jme->rx_ring_size), + rxring->alloc, + rxring->dmaalloc); +err_set_null: + rxring->desc = NULL; + rxring->dmaalloc = 0; + rxring->dma = 0; + rxring->bufinf = NULL; + + return -ENOMEM; } static inline void @@ -790,9 +814,9 @@ jme_enable_rx_engine(struct jme_adapter *jme) /* * Setup RX DMA Bass Address */ - jwrite32(jme, JME_RXDBA_LO, (__u64)jme->rxring[0].dma & 0xFFFFFFFFUL); + jwrite32(jme, JME_RXDBA_LO, (__u64)(jme->rxring[0].dma) & 0xFFFFFFFFUL); jwrite32(jme, JME_RXDBA_HI, (__u64)(jme->rxring[0].dma) >> 32); - jwrite32(jme, JME_RXNDA, (__u64)jme->rxring[0].dma & 0xFFFFFFFFUL); + jwrite32(jme, JME_RXNDA, (__u64)(jme->rxring[0].dma) & 0xFFFFFFFFUL); /* * Setup RX Descriptor Count @@ -856,27 +880,27 @@ jme_rxsum_ok(struct jme_adapter *jme, u16 flags) if (!(flags & (RXWBFLAG_TCPON | RXWBFLAG_UDPON | RXWBFLAG_IPV4))) return false; - if (unlikely(!(flags & RXWBFLAG_MF) && - (flags & RXWBFLAG_TCPON) && !(flags & RXWBFLAG_TCPCS))) { - msg_rx_err(jme, "TCP Checksum error.\n"); - goto out_sumerr; + if (unlikely((flags & (RXWBFLAG_MF | RXWBFLAG_TCPON | RXWBFLAG_TCPCS)) + == RXWBFLAG_TCPON)) { + if (flags & RXWBFLAG_IPV4) + msg_rx_err(jme, "TCP Checksum error\n"); + return false; } - if (unlikely(!(flags & RXWBFLAG_MF) && - (flags & RXWBFLAG_UDPON) && !(flags & RXWBFLAG_UDPCS))) { - msg_rx_err(jme, "UDP Checksum error.\n"); - goto out_sumerr; + if (unlikely((flags & (RXWBFLAG_MF | RXWBFLAG_UDPON | RXWBFLAG_UDPCS)) + == RXWBFLAG_UDPON)) { + if (flags & RXWBFLAG_IPV4) + msg_rx_err(jme, "UDP Checksum error.\n"); + return false; } - if (unlikely((flags & RXWBFLAG_IPV4) && !(flags & RXWBFLAG_IPCS))) { + if (unlikely((flags & (RXWBFLAG_IPV4 | RXWBFLAG_IPCS)) + == RXWBFLAG_IPV4)) { msg_rx_err(jme, "IPv4 Checksum error.\n"); - goto out_sumerr; + return false; } return true; - -out_sumerr: - return false; } static void @@ -1296,7 +1320,7 @@ jme_rx_empty_tasklet(unsigned long arg) static void jme_wake_queue_if_stopped(struct jme_adapter *jme) { - struct jme_ring *txring = jme->txring; + struct jme_ring *txring = &(jme->txring[0]); smp_wmb(); if (unlikely(netif_queue_stopped(jme->dev) && @@ -1483,12 +1507,7 @@ jme_msi(int irq, void *dev_id) struct jme_adapter *jme = netdev_priv(netdev); u32 intrstat; - pci_dma_sync_single_for_cpu(jme->pdev, - jme->shadow_dma, - sizeof(u32) * SHADOW_REG_NR, - PCI_DMA_FROMDEVICE); - intrstat = jme->shadow_regs[SHADOW_IEVE]; - jme->shadow_regs[SHADOW_IEVE] = 0; + intrstat = jread32(jme, JME_IEVE); jme_intr_msi(jme, intrstat); @@ -1566,6 +1585,7 @@ jme_open(struct net_device *netdev) jme_clear_pm(jme); JME_NAPI_ENABLE(jme); + tasklet_enable(&jme->linkch_task); tasklet_enable(&jme->txclean_task); tasklet_hi_enable(&jme->rxclean_task); tasklet_hi_enable(&jme->rxempty_task); @@ -1574,7 +1594,6 @@ jme_open(struct net_device *netdev) if (rc) goto err_out; - jme_enable_shadow(jme); jme_start_irq(jme); if (test_bit(JME_FLAG_SSET, &jme->flags)) @@ -1642,15 +1661,14 @@ jme_close(struct net_device *netdev) netif_carrier_off(netdev); jme_stop_irq(jme); - jme_disable_shadow(jme); jme_free_irq(jme); JME_NAPI_DISABLE(jme); - tasklet_kill(&jme->linkch_task); - tasklet_kill(&jme->txclean_task); - tasklet_kill(&jme->rxclean_task); - tasklet_kill(&jme->rxempty_task); + tasklet_disable(&jme->linkch_task); + tasklet_disable(&jme->txclean_task); + tasklet_disable(&jme->rxclean_task); + tasklet_disable(&jme->rxempty_task); jme_reset_ghc_speed(jme); jme_disable_rx_engine(jme); @@ -1668,7 +1686,7 @@ static int jme_alloc_txdesc(struct jme_adapter *jme, struct sk_buff *skb) { - struct jme_ring *txring = jme->txring; + struct jme_ring *txring = &(jme->txring[0]); int idx, nr_alloc, mask = jme->tx_ring_mask; idx = txring->next_to_use; @@ -1722,7 +1740,7 @@ jme_fill_tx_map(struct pci_dev *pdev, static void jme_map_tx_skb(struct jme_adapter *jme, struct sk_buff *skb, int idx) { - struct jme_ring *txring = jme->txring; + struct jme_ring *txring = &(jme->txring[0]); struct txdesc *txdesc = txring->desc, *ctxdesc; struct jme_buffer_info *txbi = txring->bufinf, *ctxbi; u8 hidma = jme->dev->features & NETIF_F_HIGHDMA; @@ -1835,7 +1853,7 @@ jme_tx_vlan(struct sk_buff *skb, __le16 *vlan, u8 *flags) static int jme_fill_tx_desc(struct jme_adapter *jme, struct sk_buff *skb, int idx) { - struct jme_ring *txring = jme->txring; + struct jme_ring *txring = &(jme->txring[0]); struct txdesc *txdesc; struct jme_buffer_info *txbi; u8 flags; @@ -1883,7 +1901,7 @@ jme_fill_tx_desc(struct jme_adapter *jme, struct sk_buff *skb, int idx) static void jme_stop_queue_if_full(struct jme_adapter *jme) { - struct jme_ring *txring = jme->txring; + struct jme_ring *txring = &(jme->txring[0]); struct jme_buffer_info *txbi = txring->bufinf; int idx = atomic_read(&txring->next_to_clean); @@ -2725,14 +2743,6 @@ jme_init_one(struct pci_dev *pdev, rc = -ENOMEM; goto err_out_free_netdev; } - jme->shadow_regs = pci_alloc_consistent(pdev, - sizeof(u32) * SHADOW_REG_NR, - &(jme->shadow_dma)); - if (!(jme->shadow_regs)) { - jeprintk(pdev, "Allocating shadow register mapping error.\n"); - rc = -ENOMEM; - goto err_out_unmap; - } if (no_pseudohp) { apmc = jread32(jme, JME_APMC) & ~JME_APMC_PSEUDO_HP_EN; @@ -2768,6 +2778,7 @@ jme_init_one(struct pci_dev *pdev, tasklet_init(&jme->rxempty_task, &jme_rx_empty_tasklet, (unsigned long) jme); + tasklet_disable_nosync(&jme->linkch_task); tasklet_disable_nosync(&jme->txclean_task); tasklet_disable_nosync(&jme->rxclean_task); tasklet_disable_nosync(&jme->rxempty_task); @@ -2817,7 +2828,7 @@ jme_init_one(struct pci_dev *pdev, if (!jme->mii_if.phy_id) { rc = -EIO; jeprintk(pdev, "Can not find phy_id.\n"); - goto err_out_free_shadow; + goto err_out_unmap; } jme->reg_ghc |= GHC_LINK_POLL; @@ -2846,7 +2857,7 @@ jme_init_one(struct pci_dev *pdev, if (rc) { jeprintk(pdev, "Reload eeprom for reading MAC Address error.\n"); - goto err_out_free_shadow; + goto err_out_unmap; } jme_load_macaddr(netdev); @@ -2862,7 +2873,7 @@ jme_init_one(struct pci_dev *pdev, rc = register_netdev(netdev); if (rc) { jeprintk(pdev, "Cannot register net device.\n"); - goto err_out_free_shadow; + goto err_out_unmap; } msg_probe(jme, "%s%s ver:%x rev:%x macaddr:%pM\n", @@ -2876,11 +2887,6 @@ jme_init_one(struct pci_dev *pdev, return 0; -err_out_free_shadow: - pci_free_consistent(pdev, - sizeof(u32) * SHADOW_REG_NR, - jme->shadow_regs, - jme->shadow_dma); err_out_unmap: iounmap(jme->regs); err_out_free_netdev: @@ -2901,10 +2907,6 @@ jme_remove_one(struct pci_dev *pdev) struct jme_adapter *jme = netdev_priv(netdev); unregister_netdev(netdev); - pci_free_consistent(pdev, - sizeof(u32) * SHADOW_REG_NR, - jme->shadow_regs, - jme->shadow_dma); iounmap(jme->regs); pci_set_drvdata(pdev, NULL); free_netdev(netdev); @@ -2930,8 +2932,6 @@ jme_suspend(struct pci_dev *pdev, pm_message_t state) tasklet_disable(&jme->rxclean_task); tasklet_disable(&jme->rxempty_task); - jme_disable_shadow(jme); - if (netif_carrier_ok(netdev)) { if (test_bit(JME_FLAG_POLL, &jme->flags)) jme_polling_mode(jme); @@ -2983,7 +2983,6 @@ jme_resume(struct pci_dev *pdev) else jme_reset_phy_processor(jme); - jme_enable_shadow(jme); jme_start_irq(jme); netif_device_attach(netdev); diff --git a/drivers/net/jme.h b/drivers/net/jme.h index 0996a069ac7..251abed3817 100644 --- a/drivers/net/jme.h +++ b/drivers/net/jme.h @@ -25,7 +25,7 @@ #define __JME_H_INCLUDED__ #define DRV_NAME "jme" -#define DRV_VERSION "1.0.4" +#define DRV_VERSION "1.0.5" #define PFX DRV_NAME ": " #define PCI_DEVICE_ID_JMICRON_JMC250 0x0250 @@ -247,7 +247,7 @@ enum jme_txdesc_flags_bits { }; #define TXDESC_MSS_SHIFT 2 -enum jme_rxdescwb_flags_bits { +enum jme_txwbdesc_flags_bits { TXWBFLAG_OWN = 0x80, TXWBFLAG_INT = 0x40, TXWBFLAG_TMOUT = 0x20, @@ -372,7 +372,6 @@ struct jme_buffer_info { /* * The structure holding buffer information and ring descriptors all together. */ -#define MAX_RING_DESC_NR 1024 struct jme_ring { void *alloc; /* pointer to allocated memory */ void *desc; /* pointer to ring memory */ @@ -380,7 +379,7 @@ struct jme_ring { dma_addr_t dma; /* phys address for ring dma */ /* Buffer information corresponding to each descriptor */ - struct jme_buffer_info bufinf[MAX_RING_DESC_NR]; + struct jme_buffer_info *bufinf; int next_to_use; atomic_t next_to_clean; @@ -411,13 +410,10 @@ struct jme_ring { /* * Jmac Adapter Private data */ -#define SHADOW_REG_NR 8 struct jme_adapter { struct pci_dev *pdev; struct net_device *dev; void __iomem *regs; - dma_addr_t shadow_dma; - u32 *shadow_regs; struct mii_if_info mii_if; struct jme_ring rxring[RX_RING_NR]; struct jme_ring txring[TX_RING_NR]; @@ -464,10 +460,6 @@ struct jme_adapter { DECLARE_NET_DEVICE_STATS }; -enum shadow_reg_val { - SHADOW_IEVE = 0, -}; - enum jme_flags_bits { JME_FLAG_MSI = 1, JME_FLAG_SSET = 2, @@ -1104,13 +1096,6 @@ enum jme_chipmode_shifts { }; /* - * Shadow base address register bits - */ -enum jme_shadow_base_address_bits { - SHBA_POSTEN = 0x1, -}; - -/* * Aggressive Power Mode Control */ enum jme_apmc_bits { diff --git a/drivers/net/lance.c b/drivers/net/lance.c index 633808d447b..30fd4f5f1d5 100644 --- a/drivers/net/lance.c +++ b/drivers/net/lance.c @@ -1016,7 +1016,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev) out: spin_unlock_irqrestore(&lp->devlock, flags); - return 0; + return NETDEV_TX_OK; } /* The LANCE interrupt handler. */ diff --git a/drivers/net/lib82596.c b/drivers/net/lib82596.c index 070fa450087..51e11c3e53e 100644 --- a/drivers/net/lib82596.c +++ b/drivers/net/lib82596.c @@ -983,7 +983,7 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev) if (length < ETH_ZLEN) { if (skb_padto(skb, ETH_ZLEN)) - return 0; + return NETDEV_TX_OK; length = ETH_ZLEN; } @@ -1028,7 +1028,7 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev) netif_start_queue(dev); - return 0; + return NETDEV_TX_OK; } static void print_eth(unsigned char *add, char *str) diff --git a/drivers/net/lib8390.c b/drivers/net/lib8390.c index f28c2334300..d6be36000c5 100644 --- a/drivers/net/lib8390.c +++ b/drivers/net/lib8390.c @@ -414,7 +414,7 @@ static int __ei_start_xmit(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb (skb); dev->stats.tx_bytes += send_length; - return 0; + return NETDEV_TX_OK; } /** diff --git a/drivers/net/ll_temac_main.c b/drivers/net/ll_temac_main.c index 96e7248876c..da8d0a0ca94 100644 --- a/drivers/net/ll_temac_main.c +++ b/drivers/net/ll_temac_main.c @@ -591,7 +591,7 @@ static int temac_start_xmit(struct sk_buff *skb, struct net_device *ndev) /* Kick off the transfer */ temac_dma_out32(lp, TX_TAILDESC_PTR, tail_p); /* DMA start */ - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index da472c68748..51bbce72bed 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -89,7 +89,7 @@ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev) } else lb_stats->drops++; - return 0; + return NETDEV_TX_OK; } static struct net_device_stats *loopback_get_stats(struct net_device *dev) diff --git a/drivers/net/lp486e.c b/drivers/net/lp486e.c index d44bddbee37..c292bad411e 100644 --- a/drivers/net/lp486e.c +++ b/drivers/net/lp486e.c @@ -871,7 +871,7 @@ static int i596_start_xmit (struct sk_buff *skb, struct net_device *dev) { if (length < ETH_ZLEN) { if (skb_padto(skb, ETH_ZLEN)) - return 0; + return NETDEV_TX_OK; length = ETH_ZLEN; } @@ -906,7 +906,7 @@ static int i596_start_xmit (struct sk_buff *skb, struct net_device *dev) { dev->stats.tx_packets++; } - return 0; + return NETDEV_TX_OK; } static void diff --git a/drivers/net/mac89x0.c b/drivers/net/mac89x0.c index dab45339d3a..149e0ed4a05 100644 --- a/drivers/net/mac89x0.c +++ b/drivers/net/mac89x0.c @@ -411,7 +411,7 @@ net_send_packet(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; dev_kfree_skb (skb); - return 0; + return NETDEV_TX_OK; } /* The typical workload of the driver: diff --git a/drivers/net/macb.c b/drivers/net/macb.c index 5b5c25368d1..d22952c78f1 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -678,7 +678,7 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } static void macb_free_consistent(struct macb *bp) diff --git a/drivers/net/mace.c b/drivers/net/mace.c index 1427755c224..7d7577b598e 100644 --- a/drivers/net/mace.c +++ b/drivers/net/mace.c @@ -581,7 +581,7 @@ static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); spin_unlock_irqrestore(&mp->lock, flags); - return 0; + return NETDEV_TX_OK; } static void mace_set_multicast(struct net_device *dev) diff --git a/drivers/net/meth.c b/drivers/net/meth.c index 5d04d94f2a2..abea35de255 100644 --- a/drivers/net/meth.c +++ b/drivers/net/meth.c @@ -715,7 +715,7 @@ static int meth_tx(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&priv->meth_lock, flags); - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/mipsnet.c b/drivers/net/mipsnet.c index b3b9a147d09..8ea98bd89ff 100644 --- a/drivers/net/mipsnet.c +++ b/drivers/net/mipsnet.c @@ -141,7 +141,7 @@ static int mipsnet_xmit(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); mipsnet_put_todevice(dev, skb); - return 0; + return NETDEV_TX_OK; } static inline ssize_t mipsnet_get_fromdev(struct net_device *dev, size_t len) diff --git a/drivers/net/mlx4/en_tx.c b/drivers/net/mlx4/en_tx.c index 08c43f2ae72..d5c18c67425 100644 --- a/drivers/net/mlx4/en_tx.c +++ b/drivers/net/mlx4/en_tx.c @@ -764,7 +764,7 @@ int mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) /* Poll CQ here */ mlx4_en_xmit_poll(priv, tx_ind); - return 0; + return NETDEV_TX_OK; tx_drop: dev_kfree_skb_any(skb); diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index 1f6e36ea669..1a34f7e11d9 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -2748,7 +2748,7 @@ again: /* The packet is gone, so we must * return 0 */ ss->stats.tx_dropped += 1; - return 0; + return NETDEV_TX_OK; } /* adjust the len to account for the zero pad * so that the nic can know how long it is */ @@ -2892,7 +2892,7 @@ again: tx->stop_queue++; netif_tx_stop_queue(netdev_queue); } - return 0; + return NETDEV_TX_OK; abort_linearize: /* Free any DMA resources we've alloced and clear out the skb @@ -2936,7 +2936,7 @@ abort_linearize: drop: dev_kfree_skb_any(skb); ss->stats.tx_dropped += 1; - return 0; + return NETDEV_TX_OK; } @@ -2968,13 +2968,13 @@ static int myri10ge_sw_tso(struct sk_buff *skb, struct net_device *dev) } } dev_kfree_skb_any(skb); - return 0; + return NETDEV_TX_OK; drop: ss = &mgp->ss[skb_get_queue_mapping(skb)]; dev_kfree_skb_any(skb); ss->stats.tx_dropped += 1; - return 0; + return NETDEV_TX_OK; } static struct net_device_stats *myri10ge_get_stats(struct net_device *dev) diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c index 5f0758bda6b..29ebebc6a95 100644 --- a/drivers/net/myri_sbus.c +++ b/drivers/net/myri_sbus.c @@ -692,7 +692,7 @@ static int myri_start_xmit(struct sk_buff *skb, struct net_device *dev) DTX(("tbusy=0, returning 0\n")); netif_start_queue(dev); spin_unlock_irqrestore(&mp->irq_lock, flags); - return 0; + return NETDEV_TX_OK; } /* Create the MyriNet MAC header for an arbitrary protocol layer diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index c9bfe4eea18..481aa2d287a 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -2125,7 +2125,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n", dev->name, np->cur_tx, entry); } - return 0; + return NETDEV_TX_OK; } static void netdev_tx_done(struct net_device *dev) diff --git a/drivers/net/netx-eth.c b/drivers/net/netx-eth.c index 946366dcc99..9f4235466d5 100644 --- a/drivers/net/netx-eth.c +++ b/drivers/net/netx-eth.c @@ -134,7 +134,7 @@ netx_eth_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev) spin_unlock_irq(&priv->lock); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } static void netx_eth_receive(struct net_device *ndev) diff --git a/drivers/net/ni5010.c b/drivers/net/ni5010.c index 2a8da476ab3..462d20f2643 100644 --- a/drivers/net/ni5010.c +++ b/drivers/net/ni5010.c @@ -463,7 +463,7 @@ static int ni5010_send_packet(struct sk_buff *skb, struct net_device *dev) hardware_send_packet(dev, (unsigned char *)skb->data, skb->len, length-skb->len); dev->trans_start = jiffies; dev_kfree_skb (skb); - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/ni52.c b/drivers/net/ni52.c index 77d44a06170..a0ac5d4f27d 100644 --- a/drivers/net/ni52.c +++ b/drivers/net/ni52.c @@ -1183,7 +1183,7 @@ static int ni52_send_packet(struct sk_buff *skb, struct net_device *dev) if (skb->len > XMIT_BUFF_SIZE) { printk(KERN_ERR "%s: Sorry, max. framelength is %d bytes. The length of your frame is %d bytes.\n", dev->name, XMIT_BUFF_SIZE, skb->len); - return 0; + return NETDEV_TX_OK; } netif_stop_queue(dev); @@ -1267,7 +1267,7 @@ static int ni52_send_packet(struct sk_buff *skb, struct net_device *dev) } dev_kfree_skb(skb); #endif - return 0; + return NETDEV_TX_OK; } /******************************************* diff --git a/drivers/net/ni65.c b/drivers/net/ni65.c index 1f10ed603e2..81a06178589 100644 --- a/drivers/net/ni65.c +++ b/drivers/net/ni65.c @@ -1216,7 +1216,7 @@ static int ni65_send_packet(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&p->ring_lock, flags); } - return 0; + return NETDEV_TX_OK; } static void set_multicast_list(struct net_device *dev) diff --git a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c index 8c1f6988f39..e4a93b8ed48 100644 --- a/drivers/net/pci-skeleton.c +++ b/drivers/net/pci-skeleton.c @@ -1356,7 +1356,7 @@ static int netdrv_start_xmit (struct sk_buff *skb, struct net_device *dev) DPRINTK ("%s: Queued Tx packet at %p size %u to slot %d.\n", dev->name, skb->data, skb->len, entry); - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c index f35c609ba02..a23aa872404 100644 --- a/drivers/net/pcmcia/3c574_cs.c +++ b/drivers/net/pcmcia/3c574_cs.c @@ -806,7 +806,7 @@ static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev) pop_tx_status(dev); spin_unlock_irqrestore(&lp->window_lock, flags); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* The EL3 interrupt handler. */ diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c index ec7cf5ac4f0..a77417c51e4 100644 --- a/drivers/net/pcmcia/3c589_cs.c +++ b/drivers/net/pcmcia/3c589_cs.c @@ -635,7 +635,7 @@ static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&priv->lock, flags); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* The EL3 interrupt handler. */ diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index 0e38d80fd25..b5cfac7c517 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c @@ -1179,7 +1179,7 @@ static int axnet_start_xmit(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb (skb); dev->stats.tx_bytes += send_length; - return 0; + return NETDEV_TX_OK; } /** diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c index 479d5b49437..434d9407bfb 100644 --- a/drivers/net/pcmcia/fmvj18x_cs.c +++ b/drivers/net/pcmcia/fmvj18x_cs.c @@ -865,7 +865,7 @@ static int fjn_start_xmit(struct sk_buff *skb, struct net_device *dev) if (length < ETH_ZLEN) { if (skb_padto(skb, ETH_ZLEN)) - return 0; + return NETDEV_TX_OK; length = ETH_ZLEN; } @@ -924,7 +924,7 @@ static int fjn_start_xmit(struct sk_buff *skb, struct net_device *dev) } dev_kfree_skb (skb); - return 0; + return NETDEV_TX_OK; } /* fjn_start_xmit */ /*====================================================================*/ diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c index 02ef63ed1f9..0f8118a8257 100644 --- a/drivers/net/pcmcia/nmclan_cs.c +++ b/drivers/net/pcmcia/nmclan_cs.c @@ -990,7 +990,7 @@ static int mace_start_xmit(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* mace_start_xmit */ /* ---------------------------------------------------------------------------- diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c index 37e05d3ab89..2f39244c17f 100644 --- a/drivers/net/pcmcia/smc91c92_cs.c +++ b/drivers/net/pcmcia/smc91c92_cs.c @@ -1399,7 +1399,7 @@ static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb (skb); smc->saved_skb = NULL; dev->stats.tx_dropped++; - return 0; /* Do not re-queue this packet. */ + return NETDEV_TX_OK; /* Do not re-queue this packet. */ } /* A packet is now waiting. */ smc->packets_waiting++; @@ -1422,7 +1422,7 @@ static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev) outw((ir&0xff00) | IM_ALLOC_INT, ioaddr + INTERRUPT); smc_hardware_send_packet(dev); /* Send the packet now.. */ spin_unlock_irqrestore(&smc->lock, flags); - return 0; + return NETDEV_TX_OK; } } @@ -1431,7 +1431,7 @@ static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev) outw((IM_ALLOC_INT << 8) | (ir & 0xff00), ioaddr + INTERRUPT); spin_unlock_irqrestore(&smc->lock, flags); - return 0; + return NETDEV_TX_OK; } /*====================================================================== diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c index ef37d22c7e1..eda7bf6047c 100644 --- a/drivers/net/pcmcia/xirc2ps_cs.c +++ b/drivers/net/pcmcia/xirc2ps_cs.c @@ -1384,7 +1384,7 @@ do_start_xmit(struct sk_buff *skb, struct net_device *dev) if (pktlen < ETH_ZLEN) { if (skb_padto(skb, ETH_ZLEN)) - return 0; + return NETDEV_TX_OK; pktlen = ETH_ZLEN; } @@ -1414,7 +1414,7 @@ do_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; dev->stats.tx_bytes += pktlen; netif_start_queue(dev); - return 0; + return NETDEV_TX_OK; } /**************** diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index 1c35e1d637a..955a87ac9af 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -2536,7 +2536,7 @@ static int pcnet32_start_xmit(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); } spin_unlock_irqrestore(&lp->lock, flags); - return 0; + return NETDEV_TX_OK; } /* The PCNET32 interrupt handler. */ diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index de9cf5136fd..d5d8e1c5bc9 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -56,6 +56,12 @@ config BROADCOM_PHY Currently supports the BCM5411, BCM5421, BCM5461, BCM5464, BCM5481 and BCM5482 PHYs. +config BCM63XX_PHY + tristate "Drivers for Broadcom 63xx SOCs internal PHY" + depends on BCM63XX + ---help--- + Currently supports the 6348 and 6358 PHYs. + config ICPLUS_PHY tristate "Drivers for ICPlus PHYs" ---help--- diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 3a1bfefefbc..edfaac48cbd 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_QSEMI_PHY) += qsemi.o obj-$(CONFIG_SMSC_PHY) += smsc.o obj-$(CONFIG_VITESSE_PHY) += vitesse.o obj-$(CONFIG_BROADCOM_PHY) += broadcom.o +obj-$(CONFIG_BCM63XX_PHY) += bcm63xx.o obj-$(CONFIG_ICPLUS_PHY) += icplus.o obj-$(CONFIG_REALTEK_PHY) += realtek.o obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o diff --git a/drivers/net/phy/bcm63xx.c b/drivers/net/phy/bcm63xx.c new file mode 100644 index 00000000000..4fed95e8350 --- /dev/null +++ b/drivers/net/phy/bcm63xx.c @@ -0,0 +1,132 @@ +/* + * Driver for Broadcom 63xx SOCs integrated PHYs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include <linux/module.h> +#include <linux/phy.h> + +#define MII_BCM63XX_IR 0x1a /* interrupt register */ +#define MII_BCM63XX_IR_EN 0x4000 /* global interrupt enable */ +#define MII_BCM63XX_IR_DUPLEX 0x0800 /* duplex changed */ +#define MII_BCM63XX_IR_SPEED 0x0400 /* speed changed */ +#define MII_BCM63XX_IR_LINK 0x0200 /* link changed */ +#define MII_BCM63XX_IR_GMASK 0x0100 /* global interrupt mask */ + +MODULE_DESCRIPTION("Broadcom 63xx internal PHY driver"); +MODULE_AUTHOR("Maxime Bizon <mbizon@freebox.fr>"); +MODULE_LICENSE("GPL"); + +static int bcm63xx_config_init(struct phy_device *phydev) +{ + int reg, err; + + reg = phy_read(phydev, MII_BCM63XX_IR); + if (reg < 0) + return reg; + + /* Mask interrupts globally. */ + reg |= MII_BCM63XX_IR_GMASK; + err = phy_write(phydev, MII_BCM63XX_IR, reg); + if (err < 0) + return err; + + /* Unmask events we are interested in */ + reg = ~(MII_BCM63XX_IR_DUPLEX | + MII_BCM63XX_IR_SPEED | + MII_BCM63XX_IR_LINK) | + MII_BCM63XX_IR_EN; + err = phy_write(phydev, MII_BCM63XX_IR, reg); + if (err < 0) + return err; + return 0; +} + +static int bcm63xx_ack_interrupt(struct phy_device *phydev) +{ + int reg; + + /* Clear pending interrupts. */ + reg = phy_read(phydev, MII_BCM63XX_IR); + if (reg < 0) + return reg; + + return 0; +} + +static int bcm63xx_config_intr(struct phy_device *phydev) +{ + int reg, err; + + reg = phy_read(phydev, MII_BCM63XX_IR); + if (reg < 0) + return reg; + + if (phydev->interrupts == PHY_INTERRUPT_ENABLED) + reg &= ~MII_BCM63XX_IR_GMASK; + else + reg |= MII_BCM63XX_IR_GMASK; + + err = phy_write(phydev, MII_BCM63XX_IR, reg); + return err; +} + +static struct phy_driver bcm63xx_1_driver = { + .phy_id = 0x00406000, + .phy_id_mask = 0xfffffc00, + .name = "Broadcom BCM63XX (1)", + /* ASYM_PAUSE bit is marked RO in datasheet, so don't cheat */ + .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause), + .flags = PHY_HAS_INTERRUPT, + .config_init = bcm63xx_config_init, + .config_aneg = genphy_config_aneg, + .read_status = genphy_read_status, + .ack_interrupt = bcm63xx_ack_interrupt, + .config_intr = bcm63xx_config_intr, + .driver = { .owner = THIS_MODULE }, +}; + +/* same phy as above, with just a different OUI */ +static struct phy_driver bcm63xx_2_driver = { + .phy_id = 0x002bdc00, + .phy_id_mask = 0xfffffc00, + .name = "Broadcom BCM63XX (2)", + .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause), + .flags = PHY_HAS_INTERRUPT, + .config_init = bcm63xx_config_init, + .config_aneg = genphy_config_aneg, + .read_status = genphy_read_status, + .ack_interrupt = bcm63xx_ack_interrupt, + .config_intr = bcm63xx_config_intr, + .driver = { .owner = THIS_MODULE }, +}; + +static int __init bcm63xx_phy_init(void) +{ + int ret; + + ret = phy_driver_register(&bcm63xx_1_driver); + if (ret) + goto out_63xx_1; + ret = phy_driver_register(&bcm63xx_2_driver); + if (ret) + goto out_63xx_2; + return ret; + +out_63xx_2: + phy_driver_unregister(&bcm63xx_1_driver); +out_63xx_1: + return ret; +} + +static void __exit bcm63xx_phy_exit(void) +{ + phy_driver_unregister(&bcm63xx_1_driver); + phy_driver_unregister(&bcm63xx_2_driver); +} + +module_init(bcm63xx_phy_init); +module_exit(bcm63xx_phy_exit); diff --git a/drivers/net/plip.c b/drivers/net/plip.c index 7a62f781fef..ef2e229ebc1 100644 --- a/drivers/net/plip.c +++ b/drivers/net/plip.c @@ -987,7 +987,7 @@ plip_tx_packet(struct sk_buff *skb, struct net_device *dev) schedule_work(&nl->immediate); spin_unlock_irq(&nl->lock); - return 0; + return NETDEV_TX_OK; } static void diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index 639d11bc444..d0b965517b4 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c @@ -988,12 +988,12 @@ ppp_start_xmit(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); skb_queue_tail(&ppp->file.xq, skb); ppp_xmit_process(ppp); - return 0; + return NETDEV_TX_OK; outf: kfree_skb(skb); ++dev->stats.tx_dropped; - return 0; + return NETDEV_TX_OK; } static int diff --git a/drivers/net/r6040.c b/drivers/net/r6040.c index 961b5397a53..840677f5ee8 100644 --- a/drivers/net/r6040.c +++ b/drivers/net/r6040.c @@ -1115,13 +1115,13 @@ static int __devinit r6040_init_one(struct pci_dev *pdev, } /* IO Size check */ - if (pci_resource_len(pdev, 0) < io_size) { + if (pci_resource_len(pdev, bar) < io_size) { printk(KERN_ERR DRV_NAME ": Insufficient PCI resources, aborting\n"); err = -EIO; goto err_out; } - pioaddr = pci_resource_start(pdev, 0); /* IO map base address */ + pioaddr = pci_resource_start(pdev, bar); /* IO map base address */ pci_set_master(pdev); dev = alloc_etherdev(sizeof(struct r6040_private)); diff --git a/drivers/net/rionet.c b/drivers/net/rionet.c index 8702e7acdee..bc98e7f69ee 100644 --- a/drivers/net/rionet.c +++ b/drivers/net/rionet.c @@ -114,11 +114,6 @@ static int rionet_rx_clean(struct net_device *ndev) if (error == NET_RX_DROP) { ndev->stats.rx_dropped++; - } else if (error == NET_RX_BAD) { - if (netif_msg_rx_err(rnet)) - printk(KERN_WARNING "%s: bad rx packet\n", - DRV_NAME); - ndev->stats.rx_errors++; } else { ndev->stats.rx_packets++; ndev->stats.rx_bytes += RIO_MAX_MSG_SIZE; @@ -208,7 +203,7 @@ static int rionet_start_xmit(struct sk_buff *skb, struct net_device *ndev) spin_unlock_irqrestore(&rnet->tx_lock, flags); - return 0; + return NETDEV_TX_OK; } static void rionet_dbell_event(struct rio_mport *mport, void *dev_id, u16 sid, u16 tid, diff --git a/drivers/net/rrunner.c b/drivers/net/rrunner.c index 81dbcbb910f..d9553465591 100644 --- a/drivers/net/rrunner.c +++ b/drivers/net/rrunner.c @@ -1466,7 +1466,7 @@ static int rr_start_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&rrpriv->lock, flags); dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 458daa06ed4..d4df9330c44 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -4111,14 +4111,14 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) if (unlikely(skb->len <= 0)) { DBG_PRINT(TX_DBG, "%s:Buffer has no data..\n", dev->name); dev_kfree_skb_any(skb); - return 0; + return NETDEV_TX_OK; } if (!is_s2io_card_up(sp)) { DBG_PRINT(TX_DBG, "%s: Card going down for reset\n", dev->name); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } queue = 0; @@ -4192,7 +4192,7 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) s2io_stop_tx_queue(sp, fifo->fifo_no); dev_kfree_skb(skb); spin_unlock_irqrestore(&fifo->tx_lock, flags); - return 0; + return NETDEV_TX_OK; } offload_type = s2io_offload_type(skb); @@ -4304,14 +4304,14 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) if (sp->config.intr_type == MSI_X) tx_intr_handler(fifo); - return 0; + return NETDEV_TX_OK; pci_map_failed: stats->pci_map_fail_cnt++; s2io_stop_tx_queue(sp, fifo->fifo_no); stats->mem_freed += skb->truesize; dev_kfree_skb(skb); spin_unlock_irqrestore(&fifo->tx_lock, flags); - return 0; + return NETDEV_TX_OK; } static void diff --git a/drivers/net/sb1000.c b/drivers/net/sb1000.c index fc0e38bddee..6a81aec645d 100644 --- a/drivers/net/sb1000.c +++ b/drivers/net/sb1000.c @@ -1086,7 +1086,7 @@ sb1000_start_xmit(struct sk_buff *skb, struct net_device *dev) printk(KERN_WARNING "%s: trying to transmit!!!\n", dev->name); /* sb1000 can't xmit datagrams */ dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* SB1000 interrupt handler. */ diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c index d8c9cf1b901..4c2450b6bd0 100644 --- a/drivers/net/sb1250-mac.c +++ b/drivers/net/sb1250-mac.c @@ -2091,7 +2091,7 @@ static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&sc->sbm_lock, flags); - return 0; + return NETDEV_TX_OK; } /********************************************************************** diff --git a/drivers/net/seeq8005.c b/drivers/net/seeq8005.c index ebbbe09725f..7cc8bb81413 100644 --- a/drivers/net/seeq8005.c +++ b/drivers/net/seeq8005.c @@ -401,7 +401,7 @@ static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev) if (length < ETH_ZLEN) { if (skb_padto(skb, ETH_ZLEN)) - return 0; + return NETDEV_TX_OK; length = ETH_ZLEN; } buf = skb->data; @@ -415,7 +415,7 @@ static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb (skb); /* You might need to clean up and record Tx statistics here. */ - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c index 5fb88ca6dd7..78f60089b55 100644 --- a/drivers/net/sgiseeq.c +++ b/drivers/net/sgiseeq.c @@ -594,7 +594,7 @@ static int sgiseeq_start_xmit(struct sk_buff *skb, struct net_device *dev) len = skb->len; if (len < ETH_ZLEN) { if (skb_padto(skb, ETH_ZLEN)) - return 0; + return NETDEV_TX_OK; len = ETH_ZLEN; } @@ -642,7 +642,7 @@ static int sgiseeq_start_xmit(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); spin_unlock_irqrestore(&sp->tx_lock, flags); - return 0; + return NETDEV_TX_OK; } static void timeout(struct net_device *dev) diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c index a2d82ddb3b4..4c4dcbf1902 100644 --- a/drivers/net/sh_eth.c +++ b/drivers/net/sh_eth.c @@ -1133,7 +1133,7 @@ static int sh_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev) ndev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } /* device close function */ diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c index a9a897bb42d..61ceeaaf104 100644 --- a/drivers/net/sis900.c +++ b/drivers/net/sis900.c @@ -1628,7 +1628,7 @@ sis900_start_xmit(struct sk_buff *skb, struct net_device *net_dev) "to slot %d.\n", net_dev->name, skb->data, (int)skb->len, entry); - return 0; + return NETDEV_TX_OK; } /** diff --git a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c index 088fe26484e..888a14a045e 100644 --- a/drivers/net/skfp/skfddi.c +++ b/drivers/net/skfp/skfddi.c @@ -1077,7 +1077,7 @@ static int skfp_send_pkt(struct sk_buff *skb, struct net_device *dev) // dequeue packets from xmt queue and send them netif_start_queue(dev); dev_kfree_skb(skb); - return (0); /* return "success" */ + return NETDEV_TX_OK; /* return "success" */ } if (bp->QueueSkb == 0) { // return with tbusy set: queue full @@ -1091,7 +1091,7 @@ static int skfp_send_pkt(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); } dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } // skfp_send_pkt diff --git a/drivers/net/slip.c b/drivers/net/slip.c index 5c61d5fad90..899c4a2112c 100644 --- a/drivers/net/slip.c +++ b/drivers/net/slip.c @@ -484,12 +484,12 @@ sl_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock(&sl->lock); printk(KERN_WARNING "%s: xmit call when iface is down\n", dev->name); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } if (sl->tty == NULL) { spin_unlock(&sl->lock); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } sl_lock(sl); @@ -498,7 +498,7 @@ sl_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock(&sl->lock); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index bc4976ac871..2a6b6de9533 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -553,7 +553,7 @@ static int smc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->stats.tx_dropped++; spin_unlock_irqrestore(&lp->lock, flags); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } #ifdef SMC_USE_DMA @@ -566,7 +566,7 @@ static int smc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) lp->pending_tx_skb = skb; netif_stop_queue(dev); spin_unlock_irqrestore(&lp->lock, flags); - return 0; + return NETDEV_TX_OK; } else { DBG(SMC_DEBUG_TX | SMC_DEBUG_DMA, "%s: Activating Tx DMA\n", dev->name); lp->txdma_active = 1; @@ -577,7 +577,7 @@ static int smc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) smc911x_hardware_send_pkt(dev); spin_unlock_irqrestore(&lp->lock, flags); - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/smc9194.c b/drivers/net/smc9194.c index e02471b2f2b..0a1b6f40108 100644 --- a/drivers/net/smc9194.c +++ b/drivers/net/smc9194.c @@ -512,7 +512,7 @@ static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * de if (length < ETH_ZLEN) { if (skb_padto(skb, ETH_ZLEN)) { netif_wake_queue(dev); - return 0; + return NETDEV_TX_OK; } length = ETH_ZLEN; } @@ -534,7 +534,7 @@ static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * de lp->saved_skb = NULL; /* this IS an error, but, i don't want the skb saved */ netif_wake_queue(dev); - return 0; + return NETDEV_TX_OK; } /* either way, a packet is waiting now */ lp->packets_waiting++; @@ -571,12 +571,12 @@ static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * de SMC_ENABLE_INT( IM_ALLOC_INT ); PRINTK2((CARDNAME": memory allocation deferred. \n")); /* it's deferred, but I'll handle it later */ - return 0; + return NETDEV_TX_OK; } /* or YES! I can send the packet now.. */ smc_hardware_send_packet(dev); netif_wake_queue(dev); - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c index fdcbaf8dfa7..2968c75ff49 100644 --- a/drivers/net/smc91x.c +++ b/drivers/net/smc91x.c @@ -655,7 +655,7 @@ static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->stats.tx_errors++; dev->stats.tx_dropped++; dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } smc_special_lock(&lp->lock); @@ -692,7 +692,7 @@ static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) smc_hardware_send_pkt((unsigned long)dev); } - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/sonic.c b/drivers/net/sonic.c index 753a1fba460..9599ce77ef8 100644 --- a/drivers/net/sonic.c +++ b/drivers/net/sonic.c @@ -211,7 +211,7 @@ static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev) length = skb->len; if (length < ETH_ZLEN) { if (skb_padto(skb, ETH_ZLEN)) - return 0; + return NETDEV_TX_OK; length = ETH_ZLEN; } @@ -265,7 +265,7 @@ static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c index 838cce8b8ff..1018349a29d 100644 --- a/drivers/net/starfire.c +++ b/drivers/net/starfire.c @@ -1311,7 +1311,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/sun3_82586.c b/drivers/net/sun3_82586.c index 7bb27426dbd..2f1eaaf7a72 100644 --- a/drivers/net/sun3_82586.c +++ b/drivers/net/sun3_82586.c @@ -1015,7 +1015,7 @@ static int sun3_82586_send_packet(struct sk_buff *skb, struct net_device *dev) if(skb->len > XMIT_BUFF_SIZE) { printk("%s: Sorry, max. framelength is %d bytes. The length of your frame is %d bytes.\n",dev->name,XMIT_BUFF_SIZE,skb->len); - return 0; + return NETDEV_TX_OK; } netif_stop_queue(dev); @@ -1110,7 +1110,7 @@ static int sun3_82586_send_packet(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb(skb); #endif } - return 0; + return NETDEV_TX_OK; } /******************************************* diff --git a/drivers/net/sun3lance.c b/drivers/net/sun3lance.c index 534dfe3eef6..0ca4241b4f6 100644 --- a/drivers/net/sun3lance.c +++ b/drivers/net/sun3lance.c @@ -562,7 +562,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ) netif_start_queue(dev); dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } @@ -648,7 +648,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ) local_irq_restore(flags); - return 0; + return NETDEV_TX_OK; } /* The LANCE interrupt handler. */ diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c index 5017d7fcb40..536cf7e06bf 100644 --- a/drivers/net/sunbmac.c +++ b/drivers/net/sunbmac.c @@ -984,7 +984,7 @@ static int bigmac_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } static struct net_device_stats *bigmac_get_stats(struct net_device *dev) diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c index 545f81b34ad..0df6332ed9c 100644 --- a/drivers/net/sundance.c +++ b/drivers/net/sundance.c @@ -1091,7 +1091,7 @@ start_tx (struct sk_buff *skb, struct net_device *dev) "%s: Transmit frame #%d queued in slot %d.\n", dev->name, np->cur_tx, entry); } - return 0; + return NETDEV_TX_OK; } /* Reset hardware tx and free all of tx buffers */ diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index 4ef729198e1..008bd59fc64 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -2338,7 +2338,7 @@ static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; tx_add_log(hp, TXLOG_ACTION_TXMIT, 0); - return 0; + return NETDEV_TX_OK; } static struct net_device_stats *happy_meal_get_stats(struct net_device *dev) diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c index afc7b351e5e..9d6fd4760ea 100644 --- a/drivers/net/sunlance.c +++ b/drivers/net/sunlance.c @@ -1163,7 +1163,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* taken from the depca driver */ diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c index c6ec61e0acc..dcefb608a9f 100644 --- a/drivers/net/sunqe.c +++ b/drivers/net/sunqe.c @@ -621,7 +621,7 @@ static int qe_start_xmit(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } static void qe_set_multicast(struct net_device *dev) diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c index d737f6b8f87..1ce2da172ca 100644 --- a/drivers/net/tc35815.c +++ b/drivers/net/tc35815.c @@ -1509,7 +1509,7 @@ static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev) */ spin_unlock_irqrestore(&lp->lock, flags); - return 0; + return NETDEV_TX_OK; } #define FATAL_ERROR_INT \ diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c index 384cb5e2839..70c9ec45d8f 100644 --- a/drivers/net/tlan.c +++ b/drivers/net/tlan.c @@ -1095,11 +1095,11 @@ static int TLan_StartTx( struct sk_buff *skb, struct net_device *dev ) TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: %s PHY is not ready\n", dev->name ); dev_kfree_skb_any(skb); - return 0; + return NETDEV_TX_OK; } if (skb_padto(skb, TLAN_MIN_FRAME_SIZE)) - return 0; + return NETDEV_TX_OK; txlen = max(skb->len, (unsigned int)TLAN_MIN_FRAME_SIZE); tail_list = priv->txList + priv->txTail; @@ -1150,7 +1150,7 @@ static int TLan_StartTx( struct sk_buff *skb, struct net_device *dev ) CIRC_INC( priv->txTail, TLAN_NUM_TX_LISTS ); dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } /* TLan_StartTx */ diff --git a/drivers/net/tokenring/3c359.c b/drivers/net/tokenring/3c359.c index b40b6de2d08..1787d52941b 100644 --- a/drivers/net/tokenring/3c359.c +++ b/drivers/net/tokenring/3c359.c @@ -1240,7 +1240,7 @@ static int xl_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&xl_priv->xl_lock,flags) ; - return 0; + return NETDEV_TX_OK; } else { spin_unlock_irqrestore(&xl_priv->xl_lock,flags) ; return NETDEV_TX_BUSY; diff --git a/drivers/net/tokenring/ibmtr.c b/drivers/net/tokenring/ibmtr.c index 9d896116cf7..6472ba5cfc5 100644 --- a/drivers/net/tokenring/ibmtr.c +++ b/drivers/net/tokenring/ibmtr.c @@ -1041,7 +1041,7 @@ static int tok_send_packet(struct sk_buff *skb, struct net_device *dev) writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); spin_unlock_irqrestore(&(ti->lock), flags); dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } /*****************************************************************************/ diff --git a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c index b3715efdce5..d07e61a9499 100644 --- a/drivers/net/tokenring/lanstreamer.c +++ b/drivers/net/tokenring/lanstreamer.c @@ -1183,7 +1183,7 @@ static int streamer_xmit(struct sk_buff *skb, struct net_device *dev) streamer_priv->tx_ring_free = (streamer_priv->tx_ring_free + 1) & (STREAMER_TX_RING_SIZE - 1); spin_unlock_irqrestore(&streamer_priv->streamer_lock,flags); - return 0; + return NETDEV_TX_OK; } else { netif_stop_queue(dev); spin_unlock_irqrestore(&streamer_priv->streamer_lock,flags); diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c index 451b54136ed..f73f4e684f3 100644 --- a/drivers/net/tokenring/olympic.c +++ b/drivers/net/tokenring/olympic.c @@ -1052,7 +1052,7 @@ static int olympic_xmit(struct sk_buff *skb, struct net_device *dev) writew((((readw(olympic_mmio+TXENQ_1)) & 0x8000) ^ 0x8000) | 1,olympic_mmio+TXENQ_1); netif_wake_queue(dev); spin_unlock_irqrestore(&olympic_priv->olympic_lock,flags); - return 0; + return NETDEV_TX_OK; } else { spin_unlock_irqrestore(&olympic_priv->olympic_lock,flags); return NETDEV_TX_BUSY; diff --git a/drivers/net/tokenring/smctr.c b/drivers/net/tokenring/smctr.c index 54ad4ed0337..6515894c83f 100644 --- a/drivers/net/tokenring/smctr.c +++ b/drivers/net/tokenring/smctr.c @@ -4609,7 +4609,7 @@ static int smctr_send_packet(struct sk_buff *skb, struct net_device *dev) if(tp->QueueSkb > 0) netif_wake_queue(dev); - return (0); + return NETDEV_TX_OK; } static int smctr_send_lobe_media_test(struct net_device *dev) diff --git a/drivers/net/tokenring/tms380tr.c b/drivers/net/tokenring/tms380tr.c index a2eab72b507..07f6dfd3ba0 100644 --- a/drivers/net/tokenring/tms380tr.c +++ b/drivers/net/tokenring/tms380tr.c @@ -682,7 +682,7 @@ static int tms380tr_hardware_send_packet(struct sk_buff *skb, struct net_device tms380tr_exec_sifcmd(dev, CMD_TX_VALID); spin_unlock_irqrestore(&tp->lock, flags); - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c index 81f054dbb88..769af558a34 100644 --- a/drivers/net/tulip/de2104x.c +++ b/drivers/net/tulip/de2104x.c @@ -651,7 +651,7 @@ static int de_start_xmit (struct sk_buff *skb, struct net_device *dev) dw32(TxPoll, NormalTxPoll); dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } /* Set or clear the multicast filter for this adaptor. diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c index 8e78f003f08..5e15fab58c1 100644 --- a/drivers/net/tulip/dmfe.c +++ b/drivers/net/tulip/dmfe.c @@ -676,7 +676,7 @@ static int dmfe_start_xmit(struct sk_buff *skb, struct DEVICE *dev) if (skb->len > MAX_PACKET_SIZE) { printk(KERN_ERR DRV_NAME ": big packet = %d\n", (u16)skb->len); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } spin_lock_irqsave(&db->lock, flags); @@ -722,7 +722,7 @@ static int dmfe_start_xmit(struct sk_buff *skb, struct DEVICE *dev) /* free this SKB */ dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index 2abb5d3becc..9d46638d250 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -690,7 +690,7 @@ tulip_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } static void tulip_clean_tx_ring(struct tulip_private *tp) diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c index 9277ce8febe..9074a34eb81 100644 --- a/drivers/net/tulip/uli526x.c +++ b/drivers/net/tulip/uli526x.c @@ -582,7 +582,7 @@ static int uli526x_start_xmit(struct sk_buff *skb, struct net_device *dev) if (skb->len > MAX_PACKET_SIZE) { printk(KERN_ERR DRV_NAME ": big packet = %d\n", (u16)skb->len); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } spin_lock_irqsave(&db->lock, flags); @@ -624,7 +624,7 @@ static int uli526x_start_xmit(struct sk_buff *skb, struct net_device *dev) /* free this SKB */ dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c index 842b1a2c40d..6bc7540b216 100644 --- a/drivers/net/tulip/winbond-840.c +++ b/drivers/net/tulip/winbond-840.c @@ -1058,7 +1058,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n", dev->name, np->cur_tx, entry); } - return 0; + return NETDEV_TX_OK; } static void netdev_tx_done(struct net_device *dev) diff --git a/drivers/net/tulip/xircom_cb.c b/drivers/net/tulip/xircom_cb.c index c2ca9f40e40..22b6a239fb3 100644 --- a/drivers/net/tulip/xircom_cb.c +++ b/drivers/net/tulip/xircom_cb.c @@ -434,7 +434,7 @@ static int xircom_start_xmit(struct sk_buff *skb, struct net_device *dev) card->transmit_used = nextdescriptor; leave("xircom-start_xmit - sent"); spin_unlock_irqrestore(&card->lock,flags); - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 027f7aba26a..dfc1054e4cb 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -398,12 +398,12 @@ static int tun_net_xmit(struct sk_buff *skb, struct net_device *dev) if (tun->flags & TUN_FASYNC) kill_fasync(&tun->fasync, SIGIO, POLL_IN); wake_up_interruptible(&tun->socket.wait); - return 0; + return NETDEV_TX_OK; drop: dev->stats.tx_dropped++; kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } static void tun_net_mclist(struct net_device *dev) @@ -997,7 +997,6 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) goto err_free_sk; } - err = -EINVAL; err = register_netdevice(tun->dev); if (err < 0) goto err_free_sk; diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c index cf25eb41b1c..2c26b4577e8 100644 --- a/drivers/net/typhoon.c +++ b/drivers/net/typhoon.c @@ -909,7 +909,7 @@ typhoon_start_tx(struct sk_buff *skb, struct net_device *dev) netif_wake_queue(dev); } - return 0; + return NETDEV_TX_OK; } static void diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index 40c6eba775c..ca476a58087 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -209,9 +209,10 @@ static struct sk_buff *get_new_skb(struct ucc_geth_private *ugeth, { struct sk_buff *skb = NULL; - skb = dev_alloc_skb(ugeth->ug_info->uf_info.max_rx_buf_length + - UCC_GETH_RX_DATA_BUF_ALIGNMENT); - + skb = __skb_dequeue(&ugeth->rx_recycle); + if (!skb) + skb = dev_alloc_skb(ugeth->ug_info->uf_info.max_rx_buf_length + + UCC_GETH_RX_DATA_BUF_ALIGNMENT); if (skb == NULL) return NULL; @@ -1986,6 +1987,8 @@ static void ucc_geth_memclean(struct ucc_geth_private *ugeth) iounmap(ugeth->ug_regs); ugeth->ug_regs = NULL; } + + skb_queue_purge(&ugeth->rx_recycle); } static void ucc_geth_set_multi(struct net_device *dev) @@ -2202,6 +2205,8 @@ static int ucc_struct_init(struct ucc_geth_private *ugeth) return -ENOMEM; } + skb_queue_head_init(&ugeth->rx_recycle); + return 0; } @@ -3173,7 +3178,7 @@ static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev) #endif spin_unlock_irq(&ugeth->lock); - return 0; + return NETDEV_TX_OK; } static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit) @@ -3208,8 +3213,10 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit if (netif_msg_rx_err(ugeth)) ugeth_err("%s, %d: ERROR!!! skb - 0x%08x", __func__, __LINE__, (u32) skb); - if (skb) - dev_kfree_skb_any(skb); + if (skb) { + skb->data = skb->head + NET_SKB_PAD; + __skb_queue_head(&ugeth->rx_recycle, skb); + } ugeth->rx_skbuff[rxQ][ugeth->skb_currx[rxQ]] = NULL; dev->stats.rx_dropped++; @@ -3267,6 +3274,8 @@ static int ucc_geth_tx(struct net_device *dev, u8 txQ) /* Normal processing. */ while ((bd_status & T_R) == 0) { + struct sk_buff *skb; + /* BD contains already transmitted buffer. */ /* Handle the transmitted buffer and release */ /* the BD to be used with the current frame */ @@ -3276,9 +3285,16 @@ static int ucc_geth_tx(struct net_device *dev, u8 txQ) dev->stats.tx_packets++; - /* Free the sk buffer associated with this TxBD */ - dev_kfree_skb(ugeth-> - tx_skbuff[txQ][ugeth->skb_dirtytx[txQ]]); + skb = ugeth->tx_skbuff[txQ][ugeth->skb_dirtytx[txQ]]; + + if (skb_queue_len(&ugeth->rx_recycle) < RX_BD_RING_LEN && + skb_recycle_check(skb, + ugeth->ug_info->uf_info.max_rx_buf_length + + UCC_GETH_RX_DATA_BUF_ALIGNMENT)) + __skb_queue_head(&ugeth->rx_recycle, skb); + else + dev_kfree_skb(skb); + ugeth->tx_skbuff[txQ][ugeth->skb_dirtytx[txQ]] = NULL; ugeth->skb_dirtytx[txQ] = (ugeth->skb_dirtytx[txQ] + @@ -3307,16 +3323,16 @@ static int ucc_geth_poll(struct napi_struct *napi, int budget) ug_info = ugeth->ug_info; - howmany = 0; - for (i = 0; i < ug_info->numQueuesRx; i++) - howmany += ucc_geth_rx(ugeth, i, budget - howmany); - /* Tx event processing */ spin_lock(&ugeth->lock); for (i = 0; i < ug_info->numQueuesTx; i++) ucc_geth_tx(ugeth->ndev, i); spin_unlock(&ugeth->lock); + howmany = 0; + for (i = 0; i < ug_info->numQueuesRx; i++) + howmany += ucc_geth_rx(ugeth, i, budget - howmany); + if (howmany < budget) { napi_complete(napi); setbits32(ugeth->uccf->p_uccm, UCCE_RX_EVENTS | UCCE_TX_EVENTS); diff --git a/drivers/net/ucc_geth.h b/drivers/net/ucc_geth.h index 195ab267ead..cfb31afc08a 100644 --- a/drivers/net/ucc_geth.h +++ b/drivers/net/ucc_geth.h @@ -1212,6 +1212,8 @@ struct ucc_geth_private { /* index of the first skb which hasn't been transmitted yet. */ u16 skb_dirtytx[NUM_TX_QUEUES]; + struct sk_buff_head rx_recycle; + struct ugeth_mii_info *mii_info; struct phy_device *phydev; phy_interface_t phy_interface; diff --git a/drivers/net/usb/catc.c b/drivers/net/usb/catc.c index b9dd4257428..7abdc4abbe0 100644 --- a/drivers/net/usb/catc.c +++ b/drivers/net/usb/catc.c @@ -448,7 +448,7 @@ static int catc_start_xmit(struct sk_buff *skb, struct net_device *netdev) dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } static void catc_tx_timeout(struct net_device *netdev) diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index f8c6d7ea726..ffe41063573 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -780,7 +780,7 @@ static int hso_net_start_xmit(struct sk_buff *skb, struct net_device *net) netif_stop_queue(net); if (hso_get_activity(odev->parent) == -EAGAIN) { odev->skb_tx_buf = skb; - return 0; + return NETDEV_TX_OK; } /* log if asked */ diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c index e0131478971..09a5bd38156 100644 --- a/drivers/net/usb/kaweth.c +++ b/drivers/net/usb/kaweth.c @@ -829,7 +829,7 @@ static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net) kaweth->stats.tx_errors++; netif_start_queue(net); spin_unlock_irq(&kaweth->device_lock); - return 0; + return NETDEV_TX_OK; } } @@ -864,7 +864,7 @@ skip: spin_unlock_irq(&kaweth->device_lock); - return 0; + return NETDEV_TX_OK; } /**************************************************************** diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c index 73acbd244aa..632d1aeda57 100644 --- a/drivers/net/usb/pegasus.c +++ b/drivers/net/usb/pegasus.c @@ -914,7 +914,7 @@ static int pegasus_start_xmit(struct sk_buff *skb, struct net_device *net) } dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } static struct net_device_stats *pegasus_netdev_stats(struct net_device *dev) diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c index fcc6fa0905d..bac8b77fb25 100644 --- a/drivers/net/usb/rtl8150.c +++ b/drivers/net/usb/rtl8150.c @@ -753,7 +753,7 @@ static int rtl8150_start_xmit(struct sk_buff *skb, struct net_device *netdev) netdev->trans_start = jiffies; } - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 1097c72e44d..f1d753daa5b 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -189,17 +189,17 @@ static int veth_xmit(struct sk_buff *skb, struct net_device *dev) rcv_stats->rx_packets++; netif_rx(skb); - return 0; + return NETDEV_TX_OK; tx_drop: kfree_skb(skb); stats->tx_dropped++; - return 0; + return NETDEV_TX_OK; rx_drop: kfree_skb(skb); rcv_stats->rx_dropped++; - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index d3489a3c4c0..71522015831 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -1225,7 +1225,7 @@ static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev) entry = rp->cur_tx % TX_RING_SIZE; if (skb_padto(skb, ETH_ZLEN)) - return 0; + return NETDEV_TX_OK; rp->tx_skbuff[entry] = skb; @@ -1237,7 +1237,7 @@ static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb(skb); rp->tx_skbuff[entry] = NULL; dev->stats.tx_dropped++; - return 0; + return NETDEV_TX_OK; } /* Padding is not copied and so must be redone. */ @@ -1285,7 +1285,7 @@ static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev) printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n", dev->name, rp->cur_tx-1, entry); } - return 0; + return NETDEV_TX_OK; } /* The interrupt handler does all of the Rx thread work and cleans up diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index 3ba35956327..42365e5f931 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -2098,7 +2098,7 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev) #ifdef VELOCITY_ZERO_COPY_SUPPORT if (skb_shinfo(skb)->nr_frags > 6 && __skb_linearize(skb)) { kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } #endif diff --git a/drivers/net/vxge/vxge-config.c b/drivers/net/vxge/vxge-config.c index 58d2551c78e..9e94c4b0fb1 100644 --- a/drivers/net/vxge/vxge-config.c +++ b/drivers/net/vxge/vxge-config.c @@ -313,14 +313,6 @@ __vxge_hw_device_reg_addr_get(struct __vxge_hw_device *hldev) hldev->kdfc = (u8 __iomem *)(hldev->bar0 + VXGE_HW_TOC_GET_KDFC_INITIAL_OFFSET(val64)); break; - case 2: - hldev->kdfc = (u8 __iomem *)(hldev->bar1 + - VXGE_HW_TOC_GET_KDFC_INITIAL_OFFSET(val64)); - break; - case 4: - hldev->kdfc = (u8 __iomem *)(hldev->bar2 + - VXGE_HW_TOC_GET_KDFC_INITIAL_OFFSET(val64)); - break; default: break; } @@ -831,8 +823,6 @@ vxge_hw_device_initialize( sizeof(struct vxge_hw_device_config)); hldev->bar0 = attr->bar0; - hldev->bar1 = attr->bar1; - hldev->bar2 = attr->bar2; hldev->pdev = attr->pdev; hldev->uld_callbacks.link_up = attr->uld_callbacks.link_up; diff --git a/drivers/net/vxge/vxge-config.h b/drivers/net/vxge/vxge-config.h index afbdf6f4d22..224acea771e 100644 --- a/drivers/net/vxge/vxge-config.h +++ b/drivers/net/vxge/vxge-config.h @@ -682,8 +682,6 @@ struct __vxge_hw_vpath_handle{ * @major_revision: PCI Device major revision * @minor_revision: PCI Device minor revision * @bar0: BAR0 virtual address. - * @bar1: BAR1 virtual address. - * @bar2: BAR2 virtual address. * @pdev: Physical device handle * @config: Confguration passed by the LL driver at initialization * @link_state: Link state @@ -698,8 +696,6 @@ struct __vxge_hw_device { u8 major_revision; u8 minor_revision; void __iomem *bar0; - void __iomem *bar1; - void __iomem *bar2; struct pci_dev *pdev; struct net_device *ndev; struct vxge_hw_device_config config; @@ -788,17 +784,13 @@ struct vxge_hw_device_hw_info { /** * struct vxge_hw_device_attr - Device memory spaces. * @bar0: BAR0 virtual address. - * @bar1: BAR1 virtual address. - * @bar2: BAR2 virtual address. * @pdev: PCI device object. * - * Device memory spaces. Includes configuration, BAR0, BAR1, etc. per device + * Device memory spaces. Includes configuration, BAR0 etc. per device * mapped memories. Also, includes a pointer to OS-specific PCI device object. */ struct vxge_hw_device_attr { void __iomem *bar0; - void __iomem *bar1; - void __iomem *bar2; struct pci_dev *pdev; struct vxge_hw_uld_cbs uld_callbacks; }; diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index 6034497536a..7b5402b50d0 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c @@ -374,10 +374,10 @@ vxge_rx_complete(struct vxge_ring *ring, struct sk_buff *skb, u16 vlan, if (ring->vlgrp && ext_info->vlan && (ring->vlan_tag_strip == VXGE_HW_VPATH_RPA_STRIP_VLAN_TAG_ENABLE)) - vlan_gro_receive(&ring->napi, ring->vlgrp, + vlan_gro_receive(ring->napi_p, ring->vlgrp, ext_info->vlan, skb); else - napi_gro_receive(&ring->napi, skb); + napi_gro_receive(ring->napi_p, skb); } else { if (ring->vlgrp && vlan && (ring->vlan_tag_strip == @@ -454,6 +454,8 @@ vxge_rx_1b_compl(struct __vxge_hw_ring *ringh, void *dtr, vxge_hw_ring_rxd_1b_get(ringh, dtr, &dma_sizes); pkt_length = dma_sizes; + pkt_length -= ETH_FCS_LEN; + vxge_debug_rx(VXGE_TRACE, "%s: %s:%d Packet Length = %d", ring->ndev->name, __func__, __LINE__, pkt_length); @@ -817,7 +819,6 @@ vxge_xmit(struct sk_buff *skb, struct net_device *dev) u64 dma_pointer; struct vxge_tx_priv *txdl_priv = NULL; struct __vxge_hw_fifo *fifo_hw; - u32 max_mss = 0x0; int offload_type; unsigned long flags = 0; int vpath_no = 0; @@ -969,10 +970,6 @@ vxge_xmit(struct sk_buff *skb, struct net_device *dev) int mss = vxge_tcp_mss(skb); if (mss) { - max_mss = dev->mtu + ETH_HLEN - - VXGE_HW_TCPIP_HEADER_MAX_SIZE; - if (mss > max_mss) - mss = max_mss; vxge_debug_tx(VXGE_TRACE, "%s: %s:%d mss = %d", dev->name, __func__, __LINE__, mss); @@ -1000,7 +997,7 @@ vxge_xmit(struct sk_buff *skb, struct net_device *dev) VXGE_COMPLETE_VPATH_TX(fifo); vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d Exiting...", dev->name, __func__, __LINE__); - return 0; + return NETDEV_TX_OK; _exit0: vxge_debug_tx(VXGE_TRACE, "%s: pci_map_page failed", dev->name); @@ -1024,7 +1021,7 @@ _exit2: spin_unlock_irqrestore(&fifo->tx_lock, flags); VXGE_COMPLETE_VPATH_TX(fifo); - return 0; + return NETDEV_TX_OK; } /* @@ -2137,16 +2134,16 @@ int vxge_open_vpaths(struct vxgedev *vdev) */ static irqreturn_t vxge_isr_napi(int irq, void *dev_id) { - struct __vxge_hw_device *hldev = (struct __vxge_hw_device *)dev_id; - struct vxgedev *vdev; struct net_device *dev; + struct __vxge_hw_device *hldev; u64 reason; enum vxge_hw_status status; + struct vxgedev *vdev = (struct vxgedev *) dev_id;; vxge_debug_intr(VXGE_TRACE, "%s:%d", __func__, __LINE__); - dev = hldev->ndev; - vdev = netdev_priv(dev); + dev = vdev->ndev; + hldev = (struct __vxge_hw_device *)pci_get_drvdata(vdev->pdev); if (pci_channel_offline(vdev->pdev)) return IRQ_NONE; @@ -2417,15 +2414,13 @@ static void vxge_rem_isr(struct vxgedev *vdev) #endif if (vdev->config.intr_type == INTA) { synchronize_irq(vdev->pdev->irq); - free_irq(vdev->pdev->irq, hldev); + free_irq(vdev->pdev->irq, vdev); } } static int vxge_add_isr(struct vxgedev *vdev) { int ret = 0; - struct __vxge_hw_device *hldev = - (struct __vxge_hw_device *) pci_get_drvdata(vdev->pdev); #ifdef CONFIG_PCI_MSI int vp_idx = 0, intr_idx = 0, intr_cnt = 0, msix_idx = 0, irq_req = 0; u64 function_mode = vdev->config.device_hw_info.function_mode; @@ -2579,7 +2574,7 @@ INTA_MODE: if (vdev->config.intr_type == INTA) { ret = request_irq((int) vdev->pdev->irq, vxge_isr_napi, - IRQF_SHARED, vdev->desc[0], hldev); + IRQF_SHARED, vdev->desc[0], vdev); if (ret) { vxge_debug_init(VXGE_ERR, "%s %s-%d: ISR registration failed", @@ -2712,11 +2707,15 @@ vxge_open(struct net_device *dev) netif_napi_add(dev, &vdev->napi, vxge_poll_inta, vdev->config.napi_weight); napi_enable(&vdev->napi); + for (i = 0; i < vdev->no_of_vpath; i++) + vdev->vpaths[i].ring.napi_p = &vdev->napi; } else { for (i = 0; i < vdev->no_of_vpath; i++) { netif_napi_add(dev, &vdev->vpaths[i].ring.napi, vxge_poll_msix, vdev->config.napi_weight); napi_enable(&vdev->vpaths[i].ring.napi); + vdev->vpaths[i].ring.napi_p = + &vdev->vpaths[i].ring.napi; } } @@ -2890,6 +2889,9 @@ int do_vxge_close(struct net_device *dev, int do_io) vdev = (struct vxgedev *)netdev_priv(dev); hldev = (struct __vxge_hw_device *) pci_get_drvdata(vdev->pdev); + if (unlikely(!is_vxge_card_up(vdev))) + return 0; + /* If vxge_handle_crit_err task is executing, * wait till it completes. */ while (test_and_set_bit(__VXGE_STATE_RESET_CARD, &vdev->state)) @@ -4152,18 +4154,6 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) attr.bar0, (unsigned long long)pci_resource_start(pdev, 0)); - attr.bar1 = pci_ioremap_bar(pdev, 2); - if (!attr.bar1) { - vxge_debug_init(VXGE_ERR, - "%s : cannot remap io memory bar2", __func__); - ret = -ENODEV; - goto _exit3; - } - vxge_debug_ll_config(VXGE_TRACE, - "pci ioremap bar1: %p:0x%llx", - attr.bar1, - (unsigned long long)pci_resource_start(pdev, 2)); - status = vxge_hw_device_hw_info_get(attr.bar0, &ll_config.device_hw_info); if (status != VXGE_HW_OK) { @@ -4171,17 +4161,17 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) "%s: Reading of hardware info failed." "Please try upgrading the firmware.", VXGE_DRIVER_NAME); ret = -EINVAL; - goto _exit4; + goto _exit3; } if (ll_config.device_hw_info.fw_version.major != - VXGE_DRIVER_VERSION_MAJOR) { + VXGE_DRIVER_FW_VERSION_MAJOR) { vxge_debug_init(VXGE_ERR, - "FW Ver.(maj): %d not driver's expected version: %d", - ll_config.device_hw_info.fw_version.major, - VXGE_DRIVER_VERSION_MAJOR); + "%s: Incorrect firmware version." + "Please upgrade the firmware to version 1.x.x", + VXGE_DRIVER_NAME); ret = -EINVAL; - goto _exit4; + goto _exit3; } vpath_mask = ll_config.device_hw_info.vpath_mask; @@ -4189,7 +4179,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) vxge_debug_ll_config(VXGE_TRACE, "%s: No vpaths available in device", VXGE_DRIVER_NAME); ret = -EINVAL; - goto _exit4; + goto _exit3; } vxge_debug_ll_config(VXGE_TRACE, @@ -4222,7 +4212,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) vxge_debug_ll_config(VXGE_ERR, "%s: No more vpaths to configure", VXGE_DRIVER_NAME); ret = 0; - goto _exit4; + goto _exit3; } /* Setting driver callbacks */ @@ -4235,7 +4225,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) vxge_debug_init(VXGE_ERR, "Failed to initialize device (%d)", status); ret = -EINVAL; - goto _exit4; + goto _exit3; } vxge_hw_device_debug_set(hldev, VXGE_ERR, VXGE_COMPONENT_LL); @@ -4260,7 +4250,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) if (vxge_device_register(hldev, &ll_config, high_dma, no_of_vpath, &vdev)) { ret = -EINVAL; - goto _exit5; + goto _exit4; } vxge_hw_device_debug_set(hldev, VXGE_TRACE, VXGE_COMPONENT_LL); @@ -4271,7 +4261,6 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) hldev->ndev = vdev->ndev; vdev->mtu = VXGE_HW_DEFAULT_MTU; vdev->bar0 = attr.bar0; - vdev->bar1 = attr.bar1; vdev->max_vpath_supported = max_vpath_supported; vdev->no_of_vpath = no_of_vpath; @@ -4336,6 +4325,27 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) ll_config.device_hw_info.fw_version.version, ll_config.device_hw_info.fw_date.date); + if (new_device) { + switch (ll_config.device_hw_info.function_mode) { + case VXGE_HW_FUNCTION_MODE_SINGLE_FUNCTION: + vxge_debug_init(VXGE_TRACE, + "%s: Single Function Mode Enabled", vdev->ndev->name); + break; + case VXGE_HW_FUNCTION_MODE_MULTI_FUNCTION: + vxge_debug_init(VXGE_TRACE, + "%s: Multi Function Mode Enabled", vdev->ndev->name); + break; + case VXGE_HW_FUNCTION_MODE_SRIOV: + vxge_debug_init(VXGE_TRACE, + "%s: Single Root IOV Mode Enabled", vdev->ndev->name); + break; + case VXGE_HW_FUNCTION_MODE_MRIOV: + vxge_debug_init(VXGE_TRACE, + "%s: Multi Root IOV Mode Enabled", vdev->ndev->name); + break; + } + } + vxge_print_parm(vdev, vpath_mask); /* Store the fw version for ethttool option */ @@ -4353,7 +4363,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) "%s: mac_addr_list : memory allocation failed", vdev->ndev->name); ret = -EPERM; - goto _exit6; + goto _exit5; } macaddr = (u8 *)&entry->macaddr; memcpy(macaddr, vdev->ndev->dev_addr, ETH_ALEN); @@ -4361,6 +4371,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) vdev->vpaths[i].mac_addr_cnt = 1; } + kfree(device_config); vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d Exiting...", vdev->ndev->name, __func__, __LINE__); @@ -4370,16 +4381,14 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) return 0; -_exit6: +_exit5: for (i = 0; i < vdev->no_of_vpath; i++) vxge_free_mac_add_list(&vdev->vpaths[i]); vxge_device_unregister(hldev); -_exit5: +_exit4: pci_disable_sriov(pdev); vxge_hw_device_terminate(hldev); -_exit4: - iounmap(attr.bar1); _exit3: iounmap(attr.bar0); _exit2: @@ -4438,7 +4447,6 @@ vxge_remove(struct pci_dev *pdev) kfree(vdev->vpaths); iounmap(vdev->bar0); - iounmap(vdev->bar1); pci_disable_sriov(pdev); diff --git a/drivers/net/vxge/vxge-main.h b/drivers/net/vxge/vxge-main.h index 9704b2bd432..18d824c3ab9 100644 --- a/drivers/net/vxge/vxge-main.h +++ b/drivers/net/vxge/vxge-main.h @@ -21,7 +21,7 @@ #define VXGE_DRIVER_NAME "vxge" #define VXGE_DRIVER_VENDOR "Neterion, Inc" -#define VXGE_DRIVER_VERSION_MAJOR 0 +#define VXGE_DRIVER_FW_VERSION_MAJOR 1 #define DRV_VERSION VXGE_VERSION_MAJOR"."VXGE_VERSION_MINOR"."\ VXGE_VERSION_FIX"."VXGE_VERSION_BUILD"-"\ @@ -260,6 +260,7 @@ struct vxge_ring { int gro_enable; struct napi_struct napi; + struct napi_struct *napi_p; #define VXGE_MAX_MAC_ADDR_COUNT 30 @@ -363,7 +364,6 @@ struct vxgedev { struct __vxge_hw_vpath_handle *vp_handles[VXGE_HW_MAX_VIRTUAL_PATHS]; void __iomem *bar0; - void __iomem *bar1; struct vxge_sw_stats stats; int mtu; /* Below variables are used for vpath selection to transmit a packet */ diff --git a/drivers/net/vxge/vxge-reg.h b/drivers/net/vxge/vxge-reg.h index 10f4da32929..9a3b823e08d 100644 --- a/drivers/net/vxge/vxge-reg.h +++ b/drivers/net/vxge/vxge-reg.h @@ -1784,7 +1784,7 @@ struct vxge_hw_mrpcim_reg { #define VXGE_HW_XMAC_GEN_ERR_REG_XMACJ_XMAC_FSM_ERR vxge_mBIT(63) /*0x01e18*/ u64 xmac_gen_err_mask; /*0x01e20*/ u64 xmac_gen_err_alarm; -/*0x01e28*/ u64 xmac_link_err_port_reg[2]; +/*0x01e28*/ u64 xmac_link_err_port0_reg; #define VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMACJ_PORT_DOWN vxge_mBIT(3) #define VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMACJ_PORT_UP vxge_mBIT(7) #define VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMACJ_PORT_WENT_DOWN vxge_mBIT(11) @@ -1798,8 +1798,11 @@ struct vxge_hw_mrpcim_reg { #define VXGE_HW_XMAC_LINK_ERR_PORT_REG_RATEMGMT_LASI_INV vxge_mBIT(39) #define VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMDIO_MDIO_MGR_ACCESS_COMPLETE \ vxge_mBIT(47) -/*0x01e30*/ u64 xmac_link_err_port_mask[2]; -/*0x01e38*/ u64 xmac_link_err_port_alarm[2]; +/*0x01e30*/ u64 xmac_link_err_port0_mask; +/*0x01e38*/ u64 xmac_link_err_port0_alarm; +/*0x01e40*/ u64 xmac_link_err_port1_reg; +/*0x01e48*/ u64 xmac_link_err_port1_mask; +/*0x01e50*/ u64 xmac_link_err_port1_alarm; /*0x01e58*/ u64 xgxs_gen_err_reg; #define VXGE_HW_XGXS_GEN_ERR_REG_XGXS_XGXS_FSM_ERR vxge_mBIT(63) /*0x01e60*/ u64 xgxs_gen_err_mask; diff --git a/drivers/net/vxge/vxge-traffic.h b/drivers/net/vxge/vxge-traffic.h index 7567a1140d0..8260b91fd79 100644 --- a/drivers/net/vxge/vxge-traffic.h +++ b/drivers/net/vxge/vxge-traffic.h @@ -35,8 +35,6 @@ VXGE_HW_HEADER_VLAN_SIZE + \ VXGE_HW_HEADER_SNAP_SIZE) -#define VXGE_HW_TCPIP_HEADER_MAX_SIZE (64 + 64) - /* 32bit alignments */ #define VXGE_HW_HEADER_ETHERNET_II_802_3_ALIGN 2 #define VXGE_HW_HEADER_802_2_SNAP_ALIGN 2 diff --git a/drivers/net/vxge/vxge-version.h b/drivers/net/vxge/vxge-version.h index 82786ffb7dd..580c6eb077b 100644 --- a/drivers/net/vxge/vxge-version.h +++ b/drivers/net/vxge/vxge-version.h @@ -18,6 +18,6 @@ #define VXGE_VERSION_MAJOR "2" #define VXGE_VERSION_MINOR "0" #define VXGE_VERSION_FIX "4" -#define VXGE_VERSION_BUILD "17795" +#define VXGE_VERSION_BUILD "17899" #define VXGE_VERSION_FOR "k" #endif diff --git a/drivers/net/wan/cycx_x25.c b/drivers/net/wan/cycx_x25.c index f525f9fe74d..4ae9bd297cc 100644 --- a/drivers/net/wan/cycx_x25.c +++ b/drivers/net/wan/cycx_x25.c @@ -663,7 +663,7 @@ static int cycx_netdevice_hard_start_xmit(struct sk_buff *skb, free_packet: dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* Get Ethernet-style interface statistics. diff --git a/drivers/net/wan/dlci.c b/drivers/net/wan/dlci.c index 2fa275a58f9..8526b6d1ee4 100644 --- a/drivers/net/wan/dlci.c +++ b/drivers/net/wan/dlci.c @@ -194,7 +194,7 @@ static int dlci_transmit(struct sk_buff *skb, struct net_device *dev) ret = 0; if (!skb || !dev) - return(0); + return NETDEV_TX_OK; dlp = netdev_priv(dev); @@ -219,7 +219,7 @@ static int dlci_transmit(struct sk_buff *skb, struct net_device *dev) /* Alan Cox recommends always returning 0, and always freeing the packet */ /* experience suggest a slightly more conservative approach */ - if (!ret) + if (ret == NETDEV_TX_OK) { dev_kfree_skb(skb); netif_wake_queue(dev); diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c index 8face5db8f3..e81946d9854 100644 --- a/drivers/net/wan/dscc4.c +++ b/drivers/net/wan/dscc4.c @@ -1182,7 +1182,7 @@ static int dscc4_start_xmit(struct sk_buff *skb, struct net_device *dev) if (dscc4_tx_quiescent(dpriv, dev)) dscc4_do_tx(dpriv, dev); - return 0; + return NETDEV_TX_OK; } static int dscc4_close(struct net_device *dev) diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c index 25c9ef6a181..20a1237a3d7 100644 --- a/drivers/net/wan/farsync.c +++ b/drivers/net/wan/farsync.c @@ -792,25 +792,6 @@ fst_process_rx_status(int rx_status, char *name) */ break; } - - case NET_RX_CN_LOW: - { - dbg(DBG_ASS, "%s: Receive Low Congestion\n", name); - break; - } - - case NET_RX_CN_MOD: - { - dbg(DBG_ASS, "%s: Receive Moderate Congestion\n", name); - break; - } - - case NET_RX_CN_HIGH: - { - dbg(DBG_ASS, "%s: Receive High Congestion\n", name); - break; - } - case NET_RX_DROP: { dbg(DBG_ASS, "%s: Received packet dropped\n", name); @@ -2313,7 +2294,7 @@ fst_start_xmit(struct sk_buff *skb, struct net_device *dev) dbg(DBG_ASS, "Tried to transmit but no carrier on card %d port %d\n", card->card_no, port->index); - return 0; + return NETDEV_TX_OK; } /* Drop it if it's too big! MTU failure ? */ @@ -2322,7 +2303,7 @@ fst_start_xmit(struct sk_buff *skb, struct net_device *dev) LEN_TX_BUFFER); dev_kfree_skb(skb); dev->stats.tx_errors++; - return 0; + return NETDEV_TX_OK; } /* @@ -2356,7 +2337,7 @@ fst_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->stats.tx_errors++; dbg(DBG_ASS, "Tx queue overflow card %d port %d\n", card->card_no, port->index); - return 0; + return NETDEV_TX_OK; } /* @@ -2373,7 +2354,7 @@ fst_start_xmit(struct sk_buff *skb, struct net_device *dev) fst_q_work_item(&fst_work_txq, card->card_no); tasklet_schedule(&fst_tx_task); - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c index bfa0161a02d..52438c76bf8 100644 --- a/drivers/net/wan/hdlc_fr.c +++ b/drivers/net/wan/hdlc_fr.c @@ -421,7 +421,7 @@ static int pvc_xmit(struct sk_buff *skb, struct net_device *dev) GFP_ATOMIC)) { dev->stats.tx_dropped++; dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } skb_put(skb, pad); memset(skb->data + len, 0, pad); @@ -435,13 +435,13 @@ static int pvc_xmit(struct sk_buff *skb, struct net_device *dev) dev->stats.tx_compressed++; skb->dev = pvc->frad; dev_queue_xmit(skb); - return 0; + return NETDEV_TX_OK; } } dev->stats.tx_dropped++; dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } static inline void fr_log_dlci_active(pvc_device *pvc) diff --git a/drivers/net/wan/lmc/lmc_main.c b/drivers/net/wan/lmc/lmc_main.c index 45b1822c962..d1492ae5d30 100644 --- a/drivers/net/wan/lmc/lmc_main.c +++ b/drivers/net/wan/lmc/lmc_main.c @@ -1428,7 +1428,7 @@ static int lmc_start_xmit(struct sk_buff *skb, struct net_device *dev) lmc_softc_t *sc = dev_to_sc(dev); u32 flag; int entry; - int ret = 0; + int ret = NETDEV_TX_OK; unsigned long flags; lmc_trace(dev, "lmc_start_xmit in"); diff --git a/drivers/net/wan/sbni.c b/drivers/net/wan/sbni.c index 3fb9dbc88a1..545178e6765 100644 --- a/drivers/net/wan/sbni.c +++ b/drivers/net/wan/sbni.c @@ -465,7 +465,7 @@ sbni_start_xmit( struct sk_buff *skb, struct net_device *dev ) prepare_to_send( skb, p ); spin_unlock( &nl->lock ); netif_start_queue( dev ); - return 0; + return NETDEV_TX_OK; } } @@ -485,7 +485,7 @@ sbni_start_xmit( struct sk_buff *skb, struct net_device *dev ) prepare_to_send( skb, dev ); spin_unlock( &nl->lock ); - return 0; + return NETDEV_TX_OK; } #endif /* CONFIG_SBNI_MULTILINE */ diff --git a/drivers/net/wan/wanxl.c b/drivers/net/wan/wanxl.c index e4ad7b6b52e..03b76adbe5f 100644 --- a/drivers/net/wan/wanxl.c +++ b/drivers/net/wan/wanxl.c @@ -310,7 +310,7 @@ static int wanxl_xmit(struct sk_buff *skb, struct net_device *dev) } spin_unlock(&port->lock); - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c index d67e208ab37..1047920e742 100644 --- a/drivers/net/wan/x25_asy.c +++ b/drivers/net/wan/x25_asy.c @@ -308,7 +308,7 @@ static int x25_asy_xmit(struct sk_buff *skb, struct net_device *dev) printk(KERN_ERR "%s: xmit call when iface is down\n", dev->name); kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } switch (skb->data[0]) { @@ -319,14 +319,14 @@ static int x25_asy_xmit(struct sk_buff *skb, struct net_device *dev) if (err != LAPB_OK) printk(KERN_ERR "x25_asy: lapb_connect_request error - %d\n", err); kfree_skb(skb); - return 0; + return NETDEV_TX_OK; case 0x02: /* Disconnect request .. do nothing - hang up ?? */ err = lapb_disconnect_request(dev); if (err != LAPB_OK) printk(KERN_ERR "x25_asy: lapb_disconnect_request error - %d\n", err); default: kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } skb_pull(skb, 1); /* Remove control byte */ /* @@ -344,9 +344,9 @@ static int x25_asy_xmit(struct sk_buff *skb, struct net_device *dev) if (err != LAPB_OK) { printk(KERN_ERR "x25_asy: lapb_data_request error - %d\n", err); kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index c70604f0329..49f3139a3fe 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -1927,7 +1927,7 @@ static int mpi_start_xmit(struct sk_buff *skb, struct net_device *dev) { if (!skb) { airo_print_err(dev->name, "%s: skb == NULL!",__func__); - return 0; + return NETDEV_TX_OK; } npacks = skb_queue_len (&ai->txq); @@ -1938,7 +1938,7 @@ static int mpi_start_xmit(struct sk_buff *skb, struct net_device *dev) { return NETDEV_TX_BUSY; } skb_queue_tail (&ai->txq, skb); - return 0; + return NETDEV_TX_OK; } spin_lock_irqsave(&ai->aux_lock, flags); @@ -1951,7 +1951,7 @@ static int mpi_start_xmit(struct sk_buff *skb, struct net_device *dev) { set_bit(FLAG_PENDING_XMIT, &ai->flags); mpi_send_packet (dev); } - return 0; + return NETDEV_TX_OK; } /* @@ -2127,7 +2127,7 @@ static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) { if ( skb == NULL ) { airo_print_err(dev->name, "%s: skb == NULL!", __func__); - return 0; + return NETDEV_TX_OK; } /* Find a vacant FID */ @@ -2155,7 +2155,7 @@ static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) { wake_up_interruptible(&priv->thr_wait); } else airo_end_xmit(dev); - return 0; + return NETDEV_TX_OK; } static void airo_end_xmit11(struct net_device *dev) { @@ -2199,7 +2199,7 @@ static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) { if ( skb == NULL ) { airo_print_err(dev->name, "%s: skb == NULL!", __func__); - return 0; + return NETDEV_TX_OK; } /* Find a vacant FID */ @@ -2227,7 +2227,7 @@ static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) { wake_up_interruptible(&priv->thr_wait); } else airo_end_xmit11(dev); - return 0; + return NETDEV_TX_OK; } static void airo_read_stats(struct net_device *dev) diff --git a/drivers/net/wireless/arlan-main.c b/drivers/net/wireless/arlan-main.c index d84caf198a2..d479f4735aa 100644 --- a/drivers/net/wireless/arlan-main.c +++ b/drivers/net/wireless/arlan-main.c @@ -1193,7 +1193,7 @@ static int arlan_tx(struct sk_buff *skb, struct net_device *dev) arlan_process_interrupt(dev); ARLAN_DEBUG_EXIT("arlan_tx"); - return 0; + return NETDEV_TX_OK; bad_end: arlan_process_interrupt(dev); diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c index 291a94bd46f..05813bc3e30 100644 --- a/drivers/net/wireless/atmel.c +++ b/drivers/net/wireless/atmel.c @@ -793,13 +793,13 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) !(*priv->present_callback)(priv->card)) { dev->stats.tx_errors++; dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } if (priv->station_state != STATION_STATE_READY) { dev->stats.tx_errors++; dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* first ensure the timer func cannot run */ @@ -856,7 +856,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) spin_unlock_bh(&priv->timerlock); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } static void atmel_transmit_management_frame(struct atmel_private *priv, diff --git a/drivers/net/wireless/hostap/hostap_80211_tx.c b/drivers/net/wireless/hostap/hostap_80211_tx.c index d313b005114..1fe1bbabb90 100644 --- a/drivers/net/wireless/hostap/hostap_80211_tx.c +++ b/drivers/net/wireless/hostap/hostap_80211_tx.c @@ -75,7 +75,7 @@ int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev) printk(KERN_DEBUG "%s: hostap_data_start_xmit: short skb " "(len=%d)\n", dev->name, skb->len); kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } if (local->ddev != dev) { @@ -89,14 +89,14 @@ int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev) printk(KERN_DEBUG "%s: prism2_tx: trying to use " "AP device with Ethernet net dev\n", dev->name); kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } } else { if (local->iw_mode == IW_MODE_REPEAT) { printk(KERN_DEBUG "%s: prism2_tx: trying to use " "non-WDS link in Repeater mode\n", dev->name); kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } else if (local->iw_mode == IW_MODE_INFRA && (local->wds_type & HOSTAP_WDS_AP_CLIENT) && memcmp(skb->data + ETH_ALEN, dev->dev_addr, @@ -210,13 +210,13 @@ int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev) skb = skb_unshare(skb, GFP_ATOMIC); if (skb == NULL) { iface->stats.tx_dropped++; - return 0; + return NETDEV_TX_OK; } if (pskb_expand_head(skb, need_headroom, need_tailroom, GFP_ATOMIC)) { kfree_skb(skb); iface->stats.tx_dropped++; - return 0; + return NETDEV_TX_OK; } } else if (skb_headroom(skb) < need_headroom) { struct sk_buff *tmp = skb; @@ -224,13 +224,13 @@ int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev) kfree_skb(tmp); if (skb == NULL) { iface->stats.tx_dropped++; - return 0; + return NETDEV_TX_OK; } } else { skb = skb_unshare(skb, GFP_ATOMIC); if (skb == NULL) { iface->stats.tx_dropped++; - return 0; + return NETDEV_TX_OK; } } @@ -256,7 +256,7 @@ int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev) /* Send IEEE 802.11 encapsulated frame using the master radio device */ skb->dev = local->dev; dev_queue_xmit(skb); - return 0; + return NETDEV_TX_OK; } @@ -276,7 +276,7 @@ int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev) printk(KERN_DEBUG "%s: hostap_mgmt_start_xmit: short skb " "(len=%d)\n", dev->name, skb->len); kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } iface->stats.tx_packets++; @@ -301,7 +301,7 @@ int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev) /* Send IEEE 802.11 encapsulated frame using the master radio device */ skb->dev = local->dev; dev_queue_xmit(skb); - return 0; + return NETDEV_TX_OK; } @@ -396,7 +396,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev) printk(KERN_DEBUG "%s: invalid skb->cb magic (0x%08x, " "expected 0x%08x)\n", dev->name, meta->magic, HOSTAP_SKB_TX_DATA_MAGIC); - ret = 0; + ret = NETDEV_TX_OK; iface->stats.tx_dropped++; goto fail; } @@ -414,7 +414,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev) if (skb->len < 24) { printk(KERN_DEBUG "%s: hostap_master_start_xmit: short skb " "(len=%d)\n", dev->name, skb->len); - ret = 0; + ret = NETDEV_TX_OK; iface->stats.tx_dropped++; goto fail; } @@ -441,13 +441,13 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->name, meta->ethertype); hostap_dump_tx_80211(dev->name, skb); - ret = 0; /* drop packet */ + ret = NETDEV_TX_OK; /* drop packet */ iface->stats.tx_dropped++; goto fail; } break; case AP_TX_DROP: - ret = 0; /* drop packet */ + ret = NETDEV_TX_OK; /* drop packet */ iface->stats.tx_dropped++; goto fail; case AP_TX_RETRY: @@ -455,7 +455,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev) case AP_TX_BUFFERED: /* do not free skb here, it will be freed when the * buffered frame is sent/timed out */ - ret = 0; + ret = NETDEV_TX_OK; goto tx_exit; } @@ -501,7 +501,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev) "frame (drop_unencrypted=1)\n", dev->name); } iface->stats.tx_dropped++; - ret = 0; + ret = NETDEV_TX_OK; goto fail; } @@ -510,7 +510,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev) if (skb == NULL) { printk(KERN_DEBUG "%s: TX - encryption failed\n", dev->name); - ret = 0; + ret = NETDEV_TX_OK; goto fail; } meta = (struct hostap_skb_tx_data *) skb->cb; @@ -519,23 +519,23 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev) "expected 0x%08x) after hostap_tx_encrypt\n", dev->name, meta->magic, HOSTAP_SKB_TX_DATA_MAGIC); - ret = 0; + ret = NETDEV_TX_OK; iface->stats.tx_dropped++; goto fail; } } if (local->func->tx == NULL || local->func->tx(skb, dev)) { - ret = 0; + ret = NETDEV_TX_OK; iface->stats.tx_dropped++; } else { - ret = 0; + ret = NETDEV_TX_OK; iface->stats.tx_packets++; iface->stats.tx_bytes += skb->len; } fail: - if (!ret && skb) + if (ret == NETDEV_TX_OK && skb) dev_kfree_skb(skb); tx_exit: if (tx.sta_ptr) diff --git a/drivers/net/wireless/ipw2x00/libipw_tx.c b/drivers/net/wireless/ipw2x00/libipw_tx.c index da2ad5437ce..2e8f84fb29f 100644 --- a/drivers/net/wireless/ipw2x00/libipw_tx.c +++ b/drivers/net/wireless/ipw2x00/libipw_tx.c @@ -527,13 +527,13 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) if (ret == 0) { dev->stats.tx_packets++; dev->stats.tx_bytes += txb->payload_size; - return 0; + return NETDEV_TX_OK; } ieee80211_txb_free(txb); } - return 0; + return NETDEV_TX_OK; failed: spin_unlock_irqrestore(&ieee->lock, flags); diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index a111bda392e..c47ef48f31c 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -314,7 +314,7 @@ static int hwsim_mon_xmit(struct sk_buff *skb, struct net_device *dev) { /* TODO: allow packet injection */ dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c index d63c8992f22..712f26eef35 100644 --- a/drivers/net/wireless/netwave_cs.c +++ b/drivers/net/wireless/netwave_cs.c @@ -1047,7 +1047,7 @@ static int netwave_start_xmit(struct sk_buff *skb, struct net_device *dev) { } dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* netwave_start_xmit */ /* diff --git a/drivers/net/wireless/prism54/islpci_eth.c b/drivers/net/wireless/prism54/islpci_eth.c index 8f621099344..c255d9c6a5f 100644 --- a/drivers/net/wireless/prism54/islpci_eth.c +++ b/drivers/net/wireless/prism54/islpci_eth.c @@ -234,7 +234,7 @@ islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev) /* unlock the driver code */ spin_unlock_irqrestore(&priv->slock, flags); - return 0; + return NETDEV_TX_OK; drop_free: ndev->stats.tx_dropped++; diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index b10b0383dfa..64e574c3655 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -937,7 +937,7 @@ static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev) if (length < ETH_ZLEN) { if (skb_padto(skb, ETH_ZLEN)) - return 0; + return NETDEV_TX_OK; length = ETH_ZLEN; } switch (ray_hw_xmit(skb->data, length, dev, DATA_TYPE)) { @@ -951,9 +951,9 @@ static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev) default: dev->trans_start = jiffies; dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } - return 0; + return NETDEV_TX_OK; } /* ray_dev_start_xmit */ /*===========================================================================*/ diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c index 38366a56b71..73300c226f6 100644 --- a/drivers/net/wireless/strip.c +++ b/drivers/net/wireless/strip.c @@ -1582,7 +1582,7 @@ static int strip_xmit(struct sk_buff *skb, struct net_device *dev) if (skb) dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c index ab7fc5c0c8b..5cb5329a20d 100644 --- a/drivers/net/wireless/wavelan.c +++ b/drivers/net/wireless/wavelan.c @@ -2891,7 +2891,7 @@ static int wavelan_packet_xmit(struct sk_buff *skb, struct net_device * dev) #ifdef DEBUG_TX_TRACE printk(KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name); #endif - return 0; + return NETDEV_TX_OK; } /*********************** HARDWARE CONFIGURATION ***********************/ diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c index 6af706408ac..9dd241adc37 100644 --- a/drivers/net/wireless/wavelan_cs.c +++ b/drivers/net/wireless/wavelan_cs.c @@ -3113,7 +3113,7 @@ wavelan_packet_xmit(struct sk_buff * skb, * able to detect collisions, therefore in theory we don't really * need to pad. Jean II */ if (skb_padto(skb, ETH_ZLEN)) - return 0; + return NETDEV_TX_OK; wv_packet_write(dev, skb->data, skb->len); @@ -3122,7 +3122,7 @@ wavelan_packet_xmit(struct sk_buff * skb, #ifdef DEBUG_TX_TRACE printk(KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name); #endif - return(0); + return NETDEV_TX_OK; } /********************** HARDWARE CONFIGURATION **********************/ diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index e3e96bb2c24..a83a5621ec4 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c @@ -1348,7 +1348,6 @@ static int wl3501_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) if (rc) { ++dev->stats.tx_dropped; netif_stop_queue(dev); - rc = NETDEV_TX_OK; } else { ++dev->stats.tx_packets; dev->stats.tx_bytes += skb->len; @@ -1358,7 +1357,7 @@ static int wl3501_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); } spin_unlock_irqrestore(&this->lock, flags); - return rc; + return NETDEV_TX_OK; } static int wl3501_open(struct net_device *dev) diff --git a/drivers/net/wireless/zd1201.c b/drivers/net/wireless/zd1201.c index 4430b8d92e2..dae1bfb7655 100644 --- a/drivers/net/wireless/zd1201.c +++ b/drivers/net/wireless/zd1201.c @@ -789,7 +789,7 @@ static int zd1201_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) if (!zd->mac_enabled || zd->monitor) { dev->stats.tx_dropped++; kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } netif_stop_queue(dev); @@ -826,7 +826,7 @@ static int zd1201_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) } kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } static void zd1201_tx_timeout(struct net_device *dev) diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 8d88daeed0c..3700c49d76c 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -558,12 +558,12 @@ static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock_irq(&np->tx_lock); - return 0; + return NETDEV_TX_OK; drop: dev->stats.tx_dropped++; dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } static int xennet_close(struct net_device *dev) diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c index 3c7a5053f1d..c3722b40a65 100644 --- a/drivers/net/yellowfin.c +++ b/drivers/net/yellowfin.c @@ -827,7 +827,7 @@ static int yellowfin_start_xmit(struct sk_buff *skb, struct net_device *dev) if (skb_padto(skb, len)) { yp->tx_skbuff[entry] = NULL; netif_wake_queue(dev); - return 0; + return NETDEV_TX_OK; } } } @@ -881,7 +881,7 @@ static int yellowfin_start_xmit(struct sk_buff *skb, struct net_device *dev) printk(KERN_DEBUG "%s: Yellowfin transmit frame #%d queued in slot %d.\n", dev->name, yp->cur_tx, entry); } - return 0; + return NETDEV_TX_OK; } /* The interrupt handler does all of the Rx thread work and cleans up diff --git a/drivers/net/znet.c b/drivers/net/znet.c index 0a6992d8611..7f9e14131a5 100644 --- a/drivers/net/znet.c +++ b/drivers/net/znet.c @@ -546,7 +546,7 @@ static int znet_send_packet(struct sk_buff *skb, struct net_device *dev) if (length < ETH_ZLEN) { if (skb_padto(skb, ETH_ZLEN)) - return 0; + return NETDEV_TX_OK; length = ETH_ZLEN; } @@ -600,7 +600,7 @@ static int znet_send_packet(struct sk_buff *skb, struct net_device *dev) printk(KERN_DEBUG "%s: Transmitter queued, length %d.\n", dev->name, length); } dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* The ZNET interrupt handler. */ diff --git a/drivers/parisc/ccio-dma.c b/drivers/parisc/ccio-dma.c index 5d610cbcfe8..0f0e0b919ef 100644 --- a/drivers/parisc/ccio-dma.c +++ b/drivers/parisc/ccio-dma.c @@ -1134,7 +1134,7 @@ static const struct file_operations ccio_proc_bitmap_fops = { .llseek = seq_lseek, .release = single_release, }; -#endif +#endif /* CONFIG_PROC_FS */ /** * ccio_find_ioc - Find the ioc in the ioc_list @@ -1568,14 +1568,15 @@ static int __init ccio_probe(struct parisc_device *dev) /* if this fails, no I/O cards will work, so may as well bug */ BUG_ON(dev->dev.platform_data == NULL); HBA_DATA(dev->dev.platform_data)->iommu = ioc; - + +#ifdef CONFIG_PROC_FS if (ioc_count == 0) { proc_create(MODULE_NAME, 0, proc_runway_root, &ccio_proc_info_fops); proc_create(MODULE_NAME"-bitmap", 0, proc_runway_root, &ccio_proc_bitmap_fops); } - +#endif ioc_count++; parisc_has_iommu(); diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c index 52ae0b1d470..c590974e981 100644 --- a/drivers/parisc/dino.c +++ b/drivers/parisc/dino.c @@ -353,7 +353,7 @@ static unsigned int dino_startup_irq(unsigned int irq) return 0; } -static struct hw_interrupt_type dino_interrupt_type = { +static struct irq_chip dino_interrupt_type = { .typename = "GSC-PCI", .startup = dino_startup_irq, .shutdown = dino_disable_irq, @@ -1019,22 +1019,22 @@ static int __init dino_probe(struct parisc_device *dev) ** It's not used to avoid chicken/egg problems ** with configuration accessor functions. */ - bus = pci_scan_bus_parented(&dev->dev, dino_current_bus, - &dino_cfg_ops, NULL); + dino_dev->hba.hba_bus = bus = pci_scan_bus_parented(&dev->dev, + dino_current_bus, &dino_cfg_ops, NULL); + if(bus) { - pci_bus_add_devices(bus); /* This code *depends* on scanning being single threaded * if it isn't, this global bus number count will fail */ dino_current_bus = bus->subordinate + 1; pci_bus_assign_resources(bus); + pci_bus_add_devices(bus); } else { - printk(KERN_ERR "ERROR: failed to scan PCI bus on %s (probably duplicate bus number %d)\n", + printk(KERN_ERR "ERROR: failed to scan PCI bus on %s (duplicate bus number %d?)\n", dev_name(&dev->dev), dino_current_bus); /* increment the bus number in case of duplicates */ dino_current_bus++; } - dino_dev->hba.hba_bus = bus; return 0; } diff --git a/drivers/parisc/eisa.c b/drivers/parisc/eisa.c index 5b89f404e66..51220749cb6 100644 --- a/drivers/parisc/eisa.c +++ b/drivers/parisc/eisa.c @@ -188,7 +188,7 @@ static unsigned int eisa_startup_irq(unsigned int irq) return 0; } -static struct hw_interrupt_type eisa_interrupt_type = { +static struct irq_chip eisa_interrupt_type = { .typename = "EISA", .startup = eisa_startup_irq, .shutdown = eisa_disable_irq, diff --git a/drivers/parisc/gsc.c b/drivers/parisc/gsc.c index d3363291769..647adc9f85a 100644 --- a/drivers/parisc/gsc.c +++ b/drivers/parisc/gsc.c @@ -148,7 +148,7 @@ static unsigned int gsc_asic_startup_irq(unsigned int irq) return 0; } -static struct hw_interrupt_type gsc_asic_interrupt_type = { +static struct irq_chip gsc_asic_interrupt_type = { .typename = "GSC-ASIC", .startup = gsc_asic_startup_irq, .shutdown = gsc_asic_disable_irq, @@ -158,7 +158,7 @@ static struct hw_interrupt_type gsc_asic_interrupt_type = { .end = no_end_irq, }; -int gsc_assign_irq(struct hw_interrupt_type *type, void *data) +int gsc_assign_irq(struct irq_chip *type, void *data) { static int irq = GSC_IRQ_BASE; struct irq_desc *desc; diff --git a/drivers/parisc/gsc.h b/drivers/parisc/gsc.h index 762a1babad6..b9d7bfb68e2 100644 --- a/drivers/parisc/gsc.h +++ b/drivers/parisc/gsc.h @@ -38,7 +38,7 @@ struct gsc_asic { int gsc_common_setup(struct parisc_device *parent, struct gsc_asic *gsc_asic); int gsc_alloc_irq(struct gsc_irq *dev); /* dev needs an irq */ int gsc_claim_irq(struct gsc_irq *dev, int irq); /* dev needs this irq */ -int gsc_assign_irq(struct hw_interrupt_type *type, void *data); +int gsc_assign_irq(struct irq_chip *type, void *data); int gsc_find_local_irq(unsigned int irq, int *global_irq, int limit); void gsc_fixup_irqs(struct parisc_device *parent, void *ctrl, void (*choose)(struct parisc_device *child, void *ctrl)); diff --git a/drivers/parisc/iosapic.c b/drivers/parisc/iosapic.c index 4a9cc92d4d1..88e33355321 100644 --- a/drivers/parisc/iosapic.c +++ b/drivers/parisc/iosapic.c @@ -729,7 +729,7 @@ static int iosapic_set_affinity_irq(unsigned int irq, } #endif -static struct hw_interrupt_type iosapic_interrupt_type = { +static struct irq_chip iosapic_interrupt_type = { .typename = "IO-SAPIC-level", .startup = iosapic_startup_irq, .shutdown = iosapic_disable_irq, diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c index 59fbbf12836..ede614616f8 100644 --- a/drivers/parisc/lba_pci.c +++ b/drivers/parisc/lba_pci.c @@ -980,28 +980,38 @@ static void lba_pat_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev) { unsigned long bytecnt; - pdc_pat_cell_mod_maddr_block_t pa_pdc_cell; /* PA_VIEW */ - pdc_pat_cell_mod_maddr_block_t io_pdc_cell; /* IO_VIEW */ long io_count; long status; /* PDC return status */ long pa_count; + pdc_pat_cell_mod_maddr_block_t *pa_pdc_cell; /* PA_VIEW */ + pdc_pat_cell_mod_maddr_block_t *io_pdc_cell; /* IO_VIEW */ int i; + pa_pdc_cell = kzalloc(sizeof(pdc_pat_cell_mod_maddr_block_t), GFP_KERNEL); + if (!pa_pdc_cell) + return; + + io_pdc_cell = kzalloc(sizeof(pdc_pat_cell_mod_maddr_block_t), GFP_KERNEL); + if (!pa_pdc_cell) { + kfree(pa_pdc_cell); + return; + } + /* return cell module (IO view) */ status = pdc_pat_cell_module(&bytecnt, pa_dev->pcell_loc, pa_dev->mod_index, - PA_VIEW, & pa_pdc_cell); - pa_count = pa_pdc_cell.mod[1]; + PA_VIEW, pa_pdc_cell); + pa_count = pa_pdc_cell->mod[1]; status |= pdc_pat_cell_module(&bytecnt, pa_dev->pcell_loc, pa_dev->mod_index, - IO_VIEW, &io_pdc_cell); - io_count = io_pdc_cell.mod[1]; + IO_VIEW, io_pdc_cell); + io_count = io_pdc_cell->mod[1]; /* We've already done this once for device discovery...*/ if (status != PDC_OK) { panic("pdc_pat_cell_module() call failed for LBA!\n"); } - if (PAT_GET_ENTITY(pa_pdc_cell.mod_info) != PAT_ENTITY_LBA) { + if (PAT_GET_ENTITY(pa_pdc_cell->mod_info) != PAT_ENTITY_LBA) { panic("pdc_pat_cell_module() entity returned != PAT_ENTITY_LBA!\n"); } @@ -1016,8 +1026,8 @@ lba_pat_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev) } *p, *io; struct resource *r; - p = (void *) &(pa_pdc_cell.mod[2+i*3]); - io = (void *) &(io_pdc_cell.mod[2+i*3]); + p = (void *) &(pa_pdc_cell->mod[2+i*3]); + io = (void *) &(io_pdc_cell->mod[2+i*3]); /* Convert the PAT range data to PCI "struct resource" */ switch(p->type & 0xff) { @@ -1096,6 +1106,9 @@ lba_pat_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev) break; } } + + kfree(pa_pdc_cell); + kfree(io_pdc_cell); } #else /* keep compiler from complaining about missing declarations */ @@ -1509,10 +1522,6 @@ lba_driver_probe(struct parisc_device *dev) lba_bus = lba_dev->hba.hba_bus = pci_scan_bus_parented(&dev->dev, lba_dev->hba.bus_num.start, cfg_ops, NULL); - if (lba_bus) { - lba_next_bus = lba_bus->subordinate + 1; - pci_bus_add_devices(lba_bus); - } /* This is in lieu of calling pci_assign_unassigned_resources() */ if (is_pdc_pat()) { @@ -1533,7 +1542,6 @@ lba_driver_probe(struct parisc_device *dev) } pci_enable_bridges(lba_bus); - /* ** Once PCI register ops has walked the bus, access to config ** space is restricted. Avoids master aborts on config cycles. @@ -1543,6 +1551,11 @@ lba_driver_probe(struct parisc_device *dev) lba_dev->flags |= LBA_FLAG_SKIP_PROBE; } + if (lba_bus) { + lba_next_bus = lba_bus->subordinate + 1; + pci_bus_add_devices(lba_bus); + } + /* Whew! Finally done! Tell services we got this one covered. */ return 0; } diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c index d46dd57450a..123d8fe3427 100644 --- a/drivers/parisc/sba_iommu.c +++ b/drivers/parisc/sba_iommu.c @@ -2057,6 +2057,7 @@ void sba_directed_lmmio(struct parisc_device *pci_hba, struct resource *r) r->start = (base & ~1UL) | PCI_F_EXTEND; size = ~ READ_REG32(reg + LMMIO_DIRECT0_MASK); r->end = r->start + size; + r->flags = IORESOURCE_MEM; } } @@ -2093,4 +2094,5 @@ void sba_distributed_lmmio(struct parisc_device *pci_hba, struct resource *r ) size = (~READ_REG32(sba->sba_hpa + LMMIO_DIST_MASK)) / ROPES_PER_IOC; r->start += rope * (size + 1); /* adjust base for this rope */ r->end = r->start + size; + r->flags = IORESOURCE_MEM; } diff --git a/drivers/parisc/superio.c b/drivers/parisc/superio.c index 33e5ade774c..675f04e6597 100644 --- a/drivers/parisc/superio.c +++ b/drivers/parisc/superio.c @@ -325,7 +325,7 @@ static unsigned int superio_startup_irq(unsigned int irq) return 0; } -static struct hw_interrupt_type superio_interrupt_type = { +static struct irq_chip superio_interrupt_type = { .typename = SUPERIO, .startup = superio_startup_irq, .shutdown = superio_disable_irq, @@ -434,8 +434,8 @@ static void __init superio_parport_init(void) 0 /*base_hi*/, PAR_IRQ, PARPORT_DMA_NONE /* dma */, - NULL /*struct pci_dev* */), - 0 /* shared irq flags */ ) + NULL /*struct pci_dev* */, + 0 /* shared irq flags */)) printk(KERN_WARNING PFX "Probing parallel port failed.\n"); #endif /* CONFIG_PARPORT_PC */ diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c index 1032d5fdbd4..2597145a066 100644 --- a/drivers/parport/parport_pc.c +++ b/drivers/parport/parport_pc.c @@ -2907,6 +2907,7 @@ enum parport_pc_pci_cards { netmos_9755, netmos_9805, netmos_9815, + netmos_9901, quatech_sppxp100, }; @@ -2987,7 +2988,7 @@ static struct parport_pc_pci { /* netmos_9755 */ { 2, { { 0, 1 }, { 2, 3 },} }, /* netmos_9805 */ { 1, { { 0, -1 }, } }, /* netmos_9815 */ { 2, { { 0, -1 }, { 2, -1 }, } }, - + /* netmos_9901 */ { 1, { { 0, -1 }, } }, /* quatech_sppxp100 */ { 1, { { 0, 1 }, } }, }; @@ -3089,6 +3090,8 @@ static const struct pci_device_id parport_pc_pci_tbl[] = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9805 }, { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9815, PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9815 }, + { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9901, + 0xA000, 0x2000, 0, 0, netmos_9901 }, /* Quatech SPPXP-100 Parallel port PCI ExpressCard */ { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_SPPXP_100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, quatech_sppxp100 }, diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c index e53eacd75c8..53075424a43 100644 --- a/drivers/pci/intel-iommu.c +++ b/drivers/pci/intel-iommu.c @@ -39,7 +39,6 @@ #include <linux/sysdev.h> #include <asm/cacheflush.h> #include <asm/iommu.h> -#include <asm/e820.h> #include "pci.h" #define ROOT_SIZE VTD_PAGE_SIZE @@ -57,14 +56,32 @@ #define MAX_AGAW_WIDTH 64 #define DOMAIN_MAX_ADDR(gaw) ((((u64)1) << gaw) - 1) +#define DOMAIN_MAX_PFN(gaw) ((((u64)1) << (gaw-VTD_PAGE_SHIFT)) - 1) #define IOVA_PFN(addr) ((addr) >> PAGE_SHIFT) #define DMA_32BIT_PFN IOVA_PFN(DMA_BIT_MASK(32)) #define DMA_64BIT_PFN IOVA_PFN(DMA_BIT_MASK(64)) -#ifndef PHYSICAL_PAGE_MASK -#define PHYSICAL_PAGE_MASK PAGE_MASK -#endif + +/* VT-d pages must always be _smaller_ than MM pages. Otherwise things + are never going to work. */ +static inline unsigned long dma_to_mm_pfn(unsigned long dma_pfn) +{ + return dma_pfn >> (PAGE_SHIFT - VTD_PAGE_SHIFT); +} + +static inline unsigned long mm_to_dma_pfn(unsigned long mm_pfn) +{ + return mm_pfn << (PAGE_SHIFT - VTD_PAGE_SHIFT); +} +static inline unsigned long page_to_dma_pfn(struct page *pg) +{ + return mm_to_dma_pfn(page_to_pfn(pg)); +} +static inline unsigned long virt_to_dma_pfn(void *p) +{ + return page_to_dma_pfn(virt_to_page(p)); +} /* global iommu list, set NULL for ignored DMAR units */ static struct intel_iommu **g_iommus; @@ -205,12 +222,17 @@ static inline void dma_set_pte_prot(struct dma_pte *pte, unsigned long prot) static inline u64 dma_pte_addr(struct dma_pte *pte) { - return (pte->val & VTD_PAGE_MASK); +#ifdef CONFIG_64BIT + return pte->val & VTD_PAGE_MASK; +#else + /* Must have a full atomic 64-bit read */ + return __cmpxchg64(pte, 0ULL, 0ULL) & VTD_PAGE_MASK; +#endif } -static inline void dma_set_pte_addr(struct dma_pte *pte, u64 addr) +static inline void dma_set_pte_pfn(struct dma_pte *pte, unsigned long pfn) { - pte->val |= (addr & VTD_PAGE_MASK); + pte->val |= (uint64_t)pfn << VTD_PAGE_SHIFT; } static inline bool dma_pte_present(struct dma_pte *pte) @@ -218,6 +240,11 @@ static inline bool dma_pte_present(struct dma_pte *pte) return (pte->val & 3) != 0; } +static inline int first_pte_in_page(struct dma_pte *pte) +{ + return !((unsigned long)pte & ~VTD_PAGE_MASK); +} + /* * This domain is a statically identity mapping domain. * 1. This domain creats a static 1:1 mapping to all usable memory. @@ -245,7 +272,6 @@ struct dmar_domain { struct iova_domain iovad; /* iova's that belong to this domain */ struct dma_pte *pgd; /* virtual address */ - spinlock_t mapping_lock; /* page table lock */ int gaw; /* max guest address width */ /* adjusted guest address width, 0 is level 2 30-bit */ @@ -649,80 +675,78 @@ static inline int width_to_agaw(int width) static inline unsigned int level_to_offset_bits(int level) { - return (12 + (level - 1) * LEVEL_STRIDE); + return (level - 1) * LEVEL_STRIDE; } -static inline int address_level_offset(u64 addr, int level) +static inline int pfn_level_offset(unsigned long pfn, int level) { - return ((addr >> level_to_offset_bits(level)) & LEVEL_MASK); + return (pfn >> level_to_offset_bits(level)) & LEVEL_MASK; } -static inline u64 level_mask(int level) +static inline unsigned long level_mask(int level) { - return ((u64)-1 << level_to_offset_bits(level)); + return -1UL << level_to_offset_bits(level); } -static inline u64 level_size(int level) +static inline unsigned long level_size(int level) { - return ((u64)1 << level_to_offset_bits(level)); + return 1UL << level_to_offset_bits(level); } -static inline u64 align_to_level(u64 addr, int level) +static inline unsigned long align_to_level(unsigned long pfn, int level) { - return ((addr + level_size(level) - 1) & level_mask(level)); + return (pfn + level_size(level) - 1) & level_mask(level); } -static struct dma_pte * addr_to_dma_pte(struct dmar_domain *domain, u64 addr) +static struct dma_pte *pfn_to_dma_pte(struct dmar_domain *domain, + unsigned long pfn) { - int addr_width = agaw_to_width(domain->agaw); + int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT; struct dma_pte *parent, *pte = NULL; int level = agaw_to_level(domain->agaw); int offset; - unsigned long flags; BUG_ON(!domain->pgd); - - addr &= (((u64)1) << addr_width) - 1; + BUG_ON(addr_width < BITS_PER_LONG && pfn >> addr_width); parent = domain->pgd; - spin_lock_irqsave(&domain->mapping_lock, flags); while (level > 0) { void *tmp_page; - offset = address_level_offset(addr, level); + offset = pfn_level_offset(pfn, level); pte = &parent[offset]; if (level == 1) break; if (!dma_pte_present(pte)) { + uint64_t pteval; + tmp_page = alloc_pgtable_page(); - if (!tmp_page) { - spin_unlock_irqrestore(&domain->mapping_lock, - flags); + if (!tmp_page) return NULL; + + domain_flush_cache(domain, tmp_page, VTD_PAGE_SIZE); + pteval = (virt_to_dma_pfn(tmp_page) << VTD_PAGE_SHIFT) | DMA_PTE_READ | DMA_PTE_WRITE; + if (cmpxchg64(&pte->val, 0ULL, pteval)) { + /* Someone else set it while we were thinking; use theirs. */ + free_pgtable_page(tmp_page); + } else { + dma_pte_addr(pte); + domain_flush_cache(domain, pte, sizeof(*pte)); } - domain_flush_cache(domain, tmp_page, PAGE_SIZE); - dma_set_pte_addr(pte, virt_to_phys(tmp_page)); - /* - * high level table always sets r/w, last level page - * table control read/write - */ - dma_set_pte_readable(pte); - dma_set_pte_writable(pte); - domain_flush_cache(domain, pte, sizeof(*pte)); } parent = phys_to_virt(dma_pte_addr(pte)); level--; } - spin_unlock_irqrestore(&domain->mapping_lock, flags); return pte; } /* return address's pte at specific level */ -static struct dma_pte *dma_addr_level_pte(struct dmar_domain *domain, u64 addr, - int level) +static struct dma_pte *dma_pfn_level_pte(struct dmar_domain *domain, + unsigned long pfn, + int level) { struct dma_pte *parent, *pte = NULL; int total = agaw_to_level(domain->agaw); @@ -730,7 +754,7 @@ static struct dma_pte *dma_addr_level_pte(struct dmar_domain *domain, u64 addr, parent = domain->pgd; while (level <= total) { - offset = address_level_offset(addr, total); + offset = pfn_level_offset(pfn, total); pte = &parent[offset]; if (level == total) return pte; @@ -743,74 +767,82 @@ static struct dma_pte *dma_addr_level_pte(struct dmar_domain *domain, u64 addr, return NULL; } -/* clear one page's page table */ -static void dma_pte_clear_one(struct dmar_domain *domain, u64 addr) -{ - struct dma_pte *pte = NULL; - - /* get last level pte */ - pte = dma_addr_level_pte(domain, addr, 1); - - if (pte) { - dma_clear_pte(pte); - domain_flush_cache(domain, pte, sizeof(*pte)); - } -} - /* clear last level pte, a tlb flush should be followed */ -static void dma_pte_clear_range(struct dmar_domain *domain, u64 start, u64 end) +static void dma_pte_clear_range(struct dmar_domain *domain, + unsigned long start_pfn, + unsigned long last_pfn) { - int addr_width = agaw_to_width(domain->agaw); - int npages; + int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT; + struct dma_pte *first_pte, *pte; + + BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width); + BUG_ON(addr_width < BITS_PER_LONG && last_pfn >> addr_width); - start &= (((u64)1) << addr_width) - 1; - end &= (((u64)1) << addr_width) - 1; - /* in case it's partial page */ - start &= PAGE_MASK; - end = PAGE_ALIGN(end); - npages = (end - start) / VTD_PAGE_SIZE; + /* we don't need lock here; nobody else touches the iova range */ + while (start_pfn <= last_pfn) { + first_pte = pte = dma_pfn_level_pte(domain, start_pfn, 1); + if (!pte) { + start_pfn = align_to_level(start_pfn + 1, 2); + continue; + } + do { + dma_clear_pte(pte); + start_pfn++; + pte++; + } while (start_pfn <= last_pfn && !first_pte_in_page(pte)); - /* we don't need lock here, nobody else touches the iova range */ - while (npages--) { - dma_pte_clear_one(domain, start); - start += VTD_PAGE_SIZE; + domain_flush_cache(domain, first_pte, + (void *)pte - (void *)first_pte); } } /* free page table pages. last level pte should already be cleared */ static void dma_pte_free_pagetable(struct dmar_domain *domain, - u64 start, u64 end) + unsigned long start_pfn, + unsigned long last_pfn) { - int addr_width = agaw_to_width(domain->agaw); - struct dma_pte *pte; + int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT; + struct dma_pte *first_pte, *pte; int total = agaw_to_level(domain->agaw); int level; - u64 tmp; + unsigned long tmp; - start &= (((u64)1) << addr_width) - 1; - end &= (((u64)1) << addr_width) - 1; + BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width); + BUG_ON(addr_width < BITS_PER_LONG && last_pfn >> addr_width); - /* we don't need lock here, nobody else touches the iova range */ + /* We don't need lock here; nobody else touches the iova range */ level = 2; while (level <= total) { - tmp = align_to_level(start, level); - if (tmp >= end || (tmp + level_size(level) > end)) + tmp = align_to_level(start_pfn, level); + + /* If we can't even clear one PTE at this level, we're done */ + if (tmp + level_size(level) - 1 > last_pfn) return; - while (tmp < end) { - pte = dma_addr_level_pte(domain, tmp, level); - if (pte) { - free_pgtable_page( - phys_to_virt(dma_pte_addr(pte))); - dma_clear_pte(pte); - domain_flush_cache(domain, pte, sizeof(*pte)); + while (tmp + level_size(level) - 1 <= last_pfn) { + first_pte = pte = dma_pfn_level_pte(domain, tmp, level); + if (!pte) { + tmp = align_to_level(tmp + 1, level + 1); + continue; } - tmp += level_size(level); + do { + if (dma_pte_present(pte)) { + free_pgtable_page(phys_to_virt(dma_pte_addr(pte))); + dma_clear_pte(pte); + } + pte++; + tmp += level_size(level); + } while (!first_pte_in_page(pte) && + tmp + level_size(level) - 1 <= last_pfn); + + domain_flush_cache(domain, first_pte, + (void *)pte - (void *)first_pte); + } level++; } /* free pgd */ - if (start == 0 && end >= ((((u64)1) << addr_width) - 1)) { + if (start_pfn == 0 && last_pfn == DOMAIN_MAX_PFN(domain->gaw)) { free_pgtable_page(domain->pgd); domain->pgd = NULL; } @@ -1036,11 +1068,11 @@ static void iommu_flush_dev_iotlb(struct dmar_domain *domain, } static void iommu_flush_iotlb_psi(struct intel_iommu *iommu, u16 did, - u64 addr, unsigned int pages) + unsigned long pfn, unsigned int pages) { unsigned int mask = ilog2(__roundup_pow_of_two(pages)); + uint64_t addr = (uint64_t)pfn << VTD_PAGE_SHIFT; - BUG_ON(addr & (~VTD_PAGE_MASK)); BUG_ON(pages == 0); /* @@ -1055,7 +1087,12 @@ static void iommu_flush_iotlb_psi(struct intel_iommu *iommu, u16 did, else iommu->flush.flush_iotlb(iommu, did, addr, mask, DMA_TLB_PSI_FLUSH); - if (did) + + /* + * In caching mode, domain ID 0 is reserved for non-present to present + * mapping flush. Device IOTLB doesn't need to be flushed in this case. + */ + if (!cap_caching_mode(iommu->cap) || did) iommu_flush_dev_iotlb(iommu->domains[did], addr, mask); } @@ -1280,7 +1317,6 @@ static void dmar_init_reserved_ranges(void) struct pci_dev *pdev = NULL; struct iova *iova; int i; - u64 addr, size; init_iova_domain(&reserved_iova_list, DMA_32BIT_PFN); @@ -1303,12 +1339,9 @@ static void dmar_init_reserved_ranges(void) r = &pdev->resource[i]; if (!r->flags || !(r->flags & IORESOURCE_MEM)) continue; - addr = r->start; - addr &= PHYSICAL_PAGE_MASK; - size = r->end - addr; - size = PAGE_ALIGN(size); - iova = reserve_iova(&reserved_iova_list, IOVA_PFN(addr), - IOVA_PFN(size + addr) - 1); + iova = reserve_iova(&reserved_iova_list, + IOVA_PFN(r->start), + IOVA_PFN(r->end)); if (!iova) printk(KERN_ERR "Reserve iova failed\n"); } @@ -1342,7 +1375,6 @@ static int domain_init(struct dmar_domain *domain, int guest_width) unsigned long sagaw; init_iova_domain(&domain->iovad, DMA_32BIT_PFN); - spin_lock_init(&domain->mapping_lock); spin_lock_init(&domain->iommu_lock); domain_reserve_special_ranges(domain); @@ -1389,7 +1421,6 @@ static void domain_exit(struct dmar_domain *domain) { struct dmar_drhd_unit *drhd; struct intel_iommu *iommu; - u64 end; /* Domain 0 is reserved, so dont process it */ if (!domain) @@ -1398,14 +1429,12 @@ static void domain_exit(struct dmar_domain *domain) domain_remove_dev_info(domain); /* destroy iovas */ put_iova_domain(&domain->iovad); - end = DOMAIN_MAX_ADDR(domain->gaw); - end = end & (~PAGE_MASK); /* clear ptes */ - dma_pte_clear_range(domain, 0, end); + dma_pte_clear_range(domain, 0, DOMAIN_MAX_PFN(domain->gaw)); /* free page tables */ - dma_pte_free_pagetable(domain, 0, end); + dma_pte_free_pagetable(domain, 0, DOMAIN_MAX_PFN(domain->gaw)); for_each_active_iommu(iommu, drhd) if (test_bit(iommu->seq_id, &domain->iommu_bmp)) @@ -1619,42 +1648,86 @@ static int domain_context_mapped(struct pci_dev *pdev) tmp->devfn); } -static int -domain_page_mapping(struct dmar_domain *domain, dma_addr_t iova, - u64 hpa, size_t size, int prot) +static int __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn, + struct scatterlist *sg, unsigned long phys_pfn, + unsigned long nr_pages, int prot) { - u64 start_pfn, end_pfn; - struct dma_pte *pte; - int index; - int addr_width = agaw_to_width(domain->agaw); + struct dma_pte *first_pte = NULL, *pte = NULL; + phys_addr_t uninitialized_var(pteval); + int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT; + unsigned long sg_res; - hpa &= (((u64)1) << addr_width) - 1; + BUG_ON(addr_width < BITS_PER_LONG && (iov_pfn + nr_pages - 1) >> addr_width); if ((prot & (DMA_PTE_READ|DMA_PTE_WRITE)) == 0) return -EINVAL; - iova &= PAGE_MASK; - start_pfn = ((u64)hpa) >> VTD_PAGE_SHIFT; - end_pfn = (VTD_PAGE_ALIGN(((u64)hpa) + size)) >> VTD_PAGE_SHIFT; - index = 0; - while (start_pfn < end_pfn) { - pte = addr_to_dma_pte(domain, iova + VTD_PAGE_SIZE * index); - if (!pte) - return -ENOMEM; + + prot &= DMA_PTE_READ | DMA_PTE_WRITE | DMA_PTE_SNP; + + if (sg) + sg_res = 0; + else { + sg_res = nr_pages + 1; + pteval = ((phys_addr_t)phys_pfn << VTD_PAGE_SHIFT) | prot; + } + + while (nr_pages--) { + uint64_t tmp; + + if (!sg_res) { + sg_res = (sg->offset + sg->length + VTD_PAGE_SIZE - 1) >> VTD_PAGE_SHIFT; + sg->dma_address = ((dma_addr_t)iov_pfn << VTD_PAGE_SHIFT) + sg->offset; + sg->dma_length = sg->length; + pteval = page_to_phys(sg_page(sg)) | prot; + } + if (!pte) { + first_pte = pte = pfn_to_dma_pte(domain, iov_pfn); + if (!pte) + return -ENOMEM; + } /* We don't need lock here, nobody else * touches the iova range */ - BUG_ON(dma_pte_addr(pte)); - dma_set_pte_addr(pte, start_pfn << VTD_PAGE_SHIFT); - dma_set_pte_prot(pte, prot); - if (prot & DMA_PTE_SNP) - dma_set_pte_snp(pte); - domain_flush_cache(domain, pte, sizeof(*pte)); - start_pfn++; - index++; + tmp = cmpxchg64_local(&pte->val, 0ULL, pteval); + if (tmp) { + static int dumps = 5; + printk(KERN_CRIT "ERROR: DMA PTE for vPFN 0x%lx already set (to %llx not %llx)\n", + iov_pfn, tmp, (unsigned long long)pteval); + if (dumps) { + dumps--; + debug_dma_dump_mappings(NULL); + } + WARN_ON(1); + } + pte++; + if (!nr_pages || first_pte_in_page(pte)) { + domain_flush_cache(domain, first_pte, + (void *)pte - (void *)first_pte); + pte = NULL; + } + iov_pfn++; + pteval += VTD_PAGE_SIZE; + sg_res--; + if (!sg_res) + sg = sg_next(sg); } return 0; } +static inline int domain_sg_mapping(struct dmar_domain *domain, unsigned long iov_pfn, + struct scatterlist *sg, unsigned long nr_pages, + int prot) +{ + return __domain_mapping(domain, iov_pfn, sg, 0, nr_pages, prot); +} + +static inline int domain_pfn_mapping(struct dmar_domain *domain, unsigned long iov_pfn, + unsigned long phys_pfn, unsigned long nr_pages, + int prot) +{ + return __domain_mapping(domain, iov_pfn, NULL, phys_pfn, nr_pages, prot); +} + static void iommu_detach_dev(struct intel_iommu *iommu, u8 bus, u8 devfn) { if (!iommu) @@ -1845,58 +1918,61 @@ error: static int iommu_identity_mapping; +static int iommu_domain_identity_map(struct dmar_domain *domain, + unsigned long long start, + unsigned long long end) +{ + unsigned long first_vpfn = start >> VTD_PAGE_SHIFT; + unsigned long last_vpfn = end >> VTD_PAGE_SHIFT; + + if (!reserve_iova(&domain->iovad, dma_to_mm_pfn(first_vpfn), + dma_to_mm_pfn(last_vpfn))) { + printk(KERN_ERR "IOMMU: reserve iova failed\n"); + return -ENOMEM; + } + + pr_debug("Mapping reserved region %llx-%llx for domain %d\n", + start, end, domain->id); + /* + * RMRR range might have overlap with physical memory range, + * clear it first + */ + dma_pte_clear_range(domain, first_vpfn, last_vpfn); + + return domain_pfn_mapping(domain, first_vpfn, first_vpfn, + last_vpfn - first_vpfn + 1, + DMA_PTE_READ|DMA_PTE_WRITE); +} + static int iommu_prepare_identity_map(struct pci_dev *pdev, unsigned long long start, unsigned long long end) { struct dmar_domain *domain; - unsigned long size; - unsigned long long base; int ret; printk(KERN_INFO - "IOMMU: Setting identity map for device %s [0x%Lx - 0x%Lx]\n", - pci_name(pdev), start, end); - if (iommu_identity_mapping) - domain = si_domain; - else - /* page table init */ - domain = get_domain_for_dev(pdev, DEFAULT_DOMAIN_ADDRESS_WIDTH); + "IOMMU: Setting identity map for device %s [0x%Lx - 0x%Lx]\n", + pci_name(pdev), start, end); + + domain = get_domain_for_dev(pdev, DEFAULT_DOMAIN_ADDRESS_WIDTH); if (!domain) return -ENOMEM; - /* The address might not be aligned */ - base = start & PAGE_MASK; - size = end - base; - size = PAGE_ALIGN(size); - if (!reserve_iova(&domain->iovad, IOVA_PFN(base), - IOVA_PFN(base + size) - 1)) { - printk(KERN_ERR "IOMMU: reserve iova failed\n"); - ret = -ENOMEM; - goto error; - } - - pr_debug("Mapping reserved region %lx@%llx for %s\n", - size, base, pci_name(pdev)); - /* - * RMRR range might have overlap with physical memory range, - * clear it first - */ - dma_pte_clear_range(domain, base, base + size); - - ret = domain_page_mapping(domain, base, base, size, - DMA_PTE_READ|DMA_PTE_WRITE); + ret = iommu_domain_identity_map(domain, start, end); if (ret) goto error; /* context entry init */ ret = domain_context_mapping(domain, pdev, CONTEXT_TT_MULTI_LEVEL); - if (!ret) - return 0; -error: + if (ret) + goto error; + + return 0; + + error: domain_exit(domain); return ret; - } static inline int iommu_prepare_rmrr_dev(struct dmar_rmrr_unit *rmrr, @@ -1908,64 +1984,6 @@ static inline int iommu_prepare_rmrr_dev(struct dmar_rmrr_unit *rmrr, rmrr->end_address + 1); } -#ifdef CONFIG_DMAR_GFX_WA -struct iommu_prepare_data { - struct pci_dev *pdev; - int ret; -}; - -static int __init iommu_prepare_work_fn(unsigned long start_pfn, - unsigned long end_pfn, void *datax) -{ - struct iommu_prepare_data *data; - - data = (struct iommu_prepare_data *)datax; - - data->ret = iommu_prepare_identity_map(data->pdev, - start_pfn<<PAGE_SHIFT, end_pfn<<PAGE_SHIFT); - return data->ret; - -} - -static int __init iommu_prepare_with_active_regions(struct pci_dev *pdev) -{ - int nid; - struct iommu_prepare_data data; - - data.pdev = pdev; - data.ret = 0; - - for_each_online_node(nid) { - work_with_active_regions(nid, iommu_prepare_work_fn, &data); - if (data.ret) - return data.ret; - } - return data.ret; -} - -static void __init iommu_prepare_gfx_mapping(void) -{ - struct pci_dev *pdev = NULL; - int ret; - - for_each_pci_dev(pdev) { - if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO || - !IS_GFX_DEVICE(pdev)) - continue; - printk(KERN_INFO "IOMMU: gfx device %s 1-1 mapping\n", - pci_name(pdev)); - ret = iommu_prepare_with_active_regions(pdev); - if (ret) - printk(KERN_ERR "IOMMU: mapping reserved region failed\n"); - } -} -#else /* !CONFIG_DMAR_GFX_WA */ -static inline void iommu_prepare_gfx_mapping(void) -{ - return; -} -#endif - #ifdef CONFIG_DMAR_FLOPPY_WA static inline void iommu_prepare_isa(void) { @@ -1976,12 +1994,12 @@ static inline void iommu_prepare_isa(void) if (!pdev) return; - printk(KERN_INFO "IOMMU: Prepare 0-16M unity mapping for LPC\n"); + printk(KERN_INFO "IOMMU: Prepare 0-16MiB unity mapping for LPC\n"); ret = iommu_prepare_identity_map(pdev, 0, 16*1024*1024); if (ret) - printk(KERN_ERR "IOMMU: Failed to create 0-64M identity map, " - "floppy might not work\n"); + printk(KERN_ERR "IOMMU: Failed to create 0-16MiB identity map; " + "floppy might not work\n"); } #else @@ -2009,16 +2027,30 @@ static int __init init_context_pass_through(void) } static int md_domain_init(struct dmar_domain *domain, int guest_width); + +static int __init si_domain_work_fn(unsigned long start_pfn, + unsigned long end_pfn, void *datax) +{ + int *ret = datax; + + *ret = iommu_domain_identity_map(si_domain, + (uint64_t)start_pfn << PAGE_SHIFT, + (uint64_t)end_pfn << PAGE_SHIFT); + return *ret; + +} + static int si_domain_init(void) { struct dmar_drhd_unit *drhd; struct intel_iommu *iommu; - int ret = 0; + int nid, ret = 0; si_domain = alloc_domain(); if (!si_domain) return -EFAULT; + pr_debug("Identity mapping domain is domain %d\n", si_domain->id); for_each_active_iommu(iommu, drhd) { ret = iommu_attach_domain(si_domain, iommu); @@ -2035,6 +2067,12 @@ static int si_domain_init(void) si_domain->flags = DOMAIN_FLAG_STATIC_IDENTITY; + for_each_online_node(nid) { + work_with_active_regions(nid, si_domain_work_fn, &ret); + if (ret) + return ret; + } + return 0; } @@ -2081,7 +2119,6 @@ static int domain_add_dev_info(struct dmar_domain *domain, static int iommu_prepare_static_identity_mapping(void) { - int i; struct pci_dev *pdev = NULL; int ret; @@ -2089,20 +2126,14 @@ static int iommu_prepare_static_identity_mapping(void) if (ret) return -EFAULT; - printk(KERN_INFO "IOMMU: Setting identity map:\n"); for_each_pci_dev(pdev) { - for (i = 0; i < e820.nr_map; i++) { - struct e820entry *ei = &e820.map[i]; - - if (ei->type == E820_RAM) { - ret = iommu_prepare_identity_map(pdev, - ei->addr, ei->addr + ei->size); - if (ret) { - printk(KERN_INFO "1:1 mapping to one domain failed.\n"); - return -EFAULT; - } - } - } + printk(KERN_INFO "IOMMU: identity mapping for device %s\n", + pci_name(pdev)); + + ret = domain_context_mapping(si_domain, pdev, + CONTEXT_TT_MULTI_LEVEL); + if (ret) + return ret; ret = domain_add_dev_info(si_domain, pdev); if (ret) return ret; @@ -2293,8 +2324,6 @@ int __init init_dmars(void) } } - iommu_prepare_gfx_mapping(); - iommu_prepare_isa(); } @@ -2339,50 +2368,40 @@ error: return ret; } -static inline u64 aligned_size(u64 host_addr, size_t size) -{ - u64 addr; - addr = (host_addr & (~PAGE_MASK)) + size; - return PAGE_ALIGN(addr); -} - -struct iova * -iommu_alloc_iova(struct dmar_domain *domain, size_t size, u64 end) +static inline unsigned long aligned_nrpages(unsigned long host_addr, + size_t size) { - struct iova *piova; + host_addr &= ~PAGE_MASK; + host_addr += size + PAGE_SIZE - 1; - /* Make sure it's in range */ - end = min_t(u64, DOMAIN_MAX_ADDR(domain->gaw), end); - if (!size || (IOVA_START_ADDR + size > end)) - return NULL; - - piova = alloc_iova(&domain->iovad, - size >> PAGE_SHIFT, IOVA_PFN(end), 1); - return piova; + return host_addr >> VTD_PAGE_SHIFT; } -static struct iova * -__intel_alloc_iova(struct device *dev, struct dmar_domain *domain, - size_t size, u64 dma_mask) +static struct iova *intel_alloc_iova(struct device *dev, + struct dmar_domain *domain, + unsigned long nrpages, uint64_t dma_mask) { struct pci_dev *pdev = to_pci_dev(dev); struct iova *iova = NULL; - if (dma_mask <= DMA_BIT_MASK(32) || dmar_forcedac) - iova = iommu_alloc_iova(domain, size, dma_mask); - else { + /* Restrict dma_mask to the width that the iommu can handle */ + dma_mask = min_t(uint64_t, DOMAIN_MAX_ADDR(domain->gaw), dma_mask); + + if (!dmar_forcedac && dma_mask > DMA_BIT_MASK(32)) { /* * First try to allocate an io virtual address in * DMA_BIT_MASK(32) and if that fails then try allocating * from higher range */ - iova = iommu_alloc_iova(domain, size, DMA_BIT_MASK(32)); - if (!iova) - iova = iommu_alloc_iova(domain, size, dma_mask); - } - - if (!iova) { - printk(KERN_ERR"Allocating iova for %s failed", pci_name(pdev)); + iova = alloc_iova(&domain->iovad, nrpages, + IOVA_PFN(DMA_BIT_MASK(32)), 1); + if (iova) + return iova; + } + iova = alloc_iova(&domain->iovad, nrpages, IOVA_PFN(dma_mask), 1); + if (unlikely(!iova)) { + printk(KERN_ERR "Allocating %ld-page iova for %s failed", + nrpages, pci_name(pdev)); return NULL; } @@ -2485,14 +2504,12 @@ static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr, return 0; iommu = domain_get_iommu(domain); - size = aligned_size((u64)paddr, size); + size = aligned_nrpages(paddr, size); - iova = __intel_alloc_iova(hwdev, domain, size, pdev->dma_mask); + iova = intel_alloc_iova(hwdev, domain, size, pdev->dma_mask); if (!iova) goto error; - start_paddr = (phys_addr_t)iova->pfn_lo << PAGE_SHIFT; - /* * Check if DMAR supports zero-length reads on write only * mappings.. @@ -2508,20 +2525,20 @@ static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr, * might have two guest_addr mapping to the same host paddr, but this * is not a big problem */ - ret = domain_page_mapping(domain, start_paddr, - ((u64)paddr) & PHYSICAL_PAGE_MASK, - size, prot); + ret = domain_pfn_mapping(domain, mm_to_dma_pfn(iova->pfn_lo), + paddr >> VTD_PAGE_SHIFT, size, prot); if (ret) goto error; /* it's a non-present to present mapping. Only flush if caching mode */ if (cap_caching_mode(iommu->cap)) - iommu_flush_iotlb_psi(iommu, 0, start_paddr, - size >> VTD_PAGE_SHIFT); + iommu_flush_iotlb_psi(iommu, 0, mm_to_dma_pfn(iova->pfn_lo), size); else iommu_flush_write_buffer(iommu); - return start_paddr + ((u64)paddr & (~PAGE_MASK)); + start_paddr = (phys_addr_t)iova->pfn_lo << PAGE_SHIFT; + start_paddr += paddr & ~PAGE_MASK; + return start_paddr; error: if (iova) @@ -2614,7 +2631,7 @@ static void intel_unmap_page(struct device *dev, dma_addr_t dev_addr, { struct pci_dev *pdev = to_pci_dev(dev); struct dmar_domain *domain; - unsigned long start_addr; + unsigned long start_pfn, last_pfn; struct iova *iova; struct intel_iommu *iommu; @@ -2627,22 +2644,25 @@ static void intel_unmap_page(struct device *dev, dma_addr_t dev_addr, iommu = domain_get_iommu(domain); iova = find_iova(&domain->iovad, IOVA_PFN(dev_addr)); - if (!iova) + if (WARN_ONCE(!iova, "Driver unmaps unmatched page at PFN %llx\n", + (unsigned long long)dev_addr)) return; - start_addr = iova->pfn_lo << PAGE_SHIFT; - size = aligned_size((u64)dev_addr, size); + start_pfn = mm_to_dma_pfn(iova->pfn_lo); + last_pfn = mm_to_dma_pfn(iova->pfn_hi + 1) - 1; - pr_debug("Device %s unmapping: %zx@%llx\n", - pci_name(pdev), size, (unsigned long long)start_addr); + pr_debug("Device %s unmapping: pfn %lx-%lx\n", + pci_name(pdev), start_pfn, last_pfn); /* clear the whole page */ - dma_pte_clear_range(domain, start_addr, start_addr + size); + dma_pte_clear_range(domain, start_pfn, last_pfn); + /* free page tables */ - dma_pte_free_pagetable(domain, start_addr, start_addr + size); + dma_pte_free_pagetable(domain, start_pfn, last_pfn); + if (intel_iommu_strict) { - iommu_flush_iotlb_psi(iommu, domain->id, start_addr, - size >> VTD_PAGE_SHIFT); + iommu_flush_iotlb_psi(iommu, domain->id, start_pfn, + last_pfn - start_pfn + 1); /* free iova */ __free_iova(&domain->iovad, iova); } else { @@ -2700,14 +2720,10 @@ static void intel_unmap_sg(struct device *hwdev, struct scatterlist *sglist, int nelems, enum dma_data_direction dir, struct dma_attrs *attrs) { - int i; struct pci_dev *pdev = to_pci_dev(hwdev); struct dmar_domain *domain; - unsigned long start_addr; + unsigned long start_pfn, last_pfn; struct iova *iova; - size_t size = 0; - phys_addr_t addr; - struct scatterlist *sg; struct intel_iommu *iommu; if (iommu_no_mapping(pdev)) @@ -2719,22 +2735,21 @@ static void intel_unmap_sg(struct device *hwdev, struct scatterlist *sglist, iommu = domain_get_iommu(domain); iova = find_iova(&domain->iovad, IOVA_PFN(sglist[0].dma_address)); - if (!iova) + if (WARN_ONCE(!iova, "Driver unmaps unmatched sglist at PFN %llx\n", + (unsigned long long)sglist[0].dma_address)) return; - for_each_sg(sglist, sg, nelems, i) { - addr = page_to_phys(sg_page(sg)) + sg->offset; - size += aligned_size((u64)addr, sg->length); - } - start_addr = iova->pfn_lo << PAGE_SHIFT; + start_pfn = mm_to_dma_pfn(iova->pfn_lo); + last_pfn = mm_to_dma_pfn(iova->pfn_hi + 1) - 1; /* clear the whole page */ - dma_pte_clear_range(domain, start_addr, start_addr + size); + dma_pte_clear_range(domain, start_pfn, last_pfn); + /* free page tables */ - dma_pte_free_pagetable(domain, start_addr, start_addr + size); + dma_pte_free_pagetable(domain, start_pfn, last_pfn); - iommu_flush_iotlb_psi(iommu, domain->id, start_addr, - size >> VTD_PAGE_SHIFT); + iommu_flush_iotlb_psi(iommu, domain->id, start_pfn, + (last_pfn - start_pfn + 1)); /* free iova */ __free_iova(&domain->iovad, iova); @@ -2757,17 +2772,16 @@ static int intel_nontranslate_map_sg(struct device *hddev, static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int nelems, enum dma_data_direction dir, struct dma_attrs *attrs) { - phys_addr_t addr; int i; struct pci_dev *pdev = to_pci_dev(hwdev); struct dmar_domain *domain; size_t size = 0; int prot = 0; - size_t offset = 0; + size_t offset_pfn = 0; struct iova *iova = NULL; int ret; struct scatterlist *sg; - unsigned long start_addr; + unsigned long start_vpfn; struct intel_iommu *iommu; BUG_ON(dir == DMA_NONE); @@ -2780,12 +2794,10 @@ static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int ne iommu = domain_get_iommu(domain); - for_each_sg(sglist, sg, nelems, i) { - addr = page_to_phys(sg_page(sg)) + sg->offset; - size += aligned_size((u64)addr, sg->length); - } + for_each_sg(sglist, sg, nelems, i) + size += aligned_nrpages(sg->offset, sg->length); - iova = __intel_alloc_iova(hwdev, domain, size, pdev->dma_mask); + iova = intel_alloc_iova(hwdev, domain, size, pdev->dma_mask); if (!iova) { sglist->dma_length = 0; return 0; @@ -2801,35 +2813,24 @@ static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int ne if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL) prot |= DMA_PTE_WRITE; - start_addr = iova->pfn_lo << PAGE_SHIFT; - offset = 0; - for_each_sg(sglist, sg, nelems, i) { - addr = page_to_phys(sg_page(sg)) + sg->offset; - size = aligned_size((u64)addr, sg->length); - ret = domain_page_mapping(domain, start_addr + offset, - ((u64)addr) & PHYSICAL_PAGE_MASK, - size, prot); - if (ret) { - /* clear the page */ - dma_pte_clear_range(domain, start_addr, - start_addr + offset); - /* free page tables */ - dma_pte_free_pagetable(domain, start_addr, - start_addr + offset); - /* free iova */ - __free_iova(&domain->iovad, iova); - return 0; - } - sg->dma_address = start_addr + offset + - ((u64)addr & (~PAGE_MASK)); - sg->dma_length = sg->length; - offset += size; + start_vpfn = mm_to_dma_pfn(iova->pfn_lo); + + ret = domain_sg_mapping(domain, start_vpfn, sglist, mm_to_dma_pfn(size), prot); + if (unlikely(ret)) { + /* clear the page */ + dma_pte_clear_range(domain, start_vpfn, + start_vpfn + size - 1); + /* free page tables */ + dma_pte_free_pagetable(domain, start_vpfn, + start_vpfn + size - 1); + /* free iova */ + __free_iova(&domain->iovad, iova); + return 0; } /* it's a non-present to present mapping. Only flush if caching mode */ if (cap_caching_mode(iommu->cap)) - iommu_flush_iotlb_psi(iommu, 0, start_addr, - offset >> VTD_PAGE_SHIFT); + iommu_flush_iotlb_psi(iommu, 0, start_vpfn, offset_pfn); else iommu_flush_write_buffer(iommu); @@ -3334,7 +3335,6 @@ static int md_domain_init(struct dmar_domain *domain, int guest_width) int adjust_width; init_iova_domain(&domain->iovad, DMA_32BIT_PFN); - spin_lock_init(&domain->mapping_lock); spin_lock_init(&domain->iommu_lock); domain_reserve_special_ranges(domain); @@ -3388,8 +3388,6 @@ static void iommu_free_vm_domain(struct dmar_domain *domain) static void vm_domain_exit(struct dmar_domain *domain) { - u64 end; - /* Domain 0 is reserved, so dont process it */ if (!domain) return; @@ -3397,14 +3395,12 @@ static void vm_domain_exit(struct dmar_domain *domain) vm_domain_remove_all_dev_info(domain); /* destroy iovas */ put_iova_domain(&domain->iovad); - end = DOMAIN_MAX_ADDR(domain->gaw); - end = end & (~VTD_PAGE_MASK); /* clear ptes */ - dma_pte_clear_range(domain, 0, end); + dma_pte_clear_range(domain, 0, DOMAIN_MAX_PFN(domain->gaw)); /* free page tables */ - dma_pte_free_pagetable(domain, 0, end); + dma_pte_free_pagetable(domain, 0, DOMAIN_MAX_PFN(domain->gaw)); iommu_free_vm_domain(domain); free_domain_mem(domain); @@ -3513,7 +3509,7 @@ static int intel_iommu_map_range(struct iommu_domain *domain, if ((iommu_prot & IOMMU_CACHE) && dmar_domain->iommu_snooping) prot |= DMA_PTE_SNP; - max_addr = (iova & VTD_PAGE_MASK) + VTD_PAGE_ALIGN(size); + max_addr = iova + size; if (dmar_domain->max_addr < max_addr) { int min_agaw; u64 end; @@ -3531,8 +3527,11 @@ static int intel_iommu_map_range(struct iommu_domain *domain, } dmar_domain->max_addr = max_addr; } - - ret = domain_page_mapping(dmar_domain, iova, hpa, size, prot); + /* Round up size to next multiple of PAGE_SIZE, if it and + the low bits of hpa would take us onto the next page */ + size = aligned_nrpages(hpa, size); + ret = domain_pfn_mapping(dmar_domain, iova >> VTD_PAGE_SHIFT, + hpa >> VTD_PAGE_SHIFT, size, prot); return ret; } @@ -3540,15 +3539,12 @@ static void intel_iommu_unmap_range(struct iommu_domain *domain, unsigned long iova, size_t size) { struct dmar_domain *dmar_domain = domain->priv; - dma_addr_t base; - /* The address might not be aligned */ - base = iova & VTD_PAGE_MASK; - size = VTD_PAGE_ALIGN(size); - dma_pte_clear_range(dmar_domain, base, base + size); + dma_pte_clear_range(dmar_domain, iova >> VTD_PAGE_SHIFT, + (iova + size - 1) >> VTD_PAGE_SHIFT); - if (dmar_domain->max_addr == base + size) - dmar_domain->max_addr = base; + if (dmar_domain->max_addr == iova + size) + dmar_domain->max_addr = iova; } static phys_addr_t intel_iommu_iova_to_phys(struct iommu_domain *domain, @@ -3558,7 +3554,7 @@ static phys_addr_t intel_iommu_iova_to_phys(struct iommu_domain *domain, struct dma_pte *pte; u64 phys = 0; - pte = addr_to_dma_pte(dmar_domain, iova); + pte = pfn_to_dma_pte(dmar_domain, iova >> VTD_PAGE_SHIFT); if (pte) phys = dma_pte_addr(pte); diff --git a/drivers/pci/iova.c b/drivers/pci/iova.c index 2287116e982..46dd440e231 100644 --- a/drivers/pci/iova.c +++ b/drivers/pci/iova.c @@ -1,9 +1,19 @@ /* - * Copyright (c) 2006, Intel Corporation. + * Copyright © 2006-2009, Intel Corporation. * - * This file is released under the GPLv2. + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. * - * Copyright (C) 2006-2008 Intel Corporation * Author: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com> */ @@ -123,7 +133,15 @@ move_left: /* Insert the new_iova into domain rbtree by holding writer lock */ /* Add new node and rebalance tree. */ { - struct rb_node **entry = &((prev)), *parent = NULL; + struct rb_node **entry, *parent = NULL; + + /* If we have 'prev', it's a valid place to start the + insertion. Otherwise, start from the root. */ + if (prev) + entry = &prev; + else + entry = &iovad->rbroot.rb_node; + /* Figure out where to put new node */ while (*entry) { struct iova *this = container_of(*entry, diff --git a/drivers/pcmcia/vrc4171_card.c b/drivers/pcmcia/vrc4171_card.c index 659421d0ca4..d4ad50d737b 100644 --- a/drivers/pcmcia/vrc4171_card.c +++ b/drivers/pcmcia/vrc4171_card.c @@ -1,7 +1,7 @@ /* * vrc4171_card.c, NEC VRC4171 Card Controller driver for Socket Services. * - * Copyright (C) 2003-2005 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp> + * Copyright (C) 2003-2005 Yoichi Yuasa <yuasa@linux-mips.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -32,7 +32,7 @@ #include "i82365.h" MODULE_DESCRIPTION("NEC VRC4171 Card Controllers driver for Socket Services"); -MODULE_AUTHOR("Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>"); +MODULE_AUTHOR("Yoichi Yuasa <yuasa@linux-mips.org>"); MODULE_LICENSE("GPL"); #define CARD_MAX_SLOTS 2 diff --git a/drivers/pcmcia/vrc4173_cardu.c b/drivers/pcmcia/vrc4173_cardu.c index 812f038e9bd..9b3c15827e5 100644 --- a/drivers/pcmcia/vrc4173_cardu.c +++ b/drivers/pcmcia/vrc4173_cardu.c @@ -6,7 +6,7 @@ * NEC VRC4173 CARDU driver for Socket Services * (This device doesn't support CardBus. it is supporting only 16bit PC Card.) * - * Copyright 2002,2003 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp> + * Copyright 2002,2003 Yoichi Yuasa <yuasa@linux-mips.org> * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -41,7 +41,7 @@ #include "vrc4173_cardu.h" MODULE_DESCRIPTION("NEC VRC4173 CARDU driver for Socket Services"); -MODULE_AUTHOR("Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>"); +MODULE_AUTHOR("Yoichi Yuasa <yuasa@linux-mips.org>"); MODULE_LICENSE("GPL"); static int vrc4173_cardu_slots; diff --git a/drivers/pcmcia/vrc4173_cardu.h b/drivers/pcmcia/vrc4173_cardu.h index 7d77c74120c..a7d96018ed8 100644 --- a/drivers/pcmcia/vrc4173_cardu.h +++ b/drivers/pcmcia/vrc4173_cardu.h @@ -5,7 +5,7 @@ * BRIEF MODULE DESCRIPTION * Include file for NEC VRC4173 CARDU. * - * Copyright 2002 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp> + * Copyright 2002 Yoichi Yuasa <yuasa@linux-mips.org> * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 7232fe7104a..46dad12f952 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -355,6 +355,7 @@ config EEEPC_LAPTOP depends on INPUT depends on EXPERIMENTAL depends on RFKILL || RFKILL = n + depends on HOTPLUG_PCI select BACKLIGHT_CLASS_DEVICE select HWMON ---help--- diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index 4207b26ff99..ec560f16d72 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -16,6 +16,8 @@ * GNU General Public License for more details. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> @@ -31,6 +33,7 @@ #include <linux/input.h> #include <linux/rfkill.h> #include <linux/pci.h> +#include <linux/pci_hotplug.h> #define EEEPC_LAPTOP_VERSION "0.1" @@ -40,11 +43,6 @@ #define EEEPC_HOTK_DEVICE_NAME "Hotkey" #define EEEPC_HOTK_HID "ASUS010" -#define EEEPC_LOG EEEPC_HOTK_FILE ": " -#define EEEPC_ERR KERN_ERR EEEPC_LOG -#define EEEPC_WARNING KERN_WARNING EEEPC_LOG -#define EEEPC_NOTICE KERN_NOTICE EEEPC_LOG -#define EEEPC_INFO KERN_INFO EEEPC_LOG /* * Definitions for Asus EeePC @@ -141,8 +139,10 @@ struct eeepc_hotk { u16 event_count[128]; /* count for each event */ struct input_dev *inputdev; u16 *keycode_map; - struct rfkill *eeepc_wlan_rfkill; - struct rfkill *eeepc_bluetooth_rfkill; + struct rfkill *wlan_rfkill; + struct rfkill *bluetooth_rfkill; + struct rfkill *wwan3g_rfkill; + struct hotplug_slot *hotplug_slot; }; /* The actual device the driver binds to */ @@ -213,6 +213,15 @@ static struct acpi_driver eeepc_hotk_driver = { }, }; +/* PCI hotplug ops */ +static int eeepc_get_adapter_status(struct hotplug_slot *slot, u8 *value); + +static struct hotplug_slot_ops eeepc_hotplug_slot_ops = { + .owner = THIS_MODULE, + .get_adapter_status = eeepc_get_adapter_status, + .get_power_status = eeepc_get_adapter_status, +}; + /* The backlight device /sys/class/backlight */ static struct backlight_device *eeepc_backlight_device; @@ -274,20 +283,20 @@ static int set_acpi(int cm, int value) if (method == NULL) return -ENODEV; if (write_acpi_int(ehotk->handle, method, value, NULL)) - printk(EEEPC_WARNING "Error writing %s\n", method); + pr_warning("Error writing %s\n", method); } return 0; } static int get_acpi(int cm) { - int value = -1; + int value = -ENODEV; if ((ehotk->cm_supported & (0x1 << cm))) { const char *method = cm_getv[cm]; if (method == NULL) return -ENODEV; if (read_acpi_int(ehotk->handle, method, &value)) - printk(EEEPC_WARNING "Error reading %s\n", method); + pr_warning("Error reading %s\n", method); } return value; } @@ -359,13 +368,19 @@ static ssize_t store_sys_acpi(int cm, const char *buf, size_t count) rv = parse_arg(buf, count, &value); if (rv > 0) - set_acpi(cm, value); + value = set_acpi(cm, value); + if (value < 0) + return value; return rv; } static ssize_t show_sys_acpi(int cm, char *buf) { - return sprintf(buf, "%d\n", get_acpi(cm)); + int value = get_acpi(cm); + + if (value < 0) + return value; + return sprintf(buf, "%d\n", value); } #define EEEPC_CREATE_DEVICE_ATTR(_name, _cm) \ @@ -539,6 +554,28 @@ static int eeepc_setkeycode(struct input_dev *dev, int scancode, int keycode) return -EINVAL; } +static void cmsg_quirk(int cm, const char *name) +{ + int dummy; + + /* Some BIOSes do not report cm although it is avaliable. + Check if cm_getv[cm] works and, if yes, assume cm should be set. */ + if (!(ehotk->cm_supported & (1 << cm)) + && !read_acpi_int(ehotk->handle, cm_getv[cm], &dummy)) { + pr_info("%s (%x) not reported by BIOS," + " enabling anyway\n", name, 1 << cm); + ehotk->cm_supported |= 1 << cm; + } +} + +static void cmsg_quirks(void) +{ + cmsg_quirk(CM_ASL_LID, "LID"); + cmsg_quirk(CM_ASL_TYPE, "TYPE"); + cmsg_quirk(CM_ASL_PANELPOWER, "PANELPOWER"); + cmsg_quirk(CM_ASL_TPD, "TPD"); +} + static int eeepc_hotk_check(void) { const struct key_entry *key; @@ -551,26 +588,24 @@ static int eeepc_hotk_check(void) if (ehotk->device->status.present) { if (write_acpi_int(ehotk->handle, "INIT", ehotk->init_flag, &buffer)) { - printk(EEEPC_ERR "Hotkey initialization failed\n"); + pr_err("Hotkey initialization failed\n"); return -ENODEV; } else { - printk(EEEPC_NOTICE "Hotkey init flags 0x%x\n", - ehotk->init_flag); + pr_notice("Hotkey init flags 0x%x\n", ehotk->init_flag); } /* get control methods supported */ if (read_acpi_int(ehotk->handle, "CMSG" , &ehotk->cm_supported)) { - printk(EEEPC_ERR - "Get control methods supported failed\n"); + pr_err("Get control methods supported failed\n"); return -ENODEV; } else { - printk(EEEPC_INFO - "Get control methods supported: 0x%x\n", - ehotk->cm_supported); + cmsg_quirks(); + pr_info("Get control methods supported: 0x%x\n", + ehotk->cm_supported); } ehotk->inputdev = input_allocate_device(); if (!ehotk->inputdev) { - printk(EEEPC_INFO "Unable to allocate input device\n"); + pr_info("Unable to allocate input device\n"); return 0; } ehotk->inputdev->name = "Asus EeePC extra buttons"; @@ -589,12 +624,12 @@ static int eeepc_hotk_check(void) } result = input_register_device(ehotk->inputdev); if (result) { - printk(EEEPC_INFO "Unable to register input device\n"); + pr_info("Unable to register input device\n"); input_free_device(ehotk->inputdev); return 0; } } else { - printk(EEEPC_ERR "Hotkey device not present, aborting\n"); + pr_err("Hotkey device not present, aborting\n"); return -EINVAL; } return 0; @@ -612,6 +647,19 @@ static int notify_brn(void) return -1; } +static int eeepc_get_adapter_status(struct hotplug_slot *hotplug_slot, + u8 *value) +{ + int val = get_acpi(CM_ASL_WLAN); + + if (val == 1 || val == 0) + *value = val; + else + return -EINVAL; + + return 0; +} + static void eeepc_rfkill_hotplug(void) { struct pci_dev *dev; @@ -619,7 +667,7 @@ static void eeepc_rfkill_hotplug(void) bool blocked; if (!bus) { - printk(EEEPC_WARNING "Unable to find PCI bus 1?\n"); + pr_warning("Unable to find PCI bus 1?\n"); return; } @@ -635,7 +683,7 @@ static void eeepc_rfkill_hotplug(void) if (dev) { pci_bus_assign_resources(bus); if (pci_bus_add_device(dev)) - printk(EEEPC_ERR "Unable to hotplug wifi\n"); + pr_err("Unable to hotplug wifi\n"); } } else { dev = pci_get_slot(bus, 0); @@ -645,7 +693,7 @@ static void eeepc_rfkill_hotplug(void) } } - rfkill_set_sw_state(ehotk->eeepc_wlan_rfkill, blocked); + rfkill_set_sw_state(ehotk->wlan_rfkill, blocked); } static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data) @@ -718,8 +766,7 @@ static int eeepc_register_rfkill_notifier(char *node) eeepc_rfkill_notify, NULL); if (ACPI_FAILURE(status)) - printk(EEEPC_WARNING - "Failed to register notify on %s\n", node); + pr_warning("Failed to register notify on %s\n", node); } else return -ENODEV; @@ -738,19 +785,66 @@ static void eeepc_unregister_rfkill_notifier(char *node) ACPI_SYSTEM_NOTIFY, eeepc_rfkill_notify); if (ACPI_FAILURE(status)) - printk(EEEPC_ERR - "Error removing rfkill notify handler %s\n", + pr_err("Error removing rfkill notify handler %s\n", node); } } +static void eeepc_cleanup_pci_hotplug(struct hotplug_slot *hotplug_slot) +{ + kfree(hotplug_slot->info); + kfree(hotplug_slot); +} + +static int eeepc_setup_pci_hotplug(void) +{ + int ret = -ENOMEM; + struct pci_bus *bus = pci_find_bus(0, 1); + + if (!bus) { + pr_err("Unable to find wifi PCI bus\n"); + return -ENODEV; + } + + ehotk->hotplug_slot = kzalloc(sizeof(struct hotplug_slot), GFP_KERNEL); + if (!ehotk->hotplug_slot) + goto error_slot; + + ehotk->hotplug_slot->info = kzalloc(sizeof(struct hotplug_slot_info), + GFP_KERNEL); + if (!ehotk->hotplug_slot->info) + goto error_info; + + ehotk->hotplug_slot->private = ehotk; + ehotk->hotplug_slot->release = &eeepc_cleanup_pci_hotplug; + ehotk->hotplug_slot->ops = &eeepc_hotplug_slot_ops; + eeepc_get_adapter_status(ehotk->hotplug_slot, + &ehotk->hotplug_slot->info->adapter_status); + + ret = pci_hp_register(ehotk->hotplug_slot, bus, 0, "eeepc-wifi"); + if (ret) { + pr_err("Unable to register hotplug slot - %d\n", ret); + goto error_register; + } + + return 0; + +error_register: + kfree(ehotk->hotplug_slot->info); +error_info: + kfree(ehotk->hotplug_slot); + ehotk->hotplug_slot = NULL; +error_slot: + return ret; +} + static int eeepc_hotk_add(struct acpi_device *device) { int result; if (!device) return -EINVAL; - printk(EEEPC_NOTICE EEEPC_HOTK_NAME "\n"); + pr_notice(EEEPC_HOTK_NAME "\n"); ehotk = kzalloc(sizeof(struct eeepc_hotk), GFP_KERNEL); if (!ehotk) return -ENOMEM; @@ -764,53 +858,8 @@ static int eeepc_hotk_add(struct acpi_device *device) if (result) goto ehotk_fail; - eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P6"); - eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7"); - - if (get_acpi(CM_ASL_WLAN) != -1) { - ehotk->eeepc_wlan_rfkill = rfkill_alloc("eeepc-wlan", - &device->dev, - RFKILL_TYPE_WLAN, - &eeepc_rfkill_ops, - (void *)CM_ASL_WLAN); - - if (!ehotk->eeepc_wlan_rfkill) - goto wlan_fail; - - rfkill_init_sw_state(ehotk->eeepc_wlan_rfkill, - get_acpi(CM_ASL_WLAN) != 1); - result = rfkill_register(ehotk->eeepc_wlan_rfkill); - if (result) - goto wlan_fail; - } - - if (get_acpi(CM_ASL_BLUETOOTH) != -1) { - ehotk->eeepc_bluetooth_rfkill = - rfkill_alloc("eeepc-bluetooth", - &device->dev, - RFKILL_TYPE_BLUETOOTH, - &eeepc_rfkill_ops, - (void *)CM_ASL_BLUETOOTH); - - if (!ehotk->eeepc_bluetooth_rfkill) - goto bluetooth_fail; - - rfkill_init_sw_state(ehotk->eeepc_bluetooth_rfkill, - get_acpi(CM_ASL_BLUETOOTH) != 1); - result = rfkill_register(ehotk->eeepc_bluetooth_rfkill); - if (result) - goto bluetooth_fail; - } - return 0; - bluetooth_fail: - rfkill_destroy(ehotk->eeepc_bluetooth_rfkill); - rfkill_unregister(ehotk->eeepc_wlan_rfkill); - wlan_fail: - rfkill_destroy(ehotk->eeepc_wlan_rfkill); - eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6"); - eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7"); ehotk_fail: kfree(ehotk); ehotk = NULL; @@ -823,16 +872,13 @@ static int eeepc_hotk_remove(struct acpi_device *device, int type) if (!device || !acpi_driver_data(device)) return -EINVAL; - eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6"); - eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7"); - kfree(ehotk); return 0; } static int eeepc_hotk_resume(struct acpi_device *device) { - if (ehotk->eeepc_wlan_rfkill) { + if (ehotk->wlan_rfkill) { bool wlan; /* Workaround - it seems that _PTS disables the wireless @@ -844,14 +890,13 @@ static int eeepc_hotk_resume(struct acpi_device *device) wlan = get_acpi(CM_ASL_WLAN); set_acpi(CM_ASL_WLAN, wlan); - rfkill_set_sw_state(ehotk->eeepc_wlan_rfkill, - wlan != 1); + rfkill_set_sw_state(ehotk->wlan_rfkill, wlan != 1); eeepc_rfkill_hotplug(); } - if (ehotk->eeepc_bluetooth_rfkill) - rfkill_set_sw_state(ehotk->eeepc_bluetooth_rfkill, + if (ehotk->bluetooth_rfkill) + rfkill_set_sw_state(ehotk->bluetooth_rfkill, get_acpi(CM_ASL_BLUETOOTH) != 1); return 0; @@ -973,10 +1018,16 @@ static void eeepc_backlight_exit(void) static void eeepc_rfkill_exit(void) { - if (ehotk->eeepc_wlan_rfkill) - rfkill_unregister(ehotk->eeepc_wlan_rfkill); - if (ehotk->eeepc_bluetooth_rfkill) - rfkill_unregister(ehotk->eeepc_bluetooth_rfkill); + eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6"); + eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7"); + if (ehotk->wlan_rfkill) + rfkill_unregister(ehotk->wlan_rfkill); + if (ehotk->bluetooth_rfkill) + rfkill_unregister(ehotk->bluetooth_rfkill); + if (ehotk->wwan3g_rfkill) + rfkill_unregister(ehotk->wwan3g_rfkill); + if (ehotk->hotplug_slot) + pci_hp_deregister(ehotk->hotplug_slot); } static void eeepc_input_exit(void) @@ -1011,6 +1062,75 @@ static void __exit eeepc_laptop_exit(void) platform_driver_unregister(&platform_driver); } +static int eeepc_new_rfkill(struct rfkill **rfkill, + const char *name, struct device *dev, + enum rfkill_type type, int cm) +{ + int result; + + result = get_acpi(cm); + if (result < 0) + return result; + + *rfkill = rfkill_alloc(name, dev, type, + &eeepc_rfkill_ops, (void *)(unsigned long)cm); + + if (!*rfkill) + return -EINVAL; + + rfkill_init_sw_state(*rfkill, get_acpi(cm) != 1); + result = rfkill_register(*rfkill); + if (result) { + rfkill_destroy(*rfkill); + *rfkill = NULL; + return result; + } + return 0; +} + + +static int eeepc_rfkill_init(struct device *dev) +{ + int result = 0; + + eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P6"); + eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7"); + + result = eeepc_new_rfkill(&ehotk->wlan_rfkill, + "eeepc-wlan", dev, + RFKILL_TYPE_WLAN, CM_ASL_WLAN); + + if (result && result != -ENODEV) + goto exit; + + result = eeepc_new_rfkill(&ehotk->bluetooth_rfkill, + "eeepc-bluetooth", dev, + RFKILL_TYPE_BLUETOOTH, CM_ASL_BLUETOOTH); + + if (result && result != -ENODEV) + goto exit; + + result = eeepc_new_rfkill(&ehotk->wwan3g_rfkill, + "eeepc-wwan3g", dev, + RFKILL_TYPE_WWAN, CM_ASL_3G); + + if (result && result != -ENODEV) + goto exit; + + result = eeepc_setup_pci_hotplug(); + /* + * If we get -EBUSY then something else is handling the PCI hotplug - + * don't fail in this case + */ + if (result == -EBUSY) + result = 0; + +exit: + if (result && result != -ENODEV) + eeepc_rfkill_exit(); + return result; +} + static int eeepc_backlight_init(struct device *dev) { struct backlight_device *bd; @@ -1018,8 +1138,7 @@ static int eeepc_backlight_init(struct device *dev) bd = backlight_device_register(EEEPC_HOTK_FILE, dev, NULL, &eeepcbl_ops); if (IS_ERR(bd)) { - printk(EEEPC_ERR - "Could not register eeepc backlight device\n"); + pr_err("Could not register eeepc backlight device\n"); eeepc_backlight_device = NULL; return PTR_ERR(bd); } @@ -1038,8 +1157,7 @@ static int eeepc_hwmon_init(struct device *dev) hwmon = hwmon_device_register(dev); if (IS_ERR(hwmon)) { - printk(EEEPC_ERR - "Could not register eeepc hwmon device\n"); + pr_err("Could not register eeepc hwmon device\n"); eeepc_hwmon_device = NULL; return PTR_ERR(hwmon); } @@ -1065,19 +1183,6 @@ static int __init eeepc_laptop_init(void) acpi_bus_unregister_driver(&eeepc_hotk_driver); return -ENODEV; } - dev = acpi_get_physical_device(ehotk->device->handle); - - if (!acpi_video_backlight_support()) { - result = eeepc_backlight_init(dev); - if (result) - goto fail_backlight; - } else - printk(EEEPC_INFO "Backlight controlled by ACPI video " - "driver\n"); - - result = eeepc_hwmon_init(dev); - if (result) - goto fail_hwmon; eeepc_enable_camera(); @@ -1097,7 +1202,33 @@ static int __init eeepc_laptop_init(void) &platform_attribute_group); if (result) goto fail_sysfs; + + dev = &platform_device->dev; + + if (!acpi_video_backlight_support()) { + result = eeepc_backlight_init(dev); + if (result) + goto fail_backlight; + } else + pr_info("Backlight controlled by ACPI video " + "driver\n"); + + result = eeepc_hwmon_init(dev); + if (result) + goto fail_hwmon; + + result = eeepc_rfkill_init(dev); + if (result) + goto fail_rfkill; + return 0; +fail_rfkill: + eeepc_hwmon_exit(); +fail_hwmon: + eeepc_backlight_exit(); +fail_backlight: + sysfs_remove_group(&platform_device->dev.kobj, + &platform_attribute_group); fail_sysfs: platform_device_del(platform_device); fail_platform_device2: @@ -1105,12 +1236,7 @@ fail_platform_device2: fail_platform_device1: platform_driver_unregister(&platform_driver); fail_platform_driver: - eeepc_hwmon_exit(); -fail_hwmon: - eeepc_backlight_exit(); -fail_backlight: eeepc_input_exit(); - eeepc_rfkill_exit(); return result; } diff --git a/drivers/rtc/rtc-bfin.c b/drivers/rtc/rtc-bfin.c index aafd3e6ebb0..a118eb0f1e6 100644 --- a/drivers/rtc/rtc-bfin.c +++ b/drivers/rtc/rtc-bfin.c @@ -1,8 +1,8 @@ /* * Blackfin On-Chip Real Time Clock Driver - * Supports BF52[257]/BF53[123]/BF53[467]/BF54[24789] + * Supports BF51x/BF52x/BF53[123]/BF53[467]/BF54x * - * Copyright 2004-2008 Analog Devices Inc. + * Copyright 2004-2009 Analog Devices Inc. * * Enter bugs at http://blackfin.uclinux.org/ * @@ -363,7 +363,7 @@ static int __devinit bfin_rtc_probe(struct platform_device *pdev) struct bfin_rtc *rtc; struct device *dev = &pdev->dev; int ret = 0; - unsigned long timeout; + unsigned long timeout = jiffies + HZ; dev_dbg_stamp(dev); @@ -374,32 +374,32 @@ static int __devinit bfin_rtc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, rtc); device_init_wakeup(dev, 1); + /* Register our RTC with the RTC framework */ + rtc->rtc_dev = rtc_device_register(pdev->name, dev, &bfin_rtc_ops, + THIS_MODULE); + if (unlikely(IS_ERR(rtc->rtc_dev))) { + ret = PTR_ERR(rtc->rtc_dev); + goto err; + } + /* Grab the IRQ and init the hardware */ ret = request_irq(IRQ_RTC, bfin_rtc_interrupt, IRQF_SHARED, pdev->name, dev); if (unlikely(ret)) - goto err; + goto err_reg; /* sometimes the bootloader touched things, but the write complete was not * enabled, so let's just do a quick timeout here since the IRQ will not fire ... */ - timeout = jiffies + HZ; while (bfin_read_RTC_ISTAT() & RTC_ISTAT_WRITE_PENDING) if (time_after(jiffies, timeout)) break; bfin_rtc_reset(dev, RTC_ISTAT_WRITE_COMPLETE); bfin_write_RTC_SWCNT(0); - /* Register our RTC with the RTC framework */ - rtc->rtc_dev = rtc_device_register(pdev->name, dev, &bfin_rtc_ops, THIS_MODULE); - if (unlikely(IS_ERR(rtc->rtc_dev))) { - ret = PTR_ERR(rtc->rtc_dev); - goto err_irq; - } - return 0; - err_irq: - free_irq(IRQ_RTC, dev); - err: +err_reg: + rtc_device_unregister(rtc->rtc_dev); +err: kfree(rtc); return ret; } diff --git a/drivers/rtc/rtc-vr41xx.c b/drivers/rtc/rtc-vr41xx.c index f11297aff85..2c839d0d21b 100644 --- a/drivers/rtc/rtc-vr41xx.c +++ b/drivers/rtc/rtc-vr41xx.c @@ -1,7 +1,7 @@ /* * Driver for NEC VR4100 series Real Time Clock unit. * - * Copyright (C) 2003-2008 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp> + * Copyright (C) 2003-2008 Yoichi Yuasa <yuasa@linux-mips.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -33,7 +33,7 @@ #include <asm/io.h> #include <asm/uaccess.h> -MODULE_AUTHOR("Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>"); +MODULE_AUTHOR("Yoichi Yuasa <yuasa@linux-mips.org>"); MODULE_DESCRIPTION("NEC VR4100 series RTC driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c index f370f8d460a..c63babefb69 100644 --- a/drivers/s390/net/claw.c +++ b/drivers/s390/net/claw.c @@ -350,6 +350,8 @@ claw_tx(struct sk_buff *skb, struct net_device *dev) CLAW_DBF_TEXT_(4, trace, "clawtx%d", rc); if (rc) rc = NETDEV_TX_BUSY; + else + rc = NETDEV_TX_OK; return rc; } /* end of claw_tx */ diff --git a/drivers/s390/net/ctcm_main.c b/drivers/s390/net/ctcm_main.c index 222e4739443..38b5079f159 100644 --- a/drivers/s390/net/ctcm_main.c +++ b/drivers/s390/net/ctcm_main.c @@ -880,7 +880,7 @@ static int ctcm_tx(struct sk_buff *skb, struct net_device *dev) "%s(%s): NULL sk_buff passed", CTCM_FUNTAIL, dev->name); priv->stats.tx_dropped++; - return 0; + return NETDEV_TX_OK; } if (skb_headroom(skb) < (LL_HEADER_LENGTH + 2)) { CTCM_DBF_TEXT_(ERROR, CTC_DBF_ERROR, @@ -888,7 +888,7 @@ static int ctcm_tx(struct sk_buff *skb, struct net_device *dev) CTCM_FUNTAIL, dev->name, LL_HEADER_LENGTH + 2); dev_kfree_skb(skb); priv->stats.tx_dropped++; - return 0; + return NETDEV_TX_OK; } /* @@ -901,7 +901,7 @@ static int ctcm_tx(struct sk_buff *skb, struct net_device *dev) priv->stats.tx_dropped++; priv->stats.tx_errors++; priv->stats.tx_carrier_errors++; - return 0; + return NETDEV_TX_OK; } if (ctcm_test_and_set_busy(dev)) @@ -910,7 +910,7 @@ static int ctcm_tx(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; if (ctcm_transmit_skb(priv->channel[WRITE], skb) != 0) return NETDEV_TX_BUSY; - return 0; + return NETDEV_TX_OK; } /* unmerged MPC variant of ctcm_tx */ @@ -1008,7 +1008,7 @@ done: if (do_debug) MPC_DBF_DEV_NAME(TRACE, dev, "exit"); - return 0; /* handle freeing of skb here */ + return NETDEV_TX_OK; /* handle freeing of skb here */ } diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index 8c675905448..a70de9b4bf2 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c @@ -1553,24 +1553,24 @@ __lcs_start_xmit(struct lcs_card *card, struct sk_buff *skb, struct net_device *dev) { struct lcs_header *header; - int rc = 0; + int rc = NETDEV_TX_OK; LCS_DBF_TEXT(5, trace, "hardxmit"); if (skb == NULL) { card->stats.tx_dropped++; card->stats.tx_errors++; - return 0; + return NETDEV_TX_OK; } if (card->state != DEV_STATE_UP) { dev_kfree_skb(skb); card->stats.tx_dropped++; card->stats.tx_errors++; card->stats.tx_carrier_errors++; - return 0; + return NETDEV_TX_OK; } if (skb->protocol == htons(ETH_P_IPV6)) { dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } netif_stop_queue(card->dev); spin_lock(&card->lock); diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c index 8c36eafcfbf..bb1183a2ed6 100644 --- a/drivers/s390/net/netiucv.c +++ b/drivers/s390/net/netiucv.c @@ -1376,14 +1376,14 @@ static int netiucv_tx(struct sk_buff *skb, struct net_device *dev) if (skb == NULL) { IUCV_DBF_TEXT(data, 2, "netiucv_tx: skb is NULL\n"); privptr->stats.tx_dropped++; - return 0; + return NETDEV_TX_OK; } if (skb_headroom(skb) < NETIUCV_HDRLEN) { IUCV_DBF_TEXT(data, 2, "netiucv_tx: skb_headroom < NETIUCV_HDRLEN\n"); dev_kfree_skb(skb); privptr->stats.tx_dropped++; - return 0; + return NETDEV_TX_OK; } /** @@ -1395,7 +1395,7 @@ static int netiucv_tx(struct sk_buff *skb, struct net_device *dev) privptr->stats.tx_dropped++; privptr->stats.tx_errors++; privptr->stats.tx_carrier_errors++; - return 0; + return NETDEV_TX_OK; } if (netiucv_test_and_set_busy(dev)) { diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 691cecd03b8..2cfc338c462 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -744,6 +744,7 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) card->stats.tx_bytes += tx_bytes; if (new_skb != skb) dev_kfree_skb_any(skb); + rc = NETDEV_TX_OK; } else { if (data_offset >= 0) kmem_cache_free(qeth_core_header_cache, hdr); diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 54872406864..048defaea81 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -2793,6 +2793,7 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) card->perf_stats.sg_frags_sent += nr_frags + 1; } } + rc = NETDEV_TX_OK; } else { if (data_offset >= 0) kmem_cache_free(qeth_core_header_cache, hdr); diff --git a/drivers/scsi/cxgb3i/Kbuild b/drivers/scsi/cxgb3i/Kbuild index 25a2032bfa2..70d060b7ff4 100644 --- a/drivers/scsi/cxgb3i/Kbuild +++ b/drivers/scsi/cxgb3i/Kbuild @@ -1,4 +1,4 @@ -EXTRA_CFLAGS += -I$(TOPDIR)/drivers/net/cxgb3 +EXTRA_CFLAGS += -I$(srctree)/drivers/net/cxgb3 cxgb3i-y := cxgb3i_init.o cxgb3i_iscsi.o cxgb3i_pdu.o cxgb3i_offload.o cxgb3i_ddp.o obj-$(CONFIG_SCSI_CXGB3_ISCSI) += cxgb3i.o diff --git a/drivers/scsi/cxgb3i/cxgb3i_iscsi.c b/drivers/scsi/cxgb3i/cxgb3i_iscsi.c index 74369a3f963..c399f485aa7 100644 --- a/drivers/scsi/cxgb3i/cxgb3i_iscsi.c +++ b/drivers/scsi/cxgb3i/cxgb3i_iscsi.c @@ -13,6 +13,7 @@ #include <linux/inet.h> #include <linux/crypto.h> +#include <linux/if_vlan.h> #include <net/dst.h> #include <net/tcp.h> #include <scsi/scsi_cmnd.h> @@ -184,6 +185,9 @@ static struct cxgb3i_hba *cxgb3i_hba_find_by_netdev(struct net_device *ndev) struct cxgb3i_adapter *snic; int i; + if (ndev->priv_flags & IFF_802_1Q_VLAN) + ndev = vlan_dev_real_dev(ndev); + read_lock(&cxgb3i_snic_rwlock); list_for_each_entry(snic, &cxgb3i_snic_list, list_head) { for (i = 0; i < snic->hba_cnt; i++) { diff --git a/drivers/scsi/fnic/fnic_main.c b/drivers/scsi/fnic/fnic_main.c index a84072865fc..2c266c01dc5 100644 --- a/drivers/scsi/fnic/fnic_main.c +++ b/drivers/scsi/fnic/fnic_main.c @@ -473,16 +473,16 @@ static int __devinit fnic_probe(struct pci_dev *pdev, * limitation for the device. Try 40-bit first, and * fail to 32-bit. */ - err = pci_set_dma_mask(pdev, DMA_40BIT_MASK); + err = pci_set_dma_mask(pdev, DMA_BIT_MASK(40)); if (err) { - err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); if (err) { shost_printk(KERN_ERR, fnic->lport->host, "No usable DMA configuration " "aborting\n"); goto err_out_release_regions; } - err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); + err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); if (err) { shost_printk(KERN_ERR, fnic->lport->host, "Unable to obtain 32-bit DMA " @@ -490,7 +490,7 @@ static int __devinit fnic_probe(struct pci_dev *pdev, goto err_out_release_regions; } } else { - err = pci_set_consistent_dma_mask(pdev, DMA_40BIT_MASK); + err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(40)); if (err) { shost_printk(KERN_ERR, fnic->lport->host, "Unable to obtain 40-bit DMA " diff --git a/drivers/scsi/fnic/fnic_scsi.c b/drivers/scsi/fnic/fnic_scsi.c index eabf3650285..bfc996971b8 100644 --- a/drivers/scsi/fnic/fnic_scsi.c +++ b/drivers/scsi/fnic/fnic_scsi.c @@ -245,7 +245,7 @@ static inline int fnic_queue_wq_copy_desc(struct fnic *fnic, struct vnic_wq_copy *wq, struct fnic_io_req *io_req, struct scsi_cmnd *sc, - u32 sg_count) + int sg_count) { struct scatterlist *sg; struct fc_rport *rport = starget_to_rport(scsi_target(sc->device)); @@ -260,9 +260,6 @@ static inline int fnic_queue_wq_copy_desc(struct fnic *fnic, char msg[2]; if (sg_count) { - BUG_ON(sg_count < 0); - BUG_ON(sg_count > FNIC_MAX_SG_DESC_CNT); - /* For each SGE, create a device desc entry */ desc = io_req->sgl_list; for_each_sg(scsi_sglist(sc), sg, sg_count, i) { @@ -344,7 +341,7 @@ int fnic_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) struct fnic *fnic; struct vnic_wq_copy *wq; int ret; - u32 sg_count; + int sg_count; unsigned long flags; unsigned long ptr; diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index 869a11bdccb..9928704e235 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -1095,9 +1095,14 @@ static void adapter_info_rsp(struct srp_event_struct *evt_struct) MAX_INDIRECT_BUFS); hostdata->host->sg_tablesize = MAX_INDIRECT_BUFS; } + + if (hostdata->madapter_info.os_type == 3) { + enable_fast_fail(hostdata); + return; + } } - enable_fast_fail(hostdata); + send_srp_login(hostdata); } /** diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index 2eee9e6e4fe..292c02f810d 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -3670,13 +3670,14 @@ static void fc_bsg_goose_queue(struct fc_rport *rport) { int flagset; + unsigned long flags; if (!rport->rqst_q) return; get_device(&rport->dev); - spin_lock(rport->rqst_q->queue_lock); + spin_lock_irqsave(rport->rqst_q->queue_lock, flags); flagset = test_bit(QUEUE_FLAG_REENTER, &rport->rqst_q->queue_flags) && !test_bit(QUEUE_FLAG_REENTER, &rport->rqst_q->queue_flags); if (flagset) @@ -3684,7 +3685,7 @@ fc_bsg_goose_queue(struct fc_rport *rport) __blk_run_queue(rport->rqst_q); if (flagset) queue_flag_clear(QUEUE_FLAG_REENTER, rport->rqst_q); - spin_unlock(rport->rqst_q->queue_lock); + spin_unlock_irqrestore(rport->rqst_q->queue_lock, flags); put_device(&rport->dev); } diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 8201387b4da..ef142fd47a8 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -210,13 +210,11 @@ static void sg_put_dev(Sg_device *sdp); static int sg_allow_access(struct file *filp, unsigned char *cmd) { struct sg_fd *sfp = (struct sg_fd *)filp->private_data; - struct request_queue *q = sfp->parentdp->device->request_queue; if (sfp->parentdp->device->type == TYPE_SCANNER) return 0; - return blk_verify_command(&q->cmd_filter, - cmd, filp->f_mode & FMODE_WRITE); + return blk_verify_command(cmd, filp->f_mode & FMODE_WRITE); } static int diff --git a/drivers/scsi/zalon.c b/drivers/scsi/zalon.c index 97f3158fa7b..27e84e4b1fa 100644 --- a/drivers/scsi/zalon.c +++ b/drivers/scsi/zalon.c @@ -134,7 +134,7 @@ zalon_probe(struct parisc_device *dev) host = ncr_attach(&zalon7xx_template, unit, &device); if (!host) - goto fail; + return -ENODEV; if (request_irq(dev->irq, ncr53c8xx_intr, IRQF_SHARED, "zalon", host)) { dev_printk(KERN_ERR, &dev->dev, "irq problem with %d, detaching\n ", diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c index a07015d646d..6160e03f410 100644 --- a/drivers/serial/8250_pci.c +++ b/drivers/serial/8250_pci.c @@ -759,6 +759,8 @@ static int pci_netmos_init(struct pci_dev *dev) /* subdevice 0x00PS means <P> parallel, <S> serial */ unsigned int num_serial = dev->subsystem_device & 0xf; + if (dev->device == PCI_DEVICE_ID_NETMOS_9901) + return 0; if (dev->subsystem_vendor == PCI_VENDOR_ID_IBM && dev->subsystem_device == 0x0299) return 0; @@ -3557,6 +3559,10 @@ static struct pci_device_id serial_pci_tbl[] = { PCI_VENDOR_ID_IBM, 0x0299, 0, 0, pbn_b0_bt_2_115200 }, + { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9901, + 0xA000, 0x1000, + 0, 0, pbn_b0_1_115200 }, + /* * These entries match devices with class COMMUNICATION_SERIAL, * COMMUNICATION_MODEM or COMMUNICATION_MULTISERIAL diff --git a/drivers/serial/vr41xx_siu.c b/drivers/serial/vr41xx_siu.c index 0573f3b5175..dac550e57c2 100644 --- a/drivers/serial/vr41xx_siu.c +++ b/drivers/serial/vr41xx_siu.c @@ -1,7 +1,7 @@ /* * Driver for NEC VR4100 series Serial Interface Unit. * - * Copyright (C) 2004-2008 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp> + * Copyright (C) 2004-2008 Yoichi Yuasa <yuasa@linux-mips.org> * * Based on drivers/serial/8250.c, by Russell King. * diff --git a/drivers/spi/omap_uwire.c b/drivers/spi/omap_uwire.c index aa90ddb3706..8980a5640bd 100644 --- a/drivers/spi/omap_uwire.c +++ b/drivers/spi/omap_uwire.c @@ -514,6 +514,8 @@ static int __init uwire_probe(struct platform_device *pdev) /* the spi->mode bits understood by this driver: */ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; + master->flags = SPI_MASTER_HALF_DUPLEX; + master->bus_num = 2; /* "official" */ master->num_chipselect = 4; master->setup = uwire_setup; diff --git a/drivers/spi/spi_bitbang.c b/drivers/spi/spi_bitbang.c index 2a5abc08e85..f1db395dd88 100644 --- a/drivers/spi/spi_bitbang.c +++ b/drivers/spi/spi_bitbang.c @@ -258,6 +258,11 @@ static void bitbang_work(struct work_struct *work) struct spi_bitbang *bitbang = container_of(work, struct spi_bitbang, work); unsigned long flags; + int do_setup = -1; + int (*setup_transfer)(struct spi_device *, + struct spi_transfer *); + + setup_transfer = bitbang->setup_transfer; spin_lock_irqsave(&bitbang->lock, flags); bitbang->busy = 1; @@ -269,8 +274,6 @@ static void bitbang_work(struct work_struct *work) unsigned tmp; unsigned cs_change; int status; - int (*setup_transfer)(struct spi_device *, - struct spi_transfer *); m = container_of(bitbang->queue.next, struct spi_message, queue); @@ -287,19 +290,19 @@ static void bitbang_work(struct work_struct *work) tmp = 0; cs_change = 1; status = 0; - setup_transfer = NULL; list_for_each_entry (t, &m->transfers, transfer_list) { - /* override or restore speed and wordsize */ - if (t->speed_hz || t->bits_per_word) { - setup_transfer = bitbang->setup_transfer; + /* override speed or wordsize? */ + if (t->speed_hz || t->bits_per_word) + do_setup = 1; + + /* init (-1) or override (1) transfer params */ + if (do_setup != 0) { if (!setup_transfer) { status = -ENOPROTOOPT; break; } - } - if (setup_transfer) { status = setup_transfer(spi, t); if (status < 0) break; @@ -363,9 +366,10 @@ static void bitbang_work(struct work_struct *work) m->status = status; m->complete(m->context); - /* restore speed and wordsize */ - if (setup_transfer) + /* restore speed and wordsize if it was overridden */ + if (do_setup == 1) setup_transfer(spi, NULL); + do_setup = 0; /* normally deactivate chipselect ... unless no error and * cs_change has hinted that the next message will probably diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c index 5d869c4d3eb..606e7a40a8d 100644 --- a/drivers/spi/spidev.c +++ b/drivers/spi/spidev.c @@ -58,15 +58,20 @@ static unsigned long minors[N_SPI_MINORS / BITS_PER_LONG]; /* Bit masks for spi_device.mode management. Note that incorrect - * settings for CS_HIGH and 3WIRE can cause *lots* of trouble for other - * devices on a shared bus: CS_HIGH, because this device will be - * active when it shouldn't be; 3WIRE, because when active it won't - * behave as it should. + * settings for some settings can cause *lots* of trouble for other + * devices on a shared bus: * - * REVISIT should changing those two modes be privileged? + * - CS_HIGH ... this device will be active when it shouldn't be + * - 3WIRE ... when active, it won't behave as it should + * - NO_CS ... there will be no explicit message boundaries; this + * is completely incompatible with the shared bus model + * - READY ... transfers may proceed when they shouldn't. + * + * REVISIT should changing those flags be privileged? */ #define SPI_MODE_MASK (SPI_CPHA | SPI_CPOL | SPI_CS_HIGH \ - | SPI_LSB_FIRST | SPI_3WIRE | SPI_LOOP) + | SPI_LSB_FIRST | SPI_3WIRE | SPI_LOOP \ + | SPI_NO_CS | SPI_READY) struct spidev_data { dev_t devt; diff --git a/drivers/ssb/driver_mipscore.c b/drivers/ssb/driver_mipscore.c index 3fd3e3b412b..3c6feed46f6 100644 --- a/drivers/ssb/driver_mipscore.c +++ b/drivers/ssb/driver_mipscore.c @@ -49,29 +49,54 @@ static const u32 ipsflag_irq_shift[] = { static inline u32 ssb_irqflag(struct ssb_device *dev) { - return ssb_read32(dev, SSB_TPSFLAG) & SSB_TPSFLAG_BPFLAG; + u32 tpsflag = ssb_read32(dev, SSB_TPSFLAG); + if (tpsflag) + return ssb_read32(dev, SSB_TPSFLAG) & SSB_TPSFLAG_BPFLAG; + else + /* not irq supported */ + return 0x3f; +} + +static struct ssb_device *find_device(struct ssb_device *rdev, int irqflag) +{ + struct ssb_bus *bus = rdev->bus; + int i; + for (i = 0; i < bus->nr_devices; i++) { + struct ssb_device *dev; + dev = &(bus->devices[i]); + if (ssb_irqflag(dev) == irqflag) + return dev; + } + return NULL; } /* Get the MIPS IRQ assignment for a specified device. * If unassigned, 0 is returned. + * If disabled, 5 is returned. + * If not supported, 6 is returned. */ unsigned int ssb_mips_irq(struct ssb_device *dev) { struct ssb_bus *bus = dev->bus; + struct ssb_device *mdev = bus->mipscore.dev; u32 irqflag; u32 ipsflag; u32 tmp; unsigned int irq; irqflag = ssb_irqflag(dev); + if (irqflag == 0x3f) + return 6; ipsflag = ssb_read32(bus->mipscore.dev, SSB_IPSFLAG); for (irq = 1; irq <= 4; irq++) { tmp = ((ipsflag & ipsflag_irq_mask[irq]) >> ipsflag_irq_shift[irq]); if (tmp == irqflag) break; } - if (irq == 5) - irq = 0; + if (irq == 5) { + if ((1 << irqflag) & ssb_read32(mdev, SSB_INTVEC)) + irq = 0; + } return irq; } @@ -97,25 +122,56 @@ static void set_irq(struct ssb_device *dev, unsigned int irq) struct ssb_device *mdev = bus->mipscore.dev; u32 irqflag = ssb_irqflag(dev); + BUG_ON(oldirq == 6); + dev->irq = irq + 2; - ssb_dprintk(KERN_INFO PFX - "set_irq: core 0x%04x, irq %d => %d\n", - dev->id.coreid, oldirq, irq); /* clear the old irq */ if (oldirq == 0) ssb_write32(mdev, SSB_INTVEC, (~(1 << irqflag) & ssb_read32(mdev, SSB_INTVEC))); - else + else if (oldirq != 5) clear_irq(bus, oldirq); /* assign the new one */ if (irq == 0) { ssb_write32(mdev, SSB_INTVEC, ((1 << irqflag) | ssb_read32(mdev, SSB_INTVEC))); } else { + u32 ipsflag = ssb_read32(mdev, SSB_IPSFLAG); + if ((ipsflag & ipsflag_irq_mask[irq]) != ipsflag_irq_mask[irq]) { + u32 oldipsflag = (ipsflag & ipsflag_irq_mask[irq]) >> ipsflag_irq_shift[irq]; + struct ssb_device *olddev = find_device(dev, oldipsflag); + if (olddev) + set_irq(olddev, 0); + } irqflag <<= ipsflag_irq_shift[irq]; - irqflag |= (ssb_read32(mdev, SSB_IPSFLAG) & ~ipsflag_irq_mask[irq]); + irqflag |= (ipsflag & ~ipsflag_irq_mask[irq]); ssb_write32(mdev, SSB_IPSFLAG, irqflag); } + ssb_dprintk(KERN_INFO PFX + "set_irq: core 0x%04x, irq %d => %d\n", + dev->id.coreid, oldirq+2, irq+2); +} + +static void print_irq(struct ssb_device *dev, unsigned int irq) +{ + int i; + static const char *irq_name[] = {"2(S)", "3", "4", "5", "6", "D", "I"}; + ssb_dprintk(KERN_INFO PFX + "core 0x%04x, irq :", dev->id.coreid); + for (i = 0; i <= 6; i++) { + ssb_dprintk(" %s%s", irq_name[i], i==irq?"*":" "); + } + ssb_dprintk("\n"); +} + +static void dump_irq(struct ssb_bus *bus) +{ + int i; + for (i = 0; i < bus->nr_devices; i++) { + struct ssb_device *dev; + dev = &(bus->devices[i]); + print_irq(dev, ssb_mips_irq(dev)); + } } static void ssb_mips_serial_init(struct ssb_mipscore *mcore) @@ -197,16 +253,23 @@ void ssb_mipscore_init(struct ssb_mipscore *mcore) /* Assign IRQs to all cores on the bus, start with irq line 2, because serial usually takes 1 */ for (irq = 2, i = 0; i < bus->nr_devices; i++) { + int mips_irq; dev = &(bus->devices[i]); - dev->irq = ssb_mips_irq(dev) + 2; + mips_irq = ssb_mips_irq(dev); + if (mips_irq > 4) + dev->irq = 0; + else + dev->irq = mips_irq + 2; + if (dev->irq > 5) + continue; switch (dev->id.coreid) { case SSB_DEV_USB11_HOST: /* shouldn't need a separate irq line for non-4710, most of them have a proper * external usb controller on the pci */ if ((bus->chip_id == 0x4710) && (irq <= 4)) { set_irq(dev, irq++); - break; } + break; /* fallthrough */ case SSB_DEV_PCI: case SSB_DEV_ETHERNET: @@ -220,6 +283,8 @@ void ssb_mipscore_init(struct ssb_mipscore *mcore) } } } + ssb_dprintk(KERN_INFO PFX "after irq reconfiguration\n"); + dump_irq(bus); ssb_mips_serial_init(mcore); ssb_mips_flash_detect(mcore); diff --git a/drivers/staging/at76_usb/at76_usb.c b/drivers/staging/at76_usb/at76_usb.c index 3f303ae97b4..7b8aa5edf42 100644 --- a/drivers/staging/at76_usb/at76_usb.c +++ b/drivers/staging/at76_usb/at76_usb.c @@ -3134,7 +3134,7 @@ static int at76_tx(struct sk_buff *skb, struct net_device *netdev) netdev->name, __func__); /* skip this packet */ dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } if (priv->tx_urb->status == -EINPROGRESS) { @@ -3142,14 +3142,14 @@ static int at76_tx(struct sk_buff *skb, struct net_device *netdev) netdev->name, __func__); /* skip this packet */ dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } if (skb->len < ETH_HLEN) { printk(KERN_ERR "%s: %s: skb too short (%d)\n", netdev->name, __func__, skb->len); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } at76_ledtrig_tx_activity(); /* tell ledtrigger we send a packet */ @@ -3173,7 +3173,7 @@ static int at76_tx(struct sk_buff *skb, struct net_device *netdev) skb->data[ETH_HLEN + 1], skb->data[ETH_HLEN + 2]); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } } else { /* add RFC 1042 header in front */ diff --git a/drivers/staging/epl/VirtualEthernetLinux.c b/drivers/staging/epl/VirtualEthernetLinux.c index 077724a556c..7b7cce1b36e 100644 --- a/drivers/staging/epl/VirtualEthernetLinux.c +++ b/drivers/staging/epl/VirtualEthernetLinux.c @@ -223,7 +223,7 @@ static int VEthXmit(struct sk_buff *pSkb_p, struct net_device *pNetDevice_p) } Exit: - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/staging/otus/usbdrv.c b/drivers/staging/otus/usbdrv.c index 540cbbb826f..7cd87caa681 100644 --- a/drivers/staging/otus/usbdrv.c +++ b/drivers/staging/otus/usbdrv.c @@ -659,7 +659,7 @@ int usbdrv_xmit_frame(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); } - return 0; + return NETDEV_TX_OK; } @@ -796,13 +796,13 @@ int zfLnxVapXmitFrame(struct sk_buff *skb, struct net_device *dev) if (vapId >= ZM_VAP_PORT_NUMBER) { dev_kfree_skb_irq(skb); - return 0; + return NETDEV_TX_OK; } #if 1 if (vap[vapId].openFlag == 0) { dev_kfree_skb_irq(skb); - return 0; + return NETDEV_TX_OK; } #endif @@ -819,7 +819,7 @@ int zfLnxVapXmitFrame(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); } - return 0; + return NETDEV_TX_OK; } static const struct net_device_ops vap_netdev_ops = { diff --git a/drivers/staging/otus/wrap_pkt.c b/drivers/staging/otus/wrap_pkt.c index 5db0004c873..89a6b92f597 100644 --- a/drivers/staging/otus/wrap_pkt.c +++ b/drivers/staging/otus/wrap_pkt.c @@ -156,10 +156,7 @@ void zfLnxRecvEth(zdev_t* dev, zbuf_t* buf, u16_t port) switch(netif_rx(buf)) #endif { - case NET_RX_BAD: case NET_RX_DROP: - case NET_RX_CN_MOD: - case NET_RX_CN_HIGH: break; default: macp->drv_stats.net_stats.rx_packets++; diff --git a/drivers/staging/rt2860/rt_main_dev.c b/drivers/staging/rt2860/rt_main_dev.c index f298b9bcec3..35c59d5aa99 100644 --- a/drivers/staging/rt2860/rt_main_dev.c +++ b/drivers/staging/rt2860/rt_main_dev.c @@ -862,7 +862,7 @@ int rt28xx_packet_xmit(struct sk_buff *skb) { struct net_device *net_dev = skb->dev; PRTMP_ADAPTER pAd = net_dev->ml_priv; - int status = 0; + int status = NETDEV_TX_OK; PNDIS_PACKET pPacket = (PNDIS_PACKET) skb; { @@ -892,7 +892,7 @@ int rt28xx_packet_xmit(struct sk_buff *skb) STASendPackets((NDIS_HANDLE)pAd, (PPNDIS_PACKET) &pPacket, 1); - status = 0; + status = NETDEV_TX_OK; done: return status; @@ -923,7 +923,7 @@ INT rt28xx_send_packets( if (!(net_dev->flags & IFF_UP)) { RELEASE_NDIS_PACKET(pAd, (PNDIS_PACKET)skb_p, NDIS_STATUS_FAILURE); - return 0; + return NETDEV_TX_OK; } NdisZeroMemory((PUCHAR)&skb_p->cb[CB_OFF], 15); diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c index 1294e05fcf1..1b774601b4a 100644 --- a/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c +++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c @@ -802,13 +802,13 @@ int ieee80211_xmit(struct sk_buff *skb, if ((*ieee->hard_start_xmit)(txb, dev) == 0) { stats->tx_packets++; stats->tx_bytes += txb->payload_size; - return 0; + return NETDEV_TX_OK; } ieee80211_txb_free(txb); } } - return 0; + return NETDEV_TX_OK; failed: spin_unlock_irqrestore(&ieee->lock, flags); diff --git a/drivers/staging/rtl8187se/r8180_core.c b/drivers/staging/rtl8187se/r8180_core.c index 7e2fecae813..26a59118d34 100644 --- a/drivers/staging/rtl8187se/r8180_core.c +++ b/drivers/staging/rtl8187se/r8180_core.c @@ -3040,7 +3040,7 @@ int rtl8180_hard_start_xmit(struct sk_buff *skb,struct net_device *dev) spin_unlock_irqrestore(&priv->tx_lock,flags); dev_kfree_skb_any(skb); - return 0; + return NETDEV_TX_OK; } rtl8180_tx(dev, skb->data, skb->len, priority, @@ -3051,7 +3051,7 @@ int rtl8180_hard_start_xmit(struct sk_buff *skb,struct net_device *dev) spin_unlock_irqrestore(&priv->tx_lock,flags); dev_kfree_skb_any(skb); - return 0; + return NETDEV_TX_OK; } // longpre 144+48 shortpre 72+24 diff --git a/drivers/staging/slicoss/slicoss.c b/drivers/staging/slicoss/slicoss.c index ed47db5ce5f..b01a2822a8e 100644 --- a/drivers/staging/slicoss/slicoss.c +++ b/drivers/staging/slicoss/slicoss.c @@ -845,7 +845,7 @@ static int slic_xmit_start(struct sk_buff *skb, struct net_device *dev) hcmd->paddrh, DONT_FLUSH); } xmit_done: - return 0; + return NETDEV_TX_OK; xmit_fail: slic_xmit_fail(adapter, skb, offloadcmd, skbtype, status); goto xmit_done; diff --git a/drivers/staging/wlan-ng/p80211netdev.c b/drivers/staging/wlan-ng/p80211netdev.c index 90f499e00dc..c273c034a83 100644 --- a/drivers/staging/wlan-ng/p80211netdev.c +++ b/drivers/staging/wlan-ng/p80211netdev.c @@ -354,7 +354,7 @@ static int p80211knetdev_hard_start_xmit(struct sk_buff *skb, p80211_metawep_t p80211_wep; if (skb == NULL) - return 0; + return NETDEV_TX_OK; if (wlandev->state != WLAN_DEVICE_OPEN) { result = 1; diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 38bfdb0f666..3f104599347 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -550,7 +550,7 @@ static void acm_waker(struct work_struct *waker) static int acm_tty_open(struct tty_struct *tty, struct file *filp) { struct acm *acm; - int rv = -EINVAL; + int rv = -ENODEV; int i; dbg("Entering acm_tty_open."); @@ -677,7 +677,7 @@ static void acm_tty_close(struct tty_struct *tty, struct file *filp) /* Perform the closing process and see if we need to do the hardware shutdown */ - if (tty_port_close_start(&acm->port, tty, filp) == 0) + if (!acm || tty_port_close_start(&acm->port, tty, filp) == 0) return; acm_port_down(acm, 0); tty_port_close_end(&acm->port, tty); diff --git a/drivers/usb/gadget/f_phonet.c b/drivers/usb/gadget/f_phonet.c index 96fb118355b..d17f1082df9 100644 --- a/drivers/usb/gadget/f_phonet.c +++ b/drivers/usb/gadget/f_phonet.c @@ -256,7 +256,7 @@ out: dev_kfree_skb(skb); dev->stats.tx_dropped++; } - return 0; + return NETDEV_TX_OK; } static int pn_net_mtu(struct net_device *dev, int new_mtu) diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c index 016f63b3902..aac69b591ae 100644 --- a/drivers/usb/gadget/u_ether.c +++ b/drivers/usb/gadget/u_ether.c @@ -487,7 +487,7 @@ static int eth_start_xmit(struct sk_buff *skb, struct net_device *net) if (!in) { dev_kfree_skb_any(skb); - return 0; + return NETDEV_TX_OK; } /* apply outgoing CDC or RNDIS filters */ @@ -506,7 +506,7 @@ static int eth_start_xmit(struct sk_buff *skb, struct net_device *net) type = USB_CDC_PACKET_TYPE_ALL_MULTICAST; if (!(cdc_filter & type)) { dev_kfree_skb_any(skb); - return 0; + return NETDEV_TX_OK; } } /* ignores USB_CDC_PACKET_TYPE_DIRECTED */ @@ -586,7 +586,7 @@ drop: list_add(&req->list, &dev->tx_reqs); spin_unlock_irqrestore(&dev->req_lock, flags); } - return 0; + return NETDEV_TX_OK; } /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index d595aa5586a..a84216464ca 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -333,6 +333,9 @@ static void serial_close(struct tty_struct *tty, struct file *filp) { struct usb_serial_port *port = tty->driver_data; + if (!port) + return; + dbg("%s - port %d", __func__, port->number); diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index d6d65ef85f5..8afcf08eba9 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -616,6 +616,8 @@ config FB_STI select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT + select STI_CONSOLE + select VT default y ---help--- STI refers to the HP "Standard Text Interface" which is a set of diff --git a/drivers/video/atafb.c b/drivers/video/atafb.c index 018850c116c..497ff8af03e 100644 --- a/drivers/video/atafb.c +++ b/drivers/video/atafb.c @@ -2414,7 +2414,10 @@ static int atafb_get_fix(struct fb_fix_screeninfo *fix, struct fb_info *info) if (err) return err; memset(fix, 0, sizeof(struct fb_fix_screeninfo)); - return fbhw->encode_fix(fix, &par); + mutex_lock(&info->mm_lock); + err = fbhw->encode_fix(fix, &par); + mutex_unlock(&info->mm_lock); + return err; } static int atafb_get_var(struct fb_var_screeninfo *var, struct fb_info *info) @@ -2743,7 +2746,9 @@ static int atafb_set_par(struct fb_info *info) /* Decode wanted screen parameters */ fbhw->decode_var(&info->var, par); + mutex_lock(&info->mm_lock); fbhw->encode_fix(&info->fix, par); + mutex_unlock(&info->mm_lock); /* Set new videomode */ ata_set_par(par); diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c index 5afd64482f5..cb88394ba99 100644 --- a/drivers/video/atmel_lcdfb.c +++ b/drivers/video/atmel_lcdfb.c @@ -270,7 +270,9 @@ static int atmel_lcdfb_alloc_video_memory(struct atmel_lcdfb_info *sinfo) smem_len = (var->xres_virtual * var->yres_virtual * ((var->bits_per_pixel + 7) / 8)); + mutex_lock(&info->mm_lock); info->fix.smem_len = max(smem_len, sinfo->smem_len); + mutex_unlock(&info->mm_lock); info->screen_base = dma_alloc_writecombine(info->device, info->fix.smem_len, (dma_addr_t *)&info->fix.smem_start, GFP_KERNEL); diff --git a/drivers/video/aty/atyfb.h b/drivers/video/aty/atyfb.h index 7691e73823d..1f39a62f899 100644 --- a/drivers/video/aty/atyfb.h +++ b/drivers/video/aty/atyfb.h @@ -187,6 +187,8 @@ struct atyfb_par { int mtrr_reg; #endif u32 mem_cntl; + struct crtc saved_crtc; + union aty_pll saved_pll; }; /* @@ -217,6 +219,7 @@ struct atyfb_par { #define M64F_XL_DLL 0x00080000 #define M64F_MFB_FORCE_4 0x00100000 #define M64F_HW_TRIPLE 0x00200000 +#define M64F_XL_MEM 0x00400000 /* * Register access */ diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c index 1207c208a30..63d3739d43a 100644 --- a/drivers/video/aty/atyfb_base.c +++ b/drivers/video/aty/atyfb_base.c @@ -66,6 +66,8 @@ #include <linux/spinlock.h> #include <linux/wait.h> #include <linux/backlight.h> +#include <linux/reboot.h> +#include <linux/dmi.h> #include <asm/io.h> #include <linux/uaccess.h> @@ -249,8 +251,6 @@ static int aty_init(struct fb_info *info); static int store_video_par(char *videopar, unsigned char m64_num); #endif -static struct crtc saved_crtc; -static union aty_pll saved_pll; static void aty_get_crtc(const struct atyfb_par *par, struct crtc *crtc); static void aty_set_crtc(const struct atyfb_par *par, const struct crtc *crtc); @@ -261,6 +261,8 @@ static void set_off_pitch(struct atyfb_par *par, const struct fb_info *info); static int read_aty_sense(const struct atyfb_par *par); #endif +static DEFINE_MUTEX(reboot_lock); +static struct fb_info *reboot_info; /* * Interface used by the world @@ -361,8 +363,8 @@ static unsigned long phys_guiregbase[FB_MAX] __devinitdata = { 0, }; #define ATI_CHIP_264GTPRO (ATI_MODERN_SET | M64F_SDRAM_MAGIC_PLL | M64F_HW_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D) #define ATI_CHIP_264LTPRO (ATI_MODERN_SET | M64F_HW_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D) -#define ATI_CHIP_264XL (ATI_MODERN_SET | M64F_HW_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D | M64F_XL_DLL | M64F_MFB_FORCE_4) -#define ATI_CHIP_MOBILITY (ATI_MODERN_SET | M64F_HW_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D | M64F_XL_DLL | M64F_MFB_FORCE_4 | M64F_MOBIL_BUS) +#define ATI_CHIP_264XL (ATI_MODERN_SET | M64F_HW_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D | M64F_XL_DLL | M64F_MFB_FORCE_4 | M64F_XL_MEM) +#define ATI_CHIP_MOBILITY (ATI_MODERN_SET | M64F_HW_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D | M64F_XL_DLL | M64F_MFB_FORCE_4 | M64F_XL_MEM | M64F_MOBIL_BUS) static struct { u16 pci_id; @@ -539,6 +541,7 @@ static char ram_edo[] __devinitdata = "EDO"; static char ram_sdram[] __devinitdata = "SDRAM (1:1)"; static char ram_sgram[] __devinitdata = "SGRAM (1:1)"; static char ram_sdram32[] __devinitdata = "SDRAM (2:1) (32-bit)"; +static char ram_wram[] __devinitdata = "WRAM"; static char ram_off[] __devinitdata = "OFF"; #endif /* CONFIG_FB_ATY_CT */ @@ -553,6 +556,10 @@ static char *aty_gx_ram[8] __devinitdata = { #ifdef CONFIG_FB_ATY_CT static char *aty_ct_ram[8] __devinitdata = { ram_off, ram_dram, ram_edo, ram_edo, + ram_sdram, ram_sgram, ram_wram, ram_resv +}; +static char *aty_xl_ram[8] __devinitdata = { + ram_off, ram_dram, ram_edo, ram_edo, ram_sdram, ram_sgram, ram_sdram32, ram_resv }; #endif /* CONFIG_FB_ATY_CT */ @@ -760,6 +767,17 @@ static void aty_set_crtc(const struct atyfb_par *par, const struct crtc *crtc) #endif /* CONFIG_FB_ATY_GENERIC_LCD */ } +static u32 calc_line_length(struct atyfb_par *par, u32 vxres, u32 bpp) +{ + u32 line_length = vxres * bpp / 8; + + if (par->ram_type == SGRAM || + (!M64_HAS(XL_MEM) && par->ram_type == WRAM)) + line_length = (line_length + 63) & ~63; + + return line_length; +} + static int aty_var_to_crtc(const struct fb_info *info, const struct fb_var_screeninfo *var, struct crtc *crtc) { @@ -769,13 +787,14 @@ static int aty_var_to_crtc(const struct fb_info *info, u32 h_total, h_disp, h_sync_strt, h_sync_end, h_sync_dly, h_sync_wid, h_sync_pol; u32 v_total, v_disp, v_sync_strt, v_sync_end, v_sync_wid, v_sync_pol, c_sync; u32 pix_width, dp_pix_width, dp_chain_mask; + u32 line_length; /* input */ - xres = var->xres; + xres = (var->xres + 7) & ~7; yres = var->yres; - vxres = var->xres_virtual; + vxres = (var->xres_virtual + 7) & ~7; vyres = var->yres_virtual; - xoffset = var->xoffset; + xoffset = (var->xoffset + 7) & ~7; yoffset = var->yoffset; bpp = var->bits_per_pixel; if (bpp == 16) @@ -827,7 +846,9 @@ static int aty_var_to_crtc(const struct fb_info *info, } else FAIL("invalid bpp"); - if (vxres * vyres * bpp / 8 > info->fix.smem_len) + line_length = calc_line_length(par, vxres, bpp); + + if (vyres * line_length > info->fix.smem_len) FAIL("not enough video RAM"); h_sync_pol = sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1; @@ -969,7 +990,9 @@ static int aty_var_to_crtc(const struct fb_info *info, crtc->xoffset = xoffset; crtc->yoffset = yoffset; crtc->bpp = bpp; - crtc->off_pitch = ((yoffset*vxres+xoffset)*bpp/64) | (vxres<<19); + crtc->off_pitch = + ((yoffset * line_length + xoffset * bpp / 8) / 8) | + ((line_length / bpp) << 22); crtc->vline_crnt_vline = 0; crtc->h_tot_disp = h_total | (h_disp<<16); @@ -1394,7 +1417,9 @@ static int atyfb_set_par(struct fb_info *info) } aty_st_8(DAC_MASK, 0xff, par); - info->fix.line_length = var->xres_virtual * var->bits_per_pixel/8; + info->fix.line_length = calc_line_length(par, var->xres_virtual, + var->bits_per_pixel); + info->fix.visual = var->bits_per_pixel <= 8 ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR; @@ -1505,10 +1530,12 @@ static void set_off_pitch(struct atyfb_par *par, const struct fb_info *info) { u32 xoffset = info->var.xoffset; u32 yoffset = info->var.yoffset; - u32 vxres = par->crtc.vxres; + u32 line_length = info->fix.line_length; u32 bpp = info->var.bits_per_pixel; - par->crtc.off_pitch = ((yoffset * vxres + xoffset) * bpp / 64) | (vxres << 19); + par->crtc.off_pitch = + ((yoffset * line_length + xoffset * bpp / 8) / 8) | + ((line_length / bpp) << 22); } @@ -2201,7 +2228,7 @@ static void __devinit aty_calc_mem_refresh(struct atyfb_par *par, int xclk) const int *refresh_tbl; int i, size; - if (IS_XL(par->pci_id) || IS_MOBILITY(par->pci_id)) { + if (M64_HAS(XL_MEM)) { refresh_tbl = ragexl_tbl; size = ARRAY_SIZE(ragexl_tbl); } else { @@ -2335,7 +2362,10 @@ static int __devinit aty_init(struct fb_info *info) par->pll_ops = &aty_pll_ct; par->bus_type = PCI; par->ram_type = (aty_ld_le32(CNFG_STAT0, par) & 0x07); - ramname = aty_ct_ram[par->ram_type]; + if (M64_HAS(XL_MEM)) + ramname = aty_xl_ram[par->ram_type]; + else + ramname = aty_ct_ram[par->ram_type]; /* for many chips, the mclk is 67 MHz for SDRAM, 63 MHz otherwise */ if (par->pll_limits.mclk == 67 && par->ram_type < SDRAM) par->pll_limits.mclk = 63; @@ -2390,9 +2420,9 @@ static int __devinit aty_init(struct fb_info *info) #endif /* CONFIG_FB_ATY_CT */ /* save previous video mode */ - aty_get_crtc(par, &saved_crtc); + aty_get_crtc(par, &par->saved_crtc); if(par->pll_ops->get_pll) - par->pll_ops->get_pll(info, &saved_pll); + par->pll_ops->get_pll(info, &par->saved_pll); par->mem_cntl = aty_ld_le32(MEM_CNTL, par); gtb_memsize = M64_HAS(GTB_DSP); @@ -2667,8 +2697,8 @@ static int __devinit aty_init(struct fb_info *info) aty_init_exit: /* restore video mode */ - aty_set_crtc(par, &saved_crtc); - par->pll_ops->set_pll(info, &saved_pll); + aty_set_crtc(par, &par->saved_crtc); + par->pll_ops->set_pll(info, &par->saved_pll); #ifdef CONFIG_MTRR if (par->mtrr_reg >= 0) { @@ -3502,6 +3532,11 @@ static int __devinit atyfb_pci_probe(struct pci_dev *pdev, const struct pci_devi par->mmap_map[1].prot_flag = _PAGE_E; #endif /* __sparc__ */ + mutex_lock(&reboot_lock); + if (!reboot_info) + reboot_info = info; + mutex_unlock(&reboot_lock); + return 0; err_release_io: @@ -3614,8 +3649,8 @@ static void __devexit atyfb_remove(struct fb_info *info) struct atyfb_par *par = (struct atyfb_par *) info->par; /* restore video mode */ - aty_set_crtc(par, &saved_crtc); - par->pll_ops->set_pll(info, &saved_pll); + aty_set_crtc(par, &par->saved_crtc); + par->pll_ops->set_pll(info, &par->saved_pll); unregister_framebuffer(info); @@ -3661,6 +3696,11 @@ static void __devexit atyfb_pci_remove(struct pci_dev *pdev) { struct fb_info *info = pci_get_drvdata(pdev); + mutex_lock(&reboot_lock); + if (reboot_info == info) + reboot_info = NULL; + mutex_unlock(&reboot_lock); + atyfb_remove(info); } @@ -3808,6 +3848,56 @@ static int __init atyfb_setup(char *options) } #endif /* MODULE */ +static int atyfb_reboot_notify(struct notifier_block *nb, + unsigned long code, void *unused) +{ + struct atyfb_par *par; + + if (code != SYS_RESTART) + return NOTIFY_DONE; + + mutex_lock(&reboot_lock); + + if (!reboot_info) + goto out; + + if (!lock_fb_info(reboot_info)) + goto out; + + par = reboot_info->par; + + /* + * HP OmniBook 500's BIOS doesn't like the state of the + * hardware after atyfb has been used. Restore the hardware + * to the original state to allow successful reboots. + */ + aty_set_crtc(par, &par->saved_crtc); + par->pll_ops->set_pll(reboot_info, &par->saved_pll); + + unlock_fb_info(reboot_info); + out: + mutex_unlock(&reboot_lock); + + return NOTIFY_DONE; +} + +static struct notifier_block atyfb_reboot_notifier = { + .notifier_call = atyfb_reboot_notify, +}; + +static const struct dmi_system_id atyfb_reboot_ids[] = { + { + .ident = "HP OmniBook 500", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP OmniBook PC"), + DMI_MATCH(DMI_PRODUCT_VERSION, "HP OmniBook 500 FA"), + }, + }, + + { } +}; + static int __init atyfb_init(void) { int err1 = 1, err2 = 1; @@ -3826,11 +3916,20 @@ static int __init atyfb_init(void) err2 = atyfb_atari_probe(); #endif - return (err1 && err2) ? -ENODEV : 0; + if (err1 && err2) + return -ENODEV; + + if (dmi_check_system(atyfb_reboot_ids)) + register_reboot_notifier(&atyfb_reboot_notifier); + + return 0; } static void __exit atyfb_exit(void) { + if (dmi_check_system(atyfb_reboot_ids)) + unregister_reboot_notifier(&atyfb_reboot_notifier); + #ifdef CONFIG_PCI pci_unregister_driver(&atyfb_driver); #endif diff --git a/drivers/video/aty/mach64_accel.c b/drivers/video/aty/mach64_accel.c index 0cc9724e61a..51fcc0a2c94 100644 --- a/drivers/video/aty/mach64_accel.c +++ b/drivers/video/aty/mach64_accel.c @@ -63,14 +63,17 @@ static void reset_GTC_3D_engine(const struct atyfb_par *par) void aty_init_engine(struct atyfb_par *par, struct fb_info *info) { u32 pitch_value; + u32 vxres; /* determine modal information from global mode structure */ - pitch_value = info->var.xres_virtual; + pitch_value = info->fix.line_length / (info->var.bits_per_pixel / 8); + vxres = info->var.xres_virtual; if (info->var.bits_per_pixel == 24) { /* In 24 bpp, the engine is in 8 bpp - this requires that all */ /* horizontal coordinates and widths must be adjusted */ pitch_value *= 3; + vxres *= 3; } /* On GTC (RagePro), we need to reset the 3D engine before */ @@ -133,7 +136,7 @@ void aty_init_engine(struct atyfb_par *par, struct fb_info *info) aty_st_le32(SC_LEFT, 0, par); aty_st_le32(SC_TOP, 0, par); aty_st_le32(SC_BOTTOM, par->crtc.vyres - 1, par); - aty_st_le32(SC_RIGHT, pitch_value - 1, par); + aty_st_le32(SC_RIGHT, vxres - 1, par); /* set background color to minimum value (usually BLACK) */ aty_st_le32(DP_BKGD_CLR, 0, par); diff --git a/drivers/video/backlight/tdo24m.c b/drivers/video/backlight/tdo24m.c index 1dae7f8f3c6..51422fc4f60 100644 --- a/drivers/video/backlight/tdo24m.c +++ b/drivers/video/backlight/tdo24m.c @@ -356,7 +356,7 @@ static int __devinit tdo24m_probe(struct spi_device *spi) lcd->power = FB_BLANK_POWERDOWN; lcd->mode = MODE_VGA; /* default to VGA */ - lcd->buf = kmalloc(TDO24M_SPI_BUFF_SIZE, sizeof(GFP_KERNEL)); + lcd->buf = kmalloc(TDO24M_SPI_BUFF_SIZE, GFP_KERNEL); if (lcd->buf == NULL) { kfree(lcd); return -ENOMEM; diff --git a/drivers/video/cobalt_lcdfb.c b/drivers/video/cobalt_lcdfb.c index 7bad24ed04e..108b89e09a8 100644 --- a/drivers/video/cobalt_lcdfb.c +++ b/drivers/video/cobalt_lcdfb.c @@ -1,7 +1,7 @@ /* * Cobalt server LCD frame buffer driver. * - * Copyright (C) 2008 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp> + * Copyright (C) 2008 Yoichi Yuasa <yuasa@linux-mips.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index f8a09bf8d0c..53ea05645ff 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -1310,8 +1310,6 @@ static long fb_compat_ioctl(struct file *file, unsigned int cmd, static int fb_mmap(struct file *file, struct vm_area_struct * vma) -__acquires(&info->lock) -__releases(&info->lock) { int fbidx = iminor(file->f_path.dentry->d_inode); struct fb_info *info = registered_fb[fbidx]; @@ -1325,16 +1323,14 @@ __releases(&info->lock) off = vma->vm_pgoff << PAGE_SHIFT; if (!fb) return -ENODEV; + mutex_lock(&info->mm_lock); if (fb->fb_mmap) { int res; - mutex_lock(&info->lock); res = fb->fb_mmap(info, vma); - mutex_unlock(&info->lock); + mutex_unlock(&info->mm_lock); return res; } - mutex_lock(&info->lock); - /* frame buffer memory */ start = info->fix.smem_start; len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len); @@ -1342,13 +1338,13 @@ __releases(&info->lock) /* memory mapped io */ off -= len; if (info->var.accel_flags) { - mutex_unlock(&info->lock); + mutex_unlock(&info->mm_lock); return -EINVAL; } start = info->fix.mmio_start; len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len); } - mutex_unlock(&info->lock); + mutex_unlock(&info->mm_lock); start &= PAGE_MASK; if ((vma->vm_end - vma->vm_start + off) > len) return -EINVAL; @@ -1518,6 +1514,7 @@ register_framebuffer(struct fb_info *fb_info) break; fb_info->node = i; mutex_init(&fb_info->lock); + mutex_init(&fb_info->mm_lock); fb_info->dev = device_create(fb_class, fb_info->device, MKDEV(FB_MAJOR, i), NULL, "fb%d", i); diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c index f153c581cbd..0bf2190928d 100644 --- a/drivers/video/fsl-diu-fb.c +++ b/drivers/video/fsl-diu-fb.c @@ -750,24 +750,26 @@ static void update_lcdc(struct fb_info *info) static int map_video_memory(struct fb_info *info) { phys_addr_t phys; + u32 smem_len = info->fix.line_length * info->var.yres_virtual; pr_debug("info->var.xres_virtual = %d\n", info->var.xres_virtual); pr_debug("info->var.yres_virtual = %d\n", info->var.yres_virtual); pr_debug("info->fix.line_length = %d\n", info->fix.line_length); + pr_debug("MAP_VIDEO_MEMORY: smem_len = %u\n", smem_len); - info->fix.smem_len = info->fix.line_length * info->var.yres_virtual; - pr_debug("MAP_VIDEO_MEMORY: smem_len = %d\n", info->fix.smem_len); - info->screen_base = fsl_diu_alloc(info->fix.smem_len, &phys); + info->screen_base = fsl_diu_alloc(smem_len, &phys); if (info->screen_base == NULL) { printk(KERN_ERR "Unable to allocate fb memory\n"); return -ENOMEM; } + mutex_lock(&info->mm_lock); info->fix.smem_start = (unsigned long) phys; + info->fix.smem_len = smem_len; + mutex_unlock(&info->mm_lock); info->screen_size = info->fix.smem_len; pr_debug("Allocated fb @ paddr=0x%08lx, size=%d.\n", - info->fix.smem_start, - info->fix.smem_len); + info->fix.smem_start, info->fix.smem_len); pr_debug("screen base %p\n", info->screen_base); return 0; @@ -776,9 +778,11 @@ static int map_video_memory(struct fb_info *info) static void unmap_video_memory(struct fb_info *info) { fsl_diu_free(info->screen_base, info->fix.smem_len); + mutex_lock(&info->mm_lock); info->screen_base = NULL; info->fix.smem_start = 0; info->fix.smem_len = 0; + mutex_unlock(&info->mm_lock); } /* diff --git a/drivers/video/i810/i810_main.c b/drivers/video/i810/i810_main.c index 2e940199fc8..71960672d72 100644 --- a/drivers/video/i810/i810_main.c +++ b/drivers/video/i810/i810_main.c @@ -1090,8 +1090,10 @@ static int encode_fix(struct fb_fix_screeninfo *fix, struct fb_info *info) memset(fix, 0, sizeof(struct fb_fix_screeninfo)); strcpy(fix->id, "I810"); + mutex_lock(&info->mm_lock); fix->smem_start = par->fb.physical; fix->smem_len = par->fb.size; + mutex_unlock(&info->mm_lock); fix->type = FB_TYPE_PACKED_PIXELS; fix->type_aux = 0; fix->xpanstep = 8; diff --git a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c index 8e7a275df50..59c3a2e1491 100644 --- a/drivers/video/matrox/matroxfb_base.c +++ b/drivers/video/matrox/matroxfb_base.c @@ -724,8 +724,10 @@ static void matroxfb_update_fix(WPMINFO2) struct fb_fix_screeninfo *fix = &ACCESS_FBINFO(fbcon).fix; DBG(__func__) + mutex_lock(&ACCESS_FBINFO(fbcon).mm_lock); fix->smem_start = ACCESS_FBINFO(video.base) + ACCESS_FBINFO(curr.ydstorg.bytes); fix->smem_len = ACCESS_FBINFO(video.len_usable) - ACCESS_FBINFO(curr.ydstorg.bytes); + mutex_unlock(&ACCESS_FBINFO(fbcon).mm_lock); } static int matroxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) @@ -2081,6 +2083,7 @@ static int matroxfb_probe(struct pci_dev* pdev, const struct pci_device_id* dumm spin_lock_init(&ACCESS_FBINFO(lock.accel)); init_rwsem(&ACCESS_FBINFO(crtc2.lock)); init_rwsem(&ACCESS_FBINFO(altout.lock)); + mutex_init(&ACCESS_FBINFO(fbcon).mm_lock); ACCESS_FBINFO(irq_flags) = 0; init_waitqueue_head(&ACCESS_FBINFO(crtc1.vsync.wait)); init_waitqueue_head(&ACCESS_FBINFO(crtc2.vsync.wait)); diff --git a/drivers/video/matrox/matroxfb_crtc2.c b/drivers/video/matrox/matroxfb_crtc2.c index 7ac4c5f6145..909e10a1189 100644 --- a/drivers/video/matrox/matroxfb_crtc2.c +++ b/drivers/video/matrox/matroxfb_crtc2.c @@ -289,13 +289,16 @@ static int matroxfb_dh_release(struct fb_info* info, int user) { #undef m2info } -static void matroxfb_dh_init_fix(struct matroxfb_dh_fb_info *m2info) { +static void matroxfb_dh_init_fix(struct matroxfb_dh_fb_info *m2info) +{ struct fb_fix_screeninfo *fix = &m2info->fbcon.fix; strcpy(fix->id, "MATROX DH"); + mutex_lock(&m2info->fbcon.mm_lock); fix->smem_start = m2info->video.base; fix->smem_len = m2info->video.len_usable; + mutex_unlock(&m2info->fbcon.mm_lock); fix->ypanstep = 1; fix->ywrapstep = 0; fix->xpanstep = 8; /* TBD */ diff --git a/drivers/video/mx3fb.c b/drivers/video/mx3fb.c index b7af5256e88..567fb944bd2 100644 --- a/drivers/video/mx3fb.c +++ b/drivers/video/mx3fb.c @@ -669,7 +669,7 @@ static uint32_t bpp_to_pixfmt(int bpp) } static int mx3fb_blank(int blank, struct fb_info *fbi); -static int mx3fb_map_video_memory(struct fb_info *fbi); +static int mx3fb_map_video_memory(struct fb_info *fbi, unsigned int mem_len); static int mx3fb_unmap_video_memory(struct fb_info *fbi); /** @@ -742,8 +742,7 @@ static int mx3fb_set_par(struct fb_info *fbi) if (fbi->fix.smem_start) mx3fb_unmap_video_memory(fbi); - fbi->fix.smem_len = mem_len; - if (mx3fb_map_video_memory(fbi) < 0) { + if (mx3fb_map_video_memory(fbi, mem_len) < 0) { mutex_unlock(&mx3_fbi->mutex); return -ENOMEM; } @@ -1198,6 +1197,7 @@ static int mx3fb_resume(struct platform_device *pdev) /** * mx3fb_map_video_memory() - allocates the DRAM memory for the frame buffer. * @fbi: framebuffer information pointer + * @mem_len: length of mapped memory * @return: Error code indicating success or failure * * This buffer is remapped into a non-cached, non-buffered, memory region to @@ -1205,23 +1205,26 @@ static int mx3fb_resume(struct platform_device *pdev) * area is remapped, all virtual memory access to the video memory should occur * at the new region. */ -static int mx3fb_map_video_memory(struct fb_info *fbi) +static int mx3fb_map_video_memory(struct fb_info *fbi, unsigned int mem_len) { int retval = 0; dma_addr_t addr; fbi->screen_base = dma_alloc_writecombine(fbi->device, - fbi->fix.smem_len, + mem_len, &addr, GFP_DMA); if (!fbi->screen_base) { dev_err(fbi->device, "Cannot allocate %u bytes framebuffer memory\n", - fbi->fix.smem_len); + mem_len); retval = -EBUSY; goto err0; } + mutex_lock(&fbi->mm_lock); fbi->fix.smem_start = addr; + fbi->fix.smem_len = mem_len; + mutex_unlock(&fbi->mm_lock); dev_dbg(fbi->device, "allocated fb @ p=0x%08x, v=0x%p, size=%d.\n", (uint32_t) fbi->fix.smem_start, fbi->screen_base, fbi->fix.smem_len); @@ -1251,8 +1254,10 @@ static int mx3fb_unmap_video_memory(struct fb_info *fbi) fbi->screen_base, fbi->fix.smem_start); fbi->screen_base = 0; + mutex_lock(&fbi->mm_lock); fbi->fix.smem_start = 0; fbi->fix.smem_len = 0; + mutex_unlock(&fbi->mm_lock); return 0; } diff --git a/drivers/video/omap/omapfb_main.c b/drivers/video/omap/omapfb_main.c index 060d72fe57c..4ea99bfc37b 100644 --- a/drivers/video/omap/omapfb_main.c +++ b/drivers/video/omap/omapfb_main.c @@ -393,8 +393,10 @@ static void set_fb_fix(struct fb_info *fbi) rg = &plane->fbdev->mem_desc.region[plane->idx]; fbi->screen_base = rg->vaddr; + mutex_lock(&fbi->mm_lock); fix->smem_start = rg->paddr; fix->smem_len = rg->size; + mutex_unlock(&fbi->mm_lock); fix->type = FB_TYPE_PACKED_PIXELS; bpp = var->bits_per_pixel; @@ -886,8 +888,10 @@ static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) * plane memory is dealloce'd, the other * screen parameters in var / fix are invalid. */ + mutex_lock(&fbi->mm_lock); fbi->fix.smem_start = 0; fbi->fix.smem_len = 0; + mutex_unlock(&fbi->mm_lock); } } } diff --git a/drivers/video/platinumfb.c b/drivers/video/platinumfb.c index 03b3670130a..bacfabd9ce1 100644 --- a/drivers/video/platinumfb.c +++ b/drivers/video/platinumfb.c @@ -141,7 +141,9 @@ static int platinumfb_set_par (struct fb_info *info) offset = 0x10; info->screen_base = pinfo->frame_buffer + init->fb_offset + offset; + mutex_lock(&info->mm_lock); info->fix.smem_start = (pinfo->frame_buffer_phys) + init->fb_offset + offset; + mutex_unlock(&info->mm_lock); info->fix.visual = (pinfo->cmode == CMODE_8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR; info->fix.line_length = vmode_attrs[pinfo->vmode-1].hres * (1<<pinfo->cmode) diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c index 0889d50c328..6506117c134 100644 --- a/drivers/video/pxafb.c +++ b/drivers/video/pxafb.c @@ -815,8 +815,10 @@ static int overlayfb_map_video_memory(struct pxafb_layer *ofb) ofb->video_mem_phys = virt_to_phys(ofb->video_mem); ofb->video_mem_size = size; + mutex_lock(&ofb->fb.mm_lock); ofb->fb.fix.smem_start = ofb->video_mem_phys; ofb->fb.fix.smem_len = ofb->fb.fix.line_length * var->yres_virtual; + mutex_unlock(&ofb->fb.mm_lock); ofb->fb.screen_base = ofb->video_mem; return 0; } diff --git a/drivers/video/sh7760fb.c b/drivers/video/sh7760fb.c index 653bdfee305..9f6d6e61f0c 100644 --- a/drivers/video/sh7760fb.c +++ b/drivers/video/sh7760fb.c @@ -120,18 +120,6 @@ static int sh7760_setcolreg (u_int regno, return 0; } -static void encode_fix(struct fb_fix_screeninfo *fix, struct fb_info *info, - unsigned long stride) -{ - memset(fix, 0, sizeof(struct fb_fix_screeninfo)); - strcpy(fix->id, "sh7760-lcdc"); - - fix->smem_start = (unsigned long)info->screen_base; - fix->smem_len = info->screen_size; - - fix->line_length = stride; -} - static int sh7760fb_get_color_info(struct device *dev, u16 lddfr, int *bpp, int *gray) { @@ -334,7 +322,8 @@ static int sh7760fb_set_par(struct fb_info *info) iowrite32(ldsarl, par->base + LDSARL); /* mem for lower half of DSTN */ - encode_fix(&info->fix, info, stride); + info->fix.line_length = stride; + sh7760fb_check_var(&info->var, info); sh7760fb_blank(FB_BLANK_UNBLANK, info); /* panel on! */ @@ -435,6 +424,8 @@ static int sh7760fb_alloc_mem(struct fb_info *info) info->screen_base = fbmem; info->screen_size = vram; + info->fix.smem_start = (unsigned long)info->screen_base; + info->fix.smem_len = info->screen_size; return 0; } @@ -520,6 +511,8 @@ static int __devinit sh7760fb_probe(struct platform_device *pdev) info->var.transp.length = 0; info->var.transp.msb_right = 0; + strcpy(info->fix.id, "sh7760-lcdc"); + /* set the DON2 bit now, before cmap allocation, as it will randomize * palette memory. */ diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index f10d2fbeda0..da983b720f0 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c @@ -17,6 +17,7 @@ #include <linux/platform_device.h> #include <linux/dma-mapping.h> #include <linux/interrupt.h> +#include <linux/vmalloc.h> #include <video/sh_mobile_lcdc.h> #include <asm/atomic.h> @@ -33,6 +34,7 @@ struct sh_mobile_lcdc_chan { struct fb_info info; dma_addr_t dma_handle; struct fb_deferred_io defio; + struct scatterlist *sglist; unsigned long frame_end; wait_queue_head_t frame_end_wait; }; @@ -206,16 +208,38 @@ static void sh_mobile_lcdc_clk_on(struct sh_mobile_lcdc_priv *priv) {} static void sh_mobile_lcdc_clk_off(struct sh_mobile_lcdc_priv *priv) {} #endif +static int sh_mobile_lcdc_sginit(struct fb_info *info, + struct list_head *pagelist) +{ + struct sh_mobile_lcdc_chan *ch = info->par; + unsigned int nr_pages_max = info->fix.smem_len >> PAGE_SHIFT; + struct page *page; + int nr_pages = 0; + + sg_init_table(ch->sglist, nr_pages_max); + + list_for_each_entry(page, pagelist, lru) + sg_set_page(&ch->sglist[nr_pages++], page, PAGE_SIZE, 0); + + return nr_pages; +} + static void sh_mobile_lcdc_deferred_io(struct fb_info *info, struct list_head *pagelist) { struct sh_mobile_lcdc_chan *ch = info->par; + unsigned int nr_pages; /* enable clocks before accessing hardware */ sh_mobile_lcdc_clk_on(ch->lcdc); + nr_pages = sh_mobile_lcdc_sginit(info, pagelist); + dma_map_sg(info->dev, ch->sglist, nr_pages, DMA_TO_DEVICE); + /* trigger panel update */ lcdc_write_chan(ch, LDSM2R, 1); + + dma_unmap_sg(info->dev, ch->sglist, nr_pages, DMA_TO_DEVICE); } static void sh_mobile_lcdc_deferred_io_touch(struct fb_info *info) @@ -846,21 +870,31 @@ static int __init sh_mobile_lcdc_probe(struct platform_device *pdev) } for (i = 0; i < j; i++) { - error = register_framebuffer(&priv->ch[i].info); + struct sh_mobile_lcdc_chan *ch = priv->ch + i; + + info = &ch->info; + + if (info->fbdefio) { + priv->ch->sglist = vmalloc(sizeof(struct scatterlist) * + info->fix.smem_len >> PAGE_SHIFT); + if (!priv->ch->sglist) { + dev_err(&pdev->dev, "cannot allocate sglist\n"); + goto err1; + } + } + + error = register_framebuffer(info); if (error < 0) goto err1; - } - for (i = 0; i < j; i++) { - info = &priv->ch[i].info; dev_info(info->dev, "registered %s/%s as %dx%d %dbpp.\n", pdev->name, - (priv->ch[i].cfg.chan == LCDC_CHAN_MAINLCD) ? + (ch->cfg.chan == LCDC_CHAN_MAINLCD) ? "mainlcd" : "sublcd", - (int) priv->ch[i].cfg.lcd_cfg.xres, - (int) priv->ch[i].cfg.lcd_cfg.yres, - priv->ch[i].cfg.bpp); + (int) ch->cfg.lcd_cfg.xres, + (int) ch->cfg.lcd_cfg.yres, + ch->cfg.bpp); /* deferred io mode: disable clock to save power */ if (info->fbdefio) @@ -892,6 +926,9 @@ static int sh_mobile_lcdc_remove(struct platform_device *pdev) if (!info->device) continue; + if (priv->ch[i].sglist) + vfree(priv->ch[i].sglist); + dma_free_coherent(&pdev->dev, info->fix.smem_len, info->screen_base, priv->ch[i].dma_handle); fb_dealloc_cmap(&info->cmap); diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c index 7072d19080d..fd33455389b 100644 --- a/drivers/video/sis/sis_main.c +++ b/drivers/video/sis/sis_main.c @@ -1847,8 +1847,10 @@ sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info) strcpy(fix->id, ivideo->myid); + mutex_lock(&info->mm_lock); fix->smem_start = ivideo->video_base + ivideo->video_offset; fix->smem_len = ivideo->sisfb_mem; + mutex_unlock(&info->mm_lock); fix->type = FB_TYPE_PACKED_PIXELS; fix->type_aux = 0; fix->visual = (ivideo->video_bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; diff --git a/drivers/video/sm501fb.c b/drivers/video/sm501fb.c index eb5d73a0670..16d4f4c7d52 100644 --- a/drivers/video/sm501fb.c +++ b/drivers/video/sm501fb.c @@ -145,7 +145,7 @@ static inline void sm501fb_sync_regs(struct sm501fb_info *info) #define SM501_MEMF_ACCEL (8) static int sm501_alloc_mem(struct sm501fb_info *inf, struct sm501_mem *mem, - unsigned int why, size_t size) + unsigned int why, size_t size, u32 smem_len) { struct sm501fb_par *par; struct fb_info *fbi; @@ -172,7 +172,7 @@ static int sm501_alloc_mem(struct sm501fb_info *inf, struct sm501_mem *mem, if (ptr > 0) ptr &= ~(PAGE_SIZE - 1); - if (fbi && ptr < fbi->fix.smem_len) + if (fbi && ptr < smem_len) return -ENOMEM; break; @@ -197,7 +197,7 @@ static int sm501_alloc_mem(struct sm501fb_info *inf, struct sm501_mem *mem, case SM501_MEMF_ACCEL: fbi = inf->fb[HEAD_CRT]; - ptr = fbi ? fbi->fix.smem_len : 0; + ptr = fbi ? smem_len : 0; fbi = inf->fb[HEAD_PANEL]; if (fbi) { @@ -413,6 +413,7 @@ static int sm501fb_set_par_common(struct fb_info *info, unsigned int mem_type; unsigned int clock_type; unsigned int head_addr; + unsigned int smem_len; dev_dbg(fbi->dev, "%s: %dx%d, bpp = %d, virtual %dx%d\n", __func__, var->xres, var->yres, var->bits_per_pixel, @@ -453,18 +454,20 @@ static int sm501fb_set_par_common(struct fb_info *info, /* allocate fb memory within 501 */ info->fix.line_length = (var->xres_virtual * var->bits_per_pixel)/8; - info->fix.smem_len = info->fix.line_length * var->yres_virtual; + smem_len = info->fix.line_length * var->yres_virtual; dev_dbg(fbi->dev, "%s: line length = %u\n", __func__, info->fix.line_length); - if (sm501_alloc_mem(fbi, &par->screen, mem_type, - info->fix.smem_len)) { + if (sm501_alloc_mem(fbi, &par->screen, mem_type, smem_len, smem_len)) { dev_err(fbi->dev, "no memory available\n"); return -ENOMEM; } + mutex_lock(&info->mm_lock); info->fix.smem_start = fbi->fbmem_res->start + par->screen.sm_addr; + info->fix.smem_len = smem_len; + mutex_unlock(&info->mm_lock); info->screen_base = fbi->fbmem + par->screen.sm_addr; info->screen_size = info->fix.smem_len; @@ -637,7 +640,8 @@ static int sm501fb_set_par_crt(struct fb_info *info) if ((control & SM501_DC_CRT_CONTROL_SEL) == 0) { /* the head is displaying panel data... */ - sm501_alloc_mem(fbi, &par->screen, SM501_MEMF_CRT, 0); + sm501_alloc_mem(fbi, &par->screen, SM501_MEMF_CRT, 0, + info->fix.smem_len); goto out_update; } @@ -1289,7 +1293,8 @@ static int sm501_init_cursor(struct fb_info *fbi, unsigned int reg_base) par->cursor_regs = info->regs + reg_base; - ret = sm501_alloc_mem(info, &par->cursor, SM501_MEMF_CURSOR, 1024); + ret = sm501_alloc_mem(info, &par->cursor, SM501_MEMF_CURSOR, 1024, + fbi->fix.smem_len); if (ret < 0) return ret; @@ -1619,6 +1624,8 @@ static int __devinit sm501fb_start_one(struct sm501fb_info *info, if (!fbi) return 0; + mutex_init(&info->fb[head]->mm_lock); + ret = sm501fb_init_fb(info->fb[head], head, drvname); if (ret) { dev_err(info->dev, "cannot initialise fb %s\n", drvname); diff --git a/drivers/video/w100fb.c b/drivers/video/w100fb.c index d0674f1e3f1..8a141c2c637 100644 --- a/drivers/video/w100fb.c +++ b/drivers/video/w100fb.c @@ -523,6 +523,7 @@ static int w100fb_set_par(struct fb_info *info) info->fix.ywrapstep = 0; info->fix.line_length = par->xres * BITS_PER_PIXEL / 8; + mutex_lock(&info->mm_lock); if ((par->xres*par->yres*BITS_PER_PIXEL/8) > (MEM_INT_SIZE+1)) { par->extmem_active = 1; info->fix.smem_len = par->mach->mem->size+1; @@ -530,6 +531,7 @@ static int w100fb_set_par(struct fb_info *info) par->extmem_active = 0; info->fix.smem_len = MEM_INT_SIZE+1; } + mutex_unlock(&info->mm_lock); w100fb_activate_var(par); } diff --git a/drivers/watchdog/wdrtas.c b/drivers/watchdog/wdrtas.c index a4fe7a38d9b..3bde56bce63 100644 --- a/drivers/watchdog/wdrtas.c +++ b/drivers/watchdog/wdrtas.c @@ -218,16 +218,14 @@ static void wdrtas_timer_keepalive(void) */ static int wdrtas_get_temperature(void) { - long result; + int result; int temperature = 0; - result = rtas_call(wdrtas_token_get_sensor_state, 2, 2, - (void *)__pa(&temperature), - WDRTAS_THERMAL_SENSOR, 0); + result = rtas_get_sensor(WDRTAS_THERMAL_SENSOR, 0, &temperature); if (result < 0) printk(KERN_WARNING "wdrtas: reading the thermal sensor " - "faild: %li\n", result); + "failed: %i\n", result); else temperature = ((temperature * 9) / 5) + 32; /* fahrenheit */ |