diff options
author | Paul Mundt <lethal@linux-sh.org> | 2009-04-21 17:12:16 +0900 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2009-04-21 17:12:16 +0900 |
commit | 4db25d496c09fdf094d52d11a90ae51f9ee473c6 (patch) | |
tree | 77ab8003db1d6ccbcf3a9acafad26002fba37b63 /drivers | |
parent | b8c193f88ebd8705b3e916532539031cd9fc0b4c (diff) | |
parent | 8c31813f31cd4403b46802866949a95a6e8fa584 (diff) |
Merge branch 'sh/stable-updates' into sh/for-2.6.30
Diffstat (limited to 'drivers')
150 files changed, 2507 insertions, 1306 deletions
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 065507c4664..17c5d48a75d 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -1231,6 +1231,9 @@ unsigned int ata_dev_classify(const struct ata_taskfile *tf) * * We follow the current spec and consider that 0x69/0x96 * identifies a port multiplier and 0x3c/0xc3 a SEMB device. + * Unfortunately, WDC WD1600JS-62MHB5 (a hard drive) reports + * SEMB signature. This is worked around in + * ata_dev_read_id(). */ if ((tf->lbam == 0) && (tf->lbah == 0)) { DPRINTK("found ATA device by sig\n"); @@ -1248,8 +1251,8 @@ unsigned int ata_dev_classify(const struct ata_taskfile *tf) } if ((tf->lbam == 0x3c) && (tf->lbah == 0xc3)) { - printk(KERN_INFO "ata: SEMB device ignored\n"); - return ATA_DEV_SEMB_UNSUP; /* not yet */ + DPRINTK("found SEMB device by sig (could be ATA device)\n"); + return ATA_DEV_SEMB; } DPRINTK("unknown device\n"); @@ -1653,8 +1656,8 @@ unsigned long ata_id_xfermask(const u16 *id) /* * Process compact flash extended modes */ - int pio = id[163] & 0x7; - int dma = (id[163] >> 3) & 7; + int pio = (id[ATA_ID_CFA_MODES] >> 0) & 0x7; + int dma = (id[ATA_ID_CFA_MODES] >> 3) & 0x7; if (pio) pio_mask |= (1 << 5); @@ -2080,6 +2083,7 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, struct ata_taskfile tf; unsigned int err_mask = 0; const char *reason; + bool is_semb = class == ATA_DEV_SEMB; int may_fallback = 1, tried_spinup = 0; int rc; @@ -2090,6 +2094,8 @@ retry: ata_tf_init(dev, &tf); switch (class) { + case ATA_DEV_SEMB: + class = ATA_DEV_ATA; /* some hard drives report SEMB sig */ case ATA_DEV_ATA: tf.command = ATA_CMD_ID_ATA; break; @@ -2126,6 +2132,14 @@ retry: return -ENOENT; } + if (is_semb) { + ata_dev_printk(dev, KERN_INFO, "IDENTIFY failed on " + "device w/ SEMB sig, disabled\n"); + /* SEMB is not supported yet */ + *p_class = ATA_DEV_SEMB_UNSUP; + return 0; + } + if ((err_mask == AC_ERR_DEV) && (tf.feature & ATA_ABORTED)) { /* Device or controller might have reported * the wrong device class. Give a shot at the @@ -2412,7 +2426,8 @@ int ata_dev_configure(struct ata_device *dev) /* ATA-specific feature tests */ if (dev->class == ATA_DEV_ATA) { if (ata_id_is_cfa(id)) { - if (id[162] & 1) /* CPRM may make this media unusable */ + /* CPRM may make this media unusable */ + if (id[ATA_ID_CFA_KEY_MGMT] & 1) ata_dev_printk(dev, KERN_WARNING, "supports DRM functions and may " "not be fully accessable.\n"); diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index b9747fa59e5..2733b0c90b7 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -647,23 +647,45 @@ int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg) return rc; } +static int ata_ioc32(struct ata_port *ap) +{ + if (ap->flags & ATA_FLAG_PIO_DMA) + return 1; + if (ap->pflags & ATA_PFLAG_PIO32) + return 1; + return 0; +} + int ata_sas_scsi_ioctl(struct ata_port *ap, struct scsi_device *scsidev, int cmd, void __user *arg) { int val = -EINVAL, rc = -EINVAL; + unsigned long flags; switch (cmd) { case ATA_IOC_GET_IO32: - val = 0; + spin_lock_irqsave(ap->lock, flags); + val = ata_ioc32(ap); + spin_unlock_irqrestore(ap->lock, flags); if (copy_to_user(arg, &val, 1)) return -EFAULT; return 0; case ATA_IOC_SET_IO32: val = (unsigned long) arg; - if (val != 0) - return -EINVAL; - return 0; + rc = 0; + spin_lock_irqsave(ap->lock, flags); + if (ap->pflags & ATA_PFLAG_PIO32CHANGE) { + if (val) + ap->pflags |= ATA_PFLAG_PIO32; + else + ap->pflags &= ~ATA_PFLAG_PIO32; + } else { + if (val != ata_ioc32(ap)) + rc = -EINVAL; + } + spin_unlock_irqrestore(ap->lock, flags); + return rc; case HDIO_GET_IDENTITY: return ata_get_identity(ap, scsidev, arg); diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 8332e97a9de..bb18415d3d6 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -87,6 +87,7 @@ const struct ata_port_operations ata_bmdma32_port_ops = { .inherits = &ata_bmdma_port_ops, .sff_data_xfer = ata_sff_data_xfer32, + .port_start = ata_sff_port_start32, }; EXPORT_SYMBOL_GPL(ata_bmdma32_port_ops); @@ -769,6 +770,9 @@ unsigned int ata_sff_data_xfer32(struct ata_device *dev, unsigned char *buf, void __iomem *data_addr = ap->ioaddr.data_addr; unsigned int words = buflen >> 2; int slop = buflen & 3; + + if (!(ap->pflags & ATA_PFLAG_PIO32)) + return ata_sff_data_xfer(dev, buf, buflen, rw); /* Transfer multiple of 4 bytes */ if (rw == READ) @@ -2402,6 +2406,29 @@ int ata_sff_port_start(struct ata_port *ap) EXPORT_SYMBOL_GPL(ata_sff_port_start); /** + * ata_sff_port_start32 - Set port up for dma. + * @ap: Port to initialize + * + * Called just after data structures for each port are + * initialized. Allocates space for PRD table if the device + * is DMA capable SFF. + * + * May be used as the port_start() entry in ata_port_operations for + * devices that are capable of 32bit PIO. + * + * LOCKING: + * Inherited from caller. + */ +int ata_sff_port_start32(struct ata_port *ap) +{ + ap->pflags |= ATA_PFLAG_PIO32 | ATA_PFLAG_PIO32CHANGE; + if (ap->ioaddr.bmdma_addr) + return ata_port_start(ap); + return 0; +} +EXPORT_SYMBOL_GPL(ata_sff_port_start32); + +/** * ata_sff_std_ports - initialize ioaddr with standard port offsets. * @ioaddr: IO address structure to be initialized * diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c index 81ab57003ab..122c786449a 100644 --- a/drivers/ata/pata_hpt37x.c +++ b/drivers/ata/pata_hpt37x.c @@ -8,7 +8,7 @@ * Copyright (C) 1999-2003 Andre Hedrick <andre@linux-ide.org> * Portions Copyright (C) 2001 Sun Microsystems, Inc. * Portions Copyright (C) 2003 Red Hat Inc - * Portions Copyright (C) 2005-2007 MontaVista Software, Inc. + * Portions Copyright (C) 2005-2009 MontaVista Software, Inc. * * TODO * Look into engine reset on timeout errors. Should not be required. @@ -24,7 +24,7 @@ #include <linux/libata.h> #define DRV_NAME "pata_hpt37x" -#define DRV_VERSION "0.6.11" +#define DRV_VERSION "0.6.12" struct hpt_clock { u8 xfer_speed; @@ -445,23 +445,6 @@ static void hpt370_set_dmamode(struct ata_port *ap, struct ata_device *adev) } /** - * hpt370_bmdma_start - DMA engine begin - * @qc: ATA command - * - * The 370 and 370A want us to reset the DMA engine each time we - * use it. The 372 and later are fine. - */ - -static void hpt370_bmdma_start(struct ata_queued_cmd *qc) -{ - struct ata_port *ap = qc->ap; - struct pci_dev *pdev = to_pci_dev(ap->host->dev); - pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37); - udelay(10); - ata_bmdma_start(qc); -} - -/** * hpt370_bmdma_end - DMA engine stop * @qc: ATA command * @@ -598,7 +581,6 @@ static struct scsi_host_template hpt37x_sht = { static struct ata_port_operations hpt370_port_ops = { .inherits = &ata_bmdma_port_ops, - .bmdma_start = hpt370_bmdma_start, .bmdma_stop = hpt370_bmdma_stop, .mode_filter = hpt370_filter, diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c index 3f830f0fe2c..f72c6c5b820 100644 --- a/drivers/ata/pata_legacy.c +++ b/drivers/ata/pata_legacy.c @@ -108,6 +108,7 @@ struct legacy_controller { struct ata_port_operations *ops; unsigned int pio_mask; unsigned int flags; + unsigned int pflags; int (*setup)(struct platform_device *, struct legacy_probe *probe, struct legacy_data *data); }; @@ -284,9 +285,11 @@ static unsigned int pdc_data_xfer_vlb(struct ata_device *dev, unsigned char *buf, unsigned int buflen, int rw) { int slop = buflen & 3; + struct ata_port *ap = dev->link->ap; + /* 32bit I/O capable *and* we need to write a whole number of dwords */ - if (ata_id_has_dword_io(dev->id) && (slop == 0 || slop == 3)) { - struct ata_port *ap = dev->link->ap; + if (ata_id_has_dword_io(dev->id) && (slop == 0 || slop == 3) + && (ap->pflags & ATA_PFLAG_PIO32)) { unsigned long flags; local_irq_save(flags); @@ -736,7 +739,8 @@ static unsigned int vlb32_data_xfer(struct ata_device *adev, unsigned char *buf, struct ata_port *ap = adev->link->ap; int slop = buflen & 3; - if (ata_id_has_dword_io(adev->id) && (slop == 0 || slop == 3)) { + if (ata_id_has_dword_io(adev->id) && (slop == 0 || slop == 3) + && (ap->pflags & ATA_PFLAG_PIO32)) { if (rw == WRITE) iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2); else @@ -858,27 +862,30 @@ static struct ata_port_operations winbond_port_ops = { static struct legacy_controller controllers[] = { {"BIOS", &legacy_port_ops, 0x1F, - ATA_FLAG_NO_IORDY, NULL }, + ATA_FLAG_NO_IORDY, 0, NULL }, {"Snooping", &simple_port_ops, 0x1F, - 0 , NULL }, + 0, 0, NULL }, {"PDC20230", &pdc20230_port_ops, 0x7, - ATA_FLAG_NO_IORDY, NULL }, + ATA_FLAG_NO_IORDY, + ATA_PFLAG_PIO32 | ATA_PFLAG_PIO32CHANGE, NULL }, {"HT6560A", &ht6560a_port_ops, 0x07, - ATA_FLAG_NO_IORDY, NULL }, + ATA_FLAG_NO_IORDY, 0, NULL }, {"HT6560B", &ht6560b_port_ops, 0x1F, - ATA_FLAG_NO_IORDY, NULL }, + ATA_FLAG_NO_IORDY, 0, NULL }, {"OPTI82C611A", &opti82c611a_port_ops, 0x0F, - 0 , NULL }, + 0, 0, NULL }, {"OPTI82C46X", &opti82c46x_port_ops, 0x0F, - 0 , NULL }, + 0, 0, NULL }, {"QDI6500", &qdi6500_port_ops, 0x07, - ATA_FLAG_NO_IORDY, qdi_port }, + ATA_FLAG_NO_IORDY, + ATA_PFLAG_PIO32 | ATA_PFLAG_PIO32CHANGE, qdi_port }, {"QDI6580", &qdi6580_port_ops, 0x1F, - 0 , qdi_port }, + 0, ATA_PFLAG_PIO32 | ATA_PFLAG_PIO32CHANGE, qdi_port }, {"QDI6580DP", &qdi6580dp_port_ops, 0x1F, - 0 , qdi_port }, + 0, ATA_PFLAG_PIO32 | ATA_PFLAG_PIO32CHANGE, qdi_port }, {"W83759A", &winbond_port_ops, 0x1F, - 0 , winbond_port } + 0, ATA_PFLAG_PIO32 | ATA_PFLAG_PIO32CHANGE, + winbond_port } }; /** @@ -1008,6 +1015,7 @@ static __init int legacy_init_one(struct legacy_probe *probe) ap->ops = ops; ap->pio_mask = pio_modes; ap->flags |= ATA_FLAG_SLAVE_POSS | iordy; + ap->pflags |= controller->pflags; ap->ioaddr.cmd_addr = io_addr; ap->ioaddr.altstatus_addr = ctrl_addr; ap->ioaddr.ctl_addr = ctrl_addr; @@ -1032,6 +1040,7 @@ static __init int legacy_init_one(struct legacy_probe *probe) return 0; } } + ata_host_detach(host); fail: platform_device_unregister(pdev); return ret; diff --git a/drivers/ata/pata_ninja32.c b/drivers/ata/pata_ninja32.c index 0fb6b1b1e63..dd53a66b19e 100644 --- a/drivers/ata/pata_ninja32.c +++ b/drivers/ata/pata_ninja32.c @@ -44,7 +44,7 @@ #include <linux/libata.h> #define DRV_NAME "pata_ninja32" -#define DRV_VERSION "0.1.3" +#define DRV_VERSION "0.1.5" /** @@ -86,6 +86,7 @@ static struct ata_port_operations ninja32_port_ops = { .sff_dev_select = ninja32_dev_select, .cable_detect = ata_cable_40wire, .set_piomode = ninja32_set_piomode, + .sff_data_xfer = ata_sff_data_xfer32 }; static void ninja32_program(void __iomem *base) @@ -144,6 +145,7 @@ static int ninja32_init_one(struct pci_dev *dev, const struct pci_device_id *id) ap->ioaddr.altstatus_addr = base + 0x1E; ap->ioaddr.bmdma_addr = base; ata_sff_std_ports(&ap->ioaddr); + ap->pflags = ATA_PFLAG_PIO32 | ATA_PFLAG_PIO32CHANGE; ninja32_program(base); /* FIXME: Should we disable them at remove ? */ diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c index b08e6e0f82b..45657cacec4 100644 --- a/drivers/ata/pata_via.c +++ b/drivers/ata/pata_via.c @@ -62,7 +62,7 @@ #include <linux/dmi.h> #define DRV_NAME "pata_via" -#define DRV_VERSION "0.3.3" +#define DRV_VERSION "0.3.4" /* * The following comes directly from Vojtech Pavlik's ide/pci/via82cxxx @@ -136,6 +136,9 @@ static const struct via_isa_bridge { { NULL } }; +struct via_port { + u8 cached_device; +}; /* * Cable special cases @@ -346,14 +349,70 @@ static void via_set_dmamode(struct ata_port *ap, struct ata_device *adev) */ static void via_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) { - struct ata_taskfile tmp_tf; + struct ata_ioports *ioaddr = &ap->ioaddr; + struct via_port *vp = ap->private_data; + unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; + int newctl = 0; + + if (tf->ctl != ap->last_ctl) { + iowrite8(tf->ctl, ioaddr->ctl_addr); + ap->last_ctl = tf->ctl; + ata_wait_idle(ap); + newctl = 1; + } + + if (tf->flags & ATA_TFLAG_DEVICE) { + iowrite8(tf->device, ioaddr->device_addr); + vp->cached_device = tf->device; + } else if (newctl) + iowrite8(vp->cached_device, ioaddr->device_addr); + + if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) { + WARN_ON_ONCE(!ioaddr->ctl_addr); + iowrite8(tf->hob_feature, ioaddr->feature_addr); + iowrite8(tf->hob_nsect, ioaddr->nsect_addr); + iowrite8(tf->hob_lbal, ioaddr->lbal_addr); + iowrite8(tf->hob_lbam, ioaddr->lbam_addr); + iowrite8(tf->hob_lbah, ioaddr->lbah_addr); + VPRINTK("hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X\n", + tf->hob_feature, + tf->hob_nsect, + tf->hob_lbal, + tf->hob_lbam, + tf->hob_lbah); + } - if (ap->ctl != ap->last_ctl && !(tf->flags & ATA_TFLAG_DEVICE)) { - tmp_tf = *tf; - tmp_tf.flags |= ATA_TFLAG_DEVICE; - tf = &tmp_tf; + if (is_addr) { + iowrite8(tf->feature, ioaddr->feature_addr); + iowrite8(tf->nsect, ioaddr->nsect_addr); + iowrite8(tf->lbal, ioaddr->lbal_addr); + iowrite8(tf->lbam, ioaddr->lbam_addr); + iowrite8(tf->lbah, ioaddr->lbah_addr); + VPRINTK("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n", + tf->feature, + tf->nsect, + tf->lbal, + tf->lbam, + tf->lbah); } - ata_sff_tf_load(ap, tf); + + ata_wait_idle(ap); +} + +static int via_port_start(struct ata_port *ap) +{ + struct via_port *vp; + struct pci_dev *pdev = to_pci_dev(ap->host->dev); + + int ret = ata_sff_port_start(ap); + if (ret < 0) + return ret; + + vp = devm_kzalloc(&pdev->dev, sizeof(struct via_port), GFP_KERNEL); + if (vp == NULL) + return -ENOMEM; + ap->private_data = vp; + return 0; } static struct scsi_host_template via_sht = { @@ -367,6 +426,7 @@ static struct ata_port_operations via_port_ops = { .set_dmamode = via_set_dmamode, .prereset = via_pre_reset, .sff_tf_load = via_tf_load, + .port_start = via_port_start, }; static struct ata_port_operations via_port_ops_noirq = { diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index 37ae5dc1070..870dcfd8235 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -1881,6 +1881,39 @@ static u8 mv_bmdma_status(struct ata_port *ap) return status; } +static void mv_rw_multi_errata_sata24(struct ata_queued_cmd *qc) +{ + struct ata_taskfile *tf = &qc->tf; + /* + * Workaround for 88SX60x1 FEr SATA#24. + * + * Chip may corrupt WRITEs if multi_count >= 4kB. + * Note that READs are unaffected. + * + * It's not clear if this errata really means "4K bytes", + * or if it always happens for multi_count > 7 + * regardless of device sector_size. + * + * So, for safety, any write with multi_count > 7 + * gets converted here into a regular PIO write instead: + */ + if ((tf->flags & ATA_TFLAG_WRITE) && is_multi_taskfile(tf)) { + if (qc->dev->multi_count > 7) { + switch (tf->command) { + case ATA_CMD_WRITE_MULTI: + tf->command = ATA_CMD_PIO_WRITE; + break; + case ATA_CMD_WRITE_MULTI_FUA_EXT: + tf->flags &= ~ATA_TFLAG_FUA; /* ugh */ + /* fall through */ + case ATA_CMD_WRITE_MULTI_EXT: + tf->command = ATA_CMD_PIO_WRITE_EXT; + break; + } + } + } +} + /** * mv_qc_prep - Host specific command preparation. * @qc: queued command to prepare @@ -1898,17 +1931,24 @@ static void mv_qc_prep(struct ata_queued_cmd *qc) struct ata_port *ap = qc->ap; struct mv_port_priv *pp = ap->private_data; __le16 *cw; - struct ata_taskfile *tf; + struct ata_taskfile *tf = &qc->tf; u16 flags = 0; unsigned in_index; - if ((qc->tf.protocol != ATA_PROT_DMA) && - (qc->tf.protocol != ATA_PROT_NCQ)) + switch (tf->protocol) { + case ATA_PROT_DMA: + case ATA_PROT_NCQ: + break; /* continue below */ + case ATA_PROT_PIO: + mv_rw_multi_errata_sata24(qc); + return; + default: return; + } /* Fill in command request block */ - if (!(qc->tf.flags & ATA_TFLAG_WRITE)) + if (!(tf->flags & ATA_TFLAG_WRITE)) flags |= CRQB_FLAG_READ; WARN_ON(MV_MAX_Q_DEPTH <= qc->tag); flags |= qc->tag << CRQB_TAG_SHIFT; @@ -1924,7 +1964,6 @@ static void mv_qc_prep(struct ata_queued_cmd *qc) pp->crqb[in_index].ctrl_flags = cpu_to_le16(flags); cw = &pp->crqb[in_index].ata_cmd[0]; - tf = &qc->tf; /* Sadly, the CRQB cannot accomodate all registers--there are * only 11 bytes...so we must pick and choose required @@ -1990,16 +2029,16 @@ static void mv_qc_prep_iie(struct ata_queued_cmd *qc) struct ata_port *ap = qc->ap; struct mv_port_priv *pp = ap->private_data; struct mv_crqb_iie *crqb; - struct ata_taskfile *tf; + struct ata_taskfile *tf = &qc->tf; unsigned in_index; u32 flags = 0; - if ((qc->tf.protocol != ATA_PROT_DMA) && - (qc->tf.protocol != ATA_PROT_NCQ)) + if ((tf->protocol != ATA_PROT_DMA) && + (tf->protocol != ATA_PROT_NCQ)) return; /* Fill in Gen IIE command request block */ - if (!(qc->tf.flags & ATA_TFLAG_WRITE)) + if (!(tf->flags & ATA_TFLAG_WRITE)) flags |= CRQB_FLAG_READ; WARN_ON(MV_MAX_Q_DEPTH <= qc->tag); @@ -2015,7 +2054,6 @@ static void mv_qc_prep_iie(struct ata_queued_cmd *qc) crqb->addr_hi = cpu_to_le32((pp->sg_tbl_dma[qc->tag] >> 16) >> 16); crqb->flags = cpu_to_le32(flags); - tf = &qc->tf; crqb->ata_cmd[0] = cpu_to_le32( (tf->command << 16) | (tf->feature << 24) diff --git a/drivers/base/base.h b/drivers/base/base.h index ddc97496db4..b528145a078 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -115,7 +115,7 @@ extern int driver_probe_device(struct device_driver *drv, struct device *dev); static inline int driver_match_device(struct device_driver *drv, struct device *dev) { - return drv->bus->match && drv->bus->match(dev, drv); + return drv->bus->match ? drv->bus->match(dev, drv) : 1; } extern void sysdev_shutdown(void); diff --git a/drivers/base/core.c b/drivers/base/core.c index e73c92d13a2..d230ff4b3ee 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -1142,6 +1142,9 @@ int device_for_each_child(struct device *parent, void *data, struct device *child; int error = 0; + if (!parent->p) + return 0; + klist_iter_init(&parent->p->klist_children, &i); while ((child = next_device(&i)) && !error) error = fn(child, data); diff --git a/drivers/base/platform.c b/drivers/base/platform.c index d2198f64ad4..b5b6c973a2e 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -990,6 +990,8 @@ int __init platform_bus_init(void) { int error; + early_platform_cleanup(); + error = device_register(&platform_bus); if (error) return error; @@ -1020,3 +1022,240 @@ u64 dma_get_required_mask(struct device *dev) } EXPORT_SYMBOL_GPL(dma_get_required_mask); #endif + +static __initdata LIST_HEAD(early_platform_driver_list); +static __initdata LIST_HEAD(early_platform_device_list); + +/** + * early_platform_driver_register + * @edrv: early_platform driver structure + * @buf: string passed from early_param() + */ +int __init early_platform_driver_register(struct early_platform_driver *epdrv, + char *buf) +{ + unsigned long index; + int n; + + /* Simply add the driver to the end of the global list. + * Drivers will by default be put on the list in compiled-in order. + */ + if (!epdrv->list.next) { + INIT_LIST_HEAD(&epdrv->list); + list_add_tail(&epdrv->list, &early_platform_driver_list); + } + + /* If the user has specified device then make sure the driver + * gets prioritized. The driver of the last device specified on + * command line will be put first on the list. + */ + n = strlen(epdrv->pdrv->driver.name); + if (buf && !strncmp(buf, epdrv->pdrv->driver.name, n)) { + list_move(&epdrv->list, &early_platform_driver_list); + + if (!strcmp(buf, epdrv->pdrv->driver.name)) + epdrv->requested_id = -1; + else if (buf[n] == '.' && strict_strtoul(&buf[n + 1], 10, + &index) == 0) + epdrv->requested_id = index; + else + epdrv->requested_id = EARLY_PLATFORM_ID_ERROR; + } + + return 0; +} + +/** + * early_platform_add_devices - add a numbers of early platform devices + * @devs: array of early platform devices to add + * @num: number of early platform devices in array + */ +void __init early_platform_add_devices(struct platform_device **devs, int num) +{ + struct device *dev; + int i; + + /* simply add the devices to list */ + for (i = 0; i < num; i++) { + dev = &devs[i]->dev; + + if (!dev->devres_head.next) { + INIT_LIST_HEAD(&dev->devres_head); + list_add_tail(&dev->devres_head, + &early_platform_device_list); + } + } +} + +/** + * early_platform_driver_register_all + * @class_str: string to identify early platform driver class + */ +void __init early_platform_driver_register_all(char *class_str) +{ + /* The "class_str" parameter may or may not be present on the kernel + * command line. If it is present then there may be more than one + * matching parameter. + * + * Since we register our early platform drivers using early_param() + * we need to make sure that they also get registered in the case + * when the parameter is missing from the kernel command line. + * + * We use parse_early_options() to make sure the early_param() gets + * called at least once. The early_param() may be called more than + * once since the name of the preferred device may be specified on + * the kernel command line. early_platform_driver_register() handles + * this case for us. + */ + parse_early_options(class_str); +} + +/** + * early_platform_match + * @edrv: early platform driver structure + * @id: id to match against + */ +static __init struct platform_device * +early_platform_match(struct early_platform_driver *epdrv, int id) +{ + struct platform_device *pd; + + list_for_each_entry(pd, &early_platform_device_list, dev.devres_head) + if (platform_match(&pd->dev, &epdrv->pdrv->driver)) + if (pd->id == id) + return pd; + + return NULL; +} + +/** + * early_platform_left + * @edrv: early platform driver structure + * @id: return true if id or above exists + */ +static __init int early_platform_left(struct early_platform_driver *epdrv, + int id) +{ + struct platform_device *pd; + + list_for_each_entry(pd, &early_platform_device_list, dev.devres_head) + if (platform_match(&pd->dev, &epdrv->pdrv->driver)) + if (pd->id >= id) + return 1; + + return 0; +} + +/** + * early_platform_driver_probe_id + * @class_str: string to identify early platform driver class + * @id: id to match against + * @nr_probe: number of platform devices to successfully probe before exiting + */ +static int __init early_platform_driver_probe_id(char *class_str, + int id, + int nr_probe) +{ + struct early_platform_driver *epdrv; + struct platform_device *match; + int match_id; + int n = 0; + int left = 0; + + list_for_each_entry(epdrv, &early_platform_driver_list, list) { + /* only use drivers matching our class_str */ + if (strcmp(class_str, epdrv->class_str)) + continue; + + if (id == -2) { + match_id = epdrv->requested_id; + left = 1; + + } else { + match_id = id; + left += early_platform_left(epdrv, id); + + /* skip requested id */ + switch (epdrv->requested_id) { + case EARLY_PLATFORM_ID_ERROR: + case EARLY_PLATFORM_ID_UNSET: + break; + default: + if (epdrv->requested_id == id) + match_id = EARLY_PLATFORM_ID_UNSET; + } + } + + switch (match_id) { + case EARLY_PLATFORM_ID_ERROR: + pr_warning("%s: unable to parse %s parameter\n", + class_str, epdrv->pdrv->driver.name); + /* fall-through */ + case EARLY_PLATFORM_ID_UNSET: + match = NULL; + break; + default: + match = early_platform_match(epdrv, match_id); + } + + if (match) { + if (epdrv->pdrv->probe(match)) + pr_warning("%s: unable to probe %s early.\n", + class_str, match->name); + else + n++; + } + + if (n >= nr_probe) + break; + } + + if (left) + return n; + else + return -ENODEV; +} + +/** + * early_platform_driver_probe + * @class_str: string to identify early platform driver class + * @nr_probe: number of platform devices to successfully probe before exiting + * @user_only: only probe user specified early platform devices + */ +int __init early_platform_driver_probe(char *class_str, + int nr_probe, + int user_only) +{ + int k, n, i; + + n = 0; + for (i = -2; n < nr_probe; i++) { + k = early_platform_driver_probe_id(class_str, i, nr_probe - n); + + if (k < 0) + break; + + n += k; + + if (user_only) + break; + } + + return n; +} + +/** + * early_platform_cleanup - clean up early platform code + */ +void __init early_platform_cleanup(void) +{ + struct platform_device *pd, *pd2; + + /* clean up the devres list used to chain devices */ + list_for_each_entry_safe(pd, pd2, &early_platform_device_list, + dev.devres_head) { + list_del(&pd->dev.devres_head); + memset(&pd->dev.devres_head, 0, sizeof(pd->dev.devres_head)); + } +} + diff --git a/drivers/block/ub.c b/drivers/block/ub.c index 69b7f8e7759..689cd27ac89 100644 --- a/drivers/block/ub.c +++ b/drivers/block/ub.c @@ -1025,6 +1025,7 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd) { struct urb *urb = &sc->work_urb; struct bulk_cs_wrap *bcs; + int endp; int len; int rc; @@ -1033,6 +1034,10 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd) return; } + endp = usb_pipeendpoint(sc->last_pipe); + if (usb_pipein(sc->last_pipe)) + endp |= USB_DIR_IN; + if (cmd->state == UB_CMDST_CLEAR) { if (urb->status == -EPIPE) { /* @@ -1048,9 +1053,7 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd) * We ignore the result for the halt clear. */ - /* reset the endpoint toggle */ - usb_settoggle(sc->dev, usb_pipeendpoint(sc->last_pipe), - usb_pipeout(sc->last_pipe), 0); + usb_reset_endpoint(sc->dev, endp); ub_state_sense(sc, cmd); @@ -1065,9 +1068,7 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd) * We ignore the result for the halt clear. */ - /* reset the endpoint toggle */ - usb_settoggle(sc->dev, usb_pipeendpoint(sc->last_pipe), - usb_pipeout(sc->last_pipe), 0); + usb_reset_endpoint(sc->dev, endp); ub_state_stat(sc, cmd); @@ -1082,9 +1083,7 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd) * We ignore the result for the halt clear. */ - /* reset the endpoint toggle */ - usb_settoggle(sc->dev, usb_pipeendpoint(sc->last_pipe), - usb_pipeout(sc->last_pipe), 0); + usb_reset_endpoint(sc->dev, endp); ub_state_stat_counted(sc, cmd); @@ -2119,8 +2118,7 @@ static int ub_probe_clear_stall(struct ub_dev *sc, int stalled_pipe) del_timer_sync(&timer); usb_kill_urb(&sc->work_urb); - /* reset the endpoint toggle */ - usb_settoggle(sc->dev, endp, usb_pipeout(sc->last_pipe), 0); + usb_reset_endpoint(sc->dev, endp); return 0; } diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 3586b3b3df3..8f05c38c2f0 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -301,33 +301,7 @@ static inline int private_mapping_ok(struct vm_area_struct *vma) } #endif -void __attribute__((weak)) -map_devmem(unsigned long pfn, unsigned long len, pgprot_t prot) -{ - /* nothing. architectures can override. */ -} - -void __attribute__((weak)) -unmap_devmem(unsigned long pfn, unsigned long len, pgprot_t prot) -{ - /* nothing. architectures can override. */ -} - -static void mmap_mem_open(struct vm_area_struct *vma) -{ - map_devmem(vma->vm_pgoff, vma->vm_end - vma->vm_start, - vma->vm_page_prot); -} - -static void mmap_mem_close(struct vm_area_struct *vma) -{ - unmap_devmem(vma->vm_pgoff, vma->vm_end - vma->vm_start, - vma->vm_page_prot); -} - static struct vm_operations_struct mmap_mem_ops = { - .open = mmap_mem_open, - .close = mmap_mem_close, #ifdef CONFIG_HAVE_IOREMAP_PROT .access = generic_access_phys #endif @@ -362,7 +336,6 @@ static int mmap_mem(struct file * file, struct vm_area_struct * vma) vma->vm_pgoff, size, vma->vm_page_prot)) { - unmap_devmem(vma->vm_pgoff, size, vma->vm_page_prot); return -EAGAIN; } return 0; diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c index ebf4be5b7c4..2d175b5928f 100644 --- a/drivers/input/gameport/gameport.c +++ b/drivers/input/gameport/gameport.c @@ -50,9 +50,8 @@ static LIST_HEAD(gameport_list); static struct bus_type gameport_bus; -static void gameport_add_driver(struct gameport_driver *drv); static void gameport_add_port(struct gameport *gameport); -static void gameport_destroy_port(struct gameport *gameport); +static void gameport_attach_driver(struct gameport_driver *drv); static void gameport_reconnect_port(struct gameport *gameport); static void gameport_disconnect_port(struct gameport *gameport); @@ -230,7 +229,6 @@ static void gameport_find_driver(struct gameport *gameport) enum gameport_event_type { GAMEPORT_REGISTER_PORT, - GAMEPORT_REGISTER_DRIVER, GAMEPORT_ATTACH_DRIVER, }; @@ -374,8 +372,8 @@ static void gameport_handle_event(void) gameport_add_port(event->object); break; - case GAMEPORT_REGISTER_DRIVER: - gameport_add_driver(event->object); + case GAMEPORT_ATTACH_DRIVER: + gameport_attach_driver(event->object); break; default: @@ -706,14 +704,14 @@ static int gameport_driver_remove(struct device *dev) return 0; } -static void gameport_add_driver(struct gameport_driver *drv) +static void gameport_attach_driver(struct gameport_driver *drv) { int error; - error = driver_register(&drv->driver); + error = driver_attach(&drv->driver); if (error) printk(KERN_ERR - "gameport: driver_register() failed for %s, error: %d\n", + "gameport: driver_attach() failed for %s, error: %d\n", drv->driver.name, error); } diff --git a/drivers/input/input.c b/drivers/input/input.c index d44065d2e66..935a1835de2 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -1549,7 +1549,6 @@ int input_register_handle(struct input_handle *handle) return error; list_add_tail_rcu(&handle->d_node, &dev->h_list); mutex_unlock(&dev->mutex); - synchronize_rcu(); /* * Since we are supposed to be called from ->connect() diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index f999dc60c3b..444dec07e5d 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c @@ -880,7 +880,7 @@ static unsigned int atkbd_hp_zv6100_forced_release_keys[] = { }; /* - * Samsung NC10 with Fn+F? key release not working + * Samsung NC10,NC20 with Fn+F? key release not working */ static unsigned int atkbd_samsung_forced_release_keys[] = { 0x82, 0x83, 0x84, 0x86, 0x88, 0x89, 0xb3, 0xf7, 0xf9, -1U @@ -1534,6 +1534,24 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { .driver_data = atkbd_samsung_forced_release_keys, }, { + .ident = "Samsung NC20", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), + DMI_MATCH(DMI_PRODUCT_NAME, "NC20"), + }, + .callback = atkbd_setup_forced_release, + .driver_data = atkbd_samsung_forced_release_keys, + }, + { + .ident = "Samsung SQ45S70S", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), + DMI_MATCH(DMI_PRODUCT_NAME, "SQ45S70S"), + }, + .callback = atkbd_setup_forced_release, + .driver_data = atkbd_samsung_forced_release_keys, + }, + { .ident = "Fujitsu Amilo PA 1510", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), diff --git a/drivers/input/keyboard/bf54x-keys.c b/drivers/input/keyboard/bf54x-keys.c index e94b7d735ac..d427f322e20 100644 --- a/drivers/input/keyboard/bf54x-keys.c +++ b/drivers/input/keyboard/bf54x-keys.c @@ -252,7 +252,7 @@ static int __devinit bfin_kpad_probe(struct platform_device *pdev) } error = request_irq(bf54x_kpad->irq, bfin_kpad_isr, - IRQF_SAMPLE_RANDOM, DRV_NAME, pdev); + 0, DRV_NAME, pdev); if (error) { printk(KERN_ERR DRV_NAME ": unable to claim irq %d; error %d\n", diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 203abac1e23..5c0a631d145 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -214,7 +214,7 @@ config INPUT_SGI_BTNS config HP_SDC_RTC tristate "HP SDC Real Time Clock" - depends on GSC || HP300 + depends on (GSC || HP300) && SERIO select HP_SDC help Say Y here if you want to support the built-in real time clock diff --git a/drivers/input/mouse/pc110pad.c b/drivers/input/mouse/pc110pad.c index f63995f854f..3941f97cfa6 100644 --- a/drivers/input/mouse/pc110pad.c +++ b/drivers/input/mouse/pc110pad.c @@ -108,7 +108,6 @@ static int pc110pad_open(struct input_dev *dev) */ static int __init pc110pad_init(void) { - struct pci_dev *dev; int err; if (!no_pci_devices()) diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index 83ed2d56b92..fb8a3cd3ffd 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -377,6 +377,24 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = { { } }; +static struct dmi_system_id __initdata i8042_dmi_reset_table[] = { + { + .ident = "MSI Wind U-100", + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "U-100"), + DMI_MATCH(DMI_BOARD_VENDOR, "MICRO-STAR INTERNATIONAL CO., LTD"), + }, + }, + { + .ident = "LG Electronics X110", + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "X110"), + DMI_MATCH(DMI_BOARD_VENDOR, "LG Electronics Inc."), + }, + }, + { } +}; + #ifdef CONFIG_PNP static struct dmi_system_id __initdata i8042_dmi_nopnp_table[] = { { @@ -386,6 +404,13 @@ static struct dmi_system_id __initdata i8042_dmi_nopnp_table[] = { DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"), }, }, + { + .ident = "MSI Wind U-100", + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "U-100"), + DMI_MATCH(DMI_BOARD_VENDOR, "MICRO-STAR INTERNATIONAL CO., LTD"), + }, + }, { } }; #endif @@ -698,6 +723,9 @@ static int __init i8042_platform_init(void) #endif #ifdef CONFIG_X86 + if (dmi_check_system(i8042_dmi_reset_table)) + i8042_reset = 1; + if (dmi_check_system(i8042_dmi_noloop_table)) i8042_noloop = 1; diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index 170f71ee577..3cffb704e37 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -712,22 +712,43 @@ static int i8042_controller_check(void) static int i8042_controller_selftest(void) { unsigned char param; + int i = 0; if (!i8042_reset) return 0; - if (i8042_command(¶m, I8042_CMD_CTL_TEST)) { - printk(KERN_ERR "i8042.c: i8042 controller self test timeout.\n"); - return -ENODEV; - } + /* + * We try this 5 times; on some really fragile systems this does not + * take the first time... + */ + do { + + if (i8042_command(¶m, I8042_CMD_CTL_TEST)) { + printk(KERN_ERR "i8042.c: i8042 controller self test timeout.\n"); + return -ENODEV; + } + + if (param == I8042_RET_CTL_TEST) + return 0; - if (param != I8042_RET_CTL_TEST) { printk(KERN_ERR "i8042.c: i8042 controller selftest failed. (%#x != %#x)\n", - param, I8042_RET_CTL_TEST); - return -EIO; - } + param, I8042_RET_CTL_TEST); + msleep(50); + } while (i++ < 5); +#ifdef CONFIG_X86 + /* + * On x86, we don't fail entire i8042 initialization if controller + * reset fails in hopes that keyboard port will still be functional + * and user will still get a working keyboard. This is especially + * important on netbooks. On other arches we trust hardware more. + */ + printk(KERN_INFO + "i8042: giving up on controller selftest, continuing anyway...\n"); return 0; +#else + return -EIO; +#endif } /* diff --git a/drivers/input/touchscreen/ad7877.c b/drivers/input/touchscreen/ad7877.c index e4728a28f49..ecaeb7e8e75 100644 --- a/drivers/input/touchscreen/ad7877.c +++ b/drivers/input/touchscreen/ad7877.c @@ -736,8 +736,8 @@ static int __devinit ad7877_probe(struct spi_device *spi) /* Request AD7877 /DAV GPIO interrupt */ - err = request_irq(spi->irq, ad7877_irq, IRQF_TRIGGER_FALLING | - IRQF_SAMPLE_RANDOM, spi->dev.driver->name, ts); + err = request_irq(spi->irq, ad7877_irq, IRQF_TRIGGER_FALLING, + spi->dev.driver->name, ts); if (err) { dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq); goto err_free_mem; diff --git a/drivers/input/touchscreen/ad7879.c b/drivers/input/touchscreen/ad7879.c index ea4c61d6868..5d8a7039880 100644 --- a/drivers/input/touchscreen/ad7879.c +++ b/drivers/input/touchscreen/ad7879.c @@ -448,8 +448,7 @@ static int __devinit ad7879_construct(bus_device *bus, struct ad7879 *ts) ad7879_setup(ts); err = request_irq(bus->irq, ad7879_irq, - IRQF_TRIGGER_FALLING | IRQF_SAMPLE_RANDOM, - bus->dev.driver->name, ts); + IRQF_TRIGGER_FALLING, bus->dev.driver->name, ts); if (err) { dev_err(&bus->dev, "irq %d busy?\n", bus->irq); diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index 056ac77e2cf..2b01e56568f 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -127,6 +127,8 @@ struct ads7846 { void (*filter_cleanup)(void *data); int (*get_pendown_state)(void); int gpio_pendown; + + void (*wait_for_sync)(void); }; /* leave chip selected when we're done, for quicker re-select? */ @@ -511,6 +513,10 @@ static int get_pendown_state(struct ads7846 *ts) return !gpio_get_value(ts->gpio_pendown); } +static void null_wait_for_sync(void) +{ +} + /* * PENIRQ only kicks the timer. The timer only reissues the SPI transfer, * to retrieve touchscreen status. @@ -686,6 +692,7 @@ static void ads7846_rx_val(void *ads) default: BUG(); } + ts->wait_for_sync(); status = spi_async(ts->spi, m); if (status) dev_err(&ts->spi->dev, "spi_async --> %d\n", @@ -723,6 +730,7 @@ static enum hrtimer_restart ads7846_timer(struct hrtimer *handle) } else { /* pen is still down, continue with the measurement */ ts->msg_idx = 0; + ts->wait_for_sync(); status = spi_async(ts->spi, &ts->msg[0]); if (status) dev_err(&ts->spi->dev, "spi_async --> %d\n", status); @@ -746,7 +754,7 @@ static irqreturn_t ads7846_irq(int irq, void *handle) * that here. (The "generic irq" framework may help...) */ ts->irq_disabled = 1; - disable_irq(ts->spi->irq); + disable_irq_nosync(ts->spi->irq); ts->pending = 1; hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_DELAY), HRTIMER_MODE_REL); @@ -947,6 +955,8 @@ static int __devinit ads7846_probe(struct spi_device *spi) ts->penirq_recheck_delay_usecs = pdata->penirq_recheck_delay_usecs; + ts->wait_for_sync = pdata->wait_for_sync ? : null_wait_for_sync; + snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&spi->dev)); input_dev->name = "ADS784x Touchscreen"; diff --git a/drivers/input/touchscreen/da9034-ts.c b/drivers/input/touchscreen/da9034-ts.c index fa67d782c3c..3ffd4c4b170 100644 --- a/drivers/input/touchscreen/da9034-ts.c +++ b/drivers/input/touchscreen/da9034-ts.c @@ -3,6 +3,7 @@ * * Copyright (C) 2006-2008 Marvell International Ltd. * Fengwei Yin <fengwei.yin@marvell.com> + * Bin Yang <bin.yang@marvell.com> * Eric Miao <eric.miao@marvell.com> * * This program is free software; you can redistribute it and/or modify @@ -175,6 +176,16 @@ static void da9034_event_handler(struct da9034_touch *touch, int event) goto err_reset; touch->state = STATE_STOP; + + /* FIXME: PEN_{UP/DOWN} events are expected to be + * available by stopping TSI, but this is found not + * always true, delay and simulate such an event + * here is more reliable + */ + mdelay(1); + da9034_event_handler(touch, + is_pen_down(touch) ? EVENT_PEN_DOWN : + EVENT_PEN_UP); break; case STATE_STOP: @@ -189,8 +200,6 @@ static void da9034_event_handler(struct da9034_touch *touch, int event) report_pen_up(touch); touch->state = STATE_IDLE; } - - input_sync(touch->input_dev); break; case STATE_WAIT: @@ -200,8 +209,10 @@ static void da9034_event_handler(struct da9034_touch *touch, int event) if (is_pen_down(touch)) { start_tsi(touch); touch->state = STATE_BUSY; - } else + } else { + report_pen_up(touch); touch->state = STATE_IDLE; + } break; } return; @@ -226,16 +237,12 @@ static int da9034_touch_notifier(struct notifier_block *nb, struct da9034_touch *touch = container_of(nb, struct da9034_touch, notifier); - if (event & DA9034_EVENT_PEN_DOWN) { - if (is_pen_down(touch)) - da9034_event_handler(touch, EVENT_PEN_DOWN); - else - da9034_event_handler(touch, EVENT_PEN_UP); - } - if (event & DA9034_EVENT_TSI_READY) da9034_event_handler(touch, EVENT_TSI_READY); + if ((event & DA9034_EVENT_PEN_DOWN) && touch->state == STATE_IDLE) + da9034_event_handler(touch, EVENT_PEN_DOWN); + return 0; } @@ -385,6 +392,6 @@ static void __exit da9034_touch_exit(void) module_exit(da9034_touch_exit); MODULE_DESCRIPTION("Touchscreen driver for Dialog Semiconductor DA9034"); -MODULE_AUTHOR("Eric Miao <eric.miao@marvell.com>"); +MODULE_AUTHOR("Eric Miao <eric.miao@marvell.com>, Bin Yang <bin.yang@marvell.com>"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:da9034-touch"); diff --git a/drivers/input/touchscreen/mainstone-wm97xx.c b/drivers/input/touchscreen/mainstone-wm97xx.c index dfa6a84ab50..4cc047a5116 100644 --- a/drivers/input/touchscreen/mainstone-wm97xx.c +++ b/drivers/input/touchscreen/mainstone-wm97xx.c @@ -111,13 +111,12 @@ static void wm97xx_acc_pen_up(struct wm97xx *wm) #else static void wm97xx_acc_pen_up(struct wm97xx *wm) { - int count = 16; + unsigned int count; + schedule_timeout_uninterruptible(1); - while (count < 16) { + for (count = 0; count < 16; count++) MODR; - count--; - } } #endif diff --git a/drivers/input/touchscreen/wm97xx-core.c b/drivers/input/touchscreen/wm97xx-core.c index cec480bffe3..69af8385ab1 100644 --- a/drivers/input/touchscreen/wm97xx-core.c +++ b/drivers/input/touchscreen/wm97xx-core.c @@ -370,8 +370,7 @@ static int wm97xx_init_pen_irq(struct wm97xx *wm) * provided. */ BUG_ON(!wm->mach_ops->irq_enable); - if (request_irq(wm->pen_irq, wm97xx_pen_interrupt, - IRQF_SHARED | IRQF_SAMPLE_RANDOM, + if (request_irq(wm->pen_irq, wm97xx_pen_interrupt, IRQF_SHARED, "wm97xx-pen", wm)) { dev_err(wm->dev, "Failed to register pen down interrupt, polling"); diff --git a/drivers/isdn/hisax/st5481_usb.c b/drivers/isdn/hisax/st5481_usb.c index ec3c0e50766..2b3a055059e 100644 --- a/drivers/isdn/hisax/st5481_usb.c +++ b/drivers/isdn/hisax/st5481_usb.c @@ -149,14 +149,7 @@ static void usb_ctrl_complete(struct urb *urb) if (ctrl_msg->dr.bRequest == USB_REQ_CLEAR_FEATURE) { /* Special case handling for pipe reset */ le16_to_cpus(&ctrl_msg->dr.wIndex); - - /* toggle is reset on clear */ - usb_settoggle(adapter->usb_dev, - ctrl_msg->dr.wIndex & ~USB_DIR_IN, - (ctrl_msg->dr.wIndex & USB_DIR_IN) == 0, - 0); - - + usb_reset_endpoint(adapter->usb_dev, ctrl_msg->dr.wIndex); } if (ctrl_msg->complete) diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index d9d974a8f52..add3395d324 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -1461,7 +1461,6 @@ static int pvr2_upload_firmware1(struct pvr2_hdw *hdw) return ret; } - usb_settoggle(hdw->usb_dev, 0 & 0xf, !(0 & USB_DIR_IN), 0); usb_clear_halt(hdw->usb_dev, usb_sndbulkpipe(hdw->usb_dev, 0 & 0x7f)); pipe = usb_sndctrlpipe(hdw->usb_dev, 0); diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c index d0d0c2fee05..02f64d57864 100644 --- a/drivers/net/a2065.c +++ b/drivers/net/a2065.c @@ -692,6 +692,17 @@ static struct zorro_driver a2065_driver = { .remove = __devexit_p(a2065_remove_one), }; +static const struct net_device_ops lance_netdev_ops = { + .ndo_open = lance_open, + .ndo_stop = lance_close, + .ndo_start_xmit = lance_start_xmit, + .ndo_tx_timeout = lance_tx_timeout, + .ndo_set_multicast_list = lance_set_multicast, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = eth_change_mtu, + .ndo_set_mac_address = eth_mac_addr, +}; + static int __devinit a2065_init_one(struct zorro_dev *z, const struct zorro_device_id *ent) { @@ -753,12 +764,8 @@ static int __devinit a2065_init_one(struct zorro_dev *z, priv->rx_ring_mod_mask = RX_RING_MOD_MASK; priv->tx_ring_mod_mask = TX_RING_MOD_MASK; - dev->open = &lance_open; - dev->stop = &lance_close; - dev->hard_start_xmit = &lance_start_xmit; - dev->tx_timeout = &lance_tx_timeout; + dev->netdev_ops = &lance_netdev_ops; dev->watchdog_timeo = 5*HZ; - dev->set_multicast_list = &lance_set_multicast; dev->dma = 0; init_timer(&priv->multicast_timer); diff --git a/drivers/net/ariadne.c b/drivers/net/ariadne.c index e1d72e06f3e..58e8d522e5b 100644 --- a/drivers/net/ariadne.c +++ b/drivers/net/ariadne.c @@ -155,6 +155,18 @@ static struct zorro_driver ariadne_driver = { .remove = __devexit_p(ariadne_remove_one), }; +static const struct net_device_ops ariadne_netdev_ops = { + .ndo_open = ariadne_open, + .ndo_stop = ariadne_close, + .ndo_start_xmit = ariadne_start_xmit, + .ndo_tx_timeout = ariadne_tx_timeout, + .ndo_get_stats = ariadne_get_stats, + .ndo_set_multicast_list = set_multicast_list, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = eth_change_mtu, + .ndo_set_mac_address = eth_mac_addr, +}; + static int __devinit ariadne_init_one(struct zorro_dev *z, const struct zorro_device_id *ent) { @@ -197,13 +209,8 @@ static int __devinit ariadne_init_one(struct zorro_dev *z, dev->mem_start = ZTWO_VADDR(mem_start); dev->mem_end = dev->mem_start+ARIADNE_RAM_SIZE; - dev->open = &ariadne_open; - dev->stop = &ariadne_close; - dev->hard_start_xmit = &ariadne_start_xmit; - dev->tx_timeout = &ariadne_tx_timeout; + dev->netdev_ops = &ariadne_netdev_ops; dev->watchdog_timeo = 5*HZ; - dev->get_stats = &ariadne_get_stats; - dev->set_multicast_list = &set_multicast_list; err = register_netdev(dev); if (err) { diff --git a/drivers/net/arm/am79c961a.c b/drivers/net/arm/am79c961a.c index 4bc6901b381..627bc75da17 100644 --- a/drivers/net/arm/am79c961a.c +++ b/drivers/net/arm/am79c961a.c @@ -665,6 +665,20 @@ static void __init am79c961_banner(void) if (net_debug && version_printed++ == 0) printk(KERN_INFO "%s", version); } +static const struct net_device_ops am79c961_netdev_ops = { + .ndo_open = am79c961_open, + .ndo_stop = am79c961_close, + .ndo_start_xmit = am79c961_sendpacket, + .ndo_get_stats = am79c961_getstats, + .ndo_set_multicast_list = am79c961_setmulticastlist, + .ndo_tx_timeout = am79c961_timeout, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = eth_change_mtu, + .ndo_set_mac_address = eth_mac_addr, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = am79c961_poll_controller, +#endif +}; static int __init am79c961_probe(struct platform_device *pdev) { @@ -732,15 +746,7 @@ static int __init am79c961_probe(struct platform_device *pdev) if (am79c961_hw_init(dev)) goto release; - dev->open = am79c961_open; - dev->stop = am79c961_close; - dev->hard_start_xmit = am79c961_sendpacket; - dev->get_stats = am79c961_getstats; - dev->set_multicast_list = am79c961_setmulticastlist; - dev->tx_timeout = am79c961_timeout; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = am79c961_poll_controller; -#endif + dev->netdev_ops = &am79c961_netdev_ops; ret = register_netdev(dev); if (ret == 0) { diff --git a/drivers/net/arm/at91_ether.c b/drivers/net/arm/at91_ether.c index 442938d5038..7f4bc8ae546 100644 --- a/drivers/net/arm/at91_ether.c +++ b/drivers/net/arm/at91_ether.c @@ -577,7 +577,7 @@ static void at91ether_sethashtable(struct net_device *dev) /* * Enable/Disable promiscuous and multicast modes. */ -static void at91ether_set_rx_mode(struct net_device *dev) +static void at91ether_set_multicast_list(struct net_device *dev) { unsigned long cfg; @@ -808,7 +808,7 @@ static int at91ether_close(struct net_device *dev) /* * Transmit packet. */ -static int at91ether_tx(struct sk_buff *skb, struct net_device *dev) +static int at91ether_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct at91_private *lp = netdev_priv(dev); @@ -828,7 +828,7 @@ static int at91ether_tx(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; } else { - printk(KERN_ERR "at91_ether.c: at91ether_tx() called, but device is busy!\n"); + printk(KERN_ERR "at91_ether.c: at91ether_start_xmit() called, but device is busy!\n"); return 1; /* if we return anything but zero, dev.c:1055 calls kfree_skb(skb) on this skb, he also reports -ENETDOWN and printk's, so either we free and return(0) or don't free and return 1 */ @@ -965,6 +965,21 @@ static void at91ether_poll_controller(struct net_device *dev) } #endif +static const struct net_device_ops at91ether_netdev_ops = { + .ndo_open = at91ether_open, + .ndo_stop = at91ether_close, + .ndo_start_xmit = at91ether_start_xmit, + .ndo_get_stats = at91ether_stats, + .ndo_set_multicast_list = at91ether_set_multicast_list, + .ndo_set_mac_address = set_mac_address, + .ndo_do_ioctl = at91ether_ioctl, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = eth_change_mtu, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = at91ether_poll_controller, +#endif +}; + /* * Initialize the ethernet interface */ @@ -1005,17 +1020,8 @@ static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_add spin_lock_init(&lp->lock); ether_setup(dev); - dev->open = at91ether_open; - dev->stop = at91ether_close; - dev->hard_start_xmit = at91ether_tx; - dev->get_stats = at91ether_stats; - dev->set_multicast_list = at91ether_set_rx_mode; - dev->set_mac_address = set_mac_address; + dev->netdev_ops = &at91ether_netdev_ops; dev->ethtool_ops = &at91ether_ethtool_ops; - dev->do_ioctl = at91ether_ioctl; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = at91ether_poll_controller; -#endif SET_NETDEV_DEV(dev, &pdev->dev); diff --git a/drivers/net/arm/ep93xx_eth.c b/drivers/net/arm/ep93xx_eth.c index cc7708775da..b72b3d639f6 100644 --- a/drivers/net/arm/ep93xx_eth.c +++ b/drivers/net/arm/ep93xx_eth.c @@ -153,7 +153,7 @@ struct ep93xx_descs struct ep93xx_priv { struct resource *res; - void *base_addr; + void __iomem *base_addr; int irq; struct ep93xx_descs *descs; @@ -770,7 +770,18 @@ static struct ethtool_ops ep93xx_ethtool_ops = { .get_link = ep93xx_get_link, }; -struct net_device *ep93xx_dev_alloc(struct ep93xx_eth_data *data) +static const struct net_device_ops ep93xx_netdev_ops = { + .ndo_open = ep93xx_open, + .ndo_stop = ep93xx_close, + .ndo_start_xmit = ep93xx_xmit, + .ndo_get_stats = ep93xx_get_stats, + .ndo_do_ioctl = ep93xx_ioctl, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = eth_change_mtu, + .ndo_set_mac_address = eth_mac_addr, +}; + +static struct net_device *ep93xx_dev_alloc(struct ep93xx_eth_data *data) { struct net_device *dev; @@ -780,12 +791,8 @@ struct net_device *ep93xx_dev_alloc(struct ep93xx_eth_data *data) memcpy(dev->dev_addr, data->dev_addr, ETH_ALEN); - dev->get_stats = ep93xx_get_stats; dev->ethtool_ops = &ep93xx_ethtool_ops; - dev->hard_start_xmit = ep93xx_xmit; - dev->open = ep93xx_open; - dev->stop = ep93xx_close; - dev->do_ioctl = ep93xx_ioctl; + dev->netdev_ops = &ep93xx_netdev_ops; dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM; diff --git a/drivers/net/arm/ether1.c b/drivers/net/arm/ether1.c index e380de45446..edf770f639f 100644 --- a/drivers/net/arm/ether1.c +++ b/drivers/net/arm/ether1.c @@ -991,6 +991,18 @@ static void __devinit ether1_banner(void) printk(KERN_INFO "%s", version); } +static const struct net_device_ops ether1_netdev_ops = { + .ndo_open = ether1_open, + .ndo_stop = ether1_close, + .ndo_start_xmit = ether1_sendpacket, + .ndo_get_stats = ether1_getstats, + .ndo_set_multicast_list = ether1_setmulticastlist, + .ndo_tx_timeout = ether1_timeout, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = eth_change_mtu, + .ndo_set_mac_address = eth_mac_addr, +}; + static int __devinit ether1_probe(struct expansion_card *ec, const struct ecard_id *id) { @@ -1031,12 +1043,7 @@ ether1_probe(struct expansion_card *ec, const struct ecard_id *id) goto free; } - dev->open = ether1_open; - dev->stop = ether1_close; - dev->hard_start_xmit = ether1_sendpacket; - dev->get_stats = ether1_getstats; - dev->set_multicast_list = ether1_setmulticastlist; - dev->tx_timeout = ether1_timeout; + dev->netdev_ops = ðer1_netdev_ops; dev->watchdog_timeo = 5 * HZ / 100; ret = register_netdev(dev); diff --git a/drivers/net/arm/ether3.c b/drivers/net/arm/ether3.c index 21a7bef12d3..ec8a1ae1e88 100644 --- a/drivers/net/arm/ether3.c +++ b/drivers/net/arm/ether3.c @@ -770,6 +770,18 @@ static void __devinit ether3_banner(void) printk(KERN_INFO "%s", version); } +static const struct net_device_ops ether3_netdev_ops = { + .ndo_open = ether3_open, + .ndo_stop = ether3_close, + .ndo_start_xmit = ether3_sendpacket, + .ndo_get_stats = ether3_getstats, + .ndo_set_multicast_list = ether3_setmulticastlist, + .ndo_tx_timeout = ether3_timeout, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = eth_change_mtu, + .ndo_set_mac_address = eth_mac_addr, +}; + static int __devinit ether3_probe(struct expansion_card *ec, const struct ecard_id *id) { @@ -846,12 +858,7 @@ ether3_probe(struct expansion_card *ec, const struct ecard_id *id) goto free; } - dev->open = ether3_open; - dev->stop = ether3_close; - dev->hard_start_xmit = ether3_sendpacket; - dev->get_stats = ether3_getstats; - dev->set_multicast_list = ether3_setmulticastlist; - dev->tx_timeout = ether3_timeout; + dev->netdev_ops = ðer3_netdev_ops; dev->watchdog_timeo = 5 * HZ / 100; ret = register_netdev(dev); diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c index 2d81f6afcb5..5425ab0c38c 100644 --- a/drivers/net/atarilance.c +++ b/drivers/net/atarilance.c @@ -453,6 +453,16 @@ static noinline int __init addr_accessible(volatile void *regp, int wordflag, return( ret ); } +static const struct net_device_ops lance_netdev_ops = { + .ndo_open = lance_open, + .ndo_stop = lance_close, + .ndo_start_xmit = lance_start_xmit, + .ndo_set_multicast_list = set_multicast_list, + .ndo_set_mac_address = lance_set_mac_address, + .ndo_tx_timeout = lance_tx_timeout, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = eth_change_mtu, +}; static unsigned long __init lance_probe1( struct net_device *dev, struct lance_addr *init_rec ) @@ -623,15 +633,9 @@ static unsigned long __init lance_probe1( struct net_device *dev, if (did_version++ == 0) DPRINTK( 1, ( version )); - /* The LANCE-specific entries in the device structure. */ - dev->open = &lance_open; - dev->hard_start_xmit = &lance_start_xmit; - dev->stop = &lance_close; - dev->set_multicast_list = &set_multicast_list; - dev->set_mac_address = &lance_set_mac_address; + dev->netdev_ops = &lance_netdev_ops; /* XXX MSch */ - dev->tx_timeout = lance_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; return( 1 ); diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c index 4274e4ac963..d58c105fc77 100644 --- a/drivers/net/au1000_eth.c +++ b/drivers/net/au1000_eth.c @@ -1004,12 +1004,12 @@ static void au1000_tx_timeout(struct net_device *dev) netif_wake_queue(dev); } -static void set_rx_mode(struct net_device *dev) +static void au1000_multicast_list(struct net_device *dev) { struct au1000_private *aup = netdev_priv(dev); if (au1000_debug > 4) - printk("%s: set_rx_mode: flags=%x\n", dev->name, dev->flags); + printk("%s: au1000_multicast_list: flags=%x\n", dev->name, dev->flags); if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ aup->mac->control |= MAC_PROMISCUOUS; @@ -1047,6 +1047,18 @@ static int au1000_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) return phy_mii_ioctl(aup->phy_dev, if_mii(rq), cmd); } +static const struct net_device_ops au1000_netdev_ops = { + .ndo_open = au1000_open, + .ndo_stop = au1000_close, + .ndo_start_xmit = au1000_tx, + .ndo_set_multicast_list = au1000_multicast_list, + .ndo_do_ioctl = au1000_ioctl, + .ndo_tx_timeout = au1000_tx_timeout, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = eth_change_mtu, +}; + static struct net_device * au1000_probe(int port_num) { static unsigned version_printed = 0; @@ -1197,13 +1209,8 @@ static struct net_device * au1000_probe(int port_num) dev->base_addr = base; dev->irq = irq; - dev->open = au1000_open; - dev->hard_start_xmit = au1000_tx; - dev->stop = au1000_close; - dev->set_multicast_list = &set_rx_mode; - dev->do_ioctl = &au1000_ioctl; + dev->netdev_ops = &au1000_netdev_ops; SET_ETHTOOL_OPS(dev, &au1000_ethtool_ops); - dev->tx_timeout = au1000_tx_timeout; dev->watchdog_timeo = ETH_TX_TIMEOUT; /* diff --git a/drivers/net/benet/be_ethtool.c b/drivers/net/benet/be_ethtool.c index 04f4b73fa8d..9592f22e4c8 100644 --- a/drivers/net/benet/be_ethtool.c +++ b/drivers/net/benet/be_ethtool.c @@ -319,7 +319,7 @@ be_get_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *ecmd) be_cmd_get_flow_control(&adapter->ctrl, &ecmd->tx_pause, &ecmd->rx_pause); - ecmd->autoneg = AUTONEG_ENABLE; + ecmd->autoneg = 0; } static int @@ -328,7 +328,7 @@ be_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *ecmd) struct be_adapter *adapter = netdev_priv(netdev); int status; - if (ecmd->autoneg != AUTONEG_ENABLE) + if (ecmd->autoneg != 0) return -EINVAL; status = be_cmd_set_flow_control(&adapter->ctrl, ecmd->tx_pause, diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c index 9afe8092dfc..9f971ed6b58 100644 --- a/drivers/net/bfin_mac.c +++ b/drivers/net/bfin_mac.c @@ -979,6 +979,20 @@ static int bfin_mac_open(struct net_device *dev) return 0; } +static const struct net_device_ops bfin_mac_netdev_ops = { + .ndo_open = bfin_mac_open, + .ndo_stop = bfin_mac_close, + .ndo_start_xmit = bfin_mac_hard_start_xmit, + .ndo_set_mac_address = bfin_mac_set_mac_address, + .ndo_tx_timeout = bfin_mac_timeout, + .ndo_set_multicast_list = bfin_mac_set_multicast_list, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = eth_change_mtu, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = bfin_mac_poll, +#endif +}; + /* * * this makes the board clean up everything that it can @@ -1086,15 +1100,7 @@ static int __devinit bfin_mac_probe(struct platform_device *pdev) /* Fill in the fields of the device structure with ethernet values. */ ether_setup(ndev); - ndev->open = bfin_mac_open; - ndev->stop = bfin_mac_close; - ndev->hard_start_xmit = bfin_mac_hard_start_xmit; - ndev->set_mac_address = bfin_mac_set_mac_address; - ndev->tx_timeout = bfin_mac_timeout; - ndev->set_multicast_list = bfin_mac_set_multicast_list; -#ifdef CONFIG_NET_POLL_CONTROLLER - ndev->poll_controller = bfin_mac_poll; -#endif + ndev->netdev_ops = &bfin_mac_netdev_ops; ndev->ethtool_ops = &bfin_mac_ethtool_ops; spin_lock_init(&lp->lock); diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index 8dc6fbb9a41..553a8991977 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -370,8 +370,6 @@ static int rlb_arp_recv(struct sk_buff *skb, struct net_device *bond_dev, struct if (arp->op_code == htons(ARPOP_REPLY)) { /* update rx hash table for this ARP */ - printk("rar: update orig %s bond_dev %s\n", orig_dev->name, - bond_dev->name); bond = netdev_priv(bond_dev); rlb_update_entry_from_arp(bond, arp); pr_debug("Server received an ARP Reply from client\n"); diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 99610f358c4..63369b6b14d 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -2570,7 +2570,7 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave) for (i = 0; (i < BOND_MAX_ARP_TARGETS); i++) { if (!targets[i]) - continue; + break; pr_debug("basa: target %x\n", targets[i]); if (list_empty(&bond->vlan_list)) { pr_debug("basa: empty vlan: arp_send\n"); @@ -2677,7 +2677,6 @@ static void bond_validate_arp(struct bonding *bond, struct slave *slave, __be32 int i; __be32 *targets = bond->params.arp_targets; - targets = bond->params.arp_targets; for (i = 0; (i < BOND_MAX_ARP_TARGETS) && targets[i]; i++) { pr_debug("bva: sip %pI4 tip %pI4 t[%d] %pI4 bhti(tip) %d\n", &sip, &tip, i, &targets[i], bond_has_this_ip(bond, tip)); @@ -3303,7 +3302,7 @@ static void bond_info_show_master(struct seq_file *seq) for(i = 0; (i < BOND_MAX_ARP_TARGETS) ;i++) { if (!bond->params.arp_targets[i]) - continue; + break; if (printed) seq_printf(seq, ","); seq_printf(seq, " %pI4", &bond->params.arp_targets[i]); diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index 18cf4787874..d2873153522 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -684,17 +684,15 @@ static ssize_t bonding_store_arp_targets(struct device *d, goto out; } /* look for an empty slot to put the target in, and check for dupes */ - for (i = 0; (i < BOND_MAX_ARP_TARGETS); i++) { + for (i = 0; (i < BOND_MAX_ARP_TARGETS) && !done; i++) { if (targets[i] == newtarget) { /* duplicate */ printk(KERN_ERR DRV_NAME ": %s: ARP target %pI4 is already present\n", bond->dev->name, &newtarget); - if (done) - targets[i] = 0; ret = -EINVAL; goto out; } - if (targets[i] == 0 && !done) { + if (targets[i] == 0) { printk(KERN_INFO DRV_NAME ": %s: adding ARP target %pI4.\n", bond->dev->name, &newtarget); @@ -720,12 +718,16 @@ static ssize_t bonding_store_arp_targets(struct device *d, goto out; } - for (i = 0; (i < BOND_MAX_ARP_TARGETS); i++) { + for (i = 0; (i < BOND_MAX_ARP_TARGETS) && !done; i++) { if (targets[i] == newtarget) { + int j; printk(KERN_INFO DRV_NAME ": %s: removing ARP target %pI4.\n", bond->dev->name, &newtarget); - targets[i] = 0; + for (j = i; (j < (BOND_MAX_ARP_TARGETS-1)) && targets[j+1]; j++) + targets[j] = targets[j+1]; + + targets[j] = 0; done = 1; } } diff --git a/drivers/net/cris/eth_v10.c b/drivers/net/cris/eth_v10.c index c9806c58b2f..7a18dc7e5c7 100644 --- a/drivers/net/cris/eth_v10.c +++ b/drivers/net/cris/eth_v10.c @@ -257,6 +257,23 @@ struct transceiver_ops transceivers[] = struct transceiver_ops* transceiver = &transceivers[0]; +static const struct net_device_ops e100_netdev_ops = { + .ndo_open = e100_open, + .ndo_stop = e100_close, + .ndo_start_xmit = e100_send_packet, + .ndo_tx_timeout = e100_tx_timeout, + .ndo_get_stats = e100_get_stats, + .ndo_set_multicast_list = set_multicast_list, + .ndo_do_ioctl = e100_ioctl, + .ndo_set_mac_address = e100_set_mac_address, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = eth_change_mtu, + .ndo_set_config = e100_set_config, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = e100_netpoll, +#endif +}; + #define tx_done(dev) (*R_DMA_CH0_CMD == 0) /* @@ -300,19 +317,8 @@ etrax_ethernet_init(void) /* fill in our handlers so the network layer can talk to us in the future */ - dev->open = e100_open; - dev->hard_start_xmit = e100_send_packet; - dev->stop = e100_close; - dev->get_stats = e100_get_stats; - dev->set_multicast_list = set_multicast_list; - dev->set_mac_address = e100_set_mac_address; dev->ethtool_ops = &e100_ethtool_ops; - dev->do_ioctl = e100_ioctl; - dev->set_config = e100_set_config; - dev->tx_timeout = e100_tx_timeout; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = e100_netpoll; -#endif + dev->netdev_ops = &e100_netdev_ops; spin_lock_init(&np->lock); spin_lock_init(&np->led_lock); diff --git a/drivers/net/declance.c b/drivers/net/declance.c index 861c867fca8..b62405a6918 100644 --- a/drivers/net/declance.c +++ b/drivers/net/declance.c @@ -1010,6 +1010,17 @@ static void lance_set_multicast_retry(unsigned long _opaque) lance_set_multicast(dev); } +static const struct net_device_ops lance_netdev_ops = { + .ndo_open = lance_open, + .ndo_stop = lance_close, + .ndo_start_xmit = lance_start_xmit, + .ndo_tx_timeout = lance_tx_timeout, + .ndo_set_multicast_list = lance_set_multicast, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, +}; + static int __init dec_lance_probe(struct device *bdev, const int type) { static unsigned version_printed; @@ -1223,12 +1234,8 @@ static int __init dec_lance_probe(struct device *bdev, const int type) printk(", addr = %pM, irq = %d\n", dev->dev_addr, dev->irq); - dev->open = &lance_open; - dev->stop = &lance_close; - dev->hard_start_xmit = &lance_start_xmit; - dev->tx_timeout = &lance_tx_timeout; + dev->netdev_ops = &lance_netdev_ops; dev->watchdog_timeo = 5*HZ; - dev->set_multicast_list = &lance_set_multicast; /* lp->ll is the location of the registers for lance card */ lp->ll = ll; diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index ddc5c533e89..ef12931d302 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -156,8 +156,8 @@ static void e1000_vlan_rx_add_vid(struct net_device *netdev, u16 vid); static void e1000_vlan_rx_kill_vid(struct net_device *netdev, u16 vid); static void e1000_restore_vlan(struct e1000_adapter *adapter); -static int e1000_suspend(struct pci_dev *pdev, pm_message_t state); #ifdef CONFIG_PM +static int e1000_suspend(struct pci_dev *pdev, pm_message_t state); static int e1000_resume(struct pci_dev *pdev); #endif static void e1000_shutdown(struct pci_dev *pdev); @@ -3834,7 +3834,7 @@ static bool e1000_clean_tx_irq(struct e1000_adapter *adapter, struct e1000_buffer *buffer_info; unsigned int i, eop; unsigned int count = 0; - bool cleaned; + bool cleaned = false; unsigned int total_tx_bytes=0, total_tx_packets=0; i = tx_ring->next_to_clean; @@ -4601,7 +4601,7 @@ int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx) return 0; } -static int e1000_suspend(struct pci_dev *pdev, pm_message_t state) +static int __e1000_shutdown(struct pci_dev *pdev, bool *enable_wake) { struct net_device *netdev = pci_get_drvdata(pdev); struct e1000_adapter *adapter = netdev_priv(netdev); @@ -4664,22 +4664,18 @@ static int e1000_suspend(struct pci_dev *pdev, pm_message_t state) ew32(WUC, E1000_WUC_PME_EN); ew32(WUFC, wufc); - pci_enable_wake(pdev, PCI_D3hot, 1); - pci_enable_wake(pdev, PCI_D3cold, 1); } else { ew32(WUC, 0); ew32(WUFC, 0); - pci_enable_wake(pdev, PCI_D3hot, 0); - pci_enable_wake(pdev, PCI_D3cold, 0); } e1000_release_manageability(adapter); + *enable_wake = !!wufc; + /* make sure adapter isn't asleep if manageability is enabled */ - if (adapter->en_mng_pt) { - pci_enable_wake(pdev, PCI_D3hot, 1); - pci_enable_wake(pdev, PCI_D3cold, 1); - } + if (adapter->en_mng_pt) + *enable_wake = true; if (hw->phy_type == e1000_phy_igp_3) e1000_phy_powerdown_workaround(hw); @@ -4693,12 +4689,29 @@ static int e1000_suspend(struct pci_dev *pdev, pm_message_t state) pci_disable_device(pdev); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); - return 0; } #ifdef CONFIG_PM +static int e1000_suspend(struct pci_dev *pdev, pm_message_t state) +{ + int retval; + bool wake; + + retval = __e1000_shutdown(pdev, &wake); + if (retval) + return retval; + + if (wake) { + pci_prepare_to_sleep(pdev); + } else { + pci_wake_from_d3(pdev, false); + pci_set_power_state(pdev, PCI_D3hot); + } + + return 0; +} + static int e1000_resume(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); @@ -4753,7 +4766,14 @@ static int e1000_resume(struct pci_dev *pdev) static void e1000_shutdown(struct pci_dev *pdev) { - e1000_suspend(pdev, PMSG_SUSPEND); + bool wake; + + __e1000_shutdown(pdev, &wake); + + if (system_state == SYSTEM_POWER_OFF) { + pci_wake_from_d3(pdev, wake); + pci_set_power_state(pdev, PCI_D3hot); + } } #ifdef CONFIG_NET_POLL_CONTROLLER diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 409b58cad0e..1693ed116b1 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -621,7 +621,7 @@ static bool e1000_clean_tx_irq(struct e1000_adapter *adapter) struct e1000_buffer *buffer_info; unsigned int i, eop; unsigned int count = 0; - bool cleaned; + bool cleaned = false; unsigned int total_tx_bytes = 0, total_tx_packets = 0; i = tx_ring->next_to_clean; @@ -4346,7 +4346,7 @@ static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) } } -static int e1000_suspend(struct pci_dev *pdev, pm_message_t state) +static int __e1000_shutdown(struct pci_dev *pdev, bool *enable_wake) { struct net_device *netdev = pci_get_drvdata(pdev); struct e1000_adapter *adapter = netdev_priv(netdev); @@ -4409,20 +4409,16 @@ static int e1000_suspend(struct pci_dev *pdev, pm_message_t state) ew32(WUC, E1000_WUC_PME_EN); ew32(WUFC, wufc); - pci_enable_wake(pdev, PCI_D3hot, 1); - pci_enable_wake(pdev, PCI_D3cold, 1); } else { ew32(WUC, 0); ew32(WUFC, 0); - pci_enable_wake(pdev, PCI_D3hot, 0); - pci_enable_wake(pdev, PCI_D3cold, 0); } + *enable_wake = !!wufc; + /* make sure adapter isn't asleep if manageability is enabled */ - if (adapter->flags & FLAG_MNG_PT_ENABLED) { - pci_enable_wake(pdev, PCI_D3hot, 1); - pci_enable_wake(pdev, PCI_D3cold, 1); - } + if (adapter->flags & FLAG_MNG_PT_ENABLED) + *enable_wake = true; if (adapter->hw.phy.type == e1000_phy_igp_3) e1000e_igp3_phy_powerdown_workaround_ich8lan(&adapter->hw); @@ -4435,6 +4431,26 @@ static int e1000_suspend(struct pci_dev *pdev, pm_message_t state) pci_disable_device(pdev); + return 0; +} + +static void e1000_power_off(struct pci_dev *pdev, bool sleep, bool wake) +{ + if (sleep && wake) { + pci_prepare_to_sleep(pdev); + return; + } + + pci_wake_from_d3(pdev, wake); + pci_set_power_state(pdev, PCI_D3hot); +} + +static void e1000_complete_shutdown(struct pci_dev *pdev, bool sleep, + bool wake) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct e1000_adapter *adapter = netdev_priv(netdev); + /* * The pci-e switch on some quad port adapters will report a * correctable error when the MAC transitions from D0 to D3. To @@ -4450,14 +4466,12 @@ static int e1000_suspend(struct pci_dev *pdev, pm_message_t state) pci_write_config_word(us_dev, pos + PCI_EXP_DEVCTL, (devctl & ~PCI_EXP_DEVCTL_CERE)); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); + e1000_power_off(pdev, sleep, wake); pci_write_config_word(us_dev, pos + PCI_EXP_DEVCTL, devctl); } else { - pci_set_power_state(pdev, pci_choose_state(pdev, state)); + e1000_power_off(pdev, sleep, wake); } - - return 0; } static void e1000e_disable_l1aspm(struct pci_dev *pdev) @@ -4486,6 +4500,18 @@ static void e1000e_disable_l1aspm(struct pci_dev *pdev) } #ifdef CONFIG_PM +static int e1000_suspend(struct pci_dev *pdev, pm_message_t state) +{ + int retval; + bool wake; + + retval = __e1000_shutdown(pdev, &wake); + if (!retval) + e1000_complete_shutdown(pdev, true, wake); + + return retval; +} + static int e1000_resume(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); @@ -4549,7 +4575,12 @@ static int e1000_resume(struct pci_dev *pdev) static void e1000_shutdown(struct pci_dev *pdev) { - e1000_suspend(pdev, PMSG_SUSPEND); + bool wake = false; + + __e1000_shutdown(pdev, &wake); + + if (system_state == SYSTEM_POWER_OFF) + e1000_complete_shutdown(pdev, false, wake); } #ifdef CONFIG_NET_POLL_CONTROLLER diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index ac0c5b438e0..604c844d076 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -3080,7 +3080,8 @@ static const struct net_device_ops ehea_netdev_ops = { .ndo_change_mtu = ehea_change_mtu, .ndo_vlan_rx_register = ehea_vlan_rx_register, .ndo_vlan_rx_add_vid = ehea_vlan_rx_add_vid, - .ndo_vlan_rx_kill_vid = ehea_vlan_rx_kill_vid + .ndo_vlan_rx_kill_vid = ehea_vlan_rx_kill_vid, + .ndo_tx_timeout = ehea_tx_watchdog, }; struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter, @@ -3142,7 +3143,6 @@ struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter, | NETIF_F_HIGHDMA | NETIF_F_IP_CSUM | NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER | NETIF_F_LLTX; - dev->tx_timeout = &ehea_tx_watchdog; dev->watchdog_timeo = EHEA_WATCH_DOG_TIMEOUT; INIT_WORK(&port->reset_task, ehea_reset_port); diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index d37465020bc..11d5db16ed9 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -3745,14 +3745,14 @@ static int nv_napi_poll(struct napi_struct *napi, int budget) mod_timer(&np->nic_poll, jiffies + POLL_WAIT); } spin_unlock_irqrestore(&np->lock, flags); - __napi_complete(napi); + napi_complete(napi); return rx_work; } if (rx_work < budget) { /* re-enable interrupts (msix not enabled in napi) */ - __napi_complete(napi); + napi_complete(napi); writel(np->irqmask, base + NvRegIrqMask); } diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c index b037ce9857b..a9cbc3191a2 100644 --- a/drivers/net/fs_enet/fs_enet-main.c +++ b/drivers/net/fs_enet/fs_enet-main.c @@ -1019,6 +1019,22 @@ out_put_phy: #define IS_FEC(match) 0 #endif +static const struct net_device_ops fs_enet_netdev_ops = { + .ndo_open = fs_enet_open, + .ndo_stop = fs_enet_close, + .ndo_get_stats = fs_enet_get_stats, + .ndo_start_xmit = fs_enet_start_xmit, + .ndo_tx_timeout = fs_timeout, + .ndo_set_multicast_list = fs_set_multicast_list, + .ndo_do_ioctl = fs_ioctl, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, + .ndo_change_mtu = eth_change_mtu, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = fs_enet_netpoll, +#endif +}; + static int __devinit fs_enet_probe(struct of_device *ofdev, const struct of_device_id *match) { @@ -1093,22 +1109,13 @@ static int __devinit fs_enet_probe(struct of_device *ofdev, fep->tx_ring = fpi->tx_ring; fep->rx_ring = fpi->rx_ring; - ndev->open = fs_enet_open; - ndev->hard_start_xmit = fs_enet_start_xmit; - ndev->tx_timeout = fs_timeout; + ndev->netdev_ops = &fs_enet_netdev_ops; ndev->watchdog_timeo = 2 * HZ; - ndev->stop = fs_enet_close; - ndev->get_stats = fs_enet_get_stats; - ndev->set_multicast_list = fs_set_multicast_list; -#ifdef CONFIG_NET_POLL_CONTROLLER - ndev->poll_controller = fs_enet_netpoll; -#endif if (fpi->use_napi) netif_napi_add(ndev, &fep->napi, fs_enet_rx_napi, fpi->napi_weight); ndev->ethtool_ops = &fs_ethtool_ops; - ndev->do_ioctl = fs_ioctl; init_timer(&fep->phy_timer_list); diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 65f55877be9..b2c49679bba 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -1583,8 +1583,10 @@ static void gfar_reset_task(struct work_struct *work) struct net_device *dev = priv->ndev; if (dev->flags & IFF_UP) { + netif_stop_queue(dev); stop_gfar(dev); startup_gfar(dev); + netif_start_queue(dev); } netif_tx_schedule_all(dev); diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c index 77e4b5b52fc..806533c831c 100644 --- a/drivers/net/ibm_newemac/core.c +++ b/drivers/net/ibm_newemac/core.c @@ -2686,6 +2686,32 @@ static int __devinit emac_init_config(struct emac_instance *dev) return 0; } +static const struct net_device_ops emac_netdev_ops = { + .ndo_open = emac_open, + .ndo_stop = emac_close, + .ndo_get_stats = emac_stats, + .ndo_set_multicast_list = emac_set_multicast_list, + .ndo_do_ioctl = emac_ioctl, + .ndo_tx_timeout = emac_tx_timeout, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, + .ndo_start_xmit = emac_start_xmit, + .ndo_change_mtu = eth_change_mtu, +}; + +static const struct net_device_ops emac_gige_netdev_ops = { + .ndo_open = emac_open, + .ndo_stop = emac_close, + .ndo_get_stats = emac_stats, + .ndo_set_multicast_list = emac_set_multicast_list, + .ndo_do_ioctl = emac_ioctl, + .ndo_tx_timeout = emac_tx_timeout, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, + .ndo_start_xmit = emac_start_xmit_sg, + .ndo_change_mtu = emac_change_mtu, +}; + static int __devinit emac_probe(struct of_device *ofdev, const struct of_device_id *match) { @@ -2827,23 +2853,14 @@ static int __devinit emac_probe(struct of_device *ofdev, if (err != 0) goto err_detach_tah; - /* Fill in the driver function table */ - ndev->open = &emac_open; if (dev->tah_dev) ndev->features |= NETIF_F_IP_CSUM | NETIF_F_SG; - ndev->tx_timeout = &emac_tx_timeout; ndev->watchdog_timeo = 5 * HZ; - ndev->stop = &emac_close; - ndev->get_stats = &emac_stats; - ndev->set_multicast_list = &emac_set_multicast_list; - ndev->do_ioctl = &emac_ioctl; if (emac_phy_supports_gige(dev->phy_mode)) { - ndev->hard_start_xmit = &emac_start_xmit_sg; - ndev->change_mtu = &emac_change_mtu; + ndev->netdev_ops = &emac_gige_netdev_ops; dev->commac.ops = &emac_commac_sg_ops; - } else { - ndev->hard_start_xmit = &emac_start_xmit; - } + } else + ndev->netdev_ops = &emac_netdev_ops; SET_ETHTOOL_OPS(ndev, &emac_ethtool_ops); netif_carrier_off(ndev); diff --git a/drivers/net/igb/e1000_mac.c b/drivers/net/igb/e1000_mac.c index f4c315b5a90..472f3f12484 100644 --- a/drivers/net/igb/e1000_mac.c +++ b/drivers/net/igb/e1000_mac.c @@ -111,7 +111,7 @@ void igb_clear_vfta(struct e1000_hw *hw) * Writes value at the given offset in the register array which stores * the VLAN filter table. **/ -void igb_write_vfta(struct e1000_hw *hw, u32 offset, u32 value) +static void igb_write_vfta(struct e1000_hw *hw, u32 offset, u32 value) { array_wr32(E1000_VFTA, offset, value); wrfl(); diff --git a/drivers/net/igb/e1000_mac.h b/drivers/net/igb/e1000_mac.h index a34de526963..1d690b4c9ae 100644 --- a/drivers/net/igb/e1000_mac.h +++ b/drivers/net/igb/e1000_mac.h @@ -66,7 +66,6 @@ void igb_rar_set(struct e1000_hw *hw, u8 *addr, u32 index); s32 igb_check_alt_mac_addr(struct e1000_hw *hw); void igb_reset_adaptive(struct e1000_hw *hw); void igb_update_adaptive(struct e1000_hw *hw); -void igb_write_vfta(struct e1000_hw *hw, u32 offset, u32 value); bool igb_enable_mng_pass_thru(struct e1000_hw *hw); diff --git a/drivers/net/igb/e1000_mbx.c b/drivers/net/igb/e1000_mbx.c index fe71c7ddaa0..840782fb573 100644 --- a/drivers/net/igb/e1000_mbx.c +++ b/drivers/net/igb/e1000_mbx.c @@ -188,7 +188,7 @@ out: * returns SUCCESS if it successfully received a message notification and * copied it into the receive buffer. **/ -s32 igb_read_posted_mbx(struct e1000_hw *hw, u32 *msg, u16 size, u16 mbx_id) +static s32 igb_read_posted_mbx(struct e1000_hw *hw, u32 *msg, u16 size, u16 mbx_id) { struct e1000_mbx_info *mbx = &hw->mbx; s32 ret_val = -E1000_ERR_MBX; @@ -214,7 +214,7 @@ out: * returns SUCCESS if it successfully copied message into the buffer and * received an ack to that message within delay * timeout period **/ -s32 igb_write_posted_mbx(struct e1000_hw *hw, u32 *msg, u16 size, u16 mbx_id) +static s32 igb_write_posted_mbx(struct e1000_hw *hw, u32 *msg, u16 size, u16 mbx_id) { struct e1000_mbx_info *mbx = &hw->mbx; s32 ret_val = 0; @@ -232,19 +232,6 @@ out: return ret_val; } -/** - * e1000_init_mbx_ops_generic - Initialize NVM function pointers - * @hw: pointer to the HW structure - * - * Setups up the function pointers to no-op functions - **/ -void e1000_init_mbx_ops_generic(struct e1000_hw *hw) -{ - struct e1000_mbx_info *mbx = &hw->mbx; - mbx->ops.read_posted = igb_read_posted_mbx; - mbx->ops.write_posted = igb_write_posted_mbx; -} - static s32 igb_check_for_bit_pf(struct e1000_hw *hw, u32 mask) { u32 mbvficr = rd32(E1000_MBVFICR); diff --git a/drivers/net/igb/e1000_mbx.h b/drivers/net/igb/e1000_mbx.h index 6ec9890a8f7..ebc02ea3f19 100644 --- a/drivers/net/igb/e1000_mbx.h +++ b/drivers/net/igb/e1000_mbx.h @@ -67,8 +67,6 @@ s32 igb_read_mbx(struct e1000_hw *, u32 *, u16, u16); s32 igb_write_mbx(struct e1000_hw *, u32 *, u16, u16); -s32 igb_read_posted_mbx(struct e1000_hw *, u32 *, u16, u16); -s32 igb_write_posted_mbx(struct e1000_hw *, u32 *, u16, u16); s32 igb_check_for_msg(struct e1000_hw *, u16); s32 igb_check_for_ack(struct e1000_hw *, u16); s32 igb_check_for_rst(struct e1000_hw *, u16); diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index db7274e6222..08c801490c7 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -1261,25 +1261,32 @@ static int __devinit igb_probe(struct pci_dev *pdev, int i; unsigned char mac_addr[ETH_ALEN]; - if (num_vfs) + if (num_vfs) { adapter->vf_data = kcalloc(num_vfs, sizeof(struct vf_data_storage), GFP_KERNEL); - if (!adapter->vf_data) { - dev_err(&pdev->dev, "Could not allocate VF private " - "data - IOV enable failed\n"); - } else { - err = pci_enable_sriov(pdev, num_vfs); - if (!err) { - adapter->vfs_allocated_count = num_vfs; - dev_info(&pdev->dev, "%d vfs allocated\n", num_vfs); - for (i = 0; i < adapter->vfs_allocated_count; i++) { - random_ether_addr(mac_addr); - igb_set_vf_mac(adapter, i, mac_addr); - } + if (!adapter->vf_data) { + dev_err(&pdev->dev, + "Could not allocate VF private data - " + "IOV enable failed\n"); } else { - kfree(adapter->vf_data); - adapter->vf_data = NULL; + err = pci_enable_sriov(pdev, num_vfs); + if (!err) { + adapter->vfs_allocated_count = num_vfs; + dev_info(&pdev->dev, + "%d vfs allocated\n", + num_vfs); + for (i = 0; + i < adapter->vfs_allocated_count; + i++) { + random_ether_addr(mac_addr); + igb_set_vf_mac(adapter, i, + mac_addr); + } + } else { + kfree(adapter->vf_data); + adapter->vf_data = NULL; + } } } } diff --git a/drivers/net/igbvf/igbvf.h b/drivers/net/igbvf/igbvf.h index 936ed2a9435..4bff35e4687 100644 --- a/drivers/net/igbvf/igbvf.h +++ b/drivers/net/igbvf/igbvf.h @@ -321,14 +321,11 @@ extern void igbvf_set_ethtool_ops(struct net_device *); extern int igbvf_up(struct igbvf_adapter *); extern void igbvf_down(struct igbvf_adapter *); extern void igbvf_reinit_locked(struct igbvf_adapter *); -extern void igbvf_reset(struct igbvf_adapter *); extern int igbvf_setup_rx_resources(struct igbvf_adapter *, struct igbvf_ring *); extern int igbvf_setup_tx_resources(struct igbvf_adapter *, struct igbvf_ring *); extern void igbvf_free_rx_resources(struct igbvf_ring *); extern void igbvf_free_tx_resources(struct igbvf_ring *); extern void igbvf_update_stats(struct igbvf_adapter *); -extern void igbvf_set_interrupt_capability(struct igbvf_adapter *); -extern void igbvf_reset_interrupt_capability(struct igbvf_adapter *); extern unsigned int copybreak; diff --git a/drivers/net/igbvf/netdev.c b/drivers/net/igbvf/netdev.c index c5648420ded..b774666ad3c 100644 --- a/drivers/net/igbvf/netdev.c +++ b/drivers/net/igbvf/netdev.c @@ -52,6 +52,9 @@ static const char igbvf_driver_string[] = static const char igbvf_copyright[] = "Copyright (c) 2009 Intel Corporation."; static int igbvf_poll(struct napi_struct *napi, int budget); +static void igbvf_reset(struct igbvf_adapter *); +static void igbvf_set_interrupt_capability(struct igbvf_adapter *); +static void igbvf_reset_interrupt_capability(struct igbvf_adapter *); static struct igbvf_info igbvf_vf_info = { .mac = e1000_vfadapt, @@ -990,7 +993,7 @@ static void igbvf_configure_msix(struct igbvf_adapter *adapter) e1e_flush(); } -void igbvf_reset_interrupt_capability(struct igbvf_adapter *adapter) +static void igbvf_reset_interrupt_capability(struct igbvf_adapter *adapter) { if (adapter->msix_entries) { pci_disable_msix(adapter->pdev); @@ -1005,7 +1008,7 @@ void igbvf_reset_interrupt_capability(struct igbvf_adapter *adapter) * Attempt to configure interrupts using the best available * capabilities of the hardware and kernel. **/ -void igbvf_set_interrupt_capability(struct igbvf_adapter *adapter) +static void igbvf_set_interrupt_capability(struct igbvf_adapter *adapter) { int err = -ENOMEM; int i; @@ -1447,7 +1450,7 @@ static void igbvf_configure(struct igbvf_adapter *adapter) * set/changed during runtime. After reset the device needs to be * properly configured for Rx, Tx etc. */ -void igbvf_reset(struct igbvf_adapter *adapter) +static void igbvf_reset(struct igbvf_adapter *adapter) { struct e1000_mac_info *mac = &adapter->hw.mac; struct net_device *netdev = adapter->netdev; diff --git a/drivers/net/igbvf/vf.c b/drivers/net/igbvf/vf.c index aa246c93279..2a4faf9ade6 100644 --- a/drivers/net/igbvf/vf.c +++ b/drivers/net/igbvf/vf.c @@ -44,7 +44,7 @@ static s32 e1000_set_vfta_vf(struct e1000_hw *, u16, bool); * e1000_init_mac_params_vf - Inits MAC params * @hw: pointer to the HW structure **/ -s32 e1000_init_mac_params_vf(struct e1000_hw *hw) +static s32 e1000_init_mac_params_vf(struct e1000_hw *hw) { struct e1000_mac_info *mac = &hw->mac; diff --git a/drivers/net/igbvf/vf.h b/drivers/net/igbvf/vf.h index ec07228f947..1e8ce3741a6 100644 --- a/drivers/net/igbvf/vf.h +++ b/drivers/net/igbvf/vf.h @@ -259,7 +259,6 @@ struct e1000_hw { /* These functions must be implemented by drivers */ void e1000_rlpml_set_vf(struct e1000_hw *, u16); void e1000_init_function_pointers_vf(struct e1000_hw *hw); -s32 e1000_init_mac_params_vf(struct e1000_hw *hw); #endif /* _E1000_VF_H_ */ diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c index cbc63ff13ad..c5593f4665a 100644 --- a/drivers/net/ioc3-eth.c +++ b/drivers/net/ioc3-eth.c @@ -1214,6 +1214,19 @@ static void __devinit ioc3_serial_probe(struct pci_dev *pdev, struct ioc3 *ioc3) } #endif +static const struct net_device_ops ioc3_netdev_ops = { + .ndo_open = ioc3_open, + .ndo_stop = ioc3_close, + .ndo_start_xmit = ioc3_start_xmit, + .ndo_tx_timeout = ioc3_timeout, + .ndo_get_stats = ioc3_get_stats, + .ndo_set_multicast_list = ioc3_set_multicast_list, + .ndo_do_ioctl = ioc3_ioctl, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = ioc3_set_mac_address, + .ndo_change_mtu = eth_change_mtu, +}; + static int __devinit ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -1310,15 +1323,8 @@ static int __devinit ioc3_probe(struct pci_dev *pdev, ioc3_get_eaddr(ip); /* The IOC3-specific entries in the device structure. */ - dev->open = ioc3_open; - dev->hard_start_xmit = ioc3_start_xmit; - dev->tx_timeout = ioc3_timeout; dev->watchdog_timeo = 5 * HZ; - dev->stop = ioc3_close; - dev->get_stats = ioc3_get_stats; - dev->do_ioctl = ioc3_ioctl; - dev->set_multicast_list = ioc3_set_multicast_list; - dev->set_mac_address = ioc3_set_mac_address; + dev->netdev_ops = &ioc3_netdev_ops; dev->ethtool_ops = &ioc3_ethtool_ops; dev->features = NETIF_F_IP_CSUM; diff --git a/drivers/net/isa-skeleton.c b/drivers/net/isa-skeleton.c index 3126678bdd3..73585fd8f29 100644 --- a/drivers/net/isa-skeleton.c +++ b/drivers/net/isa-skeleton.c @@ -181,6 +181,18 @@ out: } #endif +static const struct net_device_ops netcard_netdev_ops = { + .ndo_open = net_open, + .ndo_stop = net_close, + .ndo_start_xmit = net_send_packet, + .ndo_get_stats = net_get_stats, + .ndo_set_multicast_list = set_multicast_list, + .ndo_tx_timeout = net_tx_timeout, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, + .ndo_change_mtu = eth_change_mtu, +}; + /* * This is the real probe routine. Linux has a history of friendly device * probes on the ISA bus. A good device probes avoids doing writes, and @@ -303,13 +315,7 @@ static int __init netcard_probe1(struct net_device *dev, int ioaddr) np = netdev_priv(dev); spin_lock_init(&np->lock); - dev->open = net_open; - dev->stop = net_close; - dev->hard_start_xmit = net_send_packet; - dev->get_stats = net_get_stats; - dev->set_multicast_list = &set_multicast_list; - - dev->tx_timeout = &net_tx_timeout; + dev->netdev_ops = &netcard_netdev_ops; dev->watchdog_timeo = MY_TX_TIMEOUT; err = register_netdev(dev); diff --git a/drivers/net/ixgbe/ixgbe_82598.c b/drivers/net/ixgbe/ixgbe_82598.c index de4db0dc787..4791238c3f6 100644 --- a/drivers/net/ixgbe/ixgbe_82598.c +++ b/drivers/net/ixgbe/ixgbe_82598.c @@ -885,61 +885,6 @@ static s32 ixgbe_clear_vfta_82598(struct ixgbe_hw *hw) } /** - * ixgbe_blink_led_start_82598 - Blink LED based on index. - * @hw: pointer to hardware structure - * @index: led number to blink - **/ -static s32 ixgbe_blink_led_start_82598(struct ixgbe_hw *hw, u32 index) -{ - ixgbe_link_speed speed = 0; - bool link_up = 0; - u32 autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC); - u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL); - - /* - * Link must be up to auto-blink the LEDs on the 82598EB MAC; - * force it if link is down. - */ - hw->mac.ops.check_link(hw, &speed, &link_up, false); - - if (!link_up) { - autoc_reg |= IXGBE_AUTOC_FLU; - IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg); - msleep(10); - } - - led_reg &= ~IXGBE_LED_MODE_MASK(index); - led_reg |= IXGBE_LED_BLINK(index); - IXGBE_WRITE_REG(hw, IXGBE_LEDCTL, led_reg); - IXGBE_WRITE_FLUSH(hw); - - return 0; -} - -/** - * ixgbe_blink_led_stop_82598 - Stop blinking LED based on index. - * @hw: pointer to hardware structure - * @index: led number to stop blinking - **/ -static s32 ixgbe_blink_led_stop_82598(struct ixgbe_hw *hw, u32 index) -{ - u32 autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC); - u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL); - - autoc_reg &= ~IXGBE_AUTOC_FLU; - autoc_reg |= IXGBE_AUTOC_AN_RESTART; - IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg); - - led_reg &= ~IXGBE_LED_MODE_MASK(index); - led_reg &= ~IXGBE_LED_BLINK(index); - led_reg |= IXGBE_LED_LINK_ACTIVE << IXGBE_LED_MODE_SHIFT(index); - IXGBE_WRITE_REG(hw, IXGBE_LEDCTL, led_reg); - IXGBE_WRITE_FLUSH(hw); - - return 0; -} - -/** * ixgbe_read_analog_reg8_82598 - Reads 8 bit Atlas analog register * @hw: pointer to hardware structure * @reg: analog register to read @@ -1128,8 +1073,8 @@ static struct ixgbe_mac_operations mac_ops_82598 = { .get_link_capabilities = &ixgbe_get_link_capabilities_82598, .led_on = &ixgbe_led_on_generic, .led_off = &ixgbe_led_off_generic, - .blink_led_start = &ixgbe_blink_led_start_82598, - .blink_led_stop = &ixgbe_blink_led_stop_82598, + .blink_led_start = &ixgbe_blink_led_start_generic, + .blink_led_stop = &ixgbe_blink_led_stop_generic, .set_rar = &ixgbe_set_rar_generic, .clear_rar = &ixgbe_clear_rar_generic, .set_vmdq = &ixgbe_set_vmdq_82598, diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c index beae7e01260..29771fbaa42 100644 --- a/drivers/net/ixgbe/ixgbe_82599.c +++ b/drivers/net/ixgbe/ixgbe_82599.c @@ -68,8 +68,6 @@ s32 ixgbe_clear_vmdq_82599(struct ixgbe_hw *hw, u32 rar, u32 vmdq); s32 ixgbe_set_vfta_82599(struct ixgbe_hw *hw, u32 vlan, u32 vind, bool vlan_on); s32 ixgbe_clear_vfta_82599(struct ixgbe_hw *hw); -s32 ixgbe_blink_led_stop_82599(struct ixgbe_hw *hw, u32 index); -s32 ixgbe_blink_led_start_82599(struct ixgbe_hw *hw, u32 index); s32 ixgbe_init_uta_tables_82599(struct ixgbe_hw *hw); s32 ixgbe_read_analog_reg8_82599(struct ixgbe_hw *hw, u32 reg, u8 *val); s32 ixgbe_write_analog_reg8_82599(struct ixgbe_hw *hw, u32 reg, u8 val); @@ -991,40 +989,6 @@ s32 ixgbe_clear_vfta_82599(struct ixgbe_hw *hw) } /** - * ixgbe_blink_led_start_82599 - Blink LED based on index. - * @hw: pointer to hardware structure - * @index: led number to blink - **/ -s32 ixgbe_blink_led_start_82599(struct ixgbe_hw *hw, u32 index) -{ - u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL); - - led_reg &= ~IXGBE_LED_MODE_MASK(index); - led_reg |= IXGBE_LED_BLINK(index); - IXGBE_WRITE_REG(hw, IXGBE_LEDCTL, led_reg); - IXGBE_WRITE_FLUSH(hw); - - return 0; -} - -/** - * ixgbe_blink_led_stop_82599 - Stop blinking LED based on index. - * @hw: pointer to hardware structure - * @index: led number to stop blinking - **/ -s32 ixgbe_blink_led_stop_82599(struct ixgbe_hw *hw, u32 index) -{ - u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL); - - led_reg &= ~IXGBE_LED_MODE_MASK(index); - led_reg &= ~IXGBE_LED_BLINK(index); - IXGBE_WRITE_REG(hw, IXGBE_LEDCTL, led_reg); - IXGBE_WRITE_FLUSH(hw); - - return 0; -} - -/** * ixgbe_init_uta_tables_82599 - Initialize the Unicast Table Array * @hw: pointer to hardware structure **/ @@ -1243,8 +1207,8 @@ static struct ixgbe_mac_operations mac_ops_82599 = { .get_link_capabilities = &ixgbe_get_link_capabilities_82599, .led_on = &ixgbe_led_on_generic, .led_off = &ixgbe_led_off_generic, - .blink_led_start = &ixgbe_blink_led_start_82599, - .blink_led_stop = &ixgbe_blink_led_stop_82599, + .blink_led_start = &ixgbe_blink_led_start_generic, + .blink_led_stop = &ixgbe_blink_led_stop_generic, .set_rar = &ixgbe_set_rar_generic, .clear_rar = &ixgbe_clear_rar_generic, .set_vmdq = &ixgbe_set_vmdq_82599, diff --git a/drivers/net/ixgbe/ixgbe_common.c b/drivers/net/ixgbe/ixgbe_common.c index 63ab6671d08..5567519676d 100644 --- a/drivers/net/ixgbe/ixgbe_common.c +++ b/drivers/net/ixgbe/ixgbe_common.c @@ -2071,3 +2071,58 @@ s32 ixgbe_enable_rx_dma_generic(struct ixgbe_hw *hw, u32 regval) return 0; } + +/** + * ixgbe_blink_led_start_generic - Blink LED based on index. + * @hw: pointer to hardware structure + * @index: led number to blink + **/ +s32 ixgbe_blink_led_start_generic(struct ixgbe_hw *hw, u32 index) +{ + ixgbe_link_speed speed = 0; + bool link_up = 0; + u32 autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC); + u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL); + + /* + * Link must be up to auto-blink the LEDs; + * Force it if link is down. + */ + hw->mac.ops.check_link(hw, &speed, &link_up, false); + + if (!link_up) { + autoc_reg |= IXGBE_AUTOC_FLU; + IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg); + msleep(10); + } + + led_reg &= ~IXGBE_LED_MODE_MASK(index); + led_reg |= IXGBE_LED_BLINK(index); + IXGBE_WRITE_REG(hw, IXGBE_LEDCTL, led_reg); + IXGBE_WRITE_FLUSH(hw); + + return 0; +} + +/** + * ixgbe_blink_led_stop_generic - Stop blinking LED based on index. + * @hw: pointer to hardware structure + * @index: led number to stop blinking + **/ +s32 ixgbe_blink_led_stop_generic(struct ixgbe_hw *hw, u32 index) +{ + u32 autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC); + u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL); + + autoc_reg &= ~IXGBE_AUTOC_FLU; + autoc_reg |= IXGBE_AUTOC_AN_RESTART; + IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg); + + led_reg &= ~IXGBE_LED_MODE_MASK(index); + led_reg &= ~IXGBE_LED_BLINK(index); + led_reg |= IXGBE_LED_LINK_ACTIVE << IXGBE_LED_MODE_SHIFT(index); + IXGBE_WRITE_REG(hw, IXGBE_LEDCTL, led_reg); + IXGBE_WRITE_FLUSH(hw); + + return 0; +} diff --git a/drivers/net/ixgbe/ixgbe_common.h b/drivers/net/ixgbe/ixgbe_common.h index 24f73e719c3..dd260890ad0 100644 --- a/drivers/net/ixgbe/ixgbe_common.h +++ b/drivers/net/ixgbe/ixgbe_common.h @@ -76,6 +76,9 @@ s32 ixgbe_disable_pcie_master(struct ixgbe_hw *hw); s32 ixgbe_read_analog_reg8_generic(struct ixgbe_hw *hw, u32 reg, u8 *val); s32 ixgbe_write_analog_reg8_generic(struct ixgbe_hw *hw, u32 reg, u8 val); +s32 ixgbe_blink_led_start_generic(struct ixgbe_hw *hw, u32 index); +s32 ixgbe_blink_led_stop_generic(struct ixgbe_hw *hw, u32 index); + #define IXGBE_WRITE_REG(a, reg, value) writel((value), ((a)->hw_addr + (reg))) #ifndef writeq diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index aafc120f164..f0a20facc65 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -943,6 +943,24 @@ static void ixgbe_get_strings(struct net_device *netdev, u32 stringset, } +static int ixgbe_wol_exclusion(struct ixgbe_adapter *adapter, + struct ethtool_wolinfo *wol) +{ + struct ixgbe_hw *hw = &adapter->hw; + int retval = 1; + + switch(hw->device_id) { + case IXGBE_DEV_ID_82599_KX4: + retval = 0; + break; + default: + wol->supported = 0; + retval = 0; + } + + return retval; +} + static void ixgbe_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) { @@ -952,7 +970,8 @@ static void ixgbe_get_wol(struct net_device *netdev, WAKE_BCAST | WAKE_MAGIC; wol->wolopts = 0; - if (!device_can_wakeup(&adapter->pdev->dev)) + if (ixgbe_wol_exclusion(adapter, wol) || + !device_can_wakeup(&adapter->pdev->dev)) return; if (adapter->wol & IXGBE_WUFC_EX) @@ -974,6 +993,9 @@ static int ixgbe_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) if (wol->wolopts & (WAKE_PHY | WAKE_ARP | WAKE_MAGICSECURE)) return -EOPNOTSUPP; + if (ixgbe_wol_exclusion(adapter, wol)) + return wol->wolopts ? -EOPNOTSUPP : 0; + adapter->wol = 0; if (wol->wolopts & WAKE_UCAST) diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 9ef128ae645..febde45cf9f 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -2723,17 +2723,21 @@ static inline bool ixgbe_set_rss_queues(struct ixgbe_adapter *adapter) **/ static void ixgbe_set_num_queues(struct ixgbe_adapter *adapter) { - /* Start with base case */ - adapter->num_rx_queues = 1; - adapter->num_tx_queues = 1; - #ifdef CONFIG_IXGBE_DCB if (ixgbe_set_dcb_queues(adapter)) - return; + goto done; #endif if (ixgbe_set_rss_queues(adapter)) - return; + goto done; + + /* fallback to base case */ + adapter->num_rx_queues = 1; + adapter->num_tx_queues = 1; + +done: + /* Notify the stack of the (possibly) reduced Tx Queue count. */ + adapter->netdev->real_num_tx_queues = adapter->num_tx_queues; } static void ixgbe_acquire_msix_vectors(struct ixgbe_adapter *adapter, @@ -2992,9 +2996,6 @@ try_msi: } out: - /* Notify the stack of the (possibly) reduced Tx Queue count. */ - adapter->netdev->real_num_tx_queues = adapter->num_tx_queues; - return err; } @@ -3611,9 +3612,9 @@ static int ixgbe_resume(struct pci_dev *pdev) return 0; } - #endif /* CONFIG_PM */ -static int ixgbe_suspend(struct pci_dev *pdev, pm_message_t state) + +static int __ixgbe_shutdown(struct pci_dev *pdev, bool *enable_wake) { struct net_device *netdev = pci_get_drvdata(pdev); struct ixgbe_adapter *adapter = netdev_priv(netdev); @@ -3672,18 +3673,46 @@ static int ixgbe_suspend(struct pci_dev *pdev, pm_message_t state) pci_enable_wake(pdev, PCI_D3cold, 0); } + *enable_wake = !!wufc; + ixgbe_release_hw_control(adapter); pci_disable_device(pdev); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); + return 0; +} + +#ifdef CONFIG_PM +static int ixgbe_suspend(struct pci_dev *pdev, pm_message_t state) +{ + int retval; + bool wake; + + retval = __ixgbe_shutdown(pdev, &wake); + if (retval) + return retval; + + if (wake) { + pci_prepare_to_sleep(pdev); + } else { + pci_wake_from_d3(pdev, false); + pci_set_power_state(pdev, PCI_D3hot); + } return 0; } +#endif /* CONFIG_PM */ static void ixgbe_shutdown(struct pci_dev *pdev) { - ixgbe_suspend(pdev, PMSG_SUSPEND); + bool wake; + + __ixgbe_shutdown(pdev, &wake); + + if (system_state == SYSTEM_POWER_OFF) { + pci_wake_from_d3(pdev, wake); + pci_set_power_state(pdev, PCI_D3hot); + } } /** @@ -4342,7 +4371,7 @@ static int ixgbe_xmit_frame(struct sk_buff *skb, struct net_device *netdev) int count = 0; unsigned int f; - r_idx = (adapter->num_tx_queues - 1) & skb->queue_mapping; + r_idx = skb->queue_mapping; tx_ring = &adapter->tx_ring[r_idx]; if (adapter->vlgrp && vlan_tx_tag_present(skb)) { diff --git a/drivers/net/mac89x0.c b/drivers/net/mac89x0.c index 380a1a54d53..384e072de2e 100644 --- a/drivers/net/mac89x0.c +++ b/drivers/net/mac89x0.c @@ -168,6 +168,17 @@ writereg(struct net_device *dev, int portno, int value) nubus_writew(swab16(value), dev->mem_start + portno); } +static const struct net_device_ops mac89x0_netdev_ops = { + .ndo_open = net_open, + .ndo_stop = net_close, + .ndo_start_xmit = net_send_packet, + .ndo_get_stats = net_get_stats, + .ndo_set_multicast_list = set_multicast_list, + .ndo_set_mac_address = set_mac_address, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = eth_change_mtu, +}; + /* Probe for the CS8900 card in slot E. We won't bother looking anywhere else until we have a really good reason to do so. */ struct net_device * __init mac89x0_probe(int unit) @@ -280,12 +291,7 @@ struct net_device * __init mac89x0_probe(int unit) printk(" IRQ %d ADDR %pM\n", dev->irq, dev->dev_addr); - dev->open = net_open; - dev->stop = net_close; - dev->hard_start_xmit = net_send_packet; - dev->get_stats = net_get_stats; - dev->set_multicast_list = &set_multicast_list; - dev->set_mac_address = &set_mac_address; + dev->netdev_ops = &mac89x0_netdev_ops; err = register_netdev(dev); if (err) diff --git a/drivers/net/macb.c b/drivers/net/macb.c index f50501013b1..46073de290c 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -1100,6 +1100,18 @@ static int macb_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) return phy_mii_ioctl(phydev, if_mii(rq), cmd); } +static const struct net_device_ops macb_netdev_ops = { + .ndo_open = macb_open, + .ndo_stop = macb_close, + .ndo_start_xmit = macb_start_xmit, + .ndo_set_multicast_list = macb_set_rx_mode, + .ndo_get_stats = macb_get_stats, + .ndo_do_ioctl = macb_ioctl, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = eth_change_mtu, + .ndo_set_mac_address = eth_mac_addr, +}; + static int __init macb_probe(struct platform_device *pdev) { struct eth_platform_data *pdata; @@ -1175,12 +1187,7 @@ static int __init macb_probe(struct platform_device *pdev) goto err_out_iounmap; } - dev->open = macb_open; - dev->stop = macb_close; - dev->hard_start_xmit = macb_start_xmit; - dev->get_stats = macb_get_stats; - dev->set_multicast_list = macb_set_rx_mode; - dev->do_ioctl = macb_ioctl; + dev->netdev_ops = &macb_netdev_ops; netif_napi_add(dev, &bp->napi, macb_poll, 64); dev->ethtool_ops = &macb_ethtool_ops; diff --git a/drivers/net/macsonic.c b/drivers/net/macsonic.c index 527166e35d5..acd143da161 100644 --- a/drivers/net/macsonic.c +++ b/drivers/net/macsonic.c @@ -167,6 +167,18 @@ static int macsonic_close(struct net_device* dev) return err; } +static const struct net_device_ops macsonic_netdev_ops = { + .ndo_open = macsonic_open, + .ndo_stop = macsonic_close, + .ndo_start_xmit = sonic_send_packet, + .ndo_set_multicast_list = sonic_multicast_list, + .ndo_tx_timeout = sonic_tx_timeout, + .ndo_get_stats = sonic_get_stats, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = eth_change_mtu, + .ndo_set_mac_address = eth_mac_addr, +}; + static int __init macsonic_init(struct net_device *dev) { struct sonic_local* lp = netdev_priv(dev); @@ -198,12 +210,7 @@ static int __init macsonic_init(struct net_device *dev) lp->rra_laddr = lp->rda_laddr + (SIZEOF_SONIC_RD * SONIC_NUM_RDS * SONIC_BUS_SCALE(lp->dma_bitmode)); - dev->open = macsonic_open; - dev->stop = macsonic_close; - dev->hard_start_xmit = sonic_send_packet; - dev->get_stats = sonic_get_stats; - dev->set_multicast_list = &sonic_multicast_list; - dev->tx_timeout = sonic_tx_timeout; + dev->netdev_ops = &macsonic_netdev_ops; dev->watchdog_timeo = TX_TIMEOUT; /* diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index 9eed126a82f..f2c4a665e93 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -2447,6 +2447,7 @@ static int myri10ge_open(struct net_device *dev) lro_mgr->lro_arr = ss->rx_done.lro_desc; lro_mgr->get_frag_header = myri10ge_get_frag_header; lro_mgr->max_aggr = myri10ge_lro_max_pkts; + lro_mgr->frag_align_pad = 2; if (lro_mgr->max_aggr > MAX_SKB_FRAGS) lro_mgr->max_aggr = MAX_SKB_FRAGS; diff --git a/drivers/net/phy/fixed.c b/drivers/net/phy/fixed.c index cf24cc34deb..e7070515d2e 100644 --- a/drivers/net/phy/fixed.c +++ b/drivers/net/phy/fixed.c @@ -19,6 +19,7 @@ #include <linux/mii.h> #include <linux/phy.h> #include <linux/phy_fixed.h> +#include <linux/err.h> #define MII_REGS_NUM 29 @@ -207,8 +208,8 @@ static int __init fixed_mdio_bus_init(void) int ret; pdev = platform_device_register_simple("Fixed MDIO bus", 0, NULL, 0); - if (!pdev) { - ret = -ENOMEM; + if (IS_ERR(pdev)) { + ret = PTR_ERR(pdev); goto err_pdev; } diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index eb6411c4694..7a3ec9d39a9 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -69,6 +69,11 @@ #define MII_M1111_COPPER 0 #define MII_M1111_FIBER 1 +#define MII_88E1121_PHY_LED_CTRL 16 +#define MII_88E1121_PHY_LED_PAGE 3 +#define MII_88E1121_PHY_LED_DEF 0x0030 +#define MII_88E1121_PHY_PAGE 22 + #define MII_M1011_PHY_STATUS 0x11 #define MII_M1011_PHY_STATUS_1000 0x8000 #define MII_M1011_PHY_STATUS_100 0x4000 @@ -154,6 +159,30 @@ static int marvell_config_aneg(struct phy_device *phydev) return err; } +static int m88e1121_config_aneg(struct phy_device *phydev) +{ + int err, temp; + + err = phy_write(phydev, MII_BMCR, BMCR_RESET); + if (err < 0) + return err; + + err = phy_write(phydev, MII_M1011_PHY_SCR, + MII_M1011_PHY_SCR_AUTO_CROSS); + if (err < 0) + return err; + + temp = phy_read(phydev, MII_88E1121_PHY_PAGE); + + phy_write(phydev, MII_88E1121_PHY_PAGE, MII_88E1121_PHY_LED_PAGE); + phy_write(phydev, MII_88E1121_PHY_LED_CTRL, MII_88E1121_PHY_LED_DEF); + phy_write(phydev, MII_88E1121_PHY_PAGE, temp); + + err = genphy_config_aneg(phydev); + + return err; +} + static int m88e1111_config_init(struct phy_device *phydev) { int err; @@ -429,6 +458,18 @@ static int marvell_read_status(struct phy_device *phydev) return 0; } +static int m88e1121_did_interrupt(struct phy_device *phydev) +{ + int imask; + + imask = phy_read(phydev, MII_M1011_IEVENT); + + if (imask & MII_M1011_IMASK_INIT) + return 1; + + return 0; +} + static struct phy_driver marvell_drivers[] = { { .phy_id = 0x01410c60, @@ -482,6 +523,19 @@ static struct phy_driver marvell_drivers[] = { .driver = {.owner = THIS_MODULE,}, }, { + .phy_id = 0x01410cb0, + .phy_id_mask = 0xfffffff0, + .name = "Marvell 88E1121R", + .features = PHY_GBIT_FEATURES, + .flags = PHY_HAS_INTERRUPT, + .config_aneg = &m88e1121_config_aneg, + .read_status = &marvell_read_status, + .ack_interrupt = &marvell_ack_interrupt, + .config_intr = &marvell_config_intr, + .did_interrupt = &m88e1121_did_interrupt, + .driver = { .owner = THIS_MODULE }, + }, + { .phy_id = 0x01410cd0, .phy_id_mask = 0xfffffff0, .name = "Marvell 88E1145", diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 3ff1f425f1b..61755cbd978 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -434,7 +434,7 @@ void phy_start_machine(struct phy_device *phydev, phydev->adjust_state = handler; INIT_DELAYED_WORK(&phydev->state_queue, phy_state_machine); - schedule_delayed_work(&phydev->state_queue, jiffies + HZ); + schedule_delayed_work(&phydev->state_queue, HZ); } /** @@ -655,6 +655,10 @@ static void phy_change(struct work_struct *work) struct phy_device *phydev = container_of(work, struct phy_device, phy_queue); + if (phydev->drv->did_interrupt && + !phydev->drv->did_interrupt(phydev)) + goto ignore; + err = phy_disable_interrupts(phydev); if (err) @@ -681,6 +685,11 @@ static void phy_change(struct work_struct *work) return; +ignore: + atomic_dec(&phydev->irq_disable); + enable_irq(phydev->irq); + return; + irq_enable_err: disable_irq(phydev->irq); atomic_inc(&phydev->irq_disable); @@ -937,6 +946,5 @@ static void phy_state_machine(struct work_struct *work) if (err < 0) phy_error(phydev); - schedule_delayed_work(&phydev->state_queue, - jiffies + PHY_STATE_TIME * HZ); + schedule_delayed_work(&phydev->state_queue, PHY_STATE_TIME * HZ); } diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index dee23b159df..7269a426051 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -448,9 +448,6 @@ static void efx_init_channels(struct efx_nic *efx) WARN_ON(channel->rx_pkt != NULL); efx_rx_strategy(channel); - - netif_napi_add(channel->napi_dev, &channel->napi_str, - efx_poll, napi_weight); } } @@ -1321,6 +1318,8 @@ static int efx_init_napi(struct efx_nic *efx) efx_for_each_channel(channel, efx) { channel->napi_dev = efx->net_dev; + netif_napi_add(channel->napi_dev, &channel->napi_str, + efx_poll, napi_weight); } return 0; } @@ -1330,6 +1329,8 @@ static void efx_fini_napi(struct efx_nic *efx) struct efx_channel *channel; efx_for_each_channel(channel, efx) { + if (channel->napi_dev) + netif_napi_del(&channel->napi_str); channel->napi_dev = NULL; } } diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index d4629ab2c61..466a8abb005 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c @@ -1176,9 +1176,9 @@ void falcon_sim_phy_event(struct efx_nic *efx) EFX_POPULATE_QWORD_1(phy_event, EV_CODE, GLOBAL_EV_DECODE); if (EFX_IS10G(efx)) - EFX_SET_OWORD_FIELD(phy_event, XG_PHY_INTR, 1); + EFX_SET_QWORD_FIELD(phy_event, XG_PHY_INTR, 1); else - EFX_SET_OWORD_FIELD(phy_event, G_PHY0_INTR, 1); + EFX_SET_QWORD_FIELD(phy_event, G_PHY0_INTR, 1); falcon_generate_event(&efx->channel[0], &phy_event); } diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c index 7b1882765a0..3ab28bb00c1 100644 --- a/drivers/net/sh_eth.c +++ b/drivers/net/sh_eth.c @@ -1188,6 +1188,19 @@ out: return ret; } +static const struct net_device_ops sh_eth_netdev_ops = { + .ndo_open = sh_eth_open, + .ndo_stop = sh_eth_close, + .ndo_start_xmit = sh_eth_start_xmit, + .ndo_get_stats = sh_eth_get_stats, + .ndo_set_multicast_list = sh_eth_set_multicast_list, + .ndo_tx_timeout = sh_eth_tx_timeout, + .ndo_do_ioctl = sh_eth_do_ioctl, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, + .ndo_change_mtu = eth_change_mtu, +}; + static int sh_eth_drv_probe(struct platform_device *pdev) { int ret, i, devno = 0; @@ -1240,13 +1253,7 @@ static int sh_eth_drv_probe(struct platform_device *pdev) mdp->edmac_endian = pd->edmac_endian; /* set function */ - ndev->open = sh_eth_open; - ndev->hard_start_xmit = sh_eth_start_xmit; - ndev->stop = sh_eth_close; - ndev->get_stats = sh_eth_get_stats; - ndev->set_multicast_list = sh_eth_set_multicast_list; - ndev->do_ioctl = sh_eth_do_ioctl; - ndev->tx_timeout = sh_eth_tx_timeout; + ndev->netdev_ops = &sh_eth_netdev_ops; ndev->watchdog_timeo = TX_TIMEOUT; mdp->post_rx = POST_RX >> (devno << 1); diff --git a/drivers/net/skge.c b/drivers/net/skge.c index b8978d4af1b..c11cdd08ec5 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -2674,7 +2674,7 @@ static int skge_down(struct net_device *dev) if (netif_msg_ifdown(skge)) printk(KERN_INFO PFX "%s: disabling interface\n", dev->name); - netif_stop_queue(dev); + netif_tx_disable(dev); if (hw->chip_id == CHIP_ID_GENESIS && hw->phy_type == SK_PHY_XMAC) del_timer_sync(&skge->link_timer); @@ -2881,7 +2881,6 @@ static void skge_tx_clean(struct net_device *dev) } skge->tx_ring.to_clean = e; - netif_wake_queue(dev); } static void skge_tx_timeout(struct net_device *dev) @@ -2893,6 +2892,7 @@ static void skge_tx_timeout(struct net_device *dev) skge_write8(skge->hw, Q_ADDR(txqaddr[skge->port], Q_CSR), CSR_STOP); skge_tx_clean(dev); + netif_wake_queue(dev); } static int skge_change_mtu(struct net_device *dev, int new_mtu) diff --git a/drivers/net/sun3_82586.c b/drivers/net/sun3_82586.c index e0d84772771..a39c0b9ba8b 100644 --- a/drivers/net/sun3_82586.c +++ b/drivers/net/sun3_82586.c @@ -331,6 +331,18 @@ out: return ERR_PTR(err); } +static const struct net_device_ops sun3_82586_netdev_ops = { + .ndo_open = sun3_82586_open, + .ndo_stop = sun3_82586_close, + .ndo_start_xmit = sun3_82586_send_packet, + .ndo_set_multicast_list = set_multicast_list, + .ndo_tx_timeout = sun3_82586_timeout, + .ndo_get_stats = sun3_82586_get_stats, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, + .ndo_change_mtu = eth_change_mtu, +}; + static int __init sun3_82586_probe1(struct net_device *dev,int ioaddr) { int i, size, retval; @@ -381,13 +393,8 @@ static int __init sun3_82586_probe1(struct net_device *dev,int ioaddr) printk("Memaddr: 0x%lx, Memsize: %d, IRQ %d\n",dev->mem_start,size, dev->irq); - dev->open = sun3_82586_open; - dev->stop = sun3_82586_close; - dev->get_stats = sun3_82586_get_stats; - dev->tx_timeout = sun3_82586_timeout; + dev->netdev_ops = &sun3_82586_netdev_ops; dev->watchdog_timeo = HZ/20; - dev->hard_start_xmit = sun3_82586_send_packet; - dev->set_multicast_list = set_multicast_list; dev->if_port = 0; return 0; diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c index d91e95b237b..0ce2db6ce2b 100644 --- a/drivers/net/tc35815.c +++ b/drivers/net/tc35815.c @@ -862,6 +862,22 @@ static int __devinit tc35815_init_dev_addr(struct net_device *dev) return 0; } +static const struct net_device_ops tc35815_netdev_ops = { + .ndo_open = tc35815_open, + .ndo_stop = tc35815_close, + .ndo_start_xmit = tc35815_send_packet, + .ndo_get_stats = tc35815_get_stats, + .ndo_set_multicast_list = tc35815_set_multicast_list, + .ndo_tx_timeout = tc35815_tx_timeout, + .ndo_do_ioctl = tc35815_ioctl, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = eth_change_mtu, + .ndo_set_mac_address = eth_mac_addr, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = tc35815_poll_controller, +#endif +}; + static int __devinit tc35815_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -904,21 +920,12 @@ static int __devinit tc35815_init_one(struct pci_dev *pdev, ioaddr = pcim_iomap_table(pdev)[1]; /* Initialize the device structure. */ - dev->open = tc35815_open; - dev->hard_start_xmit = tc35815_send_packet; - dev->stop = tc35815_close; - dev->get_stats = tc35815_get_stats; - dev->set_multicast_list = tc35815_set_multicast_list; - dev->do_ioctl = tc35815_ioctl; + dev->netdev_ops = &tc35815_netdev_ops; dev->ethtool_ops = &tc35815_ethtool_ops; - dev->tx_timeout = tc35815_tx_timeout; dev->watchdog_timeo = TC35815_TX_TIMEOUT; #ifdef TC35815_NAPI netif_napi_add(dev, &lp->napi, tc35815_poll, NAPI_WEIGHT); #endif -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = tc35815_poll_controller; -#endif dev->irq = pdev->irq; dev->base_addr = (unsigned long)ioaddr; diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 6a736dda3ee..7a837c46596 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -12443,8 +12443,13 @@ static int __devinit tg3_get_device_address(struct tg3 *tp) /* Next, try NVRAM. */ if (!tg3_nvram_read_be32(tp, mac_offset + 0, &hi) && !tg3_nvram_read_be32(tp, mac_offset + 4, &lo)) { - memcpy(&dev->dev_addr[0], ((char *)&hi) + 2, 2); - memcpy(&dev->dev_addr[2], (char *)&lo, sizeof(lo)); + dev->dev_addr[0] = ((hi >> 16) & 0xff); + dev->dev_addr[1] = ((hi >> 24) & 0xff); + dev->dev_addr[2] = ((lo >> 0) & 0xff); + dev->dev_addr[3] = ((lo >> 8) & 0xff); + dev->dev_addr[4] = ((lo >> 16) & 0xff); + dev->dev_addr[5] = ((lo >> 24) & 0xff); + } /* Finally just fetch it out of the MAC control regs. */ else { diff --git a/drivers/net/tsi108_eth.c b/drivers/net/tsi108_eth.c index bb43e7fb2a5..0f78f99f9b2 100644 --- a/drivers/net/tsi108_eth.c +++ b/drivers/net/tsi108_eth.c @@ -1561,6 +1561,18 @@ static const struct ethtool_ops tsi108_ethtool_ops = { .set_settings = tsi108_set_settings, }; +static const struct net_device_ops tsi108_netdev_ops = { + .ndo_open = tsi108_open, + .ndo_stop = tsi108_close, + .ndo_start_xmit = tsi108_send_packet, + .ndo_set_multicast_list = tsi108_set_rx_mode, + .ndo_get_stats = tsi108_get_stats, + .ndo_do_ioctl = tsi108_do_ioctl, + .ndo_set_mac_address = tsi108_set_mac, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = eth_change_mtu, +}; + static int tsi108_init_one(struct platform_device *pdev) { @@ -1616,14 +1628,8 @@ tsi108_init_one(struct platform_device *pdev) data->phy_type = einfo->phy_type; data->irq_num = einfo->irq_num; data->id = pdev->id; - dev->open = tsi108_open; - dev->stop = tsi108_close; - dev->hard_start_xmit = tsi108_send_packet; - dev->set_mac_address = tsi108_set_mac; - dev->set_multicast_list = tsi108_set_rx_mode; - dev->get_stats = tsi108_get_stats; netif_napi_add(dev, &data->napi, tsi108_poll, 64); - dev->do_ioctl = tsi108_do_ioctl; + dev->netdev_ops = &tsi108_netdev_ops; dev->ethtool_ops = &tsi108_ethtool_ops; /* Apparently, the Linux networking code won't use scatter-gather diff --git a/drivers/net/tun.c b/drivers/net/tun.c index a1b0697340b..16716aef184 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -518,7 +518,7 @@ static inline struct sk_buff *tun_alloc_skb(struct tun_struct *tun, int err; /* Under a page? Don't bother with paged skb. */ - if (prepad + len < PAGE_SIZE) + if (prepad + len < PAGE_SIZE || !linear) linear = len; skb = sock_alloc_send_pskb(sk, prepad + linear, len - linear, noblock, @@ -565,7 +565,8 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun, if ((tun->flags & TUN_TYPE_MASK) == TUN_TAP_DEV) { align = NET_IP_ALIGN; - if (unlikely(len < ETH_HLEN)) + if (unlikely(len < ETH_HLEN || + (gso.hdr_len && gso.hdr_len < ETH_HLEN))) return -EINVAL; } diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index fb53ef872df..754a4b182c1 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -377,7 +377,7 @@ static void velocity_print_info(struct velocity_info *vptr); static int velocity_open(struct net_device *dev); static int velocity_change_mtu(struct net_device *dev, int mtu); static int velocity_xmit(struct sk_buff *skb, struct net_device *dev); -static int velocity_intr(int irq, void *dev_instance); +static irqreturn_t velocity_intr(int irq, void *dev_instance); static void velocity_set_multi(struct net_device *dev); static struct net_device_stats *velocity_get_stats(struct net_device *dev); static int velocity_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); @@ -2215,7 +2215,7 @@ out: * efficiently as possible. */ -static int velocity_intr(int irq, void *dev_instance) +static irqreturn_t velocity_intr(int irq, void *dev_instance) { struct net_device *dev = dev_instance; struct velocity_info *vptr = netdev_priv(dev); diff --git a/drivers/net/xtsonic.c b/drivers/net/xtsonic.c index a12a7211c98..5a4ad156f63 100644 --- a/drivers/net/xtsonic.c +++ b/drivers/net/xtsonic.c @@ -108,6 +108,18 @@ static int xtsonic_close(struct net_device *dev) return err; } +static const struct net_device_ops xtsonic_netdev_ops = { + .ndo_open = xtsonic_open, + .ndo_stop = xtsonic_close, + .ndo_start_xmit = sonic_send_packet, + .ndo_get_stats = sonic_get_stats, + .ndo_set_multicast_list = sonic_multicast_list, + .ndo_tx_timeout = sonic_tx_timeout, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = eth_change_mtu, + .ndo_set_mac_address = eth_mac_addr, +}; + static int __init sonic_probe1(struct net_device *dev) { static unsigned version_printed = 0; @@ -205,12 +217,7 @@ static int __init sonic_probe1(struct net_device *dev) lp->rra_laddr = lp->rda_laddr + (SIZEOF_SONIC_RD * SONIC_NUM_RDS * SONIC_BUS_SCALE(lp->dma_bitmode)); - dev->open = xtsonic_open; - dev->stop = xtsonic_close; - dev->hard_start_xmit = sonic_send_packet; - dev->get_stats = sonic_get_stats; - dev->set_multicast_list = &sonic_multicast_list; - dev->tx_timeout = sonic_tx_timeout; + dev->netdev_ops = &xtsonic_netdev_ops; dev->watchdog_timeo = TX_TIMEOUT; /* diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 0570794ccf1..d1815272c43 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -20,6 +20,7 @@ #include <linux/slab.h> #include <linux/buffer_head.h> #include <linux/hdreg.h> +#include <linux/async.h> #include <asm/ccwdev.h> #include <asm/ebcdic.h> @@ -480,8 +481,10 @@ static void dasd_change_state(struct dasd_device *device) if (rc && rc != -EAGAIN) device->target = device->state; - if (device->state == device->target) + if (device->state == device->target) { wake_up(&dasd_init_waitq); + dasd_put_device(device); + } /* let user-space know that the device status changed */ kobject_uevent(&device->cdev->dev.kobj, KOBJ_CHANGE); @@ -513,12 +516,15 @@ void dasd_kick_device(struct dasd_device *device) */ void dasd_set_target_state(struct dasd_device *device, int target) { + dasd_get_device(device); /* If we are in probeonly mode stop at DASD_STATE_READY. */ if (dasd_probeonly && target > DASD_STATE_READY) target = DASD_STATE_READY; if (device->target != target) { - if (device->state == target) + if (device->state == target) { wake_up(&dasd_init_waitq); + dasd_put_device(device); + } device->target = target; } if (device->state != device->target) @@ -2148,6 +2154,22 @@ dasd_exit(void) * SECTION: common functions for ccw_driver use */ +static void dasd_generic_auto_online(void *data, async_cookie_t cookie) +{ + struct ccw_device *cdev = data; + int ret; + + ret = ccw_device_set_online(cdev); + if (ret) + pr_warning("%s: Setting the DASD online failed with rc=%d\n", + dev_name(&cdev->dev), ret); + else { + struct dasd_device *device = dasd_device_from_cdev(cdev); + wait_event(dasd_init_waitq, _wait_for_device(device)); + dasd_put_device(device); + } +} + /* * Initial attempt at a probe function. this can be simplified once * the other detection code is gone. @@ -2180,10 +2202,7 @@ int dasd_generic_probe(struct ccw_device *cdev, */ if ((dasd_get_feature(cdev, DASD_FEATURE_INITIAL_ONLINE) > 0 ) || (dasd_autodetect && dasd_busid_known(dev_name(&cdev->dev)) != 0)) - ret = ccw_device_set_online(cdev); - if (ret) - pr_warning("%s: Setting the DASD online failed with rc=%d\n", - dev_name(&cdev->dev), ret); + async_schedule(dasd_generic_auto_online, cdev); return 0; } @@ -2290,13 +2309,7 @@ int dasd_generic_set_online(struct ccw_device *cdev, } else pr_debug("dasd_generic device %s found\n", dev_name(&cdev->dev)); - - /* FIXME: we have to wait for the root device but we don't want - * to wait for each single device but for all at once. */ - wait_event(dasd_init_waitq, _wait_for_device(device)); - dasd_put_device(device); - return rc; } diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 21254793c60..cb52da033f0 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -2019,15 +2019,23 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_track( ccw++; recid += count; new_track = 0; + /* first idaw for a ccw may start anywhere */ + if (!idaw_dst) + idaw_dst = dst; } - /* If we start a new idaw, everything is fine and the - * start of the new idaw is the start of this segment. + /* If we start a new idaw, we must make sure that it + * starts on an IDA_BLOCK_SIZE boundary. * If we continue an idaw, we must make sure that the * current segment begins where the so far accumulated * idaw ends */ - if (!idaw_dst) - idaw_dst = dst; + if (!idaw_dst) { + if (__pa(dst) & (IDA_BLOCK_SIZE-1)) { + dasd_sfree_request(cqr, startdev); + return ERR_PTR(-ERANGE); + } else + idaw_dst = dst; + } if ((idaw_dst + idaw_len) != dst) { dasd_sfree_request(cqr, startdev); return ERR_PTR(-ERANGE); diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 9e8a2914259..accd957454e 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -881,42 +881,6 @@ no_handler: qdio_set_state(irq_ptr, QDIO_IRQ_STATE_STOPPED); } -static void qdio_call_shutdown(struct work_struct *work) -{ - struct ccw_device_private *priv; - struct ccw_device *cdev; - - priv = container_of(work, struct ccw_device_private, kick_work); - cdev = priv->cdev; - qdio_shutdown(cdev, QDIO_FLAG_CLEANUP_USING_CLEAR); - put_device(&cdev->dev); -} - -static void qdio_int_error(struct ccw_device *cdev) -{ - struct qdio_irq *irq_ptr = cdev->private->qdio_data; - - switch (irq_ptr->state) { - case QDIO_IRQ_STATE_INACTIVE: - case QDIO_IRQ_STATE_CLEANUP: - qdio_set_state(irq_ptr, QDIO_IRQ_STATE_ERR); - break; - case QDIO_IRQ_STATE_ESTABLISHED: - case QDIO_IRQ_STATE_ACTIVE: - qdio_set_state(irq_ptr, QDIO_IRQ_STATE_STOPPED); - if (get_device(&cdev->dev)) { - /* Can't call shutdown from interrupt context. */ - PREPARE_WORK(&cdev->private->kick_work, - qdio_call_shutdown); - queue_work(ccw_device_work, &cdev->private->kick_work); - } - break; - default: - WARN_ON(1); - } - wake_up(&cdev->private->wait_q); -} - static int qdio_establish_check_errors(struct ccw_device *cdev, int cstat, int dstat) { @@ -973,10 +937,8 @@ void qdio_int_handler(struct ccw_device *cdev, unsigned long intparm, switch (PTR_ERR(irb)) { case -EIO: DBF_ERROR("%4x IO error", irq_ptr->schid.sch_no); - return; - case -ETIMEDOUT: - DBF_ERROR("%4x IO timeout", irq_ptr->schid.sch_no); - qdio_int_error(cdev); + qdio_set_state(irq_ptr, QDIO_IRQ_STATE_ERR); + wake_up(&cdev->private->wait_q); return; default: WARN_ON(1); @@ -1001,7 +963,6 @@ void qdio_int_handler(struct ccw_device *cdev, unsigned long intparm, case QDIO_IRQ_STATE_ACTIVE: if (cstat & SCHN_STAT_PCI) { qdio_int_handler_pci(irq_ptr); - /* no state change so no need to wake up wait_q */ return; } if ((cstat & ~SCHN_STAT_PCI) || dstat) { diff --git a/drivers/sbus/char/jsflash.c b/drivers/sbus/char/jsflash.c index e6d1fc8c54f..a85ad05e854 100644 --- a/drivers/sbus/char/jsflash.c +++ b/drivers/sbus/char/jsflash.c @@ -383,18 +383,22 @@ static int jsf_ioctl_program(void __user *arg) return 0; } -static int jsf_ioctl(struct inode *inode, struct file *f, unsigned int cmd, - unsigned long arg) +static long jsf_ioctl(struct file *f, unsigned int cmd, unsigned long arg) { + lock_kernel(); int error = -ENOTTY; void __user *argp = (void __user *)arg; - if (!capable(CAP_SYS_ADMIN)) + if (!capable(CAP_SYS_ADMIN)) { + unlock_kernel(); return -EPERM; + } switch (cmd) { case JSFLASH_IDENT: - if (copy_to_user(argp, &jsf0.id, JSFIDSZ)) + if (copy_to_user(argp, &jsf0.id, JSFIDSZ)) { + unlock_kernel(); return -EFAULT; + } break; case JSFLASH_ERASE: error = jsf_ioctl_erase(arg); @@ -404,6 +408,7 @@ static int jsf_ioctl(struct inode *inode, struct file *f, unsigned int cmd, break; } + unlock_kernel(); return error; } @@ -439,7 +444,7 @@ static const struct file_operations jsf_fops = { .llseek = jsf_lseek, .read = jsf_read, .write = jsf_write, - .ioctl = jsf_ioctl, + .unlocked_ioctl = jsf_ioctl, .mmap = jsf_mmap, .open = jsf_open, .release = jsf_release, diff --git a/drivers/sbus/char/uctrl.c b/drivers/sbus/char/uctrl.c index 27993c37775..2c56fd56ec6 100644 --- a/drivers/sbus/char/uctrl.c +++ b/drivers/sbus/char/uctrl.c @@ -197,9 +197,8 @@ static struct uctrl_driver { static void uctrl_get_event_status(struct uctrl_driver *); static void uctrl_get_external_status(struct uctrl_driver *); -static int -uctrl_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +static long +uctrl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { switch (cmd) { default: @@ -226,7 +225,7 @@ static irqreturn_t uctrl_interrupt(int irq, void *dev_id) static const struct file_operations uctrl_fops = { .owner = THIS_MODULE, .llseek = no_llseek, - .ioctl = uctrl_ioctl, + .unlocked_ioctl = uctrl_ioctl, .open = uctrl_open, }; diff --git a/drivers/serial/samsung.c b/drivers/serial/samsung.c index 41ac94872b8..e06686ae858 100644 --- a/drivers/serial/samsung.c +++ b/drivers/serial/samsung.c @@ -127,7 +127,7 @@ static void s3c24xx_serial_stop_tx(struct uart_port *port) struct s3c24xx_uart_port *ourport = to_ourport(port); if (tx_enabled(port)) { - disable_irq(ourport->tx_irq); + disable_irq_nosync(ourport->tx_irq); tx_enabled(port) = 0; if (port->flags & UPF_CONS_FLOW) s3c24xx_serial_rx_enable(port); @@ -154,7 +154,7 @@ static void s3c24xx_serial_stop_rx(struct uart_port *port) if (rx_enabled(port)) { dbg("s3c24xx_serial_stop_rx: port=%p\n", port); - disable_irq(ourport->rx_irq); + disable_irq_nosync(ourport->rx_irq); rx_enabled(port) = 0; } } diff --git a/drivers/spi/pxa2xx_spi.c b/drivers/spi/pxa2xx_spi.c index c1688c71f05..c76feea5fe2 100644 --- a/drivers/spi/pxa2xx_spi.c +++ b/drivers/spi/pxa2xx_spi.c @@ -195,7 +195,7 @@ static void cs_deassert(struct driver_data *drv_data) struct chip_data *chip = drv_data->cur_chip; if (chip->cs_control) { - chip->cs_control(PXA2XX_CS_ASSERT); + chip->cs_control(PXA2XX_CS_DEASSERT); return; } diff --git a/drivers/staging/android/binder.c b/drivers/staging/android/binder.c index 79e90fed27d..299d29d1dad 100644 --- a/drivers/staging/android/binder.c +++ b/drivers/staging/android/binder.c @@ -41,6 +41,8 @@ static int binder_last_id; static struct proc_dir_entry *binder_proc_dir_entry_root; static struct proc_dir_entry *binder_proc_dir_entry_proc; static struct hlist_head binder_dead_nodes; +static HLIST_HEAD(binder_deferred_list); +static DEFINE_MUTEX(binder_deferred_lock); static int binder_read_proc_proc( char *page, char **start, off_t off, int count, int *eof, void *data); @@ -54,11 +56,7 @@ static int binder_read_proc_proc( #define SZ_4M 0x400000 #endif -#ifndef __i386__ -#define FORBIDDEN_MMAP_FLAGS (VM_WRITE | VM_EXEC) -#else #define FORBIDDEN_MMAP_FLAGS (VM_WRITE) -#endif #define BINDER_SMALL_BUF_SIZE (PAGE_SIZE * 64) @@ -236,6 +234,12 @@ struct binder_buffer { uint8_t data[0]; }; +enum { + BINDER_DEFERRED_PUT_FILES = 0x01, + BINDER_DEFERRED_FLUSH = 0x02, + BINDER_DEFERRED_RELEASE = 0x04, +}; + struct binder_proc { struct hlist_node proc_node; struct rb_root threads; @@ -245,8 +249,11 @@ struct binder_proc { int pid; struct vm_area_struct *vma; struct task_struct *tsk; + struct files_struct *files; + struct hlist_node deferred_work_node; + int deferred_work; void *buffer; - size_t user_buffer_offset; + ptrdiff_t user_buffer_offset; struct list_head buffers; struct rb_root free_buffers; @@ -310,12 +317,14 @@ struct binder_transaction { uid_t sender_euid; }; +static void binder_defer_work(struct binder_proc *proc, int defer); + /* * copied from get_unused_fd_flags */ -int task_get_unused_fd_flags(struct task_struct *tsk, int flags) +int task_get_unused_fd_flags(struct binder_proc *proc, int flags) { - struct files_struct *files = get_files_struct(tsk); + struct files_struct *files = proc->files; int fd, error; struct fdtable *fdt; unsigned long rlim_cur; @@ -337,9 +346,9 @@ repeat: * will limit the total number of files that can be opened. */ rlim_cur = 0; - if (lock_task_sighand(tsk, &irqs)) { - rlim_cur = tsk->signal->rlim[RLIMIT_NOFILE].rlim_cur; - unlock_task_sighand(tsk, &irqs); + if (lock_task_sighand(proc->tsk, &irqs)) { + rlim_cur = proc->tsk->signal->rlim[RLIMIT_NOFILE].rlim_cur; + unlock_task_sighand(proc->tsk, &irqs); } if (fd >= rlim_cur) goto out; @@ -375,7 +384,6 @@ repeat: out: spin_unlock(&files->file_lock); - put_files_struct(files); return error; } @@ -383,9 +391,9 @@ out: * copied from fd_install */ static void task_fd_install( - struct task_struct *tsk, unsigned int fd, struct file *file) + struct binder_proc *proc, unsigned int fd, struct file *file) { - struct files_struct *files = get_files_struct(tsk); + struct files_struct *files = proc->files; struct fdtable *fdt; if (files == NULL) @@ -396,7 +404,6 @@ static void task_fd_install( BUG_ON(fdt->fd[fd] != NULL); rcu_assign_pointer(fdt->fd[fd], file); spin_unlock(&files->file_lock); - put_files_struct(files); } /* @@ -413,10 +420,10 @@ static void __put_unused_fd(struct files_struct *files, unsigned int fd) /* * copied from sys_close */ -static long task_close_fd(struct task_struct *tsk, unsigned int fd) +static long task_close_fd(struct binder_proc *proc, unsigned int fd) { struct file *filp; - struct files_struct *files = get_files_struct(tsk); + struct files_struct *files = proc->files; struct fdtable *fdt; int retval; @@ -443,12 +450,10 @@ static long task_close_fd(struct task_struct *tsk, unsigned int fd) retval == -ERESTART_RESTARTBLOCK)) retval = -EINTR; - put_files_struct(files); return retval; out_unlock: spin_unlock(&files->file_lock); - put_files_struct(files); return -EBADF; } @@ -618,7 +623,8 @@ static int binder_update_page_range(struct binder_proc *proc, int allocate, proc->pid, page_addr); goto err_map_kernel_failed; } - user_page_addr = (size_t)page_addr + proc->user_buffer_offset; + user_page_addr = + (uintptr_t)page_addr + proc->user_buffer_offset; ret = vm_insert_page(vma, user_page_addr, page[0]); if (ret) { printk(KERN_ERR "binder: %d: binder_alloc_buf failed " @@ -639,7 +645,7 @@ free_range: page_addr -= PAGE_SIZE) { page = &proc->pages[(page_addr - proc->buffer) / PAGE_SIZE]; if (vma) - zap_page_range(vma, (size_t)page_addr + + zap_page_range(vma, (uintptr_t)page_addr + proc->user_buffer_offset, PAGE_SIZE, NULL); err_vm_insert_page_failed: unmap_kernel_range((unsigned long)page_addr, PAGE_SIZE); @@ -720,18 +726,19 @@ static struct binder_buffer *binder_alloc_buf(struct binder_proc *proc, "er %p size %zd\n", proc->pid, size, buffer, buffer_size); has_page_addr = - (void *)(((size_t)buffer->data + buffer_size) & PAGE_MASK); + (void *)(((uintptr_t)buffer->data + buffer_size) & PAGE_MASK); if (n == NULL) { if (size + sizeof(struct binder_buffer) + 4 >= buffer_size) buffer_size = size; /* no room for other buffers */ else buffer_size = size + sizeof(struct binder_buffer); } - end_page_addr = (void *)PAGE_ALIGN((size_t)buffer->data + buffer_size); + end_page_addr = + (void *)PAGE_ALIGN((uintptr_t)buffer->data + buffer_size); if (end_page_addr > has_page_addr) end_page_addr = has_page_addr; if (binder_update_page_range(proc, 1, - (void *)PAGE_ALIGN((size_t)buffer->data), end_page_addr, NULL)) + (void *)PAGE_ALIGN((uintptr_t)buffer->data), end_page_addr, NULL)) return NULL; rb_erase(best_fit, &proc->free_buffers); @@ -762,12 +769,12 @@ static struct binder_buffer *binder_alloc_buf(struct binder_proc *proc, static void *buffer_start_page(struct binder_buffer *buffer) { - return (void *)((size_t)buffer & PAGE_MASK); + return (void *)((uintptr_t)buffer & PAGE_MASK); } static void *buffer_end_page(struct binder_buffer *buffer) { - return (void *)(((size_t)(buffer + 1) - 1) & PAGE_MASK); + return (void *)(((uintptr_t)(buffer + 1) - 1) & PAGE_MASK); } static void binder_delete_free_buffer( @@ -845,8 +852,8 @@ static void binder_free_buf( } binder_update_page_range(proc, 0, - (void *)PAGE_ALIGN((size_t)buffer->data), - (void *)(((size_t)buffer->data + buffer_size) & PAGE_MASK), + (void *)PAGE_ALIGN((uintptr_t)buffer->data), + (void *)(((uintptr_t)buffer->data + buffer_size) & PAGE_MASK), NULL); rb_erase(&buffer->rb_node, &proc->allocated_buffers); buffer->free = 1; @@ -1345,6 +1352,17 @@ binder_transaction(struct binder_proc *proc, struct binder_thread *thread, if (!(tr->flags & TF_ONE_WAY) && thread->transaction_stack) { struct binder_transaction *tmp; tmp = thread->transaction_stack; + if (tmp->to_thread != thread) { + binder_user_error("binder: %d:%d got new " + "transaction with bad transaction stack" + ", transaction %d has target %d:%d\n", + proc->pid, thread->pid, tmp->debug_id, + tmp->to_proc ? tmp->to_proc->pid : 0, + tmp->to_thread ? + tmp->to_thread->pid : 0); + return_error = BR_FAILED_REPLY; + goto err_bad_call_stack; + } while (tmp) { if (tmp->from && tmp->from->proc == target_proc) target_thread = tmp->from; @@ -1434,10 +1452,19 @@ binder_transaction(struct binder_proc *proc, struct binder_thread *thread, return_error = BR_FAILED_REPLY; goto err_copy_data_failed; } + if (!IS_ALIGNED(tr->offsets_size, sizeof(size_t))) { + binder_user_error("binder: %d:%d got transaction with " + "invalid offsets size, %zd\n", + proc->pid, thread->pid, tr->offsets_size); + return_error = BR_FAILED_REPLY; + goto err_bad_offset; + } off_end = (void *)offp + tr->offsets_size; for (; offp < off_end; offp++) { struct flat_binder_object *fp; - if (*offp > t->buffer->data_size - sizeof(*fp)) { + if (*offp > t->buffer->data_size - sizeof(*fp) || + t->buffer->data_size < sizeof(*fp) || + !IS_ALIGNED(*offp, sizeof(void *))) { binder_user_error("binder: %d:%d got transaction with " "invalid offset, %zd\n", proc->pid, thread->pid, *offp); @@ -1544,13 +1571,13 @@ binder_transaction(struct binder_proc *proc, struct binder_thread *thread, return_error = BR_FAILED_REPLY; goto err_fget_failed; } - target_fd = task_get_unused_fd_flags(target_proc->tsk, O_CLOEXEC); + target_fd = task_get_unused_fd_flags(target_proc, O_CLOEXEC); if (target_fd < 0) { fput(file); return_error = BR_FAILED_REPLY; goto err_get_unused_fd_failed; } - task_fd_install(target_proc->tsk, target_fd, file); + task_fd_install(target_proc, target_fd, file); if (binder_debug_mask & BINDER_DEBUG_TRANSACTION) printk(KERN_INFO " fd %ld -> %d\n", fp->handle, target_fd); /* TODO: fput? */ @@ -1655,7 +1682,9 @@ binder_transaction_buffer_release(struct binder_proc *proc, struct binder_buffer off_end = (void *)offp + buffer->offsets_size; for (; offp < off_end; offp++) { struct flat_binder_object *fp; - if (*offp > buffer->data_size - sizeof(*fp)) { + if (*offp > buffer->data_size - sizeof(*fp) || + buffer->data_size < sizeof(*fp) || + !IS_ALIGNED(*offp, sizeof(void *))) { printk(KERN_ERR "binder: transaction release %d bad" "offset %zd, size %zd\n", debug_id, *offp, buffer->data_size); continue; @@ -1691,7 +1720,7 @@ binder_transaction_buffer_release(struct binder_proc *proc, struct binder_buffer if (binder_debug_mask & BINDER_DEBUG_TRANSACTION) printk(KERN_INFO " fd %ld\n", fp->handle); if (failed_at) - task_close_fd(proc->tsk, fp->handle); + task_close_fd(proc, fp->handle); break; default: @@ -2340,7 +2369,7 @@ retry: tr.data_size = t->buffer->data_size; tr.offsets_size = t->buffer->offsets_size; - tr.data.ptr.buffer = (void *)((void *)t->buffer->data + proc->user_buffer_offset); + tr.data.ptr.buffer = (void *)t->buffer->data + proc->user_buffer_offset; tr.data.ptr.offsets = tr.data.ptr.buffer + ALIGN(t->buffer->data_size, sizeof(void *)); if (put_user(cmd, (uint32_t __user *)ptr)) @@ -2656,6 +2685,7 @@ static void binder_vma_open(struct vm_area_struct *vma) (unsigned long)pgprot_val(vma->vm_page_prot)); dump_stack(); } + static void binder_vma_close(struct vm_area_struct *vma) { struct binder_proc *proc = vma->vm_private_data; @@ -2666,6 +2696,7 @@ static void binder_vma_close(struct vm_area_struct *vma) (vma->vm_end - vma->vm_start) / SZ_1K, vma->vm_flags, (unsigned long)pgprot_val(vma->vm_page_prot)); proc->vma = NULL; + binder_defer_work(proc, BINDER_DEFERRED_PUT_FILES); } static struct vm_operations_struct binder_vm_ops = { @@ -2698,6 +2729,12 @@ static int binder_mmap(struct file *filp, struct vm_area_struct *vma) } vma->vm_flags = (vma->vm_flags | VM_DONTCOPY) & ~VM_MAYWRITE; + if (proc->buffer) { + ret = -EBUSY; + failure_string = "already mapped"; + goto err_already_mapped; + } + area = get_vm_area(vma->vm_end - vma->vm_start, VM_IOREMAP); if (area == NULL) { ret = -ENOMEM; @@ -2705,7 +2742,7 @@ static int binder_mmap(struct file *filp, struct vm_area_struct *vma) goto err_get_vm_area_failed; } proc->buffer = area->addr; - proc->user_buffer_offset = vma->vm_start - (size_t)proc->buffer; + proc->user_buffer_offset = vma->vm_start - (uintptr_t)proc->buffer; #ifdef CONFIG_CPU_CACHE_VIPT if (cache_is_vipt_aliasing()) { @@ -2738,6 +2775,7 @@ static int binder_mmap(struct file *filp, struct vm_area_struct *vma) binder_insert_free_buffer(proc, buffer); proc->free_async_space = proc->buffer_size / 2; barrier(); + proc->files = get_files_struct(current); proc->vma = vma; /*printk(KERN_INFO "binder_mmap: %d %lx-%lx maps %p\n", proc->pid, vma->vm_start, vma->vm_end, proc->buffer);*/ @@ -2745,10 +2783,12 @@ static int binder_mmap(struct file *filp, struct vm_area_struct *vma) err_alloc_small_buf_failed: kfree(proc->pages); + proc->pages = NULL; err_alloc_pages_failed: vfree(proc->buffer); + proc->buffer = NULL; err_get_vm_area_failed: - mutex_unlock(&binder_lock); +err_already_mapped: err_bad_arg: printk(KERN_ERR "binder_mmap: %d %lx-%lx %s failed %d\n", proc->pid, vma->vm_start, vma->vm_end, failure_string, ret); return ret; @@ -2780,6 +2820,7 @@ static int binder_open(struct inode *nodp, struct file *filp) if (binder_proc_dir_entry_proc) { char strbuf[11]; snprintf(strbuf, sizeof(strbuf), "%u", proc->pid); + remove_proc_entry(strbuf, binder_proc_dir_entry_proc); create_proc_read_entry(strbuf, S_IRUGO, binder_proc_dir_entry_proc, binder_read_proc_proc, proc); } @@ -2788,11 +2829,17 @@ static int binder_open(struct inode *nodp, struct file *filp) static int binder_flush(struct file *filp, fl_owner_t id) { - struct rb_node *n; struct binder_proc *proc = filp->private_data; - int wake_count = 0; - mutex_lock(&binder_lock); + binder_defer_work(proc, BINDER_DEFERRED_FLUSH); + + return 0; +} + +static void binder_deferred_flush(struct binder_proc *proc) +{ + struct rb_node *n; + int wake_count = 0; for (n = rb_first(&proc->threads); n != NULL; n = rb_next(n)) { struct binder_thread *thread = rb_entry(n, struct binder_thread, rb_node); thread->looper |= BINDER_LOOPER_STATE_NEED_RETURN; @@ -2802,28 +2849,35 @@ static int binder_flush(struct file *filp, fl_owner_t id) } } wake_up_interruptible_all(&proc->wait); - mutex_unlock(&binder_lock); if (binder_debug_mask & BINDER_DEBUG_OPEN_CLOSE) printk(KERN_INFO "binder_flush: %d woke %d threads\n", proc->pid, wake_count); - - return 0; } static int binder_release(struct inode *nodp, struct file *filp) { - struct hlist_node *pos; - struct binder_transaction *t; - struct rb_node *n; struct binder_proc *proc = filp->private_data; - int threads, nodes, incoming_refs, outgoing_refs, buffers, active_transactions, page_count; - if (binder_proc_dir_entry_proc) { char strbuf[11]; snprintf(strbuf, sizeof(strbuf), "%u", proc->pid); remove_proc_entry(strbuf, binder_proc_dir_entry_proc); } - mutex_lock(&binder_lock); + + binder_defer_work(proc, BINDER_DEFERRED_RELEASE); + + return 0; +} + +static void binder_deferred_release(struct binder_proc *proc) +{ + struct hlist_node *pos; + struct binder_transaction *t; + struct rb_node *n; + int threads, nodes, incoming_refs, outgoing_refs, buffers, active_transactions, page_count; + + BUG_ON(proc->vma); + BUG_ON(proc->files); + hlist_del(&proc->proc_node); if (binder_context_mgr_node && binder_context_mgr_node->proc == proc) { if (binder_debug_mask & BINDER_DEBUG_DEAD_BINDER) @@ -2897,7 +2951,6 @@ static int binder_release(struct inode *nodp, struct file *filp) } binder_stats.obj_deleted[BINDER_STAT_PROC]++; - mutex_unlock(&binder_lock); page_count = 0; if (proc->pages) { @@ -2921,7 +2974,57 @@ static int binder_release(struct inode *nodp, struct file *filp) proc->pid, threads, nodes, incoming_refs, outgoing_refs, active_transactions, buffers, page_count); kfree(proc); - return 0; +} + +static void binder_deferred_func(struct work_struct *work) +{ + struct binder_proc *proc; + struct files_struct *files; + + int defer; + do { + mutex_lock(&binder_lock); + mutex_lock(&binder_deferred_lock); + if (!hlist_empty(&binder_deferred_list)) { + proc = hlist_entry(binder_deferred_list.first, + struct binder_proc, deferred_work_node); + hlist_del_init(&proc->deferred_work_node); + defer = proc->deferred_work; + proc->deferred_work = 0; + } else { + proc = NULL; + defer = 0; + } + mutex_unlock(&binder_deferred_lock); + + files = NULL; + if (defer & BINDER_DEFERRED_PUT_FILES) + if ((files = proc->files)) + proc->files = NULL; + + if (defer & BINDER_DEFERRED_FLUSH) + binder_deferred_flush(proc); + + if (defer & BINDER_DEFERRED_RELEASE) + binder_deferred_release(proc); /* frees proc */ + + mutex_unlock(&binder_lock); + if (files) + put_files_struct(files); + } while (proc); +} +static DECLARE_WORK(binder_deferred_work, binder_deferred_func); + +static void binder_defer_work(struct binder_proc *proc, int defer) +{ + mutex_lock(&binder_deferred_lock); + proc->deferred_work |= defer; + if (hlist_unhashed(&proc->deferred_work_node)) { + hlist_add_head(&proc->deferred_work_node, + &binder_deferred_list); + schedule_work(&binder_deferred_work); + } + mutex_unlock(&binder_deferred_lock); } static char *print_binder_transaction(char *buf, char *end, const char *prefix, struct binder_transaction *t) diff --git a/drivers/staging/at76_usb/at76_usb.c b/drivers/staging/at76_usb/at76_usb.c index 6f6e36a3bd9..c8af9a868d6 100644 --- a/drivers/staging/at76_usb/at76_usb.c +++ b/drivers/staging/at76_usb/at76_usb.c @@ -5259,6 +5259,18 @@ static int at76_alloc_urbs(struct at76_priv *priv, return 0; } +static const struct net_device_ops at76_netdev_ops = { + .ndo_open = at76_open, + .ndo_stop = at76_stop, + .ndo_get_stats = at76_get_stats, + .ndo_start_xmit = at76_tx, + .ndo_tx_timeout = at76_tx_timeout, + .ndo_set_multicast_list = at76_set_multicast, + .ndo_set_mac_address = at76_set_mac_address, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = eth_change_mtu, +}; + /* Register network device and initialize the hardware */ static int at76_init_new_device(struct at76_priv *priv, struct usb_interface *interface) @@ -5303,21 +5315,15 @@ static int at76_init_new_device(struct at76_priv *priv, priv->scan_mode = SCAN_TYPE_ACTIVE; netdev->flags &= ~IFF_MULTICAST; /* not yet or never */ - netdev->open = at76_open; - netdev->stop = at76_stop; - netdev->get_stats = at76_get_stats; + netdev->netdev_ops = &at76_netdev_ops; netdev->ethtool_ops = &at76_ethtool_ops; /* Add pointers to enable iwspy support. */ priv->wireless_data.spy_data = &priv->spy_data; netdev->wireless_data = &priv->wireless_data; - netdev->hard_start_xmit = at76_tx; - netdev->tx_timeout = at76_tx_timeout; netdev->watchdog_timeo = 2 * HZ; netdev->wireless_handlers = &at76_handler_def; - netdev->set_multicast_list = at76_set_multicast; - netdev->set_mac_address = at76_set_mac_address; dev_alloc_name(netdev, "wlan%d"); ret = register_netdev(priv->netdev); diff --git a/drivers/staging/epl/VirtualEthernetLinux.c b/drivers/staging/epl/VirtualEthernetLinux.c index 21206c4d22f..077724a556c 100644 --- a/drivers/staging/epl/VirtualEthernetLinux.c +++ b/drivers/staging/epl/VirtualEthernetLinux.c @@ -284,6 +284,17 @@ static tEplKernel VEthRecvFrame(tEplFrameInfo * pFrameInfo_p) return Ret; } +static const struct net_device_ops epl_netdev_ops = { + .ndo_open = VEthOpen, + .ndo_stop = VEthClose, + .ndo_get_stats = VEthGetStats, + .ndo_start_xmit = VEthXmit, + .ndo_tx_timeout = VEthTimeout, + .ndo_change_mtu = eth_change_mtu, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, +}; + tEplKernel VEthAddInstance(tEplDllkInitParam *pInitParam_p) { tEplKernel Ret = kEplSuccessful; @@ -299,11 +310,7 @@ tEplKernel VEthAddInstance(tEplDllkInitParam *pInitParam_p) goto Exit; } - pVEthNetDevice_g->open = VEthOpen; - pVEthNetDevice_g->stop = VEthClose; - pVEthNetDevice_g->get_stats = VEthGetStats; - pVEthNetDevice_g->hard_start_xmit = VEthXmit; - pVEthNetDevice_g->tx_timeout = VEthTimeout; + pVEthNetDevice_g->netdev_ops = &epl_netdev_ops; pVEthNetDevice_g->watchdog_timeo = EPL_VETH_TX_TIMEOUT; pVEthNetDevice_g->destructor = free_netdev; diff --git a/drivers/staging/et131x/et131x_netdev.c b/drivers/staging/et131x/et131x_netdev.c index de65972ff36..951c73d5db2 100644 --- a/drivers/staging/et131x/et131x_netdev.c +++ b/drivers/staging/et131x/et131x_netdev.c @@ -112,6 +112,19 @@ void et131x_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp); void et131x_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid); void et131x_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid); +static const struct net_device_ops et131x_netdev_ops = { + .ndo_open = et131x_open, + .ndo_stop = et131x_close, + .ndo_start_xmit = et131x_tx, + .ndo_set_multicast_list = et131x_multicast, + .ndo_tx_timeout = et131x_tx_timeout, + .ndo_change_mtu = et131x_change_mtu, + .ndo_set_mac_address = et131x_set_mac_addr, + .ndo_validate_addr = eth_validate_addr, + .ndo_get_stats = et131x_stats, + .ndo_do_ioctl = et131x_ioctl, +}; + /** * et131x_device_alloc * @@ -142,16 +155,8 @@ struct net_device *et131x_device_alloc(void) */ //netdev->init = &et131x_init; //netdev->set_config = &et131x_config; - netdev->get_stats = &et131x_stats; - netdev->open = &et131x_open; - netdev->stop = &et131x_close; - netdev->do_ioctl = &et131x_ioctl; - netdev->set_multicast_list = &et131x_multicast; - netdev->hard_start_xmit = &et131x_tx; - netdev->tx_timeout = &et131x_tx_timeout; netdev->watchdog_timeo = ET131X_TX_TIMEOUT; - netdev->change_mtu = &et131x_change_mtu; - netdev->set_mac_address = &et131x_set_mac_addr; + netdev->netdev_ops = &et131x_netdev_ops; //netdev->ethtool_ops = &et131x_ethtool_ops; diff --git a/drivers/staging/go7007/go7007-driver.c b/drivers/staging/go7007/go7007-driver.c index 58bfc8d81b3..f47c0ce2849 100644 --- a/drivers/staging/go7007/go7007-driver.c +++ b/drivers/staging/go7007/go7007-driver.c @@ -268,21 +268,6 @@ int go7007_register_encoder(struct go7007 *go) init_i2c_module(&go->i2c_adapter, go->board_info->i2c_devs[i].id, go->board_info->i2c_devs[i].addr); -#ifdef TUNER_SET_TYPE_ADDR - if (go->tuner_type >= 0) { - struct tuner_setup tun_setup = { - .mode_mask = T_ANALOG_TV, - .addr = ADDR_UNSET, - .type = go->tuner_type - }; - i2c_clients_command(&go->i2c_adapter, - TUNER_SET_TYPE_ADDR, &tun_setup); - } -#else - if (go->tuner_type >= 0) - i2c_clients_command(&go->i2c_adapter, - TUNER_SET_TYPE, &go->tuner_type); -#endif if (go->board_id == GO7007_BOARDID_ADLINK_MPG24) i2c_clients_command(&go->i2c_adapter, DECODER_SET_CHANNEL, &go->channel_number); diff --git a/drivers/staging/go7007/wis-sony-tuner.c b/drivers/staging/go7007/wis-sony-tuner.c index 58fddb12237..0a7eeef7c00 100644 --- a/drivers/staging/go7007/wis-sony-tuner.c +++ b/drivers/staging/go7007/wis-sony-tuner.c @@ -386,6 +386,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) struct wis_sony_tuner *t = i2c_get_clientdata(client); switch (cmd) { +#if 0 #ifdef TUNER_SET_TYPE_ADDR case TUNER_SET_TYPE_ADDR: { @@ -463,6 +464,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) t->type, sony_tuners[t->type - 200].name); break; } +#endif case VIDIOC_G_FREQUENCY: { struct v4l2_frequency *f = arg; diff --git a/drivers/staging/line6/audio.c b/drivers/staging/line6/audio.c index 3aa946899ce..e2ac8d60f8c 100644 --- a/drivers/staging/line6/audio.c +++ b/drivers/staging/line6/audio.c @@ -27,11 +27,12 @@ int line6_init_audio(struct usb_line6 *line6) { static int dev; struct snd_card *card; + int err; - card = snd_card_new(line6_index[dev], line6_id[dev], THIS_MODULE, 0); - - if (card == NULL) - return -ENOMEM; + err = snd_card_create(line6_index[dev], line6_id[dev], THIS_MODULE, 0, + &card); + if (err < 0) + return err; line6->card = card; diff --git a/drivers/staging/otus/usbdrv.c b/drivers/staging/otus/usbdrv.c index 565a839589f..540cbbb826f 100644 --- a/drivers/staging/otus/usbdrv.c +++ b/drivers/staging/otus/usbdrv.c @@ -822,6 +822,21 @@ int zfLnxVapXmitFrame(struct sk_buff *skb, struct net_device *dev) return 0; } +static const struct net_device_ops vap_netdev_ops = { + .ndo_open = zfLnxVapOpen, + .ndo_stop = zfLnxVapClose, + .ndo_start_xmit = zfLnxVapXmitFrame, + .ndo_get_stats = usbdrv_get_stats, + .ndo_change_mtu = usbdrv_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, +#ifdef ZM_HOSTAPD_SUPPORT + .ndo_do_ioctl = usbdrv_ioctl, +#else + .ndo_do_ioctl = NULL, +#endif +}; + int zfLnxRegisterVapDev(struct net_device* parentDev, u16_t vapId) { /* Allocate net device structure */ @@ -846,16 +861,7 @@ int zfLnxRegisterVapDev(struct net_device* parentDev, u16_t vapId) vap[vapId].dev->ml_priv = parentDev->ml_priv; //dev->hard_start_xmit = &zd1212_wds_xmit_frame; - vap[vapId].dev->hard_start_xmit = &zfLnxVapXmitFrame; - vap[vapId].dev->open = &zfLnxVapOpen; - vap[vapId].dev->stop = &zfLnxVapClose; - vap[vapId].dev->get_stats = &usbdrv_get_stats; - vap[vapId].dev->change_mtu = &usbdrv_change_mtu; -#ifdef ZM_HOSTAPD_SUPPORT - vap[vapId].dev->do_ioctl = usbdrv_ioctl; -#else - vap[vapId].dev->do_ioctl = NULL; -#endif + vap[vapId].dev->netdev_ops = &vap_netdev_ops; vap[vapId].dev->destructor = free_netdev; vap[vapId].dev->tx_queue_len = 0; @@ -1068,6 +1074,18 @@ void zfLnxUnlinkAllUrbs(struct usbdrv_private *macp) usb_unlink_urb(macp->RegInUrb); } +static const struct net_device_ops otus_netdev_ops = { + .ndo_open = usbdrv_open, + .ndo_stop = usbdrv_close, + .ndo_start_xmit = usbdrv_xmit_frame, + .ndo_change_mtu = usbdrv_change_mtu, + .ndo_get_stats = usbdrv_get_stats, + .ndo_set_multicast_list = usbdrv_set_multi, + .ndo_set_mac_address = usbdrv_set_mac, + .ndo_do_ioctl = usbdrv_ioctl, + .ndo_validate_addr = eth_validate_addr, +}; + u8_t zfLnxInitSetup(struct net_device *dev, struct usbdrv_private *macp) { //unsigned char addr[6]; @@ -1092,14 +1110,7 @@ u8_t zfLnxInitSetup(struct net_device *dev, struct usbdrv_private *macp) dev->wireless_handlers = (struct iw_handler_def *)&p80211wext_handler_def; #endif - dev->open = usbdrv_open; - dev->hard_start_xmit = usbdrv_xmit_frame; - dev->stop = usbdrv_close; - dev->change_mtu = &usbdrv_change_mtu; - dev->get_stats = usbdrv_get_stats; - dev->set_multicast_list = usbdrv_set_multi; - dev->set_mac_address = usbdrv_set_mac; - dev->do_ioctl = usbdrv_ioctl; + dev->netdev_ops = &otus_netdev_ops; dev->flags |= IFF_MULTICAST; diff --git a/drivers/staging/otus/zdusb.c b/drivers/staging/otus/zdusb.c index 78f1d2224fa..2a6d937ba5e 100644 --- a/drivers/staging/otus/zdusb.c +++ b/drivers/staging/otus/zdusb.c @@ -48,7 +48,8 @@ static const char driver_name[] = "Otus"; static struct usb_device_id zd1221_ids [] = { { USB_DEVICE(VENDOR_ATHR, PRODUCT_AR9170) }, { USB_DEVICE(VENDOR_DLINK, PRODUCT_DWA160A) }, - { USB_DEVICE(0x0846, 0x9010) }, + { USB_DEVICE(VENDOR_NETGEAR, PRODUCT_WNDA3100) }, + { USB_DEVICE(VENDOR_NETGEAR, PRODUCT_WN111v2) }, { } /* Terminating entry */ }; diff --git a/drivers/staging/otus/zdusb.h b/drivers/staging/otus/zdusb.h index 656dc212ade..9f8ab2e9616 100644 --- a/drivers/staging/otus/zdusb.h +++ b/drivers/staging/otus/zdusb.h @@ -40,4 +40,8 @@ #define VENDOR_DLINK 0x07D1 //Dlink #define PRODUCT_DWA160A 0x3C10 +#define VENDOR_NETGEAR 0x0846 /* NetGear */ +#define PRODUCT_WNDA3100 0x9010 +#define PRODUCT_WN111v2 0x9001 + #endif diff --git a/drivers/staging/pohmelfs/config.c b/drivers/staging/pohmelfs/config.c index 3e67da9ea38..a6eaa42fb66 100644 --- a/drivers/staging/pohmelfs/config.c +++ b/drivers/staging/pohmelfs/config.c @@ -81,6 +81,45 @@ static struct pohmelfs_config_group *pohmelfs_find_create_config_group(unsigned return g; } +static inline void pohmelfs_insert_config_entry(struct pohmelfs_sb *psb, struct pohmelfs_config *dst) +{ + struct pohmelfs_config *tmp; + + INIT_LIST_HEAD(&dst->config_entry); + + list_for_each_entry(tmp, &psb->state_list, config_entry) { + if (dst->state.ctl.prio > tmp->state.ctl.prio) + list_add_tail(&dst->config_entry, &tmp->config_entry); + } + if (list_empty(&dst->config_entry)) + list_add_tail(&dst->config_entry, &psb->state_list); +} + +static int pohmelfs_move_config_entry(struct pohmelfs_sb *psb, + struct pohmelfs_config *dst, struct pohmelfs_config *new) +{ + if ((dst->state.ctl.prio == new->state.ctl.prio) && + (dst->state.ctl.perm == new->state.ctl.perm)) + return 0; + + dprintk("%s: dst: prio: %d, perm: %x, new: prio: %d, perm: %d.\n", + __func__, dst->state.ctl.prio, dst->state.ctl.perm, + new->state.ctl.prio, new->state.ctl.perm); + dst->state.ctl.prio = new->state.ctl.prio; + dst->state.ctl.perm = new->state.ctl.perm; + + list_del_init(&dst->config_entry); + pohmelfs_insert_config_entry(psb, dst); + return 0; +} + +/* + * pohmelfs_copy_config() is used to copy new state configs from the + * config group (controlled by the netlink messages) into the superblock. + * This happens either at startup time where no transactions can access + * the list of the configs (and thus list of the network states), or at + * run-time, where it is protected by the psb->state_lock. + */ int pohmelfs_copy_config(struct pohmelfs_sb *psb) { struct pohmelfs_config_group *g; @@ -103,7 +142,9 @@ int pohmelfs_copy_config(struct pohmelfs_sb *psb) err = 0; list_for_each_entry(dst, &psb->state_list, config_entry) { if (pohmelfs_config_eql(&dst->state.ctl, &c->state.ctl)) { - err = -EEXIST; + err = pohmelfs_move_config_entry(psb, dst, c); + if (!err) + err = -EEXIST; break; } } @@ -119,7 +160,7 @@ int pohmelfs_copy_config(struct pohmelfs_sb *psb) memcpy(&dst->state.ctl, &c->state.ctl, sizeof(struct pohmelfs_ctl)); - list_add_tail(&dst->config_entry, &psb->state_list); + pohmelfs_insert_config_entry(psb, dst); err = pohmelfs_state_init_one(psb, dst); if (err) { @@ -248,6 +289,13 @@ out_unlock: return err; } +static int pohmelfs_modify_config(struct pohmelfs_ctl *old, struct pohmelfs_ctl *new) +{ + old->perm = new->perm; + old->prio = new->prio; + return 0; +} + static int pohmelfs_cn_ctl(struct cn_msg *msg, int action) { struct pohmelfs_config_group *g; @@ -278,6 +326,9 @@ static int pohmelfs_cn_ctl(struct cn_msg *msg, int action) g->num_entry--; kfree(c); goto out_unlock; + } else if (action == POHMELFS_FLAGS_MODIFY) { + err = pohmelfs_modify_config(sc, ctl); + goto out_unlock; } else { err = -EEXIST; goto out_unlock; @@ -296,6 +347,7 @@ static int pohmelfs_cn_ctl(struct cn_msg *msg, int action) } memcpy(&c->state.ctl, ctl, sizeof(struct pohmelfs_ctl)); g->num_entry++; + list_add_tail(&c->config_entry, &g->config_list); out_unlock: @@ -401,10 +453,9 @@ static void pohmelfs_cn_callback(void *data) switch (msg->flags) { case POHMELFS_FLAGS_ADD: - err = pohmelfs_cn_ctl(msg, POHMELFS_FLAGS_ADD); - break; case POHMELFS_FLAGS_DEL: - err = pohmelfs_cn_ctl(msg, POHMELFS_FLAGS_DEL); + case POHMELFS_FLAGS_MODIFY: + err = pohmelfs_cn_ctl(msg, msg->flags); break; case POHMELFS_FLAGS_SHOW: err = pohmelfs_cn_disp(msg); diff --git a/drivers/staging/pohmelfs/dir.c b/drivers/staging/pohmelfs/dir.c index 7a41183a32e..b5799842fb8 100644 --- a/drivers/staging/pohmelfs/dir.c +++ b/drivers/staging/pohmelfs/dir.c @@ -328,7 +328,7 @@ static int pohmelfs_sync_remote_dir(struct pohmelfs_inode *pi) { struct inode *inode = &pi->vfs_inode; struct pohmelfs_sb *psb = POHMELFS_SB(inode->i_sb); - long ret = msecs_to_jiffies(25000); + long ret = psb->wait_on_page_timeout; int err; dprintk("%s: dir: %llu, state: %lx: remote_synced: %d.\n", @@ -389,11 +389,11 @@ static int pohmelfs_readdir(struct file *file, void *dirent, filldir_t filldir) dprintk("%s: parent: %llu, fpos: %llu, hash: %08lx.\n", __func__, pi->ino, (u64)file->f_pos, (unsigned long)file->private_data); - +#if 0 err = pohmelfs_data_lock(pi, 0, ~0, POHMELFS_READ_LOCK); if (err) return err; - +#endif err = pohmelfs_sync_remote_dir(pi); if (err) return err; @@ -513,10 +513,6 @@ struct dentry *pohmelfs_lookup(struct inode *dir, struct dentry *dentry, struct need_lock = pohmelfs_need_lock(parent, lock_type); - err = pohmelfs_data_lock(parent, 0, ~0, lock_type); - if (err) - goto out; - str.hash = jhash(dentry->d_name.name, dentry->d_name.len, 0); mutex_lock(&parent->offset_lock); @@ -525,8 +521,8 @@ struct dentry *pohmelfs_lookup(struct inode *dir, struct dentry *dentry, struct ino = n->ino; mutex_unlock(&parent->offset_lock); - dprintk("%s: 1 ino: %lu, inode: %p, name: '%s', hash: %x, parent_state: %lx.\n", - __func__, ino, inode, str.name, str.hash, parent->state); + dprintk("%s: start ino: %lu, inode: %p, name: '%s', hash: %x, parent_state: %lx, need_lock: %d.\n", + __func__, ino, inode, str.name, str.hash, parent->state, need_lock); if (ino) { inode = ilookup(dir->i_sb, ino); @@ -534,7 +530,7 @@ struct dentry *pohmelfs_lookup(struct inode *dir, struct dentry *dentry, struct goto out; } - dprintk("%s: dir: %p, dir_ino: %llu, name: '%s', len: %u, dir_state: %lx, ino: %lu.\n", + dprintk("%s: no inode dir: %p, dir_ino: %llu, name: '%s', len: %u, dir_state: %lx, ino: %lu.\n", __func__, dir, parent->ino, str.name, str.len, parent->state, ino); @@ -543,6 +539,10 @@ struct dentry *pohmelfs_lookup(struct inode *dir, struct dentry *dentry, struct goto out; } + err = pohmelfs_data_lock(parent, 0, ~0, lock_type); + if (err) + goto out; + err = pohmelfs_lookup_single(parent, &str, ino); if (err) goto out; @@ -557,10 +557,10 @@ struct dentry *pohmelfs_lookup(struct inode *dir, struct dentry *dentry, struct if (ino) { inode = ilookup(dir->i_sb, ino); - printk("%s: second lookup ino: %lu, inode: %p, name: '%s', hash: %x.\n", + dprintk("%s: second lookup ino: %lu, inode: %p, name: '%s', hash: %x.\n", __func__, ino, inode, str.name, str.hash); if (!inode) { - printk("%s: No inode for ino: %lu, name: '%s', hash: %x.\n", + dprintk("%s: No inode for ino: %lu, name: '%s', hash: %x.\n", __func__, ino, str.name, str.hash); //return NULL; return ERR_PTR(-EACCES); diff --git a/drivers/staging/pohmelfs/inode.c b/drivers/staging/pohmelfs/inode.c index 5bf16504cd6..b2eaf904726 100644 --- a/drivers/staging/pohmelfs/inode.c +++ b/drivers/staging/pohmelfs/inode.c @@ -1169,16 +1169,17 @@ err_out_put: static int pohmelfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) { struct inode *inode = dentry->d_inode; +#if 0 struct pohmelfs_inode *pi = POHMELFS_I(inode); int err; err = pohmelfs_data_lock(pi, 0, ~0, POHMELFS_READ_LOCK); if (err) return err; - dprintk("%s: ino: %llu, mode: %o, uid: %u, gid: %u, size: %llu.\n", __func__, pi->ino, inode->i_mode, inode->i_uid, inode->i_gid, inode->i_size); +#endif generic_fillattr(inode, stat); return 0; @@ -1342,14 +1343,6 @@ static void pohmelfs_put_super(struct super_block *sb) kfree(psb); sb->s_fs_info = NULL; - - pohmelfs_ftrans_exit(); -} - -static int pohmelfs_remount(struct super_block *sb, int *flags, char *data) -{ - *flags |= MS_RDONLY; - return 0; } static int pohmelfs_statfs(struct dentry *dentry, struct kstatfs *buf) @@ -1394,42 +1387,33 @@ static int pohmelfs_show_options(struct seq_file *seq, struct vfsmount *vfs) return 0; } -static const struct super_operations pohmelfs_sb_ops = { - .alloc_inode = pohmelfs_alloc_inode, - .destroy_inode = pohmelfs_destroy_inode, - .drop_inode = pohmelfs_drop_inode, - .write_inode = pohmelfs_write_inode, - .put_super = pohmelfs_put_super, - .remount_fs = pohmelfs_remount, - .statfs = pohmelfs_statfs, - .show_options = pohmelfs_show_options, -}; - enum { pohmelfs_opt_idx, + pohmelfs_opt_crypto_thread_num, + pohmelfs_opt_trans_max_pages, + pohmelfs_opt_crypto_fail_unsupported, + + /* Remountable options */ pohmelfs_opt_trans_scan_timeout, pohmelfs_opt_drop_scan_timeout, pohmelfs_opt_wait_on_page_timeout, pohmelfs_opt_trans_retries, - pohmelfs_opt_crypto_thread_num, - pohmelfs_opt_trans_max_pages, - pohmelfs_opt_crypto_fail_unsupported, pohmelfs_opt_mcache_timeout, }; static struct match_token pohmelfs_tokens[] = { {pohmelfs_opt_idx, "idx=%u"}, + {pohmelfs_opt_crypto_thread_num, "crypto_thread_num=%u"}, + {pohmelfs_opt_trans_max_pages, "trans_max_pages=%u"}, + {pohmelfs_opt_crypto_fail_unsupported, "crypto_fail_unsupported"}, {pohmelfs_opt_trans_scan_timeout, "trans_scan_timeout=%u"}, {pohmelfs_opt_drop_scan_timeout, "drop_scan_timeout=%u"}, {pohmelfs_opt_wait_on_page_timeout, "wait_on_page_timeout=%u"}, {pohmelfs_opt_trans_retries, "trans_retries=%u"}, - {pohmelfs_opt_crypto_thread_num, "crypto_thread_num=%u"}, - {pohmelfs_opt_trans_max_pages, "trans_max_pages=%u"}, - {pohmelfs_opt_crypto_fail_unsupported, "crypto_fail_unsupported"}, {pohmelfs_opt_mcache_timeout, "mcache_timeout=%u"}, }; -static int pohmelfs_parse_options(char *options, struct pohmelfs_sb *psb) +static int pohmelfs_parse_options(char *options, struct pohmelfs_sb *psb, int remount) { char *p; substring_t args[MAX_OPT_ARGS]; @@ -1449,6 +1433,9 @@ static int pohmelfs_parse_options(char *options, struct pohmelfs_sb *psb) if (err) return err; + if (remount && token <= pohmelfs_opt_crypto_fail_unsupported) + continue; + switch (token) { case pohmelfs_opt_idx: psb->idx = option; @@ -1485,6 +1472,25 @@ static int pohmelfs_parse_options(char *options, struct pohmelfs_sb *psb) return 0; } +static int pohmelfs_remount(struct super_block *sb, int *flags, char *data) +{ + int err; + struct pohmelfs_sb *psb = POHMELFS_SB(sb); + unsigned long old_sb_flags = sb->s_flags; + + err = pohmelfs_parse_options(data, psb, 1); + if (err) + goto err_out_restore; + + if (!(*flags & MS_RDONLY)) + sb->s_flags &= ~MS_RDONLY; + return 0; + +err_out_restore: + sb->s_flags = old_sb_flags; + return err; +} + static void pohmelfs_flush_inode(struct pohmelfs_inode *pi, unsigned int count) { struct inode *inode = &pi->vfs_inode; @@ -1753,6 +1759,57 @@ err_out_exit: return err; } +static int pohmelfs_show_stats(struct seq_file *m, struct vfsmount *mnt) +{ + struct netfs_state *st; + struct pohmelfs_ctl *ctl; + struct pohmelfs_sb *psb = POHMELFS_SB(mnt->mnt_sb); + struct pohmelfs_config *c; + + mutex_lock(&psb->state_lock); + + seq_printf(m, "\nidx addr(:port) socket_type protocol active priority permissions\n"); + + list_for_each_entry(c, &psb->state_list, config_entry) { + st = &c->state; + ctl = &st->ctl; + + seq_printf(m, "%u ", ctl->idx); + if (ctl->addr.sa_family == AF_INET) { + struct sockaddr_in *sin = (struct sockaddr_in *)&st->ctl.addr; + //seq_printf(m, "%pi4:%u", &sin->sin_addr.s_addr, ntohs(sin->sin_port)); + seq_printf(m, "%u.%u.%u.%u:%u", NIPQUAD(sin->sin_addr.s_addr), ntohs(sin->sin_port)); + } else if (ctl->addr.sa_family == AF_INET6) { + struct sockaddr_in6 *sin = (struct sockaddr_in6 *)&st->ctl.addr; + seq_printf(m, "%pi6:%u", &sin->sin6_addr, ntohs(sin->sin6_port)); + } else { + unsigned int i; + for (i=0; i<ctl->addrlen; ++i) + seq_printf(m, "%02x.", ctl->addr.addr[i]); + } + + seq_printf(m, " %u %u %d %u %x\n", + ctl->type, ctl->proto, + st->socket != NULL, + ctl->prio, ctl->perm); + } + mutex_unlock(&psb->state_lock); + + return 0; +} + +static const struct super_operations pohmelfs_sb_ops = { + .alloc_inode = pohmelfs_alloc_inode, + .destroy_inode = pohmelfs_destroy_inode, + .drop_inode = pohmelfs_drop_inode, + .write_inode = pohmelfs_write_inode, + .put_super = pohmelfs_put_super, + .remount_fs = pohmelfs_remount, + .statfs = pohmelfs_statfs, + .show_options = pohmelfs_show_options, + .show_stats = pohmelfs_show_stats, +}; + /* * Allocate private superblock and create root dir. */ @@ -1764,8 +1821,6 @@ static int pohmelfs_fill_super(struct super_block *sb, void *data, int silent) struct pohmelfs_inode *npi; struct qstr str; - pohmelfs_ftrans_init(); - psb = kzalloc(sizeof(struct pohmelfs_sb), GFP_KERNEL); if (!psb) goto err_out_exit; @@ -1816,7 +1871,7 @@ static int pohmelfs_fill_super(struct super_block *sb, void *data, int silent) mutex_init(&psb->state_lock); INIT_LIST_HEAD(&psb->state_list); - err = pohmelfs_parse_options((char *) data, psb); + err = pohmelfs_parse_options((char *) data, psb, 0); if (err) goto err_out_free_sb; @@ -1845,6 +1900,8 @@ static int pohmelfs_fill_super(struct super_block *sb, void *data, int silent) err = PTR_ERR(npi); goto err_out_crypto_exit; } + set_bit(NETFS_INODE_REMOTE_SYNCED, &npi->state); + clear_bit(NETFS_INODE_OWNED, &npi->state); root = &npi->vfs_inode; @@ -1887,11 +1944,29 @@ static int pohmelfs_get_sb(struct file_system_type *fs_type, mnt); } +/* + * We need this to sync all inodes earlier, since when writeback + * is invoked from the umount/mntput path dcache is already shrunk, + * see generic_shutdown_super(), and no inodes can access the path. + */ +static void pohmelfs_kill_super(struct super_block *sb) +{ + struct writeback_control wbc = { + .sync_mode = WB_SYNC_ALL, + .range_start = 0, + .range_end = LLONG_MAX, + .nr_to_write = LONG_MAX, + }; + generic_sync_sb_inodes(sb, &wbc); + + kill_anon_super(sb); +} + static struct file_system_type pohmel_fs_type = { .owner = THIS_MODULE, .name = "pohmel", .get_sb = pohmelfs_get_sb, - .kill_sb = kill_anon_super, + .kill_sb = pohmelfs_kill_super, }; /* diff --git a/drivers/staging/pohmelfs/lock.c b/drivers/staging/pohmelfs/lock.c index ad4a18559bd..22fef18cae9 100644 --- a/drivers/staging/pohmelfs/lock.c +++ b/drivers/staging/pohmelfs/lock.c @@ -41,7 +41,8 @@ static int pohmelfs_send_lock_trans(struct pohmelfs_inode *pi, path_len = err; err = -ENOMEM; - t = netfs_trans_alloc(psb, path_len + sizeof(struct netfs_lock) + isize, 0, 0); + t = netfs_trans_alloc(psb, path_len + sizeof(struct netfs_lock) + isize, + NETFS_TRANS_SINGLE_DST, 0); if (!t) goto err_out_exit; diff --git a/drivers/staging/pohmelfs/net.c b/drivers/staging/pohmelfs/net.c index c9b8540c1ef..11ecac026ca 100644 --- a/drivers/staging/pohmelfs/net.c +++ b/drivers/staging/pohmelfs/net.c @@ -26,55 +26,6 @@ #include "netfs.h" -static int pohmelfs_ftrans_size = 10240; -static u32 *pohmelfs_ftrans; - -int pohmelfs_ftrans_init(void) -{ - pohmelfs_ftrans = vmalloc(pohmelfs_ftrans_size * 4); - if (!pohmelfs_ftrans) - return -ENOMEM; - - return 0; -} - -void pohmelfs_ftrans_exit(void) -{ - vfree(pohmelfs_ftrans); -} - -void pohmelfs_ftrans_clean(u64 id) -{ - if (pohmelfs_ftrans) { - u32 i = id & 0xffffffff; - int idx = i % pohmelfs_ftrans_size; - - pohmelfs_ftrans[idx] = 0; - } -} - -void pohmelfs_ftrans_update(u64 id) -{ - if (pohmelfs_ftrans) { - u32 i = id & 0xffffffff; - int idx = i % pohmelfs_ftrans_size; - - pohmelfs_ftrans[idx] = i; - } -} - -int pohmelfs_ftrans_check(u64 id) -{ - if (pohmelfs_ftrans) { - u32 i = id & 0xffffffff; - int idx = i % pohmelfs_ftrans_size; - - return (pohmelfs_ftrans[idx] == i); - } - - return -1; -} - /* * Async machinery lives here. * All commands being sent to server do _not_ require sync reply, @@ -450,8 +401,24 @@ static int pohmelfs_readdir_response(struct netfs_state *st) if (err != -EEXIST) goto err_out_put; } else { + struct dentry *dentry, *alias, *pd; + set_bit(NETFS_INODE_REMOTE_SYNCED, &npi->state); clear_bit(NETFS_INODE_OWNED, &npi->state); + + pd = d_find_alias(&parent->vfs_inode); + if (pd) { + str.hash = full_name_hash(str.name, str.len); + dentry = d_alloc(pd, &str); + if (dentry) { + alias = d_materialise_unique(dentry, &npi->vfs_inode); + if (alias) + dput(dentry); + } + + dput(dentry); + dput(pd); + } } } out: @@ -638,15 +605,12 @@ static int pohmelfs_transaction_response(struct netfs_state *st) if (dst) { netfs_trans_remove_nolock(dst, st); t = dst->trans; - - pohmelfs_ftrans_update(cmd->start); } mutex_unlock(&st->trans_lock); if (!t) { - int check = pohmelfs_ftrans_check(cmd->start); - printk("%s: failed to find transaction: start: %llu: id: %llu, size: %u, ext: %u, double: %d.\n", - __func__, cmd->start, cmd->id, cmd->size, cmd->ext, check); + printk("%s: failed to find transaction: start: %llu: id: %llu, size: %u, ext: %u.\n", + __func__, cmd->start, cmd->id, cmd->size, cmd->ext); err = -EINVAL; goto out; } diff --git a/drivers/staging/pohmelfs/netfs.h b/drivers/staging/pohmelfs/netfs.h index 2ff21ae5bb1..c78cfcb042f 100644 --- a/drivers/staging/pohmelfs/netfs.h +++ b/drivers/staging/pohmelfs/netfs.h @@ -87,6 +87,7 @@ enum { POHMELFS_FLAGS_DEL, /* Network state control message for DEL */ POHMELFS_FLAGS_SHOW, /* Network state control message for SHOW */ POHMELFS_FLAGS_CRYPTO, /* Crypto data control message */ + POHMELFS_FLAGS_MODIFY, /* Network state modification message */ }; /* @@ -116,16 +117,20 @@ struct pohmelfs_crypto unsigned char data[0]; /* Algorithm string, key and IV */ }; +#define POHMELFS_IO_PERM_READ (1<<0) +#define POHMELFS_IO_PERM_WRITE (1<<1) + /* * Configuration command used to create table of different remote servers. */ struct pohmelfs_ctl { - unsigned int idx; /* Config index */ - unsigned int type; /* Socket type */ - unsigned int proto; /* Socket protocol */ - unsigned int addrlen; /* Size of the address */ - unsigned short unused; /* Align structure by 4 bytes */ + __u32 idx; /* Config index */ + __u32 type; /* Socket type */ + __u32 proto; /* Socket protocol */ + __u16 addrlen; /* Size of the address */ + __u16 perm; /* IO permission */ + __u16 prio; /* IO priority */ struct saddr addr; /* Remote server address */ }; @@ -921,12 +926,6 @@ static inline void pohmelfs_mcache_put(struct pohmelfs_sb *psb, pohmelfs_mcache_free(psb, m); } -int pohmelfs_ftrans_init(void); -void pohmelfs_ftrans_exit(void); -void pohmelfs_ftrans_update(u64 id); -int pohmelfs_ftrans_check(u64 id); -void pohmelfs_ftrans_clean(u64 id); - #endif /* __KERNEL__*/ #endif /* __NETFS_H */ diff --git a/drivers/staging/pohmelfs/trans.c b/drivers/staging/pohmelfs/trans.c index bcb59425a21..fef5f9bd692 100644 --- a/drivers/staging/pohmelfs/trans.c +++ b/drivers/staging/pohmelfs/trans.c @@ -456,34 +456,25 @@ int netfs_trans_finish_send(struct netfs_trans *t, struct pohmelfs_sb *psb) __func__, t, t->gen, t->iovec.iov_len, t->page_num, psb->active_state); #endif mutex_lock(&psb->state_lock); + list_for_each_entry(c, &psb->state_list, config_entry) { + st = &c->state; - if ((t->flags & NETFS_TRANS_SINGLE_DST) && psb->active_state) { - st = &psb->active_state->state; - - err = -EPIPE; - if (netfs_state_poll(st) & POLLOUT) { - err = netfs_trans_push_dst(t, st); - if (!err) { - err = netfs_trans_send(t, st); - if (err) { - netfs_trans_drop_last(t, st); - } else { - pohmelfs_switch_active(psb); - goto out; - } - } + if (t->flags & NETFS_TRANS_SINGLE_DST) { + if (!(st->ctl.perm & POHMELFS_IO_PERM_READ)) + continue; + } else { + if (!(st->ctl.perm & POHMELFS_IO_PERM_WRITE)) + continue; } - pohmelfs_switch_active(psb); - } - list_for_each_entry(c, &psb->state_list, config_entry) { - st = &c->state; + if (psb->active_state && (psb->active_state->state.ctl.prio >= st->ctl.prio)) + st = &psb->active_state->state; err = netfs_trans_push(t, st); if (!err && (t->flags & NETFS_TRANS_SINGLE_DST)) break; } -out: + mutex_unlock(&psb->state_lock); #if 0 dprintk("%s: fully sent t: %p, gen: %u, size: %u, page_num: %u, err: %d.\n", @@ -501,8 +492,6 @@ int netfs_trans_finish(struct netfs_trans *t, struct pohmelfs_sb *psb) t->gen = atomic_inc_return(&psb->trans_gen); - pohmelfs_ftrans_clean(t->gen); - cmd->size = t->iovec.iov_len - sizeof(struct netfs_cmd) + t->attached_size + t->attached_pages * sizeof(struct netfs_cmd); cmd->cmd = NETFS_TRANS; diff --git a/drivers/staging/rt2860/rt_main_dev.c b/drivers/staging/rt2860/rt_main_dev.c index cf17bcdd733..6c4396f0903 100644 --- a/drivers/staging/rt2860/rt_main_dev.c +++ b/drivers/staging/rt2860/rt_main_dev.c @@ -722,6 +722,20 @@ err: return (-1); } /* End of rt28xx_open */ +static const struct net_device_ops rt2860_netdev_ops = { + .ndo_open = MainVirtualIF_open, + .ndo_stop = MainVirtualIF_close, + .ndo_do_ioctl = rt28xx_ioctl, + .ndo_get_stats = RT28xx_get_ether_stats, + .ndo_validate_addr = NULL, + .ndo_set_mac_address = eth_mac_addr, + .ndo_change_mtu = eth_change_mtu, +#ifdef IKANOS_VX_1X0 + .ndo_start_xmit = IKANOS_DataFramesTx, +#else + .ndo_start_xmit = rt28xx_send_packets, +#endif +}; /* Must not be called for mdev and apdev */ static NDIS_STATUS rt_ieee80211_if_setup(struct net_device *dev, PRTMP_ADAPTER pAd) @@ -733,11 +747,6 @@ static NDIS_STATUS rt_ieee80211_if_setup(struct net_device *dev, PRTMP_ADAPTER p //ether_setup(dev); - dev->hard_start_xmit = rt28xx_send_packets; - -#ifdef IKANOS_VX_1X0 - dev->hard_start_xmit = IKANOS_DataFramesTx; -#endif // IKANOS_VX_1X0 // #ifdef CONFIG_STA_SUPPORT #if WIRELESS_EXT >= 12 @@ -760,12 +769,8 @@ static NDIS_STATUS rt_ieee80211_if_setup(struct net_device *dev, PRTMP_ADAPTER p #if WIRELESS_EXT < 21 dev->get_wireless_stats = rt28xx_get_wireless_stats; #endif - dev->get_stats = RT28xx_get_ether_stats; - dev->open = MainVirtualIF_open; //rt28xx_open; - dev->stop = MainVirtualIF_close; //rt28xx_close; dev->priv_flags = INT_MAIN; - dev->do_ioctl = rt28xx_ioctl; - dev->validate_addr = NULL; + dev->netdev_ops = &rt2860_netdev_ops; // find available device name for (i = 0; i < 8; i++) { diff --git a/drivers/staging/rt2870/rt2870.h b/drivers/staging/rt2870/rt2870.h index 5dd15aac9ce..a42caa37080 100644 --- a/drivers/staging/rt2870/rt2870.h +++ b/drivers/staging/rt2870/rt2870.h @@ -96,6 +96,7 @@ {USB_DEVICE(0x0DF6,0x002B)}, /* Sitecom */ \ {USB_DEVICE(0x0DF6,0x002C)}, /* Sitecom */ \ {USB_DEVICE(0x0DF6,0x002D)}, /* Sitecom */ \ + {USB_DEVICE(0x0DF6,0x0039)}, /* Sitecom */ \ {USB_DEVICE(0x14B2,0x3C06)}, /* Conceptronic */ \ {USB_DEVICE(0x14B2,0x3C28)}, /* Conceptronic */ \ {USB_DEVICE(0x2019,0xED06)}, /* Planex Communications, Inc. */ \ diff --git a/drivers/staging/rt2870/rt_main_dev.c b/drivers/staging/rt2870/rt_main_dev.c index 313ecea0bfa..48ad41136d0 100644 --- a/drivers/staging/rt2870/rt_main_dev.c +++ b/drivers/staging/rt2870/rt_main_dev.c @@ -855,6 +855,20 @@ err: return (-1); } /* End of rt28xx_open */ +static const struct net_device_ops rt2870_netdev_ops = { + .ndo_open = MainVirtualIF_open, + .ndo_stop = MainVirtualIF_close, + .ndo_do_ioctl = rt28xx_ioctl, + .ndo_get_stats = RT28xx_get_ether_stats, + .ndo_validate_addr = NULL, + .ndo_set_mac_address = eth_mac_addr, + .ndo_change_mtu = eth_change_mtu, +#ifdef IKANOS_VX_1X0 + .ndo_start_xmit = IKANOS_DataFramesTx, +#else + .ndo_start_xmit = rt28xx_send_packets, +#endif +}; /* Must not be called for mdev and apdev */ static NDIS_STATUS rt_ieee80211_if_setup(struct net_device *dev, PRTMP_ADAPTER pAd) @@ -866,12 +880,6 @@ static NDIS_STATUS rt_ieee80211_if_setup(struct net_device *dev, PRTMP_ADAPTER p //ether_setup(dev); - dev->hard_start_xmit = rt28xx_send_packets; - -#ifdef IKANOS_VX_1X0 - dev->hard_start_xmit = IKANOS_DataFramesTx; -#endif // IKANOS_VX_1X0 // - // dev->set_multicast_list = ieee80211_set_multicast_list; // dev->change_mtu = ieee80211_change_mtu; #ifdef CONFIG_STA_SUPPORT @@ -895,16 +903,10 @@ static NDIS_STATUS rt_ieee80211_if_setup(struct net_device *dev, PRTMP_ADAPTER p #if WIRELESS_EXT < 21 dev->get_wireless_stats = rt28xx_get_wireless_stats; #endif - dev->get_stats = RT28xx_get_ether_stats; - dev->open = MainVirtualIF_open; //rt28xx_open; - dev->stop = MainVirtualIF_close; //rt28xx_close; // dev->uninit = ieee80211_if_reinit; // dev->destructor = ieee80211_if_free; dev->priv_flags = INT_MAIN; - dev->do_ioctl = rt28xx_ioctl; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) - dev->validate_addr = NULL; -#endif + dev->netdev_ops = &rt2870_netdev_ops; // find available device name for (i = 0; i < 8; i++) { diff --git a/drivers/staging/rt3070/rt_main_dev.c b/drivers/staging/rt3070/rt_main_dev.c index c000646286e..81f769cf109 100644 --- a/drivers/staging/rt3070/rt_main_dev.c +++ b/drivers/staging/rt3070/rt_main_dev.c @@ -436,7 +436,6 @@ static int rt28xx_init(IN struct net_device *net_dev) // OID_SET_HT_PHYMODE SetHT; // WPDMA_GLO_CFG_STRUC GloCfg; UINT32 MacCsr0 = 0; - UINT32 MacValue = 0; #ifdef RT2870 #ifdef INF_AMAZON_SE @@ -849,6 +848,20 @@ err: return (-1); } /* End of rt28xx_open */ +static const struct net_device_ops rt3070_netdev_ops = { + .ndo_open = MainVirtualIF_open, + .ndo_stop = MainVirtualIF_close, + .ndo_do_ioctl = rt28xx_ioctl, + .ndo_get_stats = RT28xx_get_ether_stats, + .ndo_validate_addr = NULL, + .ndo_set_mac_address = eth_mac_addr, + .ndo_change_mtu = eth_change_mtu, +#ifdef IKANOS_VX_1X0 + .ndo_start_xmit = IKANOS_DataFramesTx, +#else + .ndo_start_xmit = rt28xx_send_packets, +#endif +}; /* Must not be called for mdev and apdev */ static NDIS_STATUS rt_ieee80211_if_setup(struct net_device *dev, PRTMP_ADAPTER pAd) @@ -860,12 +873,6 @@ static NDIS_STATUS rt_ieee80211_if_setup(struct net_device *dev, PRTMP_ADAPTER p //ether_setup(dev); - dev->hard_start_xmit = rt28xx_send_packets; - -#ifdef IKANOS_VX_1X0 - dev->hard_start_xmit = IKANOS_DataFramesTx; -#endif // IKANOS_VX_1X0 // - // dev->set_multicast_list = ieee80211_set_multicast_list; // dev->change_mtu = ieee80211_change_mtu; #ifdef CONFIG_STA_SUPPORT @@ -889,16 +896,10 @@ static NDIS_STATUS rt_ieee80211_if_setup(struct net_device *dev, PRTMP_ADAPTER p #if WIRELESS_EXT < 21 dev->get_wireless_stats = rt28xx_get_wireless_stats; #endif - dev->get_stats = RT28xx_get_ether_stats; - dev->open = MainVirtualIF_open; //rt28xx_open; - dev->stop = MainVirtualIF_close; //rt28xx_close; // dev->uninit = ieee80211_if_reinit; // dev->destructor = ieee80211_if_free; dev->priv_flags = INT_MAIN; - dev->do_ioctl = rt28xx_ioctl; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) - dev->validate_addr = NULL; -#endif + dev->netdev_ops = &rt3070_netdev_ops; // find available device name for (i = 0; i < 8; i++) { diff --git a/drivers/staging/slicoss/README b/drivers/staging/slicoss/README index 2d5b1127ce5..70f49099c06 100644 --- a/drivers/staging/slicoss/README +++ b/drivers/staging/slicoss/README @@ -10,7 +10,36 @@ TODO: - move firmware loading to request_firmware() - remove direct memory access of structures - any remaining sparse and checkpatch.pl warnings - - any netdev recommended changes + + - use net_device_ops + - use dev->stats rather than adapter->stats + - don't cast netdev_priv it is already void + - use compare_ether_addr + - GET RID OF MACROS + - work on all architectures + - without CONFIG_X86_64 confusion + - do 64 bit correctly + - don't depend on order of union + - get rid of ASSERT(), use BUG() instead but only where necessary + looks like most aren't really useful + - no new SIOCDEVPRIVATE ioctl allowed + - don't use module_param for configuring interrupt mitigation + use ethtool instead + - reorder code to elminate use of forward declarations + - don't keep private linked list of drivers. + - remove all the gratiutous debug infrastructure + - use PCI_DEVICE() + - do ethtool correctly using ethtool_ops + - NAPI? + - wasted overhead of extra stats + - state variables for things that are + easily availble and shouldn't be kept in card structure, cardnum, ... + slotnumber, events, ... + - get rid of slic_spinlock wrapper + - volatile == bad design => bad code + - locking too fine grained, not designed just throw more locks + at problem + Please send patches to: Greg Kroah-Hartman <gregkh@suse.de> diff --git a/drivers/staging/slicoss/slicoss.c b/drivers/staging/slicoss/slicoss.c index 94815634847..6f5d0bff435 100644 --- a/drivers/staging/slicoss/slicoss.c +++ b/drivers/staging/slicoss/slicoss.c @@ -345,6 +345,19 @@ static void slic_init_adapter(struct net_device *netdev, return; } +static const struct net_device_ops slic_netdev_ops = { + .ndo_open = slic_entry_open, + .ndo_stop = slic_entry_halt, + .ndo_start_xmit = slic_xmit_start, + .ndo_do_ioctl = slic_ioctl, + .ndo_set_mac_address = slic_mac_set_address, + .ndo_get_stats = slic_get_stats, + .ndo_set_multicast_list = slic_mcast_set_list, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, + .ndo_change_mtu = eth_change_mtu, +}; + static int __devinit slic_entry_probe(struct pci_dev *pcidev, const struct pci_device_id *pci_tbl_entry) { @@ -442,13 +455,7 @@ static int __devinit slic_entry_probe(struct pci_dev *pcidev, netdev->base_addr = (unsigned long)adapter->memorybase; netdev->irq = adapter->irq; - netdev->open = slic_entry_open; - netdev->stop = slic_entry_halt; - netdev->hard_start_xmit = slic_xmit_start; - netdev->do_ioctl = slic_ioctl; - netdev->set_mac_address = slic_mac_set_address; - netdev->get_stats = slic_get_stats; - netdev->set_multicast_list = slic_mcast_set_list; + netdev->netdev_ops = &slic_netdev_ops; slic_debug_adapter_create(adapter); @@ -1260,7 +1267,7 @@ static int slic_mcast_add_list(struct adapter *adapter, char *address) } /* Doesn't already exist. Allocate a structure to hold it */ - mcaddr = kmalloc(sizeof(struct mcast_address), GFP_KERNEL); + mcaddr = kmalloc(sizeof(struct mcast_address), GFP_ATOMIC); if (mcaddr == NULL) return 1; @@ -2284,7 +2291,7 @@ static u32 slic_card_locate(struct adapter *adapter) } if (!physcard) { /* no structure allocated for this physical card yet */ - physcard = kzalloc(sizeof(struct physcard), GFP_KERNEL); + physcard = kzalloc(sizeof(struct physcard), GFP_ATOMIC); ASSERT(physcard); physcard->next = slic_global.phys_card; diff --git a/drivers/staging/stlc45xx/Kconfig b/drivers/staging/stlc45xx/Kconfig index 8d3f46f190e..947fb75a9c6 100644 --- a/drivers/staging/stlc45xx/Kconfig +++ b/drivers/staging/stlc45xx/Kconfig @@ -1,6 +1,6 @@ config STLC45XX tristate "stlc4550/4560 support" - depends on MAC80211 && WLAN_80211 && SPI_MASTER + depends on MAC80211 && WLAN_80211 && SPI_MASTER && GENERIC_HARDIRQS ---help--- This is a driver for stlc4550 and stlc4560 chipsets. diff --git a/drivers/staging/sxg/sxg.c b/drivers/staging/sxg/sxg.c index 891f6e33467..076b3f7d39e 100644 --- a/drivers/staging/sxg/sxg.c +++ b/drivers/staging/sxg/sxg.c @@ -322,6 +322,8 @@ int sxg_add_msi_isr(struct adapter_t *adapter) int ret,i; if (!adapter->intrregistered) { + spin_unlock_irqrestore(&sxg_global.driver_lock, + sxg_global.flags); for (i=0; i<adapter->nr_msix_entries; i++) { ret = request_irq (adapter->msi_entries[i].vector, sxg_isr, @@ -329,6 +331,8 @@ int sxg_add_msi_isr(struct adapter_t *adapter) adapter->netdev->name, adapter->netdev); if (ret) { + spin_lock_irqsave(&sxg_global.driver_lock, + sxg_global.flags); DBG_ERROR("sxg: MSI-X request_irq (%s) " "FAILED [%x]\n", adapter->netdev->name, ret); @@ -336,6 +340,7 @@ int sxg_add_msi_isr(struct adapter_t *adapter) } } } + spin_lock_irqsave(&sxg_global.driver_lock, sxg_global.flags); adapter->msi_enabled = TRUE; adapter->intrregistered = 1; adapter->IntRegistered = TRUE; @@ -896,6 +901,22 @@ static inline int sxg_read_config(struct adapter_t *adapter) return status; } +static const struct net_device_ops sxg_netdev_ops = { + .ndo_open = sxg_entry_open, + .ndo_stop = sxg_entry_halt, + .ndo_start_xmit = sxg_send_packets, + .ndo_do_ioctl = sxg_ioctl, + .ndo_change_mtu = sxg_change_mtu, + .ndo_get_stats = sxg_get_stats, + .ndo_set_multicast_list = sxg_mcast_set_list, + .ndo_validate_addr = eth_validate_addr, +#if XXXTODO + .ndo_set_mac_address = sxg_mac_set_address, +#else + .ndo_set_mac_address = eth_mac_addr, +#endif +}; + static int sxg_entry_probe(struct pci_dev *pcidev, const struct pci_device_id *pci_tbl_entry) { @@ -1095,16 +1116,7 @@ static int sxg_entry_probe(struct pci_dev *pcidev, netdev->base_addr = (unsigned long)adapter->base_addr; netdev->irq = adapter->irq; - netdev->open = sxg_entry_open; - netdev->stop = sxg_entry_halt; - netdev->hard_start_xmit = sxg_send_packets; - netdev->do_ioctl = sxg_ioctl; - netdev->change_mtu = sxg_change_mtu; -#if XXXTODO - netdev->set_mac_address = sxg_mac_set_address; -#endif - netdev->get_stats = sxg_get_stats; - netdev->set_multicast_list = sxg_mcast_set_list; + netdev->netdev_ops = &sxg_netdev_ops; SET_ETHTOOL_OPS(netdev, &sxg_nic_ethtool_ops); netdev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; err = sxg_set_interrupt_capability(adapter); @@ -2247,6 +2259,8 @@ static int sxg_entry_open(struct net_device *dev) DBG_ERROR("sxg: %s EXIT\n", __func__); spin_unlock_irqrestore(&sxg_global.driver_lock, sxg_global.flags); + mod_timer(&adapter->watchdog_timer, jiffies); + return STATUS_SUCCESS; } @@ -2568,6 +2582,7 @@ static int sxg_dumb_sgl(struct sxg_x64_sgl *pSgl, u64 phys_addr; unsigned long flags; unsigned long queue_id=0; + int offload_cksum = 0; SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "DumbSgl", pSgl, SxgSgl, 0, 0); @@ -2606,7 +2621,11 @@ static int sxg_dumb_sgl(struct sxg_x64_sgl *pSgl, struct iphdr *ip; ip = ip_hdr(skb); - if ((ip->protocol == IPPROTO_TCP)&&(DataLength >= sizeof( + if (ip->protocol == IPPROTO_TCP) + offload_cksum = 1; + if (!offload_cksum || !tcp_hdr(skb)) + queue_id = 0; + else if (offload_cksum && (DataLength >= sizeof( struct tcphdr))){ queue_id = ((ntohs(tcp_hdr(skb)->dest) == ISCSI_PORT) ? (ntohs (tcp_hdr(skb)->source) & @@ -2615,8 +2634,11 @@ static int sxg_dumb_sgl(struct sxg_x64_sgl *pSgl, SXG_LARGE_SEND_QUEUE_MASK)); } } else if (skb->protocol == htons(ETH_P_IPV6)) { - if ((ipv6_hdr(skb)->nexthdr == IPPROTO_TCP) && (DataLength >= - sizeof(struct tcphdr)) ) { + if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP) + offload_cksum = 1; + if (!offload_cksum || !tcp_hdr(skb)) + queue_id = 0; + else if (offload_cksum && (DataLength>=sizeof(struct tcphdr))){ queue_id = ((ntohs(tcp_hdr(skb)->dest) == ISCSI_PORT) ? (ntohs (tcp_hdr(skb)->source) & SXG_LARGE_SEND_QUEUE_MASK): @@ -2645,23 +2667,38 @@ static int sxg_dumb_sgl(struct sxg_x64_sgl *pSgl, } SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "DumbCmd", XmtCmd, XmtRingInfo->Head, XmtRingInfo->Tail, 0); - /* Update stats */ - adapter->stats.tx_packets++; - adapter->stats.tx_bytes += DataLength; -#if XXXTODO /* Stats stuff */ - if (SXG_MULTICAST_PACKET(EtherHdr)) { - if (SXG_BROADCAST_PACKET(EtherHdr)) { - adapter->Stats.DumbXmtBcastPkts++; - adapter->Stats.DumbXmtBcastBytes += DataLength; + memset(XmtCmd, '\0', sizeof(*XmtCmd)); + XmtCmd->SgEntries = 1; + XmtCmd->Flags = 0; + if (skb->ip_summed == CHECKSUM_PARTIAL) { + /* + * We need to set the Checkum in IP header to 0. This is + * required by hardware. + */ + if (offload_cksum) { + ip_hdr(skb)->check = 0x0; + XmtCmd->CsumFlags.Flags |= SXG_SLOWCMD_CSUM_IP; + XmtCmd->CsumFlags.Flags |= SXG_SLOWCMD_CSUM_TCP; + /* + * Dont know if length will require a change in + * case of VLAN + */ + XmtCmd->CsumFlags.MacLen = ETH_HLEN; + XmtCmd->CsumFlags.IpHl = skb_network_header_len(skb) >> + SXG_NW_HDR_LEN_SHIFT; } else { - adapter->Stats.DumbXmtMcastPkts++; - adapter->Stats.DumbXmtMcastBytes += DataLength; + if (skb_checksum_help(skb)){ + printk(KERN_EMERG "Dropped UDP packet for" + " incorrect checksum calculation\n"); + if (XmtCmd) + SXG_ABORT_CMD(XmtRingInfo); + spin_unlock_irqrestore(&adapter->XmtZeroLock, + flags); + return STATUS_SUCCESS; + } } - } else { - adapter->Stats.DumbXmtUcastPkts++; - adapter->Stats.DumbXmtUcastBytes += DataLength; } -#endif + /* * Fill in the command * Copy out the first SGE to the command and adjust for offset @@ -2679,31 +2716,17 @@ static int sxg_dumb_sgl(struct sxg_x64_sgl *pSgl, (SXG_INVALID_SGL(phys_addr,skb->data_len))) { spin_unlock_irqrestore(&adapter->XmtZeroLock, flags); + if (XmtCmd) + SXG_ABORT_CMD(XmtRingInfo); /* Silently drop this packet */ printk(KERN_EMERG"Dropped a packet for 64k boundary problem\n"); return STATUS_SUCCESS; } - memset(XmtCmd, '\0', sizeof(*XmtCmd)); XmtCmd->Buffer.FirstSgeAddress = phys_addr; XmtCmd->Buffer.FirstSgeLength = DataLength; XmtCmd->Buffer.SgeOffset = 0; XmtCmd->Buffer.TotalLength = DataLength; - XmtCmd->SgEntries = 1; - XmtCmd->Flags = 0; - if (skb->ip_summed == CHECKSUM_PARTIAL) { - /* - * We need to set the Checkum in IP header to 0. This is - * required by hardware. - */ - ip_hdr(skb)->check = 0x0; - XmtCmd->CsumFlags.Flags |= SXG_SLOWCMD_CSUM_IP; - XmtCmd->CsumFlags.Flags |= SXG_SLOWCMD_CSUM_TCP; - /* Dont know if length will require a change in case of VLAN */ - XmtCmd->CsumFlags.MacLen = ETH_HLEN; - XmtCmd->CsumFlags.IpHl = skb_network_header_len(skb) >> - SXG_NW_HDR_LEN_SHIFT; - } /* * Advance transmit cmd descripter by 1. * NOTE - See comments in SxgTcpOutput where we write @@ -2715,6 +2738,24 @@ static int sxg_dumb_sgl(struct sxg_x64_sgl *pSgl, ASSERT((queue_id & ~SXG_LARGE_SEND_QUEUE_MASK) == 0); WRITE_REG(adapter->UcodeRegs[0].XmtCmd, ((queue_id << 16) | 1), TRUE); adapter->Stats.XmtQLen++; /* Stats within lock */ + /* Update stats */ + adapter->stats.tx_packets++; + adapter->stats.tx_bytes += DataLength; +#if XXXTODO /* Stats stuff */ + if (SXG_MULTICAST_PACKET(EtherHdr)) { + if (SXG_BROADCAST_PACKET(EtherHdr)) { + adapter->Stats.DumbXmtBcastPkts++; + adapter->Stats.DumbXmtBcastBytes += DataLength; + } else { + adapter->Stats.DumbXmtMcastPkts++; + adapter->Stats.DumbXmtMcastBytes += DataLength; + } + } else { + adapter->Stats.DumbXmtUcastPkts++; + adapter->Stats.DumbXmtUcastBytes += DataLength; + } +#endif + spin_unlock_irqrestore(&adapter->XmtZeroLock, flags); SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "XDumSgl2", XmtCmd, pSgl, SxgSgl, 0); diff --git a/drivers/staging/uc2322/aten2011.c b/drivers/staging/uc2322/aten2011.c index 85b70545306..9c62f787cc9 100644 --- a/drivers/staging/uc2322/aten2011.c +++ b/drivers/staging/uc2322/aten2011.c @@ -603,10 +603,9 @@ static void ATEN2011_bulk_out_data_callback(struct urb *urb) tty = tty_port_tty_get(&ATEN2011_port->port->port); - if (tty && ATEN2011_port->open) { + if (tty && ATEN2011_port->open) /* tell the tty driver that something has changed */ - wake_up_interruptible(&tty->write_wait); - } + tty_wakeup(tty); /* schedule_work(&ATEN2011_port->port->work); */ tty_kref_put(tty); @@ -825,12 +824,6 @@ static int ATEN2011_open(struct tty_struct *tty, struct usb_serial_port *port, status = 0; status = set_reg_sync(port, ATEN2011_port->ControlRegOffset, Data); - /* force low_latency on so that our tty_push actually forces * - * the data through,otherwise it is scheduled, and with * - * high data rates (like with OHCI) data can get lost. */ - - if (tty) - tty->low_latency = 1; /* * Check to see if we've set up our endpoint info yet * (can't set it up in ATEN2011_startup as the structures @@ -1473,22 +1466,7 @@ static void ATEN2011_set_termios(struct tty_struct *tty, cflag = tty->termios->c_cflag; - if (!cflag) { - dbg("%s %s", __func__, "cflag is NULL"); - return; - } - - /* check that they really want us to change something */ - if (old_termios) { - if ((cflag == old_termios->c_cflag) && - (RELEVANT_IFLAG(tty->termios->c_iflag) == - RELEVANT_IFLAG(old_termios->c_iflag))) { - dbg("%s", "Nothing to change"); - return; - } - } - - dbg("%s - clfag %08x iflag %08x", __func__, + dbg("%s - cflag %08x iflag %08x", __func__, tty->termios->c_cflag, RELEVANT_IFLAG(tty->termios->c_iflag)); if (old_termios) { diff --git a/drivers/staging/wlan-ng/p80211netdev.c b/drivers/staging/wlan-ng/p80211netdev.c index b2a606a3693..393e4df70df 100644 --- a/drivers/staging/wlan-ng/p80211netdev.c +++ b/drivers/staging/wlan-ng/p80211netdev.c @@ -711,6 +711,20 @@ static int wlan_change_mtu(netdevice_t *dev, int new_mtu) return 0; } +static const struct net_device_ops p80211_netdev_ops = { + .ndo_init = p80211knetdev_init, + .ndo_open = p80211knetdev_open, + .ndo_stop = p80211knetdev_stop, + .ndo_get_stats = p80211knetdev_get_stats, + .ndo_start_xmit = p80211knetdev_hard_start_xmit, + .ndo_set_multicast_list = p80211knetdev_set_multicast_list, + .ndo_do_ioctl = p80211knetdev_do_ioctl, + .ndo_set_mac_address = p80211knetdev_set_mac_address, + .ndo_tx_timeout = p80211knetdev_tx_timeout, + .ndo_change_mtu = wlan_change_mtu, + .ndo_validate_addr = eth_validate_addr, +}; + /*---------------------------------------------------------------- * wlan_setup * @@ -756,11 +770,7 @@ int wlan_setup(wlandevice_t *wlandev) } else { wlandev->netdev = dev; dev->ml_priv = wlandev; - dev->hard_start_xmit = p80211knetdev_hard_start_xmit; - dev->get_stats = p80211knetdev_get_stats; - dev->init = p80211knetdev_init; - dev->open = p80211knetdev_open; - dev->stop = p80211knetdev_stop; + dev->netdev_ops = &p80211_netdev_ops; mutex_init(&wlandev->ioctl_lock); /* block ioctls until fully initialised. Don't forget to call diff --git a/drivers/uio/uio_cif.c b/drivers/uio/uio_cif.c index c60b8fcf0e3..28034c81291 100644 --- a/drivers/uio/uio_cif.c +++ b/drivers/uio/uio_cif.c @@ -147,5 +147,6 @@ static void __exit hilscher_exit_module(void) module_init(hilscher_init_module); module_exit(hilscher_exit_module); +MODULE_DEVICE_TABLE(pci, hilscher_pci_ids); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Hans J. Koch, Benedikt Spranger"); diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index 3771d6e6d0c..34e6108e1d4 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -652,7 +652,7 @@ next_desc: iface = &intf->altsetting[0]; ep = &iface->endpoint[0].desc; - if (!usb_endpoint_is_int_in(ep)) { + if (!ep || !usb_endpoint_is_int_in(ep)) { rv = -EINVAL; goto err; } diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index df3c539f652..308609039c7 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -841,7 +841,7 @@ static int proc_resetep(struct dev_state *ps, void __user *arg) ret = checkintf(ps, ret); if (ret) return ret; - usb_settoggle(ps->dev, ep & 0xf, !(ep & USB_DIR_IN), 0); + usb_reset_endpoint(ps->dev, ep); return 0; } diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 81fa8506825..42b93da1085 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1539,6 +1539,32 @@ void usb_hcd_disable_endpoint(struct usb_device *udev, hcd->driver->endpoint_disable(hcd, ep); } +/** + * usb_hcd_reset_endpoint - reset host endpoint state + * @udev: USB device. + * @ep: the endpoint to reset. + * + * Resets any host endpoint state such as the toggle bit, sequence + * number and current window. + */ +void usb_hcd_reset_endpoint(struct usb_device *udev, + struct usb_host_endpoint *ep) +{ + struct usb_hcd *hcd = bus_to_hcd(udev->bus); + + if (hcd->driver->endpoint_reset) + hcd->driver->endpoint_reset(hcd, ep); + else { + int epnum = usb_endpoint_num(&ep->desc); + int is_out = usb_endpoint_dir_out(&ep->desc); + int is_control = usb_endpoint_xfer_control(&ep->desc); + + usb_settoggle(udev, epnum, is_out, 0); + if (is_control) + usb_settoggle(udev, epnum, !is_out, 0); + } +} + /* Protect against drivers that try to unlink URBs after the device * is gone, by waiting until all unlinks for @udev are finished. * Since we don't currently track URBs by device, simply wait until diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index f750eb1ab59..e7d4479de41 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -206,6 +206,11 @@ struct hc_driver { void (*endpoint_disable)(struct usb_hcd *hcd, struct usb_host_endpoint *ep); + /* (optional) reset any endpoint state such as sequence number + and current window */ + void (*endpoint_reset)(struct usb_hcd *hcd, + struct usb_host_endpoint *ep); + /* root hub support */ int (*hub_status_data) (struct usb_hcd *hcd, char *buf); int (*hub_control) (struct usb_hcd *hcd, @@ -234,6 +239,8 @@ extern void usb_hcd_flush_endpoint(struct usb_device *udev, struct usb_host_endpoint *ep); extern void usb_hcd_disable_endpoint(struct usb_device *udev, struct usb_host_endpoint *ep); +extern void usb_hcd_reset_endpoint(struct usb_device *udev, + struct usb_host_endpoint *ep); extern void usb_hcd_synchronize_unlinks(struct usb_device *udev); extern int usb_hcd_get_frame_number(struct usb_device *udev); @@ -279,6 +286,13 @@ extern irqreturn_t usb_hcd_irq(int irq, void *__hcd); extern void usb_hc_died(struct usb_hcd *hcd); extern void usb_hcd_poll_rh_status(struct usb_hcd *hcd); +/* The D0/D1 toggle bits ... USE WITH CAUTION (they're almost hcd-internal) */ +#define usb_gettoggle(dev, ep, out) (((dev)->toggle[out] >> (ep)) & 1) +#define usb_dotoggle(dev, ep, out) ((dev)->toggle[out] ^= (1 << (ep))) +#define usb_settoggle(dev, ep, out, bit) \ + ((dev)->toggle[out] = ((dev)->toggle[out] & ~(1 << (ep))) | \ + ((bit) << (ep))) + /* -------------------------------------------------------------------------- */ /* Enumeration is only for the hub driver, or HCD virtual root hubs */ diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 30a0690f368..b6262837765 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1002,8 +1002,7 @@ int usb_clear_halt(struct usb_device *dev, int pipe) * the copy in usb-storage, for as long as we need two copies. */ - /* toggle was reset by the clear */ - usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 0); + usb_reset_endpoint(dev, endp); return 0; } @@ -1076,6 +1075,30 @@ void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr, } /** + * usb_reset_endpoint - Reset an endpoint's state. + * @dev: the device whose endpoint is to be reset + * @epaddr: the endpoint's address. Endpoint number for output, + * endpoint number + USB_DIR_IN for input + * + * Resets any host-side endpoint state such as the toggle bit, + * sequence number or current window. + */ +void usb_reset_endpoint(struct usb_device *dev, unsigned int epaddr) +{ + unsigned int epnum = epaddr & USB_ENDPOINT_NUMBER_MASK; + struct usb_host_endpoint *ep; + + if (usb_endpoint_out(epaddr)) + ep = dev->ep_out[epnum]; + else + ep = dev->ep_in[epnum]; + if (ep) + usb_hcd_reset_endpoint(dev, ep); +} +EXPORT_SYMBOL_GPL(usb_reset_endpoint); + + +/** * usb_disable_interface -- Disable all endpoints for an interface * @dev: the device whose interface is being disabled * @intf: pointer to the interface descriptor @@ -1117,7 +1140,6 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0) usb_disable_endpoint(dev, i, true); usb_disable_endpoint(dev, i + USB_DIR_IN, true); } - dev->toggle[0] = dev->toggle[1] = 0; /* getting rid of interfaces will disconnect * any drivers bound to them (a key side effect) @@ -1154,28 +1176,24 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0) * usb_enable_endpoint - Enable an endpoint for USB communications * @dev: the device whose interface is being enabled * @ep: the endpoint - * @reset_toggle: flag to set the endpoint's toggle back to 0 + * @reset_ep: flag to reset the endpoint state * - * Resets the endpoint toggle if asked, and sets dev->ep_{in,out} pointers. + * Resets the endpoint state if asked, and sets dev->ep_{in,out} pointers. * For control endpoints, both the input and output sides are handled. */ void usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep, - bool reset_toggle) + bool reset_ep) { int epnum = usb_endpoint_num(&ep->desc); int is_out = usb_endpoint_dir_out(&ep->desc); int is_control = usb_endpoint_xfer_control(&ep->desc); - if (is_out || is_control) { - if (reset_toggle) - usb_settoggle(dev, epnum, 1, 0); + if (reset_ep) + usb_hcd_reset_endpoint(dev, ep); + if (is_out || is_control) dev->ep_out[epnum] = ep; - } - if (!is_out || is_control) { - if (reset_toggle) - usb_settoggle(dev, epnum, 0, 0); + if (!is_out || is_control) dev->ep_in[epnum] = ep; - } ep->enabled = 1; } @@ -1183,18 +1201,18 @@ void usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep, * usb_enable_interface - Enable all the endpoints for an interface * @dev: the device whose interface is being enabled * @intf: pointer to the interface descriptor - * @reset_toggles: flag to set the endpoints' toggles back to 0 + * @reset_eps: flag to reset the endpoints' state * * Enables all the endpoints for the interface's current altsetting. */ void usb_enable_interface(struct usb_device *dev, - struct usb_interface *intf, bool reset_toggles) + struct usb_interface *intf, bool reset_eps) { struct usb_host_interface *alt = intf->cur_altsetting; int i; for (i = 0; i < alt->desc.bNumEndpoints; ++i) - usb_enable_endpoint(dev, &alt->endpoint[i], reset_toggles); + usb_enable_endpoint(dev, &alt->endpoint[i], reset_eps); } /** @@ -1335,7 +1353,7 @@ EXPORT_SYMBOL_GPL(usb_set_interface); * This issues a standard SET_CONFIGURATION request to the device using * the current configuration. The effect is to reset most USB-related * state in the device, including interface altsettings (reset to zero), - * endpoint halts (cleared), and data toggle (only for bulk and interrupt + * endpoint halts (cleared), and endpoint state (only for bulk and interrupt * endpoints). Other usbcore state is unchanged, including bindings of * usb device drivers to interfaces. * @@ -1343,7 +1361,7 @@ EXPORT_SYMBOL_GPL(usb_set_interface); * (multi-interface) devices. Instead, the driver for each interface may * use usb_set_interface() on the interfaces it claims. Be careful though; * some devices don't support the SET_INTERFACE request, and others won't - * reset all the interface state (notably data toggles). Resetting the whole + * reset all the interface state (notably endpoint state). Resetting the whole * configuration would affect other drivers' interfaces. * * The caller must own the device lock. @@ -1376,8 +1394,6 @@ int usb_reset_configuration(struct usb_device *dev) if (retval < 0) return retval; - dev->toggle[0] = dev->toggle[1] = 0; - /* re-init hc/hcd interface/endpoint state */ for (i = 0; i < config->desc.bNumInterfaces; i++) { struct usb_interface *intf = config->interface[i]; diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index dcfc072630c..7eee400d3e3 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -362,7 +362,7 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent, dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE; dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT; /* ep0 maxpacket comes later, from device descriptor */ - usb_enable_endpoint(dev, &dev->ep0, true); + usb_enable_endpoint(dev, &dev->ep0, false); dev->can_submit = 1; /* Save readable and stable topology id, distinguishing devices diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c index 96d65ca06ec..4007770f7ed 100644 --- a/drivers/usb/gadget/u_ether.c +++ b/drivers/usb/gadget/u_ether.c @@ -175,12 +175,6 @@ static void eth_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *p) strlcpy(p->bus_info, dev_name(&dev->gadget->dev), sizeof p->bus_info); } -static u32 eth_get_link(struct net_device *net) -{ - struct eth_dev *dev = netdev_priv(net); - return dev->gadget->speed != USB_SPEED_UNKNOWN; -} - /* REVISIT can also support: * - WOL (by tracking suspends and issuing remote wakeup) * - msglevel (implies updated messaging) @@ -189,7 +183,7 @@ static u32 eth_get_link(struct net_device *net) static struct ethtool_ops ops = { .get_drvinfo = eth_get_drvinfo, - .get_link = eth_get_link + .get_link = ethtool_op_get_link, }; static void defer_kevent(struct eth_dev *dev, int flag) diff --git a/drivers/usb/host/whci/asl.c b/drivers/usb/host/whci/asl.c index 958751ccea4..c2050785a81 100644 --- a/drivers/usb/host/whci/asl.c +++ b/drivers/usb/host/whci/asl.c @@ -122,7 +122,8 @@ static uint32_t process_qset(struct whc *whc, struct whc_qset *qset) process_inactive_qtd(whc, qset, td); } - update |= qset_add_qtds(whc, qset); + if (!qset->remove) + update |= qset_add_qtds(whc, qset); done: /* @@ -254,23 +255,29 @@ int asl_urb_enqueue(struct whc *whc, struct urb *urb, gfp_t mem_flags) spin_lock_irqsave(&whc->lock, flags); + err = usb_hcd_link_urb_to_ep(&whc->wusbhc.usb_hcd, urb); + if (err < 0) { + spin_unlock_irqrestore(&whc->lock, flags); + return err; + } + qset = get_qset(whc, urb, GFP_ATOMIC); if (qset == NULL) err = -ENOMEM; else err = qset_add_urb(whc, qset, urb, GFP_ATOMIC); if (!err) { - usb_hcd_link_urb_to_ep(&whc->wusbhc.usb_hcd, urb); if (!qset->in_sw_list) asl_qset_insert_begin(whc, qset); - } + } else + usb_hcd_unlink_urb_from_ep(&whc->wusbhc.usb_hcd, urb); spin_unlock_irqrestore(&whc->lock, flags); if (!err) queue_work(whc->workqueue, &whc->async_work); - return 0; + return err; } /** diff --git a/drivers/usb/host/whci/hcd.c b/drivers/usb/host/whci/hcd.c index 1569afd6245..e019a5058ab 100644 --- a/drivers/usb/host/whci/hcd.c +++ b/drivers/usb/host/whci/hcd.c @@ -186,6 +186,28 @@ static void whc_endpoint_disable(struct usb_hcd *usb_hcd, } } +static void whc_endpoint_reset(struct usb_hcd *usb_hcd, + struct usb_host_endpoint *ep) +{ + struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); + struct whc *whc = wusbhc_to_whc(wusbhc); + struct whc_qset *qset; + + qset = ep->hcpriv; + if (qset) { + qset->remove = 1; + + if (usb_endpoint_xfer_bulk(&ep->desc) + || usb_endpoint_xfer_control(&ep->desc)) + queue_work(whc->workqueue, &whc->async_work); + else + queue_work(whc->workqueue, &whc->periodic_work); + + qset_reset(whc, qset); + } +} + + static struct hc_driver whc_hc_driver = { .description = "whci-hcd", .product_desc = "Wireless host controller", @@ -200,6 +222,7 @@ static struct hc_driver whc_hc_driver = { .urb_enqueue = whc_urb_enqueue, .urb_dequeue = whc_urb_dequeue, .endpoint_disable = whc_endpoint_disable, + .endpoint_reset = whc_endpoint_reset, .hub_status_data = wusbhc_rh_status_data, .hub_control = wusbhc_rh_control, diff --git a/drivers/usb/host/whci/pzl.c b/drivers/usb/host/whci/pzl.c index df8b85f0709..ff4ef9e910d 100644 --- a/drivers/usb/host/whci/pzl.c +++ b/drivers/usb/host/whci/pzl.c @@ -128,7 +128,8 @@ static enum whc_update pzl_process_qset(struct whc *whc, struct whc_qset *qset) process_inactive_qtd(whc, qset, td); } - update |= qset_add_qtds(whc, qset); + if (!qset->remove) + update |= qset_add_qtds(whc, qset); done: /* @@ -282,23 +283,29 @@ int pzl_urb_enqueue(struct whc *whc, struct urb *urb, gfp_t mem_flags) spin_lock_irqsave(&whc->lock, flags); + err = usb_hcd_link_urb_to_ep(&whc->wusbhc.usb_hcd, urb); + if (err < 0) { + spin_unlock_irqrestore(&whc->lock, flags); + return err; + } + qset = get_qset(whc, urb, GFP_ATOMIC); if (qset == NULL) err = -ENOMEM; else err = qset_add_urb(whc, qset, urb, GFP_ATOMIC); if (!err) { - usb_hcd_link_urb_to_ep(&whc->wusbhc.usb_hcd, urb); if (!qset->in_sw_list) qset_insert_in_sw_list(whc, qset); - } + } else + usb_hcd_unlink_urb_from_ep(&whc->wusbhc.usb_hcd, urb); spin_unlock_irqrestore(&whc->lock, flags); if (!err) queue_work(whc->workqueue, &whc->periodic_work); - return 0; + return err; } /** @@ -353,7 +360,6 @@ void pzl_qset_delete(struct whc *whc, struct whc_qset *qset) qset_delete(whc, qset); } - /** * pzl_init - initialize the periodic zone list * @whc: the WHCI host controller diff --git a/drivers/usb/host/whci/qset.c b/drivers/usb/host/whci/qset.c index 7be74314ee1..640b38fbd05 100644 --- a/drivers/usb/host/whci/qset.c +++ b/drivers/usb/host/whci/qset.c @@ -89,11 +89,16 @@ static void qset_fill_qh(struct whc_qset *qset, struct urb *urb) QH_INFO3_TX_RATE_53_3 | QH_INFO3_TX_PWR(0) /* 0 == max power */ ); + + qset->qh.cur_window = cpu_to_le32((1 << qset->max_burst) - 1); } /** * qset_clear - clear fields in a qset so it may be reinserted into a - * schedule + * schedule. + * + * The sequence number and current window are not cleared (see + * qset_reset()). */ void qset_clear(struct whc *whc, struct whc_qset *qset) { @@ -101,9 +106,8 @@ void qset_clear(struct whc *whc, struct whc_qset *qset) qset->remove = 0; qset->qh.link = cpu_to_le32(QH_LINK_NTDS(8) | QH_LINK_T); - qset->qh.status = cpu_to_le16(QH_STATUS_ICUR(qset->td_start)); + qset->qh.status = qset->qh.status & QH_STATUS_SEQ_MASK; qset->qh.err_count = 0; - qset->qh.cur_window = cpu_to_le32((1 << qset->max_burst) - 1); qset->qh.scratch[0] = 0; qset->qh.scratch[1] = 0; qset->qh.scratch[2] = 0; @@ -114,6 +118,20 @@ void qset_clear(struct whc *whc, struct whc_qset *qset) } /** + * qset_reset - reset endpoint state in a qset. + * + * Clears the sequence number and current window. This qset must not + * be in the ASL or PZL. + */ +void qset_reset(struct whc *whc, struct whc_qset *qset) +{ + wait_for_completion(&qset->remove_complete); + + qset->qh.status &= ~QH_STATUS_SEQ_MASK; + qset->qh.cur_window = cpu_to_le32((1 << qset->max_burst) - 1); +} + +/** * get_qset - get the qset for an async endpoint * * A new qset is created if one does not already exist. diff --git a/drivers/usb/host/whci/whcd.h b/drivers/usb/host/whci/whcd.h index d3543a181dc..24e94d983c5 100644 --- a/drivers/usb/host/whci/whcd.h +++ b/drivers/usb/host/whci/whcd.h @@ -184,6 +184,7 @@ void qset_free(struct whc *whc, struct whc_qset *qset); struct whc_qset *get_qset(struct whc *whc, struct urb *urb, gfp_t mem_flags); void qset_delete(struct whc *whc, struct whc_qset *qset); void qset_clear(struct whc *whc, struct whc_qset *qset); +void qset_reset(struct whc *whc, struct whc_qset *qset); int qset_add_urb(struct whc *whc, struct whc_qset *qset, struct urb *urb, gfp_t mem_flags); void qset_free_std(struct whc *whc, struct whc_std *std); diff --git a/drivers/usb/host/whci/whci-hc.h b/drivers/usb/host/whci/whci-hc.h index 51df7e313b3..794dba0d0f0 100644 --- a/drivers/usb/host/whci/whci-hc.h +++ b/drivers/usb/host/whci/whci-hc.h @@ -185,6 +185,7 @@ struct whc_qhead { #define QH_STATUS_FLOW_CTRL (1 << 15) #define QH_STATUS_ICUR(i) ((i) << 5) #define QH_STATUS_TO_ICUR(s) (((s) >> 5) & 0x7) +#define QH_STATUS_SEQ_MASK 0x1f /** * usb_pipe_to_qh_type - USB core pipe type to QH transfer type diff --git a/drivers/usb/musb/cppi_dma.c b/drivers/usb/musb/cppi_dma.c index 569ef0fed0f..1976e9b4180 100644 --- a/drivers/usb/musb/cppi_dma.c +++ b/drivers/usb/musb/cppi_dma.c @@ -579,6 +579,7 @@ cppi_next_tx_segment(struct musb *musb, struct cppi_channel *tx) * trigger the "send a ZLP?" confusion. */ rndis = (maxpacket & 0x3f) == 0 + && length > maxpacket && length < 0xffff && (length % maxpacket) != 0; @@ -1228,27 +1229,7 @@ void cppi_completion(struct musb *musb, u32 rx, u32 tx) hw_ep = tx_ch->hw_ep; - /* Peripheral role never repurposes the - * endpoint, so immediate completion is - * safe. Host role waits for the fifo - * to empty (TXPKTRDY irq) before going - * to the next queued bulk transfer. - */ - if (is_host_active(cppi->musb)) { -#if 0 - /* WORKAROUND because we may - * not always get TXKPTRDY ... - */ - int csr; - - csr = musb_readw(hw_ep->regs, - MUSB_TXCSR); - if (csr & MUSB_TXCSR_TXPKTRDY) -#endif - completed = false; - } - if (completed) - musb_dma_completion(musb, index + 1, 1); + musb_dma_completion(musb, index + 1, 1); } else { /* Bigger transfer than we could fit in diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 338cd1611ab..0112353ec97 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -2170,26 +2170,22 @@ static int musb_suspend(struct platform_device *pdev, pm_message_t message) return 0; } -static int musb_resume(struct platform_device *pdev) +static int musb_resume_early(struct platform_device *pdev) { - unsigned long flags; struct musb *musb = dev_to_musb(&pdev->dev); if (!musb->clock) return 0; - spin_lock_irqsave(&musb->lock, flags); - if (musb->set_clock) musb->set_clock(musb->clock, 1); else clk_enable(musb->clock); /* for static cmos like DaVinci, register values were preserved - * unless for some reason the whole soc powered down and we're - * not treating that as a whole-system restart (e.g. swsusp) + * unless for some reason the whole soc powered down or the USB + * module got reset through the PSC (vs just being disabled). */ - spin_unlock_irqrestore(&musb->lock, flags); return 0; } @@ -2207,7 +2203,7 @@ static struct platform_driver musb_driver = { .remove = __devexit_p(musb_remove), .shutdown = musb_shutdown, .suspend = musb_suspend, - .resume = musb_resume, + .resume_early = musb_resume_early, }; /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index c7ebd0867fc..f79440cdfe7 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -165,9 +165,15 @@ static void nuke(struct musb_ep *ep, const int status) if (is_dma_capable() && ep->dma) { struct dma_controller *c = ep->musb->dma_controller; int value; + if (ep->is_in) { + /* + * The programming guide says that we must not clear + * the DMAMODE bit before DMAENAB, so we only + * clear it in the second write... + */ musb_writew(epio, MUSB_TXCSR, - 0 | MUSB_TXCSR_FLUSHFIFO); + MUSB_TXCSR_DMAMODE | MUSB_TXCSR_FLUSHFIFO); musb_writew(epio, MUSB_TXCSR, 0 | MUSB_TXCSR_FLUSHFIFO); } else { @@ -230,7 +236,7 @@ static inline int max_ep_writesize(struct musb *musb, struct musb_ep *ep) | IN token(s) are recd from Host. | -> DMA interrupt on completion | calls TxAvail. - | -> stop DMA, ~DmaEenab, + | -> stop DMA, ~DMAENAB, | -> set TxPktRdy for last short pkt or zlp | -> Complete Request | -> Continue next request (call txstate) @@ -315,9 +321,17 @@ static void txstate(struct musb *musb, struct musb_request *req) request->dma, request_size); if (use_dma) { if (musb_ep->dma->desired_mode == 0) { - /* ASSERT: DMAENAB is clear */ - csr &= ~(MUSB_TXCSR_AUTOSET | - MUSB_TXCSR_DMAMODE); + /* + * We must not clear the DMAMODE bit + * before the DMAENAB bit -- and the + * latter doesn't always get cleared + * before we get here... + */ + csr &= ~(MUSB_TXCSR_AUTOSET + | MUSB_TXCSR_DMAENAB); + musb_writew(epio, MUSB_TXCSR, csr + | MUSB_TXCSR_P_WZC_BITS); + csr &= ~MUSB_TXCSR_DMAMODE; csr |= (MUSB_TXCSR_DMAENAB | MUSB_TXCSR_MODE); /* against programming guide */ @@ -334,10 +348,7 @@ static void txstate(struct musb *musb, struct musb_request *req) #elif defined(CONFIG_USB_TI_CPPI_DMA) /* program endpoint CSR first, then setup DMA */ - csr &= ~(MUSB_TXCSR_AUTOSET - | MUSB_TXCSR_DMAMODE - | MUSB_TXCSR_P_UNDERRUN - | MUSB_TXCSR_TXPKTRDY); + csr &= ~(MUSB_TXCSR_P_UNDERRUN | MUSB_TXCSR_TXPKTRDY); csr |= MUSB_TXCSR_MODE | MUSB_TXCSR_DMAENAB; musb_writew(epio, MUSB_TXCSR, (MUSB_TXCSR_P_WZC_BITS & ~MUSB_TXCSR_P_UNDERRUN) @@ -364,8 +375,8 @@ static void txstate(struct musb *musb, struct musb_request *req) if (!use_dma) { c->channel_release(musb_ep->dma); musb_ep->dma = NULL; - /* ASSERT: DMAENAB clear */ - csr &= ~(MUSB_TXCSR_DMAMODE | MUSB_TXCSR_MODE); + csr &= ~MUSB_TXCSR_DMAENAB; + musb_writew(epio, MUSB_TXCSR, csr); /* invariant: prequest->buf is non-null */ } #elif defined(CONFIG_USB_TUSB_OMAP_DMA) diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index 499c431a6d6..db1b57415ec 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -4,6 +4,7 @@ * Copyright 2005 Mentor Graphics Corporation * Copyright (C) 2005-2006 by Texas Instruments * Copyright (C) 2006-2007 Nokia Corporation + * Copyright (C) 2008-2009 MontaVista Software, Inc. <source@mvista.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -96,8 +97,8 @@ static void musb_ep_program(struct musb *musb, u8 epnum, - struct urb *urb, unsigned int nOut, - u8 *buf, u32 len); + struct urb *urb, int is_out, + u8 *buf, u32 offset, u32 len); /* * Clear TX fifo. Needed to avoid BABBLE errors. @@ -125,6 +126,29 @@ static void musb_h_tx_flush_fifo(struct musb_hw_ep *ep) } } +static void musb_h_ep0_flush_fifo(struct musb_hw_ep *ep) +{ + void __iomem *epio = ep->regs; + u16 csr; + int retries = 5; + + /* scrub any data left in the fifo */ + do { + csr = musb_readw(epio, MUSB_TXCSR); + if (!(csr & (MUSB_CSR0_TXPKTRDY | MUSB_CSR0_RXPKTRDY))) + break; + musb_writew(epio, MUSB_TXCSR, MUSB_CSR0_FLUSHFIFO); + csr = musb_readw(epio, MUSB_TXCSR); + udelay(10); + } while (--retries); + + WARN(!retries, "Could not flush host TX%d fifo: csr: %04x\n", + ep->epnum, csr); + + /* and reset for the next transfer */ + musb_writew(epio, MUSB_TXCSR, 0); +} + /* * Start transmit. Caller is responsible for locking shared resources. * musb must be locked. @@ -145,13 +169,15 @@ static inline void musb_h_tx_start(struct musb_hw_ep *ep) } -static inline void cppi_host_txdma_start(struct musb_hw_ep *ep) +static inline void musb_h_tx_dma_start(struct musb_hw_ep *ep) { u16 txcsr; /* NOTE: no locks here; caller should lock and select EP */ txcsr = musb_readw(ep->regs, MUSB_TXCSR); txcsr |= MUSB_TXCSR_DMAENAB | MUSB_TXCSR_H_WZC_BITS; + if (is_cppi_enabled()) + txcsr |= MUSB_TXCSR_DMAMODE; musb_writew(ep->regs, MUSB_TXCSR, txcsr); } @@ -166,9 +192,10 @@ musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh) { u16 frame; u32 len; - void *buf; void __iomem *mbase = musb->mregs; struct urb *urb = next_urb(qh); + void *buf = urb->transfer_buffer; + u32 offset = 0; struct musb_hw_ep *hw_ep = qh->hw_ep; unsigned pipe = urb->pipe; u8 address = usb_pipedevice(pipe); @@ -191,7 +218,7 @@ musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh) case USB_ENDPOINT_XFER_ISOC: qh->iso_idx = 0; qh->frame = 0; - buf = urb->transfer_buffer + urb->iso_frame_desc[0].offset; + offset = urb->iso_frame_desc[0].offset; len = urb->iso_frame_desc[0].length; break; default: /* bulk, interrupt */ @@ -209,14 +236,14 @@ musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh) case USB_ENDPOINT_XFER_ISOC: s = "-iso"; break; default: s = "-intr"; break; }; s; }), - epnum, buf, len); + epnum, buf + offset, len); /* Configure endpoint */ if (is_in || hw_ep->is_shared_fifo) hw_ep->in_qh = qh; else hw_ep->out_qh = qh; - musb_ep_program(musb, epnum, urb, !is_in, buf, len); + musb_ep_program(musb, epnum, urb, !is_in, buf, offset, len); /* transmit may have more work: start it when it is time */ if (is_in) @@ -227,7 +254,6 @@ musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh) case USB_ENDPOINT_XFER_ISOC: case USB_ENDPOINT_XFER_INT: DBG(3, "check whether there's still time for periodic Tx\n"); - qh->iso_idx = 0; frame = musb_readw(mbase, MUSB_FRAME); /* FIXME this doesn't implement that scheduling policy ... * or handle framecounter wrapping @@ -256,7 +282,7 @@ start: if (!hw_ep->tx_channel) musb_h_tx_start(hw_ep); else if (is_cppi_enabled() || tusb_dma_omap()) - cppi_host_txdma_start(hw_ep); + musb_h_tx_dma_start(hw_ep); } } @@ -567,10 +593,17 @@ musb_rx_reinit(struct musb *musb, struct musb_qh *qh, struct musb_hw_ep *ep) csr = musb_readw(ep->regs, MUSB_TXCSR); if (csr & MUSB_TXCSR_MODE) { musb_h_tx_flush_fifo(ep); + csr = musb_readw(ep->regs, MUSB_TXCSR); musb_writew(ep->regs, MUSB_TXCSR, - MUSB_TXCSR_FRCDATATOG); + csr | MUSB_TXCSR_FRCDATATOG); } - /* clear mode (and everything else) to enable Rx */ + + /* + * Clear the MODE bit (and everything else) to enable Rx. + * NOTE: we mustn't clear the DMAMODE bit before DMAENAB. + */ + if (csr & MUSB_TXCSR_DMAMODE) + musb_writew(ep->regs, MUSB_TXCSR, MUSB_TXCSR_DMAMODE); musb_writew(ep->regs, MUSB_TXCSR, 0); /* scrub all previous state, clearing toggle */ @@ -601,14 +634,68 @@ musb_rx_reinit(struct musb *musb, struct musb_qh *qh, struct musb_hw_ep *ep) ep->rx_reinit = 0; } +static bool musb_tx_dma_program(struct dma_controller *dma, + struct musb_hw_ep *hw_ep, struct musb_qh *qh, + struct urb *urb, u32 offset, u32 length) +{ + struct dma_channel *channel = hw_ep->tx_channel; + void __iomem *epio = hw_ep->regs; + u16 pkt_size = qh->maxpacket; + u16 csr; + u8 mode; + +#ifdef CONFIG_USB_INVENTRA_DMA + if (length > channel->max_len) + length = channel->max_len; + + csr = musb_readw(epio, MUSB_TXCSR); + if (length > pkt_size) { + mode = 1; + csr |= MUSB_TXCSR_AUTOSET + | MUSB_TXCSR_DMAMODE + | MUSB_TXCSR_DMAENAB; + } else { + mode = 0; + csr &= ~(MUSB_TXCSR_AUTOSET | MUSB_TXCSR_DMAMODE); + csr |= MUSB_TXCSR_DMAENAB; /* against programmer's guide */ + } + channel->desired_mode = mode; + musb_writew(epio, MUSB_TXCSR, csr); +#else + if (!is_cppi_enabled() && !tusb_dma_omap()) + return false; + + channel->actual_len = 0; + + /* + * TX uses "RNDIS" mode automatically but needs help + * to identify the zero-length-final-packet case. + */ + mode = (urb->transfer_flags & URB_ZERO_PACKET) ? 1 : 0; +#endif + + qh->segsize = length; + + if (!dma->channel_program(channel, pkt_size, mode, + urb->transfer_dma + offset, length)) { + dma->channel_release(channel); + hw_ep->tx_channel = NULL; + + csr = musb_readw(epio, MUSB_TXCSR); + csr &= ~(MUSB_TXCSR_AUTOSET | MUSB_TXCSR_DMAENAB); + musb_writew(epio, MUSB_TXCSR, csr | MUSB_TXCSR_H_WZC_BITS); + return false; + } + return true; +} /* * Program an HDRC endpoint as per the given URB * Context: irqs blocked, controller lock held */ static void musb_ep_program(struct musb *musb, u8 epnum, - struct urb *urb, unsigned int is_out, - u8 *buf, u32 len) + struct urb *urb, int is_out, + u8 *buf, u32 offset, u32 len) { struct dma_controller *dma_controller; struct dma_channel *dma_channel; @@ -667,12 +754,17 @@ static void musb_ep_program(struct musb *musb, u8 epnum, /* general endpoint setup */ if (epnum) { - /* ASSERT: TXCSR_DMAENAB was already cleared */ - /* flush all old state, set default */ musb_h_tx_flush_fifo(hw_ep); + + /* + * We must not clear the DMAMODE bit before or in + * the same cycle with the DMAENAB bit, so we clear + * the latter first... + */ csr &= ~(MUSB_TXCSR_H_NAKTIMEOUT - | MUSB_TXCSR_DMAMODE + | MUSB_TXCSR_AUTOSET + | MUSB_TXCSR_DMAENAB | MUSB_TXCSR_FRCDATATOG | MUSB_TXCSR_H_RXSTALL | MUSB_TXCSR_H_ERROR @@ -680,24 +772,20 @@ static void musb_ep_program(struct musb *musb, u8 epnum, ); csr |= MUSB_TXCSR_MODE; - if (usb_gettoggle(urb->dev, - qh->epnum, 1)) + if (usb_gettoggle(urb->dev, qh->epnum, 1)) csr |= MUSB_TXCSR_H_WR_DATATOGGLE | MUSB_TXCSR_H_DATATOGGLE; else csr |= MUSB_TXCSR_CLRDATATOG; - /* twice in case of double packet buffering */ musb_writew(epio, MUSB_TXCSR, csr); /* REVISIT may need to clear FLUSHFIFO ... */ + csr &= ~MUSB_TXCSR_DMAMODE; musb_writew(epio, MUSB_TXCSR, csr); csr = musb_readw(epio, MUSB_TXCSR); } else { /* endpoint 0: just flush */ - musb_writew(epio, MUSB_CSR0, - csr | MUSB_CSR0_FLUSHFIFO); - musb_writew(epio, MUSB_CSR0, - csr | MUSB_CSR0_FLUSHFIFO); + musb_h_ep0_flush_fifo(hw_ep); } /* target addr and (for multipoint) hub addr/port */ @@ -734,113 +822,14 @@ static void musb_ep_program(struct musb *musb, u8 epnum, else load_count = min((u32) packet_sz, len); -#ifdef CONFIG_USB_INVENTRA_DMA - if (dma_channel) { - - /* clear previous state */ - csr = musb_readw(epio, MUSB_TXCSR); - csr &= ~(MUSB_TXCSR_AUTOSET - | MUSB_TXCSR_DMAMODE - | MUSB_TXCSR_DMAENAB); - csr |= MUSB_TXCSR_MODE; - musb_writew(epio, MUSB_TXCSR, - csr | MUSB_TXCSR_MODE); - - qh->segsize = min(len, dma_channel->max_len); - - if (qh->segsize <= packet_sz) - dma_channel->desired_mode = 0; - else - dma_channel->desired_mode = 1; - - - if (dma_channel->desired_mode == 0) { - csr &= ~(MUSB_TXCSR_AUTOSET - | MUSB_TXCSR_DMAMODE); - csr |= (MUSB_TXCSR_DMAENAB); - /* against programming guide */ - } else - csr |= (MUSB_TXCSR_AUTOSET - | MUSB_TXCSR_DMAENAB - | MUSB_TXCSR_DMAMODE); - - musb_writew(epio, MUSB_TXCSR, csr); - - dma_ok = dma_controller->channel_program( - dma_channel, packet_sz, - dma_channel->desired_mode, - urb->transfer_dma, - qh->segsize); - if (dma_ok) { - load_count = 0; - } else { - dma_controller->channel_release(dma_channel); - if (is_out) - hw_ep->tx_channel = NULL; - else - hw_ep->rx_channel = NULL; - dma_channel = NULL; - } - } -#endif - - /* candidate for DMA */ - if ((is_cppi_enabled() || tusb_dma_omap()) && dma_channel) { - - /* program endpoint CSRs first, then setup DMA. - * assume CPPI setup succeeds. - * defer enabling dma. - */ - csr = musb_readw(epio, MUSB_TXCSR); - csr &= ~(MUSB_TXCSR_AUTOSET - | MUSB_TXCSR_DMAMODE - | MUSB_TXCSR_DMAENAB); - csr |= MUSB_TXCSR_MODE; - musb_writew(epio, MUSB_TXCSR, - csr | MUSB_TXCSR_MODE); - - dma_channel->actual_len = 0L; - qh->segsize = len; - - /* TX uses "rndis" mode automatically, but needs help - * to identify the zero-length-final-packet case. - */ - dma_ok = dma_controller->channel_program( - dma_channel, packet_sz, - (urb->transfer_flags - & URB_ZERO_PACKET) - == URB_ZERO_PACKET, - urb->transfer_dma, - qh->segsize); - if (dma_ok) { - load_count = 0; - } else { - dma_controller->channel_release(dma_channel); - hw_ep->tx_channel = NULL; - dma_channel = NULL; - - /* REVISIT there's an error path here that - * needs handling: can't do dma, but - * there's no pio buffer address... - */ - } - } + if (dma_channel && musb_tx_dma_program(dma_controller, + hw_ep, qh, urb, offset, len)) + load_count = 0; if (load_count) { - /* ASSERT: TXCSR_DMAENAB was already cleared */ - /* PIO to load FIFO */ qh->segsize = load_count; musb_write_fifo(hw_ep, load_count, buf); - csr = musb_readw(epio, MUSB_TXCSR); - csr &= ~(MUSB_TXCSR_DMAENAB - | MUSB_TXCSR_DMAMODE - | MUSB_TXCSR_AUTOSET); - /* write CSR */ - csr |= MUSB_TXCSR_MODE; - - if (epnum) - musb_writew(epio, MUSB_TXCSR, csr); } /* re-enable interrupt */ @@ -895,7 +884,7 @@ static void musb_ep_program(struct musb *musb, u8 epnum, dma_channel, packet_sz, !(urb->transfer_flags & URB_SHORT_NOT_OK), - urb->transfer_dma, + urb->transfer_dma + offset, qh->segsize); if (!dma_ok) { dma_controller->channel_release( @@ -1063,11 +1052,7 @@ irqreturn_t musb_h_ep0_irq(struct musb *musb) csr &= ~MUSB_CSR0_H_NAKTIMEOUT; musb_writew(epio, MUSB_CSR0, csr); } else { - csr |= MUSB_CSR0_FLUSHFIFO; - musb_writew(epio, MUSB_CSR0, csr); - musb_writew(epio, MUSB_CSR0, csr); - csr &= ~MUSB_CSR0_H_NAKTIMEOUT; - musb_writew(epio, MUSB_CSR0, csr); + musb_h_ep0_flush_fifo(hw_ep); } musb_writeb(epio, MUSB_NAKLIMIT0, 0); @@ -1081,10 +1066,7 @@ irqreturn_t musb_h_ep0_irq(struct musb *musb) * SHOULD NEVER HAPPEN! */ ERR("no URB for end 0\n"); - musb_writew(epio, MUSB_CSR0, MUSB_CSR0_FLUSHFIFO); - musb_writew(epio, MUSB_CSR0, MUSB_CSR0_FLUSHFIFO); - musb_writew(epio, MUSB_CSR0, 0); - + musb_h_ep0_flush_fifo(hw_ep); goto done; } @@ -1145,8 +1127,8 @@ void musb_host_tx(struct musb *musb, u8 epnum) int pipe; bool done = false; u16 tx_csr; - size_t wLength = 0; - u8 *buf = NULL; + size_t length = 0; + size_t offset = 0; struct urb *urb; struct musb_hw_ep *hw_ep = musb->endpoints + epnum; void __iomem *epio = hw_ep->regs; @@ -1164,7 +1146,7 @@ void musb_host_tx(struct musb *musb, u8 epnum) /* with CPPI, DMA sometimes triggers "extra" irqs */ if (!urb) { DBG(4, "extra TX%d ready, csr %04x\n", epnum, tx_csr); - goto finish; + return; } pipe = urb->pipe; @@ -1201,7 +1183,7 @@ void musb_host_tx(struct musb *musb, u8 epnum) musb_writew(epio, MUSB_TXCSR, MUSB_TXCSR_H_WZC_BITS | MUSB_TXCSR_TXPKTRDY); - goto finish; + return; } if (status) { @@ -1233,29 +1215,89 @@ void musb_host_tx(struct musb *musb, u8 epnum) /* second cppi case */ if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) { DBG(4, "extra TX%d ready, csr %04x\n", epnum, tx_csr); - goto finish; + return; + } + + if (is_dma_capable() && dma && !status) { + /* + * DMA has completed. But if we're using DMA mode 1 (multi + * packet DMA), we need a terminal TXPKTRDY interrupt before + * we can consider this transfer completed, lest we trash + * its last packet when writing the next URB's data. So we + * switch back to mode 0 to get that interrupt; we'll come + * back here once it happens. + */ + if (tx_csr & MUSB_TXCSR_DMAMODE) { + /* + * We shouldn't clear DMAMODE with DMAENAB set; so + * clear them in a safe order. That should be OK + * once TXPKTRDY has been set (and I've never seen + * it being 0 at this moment -- DMA interrupt latency + * is significant) but if it hasn't been then we have + * no choice but to stop being polite and ignore the + * programmer's guide... :-) + * + * Note that we must write TXCSR with TXPKTRDY cleared + * in order not to re-trigger the packet send (this bit + * can't be cleared by CPU), and there's another caveat: + * TXPKTRDY may be set shortly and then cleared in the + * double-buffered FIFO mode, so we do an extra TXCSR + * read for debouncing... + */ + tx_csr &= musb_readw(epio, MUSB_TXCSR); + if (tx_csr & MUSB_TXCSR_TXPKTRDY) { + tx_csr &= ~(MUSB_TXCSR_DMAENAB | + MUSB_TXCSR_TXPKTRDY); + musb_writew(epio, MUSB_TXCSR, + tx_csr | MUSB_TXCSR_H_WZC_BITS); + } + tx_csr &= ~(MUSB_TXCSR_DMAMODE | + MUSB_TXCSR_TXPKTRDY); + musb_writew(epio, MUSB_TXCSR, + tx_csr | MUSB_TXCSR_H_WZC_BITS); + + /* + * There is no guarantee that we'll get an interrupt + * after clearing DMAMODE as we might have done this + * too late (after TXPKTRDY was cleared by controller). + * Re-read TXCSR as we have spoiled its previous value. + */ + tx_csr = musb_readw(epio, MUSB_TXCSR); + } + /* + * We may get here from a DMA completion or TXPKTRDY interrupt. + * In any case, we must check the FIFO status here and bail out + * only if the FIFO still has data -- that should prevent the + * "missed" TXPKTRDY interrupts and deal with double-buffered + * FIFO mode too... + */ + if (tx_csr & (MUSB_TXCSR_FIFONOTEMPTY | MUSB_TXCSR_TXPKTRDY)) { + DBG(2, "DMA complete but packet still in FIFO, " + "CSR %04x\n", tx_csr); + return; + } } - /* REVISIT this looks wrong... */ if (!status || dma || usb_pipeisoc(pipe)) { if (dma) - wLength = dma->actual_len; + length = dma->actual_len; else - wLength = qh->segsize; - qh->offset += wLength; + length = qh->segsize; + qh->offset += length; if (usb_pipeisoc(pipe)) { struct usb_iso_packet_descriptor *d; d = urb->iso_frame_desc + qh->iso_idx; - d->actual_length = qh->segsize; + d->actual_length = length; + d->status = status; if (++qh->iso_idx >= urb->number_of_packets) { done = true; } else { d++; - buf = urb->transfer_buffer + d->offset; - wLength = d->length; + offset = d->offset; + length = d->length; } } else if (dma) { done = true; @@ -1268,10 +1310,8 @@ void musb_host_tx(struct musb *musb, u8 epnum) & URB_ZERO_PACKET)) done = true; if (!done) { - buf = urb->transfer_buffer - + qh->offset; - wLength = urb->transfer_buffer_length - - qh->offset; + offset = qh->offset; + length = urb->transfer_buffer_length - offset; } } } @@ -1290,28 +1330,31 @@ void musb_host_tx(struct musb *musb, u8 epnum) urb->status = status; urb->actual_length = qh->offset; musb_advance_schedule(musb, urb, hw_ep, USB_DIR_OUT); + return; + } else if (usb_pipeisoc(pipe) && dma) { + if (musb_tx_dma_program(musb->dma_controller, hw_ep, qh, urb, + offset, length)) + return; + } else if (tx_csr & MUSB_TXCSR_DMAENAB) { + DBG(1, "not complete, but DMA enabled?\n"); + return; + } - } else if (!(tx_csr & MUSB_TXCSR_DMAENAB)) { - /* WARN_ON(!buf); */ - - /* REVISIT: some docs say that when hw_ep->tx_double_buffered, - * (and presumably, fifo is not half-full) we should write TWO - * packets before updating TXCSR ... other docs disagree ... - */ - /* PIO: start next packet in this URB */ - if (wLength > qh->maxpacket) - wLength = qh->maxpacket; - musb_write_fifo(hw_ep, wLength, buf); - qh->segsize = wLength; - - musb_ep_select(mbase, epnum); - musb_writew(epio, MUSB_TXCSR, - MUSB_TXCSR_H_WZC_BITS | MUSB_TXCSR_TXPKTRDY); - } else - DBG(1, "not complete, but dma enabled?\n"); + /* + * PIO: start next packet in this URB. + * + * REVISIT: some docs say that when hw_ep->tx_double_buffered, + * (and presumably, FIFO is not half-full) we should write *two* + * packets before updating TXCSR; other docs disagree... + */ + if (length > qh->maxpacket) + length = qh->maxpacket; + musb_write_fifo(hw_ep, length, urb->transfer_buffer + offset); + qh->segsize = length; -finish: - return; + musb_ep_select(mbase, epnum); + musb_writew(epio, MUSB_TXCSR, + MUSB_TXCSR_H_WZC_BITS | MUSB_TXCSR_TXPKTRDY); } @@ -1841,7 +1884,7 @@ static int musb_urb_enqueue( unsigned long flags; struct musb *musb = hcd_to_musb(hcd); struct usb_host_endpoint *hep = urb->ep; - struct musb_qh *qh = hep->hcpriv; + struct musb_qh *qh; struct usb_endpoint_descriptor *epd = &hep->desc; int ret; unsigned type_reg; @@ -1853,22 +1896,21 @@ static int musb_urb_enqueue( spin_lock_irqsave(&musb->lock, flags); ret = usb_hcd_link_urb_to_ep(hcd, urb); + qh = ret ? NULL : hep->hcpriv; + if (qh) + urb->hcpriv = qh; spin_unlock_irqrestore(&musb->lock, flags); - if (ret) - return ret; /* DMA mapping was already done, if needed, and this urb is on - * hep->urb_list ... so there's little to do unless hep wasn't - * yet scheduled onto a live qh. + * hep->urb_list now ... so we're done, unless hep wasn't yet + * scheduled onto a live qh. * * REVISIT best to keep hep->hcpriv valid until the endpoint gets * disabled, testing for empty qh->ring and avoiding qh setup costs * except for the first urb queued after a config change. */ - if (qh) { - urb->hcpriv = qh; - return 0; - } + if (qh || ret) + return ret; /* Allocate and initialize qh, minimizing the work done each time * hw_ep gets reprogrammed, or with irqs blocked. Then schedule it. @@ -2044,7 +2086,7 @@ static int musb_cleanup_urb(struct urb *urb, struct musb_qh *qh, int is_in) * endpoint's irq status here to avoid bogus irqs. * clearing that status is platform-specific... */ - } else { + } else if (ep->epnum) { musb_h_tx_flush_fifo(ep); csr = musb_readw(epio, MUSB_TXCSR); csr &= ~(MUSB_TXCSR_AUTOSET @@ -2058,6 +2100,8 @@ static int musb_cleanup_urb(struct urb *urb, struct musb_qh *qh, int is_in) musb_writew(epio, MUSB_TXCSR, csr); /* flush cpu writebuffer */ csr = musb_readw(epio, MUSB_TXCSR); + } else { + musb_h_ep0_flush_fifo(ep); } if (status == 0) musb_advance_schedule(ep->musb, urb, ep, is_in); diff --git a/drivers/usb/musb/musbhsdma.c b/drivers/usb/musb/musbhsdma.c index 8662e9e159c..5e83f96d6b7 100644 --- a/drivers/usb/musb/musbhsdma.c +++ b/drivers/usb/musb/musbhsdma.c @@ -195,30 +195,32 @@ static int dma_channel_abort(struct dma_channel *channel) void __iomem *mbase = musb_channel->controller->base; u8 bchannel = musb_channel->idx; + int offset; u16 csr; if (channel->status == MUSB_DMA_STATUS_BUSY) { if (musb_channel->transmit) { - - csr = musb_readw(mbase, - MUSB_EP_OFFSET(musb_channel->epnum, - MUSB_TXCSR)); - csr &= ~(MUSB_TXCSR_AUTOSET | - MUSB_TXCSR_DMAENAB | - MUSB_TXCSR_DMAMODE); - musb_writew(mbase, - MUSB_EP_OFFSET(musb_channel->epnum, MUSB_TXCSR), - csr); + offset = MUSB_EP_OFFSET(musb_channel->epnum, + MUSB_TXCSR); + + /* + * The programming guide says that we must clear + * the DMAENAB bit before the DMAMODE bit... + */ + csr = musb_readw(mbase, offset); + csr &= ~(MUSB_TXCSR_AUTOSET | MUSB_TXCSR_DMAENAB); + musb_writew(mbase, offset, csr); + csr &= ~MUSB_TXCSR_DMAMODE; + musb_writew(mbase, offset, csr); } else { - csr = musb_readw(mbase, - MUSB_EP_OFFSET(musb_channel->epnum, - MUSB_RXCSR)); + offset = MUSB_EP_OFFSET(musb_channel->epnum, + MUSB_RXCSR); + + csr = musb_readw(mbase, offset); csr &= ~(MUSB_RXCSR_AUTOCLEAR | MUSB_RXCSR_DMAENAB | MUSB_RXCSR_DMAMODE); - musb_writew(mbase, - MUSB_EP_OFFSET(musb_channel->epnum, MUSB_RXCSR), - csr); + musb_writew(mbase, offset, csr); } musb_writew(mbase, @@ -296,20 +298,28 @@ static irqreturn_t dma_controller_irq(int irq, void *private_data) && ((channel->desired_mode == 0) || (channel->actual_len & (musb_channel->max_packet_sz - 1))) - ) { + ) { + u8 epnum = musb_channel->epnum; + int offset = MUSB_EP_OFFSET(epnum, + MUSB_TXCSR); + u16 txcsr; + + /* + * The programming guide says that we + * must clear DMAENAB before DMAMODE. + */ + musb_ep_select(mbase, epnum); + txcsr = musb_readw(mbase, offset); + txcsr &= ~(MUSB_TXCSR_DMAENAB + | MUSB_TXCSR_AUTOSET); + musb_writew(mbase, offset, txcsr); /* Send out the packet */ - musb_ep_select(mbase, - musb_channel->epnum); - musb_writew(mbase, MUSB_EP_OFFSET( - musb_channel->epnum, - MUSB_TXCSR), - MUSB_TXCSR_TXPKTRDY); - } else { - musb_dma_completion( - musb, - musb_channel->epnum, - musb_channel->transmit); + txcsr &= ~MUSB_TXCSR_DMAMODE; + txcsr |= MUSB_TXCSR_TXPKTRDY; + musb_writew(mbase, offset, txcsr); } + musb_dma_completion(musb, musb_channel->epnum, + musb_channel->transmit); } } } diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index dcc87aaa862..8100f1d2590 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -668,6 +668,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(DE_VID, WHT_PID) }, { USB_DEVICE(ADI_VID, ADI_GNICE_PID), .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, + { USB_DEVICE(JETI_VID, JETI_SPC1201_PID) }, { }, /* Optional parameter entry */ { } /* Terminating entry */ }; diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index daaf63db0b5..c09f658a448 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h @@ -913,6 +913,13 @@ #define ADI_GNICE_PID 0xF000 /* + * JETI SPECTROMETER SPECBOS 1201 + * http://www.jeti.com/products/sys/scb/scb1201.php + */ +#define JETI_VID 0x0c6c +#define JETI_SPC1201_PID 0x04b2 + +/* * BmRequestType: 1100 0000b * bRequest: FTDI_E2_READ * wValue: 0 diff --git a/drivers/usb/serial/moto_modem.c b/drivers/usb/serial/moto_modem.c index 2e8e05462ef..b66b71ccd12 100644 --- a/drivers/usb/serial/moto_modem.c +++ b/drivers/usb/serial/moto_modem.c @@ -25,6 +25,7 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(0x05c6, 0x3197) }, /* unknown Motorola phone */ { USB_DEVICE(0x0c44, 0x0022) }, /* unknown Mororola phone */ { USB_DEVICE(0x22b8, 0x2a64) }, /* Motorola KRZR K1m */ + { USB_DEVICE(0x22b8, 0x2c64) }, /* Motorola V950 phone */ { }, }; MODULE_DEVICE_TABLE(usb, id_table); diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index d560c0b54e6..47bd070f24b 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -300,6 +300,10 @@ static int option_resume(struct usb_serial *serial); #define BENQ_VENDOR_ID 0x04a5 #define BENQ_PRODUCT_H10 0x4068 +#define DLINK_VENDOR_ID 0x1186 +#define DLINK_PRODUCT_DWM_652 0x3e04 + + static struct usb_device_id option_ids[] = { { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) }, { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) }, @@ -516,6 +520,7 @@ static struct usb_device_id option_ids[] = { { USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_MF628) }, { USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_CDMA_TECH) }, { USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_H10) }, + { USB_DEVICE(DLINK_VENDOR_ID, DLINK_PRODUCT_DWM_652) }, { USB_DEVICE(0x1da5, 0x4515) }, /* BenQ H20 */ { } /* Terminating entry */ }; diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c index e6d6b0c17fd..7528b8d57f1 100644 --- a/drivers/usb/serial/qcserial.c +++ b/drivers/usb/serial/qcserial.c @@ -26,6 +26,27 @@ static struct usb_device_id id_table[] = { {USB_DEVICE(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */ {USB_DEVICE(0x03f0, 0x1f1d)}, /* HP un2400 Gobi Modem Device */ {USB_DEVICE(0x03f0, 0x201d)}, /* HP un2400 Gobi QDL Device */ + {USB_DEVICE(0x04da, 0x250d)}, /* Panasonic Gobi Modem device */ + {USB_DEVICE(0x04da, 0x250c)}, /* Panasonic Gobi QDL device */ + {USB_DEVICE(0x413c, 0x8172)}, /* Dell Gobi Modem device */ + {USB_DEVICE(0x413c, 0x8171)}, /* Dell Gobi QDL device */ + {USB_DEVICE(0x1410, 0xa001)}, /* Novatel Gobi Modem device */ + {USB_DEVICE(0x1410, 0xa008)}, /* Novatel Gobi QDL device */ + {USB_DEVICE(0x0b05, 0x1776)}, /* Asus Gobi Modem device */ + {USB_DEVICE(0x0b05, 0x1774)}, /* Asus Gobi QDL device */ + {USB_DEVICE(0x19d2, 0xfff3)}, /* ONDA Gobi Modem device */ + {USB_DEVICE(0x19d2, 0xfff2)}, /* ONDA Gobi QDL device */ + {USB_DEVICE(0x1557, 0x0a80)}, /* OQO Gobi QDL device */ + {USB_DEVICE(0x05c6, 0x9001)}, /* Generic Gobi Modem device */ + {USB_DEVICE(0x05c6, 0x9002)}, /* Generic Gobi Modem device */ + {USB_DEVICE(0x05c6, 0x9202)}, /* Generic Gobi Modem device */ + {USB_DEVICE(0x05c6, 0x9203)}, /* Generic Gobi Modem device */ + {USB_DEVICE(0x05c6, 0x9222)}, /* Generic Gobi Modem device */ + {USB_DEVICE(0x05c6, 0x9008)}, /* Generic Gobi QDL device */ + {USB_DEVICE(0x05c6, 0x9201)}, /* Generic Gobi QDL device */ + {USB_DEVICE(0x05c6, 0x9221)}, /* Generic Gobi QDL device */ + {USB_DEVICE(0x05c6, 0x9231)}, /* Generic Gobi QDL device */ + {USB_DEVICE(0x1f45, 0x0001)}, /* Unknown Gobi QDL device */ { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, id_table); diff --git a/drivers/usb/storage/Makefile b/drivers/usb/storage/Makefile index 5be54c01966..ef7e5a8ceab 100644 --- a/drivers/usb/storage/Makefile +++ b/drivers/usb/storage/Makefile @@ -17,7 +17,8 @@ usb-storage-objs := scsiglue.o protocol.o transport.o usb.o \ ifeq ($(CONFIG_USB_LIBUSUAL),) usb-storage-objs += usual-tables.o else - obj-$(CONFIG_USB) += libusual.o usual-tables.o + obj-$(CONFIG_USB) += usb-libusual.o + usb-libusual-objs := libusual.o usual-tables.o endif obj-$(CONFIG_USB_STORAGE_ALAUDA) += ums-alauda.o diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c index 49aedb36dc1..fcb32021721 100644 --- a/drivers/usb/storage/transport.c +++ b/drivers/usb/storage/transport.c @@ -247,10 +247,8 @@ int usb_stor_clear_halt(struct us_data *us, unsigned int pipe) USB_ENDPOINT_HALT, endp, NULL, 0, 3*HZ); - /* reset the endpoint toggle */ if (result >= 0) - usb_settoggle(us->pusb_dev, usb_pipeendpoint(pipe), - usb_pipeout(pipe), 0); + usb_reset_endpoint(us->pusb_dev, endp); US_DEBUGP("%s: result = %d\n", __func__, result); return result; diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 1c1f643e8a7..96db479d116 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -975,12 +975,14 @@ UNUSUAL_DEV( 0x07c4, 0xa400, 0x0000, 0xffff, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY | US_FL_FIX_CAPACITY ), -/* Reported by Rauch Wolke <rauchwolke@gmx.net> */ +/* Reported by Rauch Wolke <rauchwolke@gmx.net> + * and augmented by binbin <binbinsh@gmail.com> (Bugzilla #12882) + */ UNUSUAL_DEV( 0x07c4, 0xa4a5, 0x0000, 0xffff, "Simple Tech/Datafab", "CF+SM Reader", US_SC_DEVICE, US_PR_DEVICE, NULL, - US_FL_IGNORE_RESIDUE ), + US_FL_IGNORE_RESIDUE | US_FL_MAX_SECTORS_64 ), /* Casio QV 2x00/3x00/4000/8000 digital still cameras are not conformant * to the USB storage specification in two ways: @@ -1376,6 +1378,14 @@ UNUSUAL_DEV( 0x10d6, 0x2200, 0x0100, 0x0100, US_SC_DEVICE, US_PR_DEVICE, NULL, 0), +/* Reported by Pascal Terjan <pterjan@mandriva.com> + * Ignore driver CD mode and force into modem mode by default. + */ +UNUSUAL_DEV( 0x1186, 0x3e04, 0x0000, 0x0000, + "D-Link", + "USB Mass Storage", + US_SC_DEVICE, US_PR_DEVICE, option_ms_init, 0), + /* Reported by Kevin Lloyd <linux@sierrawireless.com> * Entry is needed for the initializer function override, * which instructs the device to load as a modem diff --git a/drivers/usb/wusbcore/devconnect.c b/drivers/usb/wusbcore/devconnect.c index 386eaa22d21..4ac4300a3f9 100644 --- a/drivers/usb/wusbcore/devconnect.c +++ b/drivers/usb/wusbcore/devconnect.c @@ -267,6 +267,8 @@ static void wusbhc_devconnect_acked_work(struct work_struct *work) mutex_lock(&wusbhc->mutex); wusbhc_devconnect_acked(wusbhc, wusb_dev); mutex_unlock(&wusbhc->mutex); + + wusb_dev_put(wusb_dev); } /* @@ -396,7 +398,8 @@ static void __wusbhc_dev_disconnect(struct wusbhc *wusbhc, /* After a device disconnects, change the GTK (see [WUSB] * section 6.2.11.2). */ - wusbhc_gtk_rekey(wusbhc); + if (wusbhc->active) + wusbhc_gtk_rekey(wusbhc); /* The Wireless USB part has forgotten about the device already; now * khubd's timer will pick up the disconnection and remove the USB @@ -1084,15 +1087,21 @@ error_mmcie_set: * wusbhc_devconnect_stop - stop managing connected devices * @wusbhc: the WUSB HC * - * Removes the Host Info IE and stops the keep alives. - * - * FIXME: should this disconnect all devices? + * Disconnects any devices still connected, stops the keep alives and + * removes the Host Info IE. */ void wusbhc_devconnect_stop(struct wusbhc *wusbhc) { - cancel_delayed_work_sync(&wusbhc->keep_alive_timer); - WARN_ON(!list_empty(&wusbhc->cack_list)); + int i; + mutex_lock(&wusbhc->mutex); + for (i = 0; i < wusbhc->ports_max; i++) { + if (wusbhc->port[i].wusb_dev) + __wusbhc_dev_disconnect(wusbhc, &wusbhc->port[i]); + } + mutex_unlock(&wusbhc->mutex); + + cancel_delayed_work_sync(&wusbhc->keep_alive_timer); wusbhc_mmcie_rm(wusbhc, &wusbhc->wuie_host_info->hdr); kfree(wusbhc->wuie_host_info); wusbhc->wuie_host_info = NULL; diff --git a/drivers/usb/wusbcore/wusbhc.c b/drivers/usb/wusbcore/wusbhc.c index 07c63a31c79..ee6256f2363 100644 --- a/drivers/usb/wusbcore/wusbhc.c +++ b/drivers/usb/wusbcore/wusbhc.c @@ -88,33 +88,31 @@ static DEVICE_ATTR(wusb_trust_timeout, 0644, wusb_trust_timeout_show, wusb_trust_timeout_store); /* - * Show & store the current WUSB CHID + * Show the current WUSB CHID. */ static ssize_t wusb_chid_show(struct device *dev, struct device_attribute *attr, char *buf) { struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev); + const struct wusb_ckhdid *chid; ssize_t result = 0; if (wusbhc->wuie_host_info != NULL) - result += ckhdid_printf(buf, PAGE_SIZE, - &wusbhc->wuie_host_info->CHID); + chid = &wusbhc->wuie_host_info->CHID; + else + chid = &wusb_ckhdid_zero; + + result += ckhdid_printf(buf, PAGE_SIZE, chid); + result += sprintf(buf + result, "\n"); + return result; } /* - * Store a new CHID - * - * This will (FIXME) trigger many changes. - * - * - Send an all zeros CHID and it will stop the controller - * - Send a non-zero CHID and it will start it - * (unless it was started, it will just change the CHID, - * diconnecting all devices first). + * Store a new CHID. * - * So first we scan the MMC we are sent and then we act on it. We - * read it in the same format as we print it, an ASCII string of 16 - * hex bytes. + * - Write an all zeros CHID and it will stop the controller + * - Write a non-zero CHID and it will start it. * * See wusbhc_chid_set() for more info. */ @@ -339,13 +337,15 @@ void wusbhc_giveback_urb(struct wusbhc *wusbhc, struct urb *urb, int status) { struct wusb_dev *wusb_dev = __wusb_dev_get_by_usb_dev(wusbhc, urb->dev); - if (status == 0) { + if (status == 0 && wusb_dev) { wusb_dev->entry_ts = jiffies; - /* wusbhc_devconnect_acked() can't be called from from + /* wusbhc_devconnect_acked() can't be called from atomic context so defer it to a work queue. */ if (!list_empty(&wusb_dev->cack_node)) queue_work(wusbd, &wusb_dev->devconnect_acked_work); + else + wusb_dev_put(wusb_dev); } usb_hcd_giveback_urb(&wusbhc->usb_hcd, urb, status); |