diff options
Diffstat (limited to 'drivers')
99 files changed, 1909 insertions, 2773 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig index 5c91d6afb11..aeb5ab2391e 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -68,8 +68,6 @@ source "drivers/leds/Kconfig" source "drivers/infiniband/Kconfig" -source "drivers/sn/Kconfig" - source "drivers/edac/Kconfig" source "drivers/rtc/Kconfig" diff --git a/drivers/base/topology.c b/drivers/base/topology.c index 915810f6237..8c52421cbc5 100644 --- a/drivers/base/topology.c +++ b/drivers/base/topology.c @@ -107,7 +107,7 @@ static int __cpuinit topology_remove_dev(struct sys_device * sys_dev) return 0; } -static int __cpuinit topology_cpu_callback(struct notifier_block *nfb, +static int topology_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) { unsigned int cpu = (unsigned long)hcpu; diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index bedb689b051..dff1e67b1dd 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -4301,7 +4301,7 @@ static int __init floppy_init(void) } use_virtual_dma = can_use_virtual_dma & 1; -#if defined(CONFIG_PPC64) +#if defined(CONFIG_PPC_MERGE) if (check_legacy_ioport(FDC1)) { del_timer(&fd_timeout); err = -ENODEV; diff --git a/drivers/char/genrtc.c b/drivers/char/genrtc.c index d3a2bc36129..588fca542a9 100644 --- a/drivers/char/genrtc.c +++ b/drivers/char/genrtc.c @@ -200,13 +200,13 @@ static ssize_t gen_rtc_read(struct file *file, char __user *buf, /* first test allows optimizer to nuke this case for 32-bit machines */ if (sizeof (int) != sizeof (long) && count == sizeof (unsigned int)) { unsigned int uidata = data; - retval = put_user(uidata, (unsigned long __user *)buf); + retval = put_user(uidata, (unsigned int __user *)buf) ?: + sizeof(unsigned int); } else { - retval = put_user(data, (unsigned long __user *)buf); + retval = put_user(data, (unsigned long __user *)buf) ?: + sizeof(unsigned long); } - if (!retval) - retval = sizeof(unsigned long); out: current->state = TASK_RUNNING; remove_wait_queue(&gen_rtc_wait, &wait); diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index 935670a3cd9..5755b7e5f18 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -860,9 +860,32 @@ static void k_slock(struct vc_data *vc, unsigned char value, char up_flag, struc } /* by default, 300ms interval for combination release */ -static long brl_timeout = 300; -MODULE_PARM_DESC(brl_timeout, "Braille keys release delay in ms (0 for combination on first release, < 0 for dead characters)"); -module_param(brl_timeout, long, 0644); +static unsigned brl_timeout = 300; +MODULE_PARM_DESC(brl_timeout, "Braille keys release delay in ms (0 for commit on first key release)"); +module_param(brl_timeout, uint, 0644); + +static unsigned brl_nbchords = 1; +MODULE_PARM_DESC(brl_nbchords, "Number of chords that produce a braille pattern (0 for dead chords)"); +module_param(brl_nbchords, uint, 0644); + +static void k_brlcommit(struct vc_data *vc, unsigned int pattern, char up_flag, struct pt_regs *regs) +{ + static unsigned long chords; + static unsigned committed; + + if (!brl_nbchords) + k_deadunicode(vc, BRL_UC_ROW | pattern, up_flag, regs); + else { + committed |= pattern; + chords++; + if (chords == brl_nbchords) { + k_unicode(vc, BRL_UC_ROW | committed, up_flag, regs); + chords = 0; + committed = 0; + } + } +} + static void k_brl(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs) { static unsigned pressed,committing; @@ -882,11 +905,6 @@ static void k_brl(struct vc_data *vc, unsigned char value, char up_flag, struct if (value > 8) return; - if (brl_timeout < 0) { - k_deadunicode(vc, BRL_UC_ROW | (1 << (value - 1)), up_flag, regs); - return; - } - if (up_flag) { if (brl_timeout) { if (!committing || @@ -897,13 +915,13 @@ static void k_brl(struct vc_data *vc, unsigned char value, char up_flag, struct pressed &= ~(1 << (value - 1)); if (!pressed) { if (committing) { - k_unicode(vc, BRL_UC_ROW | committing, 0, regs); + k_brlcommit(vc, committing, 0, regs); committing = 0; } } } else { if (committing) { - k_unicode(vc, BRL_UC_ROW | committing, 0, regs); + k_brlcommit(vc, committing, 0, regs); committing = 0; } pressed &= ~(1 << (value - 1)); diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 66719f9d294..1fa9fa157c1 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -27,6 +27,7 @@ #include <linux/crash_dump.h> #include <linux/backing-dev.h> #include <linux/bootmem.h> +#include <linux/pipe_fs_i.h> #include <asm/uaccess.h> #include <asm/io.h> @@ -578,6 +579,18 @@ static ssize_t write_null(struct file * file, const char __user * buf, return count; } +static int pipe_to_null(struct pipe_inode_info *info, struct pipe_buffer *buf, + struct splice_desc *sd) +{ + return sd->len; +} + +static ssize_t splice_write_null(struct pipe_inode_info *pipe,struct file *out, + loff_t *ppos, size_t len, unsigned int flags) +{ + return splice_from_pipe(pipe, out, ppos, len, flags, pipe_to_null); +} + #ifdef CONFIG_MMU /* * For fun, we are using the MMU for this. @@ -785,6 +798,7 @@ static struct file_operations null_fops = { .llseek = null_lseek, .read = read_null, .write = write_null, + .splice_write = splice_write_null, }; #if defined(CONFIG_ISA) || !defined(__mc68000__) diff --git a/drivers/char/mwave/mwavedd.c b/drivers/char/mwave/mwavedd.c index 8666171e187..d3ba2f860ef 100644 --- a/drivers/char/mwave/mwavedd.c +++ b/drivers/char/mwave/mwavedd.c @@ -271,7 +271,7 @@ static int mwave_ioctl(struct inode *inode, struct file *file, ipcnum, pDrvData->IPCs[ipcnum].usIntCount); - if (ipcnum > ARRAY_SIZE(pDrvData->IPCs)) { + if (ipcnum >= ARRAY_SIZE(pDrvData->IPCs)) { PRINTK_ERROR(KERN_ERR_MWAVE "mwavedd::mwave_ioctl:" " IOCTL_MW_REGISTER_IPC:" diff --git a/drivers/char/tipar.c b/drivers/char/tipar.c index eb2eb3e12d6..079db5a935a 100644 --- a/drivers/char/tipar.c +++ b/drivers/char/tipar.c @@ -515,7 +515,7 @@ tipar_init_module(void) err = PTR_ERR(tipar_class); goto out_chrdev; } - if (parport_register_driver(&tipar_driver) || tp_count == 0) { + if (parport_register_driver(&tipar_driver)) { printk(KERN_ERR "tipar: unable to register with parport\n"); err = -EIO; goto out_class; diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 9759d05b197..29b2fa5534a 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1497,7 +1497,7 @@ int cpufreq_update_policy(unsigned int cpu) } EXPORT_SYMBOL(cpufreq_update_policy); -static int __cpuinit cpufreq_cpu_callback(struct notifier_block *nfb, +static int cpufreq_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) { unsigned int cpu = (unsigned long)hcpu; diff --git a/drivers/edac/e752x_edac.c b/drivers/edac/e752x_edac.c index 66572c5323a..fce31936e6d 100644 --- a/drivers/edac/e752x_edac.c +++ b/drivers/edac/e752x_edac.c @@ -25,6 +25,8 @@ #include <linux/slab.h> #include "edac_mc.h" +static int force_function_unhide; + #define e752x_printk(level, fmt, arg...) \ edac_printk(level, "e752x", fmt, ##arg) @@ -782,8 +784,16 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx) debugf0("%s(): mci\n", __func__); debugf0("Starting Probe1\n"); - /* enable device 0 function 1 */ + /* check to see if device 0 function 1 is enabled; if it isn't, we + * assume the BIOS has reserved it for a reason and is expecting + * exclusive access, we take care not to violate that assumption and + * fail the probe. */ pci_read_config_byte(pdev, E752X_DEVPRES1, &stat8); + if (!force_function_unhide && !(stat8 & (1 << 5))) { + printk(KERN_INFO "Contact your BIOS vendor to see if the " + "E752x error registers can be safely un-hidden\n"); + goto fail; + } stat8 |= (1 << 5); pci_write_config_byte(pdev, E752X_DEVPRES1, stat8); @@ -1063,3 +1073,8 @@ module_exit(e752x_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Linux Networx (http://lnxi.com) Tom Zimmerman\n"); MODULE_DESCRIPTION("MC support for Intel e752x memory controllers"); + +module_param(force_function_unhide, int, 0444); +MODULE_PARM_DESC(force_function_unhide, "if BIOS sets Dev0:Fun1 up as hidden:" +" 1=force unhide and hope BIOS doesn't fight driver for Dev0:Fun1 access"); + diff --git a/drivers/infiniband/hw/ipath/ipath_debug.h b/drivers/infiniband/hw/ipath/ipath_debug.h index 593e28969c6..46762387f5f 100644 --- a/drivers/infiniband/hw/ipath/ipath_debug.h +++ b/drivers/infiniband/hw/ipath/ipath_debug.h @@ -60,11 +60,11 @@ #define __IPATH_KERNEL_SEND 0x2000 /* use kernel mode send */ #define __IPATH_EPKTDBG 0x4000 /* print ethernet packet data */ #define __IPATH_SMADBG 0x8000 /* sma packet debug */ -#define __IPATH_IPATHDBG 0x10000 /* Ethernet (IPATH) general debug on */ -#define __IPATH_IPATHWARN 0x20000 /* Ethernet (IPATH) warnings on */ -#define __IPATH_IPATHERR 0x40000 /* Ethernet (IPATH) errors on */ -#define __IPATH_IPATHPD 0x80000 /* Ethernet (IPATH) packet dump on */ -#define __IPATH_IPATHTABLE 0x100000 /* Ethernet (IPATH) table dump on */ +#define __IPATH_IPATHDBG 0x10000 /* Ethernet (IPATH) gen debug */ +#define __IPATH_IPATHWARN 0x20000 /* Ethernet (IPATH) warnings */ +#define __IPATH_IPATHERR 0x40000 /* Ethernet (IPATH) errors */ +#define __IPATH_IPATHPD 0x80000 /* Ethernet (IPATH) packet dump */ +#define __IPATH_IPATHTABLE 0x100000 /* Ethernet (IPATH) table dump */ #else /* _IPATH_DEBUGGING */ @@ -79,11 +79,12 @@ #define __IPATH_TRSAMPLE 0x0 /* generate trace buffer sample entries */ #define __IPATH_VERBDBG 0x0 /* very verbose debug */ #define __IPATH_PKTDBG 0x0 /* print packet data */ -#define __IPATH_PROCDBG 0x0 /* print process startup (init)/exit messages */ +#define __IPATH_PROCDBG 0x0 /* process startup (init)/exit messages */ /* print mmap/nopage stuff, not using VDBG any more */ #define __IPATH_MMDBG 0x0 #define __IPATH_EPKTDBG 0x0 /* print ethernet packet data */ -#define __IPATH_SMADBG 0x0 /* print process startup (init)/exit messages */#define __IPATH_IPATHDBG 0x0 /* Ethernet (IPATH) table dump on */ +#define __IPATH_SMADBG 0x0 /* process startup (init)/exit messages */ +#define __IPATH_IPATHDBG 0x0 /* Ethernet (IPATH) table dump on */ #define __IPATH_IPATHWARN 0x0 /* Ethernet (IPATH) warnings on */ #define __IPATH_IPATHERR 0x0 /* Ethernet (IPATH) errors on */ #define __IPATH_IPATHPD 0x0 /* Ethernet (IPATH) packet dump on */ diff --git a/drivers/infiniband/hw/ipath/ipath_diag.c b/drivers/infiniband/hw/ipath/ipath_diag.c index 7d3fb6996b4..28ddceb260e 100644 --- a/drivers/infiniband/hw/ipath/ipath_diag.c +++ b/drivers/infiniband/hw/ipath/ipath_diag.c @@ -277,13 +277,14 @@ static int ipath_diag_open(struct inode *in, struct file *fp) bail: spin_unlock_irqrestore(&ipath_devs_lock, flags); - mutex_unlock(&ipath_mutex); /* Only expose a way to reset the device if we make it into diag mode. */ if (ret == 0) ipath_expose_reset(&dd->pcidev->dev); + mutex_unlock(&ipath_mutex); + return ret; } diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c index e7617c3982e..398add4d4cb 100644 --- a/drivers/infiniband/hw/ipath/ipath_driver.c +++ b/drivers/infiniband/hw/ipath/ipath_driver.c @@ -418,9 +418,19 @@ static int __devinit ipath_init_one(struct pci_dev *pdev, ret = pci_set_dma_mask(pdev, DMA_64BIT_MASK); if (ret) { - dev_info(&pdev->dev, "pci_set_dma_mask unit %u " - "fails: %d\n", dd->ipath_unit, ret); - goto bail_regions; + /* + * if the 64 bit setup fails, try 32 bit. Some systems + * do not setup 64 bit maps on systems with 2GB or less + * memory installed. + */ + ret = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + if (ret) { + dev_info(&pdev->dev, "pci_set_dma_mask unit %u " + "fails: %d\n", dd->ipath_unit, ret); + goto bail_regions; + } + else + ipath_dbg("No 64bit DMA mask, used 32 bit mask\n"); } pci_set_master(pdev); @@ -1949,7 +1959,7 @@ int ipath_reset_device(int unit) } if (dd->ipath_pd) - for (i = 1; i < dd->ipath_portcnt; i++) { + for (i = 1; i < dd->ipath_cfgports; i++) { if (dd->ipath_pd[i] && dd->ipath_pd[i]->port_cnt) { ipath_dbg("unit %u port %d is in use " "(PID %u cmd %s), can't reset\n", diff --git a/drivers/infiniband/hw/ipath/ipath_init_chip.c b/drivers/infiniband/hw/ipath/ipath_init_chip.c index 2823ff9c0c6..16f640e1c16 100644 --- a/drivers/infiniband/hw/ipath/ipath_init_chip.c +++ b/drivers/infiniband/hw/ipath/ipath_init_chip.c @@ -53,13 +53,19 @@ MODULE_PARM_DESC(cfgports, "Set max number of ports to use"); /* * Number of buffers reserved for driver (layered drivers and SMA - * send). Reserved at end of buffer list. + * send). Reserved at end of buffer list. Initialized based on + * number of PIO buffers if not set via module interface. + * The problem with this is that it's global, but we'll use different + * numbers for different chip types. So the default value is not + * very useful. I've redefined it for the 1.3 release so that it's + * zero unless set by the user to something else, in which case we + * try to respect it. */ -static ushort ipath_kpiobufs = 32; +static ushort ipath_kpiobufs; static int ipath_set_kpiobufs(const char *val, struct kernel_param *kp); -module_param_call(kpiobufs, ipath_set_kpiobufs, param_get_uint, +module_param_call(kpiobufs, ipath_set_kpiobufs, param_get_ushort, &ipath_kpiobufs, S_IWUSR | S_IRUGO); MODULE_PARM_DESC(kpiobufs, "Set number of PIO buffers for driver"); @@ -531,8 +537,11 @@ static int init_housekeeping(struct ipath_devdata *dd, * Don't clear ipath_flags as 8bit mode was set before * entering this func. However, we do set the linkstate to * unknown, so we can watch for a transition. + * PRESENT is set because we want register reads to work, + * and the kernel infrastructure saw it in config space; + * We clear it if we have failures. */ - dd->ipath_flags |= IPATH_LINKUNK; + dd->ipath_flags |= IPATH_LINKUNK | IPATH_PRESENT; dd->ipath_flags &= ~(IPATH_LINKACTIVE | IPATH_LINKARMED | IPATH_LINKDOWN | IPATH_LINKINIT); @@ -560,6 +569,7 @@ static int init_housekeeping(struct ipath_devdata *dd, || (dd->ipath_uregbase & 0xffffffff) == 0xffffffff) { ipath_dev_err(dd, "Register read failures from chip, " "giving up initialization\n"); + dd->ipath_flags &= ~IPATH_PRESENT; ret = -ENODEV; goto done; } @@ -682,16 +692,14 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit) */ dd->ipath_pioavregs = ALIGN(val, sizeof(u64) * BITS_PER_BYTE / 2) / (sizeof(u64) * BITS_PER_BYTE / 2); - if (!ipath_kpiobufs) /* have to have at least 1, for SMA */ - kpiobufs = ipath_kpiobufs = 1; - else if ((dd->ipath_piobcnt2k + dd->ipath_piobcnt4k) < - (dd->ipath_cfgports * IPATH_MIN_USER_PORT_BUFCNT)) { - dev_info(&dd->pcidev->dev, "Too few PIO buffers (%u) " - "for %u ports to have %u each!\n", - dd->ipath_piobcnt2k + dd->ipath_piobcnt4k, - dd->ipath_cfgports, IPATH_MIN_USER_PORT_BUFCNT); - kpiobufs = 1; /* reserve just the minimum for SMA/ether */ - } else + if (ipath_kpiobufs == 0) { + /* not set by user, or set explictly to default */ + if ((dd->ipath_piobcnt2k + dd->ipath_piobcnt4k) > 128) + kpiobufs = 32; + else + kpiobufs = 16; + } + else kpiobufs = ipath_kpiobufs; if (kpiobufs > diff --git a/drivers/infiniband/hw/ipath/ipath_intr.c b/drivers/infiniband/hw/ipath/ipath_intr.c index 0bcb428041f..3e72a1fe3d7 100644 --- a/drivers/infiniband/hw/ipath/ipath_intr.c +++ b/drivers/infiniband/hw/ipath/ipath_intr.c @@ -665,14 +665,14 @@ static void handle_layer_pioavail(struct ipath_devdata *dd) ret = __ipath_layer_intr(dd, IPATH_LAYER_INT_SEND_CONTINUE); if (ret > 0) - goto clear; + goto set; ret = __ipath_verbs_piobufavail(dd); if (ret > 0) - goto clear; + goto set; return; -clear: +set: set_bit(IPATH_S_PIOINTBUFAVAIL, &dd->ipath_sendctrl); ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl); @@ -719,11 +719,24 @@ static void handle_rcv(struct ipath_devdata *dd, u32 istat) irqreturn_t ipath_intr(int irq, void *data, struct pt_regs *regs) { struct ipath_devdata *dd = data; - u32 istat = ipath_read_kreg32(dd, dd->ipath_kregs->kr_intstatus); + u32 istat; ipath_err_t estat = 0; static unsigned unexpected = 0; irqreturn_t ret; + if(!(dd->ipath_flags & IPATH_PRESENT)) { + /* this is mostly so we don't try to touch the chip while + * it is being reset */ + /* + * This return value is perhaps odd, but we do not want the + * interrupt core code to remove our interrupt handler + * because we don't appear to be handling an interrupt + * during a chip reset. + */ + return IRQ_HANDLED; + } + + istat = ipath_read_kreg32(dd, dd->ipath_kregs->kr_intstatus); if (unlikely(!istat)) { ipath_stats.sps_nullintr++; ret = IRQ_NONE; /* not our interrupt, or already handled */ diff --git a/drivers/infiniband/hw/ipath/ipath_kernel.h b/drivers/infiniband/hw/ipath/ipath_kernel.h index 0ce5f19c9d6..e6507f8115b 100644 --- a/drivers/infiniband/hw/ipath/ipath_kernel.h +++ b/drivers/infiniband/hw/ipath/ipath_kernel.h @@ -731,7 +731,7 @@ u64 ipath_read_kreg64_port(const struct ipath_devdata *, ipath_kreg, static inline u32 ipath_read_ureg32(const struct ipath_devdata *dd, ipath_ureg regno, int port) { - if (!dd->ipath_kregbase) + if (!dd->ipath_kregbase || !(dd->ipath_flags & IPATH_PRESENT)) return 0; return readl(regno + (u64 __iomem *) @@ -762,7 +762,7 @@ static inline void ipath_write_ureg(const struct ipath_devdata *dd, static inline u32 ipath_read_kreg32(const struct ipath_devdata *dd, ipath_kreg regno) { - if (!dd->ipath_kregbase) + if (!dd->ipath_kregbase || !(dd->ipath_flags & IPATH_PRESENT)) return -1; return readl((u32 __iomem *) & dd->ipath_kregbase[regno]); } @@ -770,7 +770,7 @@ static inline u32 ipath_read_kreg32(const struct ipath_devdata *dd, static inline u64 ipath_read_kreg64(const struct ipath_devdata *dd, ipath_kreg regno) { - if (!dd->ipath_kregbase) + if (!dd->ipath_kregbase || !(dd->ipath_flags & IPATH_PRESENT)) return -1; return readq(&dd->ipath_kregbase[regno]); @@ -786,7 +786,7 @@ static inline void ipath_write_kreg(const struct ipath_devdata *dd, static inline u64 ipath_read_creg(const struct ipath_devdata *dd, ipath_sreg regno) { - if (!dd->ipath_kregbase) + if (!dd->ipath_kregbase || !(dd->ipath_flags & IPATH_PRESENT)) return 0; return readq(regno + (u64 __iomem *) @@ -797,7 +797,7 @@ static inline u64 ipath_read_creg(const struct ipath_devdata *dd, static inline u32 ipath_read_creg32(const struct ipath_devdata *dd, ipath_sreg regno) { - if (!dd->ipath_kregbase) + if (!dd->ipath_kregbase || !(dd->ipath_flags & IPATH_PRESENT)) return 0; return readl(regno + (u64 __iomem *) (dd->ipath_cregbase + diff --git a/drivers/infiniband/hw/ipath/ipath_layer.c b/drivers/infiniband/hw/ipath/ipath_layer.c index 69ed1100701..9cb5258ffed 100644 --- a/drivers/infiniband/hw/ipath/ipath_layer.c +++ b/drivers/infiniband/hw/ipath/ipath_layer.c @@ -46,13 +46,15 @@ /* Acquire before ipath_devs_lock. */ static DEFINE_MUTEX(ipath_layer_mutex); +static int ipath_verbs_registered; + u16 ipath_layer_rcv_opcode; + static int (*layer_intr)(void *, u32); static int (*layer_rcv)(void *, void *, struct sk_buff *); static int (*layer_rcv_lid)(void *, void *); static int (*verbs_piobufavail)(void *); static void (*verbs_rcv)(void *, void *, void *, u32); -static int ipath_verbs_registered; static void *(*layer_add_one)(int, struct ipath_devdata *); static void (*layer_remove_one)(void *); @@ -586,6 +588,8 @@ void ipath_verbs_unregister(void) verbs_rcv = NULL; verbs_timer_cb = NULL; + ipath_verbs_registered = 0; + mutex_unlock(&ipath_layer_mutex); } diff --git a/drivers/infiniband/hw/ipath/ipath_pe800.c b/drivers/infiniband/hw/ipath/ipath_pe800.c index e1dc4f75706..6318067ab5e 100644 --- a/drivers/infiniband/hw/ipath/ipath_pe800.c +++ b/drivers/infiniband/hw/ipath/ipath_pe800.c @@ -972,6 +972,8 @@ static int ipath_setup_pe_reset(struct ipath_devdata *dd) /* Use ERROR so it shows up in logs, etc. */ ipath_dev_err(dd, "Resetting PE-800 unit %u\n", dd->ipath_unit); + /* keep chip from being accessed in a few places */ + dd->ipath_flags &= ~(IPATH_INITTED|IPATH_PRESENT); val = dd->ipath_control | INFINIPATH_C_RESET; ipath_write_kreg(dd, dd->ipath_kregs->kr_control, val); mb(); @@ -997,6 +999,8 @@ static int ipath_setup_pe_reset(struct ipath_devdata *dd) if ((r = pci_enable_device(dd->pcidev))) ipath_dev_err(dd, "pci_enable_device failed after " "reset: %d\n", r); + /* whether it worked or not, mark as present, again */ + dd->ipath_flags |= IPATH_PRESENT; val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_revision); if (val == dd->ipath_revision) { ipath_cdbg(VERBOSE, "Got matching revision " diff --git a/drivers/infiniband/hw/ipath/ipath_registers.h b/drivers/infiniband/hw/ipath/ipath_registers.h index 1e59750c5f6..402126eb79c 100644 --- a/drivers/infiniband/hw/ipath/ipath_registers.h +++ b/drivers/infiniband/hw/ipath/ipath_registers.h @@ -34,8 +34,9 @@ #define _IPATH_REGISTERS_H /* - * This file should only be included by kernel source, and by the diags. - * It defines the registers, and their contents, for the InfiniPath HT-400 chip + * This file should only be included by kernel source, and by the diags. It + * defines the registers, and their contents, for the InfiniPath HT-400 + * chip. */ /* @@ -156,8 +157,10 @@ #define INFINIPATH_IBCC_FLOWCTRLWATERMARK_SHIFT 8 #define INFINIPATH_IBCC_LINKINITCMD_MASK 0x3ULL #define INFINIPATH_IBCC_LINKINITCMD_DISABLE 1 -#define INFINIPATH_IBCC_LINKINITCMD_POLL 2 /* cycle through TS1/TS2 till OK */ -#define INFINIPATH_IBCC_LINKINITCMD_SLEEP 3 /* wait for TS1, then go on */ +/* cycle through TS1/TS2 till OK */ +#define INFINIPATH_IBCC_LINKINITCMD_POLL 2 +/* wait for TS1, then go on */ +#define INFINIPATH_IBCC_LINKINITCMD_SLEEP 3 #define INFINIPATH_IBCC_LINKINITCMD_SHIFT 16 #define INFINIPATH_IBCC_LINKCMD_MASK 0x3ULL #define INFINIPATH_IBCC_LINKCMD_INIT 1 /* move to 0x11 */ @@ -182,7 +185,8 @@ #define INFINIPATH_IBCS_LINKSTATE_SHIFT 4 #define INFINIPATH_IBCS_TXREADY 0x40000000 #define INFINIPATH_IBCS_TXCREDITOK 0x80000000 -/* link training states (shift by INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) */ +/* link training states (shift by + INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) */ #define INFINIPATH_IBCS_LT_STATE_DISABLED 0x00 #define INFINIPATH_IBCS_LT_STATE_LINKUP 0x01 #define INFINIPATH_IBCS_LT_STATE_POLLACTIVE 0x02 @@ -267,10 +271,12 @@ /* kr_serdesconfig0 bits */ #define INFINIPATH_SERDC0_RESET_MASK 0xfULL /* overal reset bits */ #define INFINIPATH_SERDC0_RESET_PLL 0x10000000ULL /* pll reset */ -#define INFINIPATH_SERDC0_TXIDLE 0xF000ULL /* tx idle enables (per lane) */ -#define INFINIPATH_SERDC0_RXDETECT_EN 0xF0000ULL /* rx detect enables (per lane) */ -#define INFINIPATH_SERDC0_L1PWR_DN 0xF0ULL /* L1 Power down; use with RXDETECT, - Otherwise not used on IB side */ +/* tx idle enables (per lane) */ +#define INFINIPATH_SERDC0_TXIDLE 0xF000ULL +/* rx detect enables (per lane) */ +#define INFINIPATH_SERDC0_RXDETECT_EN 0xF0000ULL +/* L1 Power down; use with RXDETECT, Otherwise not used on IB side */ +#define INFINIPATH_SERDC0_L1PWR_DN 0xF0ULL /* kr_xgxsconfig bits */ #define INFINIPATH_XGXS_RESET 0x7ULL @@ -390,12 +396,13 @@ struct ipath_kregs { ipath_kreg kr_txintmemsize; ipath_kreg kr_xgxsconfig; ipath_kreg kr_ibpllcfg; - /* use these two (and the following N ports) only with ipath_k*_kreg64_port(); - * not *kreg64() */ + /* use these two (and the following N ports) only with + * ipath_k*_kreg64_port(); not *kreg64() */ ipath_kreg kr_rcvhdraddr; ipath_kreg kr_rcvhdrtailaddr; - /* remaining registers are not present on all types of infinipath chips */ + /* remaining registers are not present on all types of infinipath + chips */ ipath_kreg kr_rcvpktledcnt; ipath_kreg kr_pcierbuftestreg0; ipath_kreg kr_pcierbuftestreg1; diff --git a/drivers/infiniband/hw/ipath/ipath_ruc.c b/drivers/infiniband/hw/ipath/ipath_ruc.c index f232e77b78e..eb81424b3c5 100644 --- a/drivers/infiniband/hw/ipath/ipath_ruc.c +++ b/drivers/infiniband/hw/ipath/ipath_ruc.c @@ -531,19 +531,12 @@ int ipath_post_rc_send(struct ipath_qp *qp, struct ib_send_wr *wr) } wqe->wr.num_sge = j; qp->s_head = next; - /* - * Wake up the send tasklet if the QP is not waiting - * for an RNR timeout. - */ - next = qp->s_rnr_timeout; spin_unlock_irqrestore(&qp->s_lock, flags); - if (next == 0) { - if (qp->ibqp.qp_type == IB_QPT_UC) - ipath_do_uc_send((unsigned long) qp); - else - ipath_do_rc_send((unsigned long) qp); - } + if (qp->ibqp.qp_type == IB_QPT_UC) + ipath_do_uc_send((unsigned long) qp); + else + ipath_do_rc_send((unsigned long) qp); ret = 0; diff --git a/drivers/infiniband/hw/ipath/ipath_sysfs.c b/drivers/infiniband/hw/ipath/ipath_sysfs.c index 32acd8048b4..f323791cc49 100644 --- a/drivers/infiniband/hw/ipath/ipath_sysfs.c +++ b/drivers/infiniband/hw/ipath/ipath_sysfs.c @@ -711,10 +711,22 @@ static struct attribute_group dev_attr_group = { * enters diag mode. A device reset is quite likely to crash the * machine entirely, so we don't want to normally make it * available. + * + * Called with ipath_mutex held. */ int ipath_expose_reset(struct device *dev) { - return device_create_file(dev, &dev_attr_reset); + static int exposed; + int ret; + + if (!exposed) { + ret = device_create_file(dev, &dev_attr_reset); + exposed = 1; + } + else + ret = 0; + + return ret; } int ipath_driver_create_group(struct device_driver *drv) diff --git a/drivers/infiniband/hw/ipath/ipath_ud.c b/drivers/infiniband/hw/ipath/ipath_ud.c index 01cfb30ee16..e606daf8321 100644 --- a/drivers/infiniband/hw/ipath/ipath_ud.c +++ b/drivers/infiniband/hw/ipath/ipath_ud.c @@ -46,8 +46,10 @@ * This is called from ipath_post_ud_send() to forward a WQE addressed * to the same HCA. */ -static void ipath_ud_loopback(struct ipath_qp *sqp, struct ipath_sge_state *ss, - u32 length, struct ib_send_wr *wr, struct ib_wc *wc) +static void ipath_ud_loopback(struct ipath_qp *sqp, + struct ipath_sge_state *ss, + u32 length, struct ib_send_wr *wr, + struct ib_wc *wc) { struct ipath_ibdev *dev = to_idev(sqp->ibqp.device); struct ipath_qp *qp; diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.c b/drivers/infiniband/hw/ipath/ipath_verbs.c index 8d2558a01f3..cb9e387c301 100644 --- a/drivers/infiniband/hw/ipath/ipath_verbs.c +++ b/drivers/infiniband/hw/ipath/ipath_verbs.c @@ -449,7 +449,6 @@ static void ipath_ib_timer(void *arg) { struct ipath_ibdev *dev = (struct ipath_ibdev *) arg; struct ipath_qp *resend = NULL; - struct ipath_qp *rnr = NULL; struct list_head *last; struct ipath_qp *qp; unsigned long flags; @@ -465,32 +464,18 @@ static void ipath_ib_timer(void *arg) last = &dev->pending[dev->pending_index]; while (!list_empty(last)) { qp = list_entry(last->next, struct ipath_qp, timerwait); - if (last->next == LIST_POISON1 || - last->next != &qp->timerwait || - qp->timerwait.prev != last) { - INIT_LIST_HEAD(last); - } else { - list_del(&qp->timerwait); - qp->timerwait.prev = (struct list_head *) resend; - resend = qp; - atomic_inc(&qp->refcount); - } + list_del(&qp->timerwait); + qp->timer_next = resend; + resend = qp; + atomic_inc(&qp->refcount); } last = &dev->rnrwait; if (!list_empty(last)) { qp = list_entry(last->next, struct ipath_qp, timerwait); if (--qp->s_rnr_timeout == 0) { do { - if (last->next == LIST_POISON1 || - last->next != &qp->timerwait || - qp->timerwait.prev != last) { - INIT_LIST_HEAD(last); - break; - } list_del(&qp->timerwait); - qp->timerwait.prev = - (struct list_head *) rnr; - rnr = qp; + tasklet_hi_schedule(&qp->s_task); if (list_empty(last)) break; qp = list_entry(last->next, struct ipath_qp, @@ -530,8 +515,7 @@ static void ipath_ib_timer(void *arg) spin_unlock_irqrestore(&dev->pending_lock, flags); /* XXX What if timer fires again while this is running? */ - for (qp = resend; qp != NULL; - qp = (struct ipath_qp *) qp->timerwait.prev) { + for (qp = resend; qp != NULL; qp = qp->timer_next) { struct ib_wc wc; spin_lock_irqsave(&qp->s_lock, flags); @@ -545,9 +529,6 @@ static void ipath_ib_timer(void *arg) if (atomic_dec_and_test(&qp->refcount)) wake_up(&qp->wait); } - for (qp = rnr; qp != NULL; - qp = (struct ipath_qp *) qp->timerwait.prev) - tasklet_hi_schedule(&qp->s_task); } /** @@ -556,9 +537,9 @@ static void ipath_ib_timer(void *arg) * * This is called from ipath_intr() at interrupt level when a PIO buffer is * available after ipath_verbs_send() returned an error that no buffers were - * available. Return 0 if we consumed all the PIO buffers and we still have + * available. Return 1 if we consumed all the PIO buffers and we still have * QPs waiting for buffers (for now, just do a tasklet_hi_schedule and - * return one). + * return zero). */ static int ipath_ib_piobufavail(void *arg) { @@ -579,7 +560,7 @@ static int ipath_ib_piobufavail(void *arg) spin_unlock_irqrestore(&dev->pending_lock, flags); bail: - return 1; + return 0; } static int ipath_query_device(struct ib_device *ibdev, @@ -1159,7 +1140,7 @@ static ssize_t show_stats(struct class_device *cdev, char *buf) len = sprintf(buf, "RC resends %d\n" - "RC QACKs %d\n" + "RC no QACK %d\n" "RC ACKs %d\n" "RC SEQ NAKs %d\n" "RC RDMA seq %d\n" diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.h b/drivers/infiniband/hw/ipath/ipath_verbs.h index fcafbc7c9e7..4f8d59300e9 100644 --- a/drivers/infiniband/hw/ipath/ipath_verbs.h +++ b/drivers/infiniband/hw/ipath/ipath_verbs.h @@ -282,7 +282,8 @@ struct ipath_srq { */ struct ipath_qp { struct ib_qp ibqp; - struct ipath_qp *next; /* link list for QPN hash table */ + struct ipath_qp *next; /* link list for QPN hash table */ + struct ipath_qp *timer_next; /* link list for ipath_ib_timer() */ struct list_head piowait; /* link for wait PIO buf */ struct list_head timerwait; /* link for waiting for timeouts */ struct ib_ah_attr remote_ah_attr; diff --git a/drivers/infiniband/hw/ipath/ips_common.h b/drivers/infiniband/hw/ipath/ips_common.h index 410a764dfce..ab7cbbbfd03 100644 --- a/drivers/infiniband/hw/ipath/ips_common.h +++ b/drivers/infiniband/hw/ipath/ips_common.h @@ -95,7 +95,7 @@ struct ether_header { __u8 seq_num; __le32 len; /* MUST be of word size due to PIO write requirements */ - __u32 csum; + __le32 csum; __le16 csum_offset; __le16 flags; __u16 first_2_bytes; diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c index 565a24b1756..a2eae8a3016 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.c +++ b/drivers/infiniband/hw/mthca/mthca_provider.c @@ -306,7 +306,7 @@ static int mthca_query_gid(struct ib_device *ibdev, u8 port, goto out; } - memcpy(gid->raw + 8, out_mad->data + (index % 8) * 16, 8); + memcpy(gid->raw + 8, out_mad->data + (index % 8) * 8, 8); out: kfree(in_mad); diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index a34e3d91d9e..ba325f16d07 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -403,6 +403,27 @@ static long evdev_ioctl_handler(struct file *file, unsigned int cmd, case EVIOCGID: if (copy_to_user(p, &dev->id, sizeof(struct input_id))) return -EFAULT; + return 0; + + case EVIOCGREP: + if (!test_bit(EV_REP, dev->evbit)) + return -ENOSYS; + if (put_user(dev->rep[REP_DELAY], ip)) + return -EFAULT; + if (put_user(dev->rep[REP_PERIOD], ip + 1)) + return -EFAULT; + return 0; + + case EVIOCSREP: + if (!test_bit(EV_REP, dev->evbit)) + return -ENOSYS; + if (get_user(u, ip)) + return -EFAULT; + if (get_user(v, ip + 1)) + return -EFAULT; + + input_event(dev, EV_REP, REP_DELAY, u); + input_event(dev, EV_REP, REP_PERIOD, v); return 0; diff --git a/drivers/input/input.c b/drivers/input/input.c index a935abeffff..3038c268917 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -155,6 +155,9 @@ void input_event(struct input_dev *dev, unsigned int type, unsigned int code, in if (code > SND_MAX || !test_bit(code, dev->sndbit)) return; + if (!!test_bit(code, dev->snd) != !!value) + change_bit(code, dev->snd); + if (dev->event) dev->event(dev, type, code, value); break; @@ -286,19 +289,19 @@ static struct input_device_id *input_match_device(struct input_device_id *id, st for (; id->flags || id->driver_info; id++) { if (id->flags & INPUT_DEVICE_ID_MATCH_BUS) - if (id->id.bustype != dev->id.bustype) + if (id->bustype != dev->id.bustype) continue; if (id->flags & INPUT_DEVICE_ID_MATCH_VENDOR) - if (id->id.vendor != dev->id.vendor) + if (id->vendor != dev->id.vendor) continue; if (id->flags & INPUT_DEVICE_ID_MATCH_PRODUCT) - if (id->id.product != dev->id.product) + if (id->product != dev->id.product) continue; if (id->flags & INPUT_DEVICE_ID_MATCH_VERSION) - if (id->id.version != dev->id.version) + if (id->version != dev->id.version) continue; MATCH_BIT(evbit, EV_MAX); diff --git a/drivers/input/keyboard/spitzkbd.c b/drivers/input/keyboard/spitzkbd.c index bc61cf8cfc6..1d238a9d52d 100644 --- a/drivers/input/keyboard/spitzkbd.c +++ b/drivers/input/keyboard/spitzkbd.c @@ -53,8 +53,8 @@ static unsigned char spitzkbd_keycode[NR_SCANCODES] = { KEY_LEFTCTRL, KEY_1, KEY_3, KEY_5, KEY_6, KEY_7, KEY_9, KEY_0, KEY_BACKSPACE, SPITZ_KEY_EXOK, SPITZ_KEY_EXCANCEL, 0, 0, 0, 0, 0, /* 1-16 */ 0, KEY_2, KEY_4, KEY_R, KEY_Y, KEY_8, KEY_I, KEY_O, KEY_P, SPITZ_KEY_EXJOGDOWN, SPITZ_KEY_EXJOGUP, 0, 0, 0, 0, 0, /* 17-32 */ KEY_TAB, KEY_Q, KEY_E, KEY_T, KEY_G, KEY_U, KEY_J, KEY_K, 0, 0, 0, 0, 0, 0, 0, 0, /* 33-48 */ - SPITZ_KEY_CALENDER, KEY_W, KEY_S, KEY_F, KEY_V, KEY_H, KEY_M, KEY_L, 0, KEY_RIGHTSHIFT, 0, 0, 0, 0, 0, 0, /* 49-64 */ - SPITZ_KEY_ADDRESS, KEY_A, KEY_D, KEY_C, KEY_B, KEY_N, KEY_DOT, 0, KEY_ENTER, KEY_LEFTSHIFT, 0, 0, 0, 0, 0, 0, /* 65-80 */ + SPITZ_KEY_ADDRESS, KEY_W, KEY_S, KEY_F, KEY_V, KEY_H, KEY_M, KEY_L, 0, KEY_RIGHTSHIFT, 0, 0, 0, 0, 0, 0, /* 49-64 */ + SPITZ_KEY_CALENDER, KEY_A, KEY_D, KEY_C, KEY_B, KEY_N, KEY_DOT, 0, KEY_ENTER, KEY_LEFTSHIFT, 0, 0, 0, 0, 0, 0, /* 65-80 */ SPITZ_KEY_MAIL, KEY_Z, KEY_X, KEY_MINUS, KEY_SPACE, KEY_COMMA, 0, KEY_UP, 0, 0, SPITZ_KEY_FN, 0, 0, 0, 0, 0, /* 81-96 */ KEY_SYSRQ, SPITZ_KEY_JAP1, SPITZ_KEY_JAP2, SPITZ_KEY_CANCEL, SPITZ_KEY_OK, SPITZ_KEY_MENU, KEY_LEFT, KEY_DOWN, KEY_RIGHT, 0, 0, 0, 0, 0, 0, 0 /* 97-112 */ }; diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c index 4b415d9b012..36cd2e07fce 100644 --- a/drivers/input/misc/wistron_btns.c +++ b/drivers/input/misc/wistron_btns.c @@ -273,6 +273,18 @@ static struct key_entry keymap_fs_amilo_pro_v2000[] = { { KE_END, 0 } }; +static struct key_entry keymap_fujitsu_n3510[] = { + { KE_KEY, 0x11, KEY_PROG1 }, + { KE_KEY, 0x12, KEY_PROG2 }, + { KE_KEY, 0x36, KEY_WWW }, + { KE_KEY, 0x31, KEY_MAIL }, + { KE_KEY, 0x71, KEY_STOPCD }, + { KE_KEY, 0x72, KEY_PLAYPAUSE }, + { KE_KEY, 0x74, KEY_REWIND }, + { KE_KEY, 0x78, KEY_FORWARD }, + { KE_END, 0 } +}; + static struct key_entry keymap_wistron_ms2141[] = { { KE_KEY, 0x11, KEY_PROG1 }, { KE_KEY, 0x12, KEY_PROG2 }, @@ -323,6 +335,24 @@ static struct dmi_system_id dmi_ids[] = { }, { .callback = dmi_matched, + .ident = "Fujitsu-Siemens Amilo M7400", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), + DMI_MATCH(DMI_PRODUCT_NAME, "AMILO M "), + }, + .driver_data = keymap_fs_amilo_pro_v2000 + }, + { + .callback = dmi_matched, + .ident = "Fujitsu N3510", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), + DMI_MATCH(DMI_PRODUCT_NAME, "N3510"), + }, + .driver_data = keymap_fujitsu_n3510 + }, + { + .callback = dmi_matched, .ident = "Acer Aspire 1500", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index 32d70ed8f41..136321a2cfd 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -302,8 +302,10 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, * Check if this is a new device announcement (0xAA 0x00) */ if (unlikely(psmouse->packet[0] == PSMOUSE_RET_BAT && psmouse->pktcnt <= 2)) { - if (psmouse->pktcnt == 1) + if (psmouse->pktcnt == 1) { + psmouse->last = jiffies; goto out; + } if (psmouse->packet[1] == PSMOUSE_RET_ID) { __psmouse_set_state(psmouse, PSMOUSE_IGNORE); diff --git a/drivers/input/serio/i8042-io.h b/drivers/input/serio/i8042-io.h index 9a922164425..cc21914fbc7 100644 --- a/drivers/input/serio/i8042-io.h +++ b/drivers/input/serio/i8042-io.h @@ -67,14 +67,14 @@ static inline int i8042_platform_init(void) * On some platforms touching the i8042 data register region can do really * bad things. Because of this the region is always reserved on such boxes. */ -#if !defined(__sh__) && !defined(__alpha__) && !defined(__mips__) && !defined(CONFIG_PPC64) +#if !defined(__sh__) && !defined(__alpha__) && !defined(__mips__) && !defined(CONFIG_PPC_MERGE) if (!request_region(I8042_DATA_REG, 16, "i8042")) return -EBUSY; #endif i8042_reset = 1; -#if defined(CONFIG_PPC64) +#if defined(CONFIG_PPC_MERGE) if (check_legacy_ioport(I8042_DATA_REG)) return -EBUSY; if (!request_region(I8042_DATA_REG, 16, "i8042")) diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index 46d1fec2cfd..1494175ac6f 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -2,6 +2,8 @@ * ADS7846 based touchscreen and sensor driver * * Copyright (c) 2005 David Brownell + * Copyright (c) 2006 Nokia Corporation + * Various changes: Imre Deak <imre.deak@nokia.com> * * Using code from: * - corgi_ts.c @@ -34,17 +36,25 @@ /* - * This code has been lightly tested on an ads7846. + * This code has been tested on an ads7846 / N770 device. * Support for ads7843 and ads7845 has only been stubbed in. * - * Not yet done: investigate the values reported. Are x/y/pressure - * event values sane enough for X11? How accurate are the temperature - * and voltage readings? (System-specific calibration should support + * Not yet done: How accurate are the temperature and voltage + * readings? (System-specific calibration should support * accuracy of 0.3 degrees C; otherwise it's 2.0 degrees.) * + * IRQ handling needs a workaround because of a shortcoming in handling + * edge triggered IRQs on some platforms like the OMAP1/2. These + * platforms don't handle the ARM lazy IRQ disabling properly, thus we + * have to maintain our own SW IRQ disabled status. This should be + * removed as soon as the affected platform's IRQ handling is fixed. + * * app note sbaa036 talks in more detail about accurate sampling... * that ought to help in situations like LCDs inducing noise (which * can also be helped by using synch signals) and more generally. + * This driver tries to utilize the measures described in the app + * note. The strength of filtering can be set in the board-* specific + * files. */ #define TS_POLL_PERIOD msecs_to_jiffies(10) @@ -61,6 +71,7 @@ struct ts_event { __be16 x; __be16 y; __be16 z1, z2; + int ignore; }; struct ads7846 { @@ -71,12 +82,23 @@ struct ads7846 { u16 model; u16 vref_delay_usecs; u16 x_plate_ohms; + u16 pressure_max; - u8 read_x, read_y, read_z1, read_z2; + u8 read_x, read_y, read_z1, read_z2, pwrdown; + u16 dummy; /* for the pwrdown read */ struct ts_event tc; - struct spi_transfer xfer[8]; - struct spi_message msg; + struct spi_transfer xfer[10]; + struct spi_message msg[5]; + struct spi_message *last_msg; + int msg_idx; + int read_cnt; + int read_rep; + int last_read; + + u16 debounce_max; + u16 debounce_tol; + u16 debounce_rep; spinlock_t lock; struct timer_list timer; /* P: lock */ @@ -84,6 +106,9 @@ struct ads7846 { unsigned pending:1; /* P: lock */ // FIXME remove "irq_disabled" unsigned irq_disabled:1; /* P: lock */ + unsigned disabled:1; + + int (*get_pendown_state)(void); }; /* leave chip selected when we're done, for quicker re-select? */ @@ -125,7 +150,9 @@ struct ads7846 { #define READ_Y (READ_12BIT_DFR(y) | ADS_PD10_ADC_ON) #define READ_Z1 (READ_12BIT_DFR(z1) | ADS_PD10_ADC_ON) #define READ_Z2 (READ_12BIT_DFR(z2) | ADS_PD10_ADC_ON) -#define READ_X (READ_12BIT_DFR(x) | ADS_PD10_PDOWN) /* LAST */ + +#define READ_X (READ_12BIT_DFR(x) | ADS_PD10_ADC_ON) +#define PWRDOWN (READ_12BIT_DFR(y) | ADS_PD10_PDOWN) /* LAST */ /* single-ended samples need to first power up reference voltage; * we leave both ADC and VREF powered @@ -152,6 +179,15 @@ struct ser_req { struct spi_transfer xfer[6]; }; +static void ads7846_enable(struct ads7846 *ts); +static void ads7846_disable(struct ads7846 *ts); + +static int device_suspended(struct device *dev) +{ + struct ads7846 *ts = dev_get_drvdata(dev); + return dev->power.power_state.event != PM_EVENT_ON || ts->disabled; +} + static int ads7846_read12_ser(struct device *dev, unsigned command) { struct spi_device *spi = to_spi_device(dev); @@ -164,7 +200,7 @@ static int ads7846_read12_ser(struct device *dev, unsigned command) if (!req) return -ENOMEM; - INIT_LIST_HEAD(&req->msg.transfers); + spi_message_init(&req->msg); /* activate reference, so it has time to settle; */ req->ref_on = REF_ON; @@ -204,8 +240,10 @@ static int ads7846_read12_ser(struct device *dev, unsigned command) for (i = 0; i < 6; i++) spi_message_add_tail(&req->xfer[i], &req->msg); + ts->irq_disabled = 1; disable_irq(spi->irq); status = spi_sync(spi, &req->msg); + ts->irq_disabled = 0; enable_irq(spi->irq); if (req->msg.status) @@ -233,6 +271,52 @@ SHOW(temp1) SHOW(vaux) SHOW(vbatt) +static int is_pen_down(struct device *dev) +{ + struct ads7846 *ts = dev_get_drvdata(dev); + + return ts->pendown; +} + +static ssize_t ads7846_pen_down_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", is_pen_down(dev)); +} + +static DEVICE_ATTR(pen_down, S_IRUGO, ads7846_pen_down_show, NULL); + +static ssize_t ads7846_disable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ads7846 *ts = dev_get_drvdata(dev); + + return sprintf(buf, "%u\n", ts->disabled); +} + +static ssize_t ads7846_disable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ads7846 *ts = dev_get_drvdata(dev); + char *endp; + int i; + + i = simple_strtoul(buf, &endp, 10); + spin_lock_irq(&ts->lock); + + if (i) + ads7846_disable(ts); + else + ads7846_enable(ts); + + spin_unlock_irq(&ts->lock); + + return count; +} + +static DEVICE_ATTR(disable, 0664, ads7846_disable_show, ads7846_disable_store); + /*--------------------------------------------------------------------------*/ /* @@ -264,7 +348,7 @@ static void ads7846_rx(void *ads) if (x == MAX_12BIT) x = 0; - if (x && z1 && ts->spi->dev.power.power_state.event == PM_EVENT_ON) { + if (likely(x && z1 && !device_suspended(&ts->spi->dev))) { /* compute touch pressure resistance using equation #2 */ Rt = z2; Rt -= z1; @@ -275,6 +359,14 @@ static void ads7846_rx(void *ads) } else Rt = 0; + /* Sample found inconsistent by debouncing or pressure is beyond + * the maximum. Don't report it to user space, repeat at least + * once more the measurement */ + if (ts->tc.ignore || Rt > ts->pressure_max) { + mod_timer(&ts->timer, jiffies + TS_POLL_PERIOD); + return; + } + /* NOTE: "pendown" is inferred from pressure; we don't rely on * being able to check nPENIRQ status, or "friendly" trigger modes * (both-edges is much better than just-falling or low-level). @@ -296,11 +388,13 @@ static void ads7846_rx(void *ads) if (Rt) { input_report_abs(input_dev, ABS_X, x); input_report_abs(input_dev, ABS_Y, y); - input_report_abs(input_dev, ABS_PRESSURE, Rt); sync = 1; } - if (sync) + + if (sync) { + input_report_abs(input_dev, ABS_PRESSURE, Rt); input_sync(input_dev); + } #ifdef VERBOSE if (Rt || ts->pendown) @@ -308,80 +402,138 @@ static void ads7846_rx(void *ads) x, y, Rt, Rt ? "" : " UP"); #endif - /* don't retrigger while we're suspended */ spin_lock_irqsave(&ts->lock, flags); ts->pendown = (Rt != 0); - ts->pending = 0; + mod_timer(&ts->timer, jiffies + TS_POLL_PERIOD); - if (ts->spi->dev.power.power_state.event == PM_EVENT_ON) { - if (ts->pendown) - mod_timer(&ts->timer, jiffies + TS_POLL_PERIOD); - else if (ts->irq_disabled) { - ts->irq_disabled = 0; - enable_irq(ts->spi->irq); + spin_unlock_irqrestore(&ts->lock, flags); +} + +static void ads7846_debounce(void *ads) +{ + struct ads7846 *ts = ads; + struct spi_message *m; + struct spi_transfer *t; + int val; + int status; + + m = &ts->msg[ts->msg_idx]; + t = list_entry(m->transfers.prev, struct spi_transfer, transfer_list); + val = (*(u16 *)t->rx_buf) >> 3; + if (!ts->read_cnt || (abs(ts->last_read - val) > ts->debounce_tol)) { + /* Repeat it, if this was the first read or the read + * wasn't consistent enough. */ + if (ts->read_cnt < ts->debounce_max) { + ts->last_read = val; + ts->read_cnt++; + } else { + /* Maximum number of debouncing reached and still + * not enough number of consistent readings. Abort + * the whole sample, repeat it in the next sampling + * period. + */ + ts->tc.ignore = 1; + ts->read_cnt = 0; + /* Last message will contain ads7846_rx() as the + * completion function. + */ + m = ts->last_msg; } + /* Start over collecting consistent readings. */ + ts->read_rep = 0; + } else { + if (++ts->read_rep > ts->debounce_rep) { + /* Got a good reading for this coordinate, + * go for the next one. */ + ts->tc.ignore = 0; + ts->msg_idx++; + ts->read_cnt = 0; + ts->read_rep = 0; + m++; + } else + /* Read more values that are consistent. */ + ts->read_cnt++; } - - spin_unlock_irqrestore(&ts->lock, flags); + status = spi_async(ts->spi, m); + if (status) + dev_err(&ts->spi->dev, "spi_async --> %d\n", + status); } static void ads7846_timer(unsigned long handle) { struct ads7846 *ts = (void *)handle; int status = 0; - unsigned long flags; + + spin_lock_irq(&ts->lock); + + if (unlikely(ts->msg_idx && !ts->pendown)) { + /* measurment cycle ended */ + if (!device_suspended(&ts->spi->dev)) { + ts->irq_disabled = 0; + enable_irq(ts->spi->irq); + } + ts->pending = 0; + ts->msg_idx = 0; + } else { + /* pen is still down, continue with the measurement */ + ts->msg_idx = 0; + status = spi_async(ts->spi, &ts->msg[0]); + if (status) + dev_err(&ts->spi->dev, "spi_async --> %d\n", status); + } + + spin_unlock_irq(&ts->lock); +} + +static irqreturn_t ads7846_irq(int irq, void *handle, struct pt_regs *regs) +{ + struct ads7846 *ts = handle; + unsigned long flags; spin_lock_irqsave(&ts->lock, flags); - if (!ts->pending) { - ts->pending = 1; + if (likely(ts->get_pendown_state())) { if (!ts->irq_disabled) { + /* REVISIT irq logic for many ARM chips has cloned a + * bug wherein disabling an irq in its handler won't + * work;(it's disabled lazily, and too late to work. + * until all their irq logic is fixed, we must shadow + * that state here. + */ ts->irq_disabled = 1; disable_irq(ts->spi->irq); + ts->pending = 1; + mod_timer(&ts->timer, jiffies); } - status = spi_async(ts->spi, &ts->msg); - if (status) - dev_err(&ts->spi->dev, "spi_async --> %d\n", - status); } spin_unlock_irqrestore(&ts->lock, flags); -} -static irqreturn_t ads7846_irq(int irq, void *handle, struct pt_regs *regs) -{ - ads7846_timer((unsigned long) handle); return IRQ_HANDLED; } /*--------------------------------------------------------------------------*/ -static int -ads7846_suspend(struct spi_device *spi, pm_message_t message) +/* Must be called with ts->lock held */ +static void ads7846_disable(struct ads7846 *ts) { - struct ads7846 *ts = dev_get_drvdata(&spi->dev); - unsigned long flags; + if (ts->disabled) + return; - spin_lock_irqsave(&ts->lock, flags); - - spi->dev.power.power_state = message; + ts->disabled = 1; /* are we waiting for IRQ, or polling? */ - if (!ts->pendown) { - if (!ts->irq_disabled) { - ts->irq_disabled = 1; - disable_irq(ts->spi->irq); - } + if (!ts->pending) { + ts->irq_disabled = 1; + disable_irq(ts->spi->irq); } else { - /* polling; force a final SPI completion; - * that will clean things up neatly + /* the timer will run at least once more, and + * leave everything in a clean state, IRQ disabled */ - if (!ts->pending) - mod_timer(&ts->timer, jiffies); - - while (ts->pendown || ts->pending) { - spin_unlock_irqrestore(&ts->lock, flags); - udelay(10); - spin_lock_irqsave(&ts->lock, flags); + while (ts->pending) { + spin_unlock_irq(&ts->lock); + msleep(1); + spin_lock_irq(&ts->lock); } } @@ -389,17 +541,45 @@ ads7846_suspend(struct spi_device *spi, pm_message_t message) * leave it that way after every request */ - spin_unlock_irqrestore(&ts->lock, flags); +} + +/* Must be called with ts->lock held */ +static void ads7846_enable(struct ads7846 *ts) +{ + if (!ts->disabled) + return; + + ts->disabled = 0; + ts->irq_disabled = 0; + enable_irq(ts->spi->irq); +} + +static int ads7846_suspend(struct spi_device *spi, pm_message_t message) +{ + struct ads7846 *ts = dev_get_drvdata(&spi->dev); + + spin_lock_irq(&ts->lock); + + spi->dev.power.power_state = message; + ads7846_disable(ts); + + spin_unlock_irq(&ts->lock); + return 0; + } static int ads7846_resume(struct spi_device *spi) { struct ads7846 *ts = dev_get_drvdata(&spi->dev); - ts->irq_disabled = 0; - enable_irq(ts->spi->irq); + spin_lock_irq(&ts->lock); + spi->dev.power.power_state = PMSG_ON; + ads7846_enable(ts); + + spin_unlock_irq(&ts->lock); + return 0; } @@ -408,6 +588,7 @@ static int __devinit ads7846_probe(struct spi_device *spi) struct ads7846 *ts; struct input_dev *input_dev; struct ads7846_platform_data *pdata = spi->dev.platform_data; + struct spi_message *m; struct spi_transfer *x; int err; @@ -428,6 +609,11 @@ static int __devinit ads7846_probe(struct spi_device *spi) return -EINVAL; } + if (pdata->get_pendown_state == NULL) { + dev_dbg(&spi->dev, "no get_pendown_state function?\n"); + return -EINVAL; + } + /* We'd set the wordsize to 12 bits ... except that some controllers * will then treat the 8 bit command words as 12 bits (and drop the * four MSBs of the 12 bit result). Result: inputs must be shifted @@ -451,9 +637,21 @@ static int __devinit ads7846_probe(struct spi_device *spi) ts->timer.data = (unsigned long) ts; ts->timer.function = ads7846_timer; + spin_lock_init(&ts->lock); + ts->model = pdata->model ? : 7846; ts->vref_delay_usecs = pdata->vref_delay_usecs ? : 100; ts->x_plate_ohms = pdata->x_plate_ohms ? : 400; + ts->pressure_max = pdata->pressure_max ? : ~0; + if (pdata->debounce_max) { + ts->debounce_max = pdata->debounce_max; + ts->debounce_tol = pdata->debounce_tol; + ts->debounce_rep = pdata->debounce_rep; + if (ts->debounce_rep > ts->debounce_max + 1) + ts->debounce_rep = ts->debounce_max - 1; + } else + ts->debounce_tol = ~0; + ts->get_pendown_state = pdata->get_pendown_state; snprintf(ts->phys, sizeof(ts->phys), "%s/input0", spi->dev.bus_id); @@ -477,60 +675,100 @@ static int __devinit ads7846_probe(struct spi_device *spi) /* set up the transfers to read touchscreen state; this assumes we * use formula #2 for pressure, not #3. */ - INIT_LIST_HEAD(&ts->msg.transfers); + m = &ts->msg[0]; x = ts->xfer; + spi_message_init(m); + /* y- still on; turn on only y+ (and ADC) */ ts->read_y = READ_Y; x->tx_buf = &ts->read_y; x->len = 1; - spi_message_add_tail(x, &ts->msg); + spi_message_add_tail(x, m); x++; x->rx_buf = &ts->tc.y; x->len = 2; - spi_message_add_tail(x, &ts->msg); + spi_message_add_tail(x, m); + + m->complete = ads7846_debounce; + m->context = ts; + + m++; + spi_message_init(m); + + /* turn y- off, x+ on, then leave in lowpower */ + x++; + ts->read_x = READ_X; + x->tx_buf = &ts->read_x; + x->len = 1; + spi_message_add_tail(x, m); + + x++; + x->rx_buf = &ts->tc.x; + x->len = 2; + spi_message_add_tail(x, m); + + m->complete = ads7846_debounce; + m->context = ts; /* turn y+ off, x- on; we'll use formula #2 */ if (ts->model == 7846) { + m++; + spi_message_init(m); + x++; ts->read_z1 = READ_Z1; x->tx_buf = &ts->read_z1; x->len = 1; - spi_message_add_tail(x, &ts->msg); + spi_message_add_tail(x, m); x++; x->rx_buf = &ts->tc.z1; x->len = 2; - spi_message_add_tail(x, &ts->msg); + spi_message_add_tail(x, m); + + m->complete = ads7846_debounce; + m->context = ts; + + m++; + spi_message_init(m); x++; ts->read_z2 = READ_Z2; x->tx_buf = &ts->read_z2; x->len = 1; - spi_message_add_tail(x, &ts->msg); + spi_message_add_tail(x, m); x++; x->rx_buf = &ts->tc.z2; x->len = 2; - spi_message_add_tail(x, &ts->msg); + spi_message_add_tail(x, m); + + m->complete = ads7846_debounce; + m->context = ts; } - /* turn y- off, x+ on, then leave in lowpower */ + /* power down */ + m++; + spi_message_init(m); + x++; - ts->read_x = READ_X; - x->tx_buf = &ts->read_x; + ts->pwrdown = PWRDOWN; + x->tx_buf = &ts->pwrdown; x->len = 1; - spi_message_add_tail(x, &ts->msg); + spi_message_add_tail(x, m); x++; - x->rx_buf = &ts->tc.x; + x->rx_buf = &ts->dummy; x->len = 2; CS_CHANGE(*x); - spi_message_add_tail(x, &ts->msg); + spi_message_add_tail(x, m); - ts->msg.complete = ads7846_rx; - ts->msg.context = ts; + m->complete = ads7846_rx; + m->context = ts; + + ts->last_msg = m; if (request_irq(spi->irq, ads7846_irq, SA_SAMPLE_RANDOM | SA_TRIGGER_FALLING, @@ -559,13 +797,27 @@ static int __devinit ads7846_probe(struct spi_device *spi) device_create_file(&spi->dev, &dev_attr_vbatt); device_create_file(&spi->dev, &dev_attr_vaux); + device_create_file(&spi->dev, &dev_attr_pen_down); + + device_create_file(&spi->dev, &dev_attr_disable); + err = input_register_device(input_dev); if (err) - goto err_free_irq; + goto err_remove_attr; return 0; - err_free_irq: + err_remove_attr: + device_remove_file(&spi->dev, &dev_attr_disable); + device_remove_file(&spi->dev, &dev_attr_pen_down); + if (ts->model == 7846) { + device_remove_file(&spi->dev, &dev_attr_temp1); + device_remove_file(&spi->dev, &dev_attr_temp0); + } + if (ts->model != 7845) + device_remove_file(&spi->dev, &dev_attr_vbatt); + device_remove_file(&spi->dev, &dev_attr_vaux); + free_irq(spi->irq, ts); err_free_mem: input_free_device(input_dev); @@ -577,20 +829,24 @@ static int __devexit ads7846_remove(struct spi_device *spi) { struct ads7846 *ts = dev_get_drvdata(&spi->dev); + input_unregister_device(ts->input); + ads7846_suspend(spi, PMSG_SUSPEND); - free_irq(ts->spi->irq, ts); - if (ts->irq_disabled) - enable_irq(ts->spi->irq); + device_remove_file(&spi->dev, &dev_attr_disable); + device_remove_file(&spi->dev, &dev_attr_pen_down); if (ts->model == 7846) { - device_remove_file(&spi->dev, &dev_attr_temp0); device_remove_file(&spi->dev, &dev_attr_temp1); + device_remove_file(&spi->dev, &dev_attr_temp0); } if (ts->model != 7845) device_remove_file(&spi->dev, &dev_attr_vbatt); device_remove_file(&spi->dev, &dev_attr_vaux); - input_unregister_device(ts->input); + free_irq(ts->spi->irq, ts); + /* suspend left the IRQ disabled */ + enable_irq(ts->spi->irq); + kfree(ts); dev_dbg(&spi->dev, "unregistered touchscreen\n"); diff --git a/drivers/input/touchscreen/corgi_ts.c b/drivers/input/touchscreen/corgi_ts.c index 1042987856f..5013703db0e 100644 --- a/drivers/input/touchscreen/corgi_ts.c +++ b/drivers/input/touchscreen/corgi_ts.c @@ -17,7 +17,7 @@ #include <linux/interrupt.h> #include <linux/module.h> #include <linux/slab.h> -#include <asm/irq.h> +//#include <asm/irq.h> #include <asm/arch/sharpsl.h> #include <asm/arch/hardware.h> diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 6081941de1b..4070eff6f0f 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -315,10 +315,11 @@ static int raid1_end_write_request(struct bio *bio, unsigned int bytes_done, int if (r1_bio->bios[mirror] == bio) break; - if (error == -ENOTSUPP && test_bit(R1BIO_Barrier, &r1_bio->state)) { + if (error == -EOPNOTSUPP && test_bit(R1BIO_Barrier, &r1_bio->state)) { set_bit(BarriersNotsupp, &conf->mirrors[mirror].rdev->flags); set_bit(R1BIO_BarrierRetry, &r1_bio->state); r1_bio->mddev->barriers_work = 0; + /* Don't rdev_dec_pending in this branch - keep it for the retry */ } else { /* * this branch is our 'one mirror IO has finished' event handler: @@ -365,6 +366,7 @@ static int raid1_end_write_request(struct bio *bio, unsigned int bytes_done, int } } } + rdev_dec_pending(conf->mirrors[mirror].rdev, conf->mddev); } /* * @@ -374,11 +376,9 @@ static int raid1_end_write_request(struct bio *bio, unsigned int bytes_done, int if (atomic_dec_and_test(&r1_bio->remaining)) { if (test_bit(R1BIO_BarrierRetry, &r1_bio->state)) { reschedule_retry(r1_bio); - /* Don't dec_pending yet, we want to hold - * the reference over the retry - */ goto out; } + /* it really is the end of this request */ if (test_bit(R1BIO_BehindIO, &r1_bio->state)) { /* free extra copy of the data pages */ int i = bio->bi_vcnt; @@ -393,8 +393,6 @@ static int raid1_end_write_request(struct bio *bio, unsigned int bytes_done, int md_write_end(r1_bio->mddev); raid_end_bio_io(r1_bio); } - - rdev_dec_pending(conf->mirrors[mirror].rdev, conf->mddev); out: if (to_put) bio_put(to_put); @@ -753,18 +751,24 @@ static int make_request(request_queue_t *q, struct bio * bio) const int rw = bio_data_dir(bio); int do_barriers; - if (unlikely(!mddev->barriers_work && bio_barrier(bio))) { - bio_endio(bio, bio->bi_size, -EOPNOTSUPP); - return 0; - } - /* * Register the new request and wait if the reconstruction * thread has put up a bar for new requests. * Continue immediately if no resync is active currently. + * We test barriers_work *after* md_write_start as md_write_start + * may cause the first superblock write, and that will check out + * if barriers work. */ + md_write_start(mddev, bio); /* wait on superblock update early */ + if (unlikely(!mddev->barriers_work && bio_barrier(bio))) { + if (rw == WRITE) + md_write_end(mddev); + bio_endio(bio, bio->bi_size, -EOPNOTSUPP); + return 0; + } + wait_barrier(conf); disk_stat_inc(mddev->gendisk, ios[rw]); @@ -1404,10 +1408,11 @@ static void raid1d(mddev_t *mddev) unplug = 1; } else if (test_bit(R1BIO_BarrierRetry, &r1_bio->state)) { /* some requests in the r1bio were BIO_RW_BARRIER - * requests which failed with -ENOTSUPP. Hohumm.. + * requests which failed with -EOPNOTSUPP. Hohumm.. * Better resubmit without the barrier. * We know which devices to resubmit for, because * all others have had their bios[] entry cleared. + * We already have a nr_pending reference on these rdevs. */ int i; clear_bit(R1BIO_BarrierRetry, &r1_bio->state); diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 617012bc107..1440935414e 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -1407,43 +1407,54 @@ static void raid10d(mddev_t *mddev) if (s > (PAGE_SIZE>>9)) s = PAGE_SIZE >> 9; + rcu_read_lock(); do { int d = r10_bio->devs[sl].devnum; - rdev = conf->mirrors[d].rdev; + rdev = rcu_dereference(conf->mirrors[d].rdev); if (rdev && - test_bit(In_sync, &rdev->flags) && - sync_page_io(rdev->bdev, - r10_bio->devs[sl].addr + - sect + rdev->data_offset, - s<<9, - conf->tmppage, READ)) - success = 1; - else { - sl++; - if (sl == conf->copies) - sl = 0; + test_bit(In_sync, &rdev->flags)) { + atomic_inc(&rdev->nr_pending); + rcu_read_unlock(); + success = sync_page_io(rdev->bdev, + r10_bio->devs[sl].addr + + sect + rdev->data_offset, + s<<9, + conf->tmppage, READ); + rdev_dec_pending(rdev, mddev); + rcu_read_lock(); + if (success) + break; } + sl++; + if (sl == conf->copies) + sl = 0; } while (!success && sl != r10_bio->read_slot); + rcu_read_unlock(); if (success) { int start = sl; /* write it back and re-read */ + rcu_read_lock(); while (sl != r10_bio->read_slot) { int d; if (sl==0) sl = conf->copies; sl--; d = r10_bio->devs[sl].devnum; - rdev = conf->mirrors[d].rdev; - atomic_add(s, &rdev->corrected_errors); + rdev = rcu_dereference(conf->mirrors[d].rdev); if (rdev && test_bit(In_sync, &rdev->flags)) { + atomic_inc(&rdev->nr_pending); + rcu_read_unlock(); + atomic_add(s, &rdev->corrected_errors); if (sync_page_io(rdev->bdev, r10_bio->devs[sl].addr + sect + rdev->data_offset, s<<9, conf->tmppage, WRITE) == 0) /* Well, this device is dead */ md_error(mddev, rdev); + rdev_dec_pending(rdev, mddev); + rcu_read_lock(); } } sl = start; @@ -1453,17 +1464,22 @@ static void raid10d(mddev_t *mddev) sl = conf->copies; sl--; d = r10_bio->devs[sl].devnum; - rdev = conf->mirrors[d].rdev; + rdev = rcu_dereference(conf->mirrors[d].rdev); if (rdev && test_bit(In_sync, &rdev->flags)) { + atomic_inc(&rdev->nr_pending); + rcu_read_unlock(); if (sync_page_io(rdev->bdev, r10_bio->devs[sl].addr + sect + rdev->data_offset, s<<9, conf->tmppage, READ) == 0) /* Well, this device is dead */ md_error(mddev, rdev); + rdev_dec_pending(rdev, mddev); + rcu_read_lock(); } } + rcu_read_unlock(); } else { /* Cannot read from anywhere -- bye bye array */ md_error(mddev, conf->mirrors[r10_bio->devs[r10_bio->read_slot].devnum].rdev); diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c index f9d87b86492..320b3d9384b 100644 --- a/drivers/media/video/cx88/cx88-alsa.c +++ b/drivers/media/video/cx88/cx88-alsa.c @@ -616,7 +616,7 @@ static struct snd_kcontrol_new snd_cx88_capture_volume = { * Only boards with eeprom and byte 1 at eeprom=1 have it */ -static struct pci_device_id cx88_audio_pci_tbl[] = { +static struct pci_device_id cx88_audio_pci_tbl[] __devinitdata = { {0x14f1,0x8801,PCI_ANY_ID,PCI_ANY_ID,0,0,0}, {0x14f1,0x8811,PCI_ANY_ID,PCI_ANY_ID,0,0,0}, {0, } diff --git a/drivers/mmc/at91_mci.c b/drivers/mmc/at91_mci.c index 6061c2d101a..88f0eef9cf3 100644 --- a/drivers/mmc/at91_mci.c +++ b/drivers/mmc/at91_mci.c @@ -621,9 +621,6 @@ static void at91_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) struct at91mci_host *host = mmc_priv(mmc); unsigned long at91_master_clock = clk_get_rate(mci_clk); - DBG("Clock %uHz, busmode %u, powermode %u, Vdd %u\n", - ios->clock, ios->bus_mode, ios->power_mode, ios->vdd); - if (host) host->bus_mode = ios->bus_mode; else diff --git a/drivers/mmc/au1xmmc.c b/drivers/mmc/au1xmmc.c index c0326bbc5f2..914d62b2406 100644 --- a/drivers/mmc/au1xmmc.c +++ b/drivers/mmc/au1xmmc.c @@ -720,10 +720,6 @@ static void au1xmmc_set_ios(struct mmc_host* mmc, struct mmc_ios* ios) { struct au1xmmc_host *host = mmc_priv(mmc); - DBG("set_ios (power=%u, clock=%uHz, vdd=%u, mode=%u)\n", - host->id, ios->power_mode, ios->clock, ios->vdd, - ios->bus_mode); - if (ios->power_mode == MMC_POWER_OFF) au1xmmc_set_power(host, 0); else if (ios->power_mode == MMC_POWER_ON) { diff --git a/drivers/mmc/imxmmc.c b/drivers/mmc/imxmmc.c index ffb7f55d346..79358e223f5 100644 --- a/drivers/mmc/imxmmc.c +++ b/drivers/mmc/imxmmc.c @@ -102,6 +102,7 @@ struct imxmci_host { #define IMXMCI_PEND_CPU_DATA_b 5 #define IMXMCI_PEND_CARD_XCHG_b 6 #define IMXMCI_PEND_SET_INIT_b 7 +#define IMXMCI_PEND_STARTED_b 8 #define IMXMCI_PEND_IRQ_m (1 << IMXMCI_PEND_IRQ_b) #define IMXMCI_PEND_DMA_END_m (1 << IMXMCI_PEND_DMA_END_b) @@ -111,6 +112,7 @@ struct imxmci_host { #define IMXMCI_PEND_CPU_DATA_m (1 << IMXMCI_PEND_CPU_DATA_b) #define IMXMCI_PEND_CARD_XCHG_m (1 << IMXMCI_PEND_CARD_XCHG_b) #define IMXMCI_PEND_SET_INIT_m (1 << IMXMCI_PEND_SET_INIT_b) +#define IMXMCI_PEND_STARTED_m (1 << IMXMCI_PEND_STARTED_b) static void imxmci_stop_clock(struct imxmci_host *host) { @@ -131,23 +133,52 @@ static void imxmci_stop_clock(struct imxmci_host *host) dev_dbg(mmc_dev(host->mmc), "imxmci_stop_clock blocked, no luck\n"); } -static void imxmci_start_clock(struct imxmci_host *host) +static int imxmci_start_clock(struct imxmci_host *host) { - int i = 0; + unsigned int trials = 0; + unsigned int delay_limit = 128; + unsigned long flags; + MMC_STR_STP_CLK &= ~STR_STP_CLK_STOP_CLK; - while(i < 0x1000) { - if(!(i & 0x7f)) - MMC_STR_STP_CLK |= STR_STP_CLK_START_CLK; - if(MMC_STATUS & STATUS_CARD_BUS_CLK_RUN) { - /* Check twice before cut */ + clear_bit(IMXMCI_PEND_STARTED_b, &host->pending_events); + + /* + * Command start of the clock, this usually succeeds in less + * then 6 delay loops, but during card detection (low clockrate) + * it takes up to 5000 delay loops and sometimes fails for the first time + */ + MMC_STR_STP_CLK |= STR_STP_CLK_START_CLK; + + do { + unsigned int delay = delay_limit; + + while(delay--){ if(MMC_STATUS & STATUS_CARD_BUS_CLK_RUN) - return; + /* Check twice before cut */ + if(MMC_STATUS & STATUS_CARD_BUS_CLK_RUN) + return 0; + + if(test_bit(IMXMCI_PEND_STARTED_b, &host->pending_events)) + return 0; } - i++; - } - dev_dbg(mmc_dev(host->mmc), "imxmci_start_clock blocked, no luck\n"); + local_irq_save(flags); + /* + * Ensure, that request is not doubled under all possible circumstances. + * It is possible, that cock running state is missed, because some other + * IRQ or schedule delays this function execution and the clocks has + * been already stopped by other means (response processing, SDHC HW) + */ + if(!test_bit(IMXMCI_PEND_STARTED_b, &host->pending_events)) + MMC_STR_STP_CLK |= STR_STP_CLK_START_CLK; + local_irq_restore(flags); + + } while(++trials<256); + + dev_err(mmc_dev(host->mmc), "imxmci_start_clock blocked, no luck\n"); + + return -1; } static void imxmci_softreset(void) @@ -498,7 +529,7 @@ static int imxmci_data_done(struct imxmci_host *host, unsigned int stat) data_error = imxmci_finish_data(host, stat); - if (host->req->stop && (data_error == MMC_ERR_NONE)) { + if (host->req->stop) { imxmci_stop_clock(host); imxmci_start_cmd(host, host->req->stop, 0); } else { @@ -622,6 +653,7 @@ static irqreturn_t imxmci_irq(int irq, void *devid, struct pt_regs *regs) atomic_set(&host->stuck_timeout, 0); host->status_reg = stat; set_bit(IMXMCI_PEND_IRQ_b, &host->pending_events); + set_bit(IMXMCI_PEND_STARTED_b, &host->pending_events); tasklet_schedule(&host->tasklet); return IRQ_RETVAL(handled);; @@ -775,10 +807,6 @@ static void imxmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) struct imxmci_host *host = mmc_priv(mmc); int prescaler; - dev_dbg(mmc_dev(host->mmc), "clock %u power %u vdd %u width %u\n", - ios->clock, ios->power_mode, ios->vdd, - (ios->bus_width==MMC_BUS_WIDTH_4)?4:1); - if( ios->bus_width==MMC_BUS_WIDTH_4 ) { host->actual_bus_width = MMC_BUS_WIDTH_4; imx_gpio_mode(PB11_PF_SD_DAT3); diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index da6ddd910fc..1ca2c8b9c9b 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -59,21 +59,23 @@ static const unsigned int tacc_mant[] = { /** - * mmc_request_done - finish processing an MMC command - * @host: MMC host which completed command - * @mrq: MMC request which completed + * mmc_request_done - finish processing an MMC request + * @host: MMC host which completed request + * @mrq: MMC request which request * * MMC drivers should call this function when they have completed - * their processing of a command. This should be called before the - * data part of the command has completed. + * their processing of a request. */ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq) { struct mmc_command *cmd = mrq->cmd; - int err = mrq->cmd->error; - pr_debug("MMC: req done (%02x): %d: %08x %08x %08x %08x\n", - cmd->opcode, err, cmd->resp[0], cmd->resp[1], - cmd->resp[2], cmd->resp[3]); + int err = cmd->error; + + pr_debug("%s: req done (CMD%u): %d/%d/%d: %08x %08x %08x %08x\n", + mmc_hostname(host), cmd->opcode, err, + mrq->data ? mrq->data->error : 0, + mrq->stop ? mrq->stop->error : 0, + cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]); if (err && cmd->retries) { cmd->retries--; @@ -97,8 +99,9 @@ EXPORT_SYMBOL(mmc_request_done); void mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) { - pr_debug("MMC: starting cmd %02x arg %08x flags %08x\n", - mrq->cmd->opcode, mrq->cmd->arg, mrq->cmd->flags); + pr_debug("%s: starting CMD%u arg %08x flags %08x\n", + mmc_hostname(host), mrq->cmd->opcode, + mrq->cmd->arg, mrq->cmd->flags); WARN_ON(host->card_busy == NULL); @@ -312,6 +315,18 @@ void mmc_release_host(struct mmc_host *host) EXPORT_SYMBOL(mmc_release_host); +static inline void mmc_set_ios(struct mmc_host *host) +{ + struct mmc_ios *ios = &host->ios; + + pr_debug("%s: clock %uHz busmode %u powermode %u cs %u Vdd %u width %u\n", + mmc_hostname(host), ios->clock, ios->bus_mode, + ios->power_mode, ios->chip_select, ios->vdd, + ios->bus_width); + + host->ops->set_ios(host, ios); +} + static int mmc_select_card(struct mmc_host *host, struct mmc_card *card) { int err; @@ -364,7 +379,7 @@ static int mmc_select_card(struct mmc_host *host, struct mmc_card *card) } } - host->ops->set_ios(host, &host->ios); + mmc_set_ios(host); return MMC_ERR_NONE; } @@ -415,7 +430,7 @@ static u32 mmc_select_voltage(struct mmc_host *host, u32 ocr) ocr = 3 << bit; host->ios.vdd = bit; - host->ops->set_ios(host, &host->ios); + mmc_set_ios(host); } else { ocr = 0; } @@ -549,6 +564,7 @@ static void mmc_decode_csd(struct mmc_card *card) csd->read_partial = UNSTUFF_BITS(resp, 79, 1); csd->write_misalign = UNSTUFF_BITS(resp, 78, 1); csd->read_misalign = UNSTUFF_BITS(resp, 77, 1); + csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3); csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4); csd->write_partial = UNSTUFF_BITS(resp, 21, 1); } else { @@ -583,6 +599,7 @@ static void mmc_decode_csd(struct mmc_card *card) csd->read_partial = UNSTUFF_BITS(resp, 79, 1); csd->write_misalign = UNSTUFF_BITS(resp, 78, 1); csd->read_misalign = UNSTUFF_BITS(resp, 77, 1); + csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3); csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4); csd->write_partial = UNSTUFF_BITS(resp, 21, 1); } @@ -666,7 +683,7 @@ static void mmc_idle_cards(struct mmc_host *host) struct mmc_command cmd; host->ios.chip_select = MMC_CS_HIGH; - host->ops->set_ios(host, &host->ios); + mmc_set_ios(host); mmc_delay(1); @@ -679,7 +696,7 @@ static void mmc_idle_cards(struct mmc_host *host) mmc_delay(1); host->ios.chip_select = MMC_CS_DONTCARE; - host->ops->set_ios(host, &host->ios); + mmc_set_ios(host); mmc_delay(1); } @@ -704,13 +721,13 @@ static void mmc_power_up(struct mmc_host *host) host->ios.chip_select = MMC_CS_DONTCARE; host->ios.power_mode = MMC_POWER_UP; host->ios.bus_width = MMC_BUS_WIDTH_1; - host->ops->set_ios(host, &host->ios); + mmc_set_ios(host); mmc_delay(1); host->ios.clock = host->f_min; host->ios.power_mode = MMC_POWER_ON; - host->ops->set_ios(host, &host->ios); + mmc_set_ios(host); mmc_delay(2); } @@ -723,7 +740,7 @@ static void mmc_power_off(struct mmc_host *host) host->ios.chip_select = MMC_CS_DONTCARE; host->ios.power_mode = MMC_POWER_OFF; host->ios.bus_width = MMC_BUS_WIDTH_1; - host->ops->set_ios(host, &host->ios); + mmc_set_ios(host); } static int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) @@ -971,7 +988,8 @@ static unsigned int mmc_calculate_clock(struct mmc_host *host) if (!mmc_card_dead(card) && max_dtr > card->csd.max_dtr) max_dtr = card->csd.max_dtr; - pr_debug("MMC: selected %d.%03dMHz transfer rate\n", + pr_debug("%s: selected %d.%03dMHz transfer rate\n", + mmc_hostname(host), max_dtr / 1000000, (max_dtr / 1000) % 1000); return max_dtr; @@ -1046,7 +1064,7 @@ static void mmc_setup(struct mmc_host *host) } else { host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; host->ios.clock = host->f_min; - host->ops->set_ios(host, &host->ios); + mmc_set_ios(host); /* * We should remember the OCR mask from the existing @@ -1082,7 +1100,7 @@ static void mmc_setup(struct mmc_host *host) * Ok, now switch to push-pull mode. */ host->ios.bus_mode = MMC_BUSMODE_PUSHPULL; - host->ops->set_ios(host, &host->ios); + mmc_set_ios(host); mmc_read_csds(host); @@ -1128,7 +1146,7 @@ static void mmc_rescan(void *data) * attached cards and the host support. */ host->ios.clock = mmc_calculate_clock(host); - host->ops->set_ios(host, &host->ios); + mmc_set_ios(host); } mmc_release_host(host); diff --git a/drivers/mmc/mmc_block.c b/drivers/mmc/mmc_block.c index 8eb2a2ede64..06bd1f4cb9b 100644 --- a/drivers/mmc/mmc_block.c +++ b/drivers/mmc/mmc_block.c @@ -187,6 +187,12 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) brq.cmd.opcode = MMC_WRITE_BLOCK; brq.data.flags |= MMC_DATA_WRITE; brq.data.blocks = 1; + + /* + * Scale up the timeout by the r2w factor + */ + brq.data.timeout_ns <<= card->csd.r2w_factor; + brq.data.timeout_clks <<= card->csd.r2w_factor; } if (brq.data.blocks > 1) { diff --git a/drivers/mmc/mmci.c b/drivers/mmc/mmci.c index df7e861e2fc..da8e4d7339c 100644 --- a/drivers/mmc/mmci.c +++ b/drivers/mmc/mmci.c @@ -402,9 +402,6 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) struct mmci_host *host = mmc_priv(mmc); u32 clk = 0, pwr = 0; - DBG(host, "clock %uHz busmode %u powermode %u Vdd %u\n", - ios->clock, ios->bus_mode, ios->power_mode, ios->vdd); - if (ios->clock) { if (ios->clock >= host->mclk) { clk = MCI_CLK_BYPASS; diff --git a/drivers/mmc/pxamci.c b/drivers/mmc/pxamci.c index eb9a8826e9b..f97b472085c 100644 --- a/drivers/mmc/pxamci.c +++ b/drivers/mmc/pxamci.c @@ -65,11 +65,6 @@ struct pxamci_host { unsigned int dma_dir; }; -static inline unsigned int ns_to_clocks(unsigned int ns) -{ - return (ns * (CLOCKRATE / 1000000) + 999) / 1000; -} - static void pxamci_stop_clock(struct pxamci_host *host) { if (readl(host->base + MMC_STAT) & STAT_CLK_EN) { @@ -113,6 +108,7 @@ static void pxamci_disable_irq(struct pxamci_host *host, unsigned int mask) static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data) { unsigned int nob = data->blocks; + unsigned long long clks; unsigned int timeout; u32 dcmd; int i; @@ -125,7 +121,9 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data) writel(nob, host->base + MMC_NOB); writel(1 << data->blksz_bits, host->base + MMC_BLKLEN); - timeout = ns_to_clocks(data->timeout_ns) + data->timeout_clks; + clks = (unsigned long long)data->timeout_ns * CLOCKRATE; + do_div(clks, 1000000000UL); + timeout = (unsigned int)clks + (data->timeout_clks << host->clkrt); writel((timeout + 255) / 256, host->base + MMC_RDTO); if (data->flags & MMC_DATA_READ) { @@ -200,7 +198,6 @@ static void pxamci_start_cmd(struct pxamci_host *host, struct mmc_command *cmd, static void pxamci_finish_request(struct pxamci_host *host, struct mmc_request *mrq) { - pr_debug("PXAMCI: request done\n"); host->mrq = NULL; host->cmd = NULL; host->data = NULL; @@ -293,7 +290,7 @@ static int pxamci_data_done(struct pxamci_host *host, unsigned int stat) pxamci_disable_irq(host, DATA_TRAN_DONE); host->data = NULL; - if (host->mrq->stop && data->error == MMC_ERR_NONE) { + if (host->mrq->stop) { pxamci_stop_clock(host); pxamci_start_cmd(host, host->mrq->stop, 0); } else { @@ -311,12 +308,10 @@ static irqreturn_t pxamci_irq(int irq, void *devid, struct pt_regs *regs) ireg = readl(host->base + MMC_I_REG); - pr_debug("PXAMCI: irq %08x\n", ireg); - if (ireg) { unsigned stat = readl(host->base + MMC_STAT); - pr_debug("PXAMCI: stat %08x\n", stat); + pr_debug("PXAMCI: irq %08x stat %08x\n", ireg, stat); if (ireg & END_CMD_RES) handled |= pxamci_cmd_done(host, stat); @@ -370,10 +365,6 @@ static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { struct pxamci_host *host = mmc_priv(mmc); - pr_debug("pxamci_set_ios: clock %u power %u vdd %u.%02u\n", - ios->clock, ios->power_mode, ios->vdd / 100, - ios->vdd % 100); - if (ios->clock) { unsigned int clk = CLOCKRATE / ios->clock; if (CLOCKRATE / clk > ios->clock) @@ -399,7 +390,7 @@ static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) host->cmdat |= CMDAT_INIT; } - pr_debug("pxamci_set_ios: clkrt = %x cmdat = %x\n", + pr_debug("PXAMCI: clkrt = %x cmdat = %x\n", host->clkrt, host->cmdat); } diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index bdbfca05002..b0053280ff2 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -570,10 +570,6 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) spin_lock_irqsave(&host->lock, flags); - DBG("clock %uHz busmode %u powermode %u cs %u Vdd %u width %u\n", - ios->clock, ios->bus_mode, ios->power_mode, ios->chip_select, - ios->vdd, ios->bus_width); - /* * Reset the chip on each power off. * Should clear out any weird states. diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c index 511f7b0b31d..39b3d97f891 100644 --- a/drivers/mmc/wbsd.c +++ b/drivers/mmc/wbsd.c @@ -931,10 +931,6 @@ static void wbsd_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) struct wbsd_host *host = mmc_priv(mmc); u8 clk, setup, pwr; - DBGF("clock %uHz busmode %u powermode %u cs %u Vdd %u width %u\n", - ios->clock, ios->bus_mode, ios->power_mode, ios->chip_select, - ios->vdd, ios->bus_width); - spin_lock_bh(&host->lock); /* diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index add8dc4aa7b..c99e87838f9 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -3768,6 +3768,7 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter, ps_page->ps_page[j] = NULL; skb->len += length; skb->data_len += length; + skb->truesize += length; } copydone: diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 7627a75f4f7..f7235c9bc42 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -105,6 +105,8 @@ * 0.50: 20 Jan 2006: Add 8021pq tagging support. * 0.51: 20 Jan 2006: Add 64bit consistent memory allocation for rings. * 0.52: 20 Jan 2006: Add MSI/MSIX support. + * 0.53: 19 Mar 2006: Fix init from low power mode and add hw reset. + * 0.54: 21 Mar 2006: Fix spin locks for multi irqs and cleanup. * * Known bugs: * We suspect that on some hardware no TX done interrupts are generated. @@ -116,7 +118,7 @@ * DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few * superfluous timer interrupts from the nic. */ -#define FORCEDETH_VERSION "0.52" +#define FORCEDETH_VERSION "0.54" #define DRV_NAME "forcedeth" #include <linux/module.h> @@ -160,6 +162,7 @@ #define DEV_HAS_VLAN 0x0020 /* device supports vlan tagging and striping */ #define DEV_HAS_MSI 0x0040 /* device supports MSI */ #define DEV_HAS_MSI_X 0x0080 /* device supports MSI-X */ +#define DEV_HAS_POWER_CNTRL 0x0100 /* device supports power savings */ enum { NvRegIrqStatus = 0x000, @@ -203,6 +206,8 @@ enum { #define NVREG_MISC1_HD 0x02 #define NVREG_MISC1_FORCE 0x3b0f3c + NvRegMacReset = 0x3c, +#define NVREG_MAC_RESET_ASSERT 0x0F3 NvRegTransmitterControl = 0x084, #define NVREG_XMITCTL_START 0x01 NvRegTransmitterStatus = 0x088, @@ -326,6 +331,10 @@ enum { NvRegMSIXMap0 = 0x3e0, NvRegMSIXMap1 = 0x3e4, NvRegMSIXIrqStatus = 0x3f0, + + NvRegPowerState2 = 0x600, +#define NVREG_POWERSTATE2_POWERUP_MASK 0x0F11 +#define NVREG_POWERSTATE2_POWERUP_REV_A3 0x0001 }; /* Big endian: should work, but is untested */ @@ -414,7 +423,8 @@ typedef union _ring_type { #define NV_RX3_VLAN_TAG_MASK (0x0000FFFF) /* Miscelaneous hardware related defines: */ -#define NV_PCI_REGSZ 0x270 +#define NV_PCI_REGSZ_VER1 0x270 +#define NV_PCI_REGSZ_VER2 0x604 /* various timeout delays: all in usec */ #define NV_TXRX_RESET_DELAY 4 @@ -431,6 +441,7 @@ typedef union _ring_type { #define NV_MIIBUSY_DELAY 50 #define NV_MIIPHY_DELAY 10 #define NV_MIIPHY_DELAYMAX 10000 +#define NV_MAC_RESET_DELAY 64 #define NV_WAKEUPPATTERNS 5 #define NV_WAKEUPMASKENTRIES 4 @@ -552,6 +563,8 @@ struct fe_priv { u32 desc_ver; u32 txrxctl_bits; u32 vlanctl_bits; + u32 driver_data; + u32 register_size; void __iomem *base; @@ -698,6 +711,72 @@ static void setup_hw_rings(struct net_device *dev, int rxtx_flags) } } +static int using_multi_irqs(struct net_device *dev) +{ + struct fe_priv *np = get_nvpriv(dev); + + if (!(np->msi_flags & NV_MSI_X_ENABLED) || + ((np->msi_flags & NV_MSI_X_ENABLED) && + ((np->msi_flags & NV_MSI_X_VECTORS_MASK) == 0x1))) + return 0; + else + return 1; +} + +static void nv_enable_irq(struct net_device *dev) +{ + struct fe_priv *np = get_nvpriv(dev); + + if (!using_multi_irqs(dev)) { + if (np->msi_flags & NV_MSI_X_ENABLED) + enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector); + else + enable_irq(dev->irq); + } else { + enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector); + enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector); + enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_OTHER].vector); + } +} + +static void nv_disable_irq(struct net_device *dev) +{ + struct fe_priv *np = get_nvpriv(dev); + + if (!using_multi_irqs(dev)) { + if (np->msi_flags & NV_MSI_X_ENABLED) + disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector); + else + disable_irq(dev->irq); + } else { + disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector); + disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector); + disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_OTHER].vector); + } +} + +/* In MSIX mode, a write to irqmask behaves as XOR */ +static void nv_enable_hw_interrupts(struct net_device *dev, u32 mask) +{ + u8 __iomem *base = get_hwbase(dev); + + writel(mask, base + NvRegIrqMask); +} + +static void nv_disable_hw_interrupts(struct net_device *dev, u32 mask) +{ + struct fe_priv *np = get_nvpriv(dev); + u8 __iomem *base = get_hwbase(dev); + + if (np->msi_flags & NV_MSI_X_ENABLED) { + writel(mask, base + NvRegIrqMask); + } else { + if (np->msi_flags & NV_MSI_ENABLED) + writel(0, base + NvRegMSIIrqMask); + writel(0, base + NvRegIrqMask); + } +} + #define MII_READ (-1) /* mii_rw: read/write a register on the PHY. * @@ -919,6 +998,24 @@ static void nv_txrx_reset(struct net_device *dev) pci_push(base); } +static void nv_mac_reset(struct net_device *dev) +{ + struct fe_priv *np = netdev_priv(dev); + u8 __iomem *base = get_hwbase(dev); + + dprintk(KERN_DEBUG "%s: nv_mac_reset\n", dev->name); + writel(NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET | np->txrxctl_bits, base + NvRegTxRxControl); + pci_push(base); + writel(NVREG_MAC_RESET_ASSERT, base + NvRegMacReset); + pci_push(base); + udelay(NV_MAC_RESET_DELAY); + writel(0, base + NvRegMacReset); + pci_push(base); + udelay(NV_MAC_RESET_DELAY); + writel(NVREG_TXRXCTL_BIT2 | np->txrxctl_bits, base + NvRegTxRxControl); + pci_push(base); +} + /* * nv_get_stats: dev->get_stats function * Get latest stats value from the nic. @@ -989,24 +1086,25 @@ static void nv_do_rx_refill(unsigned long data) struct net_device *dev = (struct net_device *) data; struct fe_priv *np = netdev_priv(dev); - - if (!(np->msi_flags & NV_MSI_X_ENABLED) || - ((np->msi_flags & NV_MSI_X_ENABLED) && - ((np->msi_flags & NV_MSI_X_VECTORS_MASK) == 0x1))) { - disable_irq(dev->irq); + if (!using_multi_irqs(dev)) { + if (np->msi_flags & NV_MSI_X_ENABLED) + disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector); + else + disable_irq(dev->irq); } else { disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector); } if (nv_alloc_rx(dev)) { - spin_lock(&np->lock); + spin_lock_irq(&np->lock); if (!np->in_shutdown) mod_timer(&np->oom_kick, jiffies + OOM_REFILL); - spin_unlock(&np->lock); + spin_unlock_irq(&np->lock); } - if (!(np->msi_flags & NV_MSI_X_ENABLED) || - ((np->msi_flags & NV_MSI_X_ENABLED) && - ((np->msi_flags & NV_MSI_X_VECTORS_MASK) == 0x1))) { - enable_irq(dev->irq); + if (!using_multi_irqs(dev)) { + if (np->msi_flags & NV_MSI_X_ENABLED) + enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector); + else + enable_irq(dev->irq); } else { enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector); } @@ -1331,7 +1429,7 @@ static void nv_tx_timeout(struct net_device *dev) dev->name, (unsigned long)np->ring_addr, np->next_tx, np->nic_tx); printk(KERN_INFO "%s: Dumping tx registers\n", dev->name); - for (i=0;i<0x400;i+= 32) { + for (i=0;i<=np->register_size;i+= 32) { printk(KERN_INFO "%3x: %08x %08x %08x %08x %08x %08x %08x %08x\n", i, readl(base + i + 0), readl(base + i + 4), @@ -1638,15 +1736,7 @@ static int nv_change_mtu(struct net_device *dev, int new_mtu) * guessed, there is probably a simpler approach. * Changing the MTU is a rare event, it shouldn't matter. */ - if (!(np->msi_flags & NV_MSI_X_ENABLED) || - ((np->msi_flags & NV_MSI_X_ENABLED) && - ((np->msi_flags & NV_MSI_X_VECTORS_MASK) == 0x1))) { - disable_irq(dev->irq); - } else { - disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector); - disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector); - disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_OTHER].vector); - } + nv_disable_irq(dev); spin_lock_bh(&dev->xmit_lock); spin_lock(&np->lock); /* stop engines */ @@ -1679,15 +1769,7 @@ static int nv_change_mtu(struct net_device *dev, int new_mtu) nv_start_tx(dev); spin_unlock(&np->lock); spin_unlock_bh(&dev->xmit_lock); - if (!(np->msi_flags & NV_MSI_X_ENABLED) || - ((np->msi_flags & NV_MSI_X_ENABLED) && - ((np->msi_flags & NV_MSI_X_VECTORS_MASK) == 0x1))) { - enable_irq(dev->irq); - } else { - enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector); - enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector); - enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_OTHER].vector); - } + nv_enable_irq(dev); } return 0; } @@ -2078,16 +2160,16 @@ static irqreturn_t nv_nic_irq_tx(int foo, void *data, struct pt_regs *regs) if (!(events & np->irqmask)) break; - spin_lock(&np->lock); + spin_lock_irq(&np->lock); nv_tx_done(dev); - spin_unlock(&np->lock); + spin_unlock_irq(&np->lock); if (events & (NVREG_IRQ_TX_ERR)) { dprintk(KERN_DEBUG "%s: received irq with events 0x%x. Probably TX fail.\n", dev->name, events); } if (i > max_interrupt_work) { - spin_lock(&np->lock); + spin_lock_irq(&np->lock); /* disable interrupts on the nic */ writel(NVREG_IRQ_TX_ALL, base + NvRegIrqMask); pci_push(base); @@ -2097,7 +2179,7 @@ static irqreturn_t nv_nic_irq_tx(int foo, void *data, struct pt_regs *regs) mod_timer(&np->nic_poll, jiffies + POLL_WAIT); } printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq_tx.\n", dev->name, i); - spin_unlock(&np->lock); + spin_unlock_irq(&np->lock); break; } @@ -2127,14 +2209,14 @@ static irqreturn_t nv_nic_irq_rx(int foo, void *data, struct pt_regs *regs) nv_rx_process(dev); if (nv_alloc_rx(dev)) { - spin_lock(&np->lock); + spin_lock_irq(&np->lock); if (!np->in_shutdown) mod_timer(&np->oom_kick, jiffies + OOM_REFILL); - spin_unlock(&np->lock); + spin_unlock_irq(&np->lock); } if (i > max_interrupt_work) { - spin_lock(&np->lock); + spin_lock_irq(&np->lock); /* disable interrupts on the nic */ writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask); pci_push(base); @@ -2144,7 +2226,7 @@ static irqreturn_t nv_nic_irq_rx(int foo, void *data, struct pt_regs *regs) mod_timer(&np->nic_poll, jiffies + POLL_WAIT); } printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq_rx.\n", dev->name, i); - spin_unlock(&np->lock); + spin_unlock_irq(&np->lock); break; } @@ -2173,14 +2255,14 @@ static irqreturn_t nv_nic_irq_other(int foo, void *data, struct pt_regs *regs) break; if (events & NVREG_IRQ_LINK) { - spin_lock(&np->lock); + spin_lock_irq(&np->lock); nv_link_irq(dev); - spin_unlock(&np->lock); + spin_unlock_irq(&np->lock); } if (np->need_linktimer && time_after(jiffies, np->link_timeout)) { - spin_lock(&np->lock); + spin_lock_irq(&np->lock); nv_linkchange(dev); - spin_unlock(&np->lock); + spin_unlock_irq(&np->lock); np->link_timeout = jiffies + LINK_TIMEOUT; } if (events & (NVREG_IRQ_UNKNOWN)) { @@ -2188,7 +2270,7 @@ static irqreturn_t nv_nic_irq_other(int foo, void *data, struct pt_regs *regs) dev->name, events); } if (i > max_interrupt_work) { - spin_lock(&np->lock); + spin_lock_irq(&np->lock); /* disable interrupts on the nic */ writel(NVREG_IRQ_OTHER, base + NvRegIrqMask); pci_push(base); @@ -2198,7 +2280,7 @@ static irqreturn_t nv_nic_irq_other(int foo, void *data, struct pt_regs *regs) mod_timer(&np->nic_poll, jiffies + POLL_WAIT); } printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq_other.\n", dev->name, i); - spin_unlock(&np->lock); + spin_unlock_irq(&np->lock); break; } @@ -2221,10 +2303,11 @@ static void nv_do_nic_poll(unsigned long data) * nv_nic_irq because that may decide to do otherwise */ - if (!(np->msi_flags & NV_MSI_X_ENABLED) || - ((np->msi_flags & NV_MSI_X_ENABLED) && - ((np->msi_flags & NV_MSI_X_VECTORS_MASK) == 0x1))) { - disable_irq(dev->irq); + if (!using_multi_irqs(dev)) { + if (np->msi_flags & NV_MSI_X_ENABLED) + disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector); + else + disable_irq(dev->irq); mask = np->irqmask; } else { if (np->nic_poll_irq & NVREG_IRQ_RX_ALL) { @@ -2247,11 +2330,12 @@ static void nv_do_nic_poll(unsigned long data) writel(mask, base + NvRegIrqMask); pci_push(base); - if (!(np->msi_flags & NV_MSI_X_ENABLED) || - ((np->msi_flags & NV_MSI_X_ENABLED) && - ((np->msi_flags & NV_MSI_X_VECTORS_MASK) == 0x1))) { + if (!using_multi_irqs(dev)) { nv_nic_irq((int) 0, (void *) data, (struct pt_regs *) NULL); - enable_irq(dev->irq); + if (np->msi_flags & NV_MSI_X_ENABLED) + enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector); + else + enable_irq(dev->irq); } else { if (np->nic_poll_irq & NVREG_IRQ_RX_ALL) { nv_nic_irq_rx((int) 0, (void *) data, (struct pt_regs *) NULL); @@ -2488,11 +2572,11 @@ static int nv_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) } #define FORCEDETH_REGS_VER 1 -#define FORCEDETH_REGS_SIZE 0x400 /* 256 32-bit registers */ static int nv_get_regs_len(struct net_device *dev) { - return FORCEDETH_REGS_SIZE; + struct fe_priv *np = netdev_priv(dev); + return np->register_size; } static void nv_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *buf) @@ -2504,7 +2588,7 @@ static void nv_get_regs(struct net_device *dev, struct ethtool_regs *regs, void regs->version = FORCEDETH_REGS_VER; spin_lock_irq(&np->lock); - for (i=0;i<FORCEDETH_REGS_SIZE/sizeof(u32);i++) + for (i = 0;i <= np->register_size/sizeof(u32); i++) rbuf[i] = readl(base + i*sizeof(u32)); spin_unlock_irq(&np->lock); } @@ -2598,6 +2682,113 @@ static void set_msix_vector_map(struct net_device *dev, u32 vector, u32 irqmask) writel(readl(base + NvRegMSIXMap1) | msixmap, base + NvRegMSIXMap1); } +static int nv_request_irq(struct net_device *dev) +{ + struct fe_priv *np = get_nvpriv(dev); + u8 __iomem *base = get_hwbase(dev); + int ret = 1; + int i; + + if (np->msi_flags & NV_MSI_X_CAPABLE) { + for (i = 0; i < (np->msi_flags & NV_MSI_X_VECTORS_MASK); i++) { + np->msi_x_entry[i].entry = i; + } + if ((ret = pci_enable_msix(np->pci_dev, np->msi_x_entry, (np->msi_flags & NV_MSI_X_VECTORS_MASK))) == 0) { + np->msi_flags |= NV_MSI_X_ENABLED; + if (optimization_mode == NV_OPTIMIZATION_MODE_THROUGHPUT) { + /* Request irq for rx handling */ + if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector, &nv_nic_irq_rx, SA_SHIRQ, dev->name, dev) != 0) { + printk(KERN_INFO "forcedeth: request_irq failed for rx %d\n", ret); + pci_disable_msix(np->pci_dev); + np->msi_flags &= ~NV_MSI_X_ENABLED; + goto out_err; + } + /* Request irq for tx handling */ + if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector, &nv_nic_irq_tx, SA_SHIRQ, dev->name, dev) != 0) { + printk(KERN_INFO "forcedeth: request_irq failed for tx %d\n", ret); + pci_disable_msix(np->pci_dev); + np->msi_flags &= ~NV_MSI_X_ENABLED; + goto out_free_rx; + } + /* Request irq for link and timer handling */ + if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_OTHER].vector, &nv_nic_irq_other, SA_SHIRQ, dev->name, dev) != 0) { + printk(KERN_INFO "forcedeth: request_irq failed for link %d\n", ret); + pci_disable_msix(np->pci_dev); + np->msi_flags &= ~NV_MSI_X_ENABLED; + goto out_free_tx; + } + /* map interrupts to their respective vector */ + writel(0, base + NvRegMSIXMap0); + writel(0, base + NvRegMSIXMap1); + set_msix_vector_map(dev, NV_MSI_X_VECTOR_RX, NVREG_IRQ_RX_ALL); + set_msix_vector_map(dev, NV_MSI_X_VECTOR_TX, NVREG_IRQ_TX_ALL); + set_msix_vector_map(dev, NV_MSI_X_VECTOR_OTHER, NVREG_IRQ_OTHER); + } else { + /* Request irq for all interrupts */ + if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector, &nv_nic_irq, SA_SHIRQ, dev->name, dev) != 0) { + printk(KERN_INFO "forcedeth: request_irq failed %d\n", ret); + pci_disable_msix(np->pci_dev); + np->msi_flags &= ~NV_MSI_X_ENABLED; + goto out_err; + } + + /* map interrupts to vector 0 */ + writel(0, base + NvRegMSIXMap0); + writel(0, base + NvRegMSIXMap1); + } + } + } + if (ret != 0 && np->msi_flags & NV_MSI_CAPABLE) { + if ((ret = pci_enable_msi(np->pci_dev)) == 0) { + np->msi_flags |= NV_MSI_ENABLED; + if (request_irq(np->pci_dev->irq, &nv_nic_irq, SA_SHIRQ, dev->name, dev) != 0) { + printk(KERN_INFO "forcedeth: request_irq failed %d\n", ret); + pci_disable_msi(np->pci_dev); + np->msi_flags &= ~NV_MSI_ENABLED; + goto out_err; + } + + /* map interrupts to vector 0 */ + writel(0, base + NvRegMSIMap0); + writel(0, base + NvRegMSIMap1); + /* enable msi vector 0 */ + writel(NVREG_MSI_VECTOR_0_ENABLED, base + NvRegMSIIrqMask); + } + } + if (ret != 0) { + if (request_irq(np->pci_dev->irq, &nv_nic_irq, SA_SHIRQ, dev->name, dev) != 0) + goto out_err; + } + + return 0; +out_free_tx: + free_irq(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector, dev); +out_free_rx: + free_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector, dev); +out_err: + return 1; +} + +static void nv_free_irq(struct net_device *dev) +{ + struct fe_priv *np = get_nvpriv(dev); + int i; + + if (np->msi_flags & NV_MSI_X_ENABLED) { + for (i = 0; i < (np->msi_flags & NV_MSI_X_VECTORS_MASK); i++) { + free_irq(np->msi_x_entry[i].vector, dev); + } + pci_disable_msix(np->pci_dev); + np->msi_flags &= ~NV_MSI_X_ENABLED; + } else { + free_irq(np->pci_dev->irq, dev); + if (np->msi_flags & NV_MSI_ENABLED) { + pci_disable_msi(np->pci_dev); + np->msi_flags &= ~NV_MSI_ENABLED; + } + } +} + static int nv_open(struct net_device *dev) { struct fe_priv *np = netdev_priv(dev); @@ -2608,6 +2799,8 @@ static int nv_open(struct net_device *dev) dprintk(KERN_DEBUG "nv_open: begin\n"); /* 1) erase previous misconfiguration */ + if (np->driver_data & DEV_HAS_POWER_CNTRL) + nv_mac_reset(dev); /* 4.1-1: stop adapter: ignored, 4.3 seems to be overkill */ writel(NVREG_MCASTADDRA_FORCE, base + NvRegMulticastAddrA); writel(0, base + NvRegMulticastAddrB); @@ -2688,12 +2881,16 @@ static int nv_open(struct net_device *dev) udelay(10); writel(readl(base + NvRegPowerState) | NVREG_POWERSTATE_VALID, base + NvRegPowerState); - writel(0, base + NvRegIrqMask); + nv_disable_hw_interrupts(dev, np->irqmask); pci_push(base); writel(NVREG_MIISTAT_MASK2, base + NvRegMIIStatus); writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus); pci_push(base); + if (nv_request_irq(dev)) { + goto out_drain; + } + if (np->msi_flags & NV_MSI_X_CAPABLE) { for (i = 0; i < (np->msi_flags & NV_MSI_X_VECTORS_MASK); i++) { np->msi_x_entry[i].entry = i; @@ -2767,7 +2964,7 @@ static int nv_open(struct net_device *dev) } /* ask for interrupts */ - writel(np->irqmask, base + NvRegIrqMask); + nv_enable_hw_interrupts(dev, np->irqmask); spin_lock_irq(&np->lock); writel(NVREG_MCASTADDRA_FORCE, base + NvRegMulticastAddrA); @@ -2811,7 +3008,6 @@ static int nv_close(struct net_device *dev) { struct fe_priv *np = netdev_priv(dev); u8 __iomem *base; - int i; spin_lock_irq(&np->lock); np->in_shutdown = 1; @@ -2829,31 +3025,13 @@ static int nv_close(struct net_device *dev) /* disable interrupts on the nic or we will lock up */ base = get_hwbase(dev); - if (np->msi_flags & NV_MSI_X_ENABLED) { - writel(np->irqmask, base + NvRegIrqMask); - } else { - if (np->msi_flags & NV_MSI_ENABLED) - writel(0, base + NvRegMSIIrqMask); - writel(0, base + NvRegIrqMask); - } + nv_disable_hw_interrupts(dev, np->irqmask); pci_push(base); dprintk(KERN_INFO "%s: Irqmask is zero again\n", dev->name); spin_unlock_irq(&np->lock); - if (np->msi_flags & NV_MSI_X_ENABLED) { - for (i = 0; i < (np->msi_flags & NV_MSI_X_VECTORS_MASK); i++) { - free_irq(np->msi_x_entry[i].vector, dev); - } - pci_disable_msix(np->pci_dev); - np->msi_flags &= ~NV_MSI_X_ENABLED; - } else { - free_irq(np->pci_dev->irq, dev); - if (np->msi_flags & NV_MSI_ENABLED) { - pci_disable_msi(np->pci_dev); - np->msi_flags &= ~NV_MSI_ENABLED; - } - } + nv_free_irq(dev); drain_ring(dev); @@ -2878,6 +3056,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i unsigned long addr; u8 __iomem *base; int err, i; + u32 powerstate; dev = alloc_etherdev(sizeof(struct fe_priv)); err = -ENOMEM; @@ -2910,6 +3089,11 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i if (err < 0) goto out_disable; + if (id->driver_data & (DEV_HAS_VLAN|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL)) + np->register_size = NV_PCI_REGSZ_VER2; + else + np->register_size = NV_PCI_REGSZ_VER1; + err = -EINVAL; addr = 0; for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { @@ -2918,7 +3102,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i pci_resource_len(pci_dev, i), pci_resource_flags(pci_dev, i)); if (pci_resource_flags(pci_dev, i) & IORESOURCE_MEM && - pci_resource_len(pci_dev, i) >= NV_PCI_REGSZ) { + pci_resource_len(pci_dev, i) >= np->register_size) { addr = pci_resource_start(pci_dev, i); break; } @@ -2929,24 +3113,25 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i goto out_relreg; } + /* copy of driver data */ + np->driver_data = id->driver_data; + /* handle different descriptor versions */ if (id->driver_data & DEV_HAS_HIGH_DMA) { /* packet format 3: supports 40-bit addressing */ np->desc_ver = DESC_VER_3; + np->txrxctl_bits = NVREG_TXRXCTL_DESC_3; if (pci_set_dma_mask(pci_dev, DMA_39BIT_MASK)) { printk(KERN_INFO "forcedeth: 64-bit DMA failed, using 32-bit addressing for device %s.\n", pci_name(pci_dev)); } else { - if (pci_set_consistent_dma_mask(pci_dev, 0x0000007fffffffffULL)) { - printk(KERN_INFO "forcedeth: 64-bit DMA (consistent) failed for device %s.\n", - pci_name(pci_dev)); - goto out_relreg; - } else { - dev->features |= NETIF_F_HIGHDMA; - printk(KERN_INFO "forcedeth: using HIGHDMA\n"); - } + dev->features |= NETIF_F_HIGHDMA; + printk(KERN_INFO "forcedeth: using HIGHDMA\n"); + } + if (pci_set_consistent_dma_mask(pci_dev, 0x0000007fffffffffULL)) { + printk(KERN_INFO "forcedeth: 64-bit DMA (consistent) failed for device %s.\n", + pci_name(pci_dev)); } - np->txrxctl_bits = NVREG_TXRXCTL_DESC_3; } else if (id->driver_data & DEV_HAS_LARGEDESC) { /* packet format 2: supports jumbo frames */ np->desc_ver = DESC_VER_2; @@ -2986,7 +3171,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i } err = -ENOMEM; - np->base = ioremap(addr, NV_PCI_REGSZ); + np->base = ioremap(addr, np->register_size); if (!np->base) goto out_relreg; dev->base_addr = (unsigned long)np->base; @@ -3062,6 +3247,20 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i writel(0, base + NvRegWakeUpFlags); np->wolenabled = 0; + if (id->driver_data & DEV_HAS_POWER_CNTRL) { + u8 revision_id; + pci_read_config_byte(pci_dev, PCI_REVISION_ID, &revision_id); + + /* take phy and nic out of low power mode */ + powerstate = readl(base + NvRegPowerState2); + powerstate &= ~NVREG_POWERSTATE2_POWERUP_MASK; + if ((id->device == PCI_DEVICE_ID_NVIDIA_NVENET_12 || + id->device == PCI_DEVICE_ID_NVIDIA_NVENET_13) && + revision_id >= 0xA3) + powerstate |= NVREG_POWERSTATE2_POWERUP_REV_A3; + writel(powerstate, base + NvRegPowerState2); + } + if (np->desc_ver == DESC_VER_1) { np->tx_flags = NV_TX_VALID; } else { @@ -3223,19 +3422,19 @@ static struct pci_device_id pci_tbl[] = { }, { /* MCP51 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_12), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL, }, { /* MCP51 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_13), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL, }, { /* MCP55 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_14), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL, }, { /* MCP55 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_15), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL, }, {0,}, }; diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 771e25d8c41..218d31764c5 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -210,7 +210,8 @@ static int gfar_probe(struct platform_device *pdev) goto regs_fail; } - spin_lock_init(&priv->lock); + spin_lock_init(&priv->txlock); + spin_lock_init(&priv->rxlock); platform_set_drvdata(pdev, dev); @@ -515,11 +516,13 @@ void stop_gfar(struct net_device *dev) phy_stop(priv->phydev); /* Lock it down */ - spin_lock_irqsave(&priv->lock, flags); + spin_lock_irqsave(&priv->txlock, flags); + spin_lock(&priv->rxlock); gfar_halt(dev); - spin_unlock_irqrestore(&priv->lock, flags); + spin_unlock(&priv->rxlock); + spin_unlock_irqrestore(&priv->txlock, flags); /* Free the IRQs */ if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) { @@ -605,14 +608,15 @@ void gfar_start(struct net_device *dev) tempval |= DMACTRL_INIT_SETTINGS; gfar_write(&priv->regs->dmactrl, tempval); - /* Clear THLT, so that the DMA starts polling now */ - gfar_write(®s->tstat, TSTAT_CLEAR_THALT); - /* Make sure we aren't stopped */ tempval = gfar_read(&priv->regs->dmactrl); tempval &= ~(DMACTRL_GRS | DMACTRL_GTS); gfar_write(&priv->regs->dmactrl, tempval); + /* Clear THLT/RHLT, so that the DMA starts polling now */ + gfar_write(®s->tstat, TSTAT_CLEAR_THALT); + gfar_write(®s->rstat, RSTAT_CLEAR_RHALT); + /* Unmask the interrupts we look for */ gfar_write(®s->imask, IMASK_DEFAULT); } @@ -928,12 +932,13 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) struct txfcb *fcb = NULL; struct txbd8 *txbdp; u16 status; + unsigned long flags; /* Update transmit stats */ priv->stats.tx_bytes += skb->len; /* Lock priv now */ - spin_lock_irq(&priv->lock); + spin_lock_irqsave(&priv->txlock, flags); /* Point at the first free tx descriptor */ txbdp = priv->cur_tx; @@ -1004,7 +1009,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) gfar_write(&priv->regs->tstat, TSTAT_CLEAR_THALT); /* Unlock priv */ - spin_unlock_irq(&priv->lock); + spin_unlock_irqrestore(&priv->txlock, flags); return 0; } @@ -1049,7 +1054,7 @@ static void gfar_vlan_rx_register(struct net_device *dev, unsigned long flags; u32 tempval; - spin_lock_irqsave(&priv->lock, flags); + spin_lock_irqsave(&priv->rxlock, flags); priv->vlgrp = grp; @@ -1076,7 +1081,7 @@ static void gfar_vlan_rx_register(struct net_device *dev, gfar_write(&priv->regs->rctrl, tempval); } - spin_unlock_irqrestore(&priv->lock, flags); + spin_unlock_irqrestore(&priv->rxlock, flags); } @@ -1085,12 +1090,12 @@ static void gfar_vlan_rx_kill_vid(struct net_device *dev, uint16_t vid) struct gfar_private *priv = netdev_priv(dev); unsigned long flags; - spin_lock_irqsave(&priv->lock, flags); + spin_lock_irqsave(&priv->rxlock, flags); if (priv->vlgrp) priv->vlgrp->vlan_devices[vid] = NULL; - spin_unlock_irqrestore(&priv->lock, flags); + spin_unlock_irqrestore(&priv->rxlock, flags); } @@ -1179,7 +1184,7 @@ static irqreturn_t gfar_transmit(int irq, void *dev_id, struct pt_regs *regs) gfar_write(&priv->regs->ievent, IEVENT_TX_MASK); /* Lock priv */ - spin_lock(&priv->lock); + spin_lock(&priv->txlock); bdp = priv->dirty_tx; while ((bdp->status & TXBD_READY) == 0) { /* If dirty_tx and cur_tx are the same, then either the */ @@ -1224,7 +1229,7 @@ static irqreturn_t gfar_transmit(int irq, void *dev_id, struct pt_regs *regs) else gfar_write(&priv->regs->txic, 0); - spin_unlock(&priv->lock); + spin_unlock(&priv->txlock); return IRQ_HANDLED; } @@ -1305,9 +1310,10 @@ irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *) dev_id; struct gfar_private *priv = netdev_priv(dev); - #ifdef CONFIG_GFAR_NAPI u32 tempval; +#else + unsigned long flags; #endif /* Clear IEVENT, so rx interrupt isn't called again @@ -1330,7 +1336,7 @@ irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs) } #else - spin_lock(&priv->lock); + spin_lock_irqsave(&priv->rxlock, flags); gfar_clean_rx_ring(dev, priv->rx_ring_size); /* If we are coalescing interrupts, update the timer */ @@ -1341,7 +1347,7 @@ irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs) else gfar_write(&priv->regs->rxic, 0); - spin_unlock(&priv->lock); + spin_unlock_irqrestore(&priv->rxlock, flags); #endif return IRQ_HANDLED; @@ -1490,13 +1496,6 @@ int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit) /* Update the current rxbd pointer to be the next one */ priv->cur_rx = bdp; - /* If no packets have arrived since the - * last one we processed, clear the IEVENT RX and - * BSY bits so that another interrupt won't be - * generated when we set IMASK */ - if (bdp->status & RXBD_EMPTY) - gfar_write(&priv->regs->ievent, IEVENT_RX_MASK); - return howmany; } @@ -1516,7 +1515,7 @@ static int gfar_poll(struct net_device *dev, int *budget) rx_work_limit -= howmany; *budget -= howmany; - if (rx_work_limit >= 0) { + if (rx_work_limit > 0) { netif_rx_complete(dev); /* Clear the halt bit in RSTAT */ @@ -1533,7 +1532,8 @@ static int gfar_poll(struct net_device *dev, int *budget) gfar_write(&priv->regs->rxic, 0); } - return (rx_work_limit < 0) ? 1 : 0; + /* Return 1 if there's more work to do */ + return (rx_work_limit > 0) ? 0 : 1; } #endif @@ -1629,7 +1629,7 @@ static void adjust_link(struct net_device *dev) struct phy_device *phydev = priv->phydev; int new_state = 0; - spin_lock_irqsave(&priv->lock, flags); + spin_lock_irqsave(&priv->txlock, flags); if (phydev->link) { u32 tempval = gfar_read(®s->maccfg2); u32 ecntrl = gfar_read(®s->ecntrl); @@ -1694,7 +1694,7 @@ static void adjust_link(struct net_device *dev) if (new_state && netif_msg_link(priv)) phy_print_status(phydev); - spin_unlock_irqrestore(&priv->lock, flags); + spin_unlock_irqrestore(&priv->txlock, flags); } /* Update the hash table based on the current list of multicast diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h index d37d5401be6..127c98cf333 100644 --- a/drivers/net/gianfar.h +++ b/drivers/net/gianfar.h @@ -656,43 +656,62 @@ struct gfar { * the buffer descriptor determines the actual condition. */ struct gfar_private { - /* pointers to arrays of skbuffs for tx and rx */ + /* Fields controlled by TX lock */ + spinlock_t txlock; + + /* Pointer to the array of skbuffs */ struct sk_buff ** tx_skbuff; - struct sk_buff ** rx_skbuff; - /* indices pointing to the next free sbk in skb arrays */ + /* next free skb in the array */ u16 skb_curtx; - u16 skb_currx; - /* index of the first skb which hasn't been transmitted - * yet. */ + /* First skb in line to be transmitted */ u16 skb_dirtytx; /* Configuration info for the coalescing features */ unsigned char txcoalescing; unsigned short txcount; unsigned short txtime; + + /* Buffer descriptor pointers */ + struct txbd8 *tx_bd_base; /* First tx buffer descriptor */ + struct txbd8 *cur_tx; /* Next free ring entry */ + struct txbd8 *dirty_tx; /* First buffer in line + to be transmitted */ + unsigned int tx_ring_size; + + /* RX Locked fields */ + spinlock_t rxlock; + + /* skb array and index */ + struct sk_buff ** rx_skbuff; + u16 skb_currx; + + /* RX Coalescing values */ unsigned char rxcoalescing; unsigned short rxcount; unsigned short rxtime; - /* GFAR addresses */ - struct rxbd8 *rx_bd_base; /* Base addresses of Rx and Tx Buffers */ - struct txbd8 *tx_bd_base; + struct rxbd8 *rx_bd_base; /* First Rx buffers */ struct rxbd8 *cur_rx; /* Next free rx ring entry */ - struct txbd8 *cur_tx; /* Next free ring entry */ - struct txbd8 *dirty_tx; /* The Ring entry to be freed. */ - struct gfar __iomem *regs; /* Pointer to the GFAR memory mapped Registers */ - u32 __iomem *hash_regs[16]; - int hash_width; - struct net_device_stats stats; /* linux network statistics */ - struct gfar_extra_stats extra_stats; - spinlock_t lock; + + /* RX parameters */ + unsigned int rx_ring_size; unsigned int rx_buffer_size; unsigned int rx_stash_size; unsigned int rx_stash_index; - unsigned int tx_ring_size; - unsigned int rx_ring_size; + + struct vlan_group *vlgrp; + + /* Unprotected fields */ + /* Pointer to the GFAR memory mapped Registers */ + struct gfar __iomem *regs; + + /* Hash registers and their width */ + u32 __iomem *hash_regs[16]; + int hash_width; + + /* global parameters */ unsigned int fifo_threshold; unsigned int fifo_starve; unsigned int fifo_starve_off; @@ -702,13 +721,15 @@ struct gfar_private { extended_hash:1, bd_stash_en:1; unsigned short padding; - struct vlan_group *vlgrp; - /* Info structure initialized by board setup code */ + unsigned int interruptTransmit; unsigned int interruptReceive; unsigned int interruptError; + + /* info structure initialized by platform code */ struct gianfar_platform_data *einfo; + /* PHY stuff */ struct phy_device *phydev; struct mii_bus *mii_bus; int oldspeed; @@ -716,6 +737,10 @@ struct gfar_private { int oldlink; uint32_t msg_enable; + + /* Network Statistics */ + struct net_device_stats stats; + struct gfar_extra_stats extra_stats; }; static inline u32 gfar_read(volatile unsigned __iomem *addr) diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c index 5de7b2e259d..d69698c695e 100644 --- a/drivers/net/gianfar_ethtool.c +++ b/drivers/net/gianfar_ethtool.c @@ -455,10 +455,14 @@ static int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rva /* Halt TX and RX, and process the frames which * have already been received */ - spin_lock_irqsave(&priv->lock, flags); + spin_lock_irqsave(&priv->txlock, flags); + spin_lock(&priv->rxlock); + gfar_halt(dev); gfar_clean_rx_ring(dev, priv->rx_ring_size); - spin_unlock_irqrestore(&priv->lock, flags); + + spin_unlock(&priv->rxlock); + spin_unlock_irqrestore(&priv->txlock, flags); /* Now we take down the rings to rebuild them */ stop_gfar(dev); @@ -488,10 +492,14 @@ static int gfar_set_rx_csum(struct net_device *dev, uint32_t data) /* Halt TX and RX, and process the frames which * have already been received */ - spin_lock_irqsave(&priv->lock, flags); + spin_lock_irqsave(&priv->txlock, flags); + spin_lock(&priv->rxlock); + gfar_halt(dev); gfar_clean_rx_ring(dev, priv->rx_ring_size); - spin_unlock_irqrestore(&priv->lock, flags); + + spin_unlock(&priv->rxlock); + spin_unlock_irqrestore(&priv->txlock, flags); /* Now we take down the rings to rebuild them */ stop_gfar(dev); @@ -523,7 +531,7 @@ static int gfar_set_tx_csum(struct net_device *dev, uint32_t data) if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_CSUM)) return -EOPNOTSUPP; - spin_lock_irqsave(&priv->lock, flags); + spin_lock_irqsave(&priv->txlock, flags); gfar_halt(dev); if (data) @@ -532,7 +540,7 @@ static int gfar_set_tx_csum(struct net_device *dev, uint32_t data) dev->features &= ~NETIF_F_IP_CSUM; gfar_start(dev); - spin_unlock_irqrestore(&priv->lock, flags); + spin_unlock_irqrestore(&priv->txlock, flags); return 0; } diff --git a/drivers/net/gianfar_sysfs.c b/drivers/net/gianfar_sysfs.c index 51ef181b136..a6d5c43199c 100644 --- a/drivers/net/gianfar_sysfs.c +++ b/drivers/net/gianfar_sysfs.c @@ -82,7 +82,7 @@ static ssize_t gfar_set_bd_stash(struct class_device *cdev, else return count; - spin_lock_irqsave(&priv->lock, flags); + spin_lock_irqsave(&priv->rxlock, flags); /* Set the new stashing value */ priv->bd_stash_en = new_setting; @@ -96,7 +96,7 @@ static ssize_t gfar_set_bd_stash(struct class_device *cdev, gfar_write(&priv->regs->attr, temp); - spin_unlock_irqrestore(&priv->lock, flags); + spin_unlock_irqrestore(&priv->rxlock, flags); return count; } @@ -118,7 +118,7 @@ static ssize_t gfar_set_rx_stash_size(struct class_device *cdev, u32 temp; unsigned long flags; - spin_lock_irqsave(&priv->lock, flags); + spin_lock_irqsave(&priv->rxlock, flags); if (length > priv->rx_buffer_size) return count; @@ -142,7 +142,7 @@ static ssize_t gfar_set_rx_stash_size(struct class_device *cdev, gfar_write(&priv->regs->attr, temp); - spin_unlock_irqrestore(&priv->lock, flags); + spin_unlock_irqrestore(&priv->rxlock, flags); return count; } @@ -166,7 +166,7 @@ static ssize_t gfar_set_rx_stash_index(struct class_device *cdev, u32 temp; unsigned long flags; - spin_lock_irqsave(&priv->lock, flags); + spin_lock_irqsave(&priv->rxlock, flags); if (index > priv->rx_stash_size) return count; @@ -180,7 +180,7 @@ static ssize_t gfar_set_rx_stash_index(struct class_device *cdev, temp |= ATTRELI_EI(index); gfar_write(&priv->regs->attreli, flags); - spin_unlock_irqrestore(&priv->lock, flags); + spin_unlock_irqrestore(&priv->rxlock, flags); return count; } @@ -205,7 +205,7 @@ static ssize_t gfar_set_fifo_threshold(struct class_device *cdev, if (length > GFAR_MAX_FIFO_THRESHOLD) return count; - spin_lock_irqsave(&priv->lock, flags); + spin_lock_irqsave(&priv->txlock, flags); priv->fifo_threshold = length; @@ -214,7 +214,7 @@ static ssize_t gfar_set_fifo_threshold(struct class_device *cdev, temp |= length; gfar_write(&priv->regs->fifo_tx_thr, temp); - spin_unlock_irqrestore(&priv->lock, flags); + spin_unlock_irqrestore(&priv->txlock, flags); return count; } @@ -240,7 +240,7 @@ static ssize_t gfar_set_fifo_starve(struct class_device *cdev, if (num > GFAR_MAX_FIFO_STARVE) return count; - spin_lock_irqsave(&priv->lock, flags); + spin_lock_irqsave(&priv->txlock, flags); priv->fifo_starve = num; @@ -249,7 +249,7 @@ static ssize_t gfar_set_fifo_starve(struct class_device *cdev, temp |= num; gfar_write(&priv->regs->fifo_tx_starve, temp); - spin_unlock_irqrestore(&priv->lock, flags); + spin_unlock_irqrestore(&priv->txlock, flags); return count; } @@ -274,7 +274,7 @@ static ssize_t gfar_set_fifo_starve_off(struct class_device *cdev, if (num > GFAR_MAX_FIFO_STARVE_OFF) return count; - spin_lock_irqsave(&priv->lock, flags); + spin_lock_irqsave(&priv->txlock, flags); priv->fifo_starve_off = num; @@ -283,7 +283,7 @@ static ssize_t gfar_set_fifo_starve_off(struct class_device *cdev, temp |= num; gfar_write(&priv->regs->fifo_tx_starve_shutoff, temp); - spin_unlock_irqrestore(&priv->lock, flags); + spin_unlock_irqrestore(&priv->txlock, flags); return count; } diff --git a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c index 79a8fbcf5f9..0d5fccc984b 100644 --- a/drivers/net/hamradio/dmascc.c +++ b/drivers/net/hamradio/dmascc.c @@ -582,7 +582,6 @@ static int __init setup_adapter(int card_base, int type, int n) INIT_WORK(&priv->rx_work, rx_bh, priv); dev->priv = priv; sprintf(dev->name, "dmascc%i", 2 * n + i); - SET_MODULE_OWNER(dev); dev->base_addr = card_base; dev->irq = irq; dev->open = scc_open; diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c index 6ace0e914fd..5927784df3f 100644 --- a/drivers/net/hamradio/scc.c +++ b/drivers/net/hamradio/scc.c @@ -1550,7 +1550,6 @@ static unsigned char ax25_nocall[AX25_ADDR_LEN] = static void scc_net_setup(struct net_device *dev) { - SET_MODULE_OWNER(dev); dev->tx_queue_len = 16; /* should be enough... */ dev->open = scc_net_open; diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c index fe22479eb20..b49884048ca 100644 --- a/drivers/net/hamradio/yam.c +++ b/drivers/net/hamradio/yam.c @@ -1098,7 +1098,6 @@ static void yam_setup(struct net_device *dev) dev->base_addr = yp->iobase; dev->irq = yp->irq; - SET_MODULE_OWNER(dev); dev->open = yam_open; dev->stop = yam_close; diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index ea62a3e7d58..411f4d809c4 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -1419,6 +1419,8 @@ static int mv643xx_eth_probe(struct platform_device *pdev) mv643xx_eth_update_pscr(dev, &cmd); mv643xx_set_settings(dev, &cmd); + SET_MODULE_OWNER(dev); + SET_NETDEV_DEV(dev, &pdev->dev); err = register_netdev(dev); if (err) goto out; diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 67b0eab1658..227df9876a2 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -51,7 +51,7 @@ #include "sky2.h" #define DRV_NAME "sky2" -#define DRV_VERSION "1.1" +#define DRV_VERSION "1.2" #define PFX DRV_NAME " " /* @@ -925,8 +925,7 @@ static inline struct sk_buff *sky2_alloc_skb(unsigned int size, gfp_t gfp_mask) skb = alloc_skb(size + RX_SKB_ALIGN, gfp_mask); if (likely(skb)) { unsigned long p = (unsigned long) skb->data; - skb_reserve(skb, - ((p + RX_SKB_ALIGN - 1) & ~(RX_SKB_ALIGN - 1)) - p); + skb_reserve(skb, ALIGN(p, RX_SKB_ALIGN) - p); } return skb; @@ -1686,13 +1685,12 @@ static void sky2_tx_timeout(struct net_device *dev) } -#define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) /* Want receive buffer size to be multiple of 64 bits * and incl room for vlan and truncation */ static inline unsigned sky2_buf_size(int mtu) { - return roundup(mtu + ETH_HLEN + VLAN_HLEN, 8) + 8; + return ALIGN(mtu + ETH_HLEN + VLAN_HLEN, 8) + 8; } static int sky2_change_mtu(struct net_device *dev, int new_mtu) @@ -2086,6 +2084,20 @@ static void sky2_descriptor_error(struct sky2_hw *hw, unsigned port, } } +/* If idle then force a fake soft NAPI poll once a second + * to work around cases where sharing an edge triggered interrupt. + */ +static void sky2_idle(unsigned long arg) +{ + struct net_device *dev = (struct net_device *) arg; + + local_irq_disable(); + if (__netif_rx_schedule_prep(dev)) + __netif_rx_schedule(dev); + local_irq_enable(); +} + + static int sky2_poll(struct net_device *dev0, int *budget) { struct sky2_hw *hw = ((struct sky2_port *) netdev_priv(dev0))->hw; @@ -2093,6 +2105,7 @@ static int sky2_poll(struct net_device *dev0, int *budget) int work_done = 0; u32 status = sky2_read32(hw, B0_Y2_SP_EISR); + restart_poll: if (unlikely(status & ~Y2_IS_STAT_BMU)) { if (status & Y2_IS_HW_ERR) sky2_hw_intr(hw); @@ -2123,7 +2136,7 @@ static int sky2_poll(struct net_device *dev0, int *budget) } if (status & Y2_IS_STAT_BMU) { - work_done = sky2_status_intr(hw, work_limit); + work_done += sky2_status_intr(hw, work_limit - work_done); *budget -= work_done; dev0->quota -= work_done; @@ -2133,9 +2146,24 @@ static int sky2_poll(struct net_device *dev0, int *budget) sky2_write32(hw, STAT_CTRL, SC_STAT_CLR_IRQ); } - netif_rx_complete(dev0); + mod_timer(&hw->idle_timer, jiffies + HZ); + + local_irq_disable(); + __netif_rx_complete(dev0); status = sky2_read32(hw, B0_Y2_SP_LISR); + + if (unlikely(status)) { + /* More work pending, try and keep going */ + if (__netif_rx_schedule_prep(dev0)) { + __netif_rx_reschedule(dev0, work_done); + status = sky2_read32(hw, B0_Y2_SP_EISR); + local_irq_enable(); + goto restart_poll; + } + } + + local_irq_enable(); return 0; } @@ -2153,8 +2181,6 @@ static irqreturn_t sky2_intr(int irq, void *dev_id, struct pt_regs *regs) prefetch(&hw->st_le[hw->st_idx]); if (likely(__netif_rx_schedule_prep(dev0))) __netif_rx_schedule(dev0); - else - printk(KERN_DEBUG PFX "irq race detected\n"); return IRQ_HANDLED; } @@ -2193,7 +2219,7 @@ static inline u32 sky2_clk2us(const struct sky2_hw *hw, u32 clk) } -static int sky2_reset(struct sky2_hw *hw) +static int __devinit sky2_reset(struct sky2_hw *hw) { u16 status; u8 t8, pmd_type; @@ -3276,6 +3302,8 @@ static int __devinit sky2_probe(struct pci_dev *pdev, sky2_write32(hw, B0_IMSK, Y2_IS_BASE); + setup_timer(&hw->idle_timer, sky2_idle, (unsigned long) dev); + pci_set_drvdata(pdev, hw); return 0; @@ -3311,13 +3339,15 @@ static void __devexit sky2_remove(struct pci_dev *pdev) if (!hw) return; + del_timer_sync(&hw->idle_timer); + + sky2_write32(hw, B0_IMSK, 0); dev0 = hw->dev[0]; dev1 = hw->dev[1]; if (dev1) unregister_netdev(dev1); unregister_netdev(dev0); - sky2_write32(hw, B0_IMSK, 0); sky2_set_power_state(hw, PCI_D3hot); sky2_write16(hw, B0_Y2LED, LED_STAT_OFF); sky2_write8(hw, B0_CTST, CS_RST_SET); diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index 89dd18cd12f..b026f5653f0 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -1880,6 +1880,8 @@ struct sky2_hw { struct sky2_status_le *st_le; u32 st_idx; dma_addr_t st_dma; + + struct timer_list idle_timer; int msi_detected; wait_queue_head_t msi_wait; }; diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 73e271e59c6..beeb612be98 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -69,8 +69,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.56" -#define DRV_MODULE_RELDATE "Apr 1, 2006" +#define DRV_MODULE_VERSION "3.57" +#define DRV_MODULE_RELDATE "Apr 28, 2006" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 @@ -974,6 +974,8 @@ static int tg3_phy_reset_5703_4_5(struct tg3 *tp) return err; } +static void tg3_link_report(struct tg3 *); + /* This will reset the tigon3 PHY if there is no valid * link unless the FORCE argument is non-zero. */ @@ -987,6 +989,11 @@ static int tg3_phy_reset(struct tg3 *tp) if (err != 0) return -EBUSY; + if (netif_running(tp->dev) && netif_carrier_ok(tp->dev)) { + netif_carrier_off(tp->dev); + tg3_link_report(tp); + } + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) { @@ -1023,6 +1030,12 @@ out: tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x14e2); tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0400); } + else if (tp->tg3_flags2 & TG3_FLG2_PHY_JITTER_BUG) { + tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00); + tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x000a); + tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x010b); + tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0400); + } /* Set Extended packet length bit (bit 14) on all chips that */ /* support jumbo frames */ if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401) { @@ -3531,7 +3544,7 @@ static irqreturn_t tg3_test_isr(int irq, void *dev_id, return IRQ_RETVAL(0); } -static int tg3_init_hw(struct tg3 *); +static int tg3_init_hw(struct tg3 *, int); static int tg3_halt(struct tg3 *, int, int); #ifdef CONFIG_NET_POLL_CONTROLLER @@ -3567,7 +3580,7 @@ static void tg3_reset_task(void *_data) tp->tg3_flags2 &= ~TG3_FLG2_RESTART_TIMER; tg3_halt(tp, RESET_KIND_SHUTDOWN, 0); - tg3_init_hw(tp); + tg3_init_hw(tp, 1); tg3_netif_start(tp); @@ -4042,7 +4055,7 @@ static int tg3_change_mtu(struct net_device *dev, int new_mtu) tg3_set_mtu(dev, tp, new_mtu); - tg3_init_hw(tp); + tg3_init_hw(tp, 0); tg3_netif_start(tp); @@ -5719,9 +5732,23 @@ static int tg3_set_mac_addr(struct net_device *dev, void *p) if (!netif_running(dev)) return 0; - spin_lock_bh(&tp->lock); - __tg3_set_mac_addr(tp); - spin_unlock_bh(&tp->lock); + if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) { + /* Reset chip so that ASF can re-init any MAC addresses it + * needs. + */ + tg3_netif_stop(tp); + tg3_full_lock(tp, 1); + + tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); + tg3_init_hw(tp, 0); + + tg3_netif_start(tp); + tg3_full_unlock(tp); + } else { + spin_lock_bh(&tp->lock); + __tg3_set_mac_addr(tp); + spin_unlock_bh(&tp->lock); + } return 0; } @@ -5771,7 +5798,7 @@ static void __tg3_set_coalesce(struct tg3 *tp, struct ethtool_coalesce *ec) } /* tp->lock is held. */ -static int tg3_reset_hw(struct tg3 *tp) +static int tg3_reset_hw(struct tg3 *tp, int reset_phy) { u32 val, rdmac_mode; int i, err, limit; @@ -5786,7 +5813,7 @@ static int tg3_reset_hw(struct tg3 *tp) tg3_abort_hw(tp, 1); } - if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES) + if ((tp->tg3_flags2 & TG3_FLG2_MII_SERDES) && reset_phy) tg3_phy_reset(tp); err = tg3_chip_reset(tp); @@ -6327,7 +6354,7 @@ static int tg3_reset_hw(struct tg3 *tp) tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl); } - err = tg3_setup_phy(tp, 1); + err = tg3_setup_phy(tp, reset_phy); if (err) return err; @@ -6400,7 +6427,7 @@ static int tg3_reset_hw(struct tg3 *tp) /* Called at device open time to get the chip ready for * packet processing. Invoked with tp->lock held. */ -static int tg3_init_hw(struct tg3 *tp) +static int tg3_init_hw(struct tg3 *tp, int reset_phy) { int err; @@ -6413,7 +6440,7 @@ static int tg3_init_hw(struct tg3 *tp) tw32(TG3PCI_MEM_WIN_BASE_ADDR, 0); - err = tg3_reset_hw(tp); + err = tg3_reset_hw(tp, reset_phy); out: return err; @@ -6683,7 +6710,7 @@ static int tg3_test_msi(struct tg3 *tp) tg3_full_lock(tp, 1); tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); - err = tg3_init_hw(tp); + err = tg3_init_hw(tp, 1); tg3_full_unlock(tp); @@ -6748,7 +6775,7 @@ static int tg3_open(struct net_device *dev) tg3_full_lock(tp, 0); - err = tg3_init_hw(tp); + err = tg3_init_hw(tp, 1); if (err) { tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); tg3_free_rings(tp); @@ -7839,7 +7866,7 @@ static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *e if (netif_running(dev)) { tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); - tg3_init_hw(tp); + tg3_init_hw(tp, 1); tg3_netif_start(tp); } @@ -7884,7 +7911,7 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam if (netif_running(dev)) { tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); - tg3_init_hw(tp); + tg3_init_hw(tp, 1); tg3_netif_start(tp); } @@ -8522,7 +8549,7 @@ static int tg3_test_loopback(struct tg3 *tp) if (!netif_running(tp->dev)) return TG3_LOOPBACK_FAILED; - tg3_reset_hw(tp); + tg3_reset_hw(tp, 1); if (tg3_run_loopback(tp, TG3_MAC_LOOPBACK)) err |= TG3_MAC_LOOPBACK_FAILED; @@ -8596,7 +8623,7 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest, tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); if (netif_running(dev)) { tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE; - tg3_init_hw(tp); + tg3_init_hw(tp, 1); tg3_netif_start(tp); } @@ -9377,7 +9404,7 @@ static int tg3_nvram_write_block_buffered(struct tg3 *tp, u32 offset, u32 len, if ((page_off == 0) || (i == 0)) nvram_cmd |= NVRAM_CMD_FIRST; - else if (page_off == (tp->nvram_pagesize - 4)) + if (page_off == (tp->nvram_pagesize - 4)) nvram_cmd |= NVRAM_CMD_LAST; if (i == (len - 4)) @@ -10353,10 +10380,13 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0) tp->tg3_flags2 |= TG3_FLG2_PHY_5704_A0_BUG; - if ((tp->tg3_flags2 & TG3_FLG2_5705_PLUS) && - (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5755) && - (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5787)) - tp->tg3_flags2 |= TG3_FLG2_PHY_BER_BUG; + if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) { + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) + tp->tg3_flags2 |= TG3_FLG2_PHY_JITTER_BUG; + else + tp->tg3_flags2 |= TG3_FLG2_PHY_BER_BUG; + } tp->coalesce_mode = 0; if (GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5700_AX && @@ -11569,7 +11599,7 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state) tg3_full_lock(tp, 0); tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE; - tg3_init_hw(tp); + tg3_init_hw(tp, 1); tp->timer.expires = jiffies + tp->timer_offset; add_timer(&tp->timer); @@ -11603,7 +11633,7 @@ static int tg3_resume(struct pci_dev *pdev) tg3_full_lock(tp, 0); tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE; - tg3_init_hw(tp); + tg3_init_hw(tp, 1); tp->timer.expires = jiffies + tp->timer_offset; add_timer(&tp->timer); diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 8c8b987d125..0e29b885d44 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2215,6 +2215,7 @@ struct tg3 { #define TG3_FLG2_HW_TSO_2 0x08000000 #define TG3_FLG2_HW_TSO (TG3_FLG2_HW_TSO_1 | TG3_FLG2_HW_TSO_2) #define TG3_FLG2_1SHOT_MSI 0x10000000 +#define TG3_FLG2_PHY_JITTER_BUG 0x20000000 u32 split_mode_max_reqs; #define SPLIT_MODE_5704_MAX_REQ 3 diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index 6a23964c131..a6dc53b4250 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -129,6 +129,7 @@ - Massive clean-up - Rewrite PHY, media handling (remove options, full_duplex, backoff) - Fix Tx engine race for good + - Craig Brind: Zero padded aligned buffers for short packets. */ @@ -1326,7 +1327,12 @@ static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev) rp->stats.tx_dropped++; return 0; } + + /* Padding is not copied and so must be redone. */ skb_copy_and_csum_dev(skb, rp->tx_buf[entry]); + if (skb->len < ETH_ZLEN) + memset(rp->tx_buf[entry] + skb->len, 0, + ETH_ZLEN - skb->len); rp->tx_skbuff_dma[entry] = 0; rp->tx_ring[entry].addr = cpu_to_le32(rp->tx_bufs_dma + (rp->tx_buf[entry] - diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 2087a397ef1..9855c4c920b 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -793,8 +793,10 @@ static int msix_capability_init(struct pci_dev *dev, if (!entry) break; vector = get_msi_vector(dev); - if (vector < 0) + if (vector < 0) { + kmem_cache_free(msi_cachep, entry); break; + } j = entries[i].entry; entries[i].vector = vector; diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index c42ae2cf8d6..19e2b174d33 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -642,13 +642,15 @@ static void quirk_via_irq(struct pci_dev *dev) new_irq = dev->irq & 0xf; pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq); if (new_irq != irq) { - printk(KERN_INFO "PCI: Via IRQ fixup for %s, from %d to %d\n", + printk(KERN_INFO "PCI: VIA IRQ fixup for %s, from %d to %d\n", pci_name(dev), irq, new_irq); udelay(15); /* unknown if delay really needed */ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, new_irq); } } -DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_ANY_ID, quirk_via_irq); +DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, quirk_via_irq); +DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_via_irq); +DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_5, quirk_via_irq); /* * VIA VT82C598 has its device ID settable and many BIOSes diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c index bd0308e8981..a2f05f48515 100644 --- a/drivers/pcmcia/i82365.c +++ b/drivers/pcmcia/i82365.c @@ -509,7 +509,8 @@ static irqreturn_t i365_count_irq(int irq, void *dev, struct pt_regs *regs) static u_int __init test_irq(u_short sock, int irq) { debug(2, " testing ISA irq %d\n", irq); - if (request_irq(irq, i365_count_irq, 0, "scan", i365_count_irq) != 0) + if (request_irq(irq, i365_count_irq, SA_PROBEIRQ, "scan", + i365_count_irq) != 0) return 1; irq_hits = 0; irq_sock = sock; msleep(10); @@ -561,7 +562,7 @@ static u_int __init isa_scan(u_short sock, u_int mask0) } else { /* Fallback: just find interrupts that aren't in use */ for (i = 0; i < 16; i++) - if ((mask0 & (1 << i)) && (_check_irq(i, 0) == 0)) + if ((mask0 & (1 << i)) && (_check_irq(i, SA_PROBEIRQ) == 0)) mask1 |= (1 << i); printk("default"); /* If scan failed, default to polled status */ @@ -725,7 +726,7 @@ static void __init add_pcic(int ns, int type) u_int cs_mask = mask & ((cs_irq) ? (1<<cs_irq) : ~(1<<12)); for (cs_irq = 15; cs_irq > 0; cs_irq--) if ((cs_mask & (1 << cs_irq)) && - (_check_irq(cs_irq, 0) == 0)) + (_check_irq(cs_irq, SA_PROBEIRQ) == 0)) break; if (cs_irq) { grab_irq = 1; diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c index b1e3e6179e5..6c9ad92747f 100644 --- a/drivers/rtc/rtc-dev.c +++ b/drivers/rtc/rtc-dev.c @@ -58,7 +58,7 @@ rtc_dev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) unsigned long data; ssize_t ret; - if (count < sizeof(unsigned long)) + if (count != sizeof(unsigned int) && count < sizeof(unsigned long)) return -EINVAL; add_wait_queue(&rtc->irq_queue, &wait); @@ -90,11 +90,16 @@ rtc_dev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) if (ret == 0) { /* Check for any data updates */ if (rtc->ops->read_callback) - data = rtc->ops->read_callback(rtc->class_dev.dev, data); - - ret = put_user(data, (unsigned long __user *)buf); - if (ret == 0) - ret = sizeof(unsigned long); + data = rtc->ops->read_callback(rtc->class_dev.dev, + data); + + if (sizeof(int) != sizeof(long) && + count == sizeof(unsigned int)) + ret = put_user(data, (unsigned int __user *)buf) ?: + sizeof(unsigned int); + else + ret = put_user(data, (unsigned long __user *)buf) ?: + sizeof(unsigned long); } return ret; } diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index a3bfebcf31e..cfb1fff3787 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -315,6 +315,11 @@ dasd_increase_state(struct dasd_device *device) rc = dasd_state_basic_to_ready(device); if (!rc && + device->state == DASD_STATE_UNFMT && + device->target > DASD_STATE_UNFMT) + rc = -EPERM; + + if (!rc && device->state == DASD_STATE_READY && device->target >= DASD_STATE_ONLINE) rc = dasd_state_ready_to_online(device); diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index c1c6f138115..216bc4fba19 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c @@ -45,6 +45,7 @@ struct dasd_devmap { unsigned int devindex; unsigned short features; struct dasd_device *device; + struct dasd_uid uid; }; /* @@ -716,6 +717,68 @@ dasd_discipline_show(struct device *dev, struct device_attribute *attr, char *bu static DEVICE_ATTR(discipline, 0444, dasd_discipline_show, NULL); +static ssize_t +dasd_alias_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct dasd_devmap *devmap; + int alias; + + devmap = dasd_find_busid(dev->bus_id); + spin_lock(&dasd_devmap_lock); + if (!IS_ERR(devmap)) + alias = devmap->uid.alias; + else + alias = 0; + spin_unlock(&dasd_devmap_lock); + + return sprintf(buf, alias ? "1\n" : "0\n"); +} + +static DEVICE_ATTR(alias, 0444, dasd_alias_show, NULL); + +static ssize_t +dasd_vendor_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct dasd_devmap *devmap; + char *vendor; + + devmap = dasd_find_busid(dev->bus_id); + spin_lock(&dasd_devmap_lock); + if (!IS_ERR(devmap) && strlen(devmap->uid.vendor) > 0) + vendor = devmap->uid.vendor; + else + vendor = ""; + spin_unlock(&dasd_devmap_lock); + + return snprintf(buf, PAGE_SIZE, "%s\n", vendor); +} + +static DEVICE_ATTR(vendor, 0444, dasd_vendor_show, NULL); + +#define UID_STRLEN ( /* vendor */ 3 + 1 + /* serial */ 14 + 1 +\ + /* SSID */ 4 + 1 + /* unit addr */ 2 + 1) + +static ssize_t +dasd_uid_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct dasd_devmap *devmap; + char uid[UID_STRLEN]; + + devmap = dasd_find_busid(dev->bus_id); + spin_lock(&dasd_devmap_lock); + if (!IS_ERR(devmap) && strlen(devmap->uid.vendor) > 0) + snprintf(uid, sizeof(uid), "%s.%s.%04x.%02x", + devmap->uid.vendor, devmap->uid.serial, + devmap->uid.ssid, devmap->uid.unit_addr); + else + uid[0] = 0; + spin_unlock(&dasd_devmap_lock); + + return snprintf(buf, PAGE_SIZE, "%s\n", uid); +} + +static DEVICE_ATTR(uid, 0444, dasd_uid_show, NULL); + /* * extended error-reporting */ @@ -759,6 +822,9 @@ static DEVICE_ATTR(eer_enabled, 0644, dasd_eer_show, dasd_eer_store); static struct attribute * dasd_attrs[] = { &dev_attr_readonly.attr, &dev_attr_discipline.attr, + &dev_attr_alias.attr, + &dev_attr_vendor.attr, + &dev_attr_uid.attr, &dev_attr_use_diag.attr, &dev_attr_eer_enabled.attr, NULL, @@ -768,6 +834,42 @@ static struct attribute_group dasd_attr_group = { .attrs = dasd_attrs, }; + +/* + * Return copy of the device unique identifier. + */ +int +dasd_get_uid(struct ccw_device *cdev, struct dasd_uid *uid) +{ + struct dasd_devmap *devmap; + + devmap = dasd_find_busid(cdev->dev.bus_id); + if (IS_ERR(devmap)) + return PTR_ERR(devmap); + spin_lock(&dasd_devmap_lock); + *uid = devmap->uid; + spin_unlock(&dasd_devmap_lock); + return 0; +} + +/* + * Register the given device unique identifier into devmap struct. + */ +int +dasd_set_uid(struct ccw_device *cdev, struct dasd_uid *uid) +{ + struct dasd_devmap *devmap; + + devmap = dasd_find_busid(cdev->dev.bus_id); + if (IS_ERR(devmap)) + return PTR_ERR(devmap); + spin_lock(&dasd_devmap_lock); + devmap->uid = *uid; + spin_unlock(&dasd_devmap_lock); + return 0; +} +EXPORT_SYMBOL(dasd_set_uid); + /* * Return value of the specified feature. */ diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index ee09ef33d08..7d5a6cee4bd 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -446,6 +446,39 @@ dasd_eckd_cdl_reclen(int recid) return LABEL_SIZE; } +/* + * Generate device unique id that specifies the physical device. + */ +static int +dasd_eckd_generate_uid(struct dasd_device *device, struct dasd_uid *uid) +{ + struct dasd_eckd_private *private; + struct dasd_eckd_confdata *confdata; + + private = (struct dasd_eckd_private *) device->private; + if (!private) + return -ENODEV; + confdata = &private->conf_data; + if (!confdata) + return -ENODEV; + + memset(uid, 0, sizeof(struct dasd_uid)); + strncpy(uid->vendor, confdata->ned1.HDA_manufacturer, + sizeof(uid->vendor) - 1); + EBCASC(uid->vendor, sizeof(uid->vendor) - 1); + strncpy(uid->serial, confdata->ned1.HDA_location, + sizeof(uid->serial) - 1); + EBCASC(uid->serial, sizeof(uid->serial) - 1); + uid->ssid = confdata->neq.subsystemID; + if (confdata->ned2.sneq.flags == 0x40) { + uid->alias = 1; + uid->unit_addr = confdata->ned2.sneq.base_unit_addr; + } else + uid->unit_addr = confdata->ned1.unit_addr; + + return 0; +} + static int dasd_eckd_read_conf(struct dasd_device *device) { @@ -507,11 +540,15 @@ dasd_eckd_read_conf(struct dasd_device *device) return 0; } - +/* + * Check device characteristics. + * If the device is accessible using ECKD discipline, the device is enabled. + */ static int dasd_eckd_check_characteristics(struct dasd_device *device) { struct dasd_eckd_private *private; + struct dasd_uid uid; void *rdc_data; int rc; @@ -536,6 +573,7 @@ dasd_eckd_check_characteristics(struct dasd_device *device) /* Read Device Characteristics */ rdc_data = (void *) &(private->rdc_data); + memset(rdc_data, 0, sizeof(rdc_data)); rc = read_dev_chars(device->cdev, &rdc_data, 64); if (rc) { DEV_MESSAGE(KERN_WARNING, device, @@ -556,8 +594,17 @@ dasd_eckd_check_characteristics(struct dasd_device *device) /* Read Configuration Data */ rc = dasd_eckd_read_conf (device); - return rc; + if (rc) + return rc; + + /* Generate device unique id and register in devmap */ + rc = dasd_eckd_generate_uid(device, &uid); + if (rc) + return rc; + rc = dasd_set_uid(device->cdev, &uid); + + return rc; } static struct dasd_ccw_req * diff --git a/drivers/s390/block/dasd_eckd.h b/drivers/s390/block/dasd_eckd.h index ad8524bb7bb..d5734e976e1 100644 --- a/drivers/s390/block/dasd_eckd.h +++ b/drivers/s390/block/dasd_eckd.h @@ -228,26 +228,36 @@ struct dasd_eckd_confdata { unsigned char HDA_manufacturer[3]; unsigned char HDA_location[2]; unsigned char HDA_seqno[12]; - __u16 ID; + __u8 ID; + __u8 unit_addr; } __attribute__ ((packed)) ned1; - struct { + union { struct { - unsigned char identifier:2; - unsigned char token_id:1; - unsigned char sno_valid:1; - unsigned char subst_sno:1; - unsigned char recNED:1; - unsigned char emuNED:1; - unsigned char reserved:1; - } __attribute__ ((packed)) flags; - __u8 descriptor; - __u8 reserved[2]; - unsigned char dev_type[6]; - unsigned char dev_model[3]; - unsigned char DASD_manufacturer[3]; - unsigned char DASD_location[2]; - unsigned char DASD_seqno[12]; - __u16 ID; + struct { + unsigned char identifier:2; + unsigned char token_id:1; + unsigned char sno_valid:1; + unsigned char subst_sno:1; + unsigned char recNED:1; + unsigned char emuNED:1; + unsigned char reserved:1; + } __attribute__ ((packed)) flags; + __u8 descriptor; + __u8 reserved[2]; + unsigned char dev_type[6]; + unsigned char dev_model[3]; + unsigned char DASD_manufacturer[3]; + unsigned char DASD_location[2]; + unsigned char DASD_seqno[12]; + __u16 ID; + } __attribute__ ((packed)) ned; + struct { + unsigned char flags; /* byte 0 */ + unsigned char res2[7]; /* byte 1- 7 */ + unsigned char sua_flags; /* byte 8 */ + __u8 base_unit_addr; /* byte 9 */ + unsigned char res3[22]; /* byte 10-31 */ + } __attribute__ ((packed)) sneq; } __attribute__ ((packed)) ned2; struct { struct { diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index 4293ba82752..d4b13e300a7 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h @@ -268,6 +268,16 @@ struct dasd_discipline { extern struct dasd_discipline *dasd_diag_discipline_pointer; +/* + * Unique identifier for dasd device. + */ +struct dasd_uid { + __u8 alias; + char vendor[4]; + char serial[15]; + __u16 ssid; + __u8 unit_addr; +}; /* * Notification numbers for extended error reporting notifications: @@ -516,6 +526,8 @@ void dasd_devmap_exit(void); struct dasd_device *dasd_create_device(struct ccw_device *); void dasd_delete_device(struct dasd_device *); +int dasd_get_uid(struct ccw_device *, struct dasd_uid *); +int dasd_set_uid(struct ccw_device *, struct dasd_uid *); int dasd_get_feature(struct ccw_device *, int); int dasd_set_feature(struct ccw_device *, int, int); diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c index c3915f60a3a..d71ef1adea5 100644 --- a/drivers/s390/char/tape_3590.c +++ b/drivers/s390/char/tape_3590.c @@ -230,14 +230,16 @@ tape_3590_read_attmsg(struct tape_device *device) * These functions are used to schedule follow-up actions from within an * interrupt context (like unsolicited interrupts). */ +struct work_handler_data { + struct tape_device *device; + enum tape_op op; + struct work_struct work; +}; + static void tape_3590_work_handler(void *data) { - struct { - struct tape_device *device; - enum tape_op op; - struct work_struct work; - } *p = data; + struct work_handler_data *p = data; switch (p->op) { case TO_MSEN: @@ -257,11 +259,7 @@ tape_3590_work_handler(void *data) static int tape_3590_schedule_work(struct tape_device *device, enum tape_op op) { - struct { - struct tape_device *device; - enum tape_op op; - struct work_struct work; - } *p; + struct work_handler_data *p; if ((p = kzalloc(sizeof(*p), GFP_ATOMIC)) == NULL) return -ENOMEM; @@ -316,7 +314,7 @@ tape_3590_bread(struct tape_device *device, struct request *req) rq_for_each_bio(bio, req) { bio_for_each_segment(bv, bio, i) { - dst = kmap(bv->bv_page) + bv->bv_offset; + dst = page_address(bv->bv_page) + bv->bv_offset; for (off = 0; off < bv->bv_len; off += TAPEBLOCK_HSEC_SIZE) { ccw->flags = CCW_FLAG_CC; @@ -1168,6 +1166,7 @@ tape_3590_setup_device(struct tape_device *device) static void tape_3590_cleanup_device(struct tape_device *device) { + flush_scheduled_work(); tape_std_unassign(device); kfree(device->discdata); @@ -1234,6 +1233,7 @@ static struct tape_discipline tape_discipline_3590 = { static struct ccw_device_id tape_3590_ids[] = { {CCW_DEVICE_DEVTYPE(0x3590, 0, 0x3590, 0), .driver_info = tape_3590}, + {CCW_DEVICE_DEVTYPE(0x3592, 0, 0x3592, 0), .driver_info = tape_3592}, { /* end of list */ } }; diff --git a/drivers/s390/char/tape_std.h b/drivers/s390/char/tape_std.h index 2d311798edf..1fc95235934 100644 --- a/drivers/s390/char/tape_std.h +++ b/drivers/s390/char/tape_std.h @@ -153,6 +153,7 @@ enum s390_tape_type { tape_3480, tape_3490, tape_3590, + tape_3592, }; #endif // _TAPE_STD_H diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 6412b2c3edd..72187e54dca 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c @@ -242,28 +242,10 @@ s390_subchannel_remove_chpid(struct device *dev, void *data) if (sch->vpm == mask) goto out_unreg; - if ((sch->schib.scsw.actl & (SCSW_ACTL_CLEAR_PEND | - SCSW_ACTL_HALT_PEND | - SCSW_ACTL_START_PEND | - SCSW_ACTL_RESUME_PEND)) && - (sch->schib.pmcw.lpum == mask)) { - int cc = cio_cancel(sch); - - if (cc == -ENODEV) - goto out_unreg; - - if (cc == -EINVAL) { - cc = cio_clear(sch); - if (cc == -ENODEV) - goto out_unreg; - /* Call handler. */ - if (sch->driver && sch->driver->termination) - sch->driver->termination(&sch->dev); - goto out_unlock; - } - } else if ((sch->schib.scsw.actl & SCSW_ACTL_DEVACT) && - (sch->schib.scsw.actl & SCSW_ACTL_SCHACT) && - (sch->schib.pmcw.lpum == mask)) { + if ((sch->schib.scsw.actl & SCSW_ACTL_DEVACT) && + (sch->schib.scsw.actl & SCSW_ACTL_SCHACT) && + (sch->schib.pmcw.lpum == mask) && + (sch->vpm == 0)) { int cc; cc = cio_clear(sch); @@ -653,13 +635,13 @@ __chp_add(struct subchannel_id schid, void *data) if (sch->schib.pmcw.chpid[i] == chp->id) { if (stsch(sch->schid, &sch->schib) != 0) { /* Endgame. */ - spin_unlock(&sch->lock); + spin_unlock_irq(&sch->lock); return -ENXIO; } break; } if (i==8) { - spin_unlock(&sch->lock); + spin_unlock_irq(&sch->lock); return 0; } sch->lpm = ((sch->schib.pmcw.pim & diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c index 814f9258ce0..96f519281d9 100644 --- a/drivers/s390/cio/qdio.c +++ b/drivers/s390/cio/qdio.c @@ -38,6 +38,7 @@ #include <linux/kernel.h> #include <linux/proc_fs.h> #include <linux/timer.h> +#include <linux/mempool.h> #include <asm/ccwdev.h> #include <asm/io.h> @@ -80,6 +81,8 @@ static int indicator_used[INDICATORS_PER_CACHELINE]; static __u32 * volatile indicators; static __u32 volatile spare_indicator; static atomic_t spare_indicator_usecount; +#define QDIO_MEMPOOL_SCSSC_ELEMENTS 2 +static mempool_t *qdio_mempool_scssc; static debug_info_t *qdio_dbf_setup; static debug_info_t *qdio_dbf_sbal; @@ -1637,7 +1640,7 @@ next: } kfree(irq_ptr->qdr); - kfree(irq_ptr); + free_page((unsigned long) irq_ptr); } static void @@ -2304,7 +2307,7 @@ qdio_get_ssqd_information(struct qdio_irq *irq_ptr) QDIO_DBF_TEXT0(0,setup,"getssqd"); qdioac = 0; - ssqd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); + ssqd_area = mempool_alloc(qdio_mempool_scssc, GFP_ATOMIC); if (!ssqd_area) { QDIO_PRINT_WARN("Could not get memory for chsc. Using all " \ "SIGAs for sch x%x.\n", irq_ptr->schid.sch_no); @@ -2364,7 +2367,7 @@ qdio_get_ssqd_information(struct qdio_irq *irq_ptr) out: qdio_check_subchannel_qebsm(irq_ptr, qdioac, ssqd_area->sch_token); - free_page ((unsigned long) ssqd_area); + mempool_free(ssqd_area, qdio_mempool_scssc); irq_ptr->qdioac = qdioac; } @@ -2458,7 +2461,7 @@ tiqdio_set_subchannel_ind(struct qdio_irq *irq_ptr, int reset_to_zero) virt_to_phys((volatile void *)irq_ptr->dev_st_chg_ind); } - scssc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); + scssc_area = mempool_alloc(qdio_mempool_scssc, GFP_ATOMIC); if (!scssc_area) { QDIO_PRINT_WARN("No memory for setting indicators on " \ "subchannel 0.%x.%x.\n", @@ -2514,7 +2517,7 @@ tiqdio_set_subchannel_ind(struct qdio_irq *irq_ptr, int reset_to_zero) QDIO_DBF_HEX2(0,setup,&real_addr_dev_st_chg_ind,sizeof(unsigned long)); result = 0; out: - free_page ((unsigned long) scssc_area); + mempool_free(scssc_area, qdio_mempool_scssc); return result; } @@ -2543,7 +2546,7 @@ tiqdio_set_delay_target(struct qdio_irq *irq_ptr, unsigned long delay_target) if (!irq_ptr->is_thinint_irq) return -ENODEV; - scsscf_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); + scsscf_area = mempool_alloc(qdio_mempool_scssc, GFP_ATOMIC); if (!scsscf_area) { QDIO_PRINT_WARN("No memory for setting delay target on " \ "subchannel 0.%x.%x.\n", @@ -2581,7 +2584,7 @@ tiqdio_set_delay_target(struct qdio_irq *irq_ptr, unsigned long delay_target) QDIO_DBF_HEX2(0,trace,&delay_target,sizeof(unsigned long)); result = 0; /* not critical */ out: - free_page ((unsigned long) scsscf_area); + mempool_free(scsscf_area, qdio_mempool_scssc); return result; } @@ -2980,7 +2983,7 @@ qdio_allocate(struct qdio_initialize *init_data) qdio_allocate_do_dbf(init_data); /* create irq */ - irq_ptr = kzalloc(sizeof(struct qdio_irq), GFP_KERNEL | GFP_DMA); + irq_ptr = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA); QDIO_DBF_TEXT0(0,setup,"irq_ptr:"); QDIO_DBF_HEX0(0,setup,&irq_ptr,sizeof(void*)); @@ -2995,7 +2998,7 @@ qdio_allocate(struct qdio_initialize *init_data) /* QDR must be in DMA area since CCW data address is only 32 bit */ irq_ptr->qdr=kmalloc(sizeof(struct qdr), GFP_KERNEL | GFP_DMA); if (!(irq_ptr->qdr)) { - kfree(irq_ptr); + free_page((unsigned long) irq_ptr); QDIO_PRINT_ERR("kmalloc of irq_ptr->qdr failed!\n"); return -ENOMEM; } @@ -3780,6 +3783,16 @@ oom: return -ENOMEM; } +static void *qdio_mempool_alloc(gfp_t gfp_mask, void *size) +{ + return (void *) get_zeroed_page(gfp_mask|GFP_DMA); +} + +static void qdio_mempool_free(void *element, void *size) +{ + free_page((unsigned long) element); +} + static int __init init_QDIO(void) { @@ -3809,6 +3822,10 @@ init_QDIO(void) qdio_add_procfs_entry(); + qdio_mempool_scssc = mempool_create(QDIO_MEMPOOL_SCSSC_ELEMENTS, + qdio_mempool_alloc, + qdio_mempool_free, NULL); + if (tiqdio_check_chsc_availability()) QDIO_PRINT_ERR("Not all CHSCs supported. Continuing.\n"); @@ -3824,6 +3841,7 @@ cleanup_QDIO(void) qdio_remove_procfs_entry(); qdio_release_qdio_memory(); qdio_unregister_dbf_views(); + mempool_destroy(qdio_mempool_scssc); printk("qdio: %s: module removed\n",version); } diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c index b3c6e790779..cb14642d97a 100644 --- a/drivers/s390/net/qeth_main.c +++ b/drivers/s390/net/qeth_main.c @@ -8014,7 +8014,6 @@ static int (*qeth_old_arp_constructor) (struct neighbour *); static struct neigh_ops arp_direct_ops_template = { .family = AF_INET, - .destructor = NULL, .solicit = NULL, .error_report = NULL, .output = dev_queue_xmit, diff --git a/drivers/s390/s390mach.c b/drivers/s390/s390mach.c index 3bf46660351..f99e55308b3 100644 --- a/drivers/s390/s390mach.c +++ b/drivers/s390/s390mach.c @@ -13,6 +13,7 @@ #include <linux/sched.h> #include <linux/errno.h> #include <linux/workqueue.h> +#include <linux/time.h> #include <asm/lowcore.h> @@ -362,12 +363,19 @@ s390_revalidate_registers(struct mci *mci) return kill_task; } +#define MAX_IPD_COUNT 29 +#define MAX_IPD_TIME (5 * 60 * USEC_PER_SEC) /* 5 minutes */ + /* * machine check handler. */ void s390_do_machine_check(struct pt_regs *regs) { + static DEFINE_SPINLOCK(ipd_lock); + static unsigned long long last_ipd; + static int ipd_count; + unsigned long long tmp; struct mci *mci; struct mcck_struct *mcck; int umode; @@ -404,11 +412,27 @@ s390_do_machine_check(struct pt_regs *regs) s390_handle_damage("processing backup machine " "check with damage."); } - if (!umode) - s390_handle_damage("processing backup machine " - "check in kernel mode."); - mcck->kill_task = 1; - mcck->mcck_code = *(unsigned long long *) mci; + + /* + * Nullifying exigent condition, therefore we might + * retry this instruction. + */ + + spin_lock(&ipd_lock); + + tmp = get_clock(); + + if (((tmp - last_ipd) >> 12) < MAX_IPD_TIME) + ipd_count++; + else + ipd_count = 1; + + last_ipd = tmp; + + if (ipd_count == MAX_IPD_COUNT) + s390_handle_damage("too many ipd retries."); + + spin_unlock(&ipd_lock); } else { /* Processing damage -> stopping machine */ diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 3e7302692db..a480a3742d4 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -446,7 +446,9 @@ config SCSI_DPT_I2O config SCSI_ADVANSYS tristate "AdvanSys SCSI support" - depends on (ISA || EISA || PCI) && SCSI && BROKEN + depends on SCSI + depends on ISA || EISA || PCI + depends on BROKEN || X86_32 help This is a driver for all SCSI host adapters manufactured by AdvanSys. It is documented in the kernel source in diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c index 28b93057b60..2a419634b25 100644 --- a/drivers/scsi/advansys.c +++ b/drivers/scsi/advansys.c @@ -2051,7 +2051,7 @@ STATIC ASC_DCNT AscGetMaxDmaCount(ushort); #define ADV_VADDR_TO_U32 virt_to_bus #define ADV_U32_TO_VADDR bus_to_virt -#define AdvPortAddr ulong /* Virtual memory address size */ +#define AdvPortAddr void __iomem * /* Virtual memory address size */ /* * Define Adv Library required memory access macros. diff --git a/drivers/serial/cpm_uart/cpm_uart.h b/drivers/serial/cpm_uart/cpm_uart.h index 73c8a088c16..3b35cb77953 100644 --- a/drivers/serial/cpm_uart/cpm_uart.h +++ b/drivers/serial/cpm_uart/cpm_uart.h @@ -5,11 +5,20 @@ * * Copyright (C) 2004 Freescale Semiconductor, Inc. * + * 2006 (c) MontaVista Software, Inc. + * Vitaly Bordug <vbordug@ru.mvista.com> + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + * */ #ifndef CPM_UART_H #define CPM_UART_H #include <linux/config.h> +#include <linux/platform_device.h> +#include <linux/fs_uart_pd.h> #if defined(CONFIG_CPM2) #include "cpm_uart_cpm2.h" @@ -26,14 +35,14 @@ #define FLAG_SMC 0x00000002 #define FLAG_CONSOLE 0x00000001 -#define UART_SMC1 0 -#define UART_SMC2 1 -#define UART_SCC1 2 -#define UART_SCC2 3 -#define UART_SCC3 4 -#define UART_SCC4 5 +#define UART_SMC1 fsid_smc1_uart +#define UART_SMC2 fsid_smc2_uart +#define UART_SCC1 fsid_scc1_uart +#define UART_SCC2 fsid_scc2_uart +#define UART_SCC3 fsid_scc3_uart +#define UART_SCC4 fsid_scc4_uart -#define UART_NR 6 +#define UART_NR fs_uart_nr #define RX_NUM_FIFO 4 #define RX_BUF_SIZE 32 @@ -64,6 +73,7 @@ struct uart_cpm_port { uint dp_addr; void *mem_addr; dma_addr_t dma_addr; + u32 mem_size; /* helpers */ int baud; int bits; @@ -90,4 +100,38 @@ void scc2_lineif(struct uart_cpm_port *pinfo); void scc3_lineif(struct uart_cpm_port *pinfo); void scc4_lineif(struct uart_cpm_port *pinfo); +/* + virtual to phys transtalion +*/ +static inline unsigned long cpu2cpm_addr(void* addr, struct uart_cpm_port *pinfo) +{ + int offset; + u32 val = (u32)addr; + /* sane check */ + if (likely((val >= (u32)pinfo->mem_addr)) && + (val<((u32)pinfo->mem_addr + pinfo->mem_size))) { + offset = val - (u32)pinfo->mem_addr; + return pinfo->dma_addr+offset; + } + /* something nasty happened */ + BUG(); + return 0; +} + +static inline void *cpm2cpu_addr(unsigned long addr, struct uart_cpm_port *pinfo) +{ + int offset; + u32 val = addr; + /* sane check */ + if (likely((val >= pinfo->dma_addr) && + (val<(pinfo->dma_addr + pinfo->mem_size)))) { + offset = val - (u32)pinfo->dma_addr; + return (void*)(pinfo->mem_addr+offset); + } + /* something nasty happened */ + BUG(); + return 0; +} + + #endif /* CPM_UART_H */ diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c index b7bf4c698a4..969f9490043 100644 --- a/drivers/serial/cpm_uart/cpm_uart_core.c +++ b/drivers/serial/cpm_uart/cpm_uart_core.c @@ -12,7 +12,8 @@ * * Copyright (C) 2004 Freescale Semiconductor, Inc. * (C) 2004 Intracom, S.A. - * (C) 2005 MontaVista Software, Inc. by Vitaly Bordug <vbordug@ru.mvista.com> + * (C) 2005-2006 MontaVista Software, Inc. + * Vitaly Bordug <vbordug@ru.mvista.com> * * 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 @@ -41,6 +42,7 @@ #include <linux/device.h> #include <linux/bootmem.h> #include <linux/dma-mapping.h> +#include <linux/fs_uart_pd.h> #include <asm/io.h> #include <asm/irq.h> @@ -60,7 +62,7 @@ /* Track which ports are configured as uarts */ int cpm_uart_port_map[UART_NR]; /* How many ports did we config as uarts */ -int cpm_uart_nr; +int cpm_uart_nr = 0; /**************************************************************/ @@ -71,18 +73,51 @@ static void cpm_uart_initbd(struct uart_cpm_port *pinfo); /**************************************************************/ -static inline unsigned long cpu2cpm_addr(void *addr) + +/* Place-holder for board-specific stuff */ +struct platform_device* __attribute__ ((weak)) __init +early_uart_get_pdev(int index) +{ + return NULL; +} + + +static void cpm_uart_count(void) { - if ((unsigned long)addr >= CPM_ADDR) - return (unsigned long)addr; - return virt_to_bus(addr); + cpm_uart_nr = 0; +#ifdef CONFIG_SERIAL_CPM_SMC1 + cpm_uart_port_map[cpm_uart_nr++] = UART_SMC1; +#endif +#ifdef CONFIG_SERIAL_CPM_SMC2 + cpm_uart_port_map[cpm_uart_nr++] = UART_SMC2; +#endif +#ifdef CONFIG_SERIAL_CPM_SCC1 + cpm_uart_port_map[cpm_uart_nr++] = UART_SCC1; +#endif +#ifdef CONFIG_SERIAL_CPM_SCC2 + cpm_uart_port_map[cpm_uart_nr++] = UART_SCC2; +#endif +#ifdef CONFIG_SERIAL_CPM_SCC3 + cpm_uart_port_map[cpm_uart_nr++] = UART_SCC3; +#endif +#ifdef CONFIG_SERIAL_CPM_SCC4 + cpm_uart_port_map[cpm_uart_nr++] = UART_SCC4; +#endif } -static inline void *cpm2cpu_addr(unsigned long addr) +/* Get UART number by its id */ +static int cpm_uart_id2nr(int id) { - if (addr >= CPM_ADDR) - return (void *)addr; - return bus_to_virt(addr); + int i; + if (id < UART_NR) { + for (i=0; i<UART_NR; i++) { + if (cpm_uart_port_map[i] == id) + return i; + } + } + + /* not found or invalid argument */ + return -1; } /* @@ -258,7 +293,7 @@ static void cpm_uart_int_rx(struct uart_port *port, struct pt_regs *regs) } /* get pointer */ - cp = cpm2cpu_addr(bdp->cbd_bufaddr); + cp = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo); /* loop through the buffer */ while (i-- > 0) { @@ -438,7 +473,11 @@ static void cpm_uart_shutdown(struct uart_port *port) } /* Shut them really down and reinit buffer descriptors */ - cpm_line_cr_cmd(line, CPM_CR_STOP_TX); + if (IS_SMC(pinfo)) + cpm_line_cr_cmd(line, CPM_CR_STOP_TX); + else + cpm_line_cr_cmd(line, CPM_CR_GRA_STOP_TX); + cpm_uart_initbd(pinfo); } } @@ -601,7 +640,7 @@ static int cpm_uart_tx_pump(struct uart_port *port) /* Pick next descriptor and fill from buffer */ bdp = pinfo->tx_cur; - p = cpm2cpu_addr(bdp->cbd_bufaddr); + p = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo); *p++ = port->x_char; bdp->cbd_datlen = 1; @@ -628,7 +667,7 @@ static int cpm_uart_tx_pump(struct uart_port *port) while (!(bdp->cbd_sc & BD_SC_READY) && (xmit->tail != xmit->head)) { count = 0; - p = cpm2cpu_addr(bdp->cbd_bufaddr); + p = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo); while (count < pinfo->tx_fifosize) { *p++ = xmit->buf[xmit->tail]; xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); @@ -677,12 +716,12 @@ static void cpm_uart_initbd(struct uart_cpm_port *pinfo) mem_addr = pinfo->mem_addr; bdp = pinfo->rx_cur = pinfo->rx_bd_base; for (i = 0; i < (pinfo->rx_nrfifos - 1); i++, bdp++) { - bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr); + bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr, pinfo); bdp->cbd_sc = BD_SC_EMPTY | BD_SC_INTRPT; mem_addr += pinfo->rx_fifosize; } - bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr); + bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr, pinfo); bdp->cbd_sc = BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT; /* Set the physical address of the host memory @@ -692,12 +731,12 @@ static void cpm_uart_initbd(struct uart_cpm_port *pinfo) mem_addr = pinfo->mem_addr + L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize); bdp = pinfo->tx_cur = pinfo->tx_bd_base; for (i = 0; i < (pinfo->tx_nrfifos - 1); i++, bdp++) { - bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr); + bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr, pinfo); bdp->cbd_sc = BD_SC_INTRPT; mem_addr += pinfo->tx_fifosize; } - bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr); + bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr, pinfo); bdp->cbd_sc = BD_SC_WRAP | BD_SC_INTRPT; } @@ -829,14 +868,6 @@ static int cpm_uart_request_port(struct uart_port *port) if (pinfo->flags & FLAG_CONSOLE) return 0; - /* - * Setup any port IO, connect any baud rate generators, - * etc. This is expected to be handled by board - * dependant code - */ - if (pinfo->set_lineif) - pinfo->set_lineif(pinfo); - if (IS_SMC(pinfo)) { pinfo->smcp->smc_smcm &= ~(SMCM_RX | SMCM_TX); pinfo->smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); @@ -988,6 +1019,58 @@ struct uart_cpm_port cpm_uart_ports[UART_NR] = { }, }; +int cpm_uart_drv_get_platform_data(struct platform_device *pdev, int is_con) +{ + struct resource *r; + struct fs_uart_platform_info *pdata = pdev->dev.platform_data; + int idx = pdata->fs_no; /* It is UART_SMCx or UART_SCCx index */ + struct uart_cpm_port *pinfo; + int line; + u32 mem, pram; + + line = cpm_uart_id2nr(idx); + if(line < 0) { + printk(KERN_ERR"%s(): port %d is not registered", __FUNCTION__, idx); + return -1; + } + + pinfo = (struct uart_cpm_port *) &cpm_uart_ports[idx]; + + pinfo->brg = pdata->brg; + + if (!is_con) { + pinfo->port.line = line; + pinfo->port.flags = UPF_BOOT_AUTOCONF; + } + + if (!(r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs"))) + return -EINVAL; + mem = r->start; + + if (!(r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pram"))) + return -EINVAL; + pram = r->start; + + if(idx > fsid_smc2_uart) { + pinfo->sccp = (scc_t *)mem; + pinfo->sccup = (scc_uart_t *)pram; + } else { + pinfo->smcp = (smc_t *)mem; + pinfo->smcup = (smc_uart_t *)pram; + } + pinfo->tx_nrfifos = pdata->tx_num_fifo; + pinfo->tx_fifosize = pdata->tx_buf_size; + + pinfo->rx_nrfifos = pdata->rx_num_fifo; + pinfo->rx_fifosize = pdata->rx_buf_size; + + pinfo->port.uartclk = pdata->uart_clk; + pinfo->port.mapbase = (unsigned long)mem; + pinfo->port.irq = platform_get_irq(pdev, 0); + + return 0; +} + #ifdef CONFIG_SERIAL_CPM_CONSOLE /* * Print a string to the serial port trying not to disturb @@ -1027,7 +1110,7 @@ static void cpm_uart_console_write(struct console *co, const char *s, * If the buffer address is in the CPM DPRAM, don't * convert it. */ - cp = cpm2cpu_addr(bdp->cbd_bufaddr); + cp = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo); *cp = *s; @@ -1044,7 +1127,7 @@ static void cpm_uart_console_write(struct console *co, const char *s, while ((bdp->cbd_sc & BD_SC_READY) != 0) ; - cp = cpm2cpu_addr(bdp->cbd_bufaddr); + cp = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo); *cp = 13; bdp->cbd_datlen = 1; @@ -1067,9 +1150,7 @@ static void cpm_uart_console_write(struct console *co, const char *s, pinfo->tx_cur = (volatile cbd_t *) bdp; } -/* - * Setup console. Be careful is called early ! - */ + static int __init cpm_uart_console_setup(struct console *co, char *options) { struct uart_port *port; @@ -1080,9 +1161,27 @@ static int __init cpm_uart_console_setup(struct console *co, char *options) int flow = 'n'; int ret; + struct fs_uart_platform_info *pdata; + struct platform_device* pdev = early_uart_get_pdev(co->index); + port = (struct uart_port *)&cpm_uart_ports[cpm_uart_port_map[co->index]]; pinfo = (struct uart_cpm_port *)port; + if (!pdev) { + pr_info("cpm_uart: console: compat mode\n"); + /* compatibility - will be cleaned up */ + cpm_uart_init_portdesc(); + + if (pinfo->set_lineif) + pinfo->set_lineif(pinfo); + } else { + pdata = pdev->dev.platform_data; + if (pdata) + if (pdata->init_ioports) + pdata->init_ioports(); + + cpm_uart_drv_get_platform_data(pdev, 1); + } pinfo->flags |= FLAG_CONSOLE; @@ -1097,14 +1196,6 @@ static int __init cpm_uart_console_setup(struct console *co, char *options) baud = 9600; } - /* - * Setup any port IO, connect any baud rate generators, - * etc. This is expected to be handled by board - * dependant code - */ - if (pinfo->set_lineif) - pinfo->set_lineif(pinfo); - if (IS_SMC(pinfo)) { pinfo->smcp->smc_smcm &= ~(SMCM_RX | SMCM_TX); pinfo->smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); @@ -1143,11 +1234,8 @@ static struct console cpm_scc_uart_console = { int __init cpm_uart_console_init(void) { - int ret = cpm_uart_init_portdesc(); - - if (!ret) - register_console(&cpm_scc_uart_console); - return ret; + register_console(&cpm_scc_uart_console); + return 0; } console_initcall(cpm_uart_console_init); @@ -1165,44 +1253,129 @@ static struct uart_driver cpm_reg = { .minor = SERIAL_CPM_MINOR, .cons = CPM_UART_CONSOLE, }; - -static int __init cpm_uart_init(void) +static int cpm_uart_drv_probe(struct device *dev) { - int ret, i; - - printk(KERN_INFO "Serial: CPM driver $Revision: 0.01 $\n"); + struct platform_device *pdev = to_platform_device(dev); + struct fs_uart_platform_info *pdata; + int ret = -ENODEV; -#ifndef CONFIG_SERIAL_CPM_CONSOLE - ret = cpm_uart_init_portdesc(); - if (ret) + if(!pdev) { + printk(KERN_ERR"CPM UART: platform data missing!\n"); return ret; -#endif + } - cpm_reg.nr = cpm_uart_nr; - ret = uart_register_driver(&cpm_reg); + pdata = pdev->dev.platform_data; + pr_debug("cpm_uart_drv_probe: Adding CPM UART %d\n", cpm_uart_id2nr(pdata->fs_no)); - if (ret) + if ((ret = cpm_uart_drv_get_platform_data(pdev, 0))) return ret; - for (i = 0; i < cpm_uart_nr; i++) { - int con = cpm_uart_port_map[i]; - cpm_uart_ports[con].port.line = i; - cpm_uart_ports[con].port.flags = UPF_BOOT_AUTOCONF; - uart_add_one_port(&cpm_reg, &cpm_uart_ports[con].port); - } + if (pdata->init_ioports) + pdata->init_ioports(); - return ret; + ret = uart_add_one_port(&cpm_reg, &cpm_uart_ports[pdata->fs_no].port); + + return ret; } -static void __exit cpm_uart_exit(void) +static int cpm_uart_drv_remove(struct device *dev) { + struct platform_device *pdev = to_platform_device(dev); + struct fs_uart_platform_info *pdata = pdev->dev.platform_data; + + pr_debug("cpm_uart_drv_remove: Removing CPM UART %d\n", + cpm_uart_id2nr(pdata->fs_no)); + + uart_remove_one_port(&cpm_reg, &cpm_uart_ports[pdata->fs_no].port); + return 0; +} + +static struct device_driver cpm_smc_uart_driver = { + .name = "fsl-cpm-smc:uart", + .bus = &platform_bus_type, + .probe = cpm_uart_drv_probe, + .remove = cpm_uart_drv_remove, +}; + +static struct device_driver cpm_scc_uart_driver = { + .name = "fsl-cpm-scc:uart", + .bus = &platform_bus_type, + .probe = cpm_uart_drv_probe, + .remove = cpm_uart_drv_remove, +}; + +/* + This is supposed to match uart devices on platform bus, + */ +static int match_is_uart (struct device* dev, void* data) +{ + struct platform_device* pdev = container_of(dev, struct platform_device, dev); + int ret = 0; + /* this was setfunc as uart */ + if(strstr(pdev->name,":uart")) { + ret = 1; + } + return ret; +} + + +static int cpm_uart_init(void) { + + int ret; int i; + struct device *dev; + printk(KERN_INFO "Serial: CPM driver $Revision: 0.02 $\n"); + + /* lookup the bus for uart devices */ + dev = bus_find_device(&platform_bus_type, NULL, 0, match_is_uart); + + /* There are devices on the bus - all should be OK */ + if (dev) { + cpm_uart_count(); + cpm_reg.nr = cpm_uart_nr; + + if (!(ret = uart_register_driver(&cpm_reg))) { + if ((ret = driver_register(&cpm_smc_uart_driver))) { + uart_unregister_driver(&cpm_reg); + return ret; + } + if ((ret = driver_register(&cpm_scc_uart_driver))) { + driver_unregister(&cpm_scc_uart_driver); + uart_unregister_driver(&cpm_reg); + } + } + } else { + /* No capable platform devices found - falling back to legacy mode */ + pr_info("cpm_uart: WARNING: no UART devices found on platform bus!\n"); + pr_info( + "cpm_uart: the driver will guess configuration, but this mode is no longer supported.\n"); +#ifndef CONFIG_SERIAL_CPM_CONSOLE + ret = cpm_uart_init_portdesc(); + if (ret) + return ret; +#endif + + cpm_reg.nr = cpm_uart_nr; + ret = uart_register_driver(&cpm_reg); + + if (ret) + return ret; + + for (i = 0; i < cpm_uart_nr; i++) { + int con = cpm_uart_port_map[i]; + cpm_uart_ports[con].port.line = i; + cpm_uart_ports[con].port.flags = UPF_BOOT_AUTOCONF; + uart_add_one_port(&cpm_reg, &cpm_uart_ports[con].port); + } - for (i = 0; i < cpm_uart_nr; i++) { - int con = cpm_uart_port_map[i]; - uart_remove_one_port(&cpm_reg, &cpm_uart_ports[con].port); } + return ret; +} +static void __exit cpm_uart_exit(void) +{ + driver_unregister(&cpm_scc_uart_driver); + driver_unregister(&cpm_smc_uart_driver); uart_unregister_driver(&cpm_reg); } diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.c b/drivers/serial/cpm_uart/cpm_uart_cpm1.c index d789ee55cbb..17406a05ce1 100644 --- a/drivers/serial/cpm_uart/cpm_uart_cpm1.c +++ b/drivers/serial/cpm_uart/cpm_uart_cpm1.c @@ -8,6 +8,8 @@ * * Copyright (C) 2004 Freescale Semiconductor, Inc. * (C) 2004 Intracom, S.A. + * (C) 2006 MontaVista Software, Inc. + * Vitaly Bordug <vbordug@ru.mvista.com> * * 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 @@ -81,58 +83,11 @@ void cpm_line_cr_cmd(int line, int cmd) void smc1_lineif(struct uart_cpm_port *pinfo) { - volatile cpm8xx_t *cp = cpmp; - - (void)cp; /* fix warning */ -#if defined (CONFIG_MPC885ADS) - /* Enable SMC1 transceivers */ - { - cp->cp_pepar |= 0x000000c0; - cp->cp_pedir &= ~0x000000c0; - cp->cp_peso &= ~0x00000040; - cp->cp_peso |= 0x00000080; - } -#elif defined (CONFIG_MPC86XADS) - unsigned int iobits = 0x000000c0; - - if (!pinfo->is_portb) { - cp->cp_pbpar |= iobits; - cp->cp_pbdir &= ~iobits; - cp->cp_pbodr &= ~iobits; - } else { - ((immap_t *)IMAP_ADDR)->im_ioport.iop_papar |= iobits; - ((immap_t *)IMAP_ADDR)->im_ioport.iop_padir &= ~iobits; - ((immap_t *)IMAP_ADDR)->im_ioport.iop_paodr &= ~iobits; - } -#endif pinfo->brg = 1; } void smc2_lineif(struct uart_cpm_port *pinfo) { - volatile cpm8xx_t *cp = cpmp; - - (void)cp; /* fix warning */ -#if defined (CONFIG_MPC885ADS) - cp->cp_pepar |= 0x00000c00; - cp->cp_pedir &= ~0x00000c00; - cp->cp_peso &= ~0x00000400; - cp->cp_peso |= 0x00000800; -#elif defined (CONFIG_MPC86XADS) - unsigned int iobits = 0x00000c00; - - if (!pinfo->is_portb) { - cp->cp_pbpar |= iobits; - cp->cp_pbdir &= ~iobits; - cp->cp_pbodr &= ~iobits; - } else { - ((immap_t *)IMAP_ADDR)->im_ioport.iop_papar |= iobits; - ((immap_t *)IMAP_ADDR)->im_ioport.iop_padir &= ~iobits; - ((immap_t *)IMAP_ADDR)->im_ioport.iop_paodr &= ~iobits; - } - -#endif - pinfo->brg = 2; } @@ -191,7 +146,7 @@ int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con) /* was hostalloc but changed cause it blows away the */ /* large tlb mapping when pinning the kernel area */ mem_addr = (u8 *) cpm_dpram_addr(cpm_dpalloc(memsz, 8)); - dma_addr = 0; + dma_addr = (u32)mem_addr; } else mem_addr = dma_alloc_coherent(NULL, memsz, &dma_addr, GFP_KERNEL); @@ -204,8 +159,9 @@ int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con) } pinfo->dp_addr = dp_offset; - pinfo->mem_addr = mem_addr; - pinfo->dma_addr = dma_addr; + pinfo->mem_addr = mem_addr; /* virtual address*/ + pinfo->dma_addr = dma_addr; /* physical address*/ + pinfo->mem_size = memsz; pinfo->rx_buf = mem_addr; pinfo->tx_buf = pinfo->rx_buf + L1_CACHE_ALIGN(pinfo->rx_nrfifos diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.c b/drivers/serial/cpm_uart/cpm_uart_cpm2.c index fd9e53ed3fe..4b2de08f46d 100644 --- a/drivers/serial/cpm_uart/cpm_uart_cpm2.c +++ b/drivers/serial/cpm_uart/cpm_uart_cpm2.c @@ -8,6 +8,8 @@ * * Copyright (C) 2004 Freescale Semiconductor, Inc. * (C) 2004 Intracom, S.A. + * (C) 2006 MontaVista Software, Inc. + * Vitaly Bordug <vbordug@ru.mvista.com> * * 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 @@ -142,14 +144,6 @@ void scc2_lineif(struct uart_cpm_port *pinfo) * be supported in a sane fashion. */ #ifndef CONFIG_STX_GP3 -#ifdef CONFIG_MPC8560_ADS - volatile iop_cpm2_t *io = &cpm2_immr->im_ioport; - io->iop_ppard |= 0x00000018; - io->iop_psord &= ~0x00000008; /* Rx */ - io->iop_psord &= ~0x00000010; /* Tx */ - io->iop_pdird &= ~0x00000008; /* Rx */ - io->iop_pdird |= 0x00000010; /* Tx */ -#else volatile iop_cpm2_t *io = &cpm2_immr->im_ioport; io->iop_pparb |= 0x008b0000; io->iop_pdirb |= 0x00880000; @@ -157,7 +151,6 @@ void scc2_lineif(struct uart_cpm_port *pinfo) io->iop_pdirb &= ~0x00030000; io->iop_psorb &= ~0x00030000; #endif -#endif cpm2_immr->im_cpmux.cmx_scr &= 0xff00ffff; cpm2_immr->im_cpmux.cmx_scr |= 0x00090000; pinfo->brg = 2; @@ -218,8 +211,10 @@ int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con) memsz = L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize) + L1_CACHE_ALIGN(pinfo->tx_nrfifos * pinfo->tx_fifosize); - if (is_con) + if (is_con) { mem_addr = alloc_bootmem(memsz); + dma_addr = mem_addr; + } else mem_addr = dma_alloc_coherent(NULL, memsz, &dma_addr, GFP_KERNEL); @@ -234,6 +229,7 @@ int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con) pinfo->dp_addr = dp_offset; pinfo->mem_addr = mem_addr; pinfo->dma_addr = dma_addr; + pinfo->mem_size = memsz; pinfo->rx_buf = mem_addr; pinfo->tx_buf = pinfo->rx_buf + L1_CACHE_ALIGN(pinfo->rx_nrfifos diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c index c3b7a6673e9..d202eb4f384 100644 --- a/drivers/serial/imx.c +++ b/drivers/serial/imx.c @@ -45,6 +45,7 @@ #include <asm/io.h> #include <asm/irq.h> #include <asm/hardware.h> +#include <asm/arch/imx-uart.h> /* We've been assigned a range on the "Low-density serial ports" major */ #define SERIAL_IMX_MAJOR 204 @@ -73,7 +74,8 @@ struct imx_port { struct uart_port port; struct timer_list timer; unsigned int old_status; - int txirq,rxirq,rtsirq; + int txirq,rxirq,rtsirq; + int have_rtscts:1; }; /* @@ -491,8 +493,12 @@ imx_set_termios(struct uart_port *port, struct termios *termios, ucr2 = UCR2_SRST | UCR2_IRTS; if (termios->c_cflag & CRTSCTS) { - ucr2 &= ~UCR2_IRTS; - ucr2 |= UCR2_CTSC; + if( sport->have_rtscts ) { + ucr2 &= ~UCR2_IRTS; + ucr2 |= UCR2_CTSC; + } else { + termios->c_cflag &= ~CRTSCTS; + } } if (termios->c_cflag & CSTOPB) @@ -719,27 +725,6 @@ static void __init imx_init_ports(void) imx_ports[i].timer.function = imx_timeout; imx_ports[i].timer.data = (unsigned long)&imx_ports[i]; } - - imx_gpio_mode(PC9_PF_UART1_CTS); - imx_gpio_mode(PC10_PF_UART1_RTS); - imx_gpio_mode(PC11_PF_UART1_TXD); - imx_gpio_mode(PC12_PF_UART1_RXD); - imx_gpio_mode(PB28_PF_UART2_CTS); - imx_gpio_mode(PB29_PF_UART2_RTS); - - imx_gpio_mode(PB30_PF_UART2_TXD); - imx_gpio_mode(PB31_PF_UART2_RXD); - -#if 0 /* We don't need these, on the mx1 the _modem_ side of the uart - * is implemented. - */ - imx_gpio_mode(PD7_AF_UART2_DTR); - imx_gpio_mode(PD8_AF_UART2_DCD); - imx_gpio_mode(PD9_AF_UART2_RI); - imx_gpio_mode(PD10_AF_UART2_DSR); -#endif - - } #ifdef CONFIG_SERIAL_IMX_CONSOLE @@ -932,7 +917,14 @@ static int serial_imx_resume(struct platform_device *dev) static int serial_imx_probe(struct platform_device *dev) { + struct imxuart_platform_data *pdata; + imx_ports[dev->id].port.dev = &dev->dev; + + pdata = (struct imxuart_platform_data *)dev->dev.platform_data; + if(pdata && (pdata->flags & IMXUART_HAVE_RTSCTS)) + imx_ports[dev->id].have_rtscts = 1; + uart_add_one_port(&imx_reg, &imx_ports[dev->id].port); platform_set_drvdata(dev, &imx_ports[dev->id]); return 0; diff --git a/drivers/sn/ioc3.c b/drivers/sn/ioc3.c index 0b49ff78efc..501316b198e 100644 --- a/drivers/sn/ioc3.c +++ b/drivers/sn/ioc3.c @@ -678,7 +678,7 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) /* Track PCI-device specific data */ pci_set_drvdata(pdev, idd); down_write(&ioc3_devices_rwsem); - list_add(&idd->list, &ioc3_devices); + list_add_tail(&idd->list, &ioc3_devices); idd->id = ioc3_counter++; up_write(&ioc3_devices_rwsem); diff --git a/drivers/sn/ioc4.c b/drivers/sn/ioc4.c index 67140a5804f..cdeff909403 100644 --- a/drivers/sn/ioc4.c +++ b/drivers/sn/ioc4.c @@ -310,7 +310,7 @@ ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) pci_set_drvdata(idd->idd_pdev, idd); mutex_lock(&ioc4_mutex); - list_add(&idd->idd_list, &ioc4_devices); + list_add_tail(&idd->idd_list, &ioc4_devices); /* Add this IOC4 to all submodules */ list_for_each_entry(is, &ioc4_submodules, is_list) { diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index 42b457030b0..0eb010a3f5b 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -1614,6 +1614,7 @@ static int activate_ep_files (struct dev_data *dev) data, &ep_config_operations, &data->dentry); if (!data->inode) { + usb_ep_free_request(ep, data->req); kfree (data); goto enomem; } diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index 6a4b93ad108..0b929349395 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -2166,7 +2166,7 @@ static void handle_ep_small (struct net2280_ep *ep) ep->stopped = 1; set_halt (ep); mode = 2; - } else if (!req && ep->stopped) + } else if (!req && !ep->stopped) write_fifo (ep, NULL); } } else { @@ -2280,9 +2280,7 @@ static void handle_ep_small (struct net2280_ep *ep) /* if we wrote it all, we're usually done */ if (req->req.actual == req->req.length) { if (ep->num == 0) { - /* wait for control status */ - if (mode != 2) - req = NULL; + /* send zlps until the status stage */ } else if (!req->req.zero || len != ep->ep.maxpacket) mode = 2; } @@ -2744,6 +2742,10 @@ static irqreturn_t net2280_irq (int irq, void *_dev, struct pt_regs * r) { struct net2280 *dev = _dev; + /* shared interrupt, not ours */ + if (!(readl(&dev->regs->irqstat0) & (1 << INTA_ASSERTED))) + return IRQ_NONE; + spin_lock (&dev->lock); /* handle disconnect, dma, and more */ @@ -2831,13 +2833,13 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id) } /* alloc, and start init */ - dev = kmalloc (sizeof *dev, SLAB_KERNEL); + dev = kzalloc (sizeof *dev, SLAB_KERNEL); if (dev == NULL){ retval = -ENOMEM; goto done; } - memset (dev, 0, sizeof *dev); + pci_set_drvdata (pdev, dev); spin_lock_init (&dev->lock); dev->pdev = pdev; dev->gadget.ops = &net2280_ops; @@ -2950,7 +2952,6 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id) dev->chiprev = get_idx_reg (dev->regs, REG_CHIPREV) & 0xffff; /* done */ - pci_set_drvdata (pdev, dev); INFO (dev, "%s\n", driver_desc); INFO (dev, "irq %s, pci mem %p, chip rev %04x\n", bufp, base, dev->chiprev); diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index 1e03f1a5a5f..a1bd2bea6de 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -350,7 +350,7 @@ static const struct hc_driver ehci_pci_hc_driver = { /* PCI driver selection metadata; PCI hotplugging uses this */ static const struct pci_device_id pci_ids [] = { { /* handle any USB 2.0 EHCI controller */ - PCI_DEVICE_CLASS(((PCI_CLASS_SERIAL_USB << 8) | 0x20), ~0), + PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_EHCI, ~0), .driver_data = (unsigned long) &ehci_pci_hc_driver, }, { /* end: all zeroes */ } diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c index 1bfe96f4d04..b268537e389 100644 --- a/drivers/usb/host/ohci-pci.c +++ b/drivers/usb/host/ohci-pci.c @@ -206,7 +206,7 @@ static const struct hc_driver ohci_pci_hc_driver = { static const struct pci_device_id pci_ids [] = { { /* handle any USB OHCI controller */ - PCI_DEVICE_CLASS((PCI_CLASS_SERIAL_USB << 8) | 0x10, ~0), + PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_OHCI, ~0), .driver_data = (unsigned long) &ohci_pci_hc_driver, }, { /* end: all zeroes */ } }; diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index c0c4db78b59..d225e11f405 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -858,7 +858,7 @@ static const struct hc_driver uhci_driver = { static const struct pci_device_id uhci_pci_ids[] = { { /* handle any USB UHCI controller */ - PCI_DEVICE_CLASS(((PCI_CLASS_SERIAL_USB << 8) | 0x00), ~0), + PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_UHCI, ~0), .driver_data = (unsigned long) &uhci_driver, }, { /* end: all zeroes */ } }; diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index f5851db67f5..82151207d81 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -308,6 +308,7 @@ static struct ftdi_sio_quirk ftdi_HE_TIRA1_quirk = { static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_IRTRANS_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_IPLUS_PID) }, { USB_DEVICE(FTDI_VID, FTDI_SIO_PID) }, { USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) }, { USB_DEVICE(FTDI_VID, FTDI_8U232AM_ALT_PID) }, @@ -493,6 +494,8 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_WESTREX_MODEL_777_PID) }, { USB_DEVICE(FTDI_VID, FTDI_WESTREX_MODEL_8900F_PID) }, { USB_DEVICE(FTDI_VID, FTDI_PCDJ_DAC2_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_RRCIRKITS_LOCOBUFFER_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ASK_RDR400_PID) }, { USB_DEVICE(ICOM_ID1_VID, ICOM_ID1_PID) }, { USB_DEVICE(PAPOUCH_VID, PAPOUCH_TMU_PID) }, { }, /* Optional parameter entry */ diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index 2155f0e4a37..2c55a5ea9c9 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h @@ -39,6 +39,9 @@ /* www.thoughttechnology.com/ TT-USB provide with procomp use ftdi_sio */ #define FTDI_TTUSB_PID 0xFF20 /* Product Id */ +/* iPlus device */ +#define FTDI_IPLUS_PID 0xD070 /* Product Id */ + /* www.crystalfontz.com devices - thanx for providing free devices for evaluation ! */ /* they use the ftdi chipset for the USB interface and the vendor id is the same */ #define FTDI_XF_632_PID 0xFC08 /* 632: 16x2 Character Display */ @@ -153,6 +156,11 @@ #define ICOM_ID1_PID 0x0004 /* + * ASK.fr devices + */ +#define FTDI_ASK_RDR400_PID 0xC991 /* ASK RDR 400 series card reader */ + +/* * DSS-20 Sync Station for Sony Ericsson P800 */ @@ -400,6 +408,11 @@ #define FTDI_WESTREX_MODEL_8900F_PID 0xDC01 /* Model 8900F */ /* + * RR-CirKits LocoBuffer USB (http://www.rr-cirkits.com) + */ +#define FTDI_RRCIRKITS_LOCOBUFFER_PID 0xc7d0 /* LocoBuffer USB */ + +/* * Eclo (http://www.eclo.pt/) product IDs. * PID 0xEA90 submitted by Martin Grill. */ diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index ccf746b27d4..c96714bb1cb 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -61,6 +61,7 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) }, { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID_UCSGT) }, { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID) }, + { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID_2080) }, { USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) }, { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) }, { USB_DEVICE(TRIPP_VENDOR_ID, TRIPP_PRODUCT_ID) }, diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h index 09f379b19e9..7f29e81d3e3 100644 --- a/drivers/usb/serial/pl2303.h +++ b/drivers/usb/serial/pl2303.h @@ -26,6 +26,7 @@ #define ITEGNO_VENDOR_ID 0x0eba #define ITEGNO_PRODUCT_ID 0x1080 +#define ITEGNO_PRODUCT_ID_2080 0x2080 #define MA620_VENDOR_ID 0x0df7 #define MA620_PRODUCT_ID 0x0620 diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index 557411c6e7c..f806553cd9a 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@ -508,6 +508,7 @@ no_firmware: err("%s: Unable to retrieve firmware version, try replugging\n", serial->type->description); err("%s: If the firmware is not running (status led not blinking)\n", serial->type->description); err("%s: please contact support@connecttech.com\n", serial->type->description); + kfree(result); return -ENODEV; no_command_private: diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index c4a9dcff5f2..aec5ea8682d 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -411,7 +411,7 @@ UNUSUAL_DEV( 0x050d, 0x0115, 0x0133, 0x0133, UNUSUAL_DEV( 0x0525, 0xa140, 0x0100, 0x0100, "Iomega", "USB Clik! 40", - US_SC_8070, US_PR_BULK, NULL, + US_SC_8070, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY ), /* Yakumo Mega Image 37 @@ -773,6 +773,13 @@ UNUSUAL_DEV( 0x069b, 0x3004, 0x0001, 0x0001, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_CAPACITY ), +/* Reported by Olivier Blondeau <zeitoun@gmail.com> */ +UNUSUAL_DEV( 0x0727, 0x0306, 0x0100, 0x0100, + "ATMEL", + "SND1 Storage", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_IGNORE_RESIDUE), + /* Submitted by Roman Hodek <roman@hodek.net> */ UNUSUAL_DEV( 0x0781, 0x0001, 0x0200, 0x0200, "Sandisk", diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 9060e713744..4587087d777 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -400,6 +400,8 @@ config FB_ASILIANT select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT + help + This is the frame buffer device driver for the Asiliant 69030 chipset config FB_IMSTT bool "IMS Twin Turbo display support" diff --git a/drivers/video/au1200fb.c b/drivers/video/au1200fb.c index b367de30b98..600d3e0e08b 100644 --- a/drivers/video/au1200fb.c +++ b/drivers/video/au1200fb.c @@ -1920,1925 +1920,3 @@ module_exit(au1200fb_cleanup); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); -/* - * BRIEF MODULE DESCRIPTION - * Au1200 LCD Driver. - * - * Copyright 2004-2005 AMD - * Author: AMD - * - * Based on: - * linux/drivers/video/skeletonfb.c -- Skeleton for a frame buffer device - * Created 28 Dec 1997 by Geert Uytterhoeven - * - * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * 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., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/string.h> -#include <linux/mm.h> -#include <linux/fb.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/ctype.h> -#include <linux/dma-mapping.h> - -#include <asm/mach-au1x00/au1000.h> -#include "au1200fb.h" - -#ifdef CONFIG_PM -#include <asm/mach-au1x00/au1xxx_pm.h> -#endif - -#ifndef CONFIG_FB_AU1200_DEVS -#define CONFIG_FB_AU1200_DEVS 4 -#endif - -#define DRIVER_NAME "au1200fb" -#define DRIVER_DESC "LCD controller driver for AU1200 processors" - -#define DEBUG 1 - -#define print_err(f, arg...) printk(KERN_ERR DRIVER_NAME ": " f "\n", ## arg) -#define print_warn(f, arg...) printk(KERN_WARNING DRIVER_NAME ": " f "\n", ## arg) -#define print_info(f, arg...) printk(KERN_INFO DRIVER_NAME ": " f "\n", ## arg) - -#if DEBUG -#define print_dbg(f, arg...) printk(KERN_DEBUG __FILE__ ": " f "\n", ## arg) -#else -#define print_dbg(f, arg...) do {} while (0) -#endif - - -#define AU1200_LCD_FB_IOCTL 0x46FF - -#define AU1200_LCD_SET_SCREEN 1 -#define AU1200_LCD_GET_SCREEN 2 -#define AU1200_LCD_SET_WINDOW 3 -#define AU1200_LCD_GET_WINDOW 4 -#define AU1200_LCD_SET_PANEL 5 -#define AU1200_LCD_GET_PANEL 6 - -#define SCREEN_SIZE (1<< 1) -#define SCREEN_BACKCOLOR (1<< 2) -#define SCREEN_BRIGHTNESS (1<< 3) -#define SCREEN_COLORKEY (1<< 4) -#define SCREEN_MASK (1<< 5) - -struct au1200_lcd_global_regs_t { - unsigned int flags; - unsigned int xsize; - unsigned int ysize; - unsigned int backcolor; - unsigned int brightness; - unsigned int colorkey; - unsigned int mask; - unsigned int panel_choice; - char panel_desc[80]; - -}; - -#define WIN_POSITION (1<< 0) -#define WIN_ALPHA_COLOR (1<< 1) -#define WIN_ALPHA_MODE (1<< 2) -#define WIN_PRIORITY (1<< 3) -#define WIN_CHANNEL (1<< 4) -#define WIN_BUFFER_FORMAT (1<< 5) -#define WIN_COLOR_ORDER (1<< 6) -#define WIN_PIXEL_ORDER (1<< 7) -#define WIN_SIZE (1<< 8) -#define WIN_COLORKEY_MODE (1<< 9) -#define WIN_DOUBLE_BUFFER_MODE (1<< 10) -#define WIN_RAM_ARRAY_MODE (1<< 11) -#define WIN_BUFFER_SCALE (1<< 12) -#define WIN_ENABLE (1<< 13) - -struct au1200_lcd_window_regs_t { - unsigned int flags; - unsigned int xpos; - unsigned int ypos; - unsigned int alpha_color; - unsigned int alpha_mode; - unsigned int priority; - unsigned int channel; - unsigned int buffer_format; - unsigned int color_order; - unsigned int pixel_order; - unsigned int xsize; - unsigned int ysize; - unsigned int colorkey_mode; - unsigned int double_buffer_mode; - unsigned int ram_array_mode; - unsigned int xscale; - unsigned int yscale; - unsigned int enable; -}; - - -struct au1200_lcd_iodata_t { - unsigned int subcmd; - struct au1200_lcd_global_regs_t global; - struct au1200_lcd_window_regs_t window; -}; - -#if defined(__BIG_ENDIAN) -#define LCD_CONTROL_DEFAULT_PO LCD_CONTROL_PO_11 -#else -#define LCD_CONTROL_DEFAULT_PO LCD_CONTROL_PO_00 -#endif -#define LCD_CONTROL_DEFAULT_SBPPF LCD_CONTROL_SBPPF_565 - -/* Private, per-framebuffer management information (independent of the panel itself) */ -struct au1200fb_device { - struct fb_info fb_info; /* FB driver info record */ - - int plane; - unsigned char* fb_mem; /* FrameBuffer memory map */ - unsigned int fb_len; - dma_addr_t fb_phys; -}; - -static struct au1200fb_device _au1200fb_devices[CONFIG_FB_AU1200_DEVS]; -/********************************************************************/ - -/* LCD controller restrictions */ -#define AU1200_LCD_MAX_XRES 1280 -#define AU1200_LCD_MAX_YRES 1024 -#define AU1200_LCD_MAX_BPP 32 -#define AU1200_LCD_MAX_CLK 96000000 /* fixme: this needs to go away ? */ -#define AU1200_LCD_NBR_PALETTE_ENTRIES 256 - -/* Default number of visible screen buffer to allocate */ -#define AU1200FB_NBR_VIDEO_BUFFERS 1 - -/********************************************************************/ - -static struct au1200_lcd *lcd = (struct au1200_lcd *) AU1200_LCD_ADDR; -static int window_index = 2; /* default is zero */ -static int panel_index = 2; /* default is zero */ -static struct window_settings *win; -static struct panel_settings *panel; -static int noblanking = 1; -static int nohwcursor = 0; - -struct window_settings { - unsigned char name[64]; - uint32 mode_backcolor; - uint32 mode_colorkey; - uint32 mode_colorkeymsk; - struct { - int xres; - int yres; - int xpos; - int ypos; - uint32 mode_winctrl1; /* winctrl1[FRM,CCO,PO,PIPE] */ - uint32 mode_winenable; - } w[4]; -}; - -#if defined(__BIG_ENDIAN) -#define LCD_WINCTRL1_PO_16BPP LCD_WINCTRL1_PO_00 -#else -#define LCD_WINCTRL1_PO_16BPP LCD_WINCTRL1_PO_01 -#endif - -extern int board_au1200fb_panel_init (void); -extern int board_au1200fb_panel_shutdown (void); - -#ifdef CONFIG_PM -int au1200fb_pm_callback(au1xxx_power_dev_t *dev, - au1xxx_request_t request, void *data); -au1xxx_power_dev_t *LCD_pm_dev; -#endif - -/* - * Default window configurations - */ -static struct window_settings windows[] = { - { /* Index 0 */ - "0-FS gfx, 1-video, 2-ovly gfx, 3-ovly gfx", - /* mode_backcolor */ 0x006600ff, - /* mode_colorkey,msk*/ 0, 0, - { - { - /* xres, yres, xpos, ypos */ 0, 0, 0, 0, - /* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 | - LCD_WINCTRL1_PO_16BPP, - /* mode_winenable*/ LCD_WINENABLE_WEN0, - }, - { - /* xres, yres, xpos, ypos */ 100, 100, 100, 100, - /* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 | - LCD_WINCTRL1_PO_16BPP | - LCD_WINCTRL1_PIPE, - /* mode_winenable*/ LCD_WINENABLE_WEN1, - }, - { - /* xres, yres, xpos, ypos */ 0, 0, 0, 0, - /* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 | - LCD_WINCTRL1_PO_16BPP, - /* mode_winenable*/ 0, - }, - { - /* xres, yres, xpos, ypos */ 0, 0, 0, 0, - /* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 | - LCD_WINCTRL1_PO_16BPP | - LCD_WINCTRL1_PIPE, - /* mode_winenable*/ 0, - }, - }, - }, - - { /* Index 1 */ - "0-FS gfx, 1-video, 2-ovly gfx, 3-ovly gfx", - /* mode_backcolor */ 0x006600ff, - /* mode_colorkey,msk*/ 0, 0, - { - { - /* xres, yres, xpos, ypos */ 320, 240, 5, 5, - /* mode_winctrl1 */ LCD_WINCTRL1_FRM_24BPP | - LCD_WINCTRL1_PO_00, - /* mode_winenable*/ LCD_WINENABLE_WEN0, - }, - { - /* xres, yres, xpos, ypos */ 0, 0, 0, 0, - /* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 - | LCD_WINCTRL1_PO_16BPP, - /* mode_winenable*/ 0, - }, - { - /* xres, yres, xpos, ypos */ 100, 100, 0, 0, - /* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 | - LCD_WINCTRL1_PO_16BPP | - LCD_WINCTRL1_PIPE, - /* mode_winenable*/ 0/*LCD_WINENABLE_WEN2*/, - }, - { - /* xres, yres, xpos, ypos */ 200, 25, 0, 0, - /* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 | - LCD_WINCTRL1_PO_16BPP | - LCD_WINCTRL1_PIPE, - /* mode_winenable*/ 0, - }, - }, - }, - { /* Index 2 */ - "0-FS gfx, 1-video, 2-ovly gfx, 3-ovly gfx", - /* mode_backcolor */ 0x006600ff, - /* mode_colorkey,msk*/ 0, 0, - { - { - /* xres, yres, xpos, ypos */ 0, 0, 0, 0, - /* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 | - LCD_WINCTRL1_PO_16BPP, - /* mode_winenable*/ LCD_WINENABLE_WEN0, - }, - { - /* xres, yres, xpos, ypos */ 0, 0, 0, 0, - /* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 | - LCD_WINCTRL1_PO_16BPP, - /* mode_winenable*/ 0, - }, - { - /* xres, yres, xpos, ypos */ 0, 0, 0, 0, - /* mode_winctrl1 */ LCD_WINCTRL1_FRM_32BPP | - LCD_WINCTRL1_PO_00|LCD_WINCTRL1_PIPE, - /* mode_winenable*/ 0/*LCD_WINENABLE_WEN2*/, - }, - { - /* xres, yres, xpos, ypos */ 0, 0, 0, 0, - /* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 | - LCD_WINCTRL1_PO_16BPP | - LCD_WINCTRL1_PIPE, - /* mode_winenable*/ 0, - }, - }, - }, - /* Need VGA 640 @ 24bpp, @ 32bpp */ - /* Need VGA 800 @ 24bpp, @ 32bpp */ - /* Need VGA 1024 @ 24bpp, @ 32bpp */ -}; - -/* - * Controller configurations for various panels. - */ - -struct panel_settings -{ - const char name[25]; /* Full name <vendor>_<model> */ - - struct fb_monspecs monspecs; /* FB monitor specs */ - - /* panel timings */ - uint32 mode_screen; - uint32 mode_horztiming; - uint32 mode_verttiming; - uint32 mode_clkcontrol; - uint32 mode_pwmdiv; - uint32 mode_pwmhi; - uint32 mode_outmask; - uint32 mode_fifoctrl; - uint32 mode_toyclksrc; - uint32 mode_backlight; - uint32 mode_auxpll; - int (*device_init)(void); - int (*device_shutdown)(void); -#define Xres min_xres -#define Yres min_yres - u32 min_xres; /* Minimum horizontal resolution */ - u32 max_xres; /* Maximum horizontal resolution */ - u32 min_yres; /* Minimum vertical resolution */ - u32 max_yres; /* Maximum vertical resolution */ -}; - -/********************************************************************/ -/* fixme: Maybe a modedb for the CRT ? otherwise panels should be as-is */ - -/* List of panels known to work with the AU1200 LCD controller. - * To add a new panel, enter the same specifications as the - * Generic_TFT one, and MAKE SURE that it doesn't conflicts - * with the controller restrictions. Restrictions are: - * - * STN color panels: max_bpp <= 12 - * STN mono panels: max_bpp <= 4 - * TFT panels: max_bpp <= 16 - * max_xres <= 800 - * max_yres <= 600 - */ -static struct panel_settings known_lcd_panels[] = -{ - [0] = { /* QVGA 320x240 H:33.3kHz V:110Hz */ - .name = "QVGA_320x240", - .monspecs = { - .modedb = NULL, - .modedb_len = 0, - .hfmin = 30000, - .hfmax = 70000, - .vfmin = 60, - .vfmax = 60, - .dclkmin = 6000000, - .dclkmax = 28000000, - .input = FB_DISP_RGB, - }, - .mode_screen = LCD_SCREEN_SX_N(320) | - LCD_SCREEN_SY_N(240), - .mode_horztiming = 0x00c4623b, - .mode_verttiming = 0x00502814, - .mode_clkcontrol = 0x00020002, /* /4=24Mhz */ - .mode_pwmdiv = 0x00000000, - .mode_pwmhi = 0x00000000, - .mode_outmask = 0x00FFFFFF, - .mode_fifoctrl = 0x2f2f2f2f, - .mode_toyclksrc = 0x00000004, /* AUXPLL directly */ - .mode_backlight = 0x00000000, - .mode_auxpll = 8, /* 96MHz AUXPLL */ - .device_init = NULL, - .device_shutdown = NULL, - 320, 320, - 240, 240, - }, - - [1] = { /* VGA 640x480 H:30.3kHz V:58Hz */ - .name = "VGA_640x480", - .monspecs = { - .modedb = NULL, - .modedb_len = 0, - .hfmin = 30000, - .hfmax = 70000, - .vfmin = 60, - .vfmax = 60, - .dclkmin = 6000000, - .dclkmax = 28000000, - .input = FB_DISP_RGB, - }, - .mode_screen = 0x13f9df80, - .mode_horztiming = 0x003c5859, - .mode_verttiming = 0x00741201, - .mode_clkcontrol = 0x00020001, /* /4=24Mhz */ - .mode_pwmdiv = 0x00000000, - .mode_pwmhi = 0x00000000, - .mode_outmask = 0x00FFFFFF, - .mode_fifoctrl = 0x2f2f2f2f, - .mode_toyclksrc = 0x00000004, /* AUXPLL directly */ - .mode_backlight = 0x00000000, - .mode_auxpll = 8, /* 96MHz AUXPLL */ - .device_init = NULL, - .device_shutdown = NULL, - 640, 480, - 640, 480, - }, - - [2] = { /* SVGA 800x600 H:46.1kHz V:69Hz */ - .name = "SVGA_800x600", - .monspecs = { - .modedb = NULL, - .modedb_len = 0, - .hfmin = 30000, - .hfmax = 70000, - .vfmin = 60, - .vfmax = 60, - .dclkmin = 6000000, - .dclkmax = 28000000, - .input = FB_DISP_RGB, - }, - .mode_screen = 0x18fa5780, - .mode_horztiming = 0x00dc7e77, - .mode_verttiming = 0x00584805, - .mode_clkcontrol = 0x00020000, /* /2=48Mhz */ - .mode_pwmdiv = 0x00000000, - .mode_pwmhi = 0x00000000, - .mode_outmask = 0x00FFFFFF, - .mode_fifoctrl = 0x2f2f2f2f, - .mode_toyclksrc = 0x00000004, /* AUXPLL directly */ - .mode_backlight = 0x00000000, - .mode_auxpll = 8, /* 96MHz AUXPLL */ - .device_init = NULL, - .device_shutdown = NULL, - 800, 800, - 600, 600, - }, - - [3] = { /* XVGA 1024x768 H:56.2kHz V:70Hz */ - .name = "XVGA_1024x768", - .monspecs = { - .modedb = NULL, - .modedb_len = 0, - .hfmin = 30000, - .hfmax = 70000, - .vfmin = 60, - .vfmax = 60, - .dclkmin = 6000000, - .dclkmax = 28000000, - .input = FB_DISP_RGB, - }, - .mode_screen = 0x1ffaff80, - .mode_horztiming = 0x007d0e57, - .mode_verttiming = 0x00740a01, - .mode_clkcontrol = 0x000A0000, /* /1 */ - .mode_pwmdiv = 0x00000000, - .mode_pwmhi = 0x00000000, - .mode_outmask = 0x00FFFFFF, - .mode_fifoctrl = 0x2f2f2f2f, - .mode_toyclksrc = 0x00000004, /* AUXPLL directly */ - .mode_backlight = 0x00000000, - .mode_auxpll = 6, /* 72MHz AUXPLL */ - .device_init = NULL, - .device_shutdown = NULL, - 1024, 1024, - 768, 768, - }, - - [4] = { /* XVGA XVGA 1280x1024 H:68.5kHz V:65Hz */ - .name = "XVGA_1280x1024", - .monspecs = { - .modedb = NULL, - .modedb_len = 0, - .hfmin = 30000, - .hfmax = 70000, - .vfmin = 60, - .vfmax = 60, - .dclkmin = 6000000, - .dclkmax = 28000000, - .input = FB_DISP_RGB, - }, - .mode_screen = 0x27fbff80, - .mode_horztiming = 0x00cdb2c7, - .mode_verttiming = 0x00600002, - .mode_clkcontrol = 0x000A0000, /* /1 */ - .mode_pwmdiv = 0x00000000, - .mode_pwmhi = 0x00000000, - .mode_outmask = 0x00FFFFFF, - .mode_fifoctrl = 0x2f2f2f2f, - .mode_toyclksrc = 0x00000004, /* AUXPLL directly */ - .mode_backlight = 0x00000000, - .mode_auxpll = 10, /* 120MHz AUXPLL */ - .device_init = NULL, - .device_shutdown = NULL, - 1280, 1280, - 1024, 1024, - }, - - [5] = { /* Samsung 1024x768 TFT */ - .name = "Samsung_1024x768_TFT", - .monspecs = { - .modedb = NULL, - .modedb_len = 0, - .hfmin = 30000, - .hfmax = 70000, - .vfmin = 60, - .vfmax = 60, - .dclkmin = 6000000, - .dclkmax = 28000000, - .input = FB_DISP_RGB, - }, - .mode_screen = 0x1ffaff80, - .mode_horztiming = 0x018cc677, - .mode_verttiming = 0x00241217, - .mode_clkcontrol = 0x00000000, /* SCB 0x1 /4=24Mhz */ - .mode_pwmdiv = 0x8000063f, /* SCB 0x0 */ - .mode_pwmhi = 0x03400000, /* SCB 0x0 */ - .mode_outmask = 0x00FFFFFF, - .mode_fifoctrl = 0x2f2f2f2f, - .mode_toyclksrc = 0x00000004, /* AUXPLL directly */ - .mode_backlight = 0x00000000, - .mode_auxpll = 8, /* 96MHz AUXPLL */ - .device_init = board_au1200fb_panel_init, - .device_shutdown = board_au1200fb_panel_shutdown, - 1024, 1024, - 768, 768, - }, - - [6] = { /* Toshiba 640x480 TFT */ - .name = "Toshiba_640x480_TFT", - .monspecs = { - .modedb = NULL, - .modedb_len = 0, - .hfmin = 30000, - .hfmax = 70000, - .vfmin = 60, - .vfmax = 60, - .dclkmin = 6000000, - .dclkmax = 28000000, - .input = FB_DISP_RGB, - }, - .mode_screen = LCD_SCREEN_SX_N(640) | - LCD_SCREEN_SY_N(480), - .mode_horztiming = LCD_HORZTIMING_HPW_N(96) | - LCD_HORZTIMING_HND1_N(13) | LCD_HORZTIMING_HND2_N(51), - .mode_verttiming = LCD_VERTTIMING_VPW_N(2) | - LCD_VERTTIMING_VND1_N(11) | LCD_VERTTIMING_VND2_N(32), - .mode_clkcontrol = 0x00000000, /* /4=24Mhz */ - .mode_pwmdiv = 0x8000063f, - .mode_pwmhi = 0x03400000, - .mode_outmask = 0x00fcfcfc, - .mode_fifoctrl = 0x2f2f2f2f, - .mode_toyclksrc = 0x00000004, /* AUXPLL directly */ - .mode_backlight = 0x00000000, - .mode_auxpll = 8, /* 96MHz AUXPLL */ - .device_init = board_au1200fb_panel_init, - .device_shutdown = board_au1200fb_panel_shutdown, - 640, 480, - 640, 480, - }, - - [7] = { /* Sharp 320x240 TFT */ - .name = "Sharp_320x240_TFT", - .monspecs = { - .modedb = NULL, - .modedb_len = 0, - .hfmin = 12500, - .hfmax = 20000, - .vfmin = 38, - .vfmax = 81, - .dclkmin = 4500000, - .dclkmax = 6800000, - .input = FB_DISP_RGB, - }, - .mode_screen = LCD_SCREEN_SX_N(320) | - LCD_SCREEN_SY_N(240), - .mode_horztiming = LCD_HORZTIMING_HPW_N(60) | - LCD_HORZTIMING_HND1_N(13) | LCD_HORZTIMING_HND2_N(2), - .mode_verttiming = LCD_VERTTIMING_VPW_N(2) | - LCD_VERTTIMING_VND1_N(2) | LCD_VERTTIMING_VND2_N(5), - .mode_clkcontrol = LCD_CLKCONTROL_PCD_N(7), /*16=6Mhz*/ - .mode_pwmdiv = 0x8000063f, - .mode_pwmhi = 0x03400000, - .mode_outmask = 0x00fcfcfc, - .mode_fifoctrl = 0x2f2f2f2f, - .mode_toyclksrc = 0x00000004, /* AUXPLL directly */ - .mode_backlight = 0x00000000, - .mode_auxpll = 8, /* 96MHz AUXPLL */ - .device_init = board_au1200fb_panel_init, - .device_shutdown = board_au1200fb_panel_shutdown, - 320, 320, - 240, 240, - }, - - [8] = { /* Toppoly TD070WGCB2 7" 856x480 TFT */ - .name = "Toppoly_TD070WGCB2", - .monspecs = { - .modedb = NULL, - .modedb_len = 0, - .hfmin = 30000, - .hfmax = 70000, - .vfmin = 60, - .vfmax = 60, - .dclkmin = 6000000, - .dclkmax = 28000000, - .input = FB_DISP_RGB, - }, - .mode_screen = LCD_SCREEN_SX_N(856) | - LCD_SCREEN_SY_N(480), - .mode_horztiming = LCD_HORZTIMING_HND2_N(43) | - LCD_HORZTIMING_HND1_N(43) | LCD_HORZTIMING_HPW_N(114), - .mode_verttiming = LCD_VERTTIMING_VND2_N(20) | - LCD_VERTTIMING_VND1_N(21) | LCD_VERTTIMING_VPW_N(4), - .mode_clkcontrol = 0x00020001, /* /4=24Mhz */ - .mode_pwmdiv = 0x8000063f, - .mode_pwmhi = 0x03400000, - .mode_outmask = 0x00fcfcfc, - .mode_fifoctrl = 0x2f2f2f2f, - .mode_toyclksrc = 0x00000004, /* AUXPLL directly */ - .mode_backlight = 0x00000000, - .mode_auxpll = 8, /* 96MHz AUXPLL */ - .device_init = board_au1200fb_panel_init, - .device_shutdown = board_au1200fb_panel_shutdown, - 856, 856, - 480, 480, - }, -}; - -#define NUM_PANELS (ARRAY_SIZE(known_lcd_panels)) - -/********************************************************************/ - -#ifdef CONFIG_PM -static int set_brightness(unsigned int brightness) -{ - unsigned int hi1, divider; - - /* limit brightness pwm duty to >= 30/1600 */ - if (brightness < 30) { - brightness = 30; - } - divider = (lcd->pwmdiv & 0x3FFFF) + 1; - hi1 = (lcd->pwmhi >> 16) + 1; - hi1 = (((brightness & 0xFF) + 1) * divider >> 8); - lcd->pwmhi &= 0xFFFF; - lcd->pwmhi |= (hi1 << 16); - - return brightness; -} -#endif /* CONFIG_PM */ - -static int winbpp (unsigned int winctrl1) -{ - int bits = 0; - - /* how many bits are needed for each pixel format */ - switch (winctrl1 & LCD_WINCTRL1_FRM) { - case LCD_WINCTRL1_FRM_1BPP: - bits = 1; - break; - case LCD_WINCTRL1_FRM_2BPP: - bits = 2; - break; - case LCD_WINCTRL1_FRM_4BPP: - bits = 4; - break; - case LCD_WINCTRL1_FRM_8BPP: - bits = 8; - break; - case LCD_WINCTRL1_FRM_12BPP: - case LCD_WINCTRL1_FRM_16BPP655: - case LCD_WINCTRL1_FRM_16BPP565: - case LCD_WINCTRL1_FRM_16BPP556: - case LCD_WINCTRL1_FRM_16BPPI1555: - case LCD_WINCTRL1_FRM_16BPPI5551: - case LCD_WINCTRL1_FRM_16BPPA1555: - case LCD_WINCTRL1_FRM_16BPPA5551: - bits = 16; - break; - case LCD_WINCTRL1_FRM_24BPP: - case LCD_WINCTRL1_FRM_32BPP: - bits = 32; - break; - } - - return bits; -} - -static int fbinfo2index (struct fb_info *fb_info) -{ - int i; - - for (i = 0; i < CONFIG_FB_AU1200_DEVS; ++i) { - if (fb_info == (struct fb_info *)(&_au1200fb_devices[i].fb_info)) - return i; - } - printk("au1200fb: ERROR: fbinfo2index failed!\n"); - return -1; -} - -static int au1200_setlocation (struct au1200fb_device *fbdev, int plane, - int xpos, int ypos) -{ - uint32 winctrl0, winctrl1, winenable, fb_offset = 0; - int xsz, ysz; - - /* FIX!!! NOT CHECKING FOR COMPLETE OFFSCREEN YET */ - - winctrl0 = lcd->window[plane].winctrl0; - winctrl1 = lcd->window[plane].winctrl1; - winctrl0 &= (LCD_WINCTRL0_A | LCD_WINCTRL0_AEN); - winctrl1 &= ~(LCD_WINCTRL1_SZX | LCD_WINCTRL1_SZY); - - /* Check for off-screen adjustments */ - xsz = win->w[plane].xres; - ysz = win->w[plane].yres; - if ((xpos + win->w[plane].xres) > panel->Xres) { - /* Off-screen to the right */ - xsz = panel->Xres - xpos; /* off by 1 ??? */ - /*printk("off screen right\n");*/ - } - - if ((ypos + win->w[plane].yres) > panel->Yres) { - /* Off-screen to the bottom */ - ysz = panel->Yres - ypos; /* off by 1 ??? */ - /*printk("off screen bottom\n");*/ - } - - if (xpos < 0) { - /* Off-screen to the left */ - xsz = win->w[plane].xres + xpos; - fb_offset += (((0 - xpos) * winbpp(lcd->window[plane].winctrl1))/8); - xpos = 0; - /*printk("off screen left\n");*/ - } - - if (ypos < 0) { - /* Off-screen to the top */ - ysz = win->w[plane].yres + ypos; - /* fixme: fb_offset += ((0-ypos)*fb_pars[plane].line_length); */ - ypos = 0; - /*printk("off screen top\n");*/ - } - - /* record settings */ - win->w[plane].xpos = xpos; - win->w[plane].ypos = ypos; - - xsz -= 1; - ysz -= 1; - winctrl0 |= (xpos << 21); - winctrl0 |= (ypos << 10); - winctrl1 |= (xsz << 11); - winctrl1 |= (ysz << 0); - - /* Disable the window while making changes, then restore WINEN */ - winenable = lcd->winenable & (1 << plane); - au_sync(); - lcd->winenable &= ~(1 << plane); - lcd->window[plane].winctrl0 = winctrl0; - lcd->window[plane].winctrl1 = winctrl1; - lcd->window[plane].winbuf0 = - lcd->window[plane].winbuf1 = fbdev->fb_phys; - lcd->window[plane].winbufctrl = 0; /* select winbuf0 */ - lcd->winenable |= winenable; - au_sync(); - - return 0; -} - -static void au1200_setpanel (struct panel_settings *newpanel) -{ - /* - * Perform global setup/init of LCD controller - */ - uint32 winenable; - - /* Make sure all windows disabled */ - winenable = lcd->winenable; - lcd->winenable = 0; - au_sync(); - /* - * Ensure everything is disabled before reconfiguring - */ - if (lcd->screen & LCD_SCREEN_SEN) { - /* Wait for vertical sync period */ - lcd->intstatus = LCD_INT_SS; - while ((lcd->intstatus & LCD_INT_SS) == 0) { - au_sync(); - } - - lcd->screen &= ~LCD_SCREEN_SEN; /*disable the controller*/ - - do { - lcd->intstatus = lcd->intstatus; /*clear interrupts*/ - au_sync(); - /*wait for controller to shut down*/ - } while ((lcd->intstatus & LCD_INT_SD) == 0); - - /* Call shutdown of current panel (if up) */ - /* this must occur last, because if an external clock is driving - the controller, the clock cannot be turned off before first - shutting down the controller. - */ - if (panel->device_shutdown != NULL) - panel->device_shutdown(); - } - - /* Newpanel == NULL indicates a shutdown operation only */ - if (newpanel == NULL) - return; - - panel = newpanel; - - printk("Panel(%s), %dx%d\n", panel->name, panel->Xres, panel->Yres); - - /* - * Setup clocking if internal LCD clock source (assumes sys_auxpll valid) - */ - if (!(panel->mode_clkcontrol & LCD_CLKCONTROL_EXT)) - { - uint32 sys_clksrc; - au_writel(panel->mode_auxpll, SYS_AUXPLL); - sys_clksrc = au_readl(SYS_CLKSRC) & ~0x0000001f; - sys_clksrc |= panel->mode_toyclksrc; - au_writel(sys_clksrc, SYS_CLKSRC); - } - - /* - * Configure panel timings - */ - lcd->screen = panel->mode_screen; - lcd->horztiming = panel->mode_horztiming; - lcd->verttiming = panel->mode_verttiming; - lcd->clkcontrol = panel->mode_clkcontrol; - lcd->pwmdiv = panel->mode_pwmdiv; - lcd->pwmhi = panel->mode_pwmhi; - lcd->outmask = panel->mode_outmask; - lcd->fifoctrl = panel->mode_fifoctrl; - au_sync(); - - /* fixme: Check window settings to make sure still valid - * for new geometry */ -#if 0 - au1200_setlocation(fbdev, 0, win->w[0].xpos, win->w[0].ypos); - au1200_setlocation(fbdev, 1, win->w[1].xpos, win->w[1].ypos); - au1200_setlocation(fbdev, 2, win->w[2].xpos, win->w[2].ypos); - au1200_setlocation(fbdev, 3, win->w[3].xpos, win->w[3].ypos); -#endif - lcd->winenable = winenable; - - /* - * Re-enable screen now that it is configured - */ - lcd->screen |= LCD_SCREEN_SEN; - au_sync(); - - /* Call init of panel */ - if (panel->device_init != NULL) panel->device_init(); - - /* FIX!!!! not appropriate on panel change!!! Global setup/init */ - lcd->intenable = 0; - lcd->intstatus = ~0; - lcd->backcolor = win->mode_backcolor; - - /* Setup Color Key - FIX!!! */ - lcd->colorkey = win->mode_colorkey; - lcd->colorkeymsk = win->mode_colorkeymsk; - - /* Setup HWCursor - FIX!!! Need to support this eventually */ - lcd->hwc.cursorctrl = 0; - lcd->hwc.cursorpos = 0; - lcd->hwc.cursorcolor0 = 0; - lcd->hwc.cursorcolor1 = 0; - lcd->hwc.cursorcolor2 = 0; - lcd->hwc.cursorcolor3 = 0; - - -#if 0 -#define D(X) printk("%25s: %08X\n", #X, X) - D(lcd->screen); - D(lcd->horztiming); - D(lcd->verttiming); - D(lcd->clkcontrol); - D(lcd->pwmdiv); - D(lcd->pwmhi); - D(lcd->outmask); - D(lcd->fifoctrl); - D(lcd->window[0].winctrl0); - D(lcd->window[0].winctrl1); - D(lcd->window[0].winctrl2); - D(lcd->window[0].winbuf0); - D(lcd->window[0].winbuf1); - D(lcd->window[0].winbufctrl); - D(lcd->window[1].winctrl0); - D(lcd->window[1].winctrl1); - D(lcd->window[1].winctrl2); - D(lcd->window[1].winbuf0); - D(lcd->window[1].winbuf1); - D(lcd->window[1].winbufctrl); - D(lcd->window[2].winctrl0); - D(lcd->window[2].winctrl1); - D(lcd->window[2].winctrl2); - D(lcd->window[2].winbuf0); - D(lcd->window[2].winbuf1); - D(lcd->window[2].winbufctrl); - D(lcd->window[3].winctrl0); - D(lcd->window[3].winctrl1); - D(lcd->window[3].winctrl2); - D(lcd->window[3].winbuf0); - D(lcd->window[3].winbuf1); - D(lcd->window[3].winbufctrl); - D(lcd->winenable); - D(lcd->intenable); - D(lcd->intstatus); - D(lcd->backcolor); - D(lcd->winenable); - D(lcd->colorkey); - D(lcd->colorkeymsk); - D(lcd->hwc.cursorctrl); - D(lcd->hwc.cursorpos); - D(lcd->hwc.cursorcolor0); - D(lcd->hwc.cursorcolor1); - D(lcd->hwc.cursorcolor2); - D(lcd->hwc.cursorcolor3); -#endif -} - -static void au1200_setmode(struct au1200fb_device *fbdev) -{ - int plane = fbdev->plane; - /* Window/plane setup */ - lcd->window[plane].winctrl1 = ( 0 - | LCD_WINCTRL1_PRI_N(plane) - | win->w[plane].mode_winctrl1 /* FRM,CCO,PO,PIPE */ - ) ; - - au1200_setlocation(fbdev, plane, win->w[plane].xpos, win->w[plane].ypos); - - lcd->window[plane].winctrl2 = ( 0 - | LCD_WINCTRL2_CKMODE_00 - | LCD_WINCTRL2_DBM - | LCD_WINCTRL2_BX_N( fbdev->fb_info.fix.line_length) - | LCD_WINCTRL2_SCX_1 - | LCD_WINCTRL2_SCY_1 - ) ; - lcd->winenable |= win->w[plane].mode_winenable; - au_sync(); -} - - -/* Inline helpers */ - -/*#define panel_is_dual(panel) ((panel->mode_screen & LCD_SCREEN_PT) == LCD_SCREEN_PT_010)*/ -/*#define panel_is_active(panel)((panel->mode_screen & LCD_SCREEN_PT) == LCD_SCREEN_PT_010)*/ - -#define panel_is_color(panel) ((panel->mode_screen & LCD_SCREEN_PT) <= LCD_SCREEN_PT_CDSTN) - -/* Bitfields format supported by the controller. */ -static struct fb_bitfield rgb_bitfields[][4] = { - /* Red, Green, Blue, Transp */ - [LCD_WINCTRL1_FRM_16BPP655 >> 25] = - { { 10, 6, 0 }, { 5, 5, 0 }, { 0, 5, 0 }, { 0, 0, 0 } }, - - [LCD_WINCTRL1_FRM_16BPP565 >> 25] = - { { 11, 5, 0 }, { 5, 6, 0 }, { 0, 5, 0 }, { 0, 0, 0 } }, - - [LCD_WINCTRL1_FRM_16BPP556 >> 25] = - { { 11, 5, 0 }, { 6, 5, 0 }, { 0, 6, 0 }, { 0, 0, 0 } }, - - [LCD_WINCTRL1_FRM_16BPPI1555 >> 25] = - { { 10, 5, 0 }, { 5, 5, 0 }, { 0, 5, 0 }, { 0, 0, 0 } }, - - [LCD_WINCTRL1_FRM_16BPPI5551 >> 25] = - { { 11, 5, 0 }, { 6, 5, 0 }, { 1, 5, 0 }, { 0, 0, 0 } }, - - [LCD_WINCTRL1_FRM_16BPPA1555 >> 25] = - { { 10, 5, 0 }, { 5, 5, 0 }, { 0, 5, 0 }, { 15, 1, 0 } }, - - [LCD_WINCTRL1_FRM_16BPPA5551 >> 25] = - { { 11, 5, 0 }, { 6, 5, 0 }, { 1, 5, 0 }, { 0, 1, 0 } }, - - [LCD_WINCTRL1_FRM_24BPP >> 25] = - { { 16, 8, 0 }, { 8, 8, 0 }, { 0, 8, 0 }, { 0, 0, 0 } }, - - [LCD_WINCTRL1_FRM_32BPP >> 25] = - { { 16, 8, 0 }, { 8, 8, 0 }, { 0, 8, 0 }, { 24, 0, 0 } }, -}; - -/*-------------------------------------------------------------------------*/ - -/* Helpers */ - -static void au1200fb_update_fbinfo(struct fb_info *fbi) -{ - /* FIX!!!! This also needs to take the window pixel format into account!!! */ - - /* Update var-dependent FB info */ - if (panel_is_color(panel)) { - if (fbi->var.bits_per_pixel <= 8) { - /* palettized */ - fbi->fix.visual = FB_VISUAL_PSEUDOCOLOR; - fbi->fix.line_length = fbi->var.xres_virtual / - (8/fbi->var.bits_per_pixel); - } else { - /* non-palettized */ - fbi->fix.visual = FB_VISUAL_TRUECOLOR; - fbi->fix.line_length = fbi->var.xres_virtual * (fbi->var.bits_per_pixel / 8); - } - } else { - /* mono FIX!!! mono 8 and 4 bits */ - fbi->fix.visual = FB_VISUAL_MONO10; - fbi->fix.line_length = fbi->var.xres_virtual / 8; - } - - fbi->screen_size = fbi->fix.line_length * fbi->var.yres_virtual; - print_dbg("line length: %d\n", fbi->fix.line_length); - print_dbg("bits_per_pixel: %d\n", fbi->var.bits_per_pixel); -} - -/*-------------------------------------------------------------------------*/ - -/* AU1200 framebuffer driver */ - -/* fb_check_var - * Validate var settings with hardware restrictions and modify it if necessary - */ -static int au1200fb_fb_check_var(struct fb_var_screeninfo *var, - struct fb_info *fbi) -{ - struct au1200fb_device *fbdev = (struct au1200fb_device *)fbi; - u32 pixclock; - int screen_size, plane; - - plane = fbdev->plane; - - /* Make sure that the mode respect all LCD controller and - * panel restrictions. */ - var->xres = win->w[plane].xres; - var->yres = win->w[plane].yres; - - /* No need for virtual resolution support */ - var->xres_virtual = var->xres; - var->yres_virtual = var->yres; - - var->bits_per_pixel = winbpp(win->w[plane].mode_winctrl1); - - screen_size = var->xres_virtual * var->yres_virtual; - if (var->bits_per_pixel > 8) screen_size *= (var->bits_per_pixel / 8); - else screen_size /= (8/var->bits_per_pixel); - - if (fbdev->fb_len < screen_size) - return -EINVAL; /* Virtual screen is to big, abort */ - - /* FIX!!!! what are the implicaitons of ignoring this for windows ??? */ - /* The max LCD clock is fixed to 48MHz (value of AUX_CLK). The pixel - * clock can only be obtain by dividing this value by an even integer. - * Fallback to a slower pixel clock if necessary. */ - pixclock = max((u32)(PICOS2KHZ(var->pixclock) * 1000), fbi->monspecs.dclkmin); - pixclock = min(pixclock, min(fbi->monspecs.dclkmax, (u32)AU1200_LCD_MAX_CLK/2)); - - if (AU1200_LCD_MAX_CLK % pixclock) { - int diff = AU1200_LCD_MAX_CLK % pixclock; - pixclock -= diff; - } - - var->pixclock = KHZ2PICOS(pixclock/1000); -#if 0 - if (!panel_is_active(panel)) { - int pcd = AU1200_LCD_MAX_CLK / (pixclock * 2) - 1; - - if (!panel_is_color(panel) - && (panel->control_base & LCD_CONTROL_MPI) && (pcd < 3)) { - /* STN 8bit mono panel support is up to 6MHz pixclock */ - var->pixclock = KHZ2PICOS(6000); - } else if (!pcd) { - /* Other STN panel support is up to 12MHz */ - var->pixclock = KHZ2PICOS(12000); - } - } -#endif - /* Set bitfield accordingly */ - switch (var->bits_per_pixel) { - case 16: - { - /* 16bpp True color. - * These must be set to MATCH WINCTRL[FORM] */ - int idx; - idx = (win->w[0].mode_winctrl1 & LCD_WINCTRL1_FRM) >> 25; - var->red = rgb_bitfields[idx][0]; - var->green = rgb_bitfields[idx][1]; - var->blue = rgb_bitfields[idx][2]; - var->transp = rgb_bitfields[idx][3]; - break; - } - - case 32: - { - /* 32bpp True color. - * These must be set to MATCH WINCTRL[FORM] */ - int idx; - idx = (win->w[0].mode_winctrl1 & LCD_WINCTRL1_FRM) >> 25; - var->red = rgb_bitfields[idx][0]; - var->green = rgb_bitfields[idx][1]; - var->blue = rgb_bitfields[idx][2]; - var->transp = rgb_bitfields[idx][3]; - break; - } - default: - print_dbg("Unsupported depth %dbpp", var->bits_per_pixel); - return -EINVAL; - } - - return 0; -} - -/* fb_set_par - * Set hardware with var settings. This will enable the controller with a - * specific mode, normally validated with the fb_check_var method - */ -static int au1200fb_fb_set_par(struct fb_info *fbi) -{ - struct au1200fb_device *fbdev = (struct au1200fb_device *)fbi; - - au1200fb_update_fbinfo(fbi); - au1200_setmode(fbdev); - - return 0; -} - -/* fb_setcolreg - * Set color in LCD palette. - */ -static int au1200fb_fb_setcolreg(unsigned regno, unsigned red, unsigned green, - unsigned blue, unsigned transp, struct fb_info *fbi) -{ - volatile u32 *palette = lcd->palette; - u32 value; - - if (regno > (AU1200_LCD_NBR_PALETTE_ENTRIES - 1)) - return -EINVAL; - - if (fbi->var.grayscale) { - /* Convert color to grayscale */ - red = green = blue = - (19595 * red + 38470 * green + 7471 * blue) >> 16; - } - - if (fbi->fix.visual == FB_VISUAL_TRUECOLOR) { - /* Place color in the pseudopalette */ - if (regno > 16) - return -EINVAL; - - palette = (u32*) fbi->pseudo_palette; - - red >>= (16 - fbi->var.red.length); - green >>= (16 - fbi->var.green.length); - blue >>= (16 - fbi->var.blue.length); - - value = (red << fbi->var.red.offset) | - (green << fbi->var.green.offset)| - (blue << fbi->var.blue.offset); - value &= 0xFFFF; - - } else if (1 /*FIX!!! panel_is_active(fbdev->panel)*/) { - /* COLOR TFT PALLETTIZED (use RGB 565) */ - value = (red & 0xF800)|((green >> 5) & - 0x07E0)|((blue >> 11) & 0x001F); - value &= 0xFFFF; - - } else if (0 /*panel_is_color(fbdev->panel)*/) { - /* COLOR STN MODE */ - value = 0x1234; - value &= 0xFFF; - } else { - /* MONOCHROME MODE */ - value = (green >> 12) & 0x000F; - value &= 0xF; - } - - palette[regno] = value; - - return 0; -} - -/* fb_blank - * Blank the screen. Depending on the mode, the screen will be - * activated with the backlight color, or desactivated - */ -static int au1200fb_fb_blank(int blank_mode, struct fb_info *fbi) -{ - /* Short-circuit screen blanking */ - if (noblanking) - return 0; - - switch (blank_mode) { - - case FB_BLANK_UNBLANK: - case FB_BLANK_NORMAL: - /* printk("turn on panel\n"); */ - au1200_setpanel(panel); - break; - case FB_BLANK_VSYNC_SUSPEND: - case FB_BLANK_HSYNC_SUSPEND: - case FB_BLANK_POWERDOWN: - /* printk("turn off panel\n"); */ - au1200_setpanel(NULL); - break; - default: - break; - - } - - /* FB_BLANK_NORMAL is a soft blank */ - return (blank_mode == FB_BLANK_NORMAL) ? -EINVAL : 0; -} - -/* fb_mmap - * Map video memory in user space. We don't use the generic fb_mmap - * method mainly to allow the use of the TLB streaming flag (CCA=6) - */ -static int au1200fb_fb_mmap(struct fb_info *info, struct vm_area_struct *vma) - -{ - unsigned int len; - unsigned long start=0, off; - struct au1200fb_device *fbdev = (struct au1200fb_device *) info; - -#ifdef CONFIG_PM - au1xxx_pm_access(LCD_pm_dev); -#endif - - if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) { - return -EINVAL; - } - - start = fbdev->fb_phys & PAGE_MASK; - len = PAGE_ALIGN((start & ~PAGE_MASK) + fbdev->fb_len); - - off = vma->vm_pgoff << PAGE_SHIFT; - - if ((vma->vm_end - vma->vm_start + off) > len) { - return -EINVAL; - } - - off += start; - vma->vm_pgoff = off >> PAGE_SHIFT; - - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); - pgprot_val(vma->vm_page_prot) |= _CACHE_MASK; /* CCA=7 */ - - vma->vm_flags |= VM_IO; - - return io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, - vma->vm_end - vma->vm_start, - vma->vm_page_prot); - - return 0; -} - -static void set_global(u_int cmd, struct au1200_lcd_global_regs_t *pdata) -{ - - unsigned int hi1, divider; - - /* SCREEN_SIZE: user cannot reset size, must switch panel choice */ - - if (pdata->flags & SCREEN_BACKCOLOR) - lcd->backcolor = pdata->backcolor; - - if (pdata->flags & SCREEN_BRIGHTNESS) { - - // limit brightness pwm duty to >= 30/1600 - if (pdata->brightness < 30) { - pdata->brightness = 30; - } - divider = (lcd->pwmdiv & 0x3FFFF) + 1; - hi1 = (lcd->pwmhi >> 16) + 1; - hi1 = (((pdata->brightness & 0xFF)+1) * divider >> 8); - lcd->pwmhi &= 0xFFFF; - lcd->pwmhi |= (hi1 << 16); - } - - if (pdata->flags & SCREEN_COLORKEY) - lcd->colorkey = pdata->colorkey; - - if (pdata->flags & SCREEN_MASK) - lcd->colorkeymsk = pdata->mask; - au_sync(); -} - -static void get_global(u_int cmd, struct au1200_lcd_global_regs_t *pdata) -{ - unsigned int hi1, divider; - - pdata->xsize = ((lcd->screen & LCD_SCREEN_SX) >> 19) + 1; - pdata->ysize = ((lcd->screen & LCD_SCREEN_SY) >> 8) + 1; - - pdata->backcolor = lcd->backcolor; - pdata->colorkey = lcd->colorkey; - pdata->mask = lcd->colorkeymsk; - - // brightness - hi1 = (lcd->pwmhi >> 16) + 1; - divider = (lcd->pwmdiv & 0x3FFFF) + 1; - pdata->brightness = ((hi1 << 8) / divider) - 1; - au_sync(); -} - -static void set_window(unsigned int plane, - struct au1200_lcd_window_regs_t *pdata) -{ - unsigned int val, bpp; - - /* Window control register 0 */ - if (pdata->flags & WIN_POSITION) { - val = lcd->window[plane].winctrl0 & ~(LCD_WINCTRL0_OX | - LCD_WINCTRL0_OY); - val |= ((pdata->xpos << 21) & LCD_WINCTRL0_OX); - val |= ((pdata->ypos << 10) & LCD_WINCTRL0_OY); - lcd->window[plane].winctrl0 = val; - } - if (pdata->flags & WIN_ALPHA_COLOR) { - val = lcd->window[plane].winctrl0 & ~(LCD_WINCTRL0_A); - val |= ((pdata->alpha_color << 2) & LCD_WINCTRL0_A); - lcd->window[plane].winctrl0 = val; - } - if (pdata->flags & WIN_ALPHA_MODE) { - val = lcd->window[plane].winctrl0 & ~(LCD_WINCTRL0_AEN); - val |= ((pdata->alpha_mode << 1) & LCD_WINCTRL0_AEN); - lcd->window[plane].winctrl0 = val; - } - - /* Window control register 1 */ - if (pdata->flags & WIN_PRIORITY) { - val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_PRI); - val |= ((pdata->priority << 30) & LCD_WINCTRL1_PRI); - lcd->window[plane].winctrl1 = val; - } - if (pdata->flags & WIN_CHANNEL) { - val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_PIPE); - val |= ((pdata->channel << 29) & LCD_WINCTRL1_PIPE); - lcd->window[plane].winctrl1 = val; - } - if (pdata->flags & WIN_BUFFER_FORMAT) { - val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_FRM); - val |= ((pdata->buffer_format << 25) & LCD_WINCTRL1_FRM); - lcd->window[plane].winctrl1 = val; - } - if (pdata->flags & WIN_COLOR_ORDER) { - val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_CCO); - val |= ((pdata->color_order << 24) & LCD_WINCTRL1_CCO); - lcd->window[plane].winctrl1 = val; - } - if (pdata->flags & WIN_PIXEL_ORDER) { - val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_PO); - val |= ((pdata->pixel_order << 22) & LCD_WINCTRL1_PO); - lcd->window[plane].winctrl1 = val; - } - if (pdata->flags & WIN_SIZE) { - val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_SZX | - LCD_WINCTRL1_SZY); - val |= (((pdata->xsize << 11) - 1) & LCD_WINCTRL1_SZX); - val |= (((pdata->ysize) - 1) & LCD_WINCTRL1_SZY); - lcd->window[plane].winctrl1 = val; - /* program buffer line width */ - bpp = winbpp(val) / 8; - val = lcd->window[plane].winctrl2 & ~(LCD_WINCTRL2_BX); - val |= (((pdata->xsize * bpp) << 8) & LCD_WINCTRL2_BX); - lcd->window[plane].winctrl2 = val; - } - - /* Window control register 2 */ - if (pdata->flags & WIN_COLORKEY_MODE) { - val = lcd->window[plane].winctrl2 & ~(LCD_WINCTRL2_CKMODE); - val |= ((pdata->colorkey_mode << 24) & LCD_WINCTRL2_CKMODE); - lcd->window[plane].winctrl2 = val; - } - if (pdata->flags & WIN_DOUBLE_BUFFER_MODE) { - val = lcd->window[plane].winctrl2 & ~(LCD_WINCTRL2_DBM); - val |= ((pdata->double_buffer_mode << 23) & LCD_WINCTRL2_DBM); - lcd->window[plane].winctrl2 = val; - } - if (pdata->flags & WIN_RAM_ARRAY_MODE) { - val = lcd->window[plane].winctrl2 & ~(LCD_WINCTRL2_RAM); - val |= ((pdata->ram_array_mode << 21) & LCD_WINCTRL2_RAM); - lcd->window[plane].winctrl2 = val; - } - - /* Buffer line width programmed with WIN_SIZE */ - - if (pdata->flags & WIN_BUFFER_SCALE) { - val = lcd->window[plane].winctrl2 & ~(LCD_WINCTRL2_SCX | - LCD_WINCTRL2_SCY); - val |= ((pdata->xsize << 11) & LCD_WINCTRL2_SCX); - val |= ((pdata->ysize) & LCD_WINCTRL2_SCY); - lcd->window[plane].winctrl2 = val; - } - - if (pdata->flags & WIN_ENABLE) { - val = lcd->winenable; - val &= ~(1<<plane); - val |= (pdata->enable & 1) << plane; - lcd->winenable = val; - } - au_sync(); -} - -static void get_window(unsigned int plane, - struct au1200_lcd_window_regs_t *pdata) -{ - /* Window control register 0 */ - pdata->xpos = (lcd->window[plane].winctrl0 & LCD_WINCTRL0_OX) >> 21; - pdata->ypos = (lcd->window[plane].winctrl0 & LCD_WINCTRL0_OY) >> 10; - pdata->alpha_color = (lcd->window[plane].winctrl0 & LCD_WINCTRL0_A) >> 2; - pdata->alpha_mode = (lcd->window[plane].winctrl0 & LCD_WINCTRL0_AEN) >> 1; - - /* Window control register 1 */ - pdata->priority = (lcd->window[plane].winctrl1& LCD_WINCTRL1_PRI) >> 30; - pdata->channel = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_PIPE) >> 29; - pdata->buffer_format = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_FRM) >> 25; - pdata->color_order = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_CCO) >> 24; - pdata->pixel_order = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_PO) >> 22; - pdata->xsize = ((lcd->window[plane].winctrl1 & LCD_WINCTRL1_SZX) >> 11) + 1; - pdata->ysize = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_SZY) + 1; - - /* Window control register 2 */ - pdata->colorkey_mode = (lcd->window[plane].winctrl2 & LCD_WINCTRL2_CKMODE) >> 24; - pdata->double_buffer_mode = (lcd->window[plane].winctrl2 & LCD_WINCTRL2_DBM) >> 23; - pdata->ram_array_mode = (lcd->window[plane].winctrl2 & LCD_WINCTRL2_RAM) >> 21; - - pdata->enable = (lcd->winenable >> plane) & 1; - au_sync(); -} - -static int au1200fb_ioctl(struct fb_info *info, unsigned int cmd, - unsigned long arg) -{ - int plane; - int val; - -#ifdef CONFIG_PM - au1xxx_pm_access(LCD_pm_dev); -#endif - - plane = fbinfo2index(info); - print_dbg("au1200fb: ioctl %d on plane %d\n", cmd, plane); - - if (cmd == AU1200_LCD_FB_IOCTL) { - struct au1200_lcd_iodata_t iodata; - - if (copy_from_user(&iodata, (void __user *) arg, sizeof(iodata))) - return -EFAULT; - - print_dbg("FB IOCTL called\n"); - - switch (iodata.subcmd) { - case AU1200_LCD_SET_SCREEN: - print_dbg("AU1200_LCD_SET_SCREEN\n"); - set_global(cmd, &iodata.global); - break; - - case AU1200_LCD_GET_SCREEN: - print_dbg("AU1200_LCD_GET_SCREEN\n"); - get_global(cmd, &iodata.global); - break; - - case AU1200_LCD_SET_WINDOW: - print_dbg("AU1200_LCD_SET_WINDOW\n"); - set_window(plane, &iodata.window); - break; - - case AU1200_LCD_GET_WINDOW: - print_dbg("AU1200_LCD_GET_WINDOW\n"); - get_window(plane, &iodata.window); - break; - - case AU1200_LCD_SET_PANEL: - print_dbg("AU1200_LCD_SET_PANEL\n"); - if ((iodata.global.panel_choice >= 0) && - (iodata.global.panel_choice < - NUM_PANELS)) - { - struct panel_settings *newpanel; - panel_index = iodata.global.panel_choice; - newpanel = &known_lcd_panels[panel_index]; - au1200_setpanel(newpanel); - } - break; - - case AU1200_LCD_GET_PANEL: - print_dbg("AU1200_LCD_GET_PANEL\n"); - iodata.global.panel_choice = panel_index; - break; - - default: - return -EINVAL; - } - - val = copy_to_user((void __user *) arg, &iodata, sizeof(iodata)); - if (val) { - print_dbg("error: could not copy %d bytes\n", val); - return -EFAULT; - } - } - - return 0; -} - - -static struct fb_ops au1200fb_fb_ops = { - .owner = THIS_MODULE, - .fb_check_var = au1200fb_fb_check_var, - .fb_set_par = au1200fb_fb_set_par, - .fb_setcolreg = au1200fb_fb_setcolreg, - .fb_blank = au1200fb_fb_blank, - .fb_fillrect = cfb_fillrect, - .fb_copyarea = cfb_copyarea, - .fb_imageblit = cfb_imageblit, - .fb_sync = NULL, - .fb_ioctl = au1200fb_ioctl, - .fb_mmap = au1200fb_fb_mmap, -}; - -/*-------------------------------------------------------------------------*/ - -static irqreturn_t au1200fb_handle_irq(int irq, void* dev_id, struct pt_regs *regs) -{ - /* Nothing to do for now, just clear any pending interrupt */ - lcd->intstatus = lcd->intstatus; - au_sync(); - - return IRQ_HANDLED; -} - -/*-------------------------------------------------------------------------*/ - -/* AU1200 LCD device probe helpers */ - -static int au1200fb_init_fbinfo(struct au1200fb_device *fbdev) -{ - struct fb_info *fbi = &fbdev->fb_info; - int bpp; - - memset(fbi, 0, sizeof(struct fb_info)); - fbi->fbops = &au1200fb_fb_ops; - - bpp = winbpp(win->w[fbdev->plane].mode_winctrl1); - - /* Copy monitor specs from panel data */ - /* fixme: we're setting up LCD controller windows, so these dont give a - damn as to what the monitor specs are (the panel itself does, but that - isnt done here...so maybe need a generic catchall monitor setting??? */ - memcpy(&fbi->monspecs, &panel->monspecs, sizeof(struct fb_monspecs)); - - /* We first try the user mode passed in argument. If that failed, - * or if no one has been specified, we default to the first mode of the - * panel list. Note that after this call, var data will be set */ - if (!fb_find_mode(&fbi->var, - fbi, - NULL, /* drv_info.opt_mode, */ - fbi->monspecs.modedb, - fbi->monspecs.modedb_len, - fbi->monspecs.modedb, - bpp)) { - - print_err("Cannot find valid mode for panel %s", panel->name); - return -EFAULT; - } - - fbi->pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL); - if (!fbi->pseudo_palette) { - return -ENOMEM; - } - memset(fbi->pseudo_palette, 0, sizeof(u32) * 16); - - if (fb_alloc_cmap(&fbi->cmap, AU1200_LCD_NBR_PALETTE_ENTRIES, 0) < 0) { - print_err("Fail to allocate colormap (%d entries)", - AU1200_LCD_NBR_PALETTE_ENTRIES); - kfree(fbi->pseudo_palette); - return -EFAULT; - } - - strncpy(fbi->fix.id, "AU1200", sizeof(fbi->fix.id)); - fbi->fix.smem_start = fbdev->fb_phys; - fbi->fix.smem_len = fbdev->fb_len; - fbi->fix.type = FB_TYPE_PACKED_PIXELS; - fbi->fix.xpanstep = 0; - fbi->fix.ypanstep = 0; - fbi->fix.mmio_start = 0; - fbi->fix.mmio_len = 0; - fbi->fix.accel = FB_ACCEL_NONE; - - fbi->screen_base = (char __iomem *) fbdev->fb_mem; - - au1200fb_update_fbinfo(fbi); - - return 0; -} - -/*-------------------------------------------------------------------------*/ - -/* AU1200 LCD controller device driver */ - -static int au1200fb_drv_probe(struct device *dev) -{ - struct au1200fb_device *fbdev; - unsigned long page; - int bpp, plane, ret; - - if (!dev) - return -EINVAL; - - for (plane = 0; plane < CONFIG_FB_AU1200_DEVS; ++plane) { - bpp = winbpp(win->w[plane].mode_winctrl1); - if (win->w[plane].xres == 0) - win->w[plane].xres = panel->Xres; - if (win->w[plane].yres == 0) - win->w[plane].yres = panel->Yres; - - fbdev = &_au1200fb_devices[plane]; - memset(fbdev, 0, sizeof(struct au1200fb_device)); - fbdev->plane = plane; - - /* Allocate the framebuffer to the maximum screen size */ - fbdev->fb_len = (win->w[plane].xres * win->w[plane].yres * bpp) / 8; - - fbdev->fb_mem = dma_alloc_noncoherent(dev, - PAGE_ALIGN(fbdev->fb_len), - &fbdev->fb_phys, GFP_KERNEL); - if (!fbdev->fb_mem) { - print_err("fail to allocate frambuffer (size: %dK))", - fbdev->fb_len / 1024); - return -ENOMEM; - } - - /* - * Set page reserved so that mmap will work. This is necessary - * since we'll be remapping normal memory. - */ - for (page = (unsigned long)fbdev->fb_phys; - page < PAGE_ALIGN((unsigned long)fbdev->fb_phys + - fbdev->fb_len); - page += PAGE_SIZE) { - SetPageReserved(pfn_to_page(page >> PAGE_SHIFT)); /* LCD DMA is NOT coherent on Au1200 */ - } - print_dbg("Framebuffer memory map at %p", fbdev->fb_mem); - print_dbg("phys=0x%08x, size=%dK", fbdev->fb_phys, fbdev->fb_len / 1024); - - /* Init FB data */ - if ((ret = au1200fb_init_fbinfo(fbdev)) < 0) - goto failed; - - /* Register new framebuffer */ - if ((ret = register_framebuffer(&fbdev->fb_info)) < 0) { - print_err("cannot register new framebuffer"); - goto failed; - } - - au1200fb_fb_set_par(&fbdev->fb_info); - -#if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO) - if (plane == 0) - if (fb_prepare_logo(&fbdev->fb_info, FB_ROTATE_UR)) { - /* Start display and show logo on boot */ - fb_set_cmap(&fbdev->fb_info.cmap, - &fbdev->fb_info); - - fb_show_logo(&fbdev->fb_info, FB_ROTATE_UR); - } -#endif - } - - /* Now hook interrupt too */ - if ((ret = request_irq(AU1200_LCD_INT, au1200fb_handle_irq, - SA_INTERRUPT | SA_SHIRQ, "lcd", (void *)dev)) < 0) { - print_err("fail to request interrupt line %d (err: %d)", - AU1200_LCD_INT, ret); - goto failed; - } - - return 0; - -failed: - /* NOTE: This only does the current plane/window that failed; others are still active */ - if (fbdev->fb_mem) - dma_free_noncoherent(dev, PAGE_ALIGN(fbdev->fb_len), - fbdev->fb_mem, fbdev->fb_phys); - if (fbdev->fb_info.cmap.len != 0) - fb_dealloc_cmap(&fbdev->fb_info.cmap); - if (fbdev->fb_info.pseudo_palette) - kfree(fbdev->fb_info.pseudo_palette); - if (plane == 0) - free_irq(AU1200_LCD_INT, (void*)dev); - return ret; -} - -static int au1200fb_drv_remove(struct device *dev) -{ - struct au1200fb_device *fbdev; - int plane; - - if (!dev) - return -ENODEV; - - /* Turn off the panel */ - au1200_setpanel(NULL); - - for (plane = 0; plane < CONFIG_FB_AU1200_DEVS; ++plane) - { - fbdev = &_au1200fb_devices[plane]; - - /* Clean up all probe data */ - unregister_framebuffer(&fbdev->fb_info); - if (fbdev->fb_mem) - dma_free_noncoherent(dev, PAGE_ALIGN(fbdev->fb_len), - fbdev->fb_mem, fbdev->fb_phys); - if (fbdev->fb_info.cmap.len != 0) - fb_dealloc_cmap(&fbdev->fb_info.cmap); - if (fbdev->fb_info.pseudo_palette) - kfree(fbdev->fb_info.pseudo_palette); - } - - free_irq(AU1200_LCD_INT, (void *)dev); - - return 0; -} - -#ifdef CONFIG_PM -static int au1200fb_drv_suspend(struct device *dev, u32 state, u32 level) -{ - /* TODO */ - return 0; -} - -static int au1200fb_drv_resume(struct device *dev, u32 level) -{ - /* TODO */ - return 0; -} -#endif /* CONFIG_PM */ - -static struct device_driver au1200fb_driver = { - .name = "au1200-lcd", - .bus = &platform_bus_type, - .probe = au1200fb_drv_probe, - .remove = au1200fb_drv_remove, -#ifdef CONFIG_PM - .suspend = au1200fb_drv_suspend, - .resume = au1200fb_drv_resume, -#endif -}; - -/*-------------------------------------------------------------------------*/ - -/* Kernel driver */ - -static void au1200fb_setup(void) -{ - char* options = NULL; - char* this_opt; - int num_panels = ARRAY_SIZE(known_lcd_panels); - int panel_idx = -1; - - fb_get_options(DRIVER_NAME, &options); - - if (options) { - while ((this_opt = strsep(&options,",")) != NULL) { - /* Panel option - can be panel name, - * "bs" for board-switch, or number/index */ - if (!strncmp(this_opt, "panel:", 6)) { - int i; - long int li; - char *endptr; - this_opt += 6; - /* First check for index, which allows - * to short circuit this mess */ - li = simple_strtol(this_opt, &endptr, 0); - if (*endptr == '\0') { - panel_idx = (int)li; - } - else if (strcmp(this_opt, "bs") == 0) { - extern int board_au1200fb_panel(void); - panel_idx = board_au1200fb_panel(); - } - - else - for (i = 0; i < num_panels; i++) { - if (!strcmp(this_opt, known_lcd_panels[i].name)) { - panel_idx = i; - break; - } - } - - if ((panel_idx < 0) || (panel_idx >= num_panels)) { - print_warn("Panel %s not supported!", this_opt); - } - else - panel_index = panel_idx; - } - - else if (strncmp(this_opt, "nohwcursor", 10) == 0) { - nohwcursor = 1; - } - - /* Unsupported option */ - else { - print_warn("Unsupported option \"%s\"", this_opt); - } - } - } -} - -#ifdef CONFIG_PM -static int au1200fb_pm_callback(au1xxx_power_dev_t *dev, - au1xxx_request_t request, void *data) { - int retval = -1; - unsigned int d = 0; - unsigned int brightness = 0; - - if (request == AU1XXX_PM_SLEEP) { - board_au1200fb_panel_shutdown(); - } - else if (request == AU1XXX_PM_WAKEUP) { - if(dev->prev_state == SLEEP_STATE) - { - int plane; - au1200_setpanel(panel); - for (plane = 0; plane < CONFIG_FB_AU1200_DEVS; ++plane) { - struct au1200fb_device *fbdev; - fbdev = &_au1200fb_devices[plane]; - au1200fb_fb_set_par(&fbdev->fb_info); - } - } - - d = *((unsigned int*)data); - if(d <=10) brightness = 26; - else if(d<=20) brightness = 51; - else if(d<=30) brightness = 77; - else if(d<=40) brightness = 102; - else if(d<=50) brightness = 128; - else if(d<=60) brightness = 153; - else if(d<=70) brightness = 179; - else if(d<=80) brightness = 204; - else if(d<=90) brightness = 230; - else brightness = 255; - set_brightness(brightness); - } else if (request == AU1XXX_PM_GETSTATUS) { - return dev->cur_state; - } else if (request == AU1XXX_PM_ACCESS) { - if (dev->cur_state != SLEEP_STATE) - return retval; - else { - au1200_setpanel(panel); - } - } else if (request == AU1XXX_PM_IDLE) { - } else if (request == AU1XXX_PM_CLEANUP) { - } - - return retval; -} -#endif - -static int __init au1200fb_init(void) -{ - print_info("" DRIVER_DESC ""); - - /* Setup driver with options */ - au1200fb_setup(); - - /* Point to the panel selected */ - panel = &known_lcd_panels[panel_index]; - win = &windows[window_index]; - - printk(DRIVER_NAME ": Panel %d %s\n", panel_index, panel->name); - printk(DRIVER_NAME ": Win %d %s\n", window_index, win->name); - - /* Kickstart the panel, the framebuffers/windows come soon enough */ - au1200_setpanel(panel); - - #ifdef CONFIG_PM - LCD_pm_dev = new_au1xxx_power_device("LCD", &au1200fb_pm_callback, NULL); - if ( LCD_pm_dev == NULL) - printk(KERN_INFO "Unable to create a power management device entry for the au1200fb.\n"); - else - printk(KERN_INFO "Power management device entry for the au1200fb loaded.\n"); - #endif - - return driver_register(&au1200fb_driver); -} - -static void __exit au1200fb_cleanup(void) -{ - driver_unregister(&au1200fb_driver); -} - -module_init(au1200fb_init); -module_exit(au1200fb_cleanup); - -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); diff --git a/drivers/video/fbsysfs.c b/drivers/video/fbsysfs.c index b72b05250a9..34e07399756 100644 --- a/drivers/video/fbsysfs.c +++ b/drivers/video/fbsysfs.c @@ -305,94 +305,6 @@ static ssize_t show_stride(struct class_device *class_device, char *buf) return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->fix.line_length); } -/* Format for cmap is "%02x%c%4x%4x%4x\n" */ -/* %02x entry %c transp %4x red %4x blue %4x green \n */ -/* 256 rows at 16 chars equals 4096, the normal page size */ -/* the code will automatically adjust for different page sizes */ -static ssize_t store_cmap(struct class_device *class_device, const char *buf, - size_t count) -{ - struct fb_info *fb_info = class_get_devdata(class_device); - int rc, i, start, length, transp = 0; - - if ((count > PAGE_SIZE) || ((count % 16) != 0)) - return -EINVAL; - - if (!fb_info->fbops->fb_setcolreg && !fb_info->fbops->fb_setcmap) - return -EINVAL; - - sscanf(buf, "%02x", &start); - length = count / 16; - - for (i = 0; i < length; i++) - if (buf[i * 16 + 2] != ' ') - transp = 1; - - /* If we can batch, do it */ - if (fb_info->fbops->fb_setcmap && length > 1) { - struct fb_cmap umap; - - memset(&umap, 0, sizeof(umap)); - if ((rc = fb_alloc_cmap(&umap, length, transp))) - return rc; - - umap.start = start; - for (i = 0; i < length; i++) { - sscanf(&buf[i * 16 + 3], "%4hx", &umap.red[i]); - sscanf(&buf[i * 16 + 7], "%4hx", &umap.blue[i]); - sscanf(&buf[i * 16 + 11], "%4hx", &umap.green[i]); - if (transp) - umap.transp[i] = (buf[i * 16 + 2] != ' '); - } - rc = fb_info->fbops->fb_setcmap(&umap, fb_info); - fb_copy_cmap(&umap, &fb_info->cmap); - fb_dealloc_cmap(&umap); - - return rc ?: count; - } - for (i = 0; i < length; i++) { - u16 red, blue, green, tsp; - - sscanf(&buf[i * 16 + 3], "%4hx", &red); - sscanf(&buf[i * 16 + 7], "%4hx", &blue); - sscanf(&buf[i * 16 + 11], "%4hx", &green); - tsp = (buf[i * 16 + 2] != ' '); - if ((rc = fb_info->fbops->fb_setcolreg(start++, - red, green, blue, tsp, fb_info))) - return rc; - - fb_info->cmap.red[i] = red; - fb_info->cmap.blue[i] = blue; - fb_info->cmap.green[i] = green; - if (transp) - fb_info->cmap.transp[i] = tsp; - } - return count; -} - -static ssize_t show_cmap(struct class_device *class_device, char *buf) -{ - struct fb_info *fb_info = class_get_devdata(class_device); - unsigned int i; - - if (!fb_info->cmap.red || !fb_info->cmap.blue || - !fb_info->cmap.green) - return -EINVAL; - - if (fb_info->cmap.len > PAGE_SIZE / 16) - return -EINVAL; - - /* don't mess with the format, the buffer is PAGE_SIZE */ - /* 256 entries at 16 chars per line equals 4096 = PAGE_SIZE */ - for (i = 0; i < fb_info->cmap.len; i++) { - snprintf(&buf[ i * 16], PAGE_SIZE - i * 16, "%02x%c%4x%4x%4x\n", i + fb_info->cmap.start, - ((fb_info->cmap.transp && fb_info->cmap.transp[i]) ? '*' : ' '), - fb_info->cmap.red[i], fb_info->cmap.blue[i], - fb_info->cmap.green[i]); - } - return 16 * fb_info->cmap.len; -} - static ssize_t store_blank(struct class_device *class_device, const char * buf, size_t count) { @@ -502,10 +414,12 @@ static ssize_t show_fbstate(struct class_device *class_device, char *buf) return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->state); } +/* When cmap is added back in it should be a binary attribute + * not a text one. Consideration should also be given to converting + * fbdev to use configfs instead of sysfs */ static struct class_device_attribute class_device_attrs[] = { __ATTR(bits_per_pixel, S_IRUGO|S_IWUSR, show_bpp, store_bpp), __ATTR(blank, S_IRUGO|S_IWUSR, show_blank, store_blank), - __ATTR(color_map, S_IRUGO|S_IWUSR, show_cmap, store_cmap), __ATTR(console, S_IRUGO|S_IWUSR, show_console, store_console), __ATTR(cursor, S_IRUGO|S_IWUSR, show_cursor, store_cursor), __ATTR(mode, S_IRUGO|S_IWUSR, show_mode, store_mode), |