aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2009-04-21 17:12:16 +0900
committerPaul Mundt <lethal@linux-sh.org>2009-04-21 17:12:16 +0900
commit4db25d496c09fdf094d52d11a90ae51f9ee473c6 (patch)
tree77ab8003db1d6ccbcf3a9acafad26002fba37b63 /drivers
parentb8c193f88ebd8705b3e916532539031cd9fc0b4c (diff)
parent8c31813f31cd4403b46802866949a95a6e8fa584 (diff)
Merge branch 'sh/stable-updates' into sh/for-2.6.30
Diffstat (limited to 'drivers')
-rw-r--r--drivers/ata/libata-core.c25
-rw-r--r--drivers/ata/libata-scsi.c30
-rw-r--r--drivers/ata/libata-sff.c27
-rw-r--r--drivers/ata/pata_hpt37x.c22
-rw-r--r--drivers/ata/pata_legacy.c37
-rw-r--r--drivers/ata/pata_ninja32.c4
-rw-r--r--drivers/ata/pata_via.c74
-rw-r--r--drivers/ata/sata_mv.c58
-rw-r--r--drivers/base/base.h2
-rw-r--r--drivers/base/core.c3
-rw-r--r--drivers/base/platform.c239
-rw-r--r--drivers/block/ub.c20
-rw-r--r--drivers/char/mem.c27
-rw-r--r--drivers/input/gameport/gameport.c14
-rw-r--r--drivers/input/input.c1
-rw-r--r--drivers/input/keyboard/atkbd.c20
-rw-r--r--drivers/input/keyboard/bf54x-keys.c2
-rw-r--r--drivers/input/misc/Kconfig2
-rw-r--r--drivers/input/mouse/pc110pad.c1
-rw-r--r--drivers/input/serio/i8042-x86ia64io.h28
-rw-r--r--drivers/input/serio/i8042.c37
-rw-r--r--drivers/input/touchscreen/ad7877.c4
-rw-r--r--drivers/input/touchscreen/ad7879.c3
-rw-r--r--drivers/input/touchscreen/ads7846.c12
-rw-r--r--drivers/input/touchscreen/da9034-ts.c29
-rw-r--r--drivers/input/touchscreen/mainstone-wm97xx.c7
-rw-r--r--drivers/input/touchscreen/wm97xx-core.c3
-rw-r--r--drivers/isdn/hisax/st5481_usb.c9
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw.c1
-rw-r--r--drivers/net/a2065.c17
-rw-r--r--drivers/net/ariadne.c19
-rw-r--r--drivers/net/arm/am79c961a.c24
-rw-r--r--drivers/net/arm/at91_ether.c32
-rw-r--r--drivers/net/arm/ep93xx_eth.c21
-rw-r--r--drivers/net/arm/ether1.c19
-rw-r--r--drivers/net/arm/ether3.c19
-rw-r--r--drivers/net/atarilance.c18
-rw-r--r--drivers/net/au1000_eth.c23
-rw-r--r--drivers/net/benet/be_ethtool.c4
-rw-r--r--drivers/net/bfin_mac.c24
-rw-r--r--drivers/net/bonding/bond_alb.c2
-rw-r--r--drivers/net/bonding/bond_main.c5
-rw-r--r--drivers/net/bonding/bond_sysfs.c14
-rw-r--r--drivers/net/cris/eth_v10.c30
-rw-r--r--drivers/net/declance.c17
-rw-r--r--drivers/net/e1000/e1000_main.c48
-rw-r--r--drivers/net/e1000e/netdev.c61
-rw-r--r--drivers/net/ehea/ehea_main.c4
-rw-r--r--drivers/net/forcedeth.c4
-rw-r--r--drivers/net/fs_enet/fs_enet-main.c27
-rw-r--r--drivers/net/gianfar.c2
-rw-r--r--drivers/net/ibm_newemac/core.c41
-rw-r--r--drivers/net/igb/e1000_mac.c2
-rw-r--r--drivers/net/igb/e1000_mac.h1
-rw-r--r--drivers/net/igb/e1000_mbx.c17
-rw-r--r--drivers/net/igb/e1000_mbx.h2
-rw-r--r--drivers/net/igb/igb_main.c37
-rw-r--r--drivers/net/igbvf/igbvf.h3
-rw-r--r--drivers/net/igbvf/netdev.c9
-rw-r--r--drivers/net/igbvf/vf.c2
-rw-r--r--drivers/net/igbvf/vf.h1
-rw-r--r--drivers/net/ioc3-eth.c22
-rw-r--r--drivers/net/isa-skeleton.c20
-rw-r--r--drivers/net/ixgbe/ixgbe_82598.c59
-rw-r--r--drivers/net/ixgbe/ixgbe_82599.c40
-rw-r--r--drivers/net/ixgbe/ixgbe_common.c55
-rw-r--r--drivers/net/ixgbe/ixgbe_common.h3
-rw-r--r--drivers/net/ixgbe/ixgbe_ethtool.c24
-rw-r--r--drivers/net/ixgbe/ixgbe_main.c57
-rw-r--r--drivers/net/mac89x0.c18
-rw-r--r--drivers/net/macb.c19
-rw-r--r--drivers/net/macsonic.c19
-rw-r--r--drivers/net/myri10ge/myri10ge.c1
-rw-r--r--drivers/net/phy/fixed.c5
-rw-r--r--drivers/net/phy/marvell.c54
-rw-r--r--drivers/net/phy/phy.c14
-rw-r--r--drivers/net/sfc/efx.c7
-rw-r--r--drivers/net/sfc/falcon.c4
-rw-r--r--drivers/net/sh_eth.c21
-rw-r--r--drivers/net/skge.c4
-rw-r--r--drivers/net/sun3_82586.c19
-rw-r--r--drivers/net/tc35815.c27
-rw-r--r--drivers/net/tg3.c9
-rw-r--r--drivers/net/tsi108_eth.c20
-rw-r--r--drivers/net/tun.c5
-rw-r--r--drivers/net/via-velocity.c4
-rw-r--r--drivers/net/xtsonic.c19
-rw-r--r--drivers/s390/block/dasd.c37
-rw-r--r--drivers/s390/block/dasd_eckd.c16
-rw-r--r--drivers/s390/cio/qdio_main.c43
-rw-r--r--drivers/sbus/char/jsflash.c15
-rw-r--r--drivers/sbus/char/uctrl.c7
-rw-r--r--drivers/serial/samsung.c4
-rw-r--r--drivers/spi/pxa2xx_spi.c2
-rw-r--r--drivers/staging/android/binder.c201
-rw-r--r--drivers/staging/at76_usb/at76_usb.c20
-rw-r--r--drivers/staging/epl/VirtualEthernetLinux.c17
-rw-r--r--drivers/staging/et131x/et131x_netdev.c23
-rw-r--r--drivers/staging/go7007/go7007-driver.c15
-rw-r--r--drivers/staging/go7007/wis-sony-tuner.c2
-rw-r--r--drivers/staging/line6/audio.c9
-rw-r--r--drivers/staging/otus/usbdrv.c47
-rw-r--r--drivers/staging/otus/zdusb.c3
-rw-r--r--drivers/staging/otus/zdusb.h4
-rw-r--r--drivers/staging/pohmelfs/config.c61
-rw-r--r--drivers/staging/pohmelfs/dir.c24
-rw-r--r--drivers/staging/pohmelfs/inode.c137
-rw-r--r--drivers/staging/pohmelfs/lock.c3
-rw-r--r--drivers/staging/pohmelfs/net.c72
-rw-r--r--drivers/staging/pohmelfs/netfs.h21
-rw-r--r--drivers/staging/pohmelfs/trans.c33
-rw-r--r--drivers/staging/rt2860/rt_main_dev.c25
-rw-r--r--drivers/staging/rt2870/rt2870.h1
-rw-r--r--drivers/staging/rt2870/rt_main_dev.c28
-rw-r--r--drivers/staging/rt3070/rt_main_dev.c29
-rw-r--r--drivers/staging/slicoss/README31
-rw-r--r--drivers/staging/slicoss/slicoss.c25
-rw-r--r--drivers/staging/stlc45xx/Kconfig2
-rw-r--r--drivers/staging/sxg/sxg.c127
-rw-r--r--drivers/staging/uc2322/aten2011.c28
-rw-r--r--drivers/staging/wlan-ng/p80211netdev.c20
-rw-r--r--drivers/uio/uio_cif.c1
-rw-r--r--drivers/usb/class/cdc-wdm.c2
-rw-r--r--drivers/usb/core/devio.c2
-rw-r--r--drivers/usb/core/hcd.c26
-rw-r--r--drivers/usb/core/hcd.h14
-rw-r--r--drivers/usb/core/message.c58
-rw-r--r--drivers/usb/core/usb.c2
-rw-r--r--drivers/usb/gadget/u_ether.c8
-rw-r--r--drivers/usb/host/whci/asl.c15
-rw-r--r--drivers/usb/host/whci/hcd.c23
-rw-r--r--drivers/usb/host/whci/pzl.c16
-rw-r--r--drivers/usb/host/whci/qset.c24
-rw-r--r--drivers/usb/host/whci/whcd.h1
-rw-r--r--drivers/usb/host/whci/whci-hc.h1
-rw-r--r--drivers/usb/musb/cppi_dma.c23
-rw-r--r--drivers/usb/musb/musb_core.c12
-rw-r--r--drivers/usb/musb/musb_gadget.c33
-rw-r--r--drivers/usb/musb/musb_host.c406
-rw-r--r--drivers/usb/musb/musbhsdma.c66
-rw-r--r--drivers/usb/serial/ftdi_sio.c1
-rw-r--r--drivers/usb/serial/ftdi_sio.h7
-rw-r--r--drivers/usb/serial/moto_modem.c1
-rw-r--r--drivers/usb/serial/option.c5
-rw-r--r--drivers/usb/serial/qcserial.c21
-rw-r--r--drivers/usb/storage/Makefile3
-rw-r--r--drivers/usb/storage/transport.c4
-rw-r--r--drivers/usb/storage/unusual_devs.h14
-rw-r--r--drivers/usb/wusbcore/devconnect.c21
-rw-r--r--drivers/usb/wusbcore/wusbhc.c32
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(&param, 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(&param, 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 = &ether1_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 = &ether3_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);