diff options
author | Steve French <sfrench@us.ibm.com> | 2009-07-16 04:21:39 +0000 |
---|---|---|
committer | Steve French <sfrench@us.ibm.com> | 2009-07-16 04:21:39 +0000 |
commit | f6c43385435640e056424034caac0d765c45e370 (patch) | |
tree | 54c2ba0a7d3abb156bc51f6b9f02e00f0a260f85 /drivers | |
parent | 65bc98b0059360e458aebd208587be44641227c1 (diff) | |
parent | 35b5c55fee08e6e4001ba98060a2d0b82f70b5f4 (diff) |
Merge branch 'master' of /pub/scm/linux/kernel/git/torvalds/linux-2.6
Diffstat (limited to 'drivers')
232 files changed, 2970 insertions, 2789 deletions
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 15a23031833..336eb1ed73c 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -513,6 +513,7 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(INTEL, 0x502a), board_ahci }, /* Tolapai */ { PCI_VDEVICE(INTEL, 0x502b), board_ahci }, /* Tolapai */ { PCI_VDEVICE(INTEL, 0x3a05), board_ahci }, /* ICH10 */ + { PCI_VDEVICE(INTEL, 0x3a22), board_ahci }, /* ICH10 */ { PCI_VDEVICE(INTEL, 0x3a25), board_ahci }, /* ICH10 */ { PCI_VDEVICE(INTEL, 0x3b24), board_ahci }, /* PCH RAID */ { PCI_VDEVICE(INTEL, 0x3b25), board_ahci }, /* PCH RAID */ diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 045a486a09e..2c6aedaef71 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -3392,17 +3392,27 @@ int ata_down_xfermask_limit(struct ata_device *dev, unsigned int sel) static int ata_dev_set_mode(struct ata_device *dev) { + struct ata_port *ap = dev->link->ap; struct ata_eh_context *ehc = &dev->link->eh_context; + const bool nosetxfer = dev->horkage & ATA_HORKAGE_NOSETXFER; const char *dev_err_whine = ""; int ign_dev_err = 0; - unsigned int err_mask; + unsigned int err_mask = 0; int rc; dev->flags &= ~ATA_DFLAG_PIO; if (dev->xfer_shift == ATA_SHIFT_PIO) dev->flags |= ATA_DFLAG_PIO; - err_mask = ata_dev_set_xfermode(dev); + if (nosetxfer && ap->flags & ATA_FLAG_SATA && ata_id_is_sata(dev->id)) + dev_err_whine = " (SET_XFERMODE skipped)"; + else { + if (nosetxfer) + ata_dev_printk(dev, KERN_WARNING, + "NOSETXFER but PATA detected - can't " + "skip SETXFER, might malfunction\n"); + err_mask = ata_dev_set_xfermode(dev); + } if (err_mask & ~AC_ERR_DEV) goto fail; @@ -4297,6 +4307,12 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { /* Devices which aren't very happy with higher link speeds */ { "WD My Book", NULL, ATA_HORKAGE_1_5_GBPS, }, + /* + * Devices which choke on SETXFER. Applies only if both the + * device and controller are SATA. + */ + { "PIONEER DVD-RW DVRTD08", "1.00", ATA_HORKAGE_NOSETXFER }, + /* End Marker */ { } }; diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index fa22f94ca41..1a07c061f64 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -2517,6 +2517,10 @@ int ata_eh_reset(struct ata_link *link, int classify, ata_eh_about_to_do(link, NULL, ATA_EH_RESET); rc = ata_do_reset(link, reset, classes, deadline, true); + if (rc) { + failed_link = link; + goto fail; + } } } else { if (verbose) diff --git a/drivers/ata/pata_at91.c b/drivers/ata/pata_at91.c index 4b27617be26..8561a9f195c 100644 --- a/drivers/ata/pata_at91.c +++ b/drivers/ata/pata_at91.c @@ -312,11 +312,12 @@ err_ide_ioremap: static int __devexit pata_at91_remove(struct platform_device *pdev) { struct ata_host *host = dev_get_drvdata(&pdev->dev); - struct at91_ide_info *info = host->private_data; + struct at91_ide_info *info; struct device *dev = &pdev->dev; if (!host) return 0; + info = host->private_data; ata_host_detach(host); diff --git a/drivers/base/devres.c b/drivers/base/devres.c index e8beb8e5b62..05dd307e8f0 100644 --- a/drivers/base/devres.c +++ b/drivers/base/devres.c @@ -428,6 +428,9 @@ int devres_release_all(struct device *dev) { unsigned long flags; + /* Looks like an uninitialized device structure */ + if (WARN_ON(dev->devres_head.next == NULL)) + return -ENODEV; spin_lock_irqsave(&dev->devres_lock, flags); return release_nodes(dev, dev->devres_head.next, &dev->devres_head, flags); diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index fc466531260..f285f441fab 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -217,8 +217,10 @@ firmware_data_read(struct kobject *kobj, struct bin_attribute *bin_attr, ret_count = -ENODEV; goto out; } - if (offset > fw->size) - return 0; + if (offset > fw->size) { + ret_count = 0; + goto out; + } if (count > fw->size - offset) count = fw->size - offset; diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c index 668dc234b8e..1e6b7c14f69 100644 --- a/drivers/block/DAC960.c +++ b/drivers/block/DAC960.c @@ -36,6 +36,7 @@ #include <linux/ioport.h> #include <linux/mm.h> #include <linux/slab.h> +#include <linux/smp_lock.h> #include <linux/proc_fs.h> #include <linux/reboot.h> #include <linux/spinlock.h> diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index bb72ada9f07..1d886e079c5 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -298,6 +298,22 @@ config BLK_DEV_NBD If unsure, say N. +config BLK_DEV_OSD + tristate "OSD object-as-blkdev support" + depends on SCSI_OSD_ULD + ---help--- + Saying Y or M here will allow the exporting of a single SCSI + OSD (object-based storage) object as a Linux block device. + + For example, if you create a 2G object on an OSD device, + you can then use this module to present that 2G object as + a Linux block device. + + To compile this driver as a module, choose M here: the + module will be called osdblk. + + If unsure, say N. + config BLK_DEV_SX8 tristate "Promise SATA SX8 support" depends on PCI diff --git a/drivers/block/Makefile b/drivers/block/Makefile index 7755a5e2a85..cdaa3f8fddf 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_XILINX_SYSACE) += xsysace.o obj-$(CONFIG_CDROM_PKTCDVD) += pktcdvd.o obj-$(CONFIG_MG_DISK) += mg_disk.o obj-$(CONFIG_SUNVDC) += sunvdc.o +obj-$(CONFIG_BLK_DEV_OSD) += osdblk.o obj-$(CONFIG_BLK_DEV_UMEM) += umem.o obj-$(CONFIG_BLK_DEV_NBD) += nbd.o diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 65a0655e7fc..a52cc7fe45e 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -26,6 +26,7 @@ #include <linux/pci.h> #include <linux/kernel.h> #include <linux/slab.h> +#include <linux/smp_lock.h> #include <linux/delay.h> #include <linux/major.h> #include <linux/fs.h> diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 801f4ab8330..5757188cd1f 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -61,7 +61,6 @@ #include <linux/blkdev.h> #include <linux/blkpg.h> #include <linux/init.h> -#include <linux/smp_lock.h> #include <linux/swap.h> #include <linux/slab.h> #include <linux/loop.h> diff --git a/drivers/block/osdblk.c b/drivers/block/osdblk.c new file mode 100644 index 00000000000..13c1aee6aa3 --- /dev/null +++ b/drivers/block/osdblk.c @@ -0,0 +1,701 @@ + +/* + osdblk.c -- Export a single SCSI OSD object as a Linux block device + + + Copyright 2009 Red Hat, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + + + Instructions for use + -------------------- + + 1) Map a Linux block device to an existing OSD object. + + In this example, we will use partition id 1234, object id 5678, + OSD device /dev/osd1. + + $ echo "1234 5678 /dev/osd1" > /sys/class/osdblk/add + + + 2) List all active blkdev<->object mappings. + + In this example, we have performed step #1 twice, creating two blkdevs, + mapped to two separate OSD objects. + + $ cat /sys/class/osdblk/list + 0 174 1234 5678 /dev/osd1 + 1 179 1994 897123 /dev/osd0 + + The columns, in order, are: + - blkdev unique id + - blkdev assigned major + - OSD object partition id + - OSD object id + - OSD device + + + 3) Remove an active blkdev<->object mapping. + + In this example, we remove the mapping with blkdev unique id 1. + + $ echo 1 > /sys/class/osdblk/remove + + + NOTE: The actual creation and deletion of OSD objects is outside the scope + of this driver. + + */ + +#include <linux/kernel.h> +#include <linux/device.h> +#include <linux/module.h> +#include <linux/fs.h> +#include <scsi/osd_initiator.h> +#include <scsi/osd_attributes.h> +#include <scsi/osd_sec.h> +#include <scsi/scsi_device.h> + +#define DRV_NAME "osdblk" +#define PFX DRV_NAME ": " + +/* #define _OSDBLK_DEBUG */ +#ifdef _OSDBLK_DEBUG +#define OSDBLK_DEBUG(fmt, a...) \ + printk(KERN_NOTICE "osdblk @%s:%d: " fmt, __func__, __LINE__, ##a) +#else +#define OSDBLK_DEBUG(fmt, a...) \ + do { if (0) printk(fmt, ##a); } while (0) +#endif + +MODULE_AUTHOR("Jeff Garzik <jeff@garzik.org>"); +MODULE_DESCRIPTION("block device inside an OSD object osdblk.ko"); +MODULE_LICENSE("GPL"); + +struct osdblk_device; + +enum { + OSDBLK_MINORS_PER_MAJOR = 256, /* max minors per blkdev */ + OSDBLK_MAX_REQ = 32, /* max parallel requests */ + OSDBLK_OP_TIMEOUT = 4 * 60, /* sync OSD req timeout */ +}; + +struct osdblk_request { + struct request *rq; /* blk layer request */ + struct bio *bio; /* cloned bio */ + struct osdblk_device *osdev; /* associated blkdev */ +}; + +struct osdblk_device { + int id; /* blkdev unique id */ + + int major; /* blkdev assigned major */ + struct gendisk *disk; /* blkdev's gendisk and rq */ + struct request_queue *q; + + struct osd_dev *osd; /* associated OSD */ + + char name[32]; /* blkdev name, e.g. osdblk34 */ + + spinlock_t lock; /* queue lock */ + + struct osd_obj_id obj; /* OSD partition, obj id */ + uint8_t obj_cred[OSD_CAP_LEN]; /* OSD cred */ + + struct osdblk_request req[OSDBLK_MAX_REQ]; /* request table */ + + struct list_head node; + + char osd_path[0]; /* OSD device path */ +}; + +static struct class *class_osdblk; /* /sys/class/osdblk */ +static DEFINE_MUTEX(ctl_mutex); /* Serialize open/close/setup/teardown */ +static LIST_HEAD(osdblkdev_list); + +static struct block_device_operations osdblk_bd_ops = { + .owner = THIS_MODULE, +}; + +static const struct osd_attr g_attr_logical_length = ATTR_DEF( + OSD_APAGE_OBJECT_INFORMATION, OSD_ATTR_OI_LOGICAL_LENGTH, 8); + +static void osdblk_make_credential(u8 cred_a[OSD_CAP_LEN], + const struct osd_obj_id *obj) +{ + osd_sec_init_nosec_doall_caps(cred_a, obj, false, true); +} + +/* copied from exofs; move to libosd? */ +/* + * Perform a synchronous OSD operation. copied from exofs; move to libosd? + */ +static int osd_sync_op(struct osd_request *or, int timeout, uint8_t *credential) +{ + int ret; + + or->timeout = timeout; + ret = osd_finalize_request(or, 0, credential, NULL); + if (ret) + return ret; + + ret = osd_execute_request(or); + + /* osd_req_decode_sense(or, ret); */ + return ret; +} + +/* + * Perform an asynchronous OSD operation. copied from exofs; move to libosd? + */ +static int osd_async_op(struct osd_request *or, osd_req_done_fn *async_done, + void *caller_context, u8 *cred) +{ + int ret; + + ret = osd_finalize_request(or, 0, cred, NULL); + if (ret) + return ret; + + ret = osd_execute_request_async(or, async_done, caller_context); + + return ret; +} + +/* copied from exofs; move to libosd? */ +static int extract_attr_from_req(struct osd_request *or, struct osd_attr *attr) +{ + struct osd_attr cur_attr = {.attr_page = 0}; /* start with zeros */ + void *iter = NULL; + int nelem; + + do { + nelem = 1; + osd_req_decode_get_attr_list(or, &cur_attr, &nelem, &iter); + if ((cur_attr.attr_page == attr->attr_page) && + (cur_attr.attr_id == attr->attr_id)) { + attr->len = cur_attr.len; + attr->val_ptr = cur_attr.val_ptr; + return 0; + } + } while (iter); + + return -EIO; +} + +static int osdblk_get_obj_size(struct osdblk_device *osdev, u64 *size_out) +{ + struct osd_request *or; + struct osd_attr attr; + int ret; + + /* start request */ + or = osd_start_request(osdev->osd, GFP_KERNEL); + if (!or) + return -ENOMEM; + + /* create a get-attributes(length) request */ + osd_req_get_attributes(or, &osdev->obj); + + osd_req_add_get_attr_list(or, &g_attr_logical_length, 1); + + /* execute op synchronously */ + ret = osd_sync_op(or, OSDBLK_OP_TIMEOUT, osdev->obj_cred); + if (ret) + goto out; + + /* extract length from returned attribute info */ + attr = g_attr_logical_length; + ret = extract_attr_from_req(or, &attr); + if (ret) + goto out; + + *size_out = get_unaligned_be64(attr.val_ptr); + +out: + osd_end_request(or); + return ret; + +} + +static void osdblk_osd_complete(struct osd_request *or, void *private) +{ + struct osdblk_request *orq = private; + struct osd_sense_info osi; + int ret = osd_req_decode_sense(or, &osi); + + if (ret) { + ret = -EIO; + OSDBLK_DEBUG("osdblk_osd_complete with err=%d\n", ret); + } + + /* complete OSD request */ + osd_end_request(or); + + /* complete request passed to osdblk by block layer */ + __blk_end_request_all(orq->rq, ret); +} + +static void bio_chain_put(struct bio *chain) +{ + struct bio *tmp; + + while (chain) { + tmp = chain; + chain = chain->bi_next; + + bio_put(tmp); + } +} + +static struct bio *bio_chain_clone(struct bio *old_chain, gfp_t gfpmask) +{ + struct bio *tmp, *new_chain = NULL, *tail = NULL; + + while (old_chain) { + tmp = bio_kmalloc(gfpmask, old_chain->bi_max_vecs); + if (!tmp) + goto err_out; + + __bio_clone(tmp, old_chain); + tmp->bi_bdev = NULL; + gfpmask &= ~__GFP_WAIT; + tmp->bi_next = NULL; + + if (!new_chain) + new_chain = tail = tmp; + else { + tail->bi_next = tmp; + tail = tmp; + } + + old_chain = old_chain->bi_next; + } + + return new_chain; + +err_out: + OSDBLK_DEBUG("bio_chain_clone with err\n"); + bio_chain_put(new_chain); + return NULL; +} + +static void osdblk_rq_fn(struct request_queue *q) +{ + struct osdblk_device *osdev = q->queuedata; + + while (1) { + struct request *rq; + struct osdblk_request *orq; + struct osd_request *or; + struct bio *bio; + bool do_write, do_flush; + + /* peek at request from block layer */ + rq = blk_fetch_request(q); + if (!rq) + break; + + /* filter out block requests we don't understand */ + if (!blk_fs_request(rq) && !blk_barrier_rq(rq)) { + blk_end_request_all(rq, 0); + continue; + } + + /* deduce our operation (read, write, flush) */ + /* I wish the block layer simplified cmd_type/cmd_flags/cmd[] + * into a clearly defined set of RPC commands: + * read, write, flush, scsi command, power mgmt req, + * driver-specific, etc. + */ + + do_flush = (rq->special == (void *) 0xdeadbeefUL); + do_write = (rq_data_dir(rq) == WRITE); + + if (!do_flush) { /* osd_flush does not use a bio */ + /* a bio clone to be passed down to OSD request */ + bio = bio_chain_clone(rq->bio, GFP_ATOMIC); + if (!bio) + break; + } else + bio = NULL; + + /* alloc internal OSD request, for OSD command execution */ + or = osd_start_request(osdev->osd, GFP_ATOMIC); + if (!or) { + bio_chain_put(bio); + OSDBLK_DEBUG("osd_start_request with err\n"); + break; + } + + orq = &osdev->req[rq->tag]; + orq->rq = rq; + orq->bio = bio; + orq->osdev = osdev; + + /* init OSD command: flush, write or read */ + if (do_flush) + osd_req_flush_object(or, &osdev->obj, + OSD_CDB_FLUSH_ALL, 0, 0); + else if (do_write) + osd_req_write(or, &osdev->obj, blk_rq_pos(rq) * 512ULL, + bio, blk_rq_bytes(rq)); + else + osd_req_read(or, &osdev->obj, blk_rq_pos(rq) * 512ULL, + bio, blk_rq_bytes(rq)); + + OSDBLK_DEBUG("%s 0x%x bytes at 0x%llx\n", + do_flush ? "flush" : do_write ? + "write" : "read", blk_rq_bytes(rq), + blk_rq_pos(rq) * 512ULL); + + /* begin OSD command execution */ + if (osd_async_op(or, osdblk_osd_complete, orq, + osdev->obj_cred)) { + osd_end_request(or); + blk_requeue_request(q, rq); + bio_chain_put(bio); + OSDBLK_DEBUG("osd_execute_request_async with err\n"); + break; + } + + /* remove the special 'flush' marker, now that the command + * is executing + */ + rq->special = NULL; + } +} + +static void osdblk_prepare_flush(struct request_queue *q, struct request *rq) +{ + /* add driver-specific marker, to indicate that this request + * is a flush command + */ + rq->special = (void *) 0xdeadbeefUL; +} + +static void osdblk_free_disk(struct osdblk_device *osdev) +{ + struct gendisk *disk = osdev->disk; + + if (!disk) + return; + + if (disk->flags & GENHD_FL_UP) + del_gendisk(disk); + if (disk->queue) + blk_cleanup_queue(disk->queue); + put_disk(disk); +} + +static int osdblk_init_disk(struct osdblk_device *osdev) +{ + struct gendisk *disk; + struct request_queue *q; + int rc; + u64 obj_size = 0; + + /* contact OSD, request size info about the object being mapped */ + rc = osdblk_get_obj_size(osdev, &obj_size); + if (rc) + return rc; + + /* create gendisk info */ + disk = alloc_disk(OSDBLK_MINORS_PER_MAJOR); + if (!disk) + return -ENOMEM; + + sprintf(disk->disk_name, DRV_NAME "%d", osdev->id); + disk->major = osdev->major; + disk->first_minor = 0; + disk->fops = &osdblk_bd_ops; + disk->private_data = osdev; + + /* init rq */ + q = blk_init_queue(osdblk_rq_fn, &osdev->lock); + if (!q) { + put_disk(disk); + return -ENOMEM; + } + + /* switch queue to TCQ mode; allocate tag map */ + rc = blk_queue_init_tags(q, OSDBLK_MAX_REQ, NULL); + if (rc) { + blk_cleanup_queue(q); + put_disk(disk); + return rc; + } + + /* Set our limits to the lower device limits, because osdblk cannot + * sleep when allocating a lower-request and therefore cannot be + * bouncing. + */ + blk_queue_stack_limits(q, osd_request_queue(osdev->osd)); + + blk_queue_prep_rq(q, blk_queue_start_tag); + blk_queue_ordered(q, QUEUE_ORDERED_DRAIN_FLUSH, osdblk_prepare_flush); + + disk->queue = q; + + q->queuedata = osdev; + + osdev->disk = disk; + osdev->q = q; + + /* finally, announce the disk to the world */ + set_capacity(disk, obj_size / 512ULL); + add_disk(disk); + + printk(KERN_INFO "%s: Added of size 0x%llx\n", + disk->disk_name, (unsigned long long)obj_size); + + return 0; +} + +/******************************************************************** + * /sys/class/osdblk/ + * add map OSD object to blkdev + * remove unmap OSD object + * list show mappings + *******************************************************************/ + +static void class_osdblk_release(struct class *cls) +{ + kfree(cls); +} + +static ssize_t class_osdblk_list(struct class *c, char *data) +{ + int n = 0; + struct list_head *tmp; + + mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); + + list_for_each(tmp, &osdblkdev_list) { + struct osdblk_device *osdev; + + osdev = list_entry(tmp, struct osdblk_device, node); + + n += sprintf(data+n, "%d %d %llu %llu %s\n", + osdev->id, + osdev->major, + osdev->obj.partition, + osdev->obj.id, + osdev->osd_path); + } + + mutex_unlock(&ctl_mutex); + return n; +} + +static ssize_t class_osdblk_add(struct class *c, const char *buf, size_t count) +{ + struct osdblk_device *osdev; + ssize_t rc; + int irc, new_id = 0; + struct list_head *tmp; + + if (!try_module_get(THIS_MODULE)) + return -ENODEV; + + /* new osdblk_device object */ + osdev = kzalloc(sizeof(*osdev) + strlen(buf) + 1, GFP_KERNEL); + if (!osdev) { + rc = -ENOMEM; + goto err_out_mod; + } + + /* static osdblk_device initialization */ + spin_lock_init(&osdev->lock); + INIT_LIST_HEAD(&osdev->node); + + /* generate unique id: find highest unique id, add one */ + + mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); + + list_for_each(tmp, &osdblkdev_list) { + struct osdblk_device *osdev; + + osdev = list_entry(tmp, struct osdblk_device, node); + if (osdev->id > new_id) + new_id = osdev->id + 1; + } + + osdev->id = new_id; + + /* add to global list */ + list_add_tail(&osdev->node, &osdblkdev_list); + + mutex_unlock(&ctl_mutex); + + /* parse add command */ + if (sscanf(buf, "%llu %llu %s", &osdev->obj.partition, &osdev->obj.id, + osdev->osd_path) != 3) { + rc = -EINVAL; + goto err_out_slot; + } + + /* initialize rest of new object */ + sprintf(osdev->name, DRV_NAME "%d", osdev->id); + + /* contact requested OSD */ + osdev->osd = osduld_path_lookup(osdev->osd_path); + if (IS_ERR(osdev->osd)) { + rc = PTR_ERR(osdev->osd); + goto err_out_slot; + } + + /* build OSD credential */ + osdblk_make_credential(osdev->obj_cred, &osdev->obj); + + /* register our block device */ + irc = register_blkdev(0, osdev->name); + if (irc < 0) { + rc = irc; + goto err_out_osd; + } + + osdev->major = irc; + + /* set up and announce blkdev mapping */ + rc = osdblk_init_disk(osdev); + if (rc) + goto err_out_blkdev; + + return count; + +err_out_blkdev: + unregister_blkdev(osdev->major, osdev->name); +err_out_osd: + osduld_put_device(osdev->osd); +err_out_slot: + mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); + list_del_init(&osdev->node); + mutex_unlock(&ctl_mutex); + + kfree(osdev); +err_out_mod: + OSDBLK_DEBUG("Error adding device %s\n", buf); + module_put(THIS_MODULE); + return rc; +} + +static ssize_t class_osdblk_remove(struct class *c, const char *buf, + size_t count) +{ + struct osdblk_device *osdev = NULL; + int target_id, rc; + unsigned long ul; + struct list_head *tmp; + + rc = strict_strtoul(buf, 10, &ul); + if (rc) + return rc; + + /* convert to int; abort if we lost anything in the conversion */ + target_id = (int) ul; + if (target_id != ul) + return -EINVAL; + + /* remove object from list immediately */ + mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); + + list_for_each(tmp, &osdblkdev_list) { + osdev = list_entry(tmp, struct osdblk_device, node); + if (osdev->id == target_id) { + list_del_init(&osdev->node); + break; + } + osdev = NULL; + } + + mutex_unlock(&ctl_mutex); + + if (!osdev) + return -ENOENT; + + /* clean up and free blkdev and associated OSD connection */ + osdblk_free_disk(osdev); + unregister_blkdev(osdev->major, osdev->name); + osduld_put_device(osdev->osd); + kfree(osdev); + + /* release module ref */ + module_put(THIS_MODULE); + + return count; +} + +static struct class_attribute class_osdblk_attrs[] = { + __ATTR(add, 0200, NULL, class_osdblk_add), + __ATTR(remove, 0200, NULL, class_osdblk_remove), + __ATTR(list, 0444, class_osdblk_list, NULL), + __ATTR_NULL +}; + +static int osdblk_sysfs_init(void) +{ + int ret = 0; + + /* + * create control files in sysfs + * /sys/class/osdblk/... + */ + class_osdblk = kzalloc(sizeof(*class_osdblk), GFP_KERNEL); + if (!class_osdblk) + return -ENOMEM; + + class_osdblk->name = DRV_NAME; + class_osdblk->owner = THIS_MODULE; + class_osdblk->class_release = class_osdblk_release; + class_osdblk->class_attrs = class_osdblk_attrs; + + ret = class_register(class_osdblk); + if (ret) { + kfree(class_osdblk); + class_osdblk = NULL; + printk(PFX "failed to create class osdblk\n"); + return ret; + } + + return 0; +} + +static void osdblk_sysfs_cleanup(void) +{ + if (class_osdblk) + class_destroy(class_osdblk); + class_osdblk = NULL; +} + +static int __init osdblk_init(void) +{ + int rc; + + rc = osdblk_sysfs_init(); + if (rc) + return rc; + + return 0; +} + +static void __exit osdblk_exit(void) +{ + osdblk_sysfs_cleanup(); +} + +module_init(osdblk_init); +module_exit(osdblk_exit); + diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index 83650e00632..99a506f619b 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -1372,8 +1372,10 @@ try_next_bio: wakeup = (pd->write_congestion_on > 0 && pd->bio_queue_size <= pd->write_congestion_off); spin_unlock(&pd->lock); - if (wakeup) - clear_bdi_congested(&pd->disk->queue->backing_dev_info, WRITE); + if (wakeup) { + clear_bdi_congested(&pd->disk->queue->backing_dev_info, + BLK_RW_ASYNC); + } pkt->sleep_time = max(PACKET_WAIT_TIME, 1); pkt_set_state(pkt, PACKET_WAITING_STATE); @@ -2592,10 +2594,10 @@ static int pkt_make_request(struct request_queue *q, struct bio *bio) spin_lock(&pd->lock); if (pd->write_congestion_on > 0 && pd->bio_queue_size >= pd->write_congestion_on) { - set_bdi_congested(&q->backing_dev_info, WRITE); + set_bdi_congested(&q->backing_dev_info, BLK_RW_ASYNC); do { spin_unlock(&pd->lock); - congestion_wait(WRITE, HZ); + congestion_wait(BLK_RW_ASYNC, HZ); spin_lock(&pd->lock); } while(pd->bio_queue_size > pd->write_congestion_off); } diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c index 1df9dda2e37..d5cde6d86f8 100644 --- a/drivers/bluetooth/hci_vhci.c +++ b/drivers/bluetooth/hci_vhci.c @@ -28,7 +28,6 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/slab.h> -#include <linux/smp_lock.h> #include <linux/types.h> #include <linux/errno.h> #include <linux/sched.h> diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c index 72429b6b2fa..6c32fbf0716 100644 --- a/drivers/char/amiserial.c +++ b/drivers/char/amiserial.c @@ -81,6 +81,7 @@ static char *serial_version = "4.30"; #include <linux/mm.h> #include <linux/seq_file.h> #include <linux/slab.h> +#include <linux/smp_lock.h> #include <linux/init.h> #include <linux/bitops.h> diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c index f3366d3f06c..2dafc2da064 100644 --- a/drivers/char/cyclades.c +++ b/drivers/char/cyclades.c @@ -633,6 +633,7 @@ #include <linux/tty.h> #include <linux/tty_flip.h> #include <linux/serial.h> +#include <linux/smp_lock.h> #include <linux/major.h> #include <linux/string.h> #include <linux/fcntl.h> diff --git a/drivers/char/epca.c b/drivers/char/epca.c index abef1f7d84f..ff647ca1c48 100644 --- a/drivers/char/epca.c +++ b/drivers/char/epca.c @@ -36,6 +36,7 @@ #include <linux/tty.h> #include <linux/tty_flip.h> #include <linux/slab.h> +#include <linux/smp_lock.h> #include <linux/ioport.h> #include <linux/interrupt.h> #include <linux/uaccess.h> diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c index 621d1184673..4f1f4cd670d 100644 --- a/drivers/char/isicom.c +++ b/drivers/char/isicom.c @@ -122,6 +122,7 @@ #include <linux/fs.h> #include <linux/sched.h> #include <linux/serial.h> +#include <linux/smp_lock.h> #include <linux/mm.h> #include <linux/interrupt.h> #include <linux/timer.h> diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c index 0c999f5bb3d..ab2f3349c5c 100644 --- a/drivers/char/istallion.c +++ b/drivers/char/istallion.c @@ -20,6 +20,7 @@ #include <linux/module.h> #include <linux/slab.h> +#include <linux/smp_lock.h> #include <linux/interrupt.h> #include <linux/tty.h> #include <linux/tty_flip.h> diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c index 65b6ff2442c..dd0083bbb64 100644 --- a/drivers/char/moxa.c +++ b/drivers/char/moxa.c @@ -34,6 +34,7 @@ #include <linux/tty.h> #include <linux/tty_flip.h> #include <linux/major.h> +#include <linux/smp_lock.h> #include <linux/string.h> #include <linux/fcntl.h> #include <linux/ptrace.h> diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c index 52d953eb30c..dbf8d52f31d 100644 --- a/drivers/char/mxser.c +++ b/drivers/char/mxser.c @@ -23,6 +23,7 @@ #include <linux/errno.h> #include <linux/signal.h> #include <linux/sched.h> +#include <linux/smp_lock.h> #include <linux/timer.h> #include <linux/interrupt.h> #include <linux/tty.h> diff --git a/drivers/char/n_hdlc.c b/drivers/char/n_hdlc.c index 1c43c8cdee2..c68118efad8 100644 --- a/drivers/char/n_hdlc.c +++ b/drivers/char/n_hdlc.c @@ -97,6 +97,7 @@ #include <linux/slab.h> #include <linux/tty.h> #include <linux/errno.h> +#include <linux/smp_lock.h> #include <linux/string.h> /* used in new tty drivers */ #include <linux/signal.h> /* used in new tty drivers */ #include <linux/if.h> diff --git a/drivers/char/n_r3964.c b/drivers/char/n_r3964.c index 2e99158ebb8..6934025a1ac 100644 --- a/drivers/char/n_r3964.c +++ b/drivers/char/n_r3964.c @@ -58,6 +58,7 @@ #include <linux/ioport.h> #include <linux/in.h> #include <linux/slab.h> +#include <linux/smp_lock.h> #include <linux/tty.h> #include <linux/errno.h> #include <linux/string.h> /* used in new tty drivers */ diff --git a/drivers/char/pty.c b/drivers/char/pty.c index 9d1b4f548f6..6e6942c45f5 100644 --- a/drivers/char/pty.c +++ b/drivers/char/pty.c @@ -22,6 +22,7 @@ #include <linux/major.h> #include <linux/mm.h> #include <linux/init.h> +#include <linux/smp_lock.h> #include <linux/sysctl.h> #include <linux/device.h> #include <linux/uaccess.h> diff --git a/drivers/char/rio/rio_linux.c b/drivers/char/rio/rio_linux.c index ce81da5b2da..d58c2eb07f0 100644 --- a/drivers/char/rio/rio_linux.c +++ b/drivers/char/rio/rio_linux.c @@ -44,6 +44,7 @@ #include <linux/delay.h> #include <linux/pci.h> #include <linux/slab.h> +#include <linux/smp_lock.h> #include <linux/miscdevice.h> #include <linux/init.h> diff --git a/drivers/char/riscom8.c b/drivers/char/riscom8.c index 21766045123..171711acf5c 100644 --- a/drivers/char/riscom8.c +++ b/drivers/char/riscom8.c @@ -47,6 +47,7 @@ #include <linux/init.h> #include <linux/delay.h> #include <linux/tty_flip.h> +#include <linux/smp_lock.h> #include <linux/spinlock.h> #include <linux/device.h> diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c index 63d5b628477..0e29a23ec4c 100644 --- a/drivers/char/rocket.c +++ b/drivers/char/rocket.c @@ -73,6 +73,7 @@ #include <linux/tty_driver.h> #include <linux/tty_flip.h> #include <linux/serial.h> +#include <linux/smp_lock.h> #include <linux/string.h> #include <linux/fcntl.h> #include <linux/ptrace.h> diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c index f1f24f0ee26..51e7a46787b 100644 --- a/drivers/char/serial167.c +++ b/drivers/char/serial167.c @@ -52,6 +52,7 @@ #include <linux/interrupt.h> #include <linux/serial.h> #include <linux/serialP.h> +#include <linux/smp_lock.h> #include <linux/string.h> #include <linux/fcntl.h> #include <linux/ptrace.h> diff --git a/drivers/char/specialix.c b/drivers/char/specialix.c index e72be4190a4..bfe4cdb2feb 100644 --- a/drivers/char/specialix.c +++ b/drivers/char/specialix.c @@ -87,6 +87,7 @@ #include <linux/tty_flip.h> #include <linux/mm.h> #include <linux/serial.h> +#include <linux/smp_lock.h> #include <linux/fcntl.h> #include <linux/major.h> #include <linux/delay.h> diff --git a/drivers/char/sx.c b/drivers/char/sx.c index 518f2a25d91..a81ec4fcf6f 100644 --- a/drivers/char/sx.c +++ b/drivers/char/sx.c @@ -216,6 +216,7 @@ #include <linux/eisa.h> #include <linux/pci.h> #include <linux/slab.h> +#include <linux/smp_lock.h> #include <linux/init.h> #include <linux/miscdevice.h> #include <linux/bitops.h> diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c index afded3a2379..813552f1488 100644 --- a/drivers/char/synclink.c +++ b/drivers/char/synclink.c @@ -81,6 +81,7 @@ #include <linux/mm.h> #include <linux/seq_file.h> #include <linux/slab.h> +#include <linux/smp_lock.h> #include <linux/delay.h> #include <linux/netdevice.h> #include <linux/vmalloc.h> diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c index a2e67e6df3a..91f20a92fdd 100644 --- a/drivers/char/synclink_gt.c +++ b/drivers/char/synclink_gt.c @@ -62,6 +62,7 @@ #include <linux/mm.h> #include <linux/seq_file.h> #include <linux/slab.h> +#include <linux/smp_lock.h> #include <linux/netdevice.h> #include <linux/vmalloc.h> #include <linux/init.h> diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c index 6f727e3c53a..8d4a2a8a0a7 100644 --- a/drivers/char/synclinkmp.c +++ b/drivers/char/synclinkmp.c @@ -52,6 +52,7 @@ #include <linux/mm.h> #include <linux/seq_file.h> #include <linux/slab.h> +#include <linux/smp_lock.h> #include <linux/netdevice.h> #include <linux/vmalloc.h> #include <linux/init.h> diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index ccdd828adce..b0603b2e568 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -26,7 +26,6 @@ #include <linux/poll.h> #include <linux/mutex.h> #include <linux/spinlock.h> -#include <linux/smp_lock.h> #include "tpm.h" diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c index b24f6c6a1ea..ad6ba4ed280 100644 --- a/drivers/char/tty_ioctl.c +++ b/drivers/char/tty_ioctl.c @@ -21,7 +21,6 @@ #include <linux/module.h> #include <linux/bitops.h> #include <linux/mutex.h> -#include <linux/smp_lock.h> #include <asm/io.h> #include <asm/uaccess.h> diff --git a/drivers/char/tty_ldisc.c b/drivers/char/tty_ldisc.c index 913aa8d3f1c..0ef0dc97ba2 100644 --- a/drivers/char/tty_ldisc.c +++ b/drivers/char/tty_ldisc.c @@ -21,7 +21,6 @@ #include <linux/proc_fs.h> #include <linux/init.h> #include <linux/module.h> -#include <linux/smp_lock.h> #include <linux/device.h> #include <linux/wait.h> #include <linux/bitops.h> diff --git a/drivers/char/vt.c b/drivers/char/vt.c index d9113b4c76e..7947bd1b4cf 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -89,6 +89,7 @@ #include <linux/mutex.h> #include <linux/vt_kern.h> #include <linux/selection.h> +#include <linux/smp_lock.h> #include <linux/tiocl.h> #include <linux/kbd_kern.h> #include <linux/consolemap.h> diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c index 7539bed0f7e..95189f288f8 100644 --- a/drivers/char/vt_ioctl.c +++ b/drivers/char/vt_ioctl.c @@ -25,6 +25,7 @@ #include <linux/console.h> #include <linux/consolemap.h> #include <linux/signal.h> +#include <linux/smp_lock.h> #include <linux/timex.h> #include <asm/io.h> diff --git a/drivers/gpio/vr41xx_giu.c b/drivers/gpio/vr41xx_giu.c index b70e06133e7..b16c9a8c03f 100644 --- a/drivers/gpio/vr41xx_giu.c +++ b/drivers/gpio/vr41xx_giu.c @@ -29,7 +29,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/platform_device.h> -#include <linux/smp_lock.h> #include <linux/spinlock.h> #include <linux/types.h> diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index a6f73f1e99d..3da9cfa3184 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -1090,6 +1090,8 @@ int drm_helper_resume_force_mode(struct drm_device *dev) if (ret == false) DRM_ERROR("failed to set mode on crtc %p\n", crtc); } + /* disable the unused connectors while restoring the modesetting */ + drm_helper_disable_unused_functions(dev); return 0; } EXPORT_SYMBOL(drm_helper_resume_force_mode); diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index f112c769d53..8c4783180bf 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -846,7 +846,7 @@ static int i915_set_status_page(struct drm_device *dev, void *data, return 0; } - printk(KERN_DEBUG "set status page addr 0x%08x\n", (u32)hws->addr); + DRM_DEBUG("set status page addr 0x%08x\n", (u32)hws->addr); dev_priv->status_gfx_addr = hws->addr & (0x1ffff<<12); @@ -885,8 +885,8 @@ static int i915_set_status_page(struct drm_device *dev, void *data, * some RAM for the framebuffer at early boot. This code figures out * how much was set aside so we can use it for our own purposes. */ -static int i915_probe_agp(struct drm_device *dev, unsigned long *aperture_size, - unsigned long *preallocated_size) +static int i915_probe_agp(struct drm_device *dev, uint32_t *aperture_size, + uint32_t *preallocated_size) { struct pci_dev *bridge_dev; u16 tmp = 0; @@ -984,10 +984,11 @@ static int i915_probe_agp(struct drm_device *dev, unsigned long *aperture_size, return 0; } -static int i915_load_modeset_init(struct drm_device *dev) +static int i915_load_modeset_init(struct drm_device *dev, + unsigned long prealloc_size, + unsigned long agp_size) { struct drm_i915_private *dev_priv = dev->dev_private; - unsigned long agp_size, prealloc_size; int fb_bar = IS_I9XX(dev) ? 2 : 0; int ret = 0; @@ -1002,10 +1003,6 @@ static int i915_load_modeset_init(struct drm_device *dev) if (IS_I965G(dev) || IS_G33(dev)) dev_priv->cursor_needs_physical = false; - ret = i915_probe_agp(dev, &agp_size, &prealloc_size); - if (ret) - goto out; - /* Basic memrange allocator for stolen space (aka vram) */ drm_mm_init(&dev_priv->vram, 0, prealloc_size); @@ -1082,6 +1079,44 @@ void i915_master_destroy(struct drm_device *dev, struct drm_master *master) master->driver_priv = NULL; } +static void i915_get_mem_freq(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + u32 tmp; + + if (!IS_IGD(dev)) + return; + + tmp = I915_READ(CLKCFG); + + switch (tmp & CLKCFG_FSB_MASK) { + case CLKCFG_FSB_533: + dev_priv->fsb_freq = 533; /* 133*4 */ + break; + case CLKCFG_FSB_800: + dev_priv->fsb_freq = 800; /* 200*4 */ + break; + case CLKCFG_FSB_667: + dev_priv->fsb_freq = 667; /* 167*4 */ + break; + case CLKCFG_FSB_400: + dev_priv->fsb_freq = 400; /* 100*4 */ + break; + } + + switch (tmp & CLKCFG_MEM_MASK) { + case CLKCFG_MEM_533: + dev_priv->mem_freq = 533; + break; + case CLKCFG_MEM_667: + dev_priv->mem_freq = 667; + break; + case CLKCFG_MEM_800: + dev_priv->mem_freq = 800; + break; + } +} + /** * i915_driver_load - setup chip and create an initial config * @dev: DRM device @@ -1098,6 +1133,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) struct drm_i915_private *dev_priv = dev->dev_private; resource_size_t base, size; int ret = 0, mmio_bar = IS_I9XX(dev) ? 0 : 1; + uint32_t agp_size, prealloc_size; /* i915 has 4 more counters */ dev->counters += 4; @@ -1146,9 +1182,22 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) "performance may suffer.\n"); } + ret = i915_probe_agp(dev, &agp_size, &prealloc_size); + if (ret) + goto out_iomapfree; + /* enable GEM by default */ dev_priv->has_gem = 1; + if (prealloc_size > agp_size * 3 / 4) { + DRM_ERROR("Detected broken video BIOS with %d/%dkB of video " + "memory stolen.\n", + prealloc_size / 1024, agp_size / 1024); + DRM_ERROR("Disabling GEM. (try reducing stolen memory or " + "updating the BIOS to fix).\n"); + dev_priv->has_gem = 0; + } + dev->driver->get_vblank_counter = i915_get_vblank_counter; dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ if (IS_G4X(dev) || IS_IGDNG(dev)) { @@ -1165,6 +1214,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) goto out_iomapfree; } + i915_get_mem_freq(dev); + /* On the 945G/GM, the chipset reports the MSI capability on the * integrated graphics even though the support isn't actually there * according to the published specs. It doesn't appear to function @@ -1180,6 +1231,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) pci_enable_msi(dev->pdev); spin_lock_init(&dev_priv->user_irq_lock); + spin_lock_init(&dev_priv->error_lock); dev_priv->user_irq_refcount = 0; ret = drm_vblank_init(dev, I915_NUM_PIPE); @@ -1190,7 +1242,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) } if (drm_core_check_feature(dev, DRIVER_MODESET)) { - ret = i915_load_modeset_init(dev); + ret = i915_load_modeset_init(dev, prealloc_size, agp_size); if (ret < 0) { DRM_ERROR("failed to init modeset\n"); goto out_rmmap; diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index e3cb4025e32..fc4b68aa2d0 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -35,6 +35,7 @@ #include "drm_pciids.h" #include <linux/console.h> +#include "drm_crtc_helper.h" static unsigned int i915_modeset = -1; module_param_named(modeset, i915_modeset, int, 0400); @@ -57,8 +58,8 @@ static int i915_suspend(struct drm_device *dev, pm_message_t state) struct drm_i915_private *dev_priv = dev->dev_private; if (!dev || !dev_priv) { - printk(KERN_ERR "dev: %p, dev_priv: %p\n", dev, dev_priv); - printk(KERN_ERR "DRM not initialized, aborting suspend.\n"); + DRM_ERROR("dev: %p, dev_priv: %p\n", dev, dev_priv); + DRM_ERROR("DRM not initialized, aborting suspend.\n"); return -ENODEV; } @@ -115,6 +116,10 @@ static int i915_resume(struct drm_device *dev) drm_irq_install(dev); } + if (drm_core_check_feature(dev, DRIVER_MODESET)) { + /* Resume the modeset for every activated CRTC */ + drm_helper_resume_force_mode(dev); + } return ret; } diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index bb4c2d387b6..d0875287588 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -133,6 +133,22 @@ struct sdvo_device_mapping { u8 initialized; }; +struct drm_i915_error_state { + u32 eir; + u32 pgtbl_er; + u32 pipeastat; + u32 pipebstat; + u32 ipeir; + u32 ipehr; + u32 instdone; + u32 acthd; + u32 instpm; + u32 instps; + u32 instdone1; + u32 seqno; + struct timeval time; +}; + typedef struct drm_i915_private { struct drm_device *dev; @@ -209,6 +225,11 @@ typedef struct drm_i915_private { int fence_reg_start; /* 4 if userland hasn't ioctl'd us yet */ int num_fence_regs; /* 8 on pre-965, 16 otherwise */ + unsigned int fsb_freq, mem_freq; + + spinlock_t error_lock; + struct drm_i915_error_state *first_error; + /* Register state */ u8 saveLBB; u32 saveDSPACNTR; @@ -468,9 +489,6 @@ struct drm_i915_gem_object { */ int fence_reg; - /** Boolean whether this object has a valid gtt offset. */ - int gtt_bound; - /** How many users have pinned this object in GTT space */ int pin_count; @@ -655,6 +673,7 @@ void i915_gem_free_object(struct drm_gem_object *obj); int i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment); void i915_gem_object_unpin(struct drm_gem_object *obj); int i915_gem_object_unbind(struct drm_gem_object *obj); +void i915_gem_release_mmap(struct drm_gem_object *obj); void i915_gem_lastclose(struct drm_device *dev); uint32_t i915_get_gem_seqno(struct drm_device *dev); int i915_gem_object_get_fence_reg(struct drm_gem_object *obj); @@ -870,6 +889,8 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); #define SUPPORTS_INTEGRATED_HDMI(dev) (IS_G4X(dev) || IS_IGDNG(dev)) #define SUPPORTS_INTEGRATED_DP(dev) (IS_G4X(dev) || IS_IGDNG(dev)) #define I915_HAS_HOTPLUG(dev) (IS_I945G(dev) || IS_I945GM(dev) || IS_I965G(dev)) +/* dsparb controlled by hw only */ +#define DSPARB_HWCONTROL(dev) (IS_G4X(dev) || IS_IGDNG(dev)) #define PRIMARY_RINGBUFFER_SIZE (128*1024) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 876b65cb762..5bf420378b6 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1252,6 +1252,31 @@ out_free_list: return ret; } +/** + * i915_gem_release_mmap - remove physical page mappings + * @obj: obj in question + * + * Preserve the reservation of the mmaping with the DRM core code, but + * relinquish ownership of the pages back to the system. + * + * It is vital that we remove the page mapping if we have mapped a tiled + * object through the GTT and then lose the fence register due to + * resource pressure. Similarly if the object has been moved out of the + * aperture, than pages mapped into userspace must be revoked. Removing the + * mapping will then trigger a page fault on the next user access, allowing + * fixup by i915_gem_fault(). + */ +void +i915_gem_release_mmap(struct drm_gem_object *obj) +{ + struct drm_device *dev = obj->dev; + struct drm_i915_gem_object *obj_priv = obj->driver_private; + + if (dev->dev_mapping) + unmap_mapping_range(dev->dev_mapping, + obj_priv->mmap_offset, obj->size, 1); +} + static void i915_gem_free_mmap_offset(struct drm_gem_object *obj) { @@ -1861,7 +1886,6 @@ i915_gem_object_unbind(struct drm_gem_object *obj) { struct drm_device *dev = obj->dev; struct drm_i915_gem_object *obj_priv = obj->driver_private; - loff_t offset; int ret = 0; #if WATCH_BUF @@ -1898,9 +1922,7 @@ i915_gem_object_unbind(struct drm_gem_object *obj) BUG_ON(obj_priv->active); /* blow away mappings if mapped through GTT */ - offset = ((loff_t) obj->map_list.hash.key) << PAGE_SHIFT; - if (dev->dev_mapping) - unmap_mapping_range(dev->dev_mapping, offset, obj->size, 1); + i915_gem_release_mmap(obj); if (obj_priv->fence_reg != I915_FENCE_REG_NONE) i915_gem_clear_fence_reg(obj); @@ -2222,7 +2244,6 @@ try_again: /* None available, try to steal one or wait for a user to finish */ if (i == dev_priv->num_fence_regs) { uint32_t seqno = dev_priv->mm.next_gem_seqno; - loff_t offset; if (avail == 0) return -ENOSPC; @@ -2274,10 +2295,7 @@ try_again: * Zap this virtual mapping so we can set up a fence again * for this object next time we need it. */ - offset = ((loff_t) reg->obj->map_list.hash.key) << PAGE_SHIFT; - if (dev->dev_mapping) - unmap_mapping_range(dev->dev_mapping, offset, - reg->obj->size, 1); + i915_gem_release_mmap(reg->obj); old_obj_priv->fence_reg = I915_FENCE_REG_NONE; } diff --git a/drivers/gpu/drm/i915/i915_gem_debugfs.c b/drivers/gpu/drm/i915/i915_gem_debugfs.c index 28146e405e8..9a44bfcb813 100644 --- a/drivers/gpu/drm/i915/i915_gem_debugfs.c +++ b/drivers/gpu/drm/i915/i915_gem_debugfs.c @@ -75,11 +75,10 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data) case ACTIVE_LIST: seq_printf(m, "Active:\n"); lock = &dev_priv->mm.active_list_lock; - spin_lock(lock); head = &dev_priv->mm.active_list; break; case INACTIVE_LIST: - seq_printf(m, "Inctive:\n"); + seq_printf(m, "Inactive:\n"); head = &dev_priv->mm.inactive_list; break; case FLUSHING_LIST: @@ -91,6 +90,8 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data) return 0; } + if (lock) + spin_lock(lock); list_for_each_entry(obj_priv, head, list) { struct drm_gem_object *obj = obj_priv->obj; @@ -104,7 +105,10 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data) if (obj->name) seq_printf(m, " (name: %d)", obj->name); if (obj_priv->fence_reg != I915_FENCE_REG_NONE) - seq_printf(m, " (fence: %d)\n", obj_priv->fence_reg); + seq_printf(m, " (fence: %d)", obj_priv->fence_reg); + if (obj_priv->gtt_space != NULL) + seq_printf(m, " (gtt_offset: %08x)", obj_priv->gtt_offset); + seq_printf(m, "\n"); } @@ -323,6 +327,39 @@ static int i915_ringbuffer_info(struct seq_file *m, void *data) return 0; } +static int i915_error_state(struct seq_file *m, void *unused) +{ + struct drm_info_node *node = (struct drm_info_node *) m->private; + struct drm_device *dev = node->minor->dev; + drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_i915_error_state *error; + unsigned long flags; + + spin_lock_irqsave(&dev_priv->error_lock, flags); + if (!dev_priv->first_error) { + seq_printf(m, "no error state collected\n"); + goto out; + } + + error = dev_priv->first_error; + + seq_printf(m, "EIR: 0x%08x\n", error->eir); + seq_printf(m, " PGTBL_ER: 0x%08x\n", error->pgtbl_er); + seq_printf(m, " INSTPM: 0x%08x\n", error->instpm); + seq_printf(m, " IPEIR: 0x%08x\n", error->ipeir); + seq_printf(m, " IPEHR: 0x%08x\n", error->ipehr); + seq_printf(m, " INSTDONE: 0x%08x\n", error->instdone); + seq_printf(m, " ACTHD: 0x%08x\n", error->acthd); + if (IS_I965G(dev)) { + seq_printf(m, " INSTPS: 0x%08x\n", error->instps); + seq_printf(m, " INSTDONE1: 0x%08x\n", error->instdone1); + } + +out: + spin_unlock_irqrestore(&dev_priv->error_lock, flags); + + return 0; +} static struct drm_info_list i915_gem_debugfs_list[] = { {"i915_gem_active", i915_gem_object_list_info, 0, (void *) ACTIVE_LIST}, @@ -336,6 +373,7 @@ static struct drm_info_list i915_gem_debugfs_list[] = { {"i915_ringbuffer_data", i915_ringbuffer_data, 0}, {"i915_ringbuffer_info", i915_ringbuffer_info, 0}, {"i915_batchbuffers", i915_batchbuffer_info, 0}, + {"i915_error_state", i915_error_state, 0}, }; #define I915_GEM_DEBUGFS_ENTRIES ARRAY_SIZE(i915_gem_debugfs_list) diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c index daeae62e1c2..a2d527b22ec 100644 --- a/drivers/gpu/drm/i915/i915_gem_tiling.c +++ b/drivers/gpu/drm/i915/i915_gem_tiling.c @@ -521,6 +521,12 @@ i915_gem_set_tiling(struct drm_device *dev, void *data, goto err; } + /* If we've changed tiling, GTT-mappings of the object + * need to re-fault to ensure that the correct fence register + * setup is in place. + */ + i915_gem_release_mmap(obj); + obj_priv->tiling_mode = args->tiling_mode; obj_priv->stride = args->stride; } diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 228546f6eaa..7ba23a69a0c 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -26,6 +26,7 @@ * */ +#include <linux/sysrq.h> #include "drmP.h" #include "drm.h" #include "i915_drm.h" @@ -41,9 +42,10 @@ * we leave them always unmasked in IMR and then control enabling them through * PIPESTAT alone. */ -#define I915_INTERRUPT_ENABLE_FIX (I915_ASLE_INTERRUPT | \ - I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | \ - I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) +#define I915_INTERRUPT_ENABLE_FIX (I915_ASLE_INTERRUPT | \ + I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | \ + I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | \ + I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT) /** Interrupts that we mask and unmask at runtime. */ #define I915_INTERRUPT_ENABLE_VAR (I915_USER_INTERRUPT) @@ -288,6 +290,47 @@ irqreturn_t igdng_irq_handler(struct drm_device *dev) return ret; } +static void i915_capture_error_state(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_error_state *error; + unsigned long flags; + + spin_lock_irqsave(&dev_priv->error_lock, flags); + if (dev_priv->first_error) + goto out; + + error = kmalloc(sizeof(*error), GFP_ATOMIC); + if (!error) { + DRM_DEBUG("out ot memory, not capturing error state\n"); + goto out; + } + + error->eir = I915_READ(EIR); + error->pgtbl_er = I915_READ(PGTBL_ER); + error->pipeastat = I915_READ(PIPEASTAT); + error->pipebstat = I915_READ(PIPEBSTAT); + error->instpm = I915_READ(INSTPM); + if (!IS_I965G(dev)) { + error->ipeir = I915_READ(IPEIR); + error->ipehr = I915_READ(IPEHR); + error->instdone = I915_READ(INSTDONE); + error->acthd = I915_READ(ACTHD); + } else { + error->ipeir = I915_READ(IPEIR_I965); + error->ipehr = I915_READ(IPEHR_I965); + error->instdone = I915_READ(INSTDONE_I965); + error->instps = I915_READ(INSTPS); + error->instdone1 = I915_READ(INSTDONE1); + error->acthd = I915_READ(ACTHD_I965); + } + + dev_priv->first_error = error; + +out: + spin_unlock_irqrestore(&dev_priv->error_lock, flags); +} + irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) { struct drm_device *dev = (struct drm_device *) arg; @@ -333,11 +376,15 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) * Clear the PIPE(A|B)STAT regs before the IIR */ if (pipea_stats & 0x8000ffff) { + if (pipea_stats & PIPE_FIFO_UNDERRUN_STATUS) + DRM_DEBUG("pipe a underrun\n"); I915_WRITE(PIPEASTAT, pipea_stats); irq_received = 1; } if (pipeb_stats & 0x8000ffff) { + if (pipeb_stats & PIPE_FIFO_UNDERRUN_STATUS) + DRM_DEBUG("pipe b underrun\n"); I915_WRITE(PIPEBSTAT, pipeb_stats); irq_received = 1; } @@ -362,6 +409,80 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) I915_READ(PORT_HOTPLUG_STAT); } + if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT) { + u32 eir = I915_READ(EIR); + + i915_capture_error_state(dev); + + printk(KERN_ERR "render error detected, EIR: 0x%08x\n", + eir); + if (eir & I915_ERROR_PAGE_TABLE) { + u32 pgtbl_err = I915_READ(PGTBL_ER); + printk(KERN_ERR "page table error\n"); + printk(KERN_ERR " PGTBL_ER: 0x%08x\n", + pgtbl_err); + I915_WRITE(PGTBL_ER, pgtbl_err); + (void)I915_READ(PGTBL_ER); + } + if (eir & I915_ERROR_MEMORY_REFRESH) { + printk(KERN_ERR "memory refresh error\n"); + printk(KERN_ERR "PIPEASTAT: 0x%08x\n", + pipea_stats); + printk(KERN_ERR "PIPEBSTAT: 0x%08x\n", + pipeb_stats); + /* pipestat has already been acked */ + } + if (eir & I915_ERROR_INSTRUCTION) { + printk(KERN_ERR "instruction error\n"); + printk(KERN_ERR " INSTPM: 0x%08x\n", + I915_READ(INSTPM)); + if (!IS_I965G(dev)) { + u32 ipeir = I915_READ(IPEIR); + + printk(KERN_ERR " IPEIR: 0x%08x\n", + I915_READ(IPEIR)); + printk(KERN_ERR " IPEHR: 0x%08x\n", + I915_READ(IPEHR)); + printk(KERN_ERR " INSTDONE: 0x%08x\n", + I915_READ(INSTDONE)); + printk(KERN_ERR " ACTHD: 0x%08x\n", + I915_READ(ACTHD)); + I915_WRITE(IPEIR, ipeir); + (void)I915_READ(IPEIR); + } else { + u32 ipeir = I915_READ(IPEIR_I965); + + printk(KERN_ERR " IPEIR: 0x%08x\n", + I915_READ(IPEIR_I965)); + printk(KERN_ERR " IPEHR: 0x%08x\n", + I915_READ(IPEHR_I965)); + printk(KERN_ERR " INSTDONE: 0x%08x\n", + I915_READ(INSTDONE_I965)); + printk(KERN_ERR " INSTPS: 0x%08x\n", + I915_READ(INSTPS)); + printk(KERN_ERR " INSTDONE1: 0x%08x\n", + I915_READ(INSTDONE1)); + printk(KERN_ERR " ACTHD: 0x%08x\n", + I915_READ(ACTHD_I965)); + I915_WRITE(IPEIR_I965, ipeir); + (void)I915_READ(IPEIR_I965); + } + } + + I915_WRITE(EIR, eir); + (void)I915_READ(EIR); + eir = I915_READ(EIR); + if (eir) { + /* + * some errors might have become stuck, + * mask them. + */ + DRM_ERROR("EIR stuck: 0x%08x, masking\n", eir); + I915_WRITE(EMR, I915_READ(EMR) | eir); + I915_WRITE(IIR, I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT); + } + } + I915_WRITE(IIR, iir); new_iir = I915_READ(IIR); /* Flush posted writes */ @@ -732,6 +853,7 @@ int i915_driver_irq_postinstall(struct drm_device *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; u32 enable_mask = I915_INTERRUPT_ENABLE_FIX | I915_INTERRUPT_ENABLE_VAR; + u32 error_mask; DRM_INIT_WAITQUEUE(&dev_priv->irq_queue); @@ -768,6 +890,21 @@ int i915_driver_irq_postinstall(struct drm_device *dev) i915_enable_irq(dev_priv, I915_DISPLAY_PORT_INTERRUPT); } + /* + * Enable some error detection, note the instruction error mask + * bit is reserved, so we leave it masked. + */ + if (IS_G4X(dev)) { + error_mask = ~(GM45_ERROR_PAGE_TABLE | + GM45_ERROR_MEM_PRIV | + GM45_ERROR_CP_PRIV | + I915_ERROR_MEMORY_REFRESH); + } else { + error_mask = ~(I915_ERROR_PAGE_TABLE | + I915_ERROR_MEMORY_REFRESH); + } + I915_WRITE(EMR, error_mask); + /* Disable pipe interrupt enables, clear pending pipe status */ I915_WRITE(PIPEASTAT, I915_READ(PIPEASTAT) & 0x8000ffff); I915_WRITE(PIPEBSTAT, I915_READ(PIPEBSTAT) & 0x8000ffff); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 88bf7521405..6c085848409 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -206,6 +206,7 @@ /* * Instruction and interrupt control regs */ +#define PGTBL_ER 0x02024 #define PRB0_TAIL 0x02030 #define PRB0_HEAD 0x02034 #define PRB0_START 0x02038 @@ -226,11 +227,18 @@ #define PRB1_HEAD 0x02044 /* 915+ only */ #define PRB1_START 0x02048 /* 915+ only */ #define PRB1_CTL 0x0204c /* 915+ only */ +#define IPEIR_I965 0x02064 +#define IPEHR_I965 0x02068 +#define INSTDONE_I965 0x0206c +#define INSTPS 0x02070 /* 965+ only */ +#define INSTDONE1 0x0207c /* 965+ only */ #define ACTHD_I965 0x02074 #define HWS_PGA 0x02080 #define HWS_ADDRESS_MASK 0xfffff000 #define HWS_START_ADDRESS_SHIFT 4 #define IPEIR 0x02088 +#define IPEHR 0x0208c +#define INSTDONE 0x02090 #define NOPID 0x02094 #define HWSTAM 0x02098 #define SCPD0 0x0209c /* 915+ only */ @@ -258,10 +266,22 @@ #define EIR 0x020b0 #define EMR 0x020b4 #define ESR 0x020b8 +#define GM45_ERROR_PAGE_TABLE (1<<5) +#define GM45_ERROR_MEM_PRIV (1<<4) +#define I915_ERROR_PAGE_TABLE (1<<4) +#define GM45_ERROR_CP_PRIV (1<<3) +#define I915_ERROR_MEMORY_REFRESH (1<<1) +#define I915_ERROR_INSTRUCTION (1<<0) #define INSTPM 0x020c0 #define ACTHD 0x020c8 #define FW_BLC 0x020d8 +#define FW_BLC2 0x020dc #define FW_BLC_SELF 0x020e0 /* 915+ only */ +#define FW_BLC_SELF_EN (1<<15) +#define MM_BURST_LENGTH 0x00700000 +#define MM_FIFO_WATERMARK 0x0001F000 +#define LM_BURST_LENGTH 0x00000700 +#define LM_FIFO_WATERMARK 0x0000001F #define MI_ARB_STATE 0x020e4 /* 915+ only */ #define CACHE_MODE_0 0x02120 /* 915+ only */ #define CM0_MASK_SHIFT 16 @@ -571,17 +591,21 @@ /* Clocking configuration register */ #define CLKCFG 0x10c00 -#define CLKCFG_FSB_400 (0 << 0) /* hrawclk 100 */ +#define CLKCFG_FSB_400 (5 << 0) /* hrawclk 100 */ #define CLKCFG_FSB_533 (1 << 0) /* hrawclk 133 */ #define CLKCFG_FSB_667 (3 << 0) /* hrawclk 166 */ #define CLKCFG_FSB_800 (2 << 0) /* hrawclk 200 */ #define CLKCFG_FSB_1067 (6 << 0) /* hrawclk 266 */ #define CLKCFG_FSB_1333 (7 << 0) /* hrawclk 333 */ -/* this is a guess, could be 5 as well */ +/* Note, below two are guess */ #define CLKCFG_FSB_1600 (4 << 0) /* hrawclk 400 */ -#define CLKCFG_FSB_1600_ALT (5 << 0) /* hrawclk 400 */ +#define CLKCFG_FSB_1600_ALT (0 << 0) /* hrawclk 400 */ #define CLKCFG_FSB_MASK (7 << 0) - +#define CLKCFG_MEM_533 (1 << 4) +#define CLKCFG_MEM_667 (2 << 4) +#define CLKCFG_MEM_800 (3 << 4) +#define CLKCFG_MEM_MASK (7 << 4) + /** GM965 GM45 render standby register */ #define MCHBAR_RENDER_STANDBY 0x111B8 @@ -1581,6 +1605,34 @@ #define DSPARB_CSTART_SHIFT 7 #define DSPARB_BSTART_MASK (0x7f) #define DSPARB_BSTART_SHIFT 0 +#define DSPARB_BEND_SHIFT 9 /* on 855 */ +#define DSPARB_AEND_SHIFT 0 + +#define DSPFW1 0x70034 +#define DSPFW2 0x70038 +#define DSPFW3 0x7003c +#define IGD_SELF_REFRESH_EN (1<<30) + +/* FIFO watermark sizes etc */ +#define I915_FIFO_LINE_SIZE 64 +#define I830_FIFO_LINE_SIZE 32 +#define I945_FIFO_SIZE 127 /* 945 & 965 */ +#define I915_FIFO_SIZE 95 +#define I855GM_FIFO_SIZE 255 +#define I830_FIFO_SIZE 95 +#define I915_MAX_WM 0x3f + +#define IGD_DISPLAY_FIFO 512 /* in 64byte unit */ +#define IGD_FIFO_LINE_SIZE 64 +#define IGD_MAX_WM 0x1ff +#define IGD_DFT_WM 0x3f +#define IGD_DFT_HPLLOFF_WM 0 +#define IGD_GUARD_WM 10 +#define IGD_CURSOR_FIFO 64 +#define IGD_CURSOR_MAX_WM 0x3f +#define IGD_CURSOR_DFT_WM 0 +#define IGD_CURSOR_GUARD_WM 5 + /* * The two pipe frame counter registers are not synchronized, so * reading a stable value is somewhat tricky. The following code diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index 8d8e083d14a..9e1d16e5c3e 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -222,23 +222,12 @@ static void i915_restore_vga(struct drm_device *dev) I915_WRITE8(VGA_DACMASK, dev_priv->saveDACMASK); } -int i915_save_state(struct drm_device *dev) +static void i915_save_modeset_reg(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - int i; - - pci_read_config_byte(dev->pdev, LBB, &dev_priv->saveLBB); - - /* Render Standby */ - if (IS_I965G(dev) && IS_MOBILE(dev)) - dev_priv->saveRENDERSTANDBY = I915_READ(MCHBAR_RENDER_STANDBY); - - /* Hardware status page */ - dev_priv->saveHWS = I915_READ(HWS_PGA); - - /* Display arbitration control */ - dev_priv->saveDSPARB = I915_READ(DSPARB); + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return; /* Pipe & plane A info */ dev_priv->savePIPEACONF = I915_READ(PIPEACONF); dev_priv->savePIPEASRC = I915_READ(PIPEASRC); @@ -294,7 +283,122 @@ int i915_save_state(struct drm_device *dev) } i915_save_palette(dev, PIPE_B); dev_priv->savePIPEBSTAT = I915_READ(PIPEBSTAT); + return; +} +static void i915_restore_modeset_reg(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return; + + /* Pipe & plane A info */ + /* Prime the clock */ + if (dev_priv->saveDPLL_A & DPLL_VCO_ENABLE) { + I915_WRITE(DPLL_A, dev_priv->saveDPLL_A & + ~DPLL_VCO_ENABLE); + DRM_UDELAY(150); + } + I915_WRITE(FPA0, dev_priv->saveFPA0); + I915_WRITE(FPA1, dev_priv->saveFPA1); + /* Actually enable it */ + I915_WRITE(DPLL_A, dev_priv->saveDPLL_A); + DRM_UDELAY(150); + if (IS_I965G(dev)) + I915_WRITE(DPLL_A_MD, dev_priv->saveDPLL_A_MD); + DRM_UDELAY(150); + + /* Restore mode */ + I915_WRITE(HTOTAL_A, dev_priv->saveHTOTAL_A); + I915_WRITE(HBLANK_A, dev_priv->saveHBLANK_A); + I915_WRITE(HSYNC_A, dev_priv->saveHSYNC_A); + I915_WRITE(VTOTAL_A, dev_priv->saveVTOTAL_A); + I915_WRITE(VBLANK_A, dev_priv->saveVBLANK_A); + I915_WRITE(VSYNC_A, dev_priv->saveVSYNC_A); + I915_WRITE(BCLRPAT_A, dev_priv->saveBCLRPAT_A); + + /* Restore plane info */ + I915_WRITE(DSPASIZE, dev_priv->saveDSPASIZE); + I915_WRITE(DSPAPOS, dev_priv->saveDSPAPOS); + I915_WRITE(PIPEASRC, dev_priv->savePIPEASRC); + I915_WRITE(DSPAADDR, dev_priv->saveDSPAADDR); + I915_WRITE(DSPASTRIDE, dev_priv->saveDSPASTRIDE); + if (IS_I965G(dev)) { + I915_WRITE(DSPASURF, dev_priv->saveDSPASURF); + I915_WRITE(DSPATILEOFF, dev_priv->saveDSPATILEOFF); + } + + I915_WRITE(PIPEACONF, dev_priv->savePIPEACONF); + + i915_restore_palette(dev, PIPE_A); + /* Enable the plane */ + I915_WRITE(DSPACNTR, dev_priv->saveDSPACNTR); + I915_WRITE(DSPAADDR, I915_READ(DSPAADDR)); + + /* Pipe & plane B info */ + if (dev_priv->saveDPLL_B & DPLL_VCO_ENABLE) { + I915_WRITE(DPLL_B, dev_priv->saveDPLL_B & + ~DPLL_VCO_ENABLE); + DRM_UDELAY(150); + } + I915_WRITE(FPB0, dev_priv->saveFPB0); + I915_WRITE(FPB1, dev_priv->saveFPB1); + /* Actually enable it */ + I915_WRITE(DPLL_B, dev_priv->saveDPLL_B); + DRM_UDELAY(150); + if (IS_I965G(dev)) + I915_WRITE(DPLL_B_MD, dev_priv->saveDPLL_B_MD); + DRM_UDELAY(150); + + /* Restore mode */ + I915_WRITE(HTOTAL_B, dev_priv->saveHTOTAL_B); + I915_WRITE(HBLANK_B, dev_priv->saveHBLANK_B); + I915_WRITE(HSYNC_B, dev_priv->saveHSYNC_B); + I915_WRITE(VTOTAL_B, dev_priv->saveVTOTAL_B); + I915_WRITE(VBLANK_B, dev_priv->saveVBLANK_B); + I915_WRITE(VSYNC_B, dev_priv->saveVSYNC_B); + I915_WRITE(BCLRPAT_B, dev_priv->saveBCLRPAT_B); + + /* Restore plane info */ + I915_WRITE(DSPBSIZE, dev_priv->saveDSPBSIZE); + I915_WRITE(DSPBPOS, dev_priv->saveDSPBPOS); + I915_WRITE(PIPEBSRC, dev_priv->savePIPEBSRC); + I915_WRITE(DSPBADDR, dev_priv->saveDSPBADDR); + I915_WRITE(DSPBSTRIDE, dev_priv->saveDSPBSTRIDE); + if (IS_I965G(dev)) { + I915_WRITE(DSPBSURF, dev_priv->saveDSPBSURF); + I915_WRITE(DSPBTILEOFF, dev_priv->saveDSPBTILEOFF); + } + + I915_WRITE(PIPEBCONF, dev_priv->savePIPEBCONF); + + i915_restore_palette(dev, PIPE_B); + /* Enable the plane */ + I915_WRITE(DSPBCNTR, dev_priv->saveDSPBCNTR); + I915_WRITE(DSPBADDR, I915_READ(DSPBADDR)); + return; +} +int i915_save_state(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int i; + + pci_read_config_byte(dev->pdev, LBB, &dev_priv->saveLBB); + + /* Render Standby */ + if (IS_I965G(dev) && IS_MOBILE(dev)) + dev_priv->saveRENDERSTANDBY = I915_READ(MCHBAR_RENDER_STANDBY); + + /* Hardware status page */ + dev_priv->saveHWS = I915_READ(HWS_PGA); + + /* Display arbitration control */ + dev_priv->saveDSPARB = I915_READ(DSPARB); + + /* This is only meaningful in non-KMS mode */ + /* Don't save them in KMS mode */ + i915_save_modeset_reg(dev); /* Cursor state */ dev_priv->saveCURACNTR = I915_READ(CURACNTR); dev_priv->saveCURAPOS = I915_READ(CURAPOS); @@ -430,92 +534,9 @@ int i915_restore_state(struct drm_device *dev) I915_WRITE(PIPEA_DP_LINK_N, dev_priv->savePIPEA_DP_LINK_N); I915_WRITE(PIPEB_DP_LINK_N, dev_priv->savePIPEB_DP_LINK_N); } - - /* Pipe & plane A info */ - /* Prime the clock */ - if (dev_priv->saveDPLL_A & DPLL_VCO_ENABLE) { - I915_WRITE(DPLL_A, dev_priv->saveDPLL_A & - ~DPLL_VCO_ENABLE); - DRM_UDELAY(150); - } - I915_WRITE(FPA0, dev_priv->saveFPA0); - I915_WRITE(FPA1, dev_priv->saveFPA1); - /* Actually enable it */ - I915_WRITE(DPLL_A, dev_priv->saveDPLL_A); - DRM_UDELAY(150); - if (IS_I965G(dev)) - I915_WRITE(DPLL_A_MD, dev_priv->saveDPLL_A_MD); - DRM_UDELAY(150); - - /* Restore mode */ - I915_WRITE(HTOTAL_A, dev_priv->saveHTOTAL_A); - I915_WRITE(HBLANK_A, dev_priv->saveHBLANK_A); - I915_WRITE(HSYNC_A, dev_priv->saveHSYNC_A); - I915_WRITE(VTOTAL_A, dev_priv->saveVTOTAL_A); - I915_WRITE(VBLANK_A, dev_priv->saveVBLANK_A); - I915_WRITE(VSYNC_A, dev_priv->saveVSYNC_A); - I915_WRITE(BCLRPAT_A, dev_priv->saveBCLRPAT_A); - - /* Restore plane info */ - I915_WRITE(DSPASIZE, dev_priv->saveDSPASIZE); - I915_WRITE(DSPAPOS, dev_priv->saveDSPAPOS); - I915_WRITE(PIPEASRC, dev_priv->savePIPEASRC); - I915_WRITE(DSPAADDR, dev_priv->saveDSPAADDR); - I915_WRITE(DSPASTRIDE, dev_priv->saveDSPASTRIDE); - if (IS_I965G(dev)) { - I915_WRITE(DSPASURF, dev_priv->saveDSPASURF); - I915_WRITE(DSPATILEOFF, dev_priv->saveDSPATILEOFF); - } - - I915_WRITE(PIPEACONF, dev_priv->savePIPEACONF); - - i915_restore_palette(dev, PIPE_A); - /* Enable the plane */ - I915_WRITE(DSPACNTR, dev_priv->saveDSPACNTR); - I915_WRITE(DSPAADDR, I915_READ(DSPAADDR)); - - /* Pipe & plane B info */ - if (dev_priv->saveDPLL_B & DPLL_VCO_ENABLE) { - I915_WRITE(DPLL_B, dev_priv->saveDPLL_B & - ~DPLL_VCO_ENABLE); - DRM_UDELAY(150); - } - I915_WRITE(FPB0, dev_priv->saveFPB0); - I915_WRITE(FPB1, dev_priv->saveFPB1); - /* Actually enable it */ - I915_WRITE(DPLL_B, dev_priv->saveDPLL_B); - DRM_UDELAY(150); - if (IS_I965G(dev)) - I915_WRITE(DPLL_B_MD, dev_priv->saveDPLL_B_MD); - DRM_UDELAY(150); - - /* Restore mode */ - I915_WRITE(HTOTAL_B, dev_priv->saveHTOTAL_B); - I915_WRITE(HBLANK_B, dev_priv->saveHBLANK_B); - I915_WRITE(HSYNC_B, dev_priv->saveHSYNC_B); - I915_WRITE(VTOTAL_B, dev_priv->saveVTOTAL_B); - I915_WRITE(VBLANK_B, dev_priv->saveVBLANK_B); - I915_WRITE(VSYNC_B, dev_priv->saveVSYNC_B); - I915_WRITE(BCLRPAT_B, dev_priv->saveBCLRPAT_B); - - /* Restore plane info */ - I915_WRITE(DSPBSIZE, dev_priv->saveDSPBSIZE); - I915_WRITE(DSPBPOS, dev_priv->saveDSPBPOS); - I915_WRITE(PIPEBSRC, dev_priv->savePIPEBSRC); - I915_WRITE(DSPBADDR, dev_priv->saveDSPBADDR); - I915_WRITE(DSPBSTRIDE, dev_priv->saveDSPBSTRIDE); - if (IS_I965G(dev)) { - I915_WRITE(DSPBSURF, dev_priv->saveDSPBSURF); - I915_WRITE(DSPBTILEOFF, dev_priv->saveDSPBTILEOFF); - } - - I915_WRITE(PIPEBCONF, dev_priv->savePIPEBCONF); - - i915_restore_palette(dev, PIPE_B); - /* Enable the plane */ - I915_WRITE(DSPBCNTR, dev_priv->saveDSPBCNTR); - I915_WRITE(DSPBADDR, I915_READ(DSPBADDR)); - + /* This is only meaningful in non-KMS mode */ + /* Don't restore them in KMS mode */ + i915_restore_modeset_reg(dev); /* Cursor state */ I915_WRITE(CURAPOS, dev_priv->saveCURAPOS); I915_WRITE(CURACNTR, dev_priv->saveCURACNTR); diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 716409a5724..7cc44719102 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -97,6 +97,7 @@ static void parse_lfp_panel_data(struct drm_i915_private *dev_priv, struct bdb_header *bdb) { + struct drm_device *dev = dev_priv->dev; struct bdb_lvds_options *lvds_options; struct bdb_lvds_lfp_data *lvds_lfp_data; struct bdb_lvds_lfp_data_ptrs *lvds_lfp_data_ptrs; @@ -132,7 +133,14 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv, entry = (struct bdb_lvds_lfp_data_entry *) ((uint8_t *)lvds_lfp_data->data + (lfp_data_size * lvds_options->panel_type)); - dvo_timing = &entry->dvo_timing; + + /* On IGDNG mobile, LVDS data block removes panel fitting registers. + So dec 2 dword from dvo_timing offset */ + if (IS_IGDNG(dev)) + dvo_timing = (struct lvds_dvo_timing *) + ((u8 *)&entry->dvo_timing - 8); + else + dvo_timing = &entry->dvo_timing; panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), GFP_KERNEL); @@ -195,10 +203,12 @@ parse_general_features(struct drm_i915_private *dev_priv, dev_priv->lvds_use_ssc = general->enable_ssc; if (dev_priv->lvds_use_ssc) { - if (IS_I855(dev_priv->dev)) - dev_priv->lvds_ssc_freq = general->ssc_freq ? 66 : 48; - else - dev_priv->lvds_ssc_freq = general->ssc_freq ? 100 : 96; + if (IS_I85X(dev_priv->dev)) + dev_priv->lvds_ssc_freq = + general->ssc_freq ? 66 : 48; + else + dev_priv->lvds_ssc_freq = + general->ssc_freq ? 100 : 96; } } } diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 6de97fc6602..d6a1a6e5539 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -46,7 +46,7 @@ static void intel_crt_dpms(struct drm_encoder *encoder, int mode) temp = I915_READ(reg); temp &= ~(ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE); - temp |= ADPA_DAC_ENABLE; + temp &= ~ADPA_DAC_ENABLE; switch(mode) { case DRM_MODE_DPMS_ON: @@ -428,8 +428,34 @@ static void intel_crt_destroy(struct drm_connector *connector) static int intel_crt_get_modes(struct drm_connector *connector) { + int ret; struct intel_output *intel_output = to_intel_output(connector); - return intel_ddc_get_modes(intel_output); + struct i2c_adapter *ddcbus; + struct drm_device *dev = connector->dev; + + + ret = intel_ddc_get_modes(intel_output); + if (ret || !IS_G4X(dev)) + goto end; + + ddcbus = intel_output->ddc_bus; + /* Try to probe digital port for output in DVI-I -> VGA mode. */ + intel_output->ddc_bus = + intel_i2c_create(connector->dev, GPIOD, "CRTDDC_D"); + + if (!intel_output->ddc_bus) { + intel_output->ddc_bus = ddcbus; + dev_printk(KERN_ERR, &connector->dev->pdev->dev, + "DDC bus registration failed for CRTDDC_D.\n"); + goto end; + } + /* Try to get modes by GPIOD port */ + ret = intel_ddc_get_modes(intel_output); + intel_i2c_destroy(ddcbus); + +end: + return ret; + } static int intel_crt_set_property(struct drm_connector *connector, diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 73e7b9cecac..508838ee31e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -25,6 +25,7 @@ */ #include <linux/i2c.h> +#include <linux/kernel.h> #include "drmP.h" #include "intel_drv.h" #include "i915_drm.h" @@ -34,6 +35,7 @@ #include "drm_crtc_helper.h" bool intel_pipe_has_type (struct drm_crtc *crtc, int type); +static void intel_update_watermarks(struct drm_device *dev); typedef struct { /* given values */ @@ -814,24 +816,21 @@ intel_find_pll_g4x_dp(const intel_limit_t *limit, struct drm_crtc *crtc, { intel_clock_t clock; if (target < 200000) { - clock.dot = 161670; - clock.p = 20; clock.p1 = 2; clock.p2 = 10; - clock.n = 0x01; - clock.m = 97; - clock.m1 = 0x10; - clock.m2 = 0x05; + clock.n = 2; + clock.m1 = 23; + clock.m2 = 8; } else { - clock.dot = 270000; - clock.p = 10; clock.p1 = 1; clock.p2 = 10; - clock.n = 0x02; - clock.m = 108; - clock.m1 = 0x12; - clock.m2 = 0x06; + clock.n = 1; + clock.m1 = 14; + clock.m2 = 2; } + clock.m = 5 * (clock.m1 + 2) + (clock.m2 + 2); + clock.p = (clock.p1 * clock.p2); + clock.dot = 96000 * clock.m / (clock.n + 2) / clock.p; memcpy(best_clock, &clock, sizeof(intel_clock_t)); return true; } @@ -1005,7 +1004,7 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int pipe = intel_crtc->pipe; - int plane = intel_crtc->pipe; + int plane = intel_crtc->plane; int pch_dpll_reg = (pipe == 0) ? PCH_DPLL_A : PCH_DPLL_B; int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF; int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR; @@ -1335,8 +1334,10 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode) /* Give the overlay scaler a chance to enable if it's on this pipe */ //intel_crtc_dpms_video(crtc, true); TODO + intel_update_watermarks(dev); break; case DRM_MODE_DPMS_OFF: + intel_update_watermarks(dev); /* Give the overlay scaler a chance to disable if it's on this pipe */ //intel_crtc_dpms_video(crtc, FALSE); TODO @@ -1515,7 +1516,6 @@ static int intel_get_core_clock_speed(struct drm_device *dev) return 0; /* Silence gcc warning */ } - /** * Return the pipe currently connected to the panel fitter, * or -1 if the panel fitter is not present or not in use @@ -1574,7 +1574,7 @@ igdng_compute_m_n(int bytes_per_pixel, int nlanes, temp = (u64) DATA_N * pixel_clock; temp = div_u64(temp, link_clock); - m_n->gmch_m = (temp * bytes_per_pixel) / nlanes; + m_n->gmch_m = div_u64(temp * bytes_per_pixel, nlanes); m_n->gmch_n = DATA_N; fdi_reduce_ratio(&m_n->gmch_m, &m_n->gmch_n); @@ -1585,6 +1585,420 @@ igdng_compute_m_n(int bytes_per_pixel, int nlanes, } +struct intel_watermark_params { + unsigned long fifo_size; + unsigned long max_wm; + unsigned long default_wm; + unsigned long guard_size; + unsigned long cacheline_size; +}; + +/* IGD has different values for various configs */ +static struct intel_watermark_params igd_display_wm = { + IGD_DISPLAY_FIFO, + IGD_MAX_WM, + IGD_DFT_WM, + IGD_GUARD_WM, + IGD_FIFO_LINE_SIZE +}; +static struct intel_watermark_params igd_display_hplloff_wm = { + IGD_DISPLAY_FIFO, + IGD_MAX_WM, + IGD_DFT_HPLLOFF_WM, + IGD_GUARD_WM, + IGD_FIFO_LINE_SIZE +}; +static struct intel_watermark_params igd_cursor_wm = { + IGD_CURSOR_FIFO, + IGD_CURSOR_MAX_WM, + IGD_CURSOR_DFT_WM, + IGD_CURSOR_GUARD_WM, + IGD_FIFO_LINE_SIZE, +}; +static struct intel_watermark_params igd_cursor_hplloff_wm = { + IGD_CURSOR_FIFO, + IGD_CURSOR_MAX_WM, + IGD_CURSOR_DFT_WM, + IGD_CURSOR_GUARD_WM, + IGD_FIFO_LINE_SIZE +}; +static struct intel_watermark_params i945_wm_info = { + I915_FIFO_LINE_SIZE, + I915_MAX_WM, + 1, + 0, + IGD_FIFO_LINE_SIZE +}; +static struct intel_watermark_params i915_wm_info = { + I945_FIFO_SIZE, + I915_MAX_WM, + 1, + 0, + I915_FIFO_LINE_SIZE +}; +static struct intel_watermark_params i855_wm_info = { + I855GM_FIFO_SIZE, + I915_MAX_WM, + 1, + 0, + I830_FIFO_LINE_SIZE +}; +static struct intel_watermark_params i830_wm_info = { + I830_FIFO_SIZE, + I915_MAX_WM, + 1, + 0, + I830_FIFO_LINE_SIZE +}; + +static unsigned long intel_calculate_wm(unsigned long clock_in_khz, + struct intel_watermark_params *wm, + int pixel_size, + unsigned long latency_ns) +{ + unsigned long bytes_required, wm_size; + + bytes_required = (clock_in_khz * pixel_size * latency_ns) / 1000000; + bytes_required /= wm->cacheline_size; + wm_size = wm->fifo_size - bytes_required - wm->guard_size; + + if (wm_size > wm->max_wm) + wm_size = wm->max_wm; + if (wm_size == 0) + wm_size = wm->default_wm; + return wm_size; +} + +struct cxsr_latency { + int is_desktop; + unsigned long fsb_freq; + unsigned long mem_freq; + unsigned long display_sr; + unsigned long display_hpll_disable; + unsigned long cursor_sr; + unsigned long cursor_hpll_disable; +}; + +static struct cxsr_latency cxsr_latency_table[] = { + {1, 800, 400, 3382, 33382, 3983, 33983}, /* DDR2-400 SC */ + {1, 800, 667, 3354, 33354, 3807, 33807}, /* DDR2-667 SC */ + {1, 800, 800, 3347, 33347, 3763, 33763}, /* DDR2-800 SC */ + + {1, 667, 400, 3400, 33400, 4021, 34021}, /* DDR2-400 SC */ + {1, 667, 667, 3372, 33372, 3845, 33845}, /* DDR2-667 SC */ + {1, 667, 800, 3386, 33386, 3822, 33822}, /* DDR2-800 SC */ + + {1, 400, 400, 3472, 33472, 4173, 34173}, /* DDR2-400 SC */ + {1, 400, 667, 3443, 33443, 3996, 33996}, /* DDR2-667 SC */ + {1, 400, 800, 3430, 33430, 3946, 33946}, /* DDR2-800 SC */ + + {0, 800, 400, 3438, 33438, 4065, 34065}, /* DDR2-400 SC */ + {0, 800, 667, 3410, 33410, 3889, 33889}, /* DDR2-667 SC */ + {0, 800, 800, 3403, 33403, 3845, 33845}, /* DDR2-800 SC */ + + {0, 667, 400, 3456, 33456, 4103, 34106}, /* DDR2-400 SC */ + {0, 667, 667, 3428, 33428, 3927, 33927}, /* DDR2-667 SC */ + {0, 667, 800, 3443, 33443, 3905, 33905}, /* DDR2-800 SC */ + + {0, 400, 400, 3528, 33528, 4255, 34255}, /* DDR2-400 SC */ + {0, 400, 667, 3500, 33500, 4079, 34079}, /* DDR2-667 SC */ + {0, 400, 800, 3487, 33487, 4029, 34029}, /* DDR2-800 SC */ +}; + +static struct cxsr_latency *intel_get_cxsr_latency(int is_desktop, int fsb, + int mem) +{ + int i; + struct cxsr_latency *latency; + + if (fsb == 0 || mem == 0) + return NULL; + + for (i = 0; i < ARRAY_SIZE(cxsr_latency_table); i++) { + latency = &cxsr_latency_table[i]; + if (is_desktop == latency->is_desktop && + fsb == latency->fsb_freq && mem == latency->mem_freq) + break; + } + if (i >= ARRAY_SIZE(cxsr_latency_table)) { + DRM_DEBUG("Unknown FSB/MEM found, disable CxSR\n"); + return NULL; + } + return latency; +} + +static void igd_disable_cxsr(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 reg; + + /* deactivate cxsr */ + reg = I915_READ(DSPFW3); + reg &= ~(IGD_SELF_REFRESH_EN); + I915_WRITE(DSPFW3, reg); + DRM_INFO("Big FIFO is disabled\n"); +} + +static void igd_enable_cxsr(struct drm_device *dev, unsigned long clock, + int pixel_size) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 reg; + unsigned long wm; + struct cxsr_latency *latency; + + latency = intel_get_cxsr_latency(IS_IGDG(dev), dev_priv->fsb_freq, + dev_priv->mem_freq); + if (!latency) { + DRM_DEBUG("Unknown FSB/MEM found, disable CxSR\n"); + igd_disable_cxsr(dev); + return; + } + + /* Display SR */ + wm = intel_calculate_wm(clock, &igd_display_wm, pixel_size, + latency->display_sr); + reg = I915_READ(DSPFW1); + reg &= 0x7fffff; + reg |= wm << 23; + I915_WRITE(DSPFW1, reg); + DRM_DEBUG("DSPFW1 register is %x\n", reg); + + /* cursor SR */ + wm = intel_calculate_wm(clock, &igd_cursor_wm, pixel_size, + latency->cursor_sr); + reg = I915_READ(DSPFW3); + reg &= ~(0x3f << 24); + reg |= (wm & 0x3f) << 24; + I915_WRITE(DSPFW3, reg); + + /* Display HPLL off SR */ + wm = intel_calculate_wm(clock, &igd_display_hplloff_wm, + latency->display_hpll_disable, I915_FIFO_LINE_SIZE); + reg = I915_READ(DSPFW3); + reg &= 0xfffffe00; + reg |= wm & 0x1ff; + I915_WRITE(DSPFW3, reg); + + /* cursor HPLL off SR */ + wm = intel_calculate_wm(clock, &igd_cursor_hplloff_wm, pixel_size, + latency->cursor_hpll_disable); + reg = I915_READ(DSPFW3); + reg &= ~(0x3f << 16); + reg |= (wm & 0x3f) << 16; + I915_WRITE(DSPFW3, reg); + DRM_DEBUG("DSPFW3 register is %x\n", reg); + + /* activate cxsr */ + reg = I915_READ(DSPFW3); + reg |= IGD_SELF_REFRESH_EN; + I915_WRITE(DSPFW3, reg); + + DRM_INFO("Big FIFO is enabled\n"); + + return; +} + +const static int latency_ns = 5000; /* default for non-igd platforms */ + + +static void i965_update_wm(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + DRM_DEBUG("Setting FIFO watermarks - A: 8, B: 8, C: 8, SR 8\n"); + + /* 965 has limitations... */ + I915_WRITE(DSPFW1, (8 << 16) | (8 << 8) | (8 << 0)); + I915_WRITE(DSPFW2, (8 << 8) | (8 << 0)); +} + +static void i9xx_update_wm(struct drm_device *dev, int planea_clock, + int planeb_clock, int sr_hdisplay, int pixel_size) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t fwater_lo = I915_READ(FW_BLC) & MM_FIFO_WATERMARK; + uint32_t fwater_hi = I915_READ(FW_BLC2) & LM_FIFO_WATERMARK; + int bsize, asize, cwm, bwm = 1, awm = 1, srwm = 1; + uint32_t dsparb = I915_READ(DSPARB); + int planea_entries, planeb_entries; + struct intel_watermark_params *wm_params; + unsigned long line_time_us; + int sr_clock, sr_entries = 0; + + if (IS_I965GM(dev) || IS_I945GM(dev)) + wm_params = &i945_wm_info; + else if (IS_I9XX(dev)) + wm_params = &i915_wm_info; + else + wm_params = &i855_wm_info; + + planea_entries = intel_calculate_wm(planea_clock, wm_params, + pixel_size, latency_ns); + planeb_entries = intel_calculate_wm(planeb_clock, wm_params, + pixel_size, latency_ns); + + DRM_DEBUG("FIFO entries - A: %d, B: %d\n", planea_entries, + planeb_entries); + + if (IS_I9XX(dev)) { + asize = dsparb & 0x7f; + bsize = (dsparb >> DSPARB_CSTART_SHIFT) & 0x7f; + } else { + asize = dsparb & 0x1ff; + bsize = (dsparb >> DSPARB_BEND_SHIFT) & 0x1ff; + } + DRM_DEBUG("FIFO size - A: %d, B: %d\n", asize, bsize); + + /* Two extra entries for padding */ + awm = asize - (planea_entries + 2); + bwm = bsize - (planeb_entries + 2); + + /* Sanity check against potentially bad FIFO allocations */ + if (awm <= 0) { + /* pipe is on but has too few FIFO entries */ + if (planea_entries != 0) + DRM_DEBUG("plane A needs more FIFO entries\n"); + awm = 1; + } + if (bwm <= 0) { + if (planeb_entries != 0) + DRM_DEBUG("plane B needs more FIFO entries\n"); + bwm = 1; + } + + /* + * Overlay gets an aggressive default since video jitter is bad. + */ + cwm = 2; + + /* Calc sr entries for one pipe configs */ + if (!planea_clock || !planeb_clock) { + sr_clock = planea_clock ? planea_clock : planeb_clock; + line_time_us = (sr_hdisplay * 1000) / sr_clock; + sr_entries = (((latency_ns / line_time_us) + 1) * pixel_size * + sr_hdisplay) / 1000; + sr_entries = roundup(sr_entries / wm_params->cacheline_size, 1); + if (sr_entries < wm_params->fifo_size) + srwm = wm_params->fifo_size - sr_entries; + } + + DRM_DEBUG("Setting FIFO watermarks - A: %d, B: %d, C: %d, SR %d\n", + awm, bwm, cwm, srwm); + + fwater_lo = fwater_lo | ((bwm & 0x3f) << 16) | (awm & 0x3f); + fwater_hi = fwater_hi | (cwm & 0x1f); + + I915_WRITE(FW_BLC, fwater_lo); + I915_WRITE(FW_BLC2, fwater_hi); + if (IS_I9XX(dev)) + I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN | (srwm & 0x3f)); +} + +static void i830_update_wm(struct drm_device *dev, int planea_clock, + int pixel_size) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t dsparb = I915_READ(DSPARB); + uint32_t fwater_lo = I915_READ(FW_BLC) & MM_FIFO_WATERMARK; + unsigned int asize, awm; + int planea_entries; + + planea_entries = intel_calculate_wm(planea_clock, &i830_wm_info, + pixel_size, latency_ns); + + asize = dsparb & 0x7f; + + awm = asize - planea_entries; + + fwater_lo = fwater_lo | awm; + + I915_WRITE(FW_BLC, fwater_lo); +} + +/** + * intel_update_watermarks - update FIFO watermark values based on current modes + * + * Calculate watermark values for the various WM regs based on current mode + * and plane configuration. + * + * There are several cases to deal with here: + * - normal (i.e. non-self-refresh) + * - self-refresh (SR) mode + * - lines are large relative to FIFO size (buffer can hold up to 2) + * - lines are small relative to FIFO size (buffer can hold more than 2 + * lines), so need to account for TLB latency + * + * The normal calculation is: + * watermark = dotclock * bytes per pixel * latency + * where latency is platform & configuration dependent (we assume pessimal + * values here). + * + * The SR calculation is: + * watermark = (trunc(latency/line time)+1) * surface width * + * bytes per pixel + * where + * line time = htotal / dotclock + * and latency is assumed to be high, as above. + * + * The final value programmed to the register should always be rounded up, + * and include an extra 2 entries to account for clock crossings. + * + * We don't use the sprite, so we can ignore that. And on Crestline we have + * to set the non-SR watermarks to 8. + */ +static void intel_update_watermarks(struct drm_device *dev) +{ + struct drm_crtc *crtc; + struct intel_crtc *intel_crtc; + int sr_hdisplay = 0; + unsigned long planea_clock = 0, planeb_clock = 0, sr_clock = 0; + int enabled = 0, pixel_size = 0; + + if (DSPARB_HWCONTROL(dev)) + return; + + /* Get the clock config from both planes */ + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + intel_crtc = to_intel_crtc(crtc); + if (crtc->enabled) { + enabled++; + if (intel_crtc->plane == 0) { + DRM_DEBUG("plane A (pipe %d) clock: %d\n", + intel_crtc->pipe, crtc->mode.clock); + planea_clock = crtc->mode.clock; + } else { + DRM_DEBUG("plane B (pipe %d) clock: %d\n", + intel_crtc->pipe, crtc->mode.clock); + planeb_clock = crtc->mode.clock; + } + sr_hdisplay = crtc->mode.hdisplay; + sr_clock = crtc->mode.clock; + if (crtc->fb) + pixel_size = crtc->fb->bits_per_pixel / 8; + else + pixel_size = 4; /* by default */ + } + } + + if (enabled <= 0) + return; + + /* Single pipe configs can enable self refresh */ + if (enabled == 1 && IS_IGD(dev)) + igd_enable_cxsr(dev, sr_clock, pixel_size); + else if (IS_IGD(dev)) + igd_disable_cxsr(dev); + + if (IS_I965G(dev)) + i965_update_wm(dev); + else if (IS_I9XX(dev) || IS_MOBILE(dev)) + i9xx_update_wm(dev, planea_clock, planeb_clock, sr_hdisplay, + pixel_size); + else + i830_update_wm(dev, planea_clock, pixel_size); +} + static int intel_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode, @@ -1951,6 +2365,9 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, /* Flush the plane changes */ ret = intel_pipe_set_base(crtc, x, y, old_fb); + + intel_update_watermarks(dev); + drm_vblank_post_modeset(dev, pipe); return ret; @@ -2439,6 +2856,7 @@ static void intel_crtc_init(struct drm_device *dev, int pipe) drm_mode_crtc_set_gamma_size(&intel_crtc->base, 256); intel_crtc->pipe = pipe; + intel_crtc->plane = pipe; for (i = 0; i < 256; i++) { intel_crtc->lut_r[i] = i; intel_crtc->lut_g[i] = i; diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 8f8d37d5663..6770ae88370 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -246,7 +246,7 @@ intel_dp_aux_ch(struct intel_output *intel_output, } if ((status & DP_AUX_CH_CTL_DONE) == 0) { - printk(KERN_ERR "dp_aux_ch not done status 0x%08x\n", status); + DRM_ERROR("dp_aux_ch not done status 0x%08x\n", status); return -EBUSY; } @@ -254,11 +254,14 @@ intel_dp_aux_ch(struct intel_output *intel_output, * Timeouts occur when the sink is not connected */ if (status & DP_AUX_CH_CTL_RECEIVE_ERROR) { - printk(KERN_ERR "dp_aux_ch receive error status 0x%08x\n", status); + DRM_ERROR("dp_aux_ch receive error status 0x%08x\n", status); return -EIO; } + + /* Timeouts occur when the device isn't connected, so they're + * "normal" -- don't fill the kernel log with these */ if (status & DP_AUX_CH_CTL_TIME_OUT_ERROR) { - printk(KERN_ERR "dp_aux_ch timeout status 0x%08x\n", status); + DRM_DEBUG("dp_aux_ch timeout status 0x%08x\n", status); return -ETIMEDOUT; } @@ -411,7 +414,7 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, dp_priv->link_bw = bws[clock]; dp_priv->lane_count = lane_count; adjusted_mode->clock = intel_dp_link_clock(dp_priv->link_bw); - printk(KERN_ERR "link bw %02x lane count %d clock %d\n", + DRM_DEBUG("Display port link bw %02x lane count %d clock %d\n", dp_priv->link_bw, dp_priv->lane_count, adjusted_mode->clock); return true; diff --git a/drivers/gpu/drm/i915/intel_dp_i2c.c b/drivers/gpu/drm/i915/intel_dp_i2c.c index 4e60f14b1a6..a63b6f57d2d 100644 --- a/drivers/gpu/drm/i915/intel_dp_i2c.c +++ b/drivers/gpu/drm/i915/intel_dp_i2c.c @@ -29,6 +29,7 @@ #include <linux/sched.h> #include <linux/i2c.h> #include "intel_dp.h" +#include "drmP.h" /* Run a single AUX_CH I2C transaction, writing/reading data as necessary */ @@ -84,7 +85,7 @@ i2c_algo_dp_aux_transaction(struct i2c_adapter *adapter, int mode, msg, msg_bytes, reply, reply_bytes); if (ret < 0) { - printk(KERN_ERR "aux_ch failed %d\n", ret); + DRM_DEBUG("aux_ch failed %d\n", ret); return ret; } switch (reply[0] & AUX_I2C_REPLY_MASK) { @@ -94,14 +95,14 @@ i2c_algo_dp_aux_transaction(struct i2c_adapter *adapter, int mode, } return reply_bytes - 1; case AUX_I2C_REPLY_NACK: - printk(KERN_ERR "aux_ch nack\n"); + DRM_DEBUG("aux_ch nack\n"); return -EREMOTEIO; case AUX_I2C_REPLY_DEFER: - printk(KERN_ERR "aux_ch defer\n"); + DRM_DEBUG("aux_ch defer\n"); udelay(100); break; default: - printk(KERN_ERR "aux_ch invalid reply 0x%02x\n", reply[0]); + DRM_ERROR("aux_ch invalid reply 0x%02x\n", reply[0]); return -EREMOTEIO; } } @@ -223,7 +224,7 @@ i2c_algo_dp_aux_xfer(struct i2c_adapter *adapter, if (ret >= 0) ret = num; i2c_algo_dp_aux_stop(adapter, reading); - printk(KERN_ERR "dp_aux_xfer return %d\n", ret); + DRM_DEBUG("dp_aux_xfer return %d\n", ret); return ret; } diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index 1af7d68e380..1d30802e773 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -453,7 +453,7 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width, size = ALIGN(size, PAGE_SIZE); fbo = drm_gem_object_alloc(dev, size); if (!fbo) { - printk(KERN_ERR "failed to allocate framebuffer\n"); + DRM_ERROR("failed to allocate framebuffer\n"); ret = -ENOMEM; goto out; } @@ -610,8 +610,8 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width, par->dev = dev; /* To allow resizeing without swapping buffers */ - printk("allocated %dx%d fb: 0x%08x, bo %p\n", intel_fb->base.width, - intel_fb->base.height, obj_priv->gtt_offset, fbo); + DRM_DEBUG("allocated %dx%d fb: 0x%08x, bo %p\n", intel_fb->base.width, + intel_fb->base.height, obj_priv->gtt_offset, fbo); mutex_unlock(&dev->struct_mutex); return 0; @@ -698,13 +698,13 @@ static int intelfb_multi_fb_probe_crtc(struct drm_device *dev, struct drm_crtc * } else intelfb_set_par(info); - printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, + DRM_INFO("fb%d: %s frame buffer device\n", info->node, info->fix.id); /* Switch back to kernel console on panic */ kernelfb_mode = *modeset; atomic_notifier_chain_register(&panic_notifier_list, &paniced); - printk(KERN_INFO "registered panic notifier\n"); + DRM_DEBUG("registered panic notifier\n"); return 0; } @@ -852,13 +852,13 @@ static int intelfb_single_fb_probe(struct drm_device *dev) } else intelfb_set_par(info); - printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, + DRM_INFO("fb%d: %s frame buffer device\n", info->node, info->fix.id); /* Switch back to kernel console on panic */ kernelfb_mode = *modeset; atomic_notifier_chain_register(&panic_notifier_list, &paniced); - printk(KERN_INFO "registered panic notifier\n"); + DRM_DEBUG("registered panic notifier\n"); return 0; } @@ -872,8 +872,8 @@ void intelfb_restore(void) { int ret; if ((ret = drm_crtc_helper_set_config(&kernelfb_mode)) != 0) { - printk(KERN_ERR "Failed to restore crtc configuration: %d\n", - ret); + DRM_ERROR("Failed to restore crtc configuration: %d\n", + ret); } } diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 9564ca44a97..9ab38efffec 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -36,6 +36,7 @@ #include "intel_drv.h" #include "i915_drm.h" #include "i915_drv.h" +#include <linux/acpi.h> #define I915_LVDS "i915_lvds" @@ -252,14 +253,14 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, /* Should never happen!! */ if (!IS_I965G(dev) && intel_crtc->pipe == 0) { - printk(KERN_ERR "Can't support LVDS on pipe A\n"); + DRM_ERROR("Can't support LVDS on pipe A\n"); return false; } /* Should never happen!! */ list_for_each_entry(tmp_encoder, &dev->mode_config.encoder_list, head) { if (tmp_encoder != encoder && tmp_encoder->crtc == encoder->crtc) { - printk(KERN_ERR "Can't enable LVDS and another " + DRM_ERROR("Can't enable LVDS and another " "encoder on the same pipe\n"); return false; } @@ -788,6 +789,65 @@ static const struct dmi_system_id intel_no_lvds[] = { { } /* terminating entry */ }; +#ifdef CONFIG_ACPI +/* + * check_lid_device -- check whether @handle is an ACPI LID device. + * @handle: ACPI device handle + * @level : depth in the ACPI namespace tree + * @context: the number of LID device when we find the device + * @rv: a return value to fill if desired (Not use) + */ +static acpi_status +check_lid_device(acpi_handle handle, u32 level, void *context, + void **return_value) +{ + struct acpi_device *acpi_dev; + int *lid_present = context; + + acpi_dev = NULL; + /* Get the acpi device for device handle */ + if (acpi_bus_get_device(handle, &acpi_dev) || !acpi_dev) { + /* If there is no ACPI device for handle, return */ + return AE_OK; + } + + if (!strncmp(acpi_device_hid(acpi_dev), "PNP0C0D", 7)) + *lid_present = 1; + + return AE_OK; +} + +/** + * check whether there exists the ACPI LID device by enumerating the ACPI + * device tree. + */ +static int intel_lid_present(void) +{ + int lid_present = 0; + + if (acpi_disabled) { + /* If ACPI is disabled, there is no ACPI device tree to + * check, so assume the LID device would have been present. + */ + return 1; + } + + acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, + check_lid_device, &lid_present, NULL); + + return lid_present; +} +#else +static int intel_lid_present(void) +{ + /* In the absence of ACPI built in, assume that the LID device would + * have been present. + */ + return 1; +} +#endif + /** * intel_lvds_init - setup LVDS connectors on this device * @dev: drm device @@ -811,6 +871,16 @@ void intel_lvds_init(struct drm_device *dev) if (dmi_check_system(intel_no_lvds)) return; + /* Assume that any device without an ACPI LID device also doesn't + * have an integrated LVDS. We would be better off parsing the BIOS + * to get a reliable indicator, but that code isn't written yet. + * + * In the case of all-in-one desktops using LVDS that we've seen, + * they're using SDVO LVDS. + */ + if (!intel_lid_present()) + return; + if (IS_IGDNG(dev)) { if ((I915_READ(PCH_LVDS) & LVDS_DETECTED) == 0) return; diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index f03473779fe..4f0c30948bc 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -68,12 +68,23 @@ struct intel_sdvo_priv { * This is set if we treat the device as HDMI, instead of DVI. */ bool is_hdmi; + /** * This is set if we detect output of sdvo device as LVDS. */ bool is_lvds; /** + * This is sdvo flags for input timing. + */ + uint8_t sdvo_flags; + + /** + * This is sdvo fixed pannel mode pointer + */ + struct drm_display_mode *sdvo_lvds_fixed_mode; + + /** * Returned SDTV resolutions allowed for the current format, if the * device reported it. */ @@ -592,6 +603,7 @@ intel_sdvo_create_preferred_input_timing(struct intel_output *output, uint16_t height) { struct intel_sdvo_preferred_input_timing_args args; + struct intel_sdvo_priv *sdvo_priv = output->dev_priv; uint8_t status; memset(&args, 0, sizeof(args)); @@ -599,7 +611,12 @@ intel_sdvo_create_preferred_input_timing(struct intel_output *output, args.width = width; args.height = height; args.interlace = 0; - args.scaled = 0; + + if (sdvo_priv->is_lvds && + (sdvo_priv->sdvo_lvds_fixed_mode->hdisplay != width || + sdvo_priv->sdvo_lvds_fixed_mode->vdisplay != height)) + args.scaled = 1; + intel_sdvo_write_cmd(output, SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING, &args, sizeof(args)); status = intel_sdvo_read_response(output, NULL, 0); @@ -944,12 +961,7 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder, struct intel_output *output = enc_to_intel_output(encoder); struct intel_sdvo_priv *dev_priv = output->dev_priv; - if (!dev_priv->is_tv) { - /* Make the CRTC code factor in the SDVO pixel multiplier. The - * SDVO device will be told of the multiplier during mode_set. - */ - adjusted_mode->clock *= intel_sdvo_get_pixel_multiplier(mode); - } else { + if (dev_priv->is_tv) { struct intel_sdvo_dtd output_dtd; bool success; @@ -980,6 +992,47 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder, intel_sdvo_get_preferred_input_timing(output, &input_dtd); intel_sdvo_get_mode_from_dtd(adjusted_mode, &input_dtd); + dev_priv->sdvo_flags = input_dtd.part2.sdvo_flags; + + drm_mode_set_crtcinfo(adjusted_mode, 0); + + mode->clock = adjusted_mode->clock; + + adjusted_mode->clock *= + intel_sdvo_get_pixel_multiplier(mode); + } else { + return false; + } + } else if (dev_priv->is_lvds) { + struct intel_sdvo_dtd output_dtd; + bool success; + + drm_mode_set_crtcinfo(dev_priv->sdvo_lvds_fixed_mode, 0); + /* Set output timings */ + intel_sdvo_get_dtd_from_mode(&output_dtd, + dev_priv->sdvo_lvds_fixed_mode); + + intel_sdvo_set_target_output(output, + dev_priv->controlled_output); + intel_sdvo_set_output_timing(output, &output_dtd); + + /* Set the input timing to the screen. Assume always input 0. */ + intel_sdvo_set_target_input(output, true, false); + + + success = intel_sdvo_create_preferred_input_timing( + output, + mode->clock / 10, + mode->hdisplay, + mode->vdisplay); + + if (success) { + struct intel_sdvo_dtd input_dtd; + + intel_sdvo_get_preferred_input_timing(output, + &input_dtd); + intel_sdvo_get_mode_from_dtd(adjusted_mode, &input_dtd); + dev_priv->sdvo_flags = input_dtd.part2.sdvo_flags; drm_mode_set_crtcinfo(adjusted_mode, 0); @@ -990,6 +1043,12 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder, } else { return false; } + + } else { + /* Make the CRTC code factor in the SDVO pixel multiplier. The + * SDVO device will be told of the multiplier during mode_set. + */ + adjusted_mode->clock *= intel_sdvo_get_pixel_multiplier(mode); } return true; } @@ -1033,15 +1092,16 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, /* We have tried to get input timing in mode_fixup, and filled into adjusted_mode */ - if (sdvo_priv->is_tv) + if (sdvo_priv->is_tv || sdvo_priv->is_lvds) { intel_sdvo_get_dtd_from_mode(&input_dtd, adjusted_mode); - else + input_dtd.part2.sdvo_flags = sdvo_priv->sdvo_flags; + } else intel_sdvo_get_dtd_from_mode(&input_dtd, mode); /* If it's a TV, we already set the output timing in mode_fixup. * Otherwise, the output timing is equal to the input timing. */ - if (!sdvo_priv->is_tv) { + if (!sdvo_priv->is_tv && !sdvo_priv->is_lvds) { /* Set the output timing to the screen */ intel_sdvo_set_target_output(output, sdvo_priv->controlled_output); @@ -1116,6 +1176,8 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, sdvox |= (sdvo_pixel_multiply - 1) << SDVO_PORT_MULTIPLY_SHIFT; } + if (sdvo_priv->sdvo_flags & SDVO_NEED_TO_STALL) + sdvox |= SDVO_STALL_SELECT; intel_sdvo_write_sdvox(output, sdvox); } @@ -1276,6 +1338,17 @@ static int intel_sdvo_mode_valid(struct drm_connector *connector, if (sdvo_priv->pixel_clock_max < mode->clock) return MODE_CLOCK_HIGH; + if (sdvo_priv->is_lvds == true) { + if (sdvo_priv->sdvo_lvds_fixed_mode == NULL) + return MODE_PANEL; + + if (mode->hdisplay > sdvo_priv->sdvo_lvds_fixed_mode->hdisplay) + return MODE_PANEL; + + if (mode->vdisplay > sdvo_priv->sdvo_lvds_fixed_mode->vdisplay) + return MODE_PANEL; + } + return MODE_OK; } @@ -1549,6 +1622,8 @@ static void intel_sdvo_get_lvds_modes(struct drm_connector *connector) { struct intel_output *intel_output = to_intel_output(connector); struct drm_i915_private *dev_priv = connector->dev->dev_private; + struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; + struct drm_display_mode *newmode; /* * Attempt to get the mode list from DDC. @@ -1557,11 +1632,10 @@ static void intel_sdvo_get_lvds_modes(struct drm_connector *connector) */ intel_ddc_get_modes(intel_output); if (list_empty(&connector->probed_modes) == false) - return; + goto end; /* Fetch modes from VBT */ if (dev_priv->sdvo_lvds_vbt_mode != NULL) { - struct drm_display_mode *newmode; newmode = drm_mode_duplicate(connector->dev, dev_priv->sdvo_lvds_vbt_mode); if (newmode != NULL) { @@ -1571,6 +1645,16 @@ static void intel_sdvo_get_lvds_modes(struct drm_connector *connector) drm_mode_probed_add(connector, newmode); } } + +end: + list_for_each_entry(newmode, &connector->probed_modes, head) { + if (newmode->type & DRM_MODE_TYPE_PREFERRED) { + sdvo_priv->sdvo_lvds_fixed_mode = + drm_mode_duplicate(connector->dev, newmode); + break; + } + } + } static int intel_sdvo_get_modes(struct drm_connector *connector) @@ -1593,14 +1677,20 @@ static int intel_sdvo_get_modes(struct drm_connector *connector) static void intel_sdvo_destroy(struct drm_connector *connector) { struct intel_output *intel_output = to_intel_output(connector); + struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; if (intel_output->i2c_bus) intel_i2c_destroy(intel_output->i2c_bus); if (intel_output->ddc_bus) intel_i2c_destroy(intel_output->ddc_bus); + if (sdvo_priv->sdvo_lvds_fixed_mode != NULL) + drm_mode_destroy(connector->dev, + sdvo_priv->sdvo_lvds_fixed_mode); + drm_sysfs_connector_remove(connector); drm_connector_cleanup(connector); + kfree(intel_output); } diff --git a/drivers/gpu/drm/i915/intel_sdvo_regs.h b/drivers/gpu/drm/i915/intel_sdvo_regs.h index 193938b7d7f..ba5cdf8ae40 100644 --- a/drivers/gpu/drm/i915/intel_sdvo_regs.h +++ b/drivers/gpu/drm/i915/intel_sdvo_regs.h @@ -715,6 +715,7 @@ struct intel_sdvo_enhancements_arg { #define SDVO_HBUF_TX_ONCE (2 << 6) #define SDVO_HBUF_TX_VSYNC (3 << 6) #define SDVO_CMD_GET_AUDIO_TX_INFO 0x9c +#define SDVO_NEED_TO_STALL (1 << 7) struct intel_sdvo_encode{ u8 dvi_rev; diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index 76c4bbe9dcc..3c1fcb7640a 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -22,7 +22,6 @@ #include <linux/list.h> #include <linux/mm.h> #include <linux/mutex.h> -#include <linux/smp_lock.h> #include <linux/spinlock.h> #include <asm/unaligned.h> #include <asm/byteorder.h> diff --git a/drivers/hwmon/abituguru3.c b/drivers/hwmon/abituguru3.c index ad2b3431b72..7d3f15d32fd 100644 --- a/drivers/hwmon/abituguru3.c +++ b/drivers/hwmon/abituguru3.c @@ -357,7 +357,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = { { "AUX5 Fan", 39, 2, 60, 1, 0 }, { NULL, 0, 0, 0, 0, 0 } } }, - { 0x0014, NULL /* Abit AB9 Pro, need DMI string */, { + { 0x0014, "AB9", /* + AB9 Pro */ { { "CPU Core", 0, 0, 10, 1, 0 }, { "DDR", 1, 0, 10, 1, 0 }, { "DDR VTT", 2, 0, 10, 1, 0 }, @@ -455,7 +455,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = { { "AUX3 FAN", 37, 2, 60, 1, 0 }, { NULL, 0, 0, 0, 0, 0 } } }, - { 0x0018, NULL /* Unknown, need DMI string */, { + { 0x0018, "AB9 QuadGT", { { "CPU Core", 0, 0, 10, 1, 0 }, { "DDR2", 1, 0, 20, 1, 0 }, { "DDR2 VTT", 2, 0, 10, 1, 0 }, @@ -564,7 +564,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = { { "AUX3 Fan", 36, 2, 60, 1, 0 }, { NULL, 0, 0, 0, 0, 0 } } }, - { 0x001C, NULL /* Unknown, need DMI string */, { + { 0x001C, "IX38 QuadGT", { { "CPU Core", 0, 0, 10, 1, 0 }, { "DDR2", 1, 0, 20, 1, 0 }, { "DDR2 VTT", 2, 0, 10, 1, 0 }, diff --git a/drivers/hwmon/max6650.c b/drivers/hwmon/max6650.c index 86142a85823..58f66be61b1 100644 --- a/drivers/hwmon/max6650.c +++ b/drivers/hwmon/max6650.c @@ -418,6 +418,7 @@ static ssize_t set_div(struct device *dev, struct device_attribute *devattr, data->count = 3; break; default: + mutex_unlock(&data->update_lock); dev_err(&client->dev, "illegal value for fan divider (%d)\n", div); return -EINVAL; diff --git a/drivers/hwmon/sht15.c b/drivers/hwmon/sht15.c index 56cd6004da3..6290a259456 100644 --- a/drivers/hwmon/sht15.c +++ b/drivers/hwmon/sht15.c @@ -257,7 +257,7 @@ static inline int sht15_update_single_val(struct sht15_data *data, (data->flag == SHT15_READING_NOTHING), msecs_to_jiffies(timeout_msecs)); if (ret == 0) {/* timeout occurred */ - disable_irq_nosync(gpio_to_irq(data->pdata->gpio_data));; + disable_irq_nosync(gpio_to_irq(data->pdata->gpio_data)); sht15_connection_reset(data); return -ETIME; } diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c index 3fae3a91ce5..c89687a1083 100644 --- a/drivers/i2c/busses/i2c-davinci.c +++ b/drivers/i2c/busses/i2c-davinci.c @@ -187,6 +187,11 @@ static int i2c_davinci_init(struct davinci_i2c_dev *dev) davinci_i2c_write_reg(dev, DAVINCI_I2C_CLKH_REG, clkh); davinci_i2c_write_reg(dev, DAVINCI_I2C_CLKL_REG, clkl); + /* Respond at reserved "SMBus Host" slave address" (and zero); + * we seem to have no option to not respond... + */ + davinci_i2c_write_reg(dev, DAVINCI_I2C_OAR_REG, 0x08); + dev_dbg(dev->dev, "input_clock = %d, CLK = %d\n", input_clock, clk); dev_dbg(dev->dev, "PSC = %d\n", davinci_i2c_read_reg(dev, DAVINCI_I2C_PSC_REG)); @@ -387,7 +392,7 @@ static void terminate_write(struct davinci_i2c_dev *dev) davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, w); if (!dev->terminate) - dev_err(dev->dev, "TDR IRQ while no data to send\n"); + dev_dbg(dev->dev, "TDR IRQ while no data to send\n"); } /* @@ -473,9 +478,14 @@ static irqreturn_t i2c_davinci_isr(int this_irq, void *dev_id) break; case DAVINCI_I2C_IVR_AAS: - dev_warn(dev->dev, "Address as slave interrupt\n"); - }/* switch */ - }/* while */ + dev_dbg(dev->dev, "Address as slave interrupt\n"); + break; + + default: + dev_warn(dev->dev, "Unrecognized irq stat %d\n", stat); + break; + } + } return count ? IRQ_HANDLED : IRQ_NONE; } @@ -505,7 +515,7 @@ static int davinci_i2c_probe(struct platform_device *pdev) return -ENODEV; } - ioarea = request_mem_region(mem->start, (mem->end - mem->start) + 1, + ioarea = request_mem_region(mem->start, resource_size(mem), pdev->name); if (!ioarea) { dev_err(&pdev->dev, "I2C region already claimed\n"); @@ -523,7 +533,7 @@ static int davinci_i2c_probe(struct platform_device *pdev) dev->irq = irq->start; platform_set_drvdata(pdev, dev); - dev->clk = clk_get(&pdev->dev, "I2CCLK"); + dev->clk = clk_get(&pdev->dev, NULL); if (IS_ERR(dev->clk)) { r = -ENODEV; goto err_free_mem; @@ -568,7 +578,7 @@ err_free_mem: put_device(&pdev->dev); kfree(dev); err_release_region: - release_mem_region(mem->start, (mem->end - mem->start) + 1); + release_mem_region(mem->start, resource_size(mem)); return r; } @@ -591,7 +601,7 @@ static int davinci_i2c_remove(struct platform_device *pdev) kfree(dev); mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(mem->start, (mem->end - mem->start) + 1); + release_mem_region(mem->start, resource_size(mem)); return 0; } diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index ad8d2010c92..fdd83277c8a 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -806,7 +806,7 @@ omap_i2c_probe(struct platform_device *pdev) return -ENODEV; } - ioarea = request_mem_region(mem->start, (mem->end - mem->start) + 1, + ioarea = request_mem_region(mem->start, resource_size(mem), pdev->name); if (!ioarea) { dev_err(&pdev->dev, "I2C region already claimed\n"); @@ -905,7 +905,7 @@ err_free_mem: platform_set_drvdata(pdev, NULL); kfree(dev); err_release_region: - release_mem_region(mem->start, (mem->end - mem->start) + 1); + release_mem_region(mem->start, resource_size(mem)); return r; } @@ -925,7 +925,7 @@ omap_i2c_remove(struct platform_device *pdev) iounmap(dev->base); kfree(dev); mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(mem->start, (mem->end - mem->start) + 1); + release_mem_region(mem->start, resource_size(mem)); return 0; } diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index 1c01083b01b..4f3d99cd169 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -563,7 +563,7 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) goto err_irq; } - size = (res->end - res->start) + 1; + size = resource_size(res); pd->reg = ioremap(res->start, size); if (pd->reg == NULL) { diff --git a/drivers/i2c/busses/i2c-simtec.c b/drivers/i2c/busses/i2c-simtec.c index 042fda295f3..6407f47bda8 100644 --- a/drivers/i2c/busses/i2c-simtec.c +++ b/drivers/i2c/busses/i2c-simtec.c @@ -92,7 +92,7 @@ static int simtec_i2c_probe(struct platform_device *dev) goto err; } - size = (res->end-res->start)+1; + size = resource_size(res); pd->ioarea = request_mem_region(res->start, size, dev->name); if (pd->ioarea == NULL) { diff --git a/drivers/isdn/hisax/hfc_usb.c b/drivers/isdn/hisax/hfc_usb.c index 8df889b0c1a..9de54202c90 100644 --- a/drivers/isdn/hisax/hfc_usb.c +++ b/drivers/isdn/hisax/hfc_usb.c @@ -37,7 +37,6 @@ #include <linux/kernel_stat.h> #include <linux/usb.h> #include <linux/kernel.h> -#include <linux/smp_lock.h> #include <linux/sched.h> #include <linux/moduleparam.h> #include "hisax.h" diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c index b4d4522e507..2881a66c1aa 100644 --- a/drivers/isdn/i4l/isdn_tty.c +++ b/drivers/isdn/i4l/isdn_tty.c @@ -13,6 +13,7 @@ #include <linux/isdn.h> #include <linux/delay.h> +#include <linux/smp_lock.h> #include "isdn_common.h" #include "isdn_tty.h" #ifdef CONFIG_ISDN_AUDIO diff --git a/drivers/isdn/mISDN/stack.c b/drivers/isdn/mISDN/stack.c index e2f45019ebf..3e1532a180f 100644 --- a/drivers/isdn/mISDN/stack.c +++ b/drivers/isdn/mISDN/stack.c @@ -17,6 +17,7 @@ #include <linux/mISDNif.h> #include <linux/kthread.h> +#include <linux/smp_lock.h> #include "core.h" static u_int *debug; diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 9933eb861c7..529e2ba505c 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -776,7 +776,7 @@ static void kcryptd_crypt_write_convert(struct dm_crypt_io *io) * But don't wait if split was due to the io size restriction */ if (unlikely(out_of_pages)) - congestion_wait(WRITE, HZ/100); + congestion_wait(BLK_RW_ASYNC, HZ/100); /* * With async crypto it is unsafe to share the crypto context diff --git a/drivers/media/dvb/bt8xx/dst_ca.c b/drivers/media/dvb/bt8xx/dst_ca.c index 4601b059b2b..0e246eaad05 100644 --- a/drivers/media/dvb/bt8xx/dst_ca.c +++ b/drivers/media/dvb/bt8xx/dst_ca.c @@ -21,6 +21,7 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> +#include <linux/smp_lock.h> #include <linux/string.h> #include <linux/dvb/ca.h> #include "dvbdev.h" diff --git a/drivers/media/dvb/dvb-core/dvbdev.h b/drivers/media/dvb/dvb-core/dvbdev.h index 79927305e84..487919bea7a 100644 --- a/drivers/media/dvb/dvb-core/dvbdev.h +++ b/drivers/media/dvb/dvb-core/dvbdev.h @@ -27,7 +27,6 @@ #include <linux/poll.h> #include <linux/fs.h> #include <linux/list.h> -#include <linux/smp_lock.h> #define DVB_MAJOR 212 diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c index d1d959ed37b..8d65c652ba5 100644 --- a/drivers/media/dvb/ttpci/av7110.c +++ b/drivers/media/dvb/ttpci/av7110.c @@ -36,7 +36,6 @@ #include <linux/fs.h> #include <linux/timer.h> #include <linux/poll.h> -#include <linux/smp_lock.h> #include <linux/kernel.h> #include <linux/sched.h> diff --git a/drivers/media/radio/radio-mr800.c b/drivers/media/radio/radio-mr800.c index 837467f9380..575bf9d8941 100644 --- a/drivers/media/radio/radio-mr800.c +++ b/drivers/media/radio/radio-mr800.c @@ -58,6 +58,7 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> +#include <linux/smp_lock.h> #include <linux/input.h> #include <linux/videodev2.h> #include <media/v4l2-device.h> diff --git a/drivers/media/radio/radio-si470x.c b/drivers/media/radio/radio-si470x.c index 46d21632961..e85f318b4d2 100644 --- a/drivers/media/radio/radio-si470x.c +++ b/drivers/media/radio/radio-si470x.c @@ -127,6 +127,7 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> +#include <linux/smp_lock.h> #include <linux/input.h> #include <linux/usb.h> #include <linux/hid.h> diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index 5eb1464af67..d147d29bb0d 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -41,6 +41,7 @@ #include <linux/fs.h> #include <linux/kernel.h> #include <linux/sched.h> +#include <linux/smp_lock.h> #include <linux/interrupt.h> #include <linux/kdev_t.h> #include "bttvp.h" diff --git a/drivers/media/video/cx23885/cx23885-417.c b/drivers/media/video/cx23885/cx23885-417.c index 2943bfd32a9..428f0c45e6b 100644 --- a/drivers/media/video/cx23885/cx23885-417.c +++ b/drivers/media/video/cx23885/cx23885-417.c @@ -31,6 +31,7 @@ #include <linux/delay.h> #include <linux/device.h> #include <linux/firmware.h> +#include <linux/smp_lock.h> #include <media/v4l2-common.h> #include <media/v4l2-ioctl.h> #include <media/cx2341x.h> diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c index 70836af3ab4..5d609333630 100644 --- a/drivers/media/video/cx23885/cx23885-video.c +++ b/drivers/media/video/cx23885/cx23885-video.c @@ -26,6 +26,7 @@ #include <linux/kmod.h> #include <linux/kernel.h> #include <linux/slab.h> +#include <linux/smp_lock.h> #include <linux/interrupt.h> #include <linux/delay.h> #include <linux/kthread.h> diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c index 44eacfb0d0d..356d6896da3 100644 --- a/drivers/media/video/cx88/cx88-blackbird.c +++ b/drivers/media/video/cx88/cx88-blackbird.c @@ -32,6 +32,7 @@ #include <linux/delay.h> #include <linux/device.h> #include <linux/firmware.h> +#include <linux/smp_lock.h> #include <media/v4l2-common.h> #include <media/v4l2-ioctl.h> #include <media/cx2341x.h> diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index b12770848c0..2bb54c3ef5c 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -31,6 +31,7 @@ #include <linux/kmod.h> #include <linux/kernel.h> #include <linux/slab.h> +#include <linux/smp_lock.h> #include <linux/interrupt.h> #include <linux/dma-mapping.h> #include <linux/delay.h> diff --git a/drivers/media/video/dabusb.c b/drivers/media/video/dabusb.c index ec2f45dde16..0664d111085 100644 --- a/drivers/media/video/dabusb.c +++ b/drivers/media/video/dabusb.c @@ -32,6 +32,7 @@ #include <linux/list.h> #include <linux/vmalloc.h> #include <linux/slab.h> +#include <linux/smp_lock.h> #include <linux/init.h> #include <asm/uaccess.h> #include <asm/atomic.h> diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c index db25c3034c1..8d17cf61330 100644 --- a/drivers/media/video/pwc/pwc-if.c +++ b/drivers/media/video/pwc/pwc-if.c @@ -62,6 +62,7 @@ #include <linux/module.h> #include <linux/poll.h> #include <linux/slab.h> +#include <linux/smp_lock.h> #ifdef CONFIG_USB_PWC_INPUT_EVDEV #include <linux/usb/input.h> #endif diff --git a/drivers/media/video/pwc/pwc.h b/drivers/media/video/pwc/pwc.h index 0be6f814f53..0b658dee05a 100644 --- a/drivers/media/video/pwc/pwc.h +++ b/drivers/media/video/pwc/pwc.h @@ -29,7 +29,6 @@ #include <linux/usb.h> #include <linux/spinlock.h> #include <linux/wait.h> -#include <linux/smp_lock.h> #include <linux/version.h> #include <linux/mutex.h> #include <linux/mm.h> diff --git a/drivers/media/video/s2255drv.c b/drivers/media/video/s2255drv.c index 6be845ccc7d..9e3262c0ba3 100644 --- a/drivers/media/video/s2255drv.c +++ b/drivers/media/video/s2255drv.c @@ -48,6 +48,7 @@ #include <linux/videodev2.h> #include <linux/version.h> #include <linux/mm.h> +#include <linux/smp_lock.h> #include <media/videobuf-vmalloc.h> #include <media/v4l2-common.h> #include <media/v4l2-ioctl.h> diff --git a/drivers/media/video/saa5246a.c b/drivers/media/video/saa5246a.c index 155804b061e..b624a4c01fd 100644 --- a/drivers/media/video/saa5246a.c +++ b/drivers/media/video/saa5246a.c @@ -43,7 +43,6 @@ #include <linux/mm.h> #include <linux/init.h> #include <linux/i2c.h> -#include <linux/smp_lock.h> #include <linux/mutex.h> #include <linux/videotext.h> #include <linux/videodev2.h> diff --git a/drivers/media/video/saa5249.c b/drivers/media/video/saa5249.c index 271d6e931b7..12835fb82c9 100644 --- a/drivers/media/video/saa5249.c +++ b/drivers/media/video/saa5249.c @@ -46,7 +46,6 @@ #include <linux/mm.h> #include <linux/init.h> #include <linux/i2c.h> -#include <linux/smp_lock.h> #include <linux/mutex.h> #include <linux/delay.h> #include <linux/videotext.h> diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c index add1757f893..296788c3bf0 100644 --- a/drivers/media/video/saa7134/saa7134-empress.c +++ b/drivers/media/video/saa7134/saa7134-empress.c @@ -22,6 +22,7 @@ #include <linux/module.h> #include <linux/kernel.h> #include <linux/slab.h> +#include <linux/smp_lock.h> #include <linux/delay.h> #include "saa7134-reg.h" diff --git a/drivers/media/video/se401.c b/drivers/media/video/se401.c index c8f05297d0f..85ffc2cba03 100644 --- a/drivers/media/video/se401.c +++ b/drivers/media/video/se401.c @@ -31,6 +31,7 @@ static const char version[] = "0.24"; #include <linux/init.h> #include <linux/vmalloc.h> #include <linux/slab.h> +#include <linux/smp_lock.h> #include <linux/pagemap.h> #include <linux/usb.h> #include "se401.h" diff --git a/drivers/media/video/stk-webcam.c b/drivers/media/video/stk-webcam.c index 2e593704727..4d6785e6345 100644 --- a/drivers/media/video/stk-webcam.c +++ b/drivers/media/video/stk-webcam.c @@ -27,6 +27,7 @@ #include <linux/kernel.h> #include <linux/errno.h> #include <linux/slab.h> +#include <linux/smp_lock.h> #include <linux/usb.h> #include <linux/mm.h> diff --git a/drivers/media/video/stradis.c b/drivers/media/video/stradis.c index 0eb313082c9..eaada39c76f 100644 --- a/drivers/media/video/stradis.c +++ b/drivers/media/video/stradis.c @@ -26,6 +26,7 @@ #include <linux/kernel.h> #include <linux/major.h> #include <linux/slab.h> +#include <linux/smp_lock.h> #include <linux/mm.h> #include <linux/init.h> #include <linux/poll.h> diff --git a/drivers/media/video/stv680.c b/drivers/media/video/stv680.c index 75f286f7a2e..8b4e7dafce7 100644 --- a/drivers/media/video/stv680.c +++ b/drivers/media/video/stv680.c @@ -62,6 +62,7 @@ #include <linux/init.h> #include <linux/vmalloc.h> #include <linux/slab.h> +#include <linux/smp_lock.h> #include <linux/pagemap.h> #include <linux/errno.h> #include <linux/videodev.h> diff --git a/drivers/media/video/usbvideo/vicam.c b/drivers/media/video/usbvideo/vicam.c index 8d73979596f..45fce39ec9a 100644 --- a/drivers/media/video/usbvideo/vicam.c +++ b/drivers/media/video/usbvideo/vicam.c @@ -43,6 +43,7 @@ #include <linux/vmalloc.h> #include <linux/mm.h> #include <linux/slab.h> +#include <linux/smp_lock.h> #include <linux/mutex.h> #include <linux/firmware.h> #include <linux/ihex.h> diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c index 90b58914f98..90d9b5c0e9a 100644 --- a/drivers/media/video/usbvision/usbvision-video.c +++ b/drivers/media/video/usbvision/usbvision-video.c @@ -50,6 +50,7 @@ #include <linux/list.h> #include <linux/timer.h> #include <linux/slab.h> +#include <linux/smp_lock.h> #include <linux/mm.h> #include <linux/utsname.h> #include <linux/highmem.h> diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c index 31eac66411d..a7f1b69a7da 100644 --- a/drivers/media/video/v4l2-dev.c +++ b/drivers/media/video/v4l2-dev.c @@ -25,7 +25,6 @@ #include <linux/init.h> #include <linux/kmod.h> #include <linux/slab.h> -#include <linux/smp_lock.h> #include <asm/uaccess.h> #include <asm/system.h> diff --git a/drivers/media/video/zoran/zoran_driver.c b/drivers/media/video/zoran/zoran_driver.c index 3d7df32a3d8..bcdefb1bcb3 100644 --- a/drivers/media/video/zoran/zoran_driver.c +++ b/drivers/media/video/zoran/zoran_driver.c @@ -49,6 +49,7 @@ #include <linux/module.h> #include <linux/delay.h> #include <linux/slab.h> +#include <linux/smp_lock.h> #include <linux/pci.h> #include <linux/vmalloc.h> #include <linux/wait.h> diff --git a/drivers/misc/sgi-gru/grufile.c b/drivers/misc/sgi-gru/grufile.c index fa2d93a9fb8..aed609832bc 100644 --- a/drivers/misc/sgi-gru/grufile.c +++ b/drivers/misc/sgi-gru/grufile.c @@ -29,7 +29,6 @@ #include <linux/slab.h> #include <linux/mm.h> #include <linux/io.h> -#include <linux/smp_lock.h> #include <linux/spinlock.h> #include <linux/device.h> #include <linux/miscdevice.h> diff --git a/drivers/misc/sgi-gru/grukservices.c b/drivers/misc/sgi-gru/grukservices.c index eedbf9c3276..79689b10f93 100644 --- a/drivers/misc/sgi-gru/grukservices.c +++ b/drivers/misc/sgi-gru/grukservices.c @@ -24,7 +24,6 @@ #include <linux/errno.h> #include <linux/slab.h> #include <linux/mm.h> -#include <linux/smp_lock.h> #include <linux/spinlock.h> #include <linux/device.h> #include <linux/miscdevice.h> diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 286ed594e5a..e1f7d0a78b9 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -657,6 +657,11 @@ static int io_init(struct ubi_device *ubi) if (ubi->mtd->block_isbad && ubi->mtd->block_markbad) ubi->bad_allowed = 1; + if (ubi->mtd->type == MTD_NORFLASH) { + ubi_assert(ubi->mtd->writesize == 1); + ubi->nor_flash = 1; + } + ubi->min_io_size = ubi->mtd->writesize; ubi->hdrs_min_io_size = ubi->mtd->writesize >> ubi->mtd->subpage_sft; @@ -996,6 +1001,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset) ubi_msg("number of PEBs reserved for bad PEB handling: %d", ubi->beb_rsvd_pebs); ubi_msg("max/mean erase counter: %d/%d", ubi->max_ec, ubi->mean_ec); + ubi_msg("image sequence number: %d", ubi->image_seq); /* * The below lock makes sure we do not race with 'ubi_thread()' which diff --git a/drivers/mtd/ubi/debug.c b/drivers/mtd/ubi/debug.c index c0ed60e8ade..54b0186915f 100644 --- a/drivers/mtd/ubi/debug.c +++ b/drivers/mtd/ubi/debug.c @@ -44,6 +44,8 @@ void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr) be32_to_cpu(ec_hdr->vid_hdr_offset)); printk(KERN_DEBUG "\tdata_offset %d\n", be32_to_cpu(ec_hdr->data_offset)); + printk(KERN_DEBUG "\timage_seq %d\n", + be32_to_cpu(ec_hdr->image_seq)); printk(KERN_DEBUG "\thdr_crc %#08x\n", be32_to_cpu(ec_hdr->hdr_crc)); printk(KERN_DEBUG "erase counter header hexdump:\n"); diff --git a/drivers/mtd/ubi/debug.h b/drivers/mtd/ubi/debug.h index 13777e5beac..a4da7a09b94 100644 --- a/drivers/mtd/ubi/debug.h +++ b/drivers/mtd/ubi/debug.h @@ -93,6 +93,12 @@ void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req); #define UBI_IO_DEBUG 0 #endif +#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID +int ubi_dbg_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len); +#else +#define ubi_dbg_check_all_ff(ubi, pnum, offset, len) 0 +#endif + #ifdef CONFIG_MTD_UBI_DEBUG_DISABLE_BGT #define DBG_DISABLE_BGT 1 #else @@ -167,6 +173,7 @@ static inline int ubi_dbg_is_erase_failure(void) #define ubi_dbg_is_bitflip() 0 #define ubi_dbg_is_write_failure() 0 #define ubi_dbg_is_erase_failure() 0 +#define ubi_dbg_check_all_ff(ubi, pnum, offset, len) 0 #endif /* !CONFIG_MTD_UBI_DEBUG */ #endif /* !__UBI_DEBUG_H__ */ diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c index effaff28bab..4cb69925d8d 100644 --- a/drivers/mtd/ubi/io.c +++ b/drivers/mtd/ubi/io.c @@ -98,17 +98,12 @@ static int paranoid_check_ec_hdr(const struct ubi_device *ubi, int pnum, static int paranoid_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum); static int paranoid_check_vid_hdr(const struct ubi_device *ubi, int pnum, const struct ubi_vid_hdr *vid_hdr); -static int paranoid_check_all_ff(struct ubi_device *ubi, int pnum, int offset, - int len); -static int paranoid_check_empty(struct ubi_device *ubi, int pnum); #else #define paranoid_check_not_bad(ubi, pnum) 0 #define paranoid_check_peb_ec_hdr(ubi, pnum) 0 #define paranoid_check_ec_hdr(ubi, pnum, ec_hdr) 0 #define paranoid_check_peb_vid_hdr(ubi, pnum) 0 #define paranoid_check_vid_hdr(ubi, pnum, vid_hdr) 0 -#define paranoid_check_all_ff(ubi, pnum, offset, len) 0 -#define paranoid_check_empty(ubi, pnum) 0 #endif /** @@ -244,7 +239,7 @@ int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset, return err > 0 ? -EINVAL : err; /* The area we are writing to has to contain all 0xFF bytes */ - err = paranoid_check_all_ff(ubi, pnum, offset, len); + err = ubi_dbg_check_all_ff(ubi, pnum, offset, len); if (err) return err > 0 ? -EINVAL : err; @@ -271,8 +266,8 @@ int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset, addr = (loff_t)pnum * ubi->peb_size + offset; err = ubi->mtd->write(ubi->mtd, addr, len, &written, buf); if (err) { - ubi_err("error %d while writing %d bytes to PEB %d:%d, written" - " %zd bytes", err, len, pnum, offset, written); + ubi_err("error %d while writing %d bytes to PEB %d:%d, written " + "%zd bytes", err, len, pnum, offset, written); ubi_dbg_dump_stack(); } else ubi_assert(written == len); @@ -350,7 +345,7 @@ retry: return -EIO; } - err = paranoid_check_all_ff(ubi, pnum, 0, ubi->peb_size); + err = ubi_dbg_check_all_ff(ubi, pnum, 0, ubi->peb_size); if (err) return err > 0 ? -EINVAL : err; @@ -459,6 +454,54 @@ out: } /** + * nor_erase_prepare - prepare a NOR flash PEB for erasure. + * @ubi: UBI device description object + * @pnum: physical eraseblock number to prepare + * + * NOR flash, or at least some of them, have peculiar embedded PEB erasure + * algorithm: the PEB is first filled with zeroes, then it is erased. And + * filling with zeroes starts from the end of the PEB. This was observed with + * Spansion S29GL512N NOR flash. + * + * This means that in case of a power cut we may end up with intact data at the + * beginning of the PEB, and all zeroes at the end of PEB. In other words, the + * EC and VID headers are OK, but a large chunk of data at the end of PEB is + * zeroed. This makes UBI mistakenly treat this PEB as used and associate it + * with an LEB, which leads to subsequent failures (e.g., UBIFS fails). + * + * This function is called before erasing NOR PEBs and it zeroes out EC and VID + * magic numbers in order to invalidate them and prevent the failures. Returns + * zero in case of success and a negative error code in case of failure. + */ +static int nor_erase_prepare(struct ubi_device *ubi, int pnum) +{ + int err; + size_t written; + loff_t addr; + uint32_t data = 0; + + addr = (loff_t)pnum * ubi->peb_size; + err = ubi->mtd->write(ubi->mtd, addr, 4, &written, (void *)&data); + if (err) { + ubi_err("error %d while writing 4 bytes to PEB %d:%d, written " + "%zd bytes", err, pnum, 0, written); + ubi_dbg_dump_stack(); + return err; + } + + addr += ubi->vid_hdr_aloffset; + err = ubi->mtd->write(ubi->mtd, addr, 4, &written, (void *)&data); + if (err) { + ubi_err("error %d while writing 4 bytes to PEB %d:%d, written " + "%zd bytes", err, pnum, ubi->vid_hdr_aloffset, written); + ubi_dbg_dump_stack(); + return err; + } + + return 0; +} + +/** * ubi_io_sync_erase - synchronously erase a physical eraseblock. * @ubi: UBI device description object * @pnum: physical eraseblock number to erase @@ -489,6 +532,12 @@ int ubi_io_sync_erase(struct ubi_device *ubi, int pnum, int torture) return -EROFS; } + if (ubi->nor_flash) { + err = nor_erase_prepare(ubi, pnum); + if (err) + return err; + } + if (torture) { ret = torture_peb(ubi, pnum); if (ret < 0) @@ -672,11 +721,6 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum, if (read_err != -EBADMSG && check_pattern(ec_hdr, 0xFF, UBI_EC_HDR_SIZE)) { /* The physical eraseblock is supposedly empty */ - err = paranoid_check_all_ff(ubi, pnum, 0, - ubi->peb_size); - if (err) - return err > 0 ? UBI_IO_BAD_EC_HDR : err; - if (verbose) ubi_warn("no EC header found at PEB %d, " "only 0xFF bytes", pnum); @@ -752,6 +796,7 @@ int ubi_io_write_ec_hdr(struct ubi_device *ubi, int pnum, ec_hdr->version = UBI_VERSION; ec_hdr->vid_hdr_offset = cpu_to_be32(ubi->vid_hdr_offset); ec_hdr->data_offset = cpu_to_be32(ubi->leb_start); + ec_hdr->image_seq = cpu_to_be32(ubi->image_seq); crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC); ec_hdr->hdr_crc = cpu_to_be32(crc); @@ -947,15 +992,6 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum, if (read_err != -EBADMSG && check_pattern(vid_hdr, 0xFF, UBI_VID_HDR_SIZE)) { /* The physical eraseblock is supposedly free */ - - /* - * The below is just a paranoid check, it has to be - * compiled out if paranoid checks are disabled. - */ - err = paranoid_check_empty(ubi, pnum); - if (err) - return err > 0 ? UBI_IO_BAD_VID_HDR : err; - if (verbose) ubi_warn("no VID header found at PEB %d, " "only 0xFF bytes", pnum); @@ -1229,7 +1265,7 @@ exit: } /** - * paranoid_check_all_ff - check that a region of flash is empty. + * ubi_dbg_check_all_ff - check that a region of flash is empty. * @ubi: UBI device description object * @pnum: the physical eraseblock number to check * @offset: the starting offset within the physical eraseblock to check @@ -1239,8 +1275,7 @@ exit: * @offset of the physical eraseblock @pnum, %1 if not, and a negative error * code if an error occurred. */ -static int paranoid_check_all_ff(struct ubi_device *ubi, int pnum, int offset, - int len) +int ubi_dbg_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len) { size_t read; int err; @@ -1276,74 +1311,4 @@ error: return err; } -/** - * paranoid_check_empty - whether a PEB is empty. - * @ubi: UBI device description object - * @pnum: the physical eraseblock number to check - * - * This function makes sure PEB @pnum is empty, which means it contains only - * %0xFF data bytes. Returns zero if the PEB is empty, %1 if not, and a - * negative error code in case of failure. - * - * Empty PEBs have the EC header, and do not have the VID header. The caller of - * this function should have already made sure the PEB does not have the VID - * header. However, this function re-checks that, because it is possible that - * the header and data has already been written to the PEB. - * - * Let's consider a possible scenario. Suppose there are 2 tasks - A and B. - * Task A is in 'wear_leveling_worker()'. It is reading VID header of PEB X to - * find which LEB it corresponds to. PEB X is currently unmapped, and has no - * VID header. Task B is trying to write to PEB X. - * - * Task A: in 'ubi_io_read_vid_hdr()': reads the VID header from PEB X. The - * read data contain all 0xFF bytes; - * Task B: writes VID header and some data to PEB X; - * Task A: assumes PEB X is empty, calls 'paranoid_check_empty()'. And if we - * do not re-read the VID header, and do not cancel the checking if it - * is there, we fail. - */ -static int paranoid_check_empty(struct ubi_device *ubi, int pnum) -{ - int err, offs = ubi->vid_hdr_aloffset, len = ubi->vid_hdr_alsize; - size_t read; - uint32_t magic; - const struct ubi_vid_hdr *vid_hdr; - - mutex_lock(&ubi->dbg_buf_mutex); - err = ubi->mtd->read(ubi->mtd, offs, len, &read, ubi->dbg_peb_buf); - if (err && err != -EUCLEAN) { - ubi_err("error %d while reading %d bytes from PEB %d:%d, " - "read %zd bytes", err, len, pnum, offs, read); - goto error; - } - - vid_hdr = ubi->dbg_peb_buf; - magic = be32_to_cpu(vid_hdr->magic); - if (magic == UBI_VID_HDR_MAGIC) - /* The PEB contains VID header, so it is not empty */ - goto out; - - err = check_pattern(ubi->dbg_peb_buf, 0xFF, len); - if (err == 0) { - ubi_err("flash region at PEB %d:%d, length %d does not " - "contain all 0xFF bytes", pnum, offs, len); - goto fail; - } - -out: - mutex_unlock(&ubi->dbg_buf_mutex); - return 0; - -fail: - ubi_err("paranoid check failed for PEB %d", pnum); - ubi_msg("hex dump of the %d-%d region", offs, offs + len); - print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, - ubi->dbg_peb_buf, len, 1); - err = 1; -error: - ubi_dbg_dump_stack(); - mutex_unlock(&ubi->dbg_buf_mutex); - return err; -} - #endif /* CONFIG_MTD_UBI_DEBUG_PARANOID */ diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c index c3d653ba5ca..f60895ee0ae 100644 --- a/drivers/mtd/ubi/scan.c +++ b/drivers/mtd/ubi/scan.c @@ -757,6 +757,8 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, si->is_empty = 0; if (!ec_corr) { + int image_seq; + /* Make sure UBI version is OK */ if (ech->version != UBI_VERSION) { ubi_err("this UBI version is %d, image version is %d", @@ -778,6 +780,18 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, ubi_dbg_dump_ec_hdr(ech); return -EINVAL; } + + image_seq = be32_to_cpu(ech->ec); + if (!si->image_seq_set) { + ubi->image_seq = image_seq; + si->image_seq_set = 1; + } else if (ubi->image_seq != image_seq) { + ubi_err("bad image sequence number %d in PEB %d, " + "expected %d", image_seq, pnum, ubi->image_seq); + ubi_dbg_dump_ec_hdr(ech); + return -EINVAL; + } + } /* OK, we've done with the EC header, let's look at the VID header */ diff --git a/drivers/mtd/ubi/scan.h b/drivers/mtd/ubi/scan.h index 61df208e2f2..1017cf12def 100644 --- a/drivers/mtd/ubi/scan.h +++ b/drivers/mtd/ubi/scan.h @@ -102,6 +102,7 @@ struct ubi_scan_volume { * @mean_ec: mean erase counter value * @ec_sum: a temporary variable used when calculating @mean_ec * @ec_count: a temporary variable used when calculating @mean_ec + * @image_seq_set: indicates @ubi->image_seq is known * * This data structure contains the result of scanning and may be used by other * UBI sub-systems to build final UBI data structures, further error-recovery @@ -124,6 +125,7 @@ struct ubi_scan_info { int mean_ec; uint64_t ec_sum; int ec_count; + int image_seq_set; }; struct ubi_device; diff --git a/drivers/mtd/ubi/ubi-media.h b/drivers/mtd/ubi/ubi-media.h index 8419fdccc79..503ea9b2730 100644 --- a/drivers/mtd/ubi/ubi-media.h +++ b/drivers/mtd/ubi/ubi-media.h @@ -129,6 +129,7 @@ enum { * @ec: the erase counter * @vid_hdr_offset: where the VID header starts * @data_offset: where the user data start + * @image_seq: image sequence number * @padding2: reserved for future, zeroes * @hdr_crc: erase counter header CRC checksum * @@ -144,6 +145,14 @@ enum { * volume identifier header and user data, relative to the beginning of the * physical eraseblock. These values have to be the same for all physical * eraseblocks. + * + * The @image_seq field is used to validate a UBI image that has been prepared + * for a UBI device. The @image_seq value can be any value, but it must be the + * same on all eraseblocks. UBI will ensure that all new erase counter headers + * also contain this value, and will check the value when scanning at start-up. + * One way to make use of @image_seq is to increase its value by one every time + * an image is flashed over an existing image, then, if the flashing does not + * complete, UBI will detect the error when scanning. */ struct ubi_ec_hdr { __be32 magic; @@ -152,7 +161,8 @@ struct ubi_ec_hdr { __be64 ec; /* Warning: the current limit is 31-bit anyway! */ __be32 vid_hdr_offset; __be32 data_offset; - __u8 padding2[36]; + __be32 image_seq; + __u8 padding2[32]; __be32 hdr_crc; } __attribute__ ((packed)); diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h index 28acd133c99..6a5fe963378 100644 --- a/drivers/mtd/ubi/ubi.h +++ b/drivers/mtd/ubi/ubi.h @@ -301,6 +301,7 @@ struct ubi_wl_entry; * @vol->readers, @vol->writers, @vol->exclusive, * @vol->ref_count, @vol->mapping and @vol->eba_tbl. * @ref_count: count of references on the UBI device + * @image_seq: image sequence number recorded on EC headers * * @rsvd_pebs: count of reserved physical eraseblocks * @avail_pebs: count of available physical eraseblocks @@ -372,6 +373,7 @@ struct ubi_wl_entry; * @vid_hdr_shift: contains @vid_hdr_offset - @vid_hdr_aloffset * @bad_allowed: whether the MTD device admits of bad physical eraseblocks or * not + * @nor_flash: non-zero if working on top of NOR flash * @mtd: MTD device descriptor * * @peb_buf1: a buffer of PEB size used for different purposes @@ -390,6 +392,7 @@ struct ubi_device { struct ubi_volume *volumes[UBI_MAX_VOLUMES+UBI_INT_VOL_COUNT]; spinlock_t volumes_lock; int ref_count; + int image_seq; int rsvd_pebs; int avail_pebs; @@ -452,7 +455,8 @@ struct ubi_device { int vid_hdr_offset; int vid_hdr_aloffset; int vid_hdr_shift; - int bad_allowed; + unsigned int bad_allowed:1; + unsigned int nor_flash:1; struct mtd_info *mtd; void *peb_buf1; diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index 2b247230061..600c7229d5c 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c @@ -459,6 +459,14 @@ retry: dbg_wl("PEB %d EC %d", e->pnum, e->ec); prot_queue_add(ubi, e); spin_unlock(&ubi->wl_lock); + + err = ubi_dbg_check_all_ff(ubi, e->pnum, ubi->vid_hdr_aloffset, + ubi->peb_size - ubi->vid_hdr_aloffset); + if (err) { + ubi_err("new PEB %d does not contain all 0xFF bytes", e->pnum); + return err > 0 ? -EINVAL : err; + } + return e->pnum; } diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index 8ae72ec1445..0e2ba21d444 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -908,6 +908,7 @@ static const struct net_device_ops rtl8139_netdev_ops = { .ndo_open = rtl8139_open, .ndo_stop = rtl8139_close, .ndo_get_stats = rtl8139_get_stats, + .ndo_change_mtu = eth_change_mtu, .ndo_validate_addr = eth_validate_addr, .ndo_set_mac_address = rtl8139_set_mac_address, .ndo_start_xmit = rtl8139_start_xmit, diff --git a/drivers/net/arm/ixp4xx_eth.c b/drivers/net/arm/ixp4xx_eth.c index 6f42ad72891..3fe09876e76 100644 --- a/drivers/net/arm/ixp4xx_eth.c +++ b/drivers/net/arm/ixp4xx_eth.c @@ -1142,7 +1142,9 @@ static const struct net_device_ops ixp4xx_netdev_ops = { .ndo_start_xmit = eth_xmit, .ndo_set_multicast_list = eth_set_mcast_list, .ndo_do_ioctl = eth_ioctl, - + .ndo_change_mtu = eth_change_mtu, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, }; static int __devinit eth_init_one(struct platform_device *pdev) diff --git a/drivers/net/atlx/atl2.c b/drivers/net/atlx/atl2.c index c734b1983ec..204db961029 100644 --- a/drivers/net/atlx/atl2.c +++ b/drivers/net/atlx/atl2.c @@ -2071,7 +2071,7 @@ static int atl2_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) if (wol->wolopts & (WAKE_ARP | WAKE_MAGICSECURE)) return -EOPNOTSUPP; - if (wol->wolopts & (WAKE_MCAST|WAKE_BCAST|WAKE_MCAST)) + if (wol->wolopts & (WAKE_UCAST | WAKE_BCAST | WAKE_MCAST)) return -EOPNOTSUPP; /* these settings will always override what we currently have */ diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c index 3eee666a9cd..55445f980f9 100644 --- a/drivers/net/cs89x0.c +++ b/drivers/net/cs89x0.c @@ -1524,6 +1524,7 @@ static void net_timeout(struct net_device *dev) static int net_send_packet(struct sk_buff *skb, struct net_device *dev) { struct net_local *lp = netdev_priv(dev); + unsigned long flags; if (net_debug > 3) { printk("%s: sent %d byte packet of type %x\n", @@ -1535,7 +1536,7 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev) ask the chip to start transmitting before the whole packet has been completely uploaded. */ - spin_lock_irq(&lp->lock); + spin_lock_irqsave(&lp->lock, flags); netif_stop_queue(dev); /* initiate a transmit sequence */ @@ -1549,13 +1550,13 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev) * we're waiting for TxOk, so return 1 and requeue this packet. */ - spin_unlock_irq(&lp->lock); + spin_unlock_irqrestore(&lp->lock, flags); if (net_debug) printk("cs89x0: Tx buffer not free!\n"); return NETDEV_TX_BUSY; } /* Write the contents of the packet */ writewords(dev->base_addr, TX_FRAME_PORT,skb->data,(skb->len+1) >>1); - spin_unlock_irq(&lp->lock); + spin_unlock_irqrestore(&lp->lock, flags); lp->stats.tx_bytes += skb->len; dev->trans_start = jiffies; dev_kfree_skb (skb); diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index 147c4b088fb..e8d46cc1bec 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -3080,7 +3080,9 @@ static const struct net_device_ops ehea_netdev_ops = { .ndo_poll_controller = ehea_netpoll, #endif .ndo_get_stats = ehea_get_stats, + .ndo_change_mtu = eth_change_mtu, .ndo_set_mac_address = ehea_set_mac_addr, + .ndo_validate_addr = eth_validate_addr, .ndo_set_multicast_list = ehea_set_multicast_list, .ndo_change_mtu = ehea_change_mtu, .ndo_vlan_rx_register = ehea_vlan_rx_register, diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 0f19b743749..d4b98074b1b 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -1642,6 +1642,7 @@ static const struct net_device_ops fec_netdev_ops = { .ndo_stop = fec_enet_close, .ndo_start_xmit = fec_enet_start_xmit, .ndo_set_multicast_list = set_multicast_list, + .ndo_change_mtu = eth_change_mtu, .ndo_validate_addr = eth_validate_addr, .ndo_tx_timeout = fec_timeout, .ndo_set_mac_address = fec_set_mac_address, diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 4ae1d259fce..43d813ed9f4 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -156,6 +156,8 @@ static const struct net_device_ops gfar_netdev_ops = { .ndo_tx_timeout = gfar_timeout, .ndo_do_ioctl = gfar_ioctl, .ndo_vlan_rx_register = gfar_vlan_rx_register, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = gfar_netpoll, #endif diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index be480292aba..adb09d32625 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -127,14 +127,48 @@ static void igb_restore_vlan(struct igb_adapter *); static void igb_ping_all_vfs(struct igb_adapter *); static void igb_msg_task(struct igb_adapter *); static int igb_rcv_msg_from_vf(struct igb_adapter *, u32); -static inline void igb_set_rah_pool(struct e1000_hw *, int , int); static void igb_set_mc_list_pools(struct igb_adapter *, int, u16); static void igb_vmm_control(struct igb_adapter *); -static inline void igb_set_vmolr(struct e1000_hw *, int); -static inline int igb_set_vf_rlpml(struct igb_adapter *, int, int); static int igb_set_vf_mac(struct igb_adapter *adapter, int, unsigned char *); static void igb_restore_vf_multicasts(struct igb_adapter *adapter); +static inline void igb_set_vmolr(struct e1000_hw *hw, int vfn) +{ + u32 reg_data; + + reg_data = rd32(E1000_VMOLR(vfn)); + reg_data |= E1000_VMOLR_BAM | /* Accept broadcast */ + E1000_VMOLR_ROPE | /* Accept packets matched in UTA */ + E1000_VMOLR_ROMPE | /* Accept packets matched in MTA */ + E1000_VMOLR_AUPE | /* Accept untagged packets */ + E1000_VMOLR_STRVLAN; /* Strip vlan tags */ + wr32(E1000_VMOLR(vfn), reg_data); +} + +static inline int igb_set_vf_rlpml(struct igb_adapter *adapter, int size, + int vfn) +{ + struct e1000_hw *hw = &adapter->hw; + u32 vmolr; + + vmolr = rd32(E1000_VMOLR(vfn)); + vmolr &= ~E1000_VMOLR_RLPML_MASK; + vmolr |= size | E1000_VMOLR_LPE; + wr32(E1000_VMOLR(vfn), vmolr); + + return 0; +} + +static inline void igb_set_rah_pool(struct e1000_hw *hw, int pool, int entry) +{ + u32 reg_data; + + reg_data = rd32(E1000_RAH(entry)); + reg_data &= ~E1000_RAH_POOL_MASK; + reg_data |= E1000_RAH_POOL_1 << pool;; + wr32(E1000_RAH(entry), reg_data); +} + #ifdef CONFIG_PM static int igb_suspend(struct pci_dev *, pm_message_t); static int igb_resume(struct pci_dev *); @@ -5418,43 +5452,6 @@ static void igb_io_resume(struct pci_dev *pdev) igb_get_hw_control(adapter); } -static inline void igb_set_vmolr(struct e1000_hw *hw, int vfn) -{ - u32 reg_data; - - reg_data = rd32(E1000_VMOLR(vfn)); - reg_data |= E1000_VMOLR_BAM | /* Accept broadcast */ - E1000_VMOLR_ROPE | /* Accept packets matched in UTA */ - E1000_VMOLR_ROMPE | /* Accept packets matched in MTA */ - E1000_VMOLR_AUPE | /* Accept untagged packets */ - E1000_VMOLR_STRVLAN; /* Strip vlan tags */ - wr32(E1000_VMOLR(vfn), reg_data); -} - -static inline int igb_set_vf_rlpml(struct igb_adapter *adapter, int size, - int vfn) -{ - struct e1000_hw *hw = &adapter->hw; - u32 vmolr; - - vmolr = rd32(E1000_VMOLR(vfn)); - vmolr &= ~E1000_VMOLR_RLPML_MASK; - vmolr |= size | E1000_VMOLR_LPE; - wr32(E1000_VMOLR(vfn), vmolr); - - return 0; -} - -static inline void igb_set_rah_pool(struct e1000_hw *hw, int pool, int entry) -{ - u32 reg_data; - - reg_data = rd32(E1000_RAH(entry)); - reg_data &= ~E1000_RAH_POOL_MASK; - reg_data |= E1000_RAH_POOL_1 << pool;; - wr32(E1000_RAH(entry), reg_data); -} - static void igb_set_mc_list_pools(struct igb_adapter *adapter, int entry_count, u16 total_rar_filters) { diff --git a/drivers/net/irda/irtty-sir.c b/drivers/net/irda/irtty-sir.c index d53aa958213..20f9bc62668 100644 --- a/drivers/net/irda/irtty-sir.c +++ b/drivers/net/irda/irtty-sir.c @@ -31,7 +31,6 @@ #include <linux/tty.h> #include <linux/init.h> #include <asm/uaccess.h> -#include <linux/smp_lock.h> #include <linux/delay.h> #include <linux/mutex.h> diff --git a/drivers/net/isa-skeleton.c b/drivers/net/isa-skeleton.c index 73585fd8f29..d12377b8435 100644 --- a/drivers/net/isa-skeleton.c +++ b/drivers/net/isa-skeleton.c @@ -430,7 +430,8 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev) * hardware interrupt handler. Queue flow control is * thus managed under this lock as well. */ - spin_lock_irq(&np->lock); + unsigned long flags; + spin_lock_irqsave(&np->lock, flags); add_to_tx_ring(np, skb, length); dev->trans_start = jiffies; @@ -446,7 +447,7 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev) * is when the transmit statistics are updated. */ - spin_unlock_irq(&np->lock); + spin_unlock_irqrestore(&np->lock, flags); #else /* This is the case for older hardware which takes * a single transmit buffer at a time, and it is diff --git a/drivers/net/mlx4/cmd.c b/drivers/net/mlx4/cmd.c index 2845a0560b8..65ec77dc31f 100644 --- a/drivers/net/mlx4/cmd.c +++ b/drivers/net/mlx4/cmd.c @@ -80,7 +80,9 @@ enum { /* Bad management packet (silently discarded): */ CMD_STAT_BAD_PKT = 0x30, /* More outstanding CQEs in CQ than new CQ size: */ - CMD_STAT_BAD_SIZE = 0x40 + CMD_STAT_BAD_SIZE = 0x40, + /* Multi Function device support required: */ + CMD_STAT_MULTI_FUNC_REQ = 0x50, }; enum { @@ -128,6 +130,7 @@ static int mlx4_status_to_errno(u8 status) [CMD_STAT_LAM_NOT_PRE] = -EAGAIN, [CMD_STAT_BAD_PKT] = -EINVAL, [CMD_STAT_BAD_SIZE] = -ENOMEM, + [CMD_STAT_MULTI_FUNC_REQ] = -EACCES, }; if (status >= ARRAY_SIZE(trans_table) || diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c index 018348c0119..dac621b1e9f 100644 --- a/drivers/net/mlx4/main.c +++ b/drivers/net/mlx4/main.c @@ -729,7 +729,10 @@ static int mlx4_init_hca(struct mlx4_dev *dev) err = mlx4_QUERY_FW(dev); if (err) { - mlx4_err(dev, "QUERY_FW command failed, aborting.\n"); + if (err == -EACCES) + mlx4_info(dev, "non-primary physical function, skipping.\n"); + else + mlx4_err(dev, "QUERY_FW command failed, aborting.\n"); return err; } @@ -1285,6 +1288,7 @@ static struct pci_device_id mlx4_pci_table[] = { { PCI_VDEVICE(MELLANOX, 0x6750) }, /* MT25408 "Hermon" EN 10GigE PCIe gen2 */ { PCI_VDEVICE(MELLANOX, 0x6372) }, /* MT25458 ConnectX EN 10GBASE-T 10GigE */ { PCI_VDEVICE(MELLANOX, 0x675a) }, /* MT25458 ConnectX EN 10GBASE-T+Gen2 10GigE */ + { PCI_VDEVICE(MELLANOX, 0x6764) }, /* MT26468 ConnectX EN 10GigE PCIe gen2*/ { 0, } }; diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index eba937c4637..b10fedd8214 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -134,8 +134,10 @@ int phy_scan_fixups(struct phy_device *phydev) err = fixup->run(phydev); - if (err < 0) + if (err < 0) { + mutex_unlock(&phy_fixup_lock); return err; + } } } mutex_unlock(&phy_fixup_lock); diff --git a/drivers/net/plip.c b/drivers/net/plip.c index 7a62f781fef..2ca8b0d84ee 100644 --- a/drivers/net/plip.c +++ b/drivers/net/plip.c @@ -270,6 +270,9 @@ static const struct net_device_ops plip_netdev_ops = { .ndo_stop = plip_close, .ndo_start_xmit = plip_tx_packet, .ndo_do_ioctl = plip_ioctl, + .ndo_change_mtu = eth_change_mtu, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, }; /* Entry point of PLIP driver. diff --git a/drivers/net/ps3_gelic_net.c b/drivers/net/ps3_gelic_net.c index d1a5fb4d6ac..a3932c9f340 100644 --- a/drivers/net/ps3_gelic_net.c +++ b/drivers/net/ps3_gelic_net.c @@ -1411,6 +1411,7 @@ static const struct net_device_ops gelic_netdevice_ops = { .ndo_set_multicast_list = gelic_net_set_multi, .ndo_change_mtu = gelic_net_change_mtu, .ndo_tx_timeout = gelic_net_tx_timeout, + .ndo_set_mac_address = eth_mac_addr, .ndo_validate_addr = eth_validate_addr, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = gelic_net_poll_controller, diff --git a/drivers/net/ps3_gelic_wireless.c b/drivers/net/ps3_gelic_wireless.c index b6b3ca9bdb2..6932b08d746 100644 --- a/drivers/net/ps3_gelic_wireless.c +++ b/drivers/net/ps3_gelic_wireless.c @@ -2707,6 +2707,7 @@ static const struct net_device_ops gelic_wl_netdevice_ops = { .ndo_set_multicast_list = gelic_net_set_multi, .ndo_change_mtu = gelic_net_change_mtu, .ndo_tx_timeout = gelic_net_tx_timeout, + .ndo_set_mac_address = eth_mac_addr, .ndo_validate_addr = eth_validate_addr, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = gelic_net_poll_controller, diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c index fdcbaf8dfa7..1c70e999cc5 100644 --- a/drivers/net/smc91x.c +++ b/drivers/net/smc91x.c @@ -1774,6 +1774,7 @@ static const struct net_device_ops smc_netdev_ops = { .ndo_start_xmit = smc_hard_start_xmit, .ndo_tx_timeout = smc_timeout, .ndo_set_multicast_list = smc_set_multicast_list, + .ndo_change_mtu = eth_change_mtu, .ndo_validate_addr = eth_validate_addr, .ndo_set_mac_address = eth_mac_addr, #ifdef CONFIG_NET_POLL_CONTROLLER diff --git a/drivers/net/smsc911x.c b/drivers/net/smsc911x.c index 66067f9d91c..94b6d2658dd 100644 --- a/drivers/net/smsc911x.c +++ b/drivers/net/smsc911x.c @@ -1779,6 +1779,7 @@ static const struct net_device_ops smsc911x_netdev_ops = { .ndo_get_stats = smsc911x_get_stats, .ndo_set_multicast_list = smsc911x_set_multicast_list, .ndo_do_ioctl = smsc911x_do_ioctl, + .ndo_change_mtu = eth_change_mtu, .ndo_validate_addr = eth_validate_addr, .ndo_set_mac_address = smsc911x_set_mac_address, #ifdef CONFIG_NET_POLL_CONTROLLER diff --git a/drivers/net/sunvnet.c b/drivers/net/sunvnet.c index a82fb2aca4c..f1e5e4542c2 100644 --- a/drivers/net/sunvnet.c +++ b/drivers/net/sunvnet.c @@ -1016,7 +1016,9 @@ static const struct net_device_ops vnet_ops = { .ndo_open = vnet_open, .ndo_stop = vnet_close, .ndo_set_multicast_list = vnet_set_rx_mode, + .ndo_change_mtu = eth_change_mtu, .ndo_set_mac_address = vnet_set_mac_addr, + .ndo_validate_addr = eth_validate_addr, .ndo_tx_timeout = vnet_tx_timeout, .ndo_change_mtu = vnet_change_mtu, .ndo_start_xmit = vnet_start_xmit, diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c index e0131478971..1f9ec29fce5 100644 --- a/drivers/net/usb/kaweth.c +++ b/drivers/net/usb/kaweth.c @@ -999,6 +999,9 @@ static const struct net_device_ops kaweth_netdev_ops = { .ndo_tx_timeout = kaweth_tx_timeout, .ndo_set_multicast_list = kaweth_set_rx_mode, .ndo_get_stats = kaweth_netdev_stats, + .ndo_change_mtu = eth_change_mtu, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, }; static int kaweth_probe( diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c index 73acbd244aa..631d269ac98 100644 --- a/drivers/net/usb/pegasus.c +++ b/drivers/net/usb/pegasus.c @@ -1493,6 +1493,9 @@ static const struct net_device_ops pegasus_netdev_ops = { .ndo_set_multicast_list = pegasus_set_multicast, .ndo_get_stats = pegasus_netdev_stats, .ndo_tx_timeout = pegasus_tx_timeout, + .ndo_change_mtu = eth_change_mtu, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, }; static struct usb_driver pegasus_driver = { diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index d3489a3c4c0..88c30a58b4b 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -621,6 +621,7 @@ static const struct net_device_ops rhine_netdev_ops = { .ndo_start_xmit = rhine_start_tx, .ndo_get_stats = rhine_get_stats, .ndo_set_multicast_list = rhine_set_rx_mode, + .ndo_change_mtu = eth_change_mtu, .ndo_validate_addr = eth_validate_addr, .ndo_set_mac_address = eth_mac_addr, .ndo_do_ioctl = netdev_ioctl, diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c index 345593c4acc..a370e510f19 100644 --- a/drivers/net/wireless/orinoco/main.c +++ b/drivers/net/wireless/orinoco/main.c @@ -2521,6 +2521,8 @@ static const struct net_device_ops orinoco_netdev_ops = { .ndo_start_xmit = orinoco_xmit, .ndo_set_multicast_list = orinoco_set_multicast_list, .ndo_change_mtu = orinoco_change_mtu, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, .ndo_tx_timeout = orinoco_tx_timeout, .ndo_get_stats = orinoco_get_stats, }; @@ -2555,7 +2557,6 @@ struct net_device priv->wireless_data.spy_data = &priv->spy_data; dev->wireless_data = &priv->wireless_data; #endif - /* we use the default eth_mac_addr for setting the MAC addr */ /* Reserve space in skb for the SNAP header */ dev->hard_header_len += ENCAPS_OVERHEAD; diff --git a/drivers/oprofile/oprofile_stats.c b/drivers/oprofile/oprofile_stats.c index e1f6ce03705..3c2270a8300 100644 --- a/drivers/oprofile/oprofile_stats.c +++ b/drivers/oprofile/oprofile_stats.c @@ -33,6 +33,7 @@ void oprofile_reset_stats(void) atomic_set(&oprofile_stats.sample_lost_no_mm, 0); atomic_set(&oprofile_stats.sample_lost_no_mapping, 0); atomic_set(&oprofile_stats.event_lost_overflow, 0); + atomic_set(&oprofile_stats.bt_lost_no_mapping, 0); } diff --git a/drivers/pci/hotplug/cpci_hotplug_core.c b/drivers/pci/hotplug/cpci_hotplug_core.c index a5b9f6ae507..d703e73fffa 100644 --- a/drivers/pci/hotplug/cpci_hotplug_core.c +++ b/drivers/pci/hotplug/cpci_hotplug_core.c @@ -32,7 +32,6 @@ #include <linux/pci_hotplug.h> #include <linux/init.h> #include <linux/interrupt.h> -#include <linux/smp_lock.h> #include <asm/atomic.h> #include <linux/delay.h> #include <linux/kthread.h> diff --git a/drivers/pci/hotplug/cpqphp_ctrl.c b/drivers/pci/hotplug/cpqphp_ctrl.c index 2fa47af992a..0ff689afa75 100644 --- a/drivers/pci/hotplug/cpqphp_ctrl.c +++ b/drivers/pci/hotplug/cpqphp_ctrl.c @@ -34,7 +34,6 @@ #include <linux/interrupt.h> #include <linux/delay.h> #include <linux/wait.h> -#include <linux/smp_lock.h> #include <linux/pci.h> #include <linux/pci_hotplug.h> #include <linux/kthread.h> diff --git a/drivers/pci/hotplug/cpqphp_sysfs.c b/drivers/pci/hotplug/cpqphp_sysfs.c index 8450f4a6568..e6089bdb6e5 100644 --- a/drivers/pci/hotplug/cpqphp_sysfs.c +++ b/drivers/pci/hotplug/cpqphp_sysfs.c @@ -33,6 +33,7 @@ #include <linux/workqueue.h> #include <linux/pci.h> #include <linux/pci_hotplug.h> +#include <linux/smp_lock.h> #include <linux/debugfs.h> #include "cpqphp.h" diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index ff4034502d2..8aab8edf123 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c @@ -30,7 +30,6 @@ #include <linux/module.h> #include <linux/kernel.h> #include <linux/types.h> -#include <linux/smp_lock.h> #include <linux/pci.h> #include <linux/workqueue.h> #include "../pci.h" diff --git a/drivers/pci/syscall.c b/drivers/pci/syscall.c index ec22284eed3..e1c1ec54089 100644 --- a/drivers/pci/syscall.c +++ b/drivers/pci/syscall.c @@ -9,7 +9,6 @@ #include <linux/errno.h> #include <linux/pci.h> -#include <linux/smp_lock.h> #include <linux/syscalls.h> #include <asm/uaccess.h> #include "pci.h" diff --git a/drivers/power/wm97xx_battery.c b/drivers/power/wm97xx_battery.c index 8bde92126d3..b787335a841 100644 --- a/drivers/power/wm97xx_battery.c +++ b/drivers/power/wm97xx_battery.c @@ -33,14 +33,14 @@ static enum power_supply_property *prop; static unsigned long wm97xx_read_bat(struct power_supply *bat_ps) { - return wm97xx_read_aux_adc(bat_ps->dev->parent->driver_data, + return wm97xx_read_aux_adc(dev_get_drvdata(bat_ps->dev->parent), pdata->batt_aux) * pdata->batt_mult / pdata->batt_div; } static unsigned long wm97xx_read_temp(struct power_supply *bat_ps) { - return wm97xx_read_aux_adc(bat_ps->dev->parent->driver_data, + return wm97xx_read_aux_adc(dev_get_drvdata(bat_ps->dev->parent), pdata->temp_aux) * pdata->temp_mult / pdata->temp_div; } diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index f8b1f04f26b..c11770f5b36 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -1696,8 +1696,7 @@ static void dasd_eckd_handle_unsolicited_interrupt(struct dasd_device *device, DBF_DEV_EVENT(DBF_ERR, device, "%s", "unsolicited interrupt received " "(sense available)"); - device->discipline->dump_sense_dbf(device, NULL, irb, - "unsolicited"); + device->discipline->dump_sense_dbf(device, irb, "unsolicited"); } dasd_schedule_device_bh(device); @@ -2941,42 +2940,20 @@ dasd_eckd_dump_ccw_range(struct ccw1 *from, struct ccw1 *to, char *page) } static void -dasd_eckd_dump_sense_dbf(struct dasd_device *device, struct dasd_ccw_req *req, - struct irb *irb, char *reason) +dasd_eckd_dump_sense_dbf(struct dasd_device *device, struct irb *irb, + char *reason) { u64 *sense; - int sl; - struct tsb *tsb; - sense = NULL; - tsb = NULL; - if (req && scsw_is_tm(&req->irb.scsw)) { - if (irb->scsw.tm.tcw) - tsb = tcw_get_tsb( - (struct tcw *)(unsigned long)irb->scsw.tm.tcw); - if (tsb && (irb->scsw.tm.fcxs == 0x01)) { - switch (tsb->flags & 0x07) { - case 1: /* tsa_iostat */ - sense = (u64 *)tsb->tsa.iostat.sense; - break; - case 2: /* ts_ddpc */ - sense = (u64 *)tsb->tsa.ddpc.sense; - break; - case 3: /* tsa_intrg */ - break; - } - } - } else { - if (irb->esw.esw0.erw.cons) - sense = (u64 *)irb->ecw; - } + sense = (u64 *) dasd_get_sense(irb); if (sense) { - for (sl = 0; sl < 4; sl++) { - DBF_DEV_EVENT(DBF_EMERG, device, - "%s: %016llx %016llx %016llx %016llx", - reason, sense[0], sense[1], sense[2], - sense[3]); - } + DBF_DEV_EVENT(DBF_EMERG, device, + "%s: %s %02x%02x%02x %016llx %016llx %016llx " + "%016llx", reason, + scsw_is_tm(&irb->scsw) ? "t" : "c", + scsw_cc(&irb->scsw), scsw_cstat(&irb->scsw), + scsw_dstat(&irb->scsw), sense[0], sense[1], + sense[2], sense[3]); } else { DBF_DEV_EVENT(DBF_EMERG, device, "%s", "SORRY - NO VALID SENSE AVAILABLE\n"); diff --git a/drivers/s390/block/dasd_erp.c b/drivers/s390/block/dasd_erp.c index d970ce2814b..cb8f9cef742 100644 --- a/drivers/s390/block/dasd_erp.c +++ b/drivers/s390/block/dasd_erp.c @@ -172,7 +172,7 @@ dasd_log_sense_dbf(struct dasd_ccw_req *cqr, struct irb *irb) device = cqr->startdev; /* dump sense data to s390 debugfeature*/ if (device->discipline && device->discipline->dump_sense_dbf) - device->discipline->dump_sense_dbf(device, cqr, irb, "log"); + device->discipline->dump_sense_dbf(device, irb, "log"); } EXPORT_SYMBOL(dasd_log_sense_dbf); diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c index e21ee735f92..31849ad5e59 100644 --- a/drivers/s390/block/dasd_fba.c +++ b/drivers/s390/block/dasd_fba.c @@ -241,7 +241,7 @@ static void dasd_fba_handle_unsolicited_interrupt(struct dasd_device *device, /* check for unsolicited interrupts */ DBF_DEV_EVENT(DBF_WARNING, device, "%s", "unsolicited interrupt received"); - device->discipline->dump_sense_dbf(device, NULL, irb, "unsolicited"); + device->discipline->dump_sense_dbf(device, irb, "unsolicited"); dasd_schedule_device_bh(device); return; }; @@ -444,17 +444,20 @@ dasd_fba_fill_info(struct dasd_device * device, } static void -dasd_fba_dump_sense_dbf(struct dasd_device *device, struct dasd_ccw_req *req, - struct irb *irb, char *reason) +dasd_fba_dump_sense_dbf(struct dasd_device *device, struct irb *irb, + char *reason) { - int sl; - if (irb->esw.esw0.erw.cons) { - for (sl = 0; sl < 4; sl++) { - DBF_DEV_EVENT(DBF_EMERG, device, - "%s: %08x %08x %08x %08x", - reason, irb->ecw[8 * 0], irb->ecw[8 * 1], - irb->ecw[8 * 2], irb->ecw[8 * 3]); - } + u64 *sense; + + sense = (u64 *) dasd_get_sense(irb); + if (sense) { + DBF_DEV_EVENT(DBF_EMERG, device, + "%s: %s %02x%02x%02x %016llx %016llx %016llx " + "%016llx", reason, + scsw_is_tm(&irb->scsw) ? "t" : "c", + scsw_cc(&irb->scsw), scsw_cstat(&irb->scsw), + scsw_dstat(&irb->scsw), sense[0], sense[1], + sense[2], sense[3]); } else { DBF_DEV_EVENT(DBF_EMERG, device, "%s", "SORRY - NO VALID SENSE AVAILABLE\n"); diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index fd63b2f2bda..b699ca356ac 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h @@ -284,8 +284,7 @@ struct dasd_discipline { dasd_erp_fn_t(*erp_postaction) (struct dasd_ccw_req *); void (*dump_sense) (struct dasd_device *, struct dasd_ccw_req *, struct irb *); - void (*dump_sense_dbf) (struct dasd_device *, struct dasd_ccw_req *, - struct irb *, char *); + void (*dump_sense_dbf) (struct dasd_device *, struct irb *, char *); void (*handle_unsolicited_interrupt) (struct dasd_device *, struct irb *); diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c index 4ce3f72ee1c..df918ef2796 100644 --- a/drivers/s390/block/dasd_ioctl.c +++ b/drivers/s390/block/dasd_ioctl.c @@ -16,6 +16,7 @@ #include <linux/major.h> #include <linux/fs.h> #include <linux/blkpg.h> +#include <linux/smp_lock.h> #include <asm/ccwdev.h> #include <asm/cmb.h> diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index 016f9e9d259..d34617682a6 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c @@ -964,7 +964,8 @@ static int dcssblk_freeze(struct device *dev) break; } if (rc) - pr_err("Suspend failed because device %s is writeable.\n", + pr_err("Suspending the system failed because DCSS device %s " + "is writable\n", dev_info->segment_name); return rc; } @@ -987,8 +988,8 @@ static int dcssblk_restore(struct device *dev) goto out_panic; } if (start != entry->start || end != entry->end) { - pr_err("Mismatch of start / end address after " - "resuming device %s\n", + pr_err("The address range of DCSS %s changed " + "while the system was suspended\n", entry->segment_name); goto out_panic; } diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c index 2e9e1ecd6d8..db442cd6621 100644 --- a/drivers/s390/block/xpram.c +++ b/drivers/s390/block/xpram.c @@ -443,7 +443,7 @@ fail: */ static void xpram_resume_error(const char *message) { - pr_err("Resume error: %s\n", message); + pr_err("Resuming the system failed: %s\n", message); panic("xpram resume error\n"); } diff --git a/drivers/s390/char/monreader.c b/drivers/s390/char/monreader.c index 7892550d793..3234e90bd7f 100644 --- a/drivers/s390/char/monreader.c +++ b/drivers/s390/char/monreader.c @@ -320,7 +320,7 @@ static int mon_open(struct inode *inode, struct file *filp) goto out_path; } filp->private_data = monpriv; - dev_set_drvdata(&monreader_device, monpriv); + dev_set_drvdata(monreader_device, monpriv); unlock_kernel(); return nonseekable_open(inode, filp); @@ -463,7 +463,7 @@ static struct miscdevice mon_dev = { *****************************************************************************/ static int monreader_freeze(struct device *dev) { - struct mon_private *monpriv = dev_get_drvdata(&dev); + struct mon_private *monpriv = dev_get_drvdata(dev); int rc; if (!monpriv) diff --git a/drivers/s390/char/sclp_rw.h b/drivers/s390/char/sclp_rw.h index 85f491ea929..7a7bfc947d9 100644 --- a/drivers/s390/char/sclp_rw.h +++ b/drivers/s390/char/sclp_rw.h @@ -92,5 +92,10 @@ void sclp_set_columns(struct sclp_buffer *, unsigned short); void sclp_set_htab(struct sclp_buffer *, unsigned short); int sclp_chars_in_buffer(struct sclp_buffer *); +#ifdef CONFIG_SCLP_CONSOLE void sclp_console_pm_event(enum sclp_pm_event sclp_pm_event); +#else +static inline void sclp_console_pm_event(enum sclp_pm_event sclp_pm_event) { } +#endif + #endif /* __SCLP_RW_H__ */ diff --git a/drivers/s390/char/vmwatchdog.c b/drivers/s390/char/vmwatchdog.c index cb7854c10c0..f2bc287b69e 100644 --- a/drivers/s390/char/vmwatchdog.c +++ b/drivers/s390/char/vmwatchdog.c @@ -250,14 +250,14 @@ static int vmwdt_resume(void) static int vmwdt_suspend(void) { if (test_and_set_bit(VMWDT_OPEN, &vmwdt_is_open)) { - pr_err("The watchdog is in use. " - "This prevents hibernation or suspend.\n"); + pr_err("The system cannot be suspended while the watchdog" + " is in use\n"); return NOTIFY_BAD; } if (test_bit(VMWDT_RUNNING, &vmwdt_is_open)) { clear_bit(VMWDT_OPEN, &vmwdt_is_open); - pr_err("The watchdog is running. " - "This prevents hibernation or suspend.\n"); + pr_err("The system cannot be suspended while the watchdog" + " is running\n"); return NOTIFY_BAD; } return NOTIFY_DONE; diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c index 650bcef08f2..cd78c501803 100644 --- a/drivers/scsi/qla2xxx/qla_mid.c +++ b/drivers/scsi/qla2xxx/qla_mid.c @@ -9,7 +9,6 @@ #include <linux/moduleparam.h> #include <linux/vmalloc.h> -#include <linux/smp_lock.h> #include <linux/list.h> #include <scsi/scsi_tcq.h> diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 4d6f2fe1cfe..9230402c45a 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -1656,6 +1656,10 @@ static int sg_start_req(Sg_request *srp, unsigned char *cmd) md->nr_entries = req_schp->k_use_sg; md->offset = 0; md->null_mapped = hp->dxferp ? 0 : 1; + if (dxfer_dir == SG_DXFER_TO_FROM_DEV) + md->from_user = 1; + else + md->from_user = 0; } if (iov_count) { diff --git a/drivers/staging/comedi/drivers/jr3_pci.c b/drivers/staging/comedi/drivers/jr3_pci.c index baf83c6a941..e3c3adc282e 100644 --- a/drivers/staging/comedi/drivers/jr3_pci.c +++ b/drivers/staging/comedi/drivers/jr3_pci.c @@ -45,6 +45,8 @@ Devices: [JR3] PCI force sensor board (jr3_pci) #include <linux/delay.h> #include <linux/ctype.h> #include <linux/firmware.h> +#include <linux/jiffies.h> +#include <linux/timer.h> #include "comedi_pci.h" #include "jr3_pci.h" diff --git a/drivers/staging/comedi/drivers/s626.c b/drivers/staging/comedi/drivers/s626.c index 92121cf8c45..5d9bab352c1 100644 --- a/drivers/staging/comedi/drivers/s626.c +++ b/drivers/staging/comedi/drivers/s626.c @@ -111,9 +111,13 @@ static const struct s626_board s626_boards[] = { #define PCI_VENDOR_ID_S626 0x1131 #define PCI_DEVICE_ID_S626 0x7146 +/* + * For devices with vendor:device id == 0x1131:0x7146 you must specify + * also subvendor:subdevice ids, because otherwise it will conflict with + * Philips SAA7146 media/dvb based cards. + */ static DEFINE_PCI_DEVICE_TABLE(s626_pci_table) = { - {PCI_VENDOR_ID_S626, PCI_DEVICE_ID_S626, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - 0}, + {PCI_VENDOR_ID_S626, PCI_DEVICE_ID_S626, 0x6000, 0x0272, 0, 0, 0}, {0} }; @@ -499,25 +503,26 @@ static int s626_attach(struct comedi_device *dev, struct comedi_devconfig *it) resource_size_t resourceStart; dma_addr_t appdma; struct comedi_subdevice *s; - struct pci_dev *pdev; + const struct pci_device_id *ids; + struct pci_dev *pdev = NULL; if (alloc_private(dev, sizeof(struct s626_private)) < 0) return -ENOMEM; - for (pdev = pci_get_device(PCI_VENDOR_ID_S626, PCI_DEVICE_ID_S626, - NULL); pdev != NULL; - pdev = pci_get_device(PCI_VENDOR_ID_S626, - PCI_DEVICE_ID_S626, pdev)) { - if (it->options[0] || it->options[1]) { - if (pdev->bus->number == it->options[0] && - PCI_SLOT(pdev->devfn) == it->options[1]) { + for (i = 0; i < (ARRAY_SIZE(s626_pci_table) - 1) && !pdev; i++) { + ids = &s626_pci_table[i]; + do { + pdev = pci_get_subsys(ids->vendor, ids->device, ids->subvendor, + ids->subdevice, pdev); + + if ((it->options[0] || it->options[1]) && pdev) { /* matches requested bus/slot */ + if (pdev->bus->number == it->options[0] && + PCI_SLOT(pdev->devfn) == it->options[1]) + break; + } else break; - } - } else { - /* no bus/slot specified */ - break; - } + } while (1); } devpriv->pdev = pdev; diff --git a/drivers/staging/go7007/s2250-loader.c b/drivers/staging/go7007/s2250-loader.c index a5e4acab089..bb22347af60 100644 --- a/drivers/staging/go7007/s2250-loader.c +++ b/drivers/staging/go7007/s2250-loader.c @@ -17,6 +17,7 @@ #include <linux/module.h> #include <linux/init.h> +#include <linux/smp_lock.h> #include <linux/usb.h> #include <dvb-usb.h> diff --git a/drivers/staging/meilhaus/TODO b/drivers/staging/meilhaus/TODO index 6ec25203089..d6ce39823de 100644 --- a/drivers/staging/meilhaus/TODO +++ b/drivers/staging/meilhaus/TODO @@ -7,4 +7,4 @@ TODO: - possible comedi merge Please send cleanup patches to Greg Kroah-Hartman <greg@kroah.com> -and CC: David Kiliani <mail@davidkiliani.de> +and CC: David Kiliani <mail@davidkiliani.de> and Meilhaus Support <support@meilhaus.de> diff --git a/drivers/staging/rspiusb/rspiusb.c b/drivers/staging/rspiusb/rspiusb.c index 1cdfe69585e..2f8155c1968 100644 --- a/drivers/staging/rspiusb/rspiusb.c +++ b/drivers/staging/rspiusb/rspiusb.c @@ -444,8 +444,7 @@ static void piusb_write_bulk_callback(struct urb *urb) __func__, status); pdx->pendingWrite = 0; - usb_buffer_free(urb->dev, urb->transfer_buffer_length, - urb->transfer_buffer, urb->transfer_dma); + kfree(urb->transfer_buffer); } int piusb_output(struct ioctl_struct *io, unsigned char *uBuf, int len, @@ -457,9 +456,7 @@ int piusb_output(struct ioctl_struct *io, unsigned char *uBuf, int len, urb = usb_alloc_urb(0, GFP_KERNEL); if (urb != NULL) { - kbuf = - usb_buffer_alloc(pdx->udev, len, GFP_KERNEL, - &urb->transfer_dma); + kbuf = kmalloc(len, GFP_KERNEL); if (!kbuf) { dev_err(&pdx->udev->dev, "buffer_alloc failed\n"); return -ENOMEM; @@ -470,7 +467,6 @@ int piusb_output(struct ioctl_struct *io, unsigned char *uBuf, int len, } usb_fill_bulk_urb(urb, pdx->udev, pdx->hEP[io->endpoint], kbuf, len, piusb_write_bulk_callback, pdx); - urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; err = usb_submit_urb(urb, GFP_KERNEL); if (err) { dev_err(&pdx->udev->dev, @@ -641,7 +637,7 @@ static int MapUserBuffer(struct ioctl_struct *io, struct device_extension *pdx) numPagesRequired = ((uaddr & ~PAGE_MASK) + count + ~PAGE_MASK) >> PAGE_SHIFT; dbg("Number of pages needed = %d", numPagesRequired); - maplist_p = vmalloc(numPagesRequired * sizeof(struct page)); + maplist_p = vmalloc(numPagesRequired * sizeof(struct page *)); if (!maplist_p) { dbg("Can't Allocate Memory for maplist_p"); return -ENOMEM; @@ -712,9 +708,7 @@ static int MapUserBuffer(struct ioctl_struct *io, struct device_extension *pdx) usb_fill_bulk_urb(pdx->PixelUrb[frameInfo][i], pdx->udev, epAddr, - (dma_addr_t *) sg_dma_address(&pdx-> - sgl[frameInfo] - [i]), + NULL, // non-DMA HC? buy a better hardware sg_dma_len(&pdx->sgl[frameInfo][i]), piusb_readPIXEL_callback, (void *)pdx); pdx->PixelUrb[frameInfo][i]->transfer_dma = diff --git a/drivers/staging/rt2870/rt2870.h b/drivers/staging/rt2870/rt2870.h index 5e5b3f2b7eb..29e3b53e52a 100644 --- a/drivers/staging/rt2870/rt2870.h +++ b/drivers/staging/rt2870/rt2870.h @@ -89,6 +89,7 @@ {USB_DEVICE(0x0DF6,0x002C)}, /* Sitecom */ \ {USB_DEVICE(0x0DF6,0x002D)}, /* Sitecom */ \ {USB_DEVICE(0x0DF6,0x0039)}, /* Sitecom */ \ + {USB_DEVICE(0x0DF6,0x003F)}, /* Sitecom WL-608 */ \ {USB_DEVICE(0x14B2,0x3C06)}, /* Conceptronic */ \ {USB_DEVICE(0x14B2,0x3C28)}, /* Conceptronic */ \ {USB_DEVICE(0x2019,0xED06)}, /* Planex Communications, Inc. */ \ diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c index 93af37e2d31..54b4b718f84 100644 --- a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c +++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c @@ -461,19 +461,19 @@ int ieee80211_wx_get_name(struct ieee80211_device *ieee, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - strcpy(wrqu->name, "802.11"); + strlcpy(wrqu->name, "802.11", IFNAMSIZ); if(ieee->modulation & IEEE80211_CCK_MODULATION){ - strcat(wrqu->name, "b"); + strlcat(wrqu->name, "b", IFNAMSIZ); if(ieee->modulation & IEEE80211_OFDM_MODULATION) - strcat(wrqu->name, "/g"); + strlcat(wrqu->name, "/g", IFNAMSIZ); }else if(ieee->modulation & IEEE80211_OFDM_MODULATION) - strcat(wrqu->name, "g"); + strlcat(wrqu->name, "g", IFNAMSIZ); if((ieee->state == IEEE80211_LINKED) || (ieee->state == IEEE80211_LINKED_SCANNING)) - strcat(wrqu->name," linked"); + strlcat(wrqu->name," link", IFNAMSIZ); else if(ieee->state != IEEE80211_NOLINK) - strcat(wrqu->name," link.."); + strlcat(wrqu->name," .....", IFNAMSIZ); return 0; diff --git a/drivers/staging/rtl8192su/Kconfig b/drivers/staging/rtl8192su/Kconfig index 4b5552c5926..770f41280f2 100644 --- a/drivers/staging/rtl8192su/Kconfig +++ b/drivers/staging/rtl8192su/Kconfig @@ -1,6 +1,6 @@ config RTL8192SU tristate "RealTek RTL8192SU Wireless LAN NIC driver" depends on PCI - depends on WIRELESS_EXT && COMPAT_NET_DEV_OPS + depends on WIRELESS_EXT default N ---help--- diff --git a/drivers/staging/rtl8192su/ieee80211/ieee80211_module.c b/drivers/staging/rtl8192su/ieee80211/ieee80211_module.c index f408b4583b8..759032db4a3 100644 --- a/drivers/staging/rtl8192su/ieee80211/ieee80211_module.c +++ b/drivers/staging/rtl8192su/ieee80211/ieee80211_module.c @@ -118,7 +118,6 @@ struct net_device *alloc_ieee80211(int sizeof_priv) #else ieee = (struct ieee80211_device *)dev->priv; #endif - dev->hard_start_xmit = ieee80211_xmit; memset(ieee, 0, sizeof(struct ieee80211_device)+sizeof_priv); ieee->dev = dev; diff --git a/drivers/staging/rtl8192su/ieee80211/ieee80211_softmac_wx.c b/drivers/staging/rtl8192su/ieee80211/ieee80211_softmac_wx.c index 1f50c46dcb9..191dc3fbbe3 100644 --- a/drivers/staging/rtl8192su/ieee80211/ieee80211_softmac_wx.c +++ b/drivers/staging/rtl8192su/ieee80211/ieee80211_softmac_wx.c @@ -548,21 +548,21 @@ int ieee80211_wx_get_name(struct ieee80211_device *ieee, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - strcpy(wrqu->name, "802.11"); + strlcpy(wrqu->name, "802.11", IFNAMSIZ); if(ieee->modulation & IEEE80211_CCK_MODULATION){ - strcat(wrqu->name, "b"); + strlcat(wrqu->name, "b", IFNAMSIZ); if(ieee->modulation & IEEE80211_OFDM_MODULATION) - strcat(wrqu->name, "/g"); + strlcat(wrqu->name, "/g", IFNAMSIZ); }else if(ieee->modulation & IEEE80211_OFDM_MODULATION) - strcat(wrqu->name, "g"); + strlcat(wrqu->name, "g", IFNAMSIZ); if (ieee->mode & (IEEE_N_24G | IEEE_N_5G)) - strcat(wrqu->name, "/n"); + strlcat(wrqu->name, "/n", IFNAMSIZ); if((ieee->state == IEEE80211_LINKED) || (ieee->state == IEEE80211_LINKED_SCANNING)) - strcat(wrqu->name," linked"); + strlcat(wrqu->name, " link", IFNAMSIZ); else if(ieee->state != IEEE80211_NOLINK) - strcat(wrqu->name," link.."); + strlcat(wrqu->name, " .....", IFNAMSIZ); return 0; diff --git a/drivers/staging/rtl8192su/r8192U_core.c b/drivers/staging/rtl8192su/r8192U_core.c index f1423d71449..4ab250743e8 100644 --- a/drivers/staging/rtl8192su/r8192U_core.c +++ b/drivers/staging/rtl8192su/r8192U_core.c @@ -12132,6 +12132,19 @@ static void HalUsbSetQueuePipeMapping8192SUsb(struct usb_interface *intf, struct } #endif +static const struct net_device_ops rtl8192_netdev_ops = { + .ndo_open = rtl8192_open, + .ndo_stop = rtl8192_close, + .ndo_get_stats = rtl8192_stats, + .ndo_tx_timeout = tx_timeout, + .ndo_do_ioctl = rtl8192_ioctl, + .ndo_set_multicast_list = r8192_set_multicast, + .ndo_set_mac_address = r8192_set_mac_adr, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = eth_change_mtu, + .ndo_start_xmit = ieee80211_xmit, +}; + #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) static int __devinit rtl8192_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) @@ -12186,15 +12199,7 @@ static void * __devinit rtl8192_usb_probe(struct usb_device *udev, priv->ops = &rtl8192u_ops; #endif - dev->open = rtl8192_open; - dev->stop = rtl8192_close; - //dev->hard_start_xmit = rtl8192_8023_hard_start_xmit; - dev->tx_timeout = tx_timeout; - //dev->wireless_handlers = &r8192_wx_handlers_def; - dev->do_ioctl = rtl8192_ioctl; - dev->set_multicast_list = r8192_set_multicast; - dev->set_mac_address = r8192_set_mac_adr; - dev->get_stats = rtl8192_stats; + dev->netdev_ops = &rtl8192_netdev_ops; //DMESG("Oops: i'm coming\n"); #if WIRELESS_EXT >= 12 diff --git a/drivers/staging/rtl8192su/r8192U_pm.c b/drivers/staging/rtl8192su/r8192U_pm.c index 92c95aa3663..b1531a8d0cd 100644 --- a/drivers/staging/rtl8192su/r8192U_pm.c +++ b/drivers/staging/rtl8192su/r8192U_pm.c @@ -35,7 +35,9 @@ int rtl8192U_suspend(struct usb_interface *intf, pm_message_t state) return 0; } - dev->stop(dev); + if (dev->netdev_ops->ndo_stop) + dev->netdev_ops->ndo_stop(dev); + mdelay(10); netif_device_detach(dev); @@ -61,7 +63,9 @@ int rtl8192U_resume (struct usb_interface *intf) } netif_device_attach(dev); - dev->open(dev); + + if (dev->netdev_ops->ndo_open) + dev->netdev_ops->ndo_open(dev); } return 0; diff --git a/drivers/staging/serqt_usb2/serqt_usb2.c b/drivers/staging/serqt_usb2/serqt_usb2.c index 90b29b56463..a9bd4106beb 100644 --- a/drivers/staging/serqt_usb2/serqt_usb2.c +++ b/drivers/staging/serqt_usb2/serqt_usb2.c @@ -866,7 +866,7 @@ static void qt_release(struct usb_serial *serial) } -int qt_open(struct tty_struct *tty, +static int qt_open(struct tty_struct *tty, struct usb_serial_port *port, struct file *filp) { struct usb_serial *serial; @@ -1041,17 +1041,19 @@ static void qt_block_until_empty(struct tty_struct *tty, } } -static void qt_close(struct tty_struct *tty, struct usb_serial_port *port, - struct file *filp) +static void qt_close( struct usb_serial_port *port) { struct usb_serial *serial = port->serial; struct quatech_port *qt_port; struct quatech_port *port0; + struct tty_struct *tty; int status; unsigned int index; status = 0; dbg("%s - port %d\n", __func__, port->number); + + tty = tty_port_tty_get(&port->port); index = tty->index - serial->minor; qt_port = qt_get_port_private(port); diff --git a/drivers/staging/stlc45xx/stlc45xx.c b/drivers/staging/stlc45xx/stlc45xx.c index cfdaac9b747..a137c78fac0 100644 --- a/drivers/staging/stlc45xx/stlc45xx.c +++ b/drivers/staging/stlc45xx/stlc45xx.c @@ -2235,24 +2235,6 @@ static void stlc45xx_op_remove_interface(struct ieee80211_hw *hw, stlc45xx_debug(DEBUG_FUNC, "%s", __func__); } -static int stlc45xx_op_config_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_if_conf *conf) -{ - struct stlc45xx *stlc = hw->priv; - - stlc45xx_debug(DEBUG_FUNC, "%s", __func__); - - mutex_lock(&stlc->mutex); - - memcpy(stlc->bssid, conf->bssid, ETH_ALEN); - stlc45xx_tx_setup(stlc); - - mutex_unlock(&stlc->mutex); - - return 0; -} - static int stlc45xx_op_config(struct ieee80211_hw *hw, u32 changed) { struct stlc45xx *stlc = hw->priv; @@ -2295,6 +2277,14 @@ static void stlc45xx_op_bss_info_changed(struct ieee80211_hw *hw, { struct stlc45xx *stlc = hw->priv; + stlc45xx_debug(DEBUG_FUNC, "%s", __func__); + mutex_lock(&stlc->mutex); + + memcpy(stlc->bssid, info->bssid, ETH_ALEN); + stlc45xx_tx_setup(stlc); + + mutex_unlock(&stlc->mutex); + if (changed & BSS_CHANGED_ASSOC) { stlc->associated = info->assoc; if (info->assoc) @@ -2357,7 +2347,6 @@ static const struct ieee80211_ops stlc45xx_ops = { .add_interface = stlc45xx_op_add_interface, .remove_interface = stlc45xx_op_remove_interface, .config = stlc45xx_op_config, - .config_interface = stlc45xx_op_config_interface, .configure_filter = stlc45xx_op_configure_filter, .tx = stlc45xx_op_tx, .bss_info_changed = stlc45xx_op_bss_info_changed, diff --git a/drivers/staging/usbip/usbip_common.c b/drivers/staging/usbip/usbip_common.c index 22f93dd0ba0..251220dc885 100644 --- a/drivers/staging/usbip/usbip_common.c +++ b/drivers/staging/usbip/usbip_common.c @@ -18,6 +18,7 @@ */ #include <linux/kernel.h> +#include <linux/smp_lock.h> #include <linux/file.h> #include <linux/tcp.h> #include <linux/in.h> diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c index a10ed27acbc..f43ca416e4a 100644 --- a/drivers/staging/vt6655/device_main.c +++ b/drivers/staging/vt6655/device_main.c @@ -344,7 +344,7 @@ static CHIP_INFO chip_info_table[]= { }; static struct pci_device_id device_id_table[] __devinitdata = { -{ 0x1106, 0x3253, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (int)&chip_info_table[0]}, +{ 0x1106, 0x3253, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long)&chip_info_table[0]}, { 0, } }; #endif @@ -369,7 +369,7 @@ static int device_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); #ifdef CONFIG_PM static int device_notify_reboot(struct notifier_block *, unsigned long event, void *ptr); -static int viawget_suspend(struct pci_dev *pcid, u32 state); +static int viawget_suspend(struct pci_dev *pcid, pm_message_t state); static int viawget_resume(struct pci_dev *pcid); struct notifier_block device_notifier = { notifier_call: device_notify_reboot, @@ -3941,7 +3941,7 @@ device_notify_reboot(struct notifier_block *nb, unsigned long event, void *p) while ((pdev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) { if(pci_dev_driver(pdev) == &device_driver) { if (pci_get_drvdata(pdev)) - viawget_suspend(pdev, 3); + viawget_suspend(pdev, PMSG_HIBERNATE); } } } @@ -3949,7 +3949,7 @@ device_notify_reboot(struct notifier_block *nb, unsigned long event, void *p) } static int -viawget_suspend(struct pci_dev *pcid, u32 state) +viawget_suspend(struct pci_dev *pcid, pm_message_t state) { int power_status; // to silence the compiler @@ -3971,7 +3971,7 @@ viawget_suspend(struct pci_dev *pcid, u32 state) memset(pMgmt->abyCurrBSSID, 0, 6); pMgmt->eCurrState = WMAC_STATE_IDLE; pci_disable_device(pcid); - power_status = pci_set_power_state(pcid, state); + power_status = pci_set_power_state(pcid, pci_choose_state(pcid, state)); spin_unlock_irq(&pDevice->lock); return 0; } diff --git a/drivers/telephony/ixj.c b/drivers/telephony/ixj.c index a913efc6966..40de151f278 100644 --- a/drivers/telephony/ixj.c +++ b/drivers/telephony/ixj.c @@ -257,6 +257,7 @@ #include <linux/fs.h> /* everything... */ #include <linux/errno.h> /* error codes */ #include <linux/slab.h> +#include <linux/smp_lock.h> #include <linux/mm.h> #include <linux/ioport.h> #include <linux/interrupt.h> diff --git a/drivers/telephony/phonedev.c b/drivers/telephony/phonedev.c index b52cc830c0b..f3873f650bb 100644 --- a/drivers/telephony/phonedev.c +++ b/drivers/telephony/phonedev.c @@ -23,7 +23,6 @@ #include <linux/errno.h> #include <linux/phonedev.h> #include <linux/init.h> -#include <linux/smp_lock.h> #include <asm/uaccess.h> #include <asm/system.h> diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 3f104599347..5b15d9d8896 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -387,6 +387,7 @@ static void acm_rx_tasklet(unsigned long _acm) struct acm_ru *rcv; unsigned long flags; unsigned char throttled; + struct usb_host_endpoint *ep; dbg("Entering acm_rx_tasklet"); @@ -462,11 +463,20 @@ urbs: rcv->buffer = buf; - usb_fill_bulk_urb(rcv->urb, acm->dev, - acm->rx_endpoint, - buf->base, - acm->readsize, - acm_read_bulk, rcv); + ep = (usb_pipein(acm->rx_endpoint) ? acm->dev->ep_in : acm->dev->ep_out) + [usb_pipeendpoint(acm->rx_endpoint)]; + if (usb_endpoint_xfer_int(&ep->desc)) + usb_fill_int_urb(rcv->urb, acm->dev, + acm->rx_endpoint, + buf->base, + acm->readsize, + acm_read_bulk, rcv, ep->desc.bInterval); + else + usb_fill_bulk_urb(rcv->urb, acm->dev, + acm->rx_endpoint, + buf->base, + acm->readsize, + acm_read_bulk, rcv); rcv->urb->transfer_dma = buf->dma; rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; @@ -1227,9 +1237,14 @@ made_compressed_probe: goto alloc_fail7; } - usb_fill_bulk_urb(snd->urb, usb_dev, - usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress), - NULL, acm->writesize, acm_write_bulk, snd); + if (usb_endpoint_xfer_int(epwrite)) + usb_fill_int_urb(snd->urb, usb_dev, + usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress), + NULL, acm->writesize, acm_write_bulk, snd, epwrite->bInterval); + else + usb_fill_bulk_urb(snd->urb, usb_dev, + usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress), + NULL, acm->writesize, acm_write_bulk, snd); snd->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; snd->instance = acm; } diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index 0fe434505ac..ba589d4ca8b 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -15,7 +15,6 @@ #include <linux/errno.h> #include <linux/slab.h> #include <linux/module.h> -#include <linux/smp_lock.h> #include <linux/mutex.h> #include <linux/uaccess.h> #include <linux/bitops.h> diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index 3703789d0d2..b09a527f734 100644 --- a/drivers/usb/class/usbtmc.c +++ b/drivers/usb/class/usbtmc.c @@ -751,7 +751,7 @@ static int get_capabilities(struct usbtmc_device_data *data) { struct device *dev = &data->usb_dev->dev; char *buffer; - int rv; + int rv = 0; buffer = kmalloc(0x18, GFP_KERNEL); if (!buffer) @@ -763,7 +763,7 @@ static int get_capabilities(struct usbtmc_device_data *data) 0, 0, buffer, 0x18, USBTMC_TIMEOUT); if (rv < 0) { dev_err(dev, "usb_control_msg returned %d\n", rv); - return rv; + goto err_out; } dev_dbg(dev, "GET_CAPABILITIES returned %x\n", buffer[0]); @@ -773,7 +773,8 @@ static int get_capabilities(struct usbtmc_device_data *data) dev_dbg(dev, "USB488 device capabilities are %x\n", buffer[15]); if (buffer[0] != USBTMC_STATUS_SUCCESS) { dev_err(dev, "GET_CAPABILITIES returned %x\n", buffer[0]); - return -EPERM; + rv = -EPERM; + goto err_out; } data->capabilities.interface_capabilities = buffer[4]; @@ -781,8 +782,9 @@ static int get_capabilities(struct usbtmc_device_data *data) data->capabilities.usb488_interface_capabilities = buffer[14]; data->capabilities.usb488_device_capabilities = buffer[15]; +err_out: kfree(buffer); - return 0; + return rv; } #define capability_attribute(name) \ diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig index 69280c35b5c..ad925946f86 100644 --- a/drivers/usb/core/Kconfig +++ b/drivers/usb/core/Kconfig @@ -28,7 +28,7 @@ comment "Miscellaneous USB options" depends on USB config USB_DEVICEFS - bool "USB device filesystem (DEPRECATED)" if EMBEDDED + bool "USB device filesystem (DEPRECATED)" depends on USB ---help--- If you say Y here (and to "/proc file system support" in the "File diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c index 73c108d117b..96f11715cd2 100644 --- a/drivers/usb/core/devices.c +++ b/drivers/usb/core/devices.c @@ -136,17 +136,19 @@ static const struct class_info clas_info[] = {USB_CLASS_AUDIO, "audio"}, {USB_CLASS_COMM, "comm."}, {USB_CLASS_HID, "HID"}, - {USB_CLASS_HUB, "hub"}, {USB_CLASS_PHYSICAL, "PID"}, + {USB_CLASS_STILL_IMAGE, "still"}, {USB_CLASS_PRINTER, "print"}, {USB_CLASS_MASS_STORAGE, "stor."}, + {USB_CLASS_HUB, "hub"}, {USB_CLASS_CDC_DATA, "data"}, - {USB_CLASS_APP_SPEC, "app."}, - {USB_CLASS_VENDOR_SPEC, "vend."}, - {USB_CLASS_STILL_IMAGE, "still"}, {USB_CLASS_CSCID, "scard"}, {USB_CLASS_CONTENT_SEC, "c-sec"}, {USB_CLASS_VIDEO, "video"}, + {USB_CLASS_WIRELESS_CONTROLLER, "wlcon"}, + {USB_CLASS_MISC, "misc"}, + {USB_CLASS_APP_SPEC, "app."}, + {USB_CLASS_VENDOR_SPEC, "vend."}, {-1, "unk."} /* leave as last */ }; diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 308609039c7..38b8bce782d 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -325,21 +325,34 @@ static void async_completed(struct urb *urb) struct async *as = urb->context; struct dev_state *ps = as->ps; struct siginfo sinfo; + struct pid *pid = NULL; + uid_t uid = 0; + uid_t euid = 0; + u32 secid = 0; + int signr; spin_lock(&ps->lock); list_move_tail(&as->asynclist, &ps->async_completed); - spin_unlock(&ps->lock); as->status = urb->status; - if (as->signr) { + signr = as->signr; + if (signr) { sinfo.si_signo = as->signr; sinfo.si_errno = as->status; sinfo.si_code = SI_ASYNCIO; sinfo.si_addr = as->userurb; - kill_pid_info_as_uid(as->signr, &sinfo, as->pid, as->uid, - as->euid, as->secid); + pid = as->pid; + uid = as->uid; + euid = as->euid; + secid = as->secid; } snoop(&urb->dev->dev, "urb complete\n"); snoop_urb(urb, as->userurb); + spin_unlock(&ps->lock); + + if (signr) + kill_pid_info_as_uid(sinfo.si_signo, &sinfo, pid, uid, + euid, secid); + wake_up(&ps->wait); } @@ -982,7 +995,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, USBDEVFS_URB_ZERO_PACKET | USBDEVFS_URB_NO_INTERRUPT)) return -EINVAL; - if (!uurb->buffer) + if (uurb->buffer_length > 0 && !uurb->buffer) return -EINVAL; if (!(uurb->type == USBDEVFS_URB_TYPE_CONTROL && (uurb->endpoint & ~USB_ENDPOINT_DIR_MASK) == 0)) { @@ -1038,11 +1051,6 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, is_in = 0; uurb->endpoint &= ~USB_DIR_IN; } - if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ, - uurb->buffer, uurb->buffer_length)) { - kfree(dr); - return -EFAULT; - } snoop(&ps->dev->dev, "control urb: bRequest=%02x " "bRrequestType=%02x wValue=%04x " "wIndex=%04x wLength=%04x\n", @@ -1062,9 +1070,6 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, uurb->number_of_packets = 0; if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE) return -EINVAL; - if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ, - uurb->buffer, uurb->buffer_length)) - return -EFAULT; snoop(&ps->dev->dev, "bulk urb\n"); break; @@ -1106,28 +1111,35 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, return -EINVAL; if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE) return -EINVAL; - if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ, - uurb->buffer, uurb->buffer_length)) - return -EFAULT; snoop(&ps->dev->dev, "interrupt urb\n"); break; default: return -EINVAL; } - as = alloc_async(uurb->number_of_packets); - if (!as) { + if (uurb->buffer_length > 0 && + !access_ok(is_in ? VERIFY_WRITE : VERIFY_READ, + uurb->buffer, uurb->buffer_length)) { kfree(isopkt); kfree(dr); - return -ENOMEM; + return -EFAULT; } - as->urb->transfer_buffer = kmalloc(uurb->buffer_length, GFP_KERNEL); - if (!as->urb->transfer_buffer) { + as = alloc_async(uurb->number_of_packets); + if (!as) { kfree(isopkt); kfree(dr); - free_async(as); return -ENOMEM; } + if (uurb->buffer_length > 0) { + as->urb->transfer_buffer = kmalloc(uurb->buffer_length, + GFP_KERNEL); + if (!as->urb->transfer_buffer) { + kfree(isopkt); + kfree(dr); + free_async(as); + return -ENOMEM; + } + } as->urb->dev = ps->dev; as->urb->pipe = (uurb->type << 30) | __create_pipe(ps->dev, uurb->endpoint & 0xf) | @@ -1169,7 +1181,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, kfree(isopkt); as->ps = ps; as->userurb = arg; - if (uurb->endpoint & USB_DIR_IN) + if (is_in && uurb->buffer_length > 0) as->userbuffer = uurb->buffer; else as->userbuffer = NULL; @@ -1179,9 +1191,9 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, as->uid = cred->uid; as->euid = cred->euid; security_task_getsecid(current, &as->secid); - if (!is_in) { + if (!is_in && uurb->buffer_length > 0) { if (copy_from_user(as->urb->transfer_buffer, uurb->buffer, - as->urb->transfer_buffer_length)) { + uurb->buffer_length)) { free_async(as); return -EFAULT; } @@ -1231,22 +1243,22 @@ static int processcompl(struct async *as, void __user * __user *arg) if (as->userbuffer) if (copy_to_user(as->userbuffer, urb->transfer_buffer, urb->transfer_buffer_length)) - return -EFAULT; + goto err_out; if (put_user(as->status, &userurb->status)) - return -EFAULT; + goto err_out; if (put_user(urb->actual_length, &userurb->actual_length)) - return -EFAULT; + goto err_out; if (put_user(urb->error_count, &userurb->error_count)) - return -EFAULT; + goto err_out; if (usb_endpoint_xfer_isoc(&urb->ep->desc)) { for (i = 0; i < urb->number_of_packets; i++) { if (put_user(urb->iso_frame_desc[i].actual_length, &userurb->iso_frame_desc[i].actual_length)) - return -EFAULT; + goto err_out; if (put_user(urb->iso_frame_desc[i].status, &userurb->iso_frame_desc[i].status)) - return -EFAULT; + goto err_out; } } @@ -1255,6 +1267,10 @@ static int processcompl(struct async *as, void __user * __user *arg) if (put_user(addr, (void __user * __user *)arg)) return -EFAULT; return 0; + +err_out: + free_async(as); + return -EFAULT; } static struct async *reap_as(struct dev_state *ps) diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index d397ecfd5b1..ec5c67ea07b 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -227,6 +227,10 @@ struct hc_driver { /* has a port been handed over to a companion? */ int (*port_handed_over)(struct usb_hcd *, int); + /* CLEAR_TT_BUFFER completion callback */ + void (*clear_tt_buffer_complete)(struct usb_hcd *, + struct usb_host_endpoint *); + /* xHCI specific functions */ /* Called by usb_alloc_dev to alloc HC device structures */ int (*alloc_dev)(struct usb_hcd *, struct usb_device *); diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 2af3b4f0605..71f86c60d83 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -450,10 +450,10 @@ hub_clear_tt_buffer (struct usb_device *hdev, u16 devinfo, u16 tt) * talking to TTs must queue control transfers (not just bulk and iso), so * both can talk to the same hub concurrently. */ -static void hub_tt_kevent (struct work_struct *work) +static void hub_tt_work(struct work_struct *work) { struct usb_hub *hub = - container_of(work, struct usb_hub, tt.kevent); + container_of(work, struct usb_hub, tt.clear_work); unsigned long flags; int limit = 100; @@ -462,6 +462,7 @@ static void hub_tt_kevent (struct work_struct *work) struct list_head *next; struct usb_tt_clear *clear; struct usb_device *hdev = hub->hdev; + const struct hc_driver *drv; int status; next = hub->tt.clear_list.next; @@ -471,21 +472,25 @@ static void hub_tt_kevent (struct work_struct *work) /* drop lock so HCD can concurrently report other TT errors */ spin_unlock_irqrestore (&hub->tt.lock, flags); status = hub_clear_tt_buffer (hdev, clear->devinfo, clear->tt); - spin_lock_irqsave (&hub->tt.lock, flags); - if (status) dev_err (&hdev->dev, "clear tt %d (%04x) error %d\n", clear->tt, clear->devinfo, status); + + /* Tell the HCD, even if the operation failed */ + drv = clear->hcd->driver; + if (drv->clear_tt_buffer_complete) + (drv->clear_tt_buffer_complete)(clear->hcd, clear->ep); + kfree(clear); + spin_lock_irqsave(&hub->tt.lock, flags); } spin_unlock_irqrestore (&hub->tt.lock, flags); } /** - * usb_hub_tt_clear_buffer - clear control/bulk TT state in high speed hub - * @udev: the device whose split transaction failed - * @pipe: identifies the endpoint of the failed transaction + * usb_hub_clear_tt_buffer - clear control/bulk TT state in high speed hub + * @urb: an URB associated with the failed or incomplete split transaction * * High speed HCDs use this to tell the hub driver that some split control or * bulk transaction failed in a way that requires clearing internal state of @@ -495,8 +500,10 @@ static void hub_tt_kevent (struct work_struct *work) * It may not be possible for that hub to handle additional full (or low) * speed transactions until that state is fully cleared out. */ -void usb_hub_tt_clear_buffer (struct usb_device *udev, int pipe) +int usb_hub_clear_tt_buffer(struct urb *urb) { + struct usb_device *udev = urb->dev; + int pipe = urb->pipe; struct usb_tt *tt = udev->tt; unsigned long flags; struct usb_tt_clear *clear; @@ -508,7 +515,7 @@ void usb_hub_tt_clear_buffer (struct usb_device *udev, int pipe) if ((clear = kmalloc (sizeof *clear, GFP_ATOMIC)) == NULL) { dev_err (&udev->dev, "can't save CLEAR_TT_BUFFER state\n"); /* FIXME recover somehow ... RESET_TT? */ - return; + return -ENOMEM; } /* info that CLEAR_TT_BUFFER needs */ @@ -520,14 +527,19 @@ void usb_hub_tt_clear_buffer (struct usb_device *udev, int pipe) : (USB_ENDPOINT_XFER_BULK << 11); if (usb_pipein (pipe)) clear->devinfo |= 1 << 15; - + + /* info for completion callback */ + clear->hcd = bus_to_hcd(udev->bus); + clear->ep = urb->ep; + /* tell keventd to clear state for this TT */ spin_lock_irqsave (&tt->lock, flags); list_add_tail (&clear->clear_list, &tt->clear_list); - schedule_work (&tt->kevent); + schedule_work(&tt->clear_work); spin_unlock_irqrestore (&tt->lock, flags); + return 0; } -EXPORT_SYMBOL_GPL(usb_hub_tt_clear_buffer); +EXPORT_SYMBOL_GPL(usb_hub_clear_tt_buffer); /* If do_delay is false, return the number of milliseconds the caller * needs to delay. @@ -818,7 +830,7 @@ static void hub_quiesce(struct usb_hub *hub, enum hub_quiescing_type type) if (hub->has_indicators) cancel_delayed_work_sync(&hub->leds); if (hub->tt.hub) - cancel_work_sync(&hub->tt.kevent); + cancel_work_sync(&hub->tt.clear_work); } /* caller has locked the hub device */ @@ -935,7 +947,7 @@ static int hub_configure(struct usb_hub *hub, spin_lock_init (&hub->tt.lock); INIT_LIST_HEAD (&hub->tt.clear_list); - INIT_WORK (&hub->tt.kevent, hub_tt_kevent); + INIT_WORK(&hub->tt.clear_work, hub_tt_work); switch (hdev->descriptor.bDeviceProtocol) { case 0: break; diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h index 889c0f32a40..de8081f065e 100644 --- a/drivers/usb/core/hub.h +++ b/drivers/usb/core/hub.h @@ -188,16 +188,18 @@ struct usb_tt { /* for control/bulk error recovery (CLEAR_TT_BUFFER) */ spinlock_t lock; struct list_head clear_list; /* of usb_tt_clear */ - struct work_struct kevent; + struct work_struct clear_work; }; struct usb_tt_clear { struct list_head clear_list; unsigned tt; u16 devinfo; + struct usb_hcd *hcd; + struct usb_host_endpoint *ep; }; -extern void usb_hub_tt_clear_buffer(struct usb_device *dev, int pipe); +extern int usb_hub_clear_tt_buffer(struct urb *urb); extern void usb_ep0_reinit(struct usb_device *); #endif /* __LINUX_HUB_H */ diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 2bed83caacb..9720e699f47 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -806,6 +806,48 @@ static int usb_string_sub(struct usb_device *dev, unsigned int langid, return rc; } +static int usb_get_langid(struct usb_device *dev, unsigned char *tbuf) +{ + int err; + + if (dev->have_langid) + return 0; + + if (dev->string_langid < 0) + return -EPIPE; + + err = usb_string_sub(dev, 0, 0, tbuf); + + /* If the string was reported but is malformed, default to english + * (0x0409) */ + if (err == -ENODATA || (err > 0 && err < 4)) { + dev->string_langid = 0x0409; + dev->have_langid = 1; + dev_err(&dev->dev, + "string descriptor 0 malformed (err = %d), " + "defaulting to 0x%04x\n", + err, dev->string_langid); + return 0; + } + + /* In case of all other errors, we assume the device is not able to + * deal with strings at all. Set string_langid to -1 in order to + * prevent any string to be retrieved from the device */ + if (err < 0) { + dev_err(&dev->dev, "string descriptor 0 read error: %d\n", + err); + dev->string_langid = -1; + return -EPIPE; + } + + /* always use the first langid listed */ + dev->string_langid = tbuf[2] | (tbuf[3] << 8); + dev->have_langid = 1; + dev_dbg(&dev->dev, "default language 0x%04x\n", + dev->string_langid); + return 0; +} + /** * usb_string - returns UTF-8 version of a string descriptor * @dev: the device whose string descriptor is being retrieved @@ -837,24 +879,9 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size) if (!tbuf) return -ENOMEM; - /* get langid for strings if it's not yet known */ - if (!dev->have_langid) { - err = usb_string_sub(dev, 0, 0, tbuf); - if (err < 0) { - dev_err(&dev->dev, - "string descriptor 0 read error: %d\n", - err); - } else if (err < 4) { - dev_err(&dev->dev, "string descriptor 0 too short\n"); - } else { - dev->string_langid = tbuf[2] | (tbuf[3] << 8); - /* always use the first langid listed */ - dev_dbg(&dev->dev, "default language 0x%04x\n", - dev->string_langid); - } - - dev->have_langid = 1; - } + err = usb_get_langid(dev, tbuf); + if (err < 0) + goto errout; err = usb_string_sub(dev, dev->string_langid, index, tbuf); if (err < 0) diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 5d1ddf485d1..7f8e83a954a 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -286,6 +286,27 @@ config USB_S3C_HSOTG default USB_GADGET select USB_GADGET_SELECTED +config USB_GADGET_IMX + boolean "Freescale IMX USB Peripheral Controller" + depends on ARCH_MX1 + help + Freescale's IMX series include an integrated full speed + USB 1.1 device controller. The controller in the IMX series + is register-compatible. + + It has Six fixed-function endpoints, as well as endpoint + zero (for control transfers). + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "imx_udc" and force all + gadget drivers to also be dynamically linked. + +config USB_IMX + tristate + depends on USB_GADGET_IMX + default USB_GADGET + select USB_GADGET_SELECTED + config USB_GADGET_S3C2410 boolean "S3C2410 USB Device Controller" depends on ARCH_S3C2410 @@ -321,27 +342,6 @@ config USB_GADGET_MUSB_HDRC This OTG-capable silicon IP is used in dual designs including the TI DaVinci, OMAP 243x, OMAP 343x, TUSB 6010, and ADI Blackfin -config USB_GADGET_IMX - boolean "Freescale IMX USB Peripheral Controller" - depends on ARCH_MX1 - help - Freescale's IMX series include an integrated full speed - USB 1.1 device controller. The controller in the IMX series - is register-compatible. - - It has Six fixed-function endpoints, as well as endpoint - zero (for control transfers). - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "imx_udc" and force all - gadget drivers to also be dynamically linked. - -config USB_IMX - tristate - depends on USB_GADGET_IMX - default USB_GADGET - select USB_GADGET_SELECTED - config USB_GADGET_M66592 boolean "Renesas M66592 USB Peripheral Controller" select USB_GADGET_DUALSPEED @@ -604,6 +604,7 @@ config USB_ZERO_HNPTEST config USB_AUDIO tristate "Audio Gadget (EXPERIMENTAL)" depends on SND + select SND_PCM help Gadget Audio is compatible with USB Audio Class specification 1.0. It will include at least one AudioControl interface, zero or more diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c index 826f3adde5d..77352ccc245 100644 --- a/drivers/usb/gadget/amd5536udc.c +++ b/drivers/usb/gadget/amd5536udc.c @@ -48,7 +48,6 @@ #include <linux/ioport.h> #include <linux/sched.h> #include <linux/slab.h> -#include <linux/smp_lock.h> #include <linux/errno.h> #include <linux/init.h> #include <linux/timer.h> diff --git a/drivers/usb/gadget/audio.c b/drivers/usb/gadget/audio.c index 94de7e86461..9f80f4e970b 100644 --- a/drivers/usb/gadget/audio.c +++ b/drivers/usb/gadget/audio.c @@ -42,9 +42,9 @@ * Instead: allocate your own, using normal USB-IF procedures. */ -/* Thanks to NetChip Technologies for donating this product ID. */ -#define AUDIO_VENDOR_NUM 0x0525 /* NetChip */ -#define AUDIO_PRODUCT_NUM 0xa4a1 /* Linux-USB Audio Gadget */ +/* Thanks to Linux Foundation for donating this product ID. */ +#define AUDIO_VENDOR_NUM 0x1d6b /* Linux Foundation */ +#define AUDIO_PRODUCT_NUM 0x0101 /* Linux-USB Audio Gadget */ /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index d006dc652e0..bd102f5052b 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -293,15 +293,16 @@ static int __init eth_bind(struct usb_composite_dev *cdev) /* CDC Subset */ eth_config_driver.label = "CDC Subset/SAFE"; - device_desc.idVendor = cpu_to_le16(SIMPLE_VENDOR_NUM), - device_desc.idProduct = cpu_to_le16(SIMPLE_PRODUCT_NUM), - device_desc.bDeviceClass = USB_CLASS_VENDOR_SPEC; + device_desc.idVendor = cpu_to_le16(SIMPLE_VENDOR_NUM); + device_desc.idProduct = cpu_to_le16(SIMPLE_PRODUCT_NUM); + if (!has_rndis()) + device_desc.bDeviceClass = USB_CLASS_VENDOR_SPEC; } if (has_rndis()) { /* RNDIS plus ECM-or-Subset */ - device_desc.idVendor = cpu_to_le16(RNDIS_VENDOR_NUM), - device_desc.idProduct = cpu_to_le16(RNDIS_PRODUCT_NUM), + device_desc.idVendor = cpu_to_le16(RNDIS_VENDOR_NUM); + device_desc.idProduct = cpu_to_le16(RNDIS_PRODUCT_NUM); device_desc.bNumConfigurations = 2; } diff --git a/drivers/usb/gadget/langwell_udc.c b/drivers/usb/gadget/langwell_udc.c index 6829d596135..a3913519fd5 100644 --- a/drivers/usb/gadget/langwell_udc.c +++ b/drivers/usb/gadget/langwell_udc.c @@ -34,7 +34,6 @@ #include <linux/ioport.h> #include <linux/sched.h> #include <linux/slab.h> -#include <linux/smp_lock.h> #include <linux/errno.h> #include <linux/init.h> #include <linux/timer.h> diff --git a/drivers/usb/gadget/pxa25x_udc.c b/drivers/usb/gadget/pxa25x_udc.c index 0ce4e281984..ed21e263f83 100644 --- a/drivers/usb/gadget/pxa25x_udc.c +++ b/drivers/usb/gadget/pxa25x_udc.c @@ -139,7 +139,7 @@ static int is_vbus_present(void) { struct pxa2xx_udc_mach_info *mach = the_controller->mach; - if (mach->gpio_vbus) { + if (gpio_is_valid(mach->gpio_vbus)) { int value = gpio_get_value(mach->gpio_vbus); if (mach->gpio_vbus_inverted) @@ -158,7 +158,7 @@ static void pullup_off(void) struct pxa2xx_udc_mach_info *mach = the_controller->mach; int off_level = mach->gpio_pullup_inverted; - if (mach->gpio_pullup) + if (gpio_is_valid(mach->gpio_pullup)) gpio_set_value(mach->gpio_pullup, off_level); else if (mach->udc_command) mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT); @@ -169,7 +169,7 @@ static void pullup_on(void) struct pxa2xx_udc_mach_info *mach = the_controller->mach; int on_level = !mach->gpio_pullup_inverted; - if (mach->gpio_pullup) + if (gpio_is_valid(mach->gpio_pullup)) gpio_set_value(mach->gpio_pullup, on_level); else if (mach->udc_command) mach->udc_command(PXA2XX_UDC_CMD_CONNECT); @@ -1000,7 +1000,7 @@ static int pxa25x_udc_pullup(struct usb_gadget *_gadget, int is_active) udc = container_of(_gadget, struct pxa25x_udc, gadget); /* not all boards support pullup control */ - if (!udc->mach->gpio_pullup && !udc->mach->udc_command) + if (!gpio_is_valid(udc->mach->gpio_pullup) && !udc->mach->udc_command) return -EOPNOTSUPP; udc->pullup = (is_active != 0); @@ -1802,11 +1802,13 @@ pxa25x_udc_irq(int irq, void *_dev) USIR0 |= tmp; handled = 1; } +#ifndef CONFIG_USB_PXA25X_SMALL if (usir1 & tmp) { handle_ep(&dev->ep[i+8]); USIR1 |= tmp; handled = 1; } +#endif } } @@ -2160,7 +2162,7 @@ static int __init pxa25x_udc_probe(struct platform_device *pdev) dev->dev = &pdev->dev; dev->mach = pdev->dev.platform_data; - if (dev->mach->gpio_vbus) { + if (gpio_is_valid(dev->mach->gpio_vbus)) { if ((retval = gpio_request(dev->mach->gpio_vbus, "pxa25x_udc GPIO VBUS"))) { dev_dbg(&pdev->dev, @@ -2173,7 +2175,7 @@ static int __init pxa25x_udc_probe(struct platform_device *pdev) } else vbus_irq = 0; - if (dev->mach->gpio_pullup) { + if (gpio_is_valid(dev->mach->gpio_pullup)) { if ((retval = gpio_request(dev->mach->gpio_pullup, "pca25x_udc GPIO PULLUP"))) { dev_dbg(&pdev->dev, @@ -2256,10 +2258,10 @@ lubbock_fail0: #endif free_irq(irq, dev); err_irq1: - if (dev->mach->gpio_pullup) + if (gpio_is_valid(dev->mach->gpio_pullup)) gpio_free(dev->mach->gpio_pullup); err_gpio_pullup: - if (dev->mach->gpio_vbus) + if (gpio_is_valid(dev->mach->gpio_vbus)) gpio_free(dev->mach->gpio_vbus); err_gpio_vbus: clk_put(dev->clk); @@ -2294,11 +2296,11 @@ static int __exit pxa25x_udc_remove(struct platform_device *pdev) free_irq(LUBBOCK_USB_IRQ, dev); } #endif - if (dev->mach->gpio_vbus) { + if (gpio_is_valid(dev->mach->gpio_vbus)) { free_irq(gpio_to_irq(dev->mach->gpio_vbus), dev); gpio_free(dev->mach->gpio_vbus); } - if (dev->mach->gpio_pullup) + if (gpio_is_valid(dev->mach->gpio_pullup)) gpio_free(dev->mach->gpio_pullup); clk_put(dev->clk); @@ -2329,7 +2331,7 @@ static int pxa25x_udc_suspend(struct platform_device *dev, pm_message_t state) struct pxa25x_udc *udc = platform_get_drvdata(dev); unsigned long flags; - if (!udc->mach->gpio_pullup && !udc->mach->udc_command) + if (!gpio_is_valid(udc->mach->gpio_pullup) && !udc->mach->udc_command) WARNING("USB host won't detect disconnect!\n"); udc->suspended = 1; diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c index 2b4660e08c4..ca41b0b5afb 100644 --- a/drivers/usb/gadget/rndis.c +++ b/drivers/usb/gadget/rndis.c @@ -442,6 +442,8 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, case OID_802_3_MAC_OPTIONS: pr_debug("%s: OID_802_3_MAC_OPTIONS\n", __func__); + *outbuf = cpu_to_le32(0); + retval = 0; break; /* ieee802.3 statistics OIDs (table 4-4) */ diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c index 9a2b8920532..a9b452fe622 100644 --- a/drivers/usb/gadget/s3c2410_udc.c +++ b/drivers/usb/gadget/s3c2410_udc.c @@ -28,7 +28,6 @@ #include <linux/ioport.h> #include <linux/sched.h> #include <linux/slab.h> -#include <linux/smp_lock.h> #include <linux/errno.h> #include <linux/init.h> #include <linux/timer.h> diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 0c03471f0d4..1a920c70b5a 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -181,26 +181,27 @@ config USB_OHCI_HCD_PPC_SOC Enables support for the USB controller on the MPC52xx or STB03xxx processor chip. If unsure, say Y. -config USB_OHCI_HCD_PPC_OF - bool "OHCI support for PPC USB controller on OF platform bus" - depends on USB_OHCI_HCD && PPC_OF - default y - ---help--- - Enables support for the USB controller PowerPC present on the - OpenFirmware platform bus. - config USB_OHCI_HCD_PPC_OF_BE - bool "Support big endian HC" - depends on USB_OHCI_HCD_PPC_OF - default y + bool "OHCI support for OF platform bus (big endian)" + depends on USB_OHCI_HCD && PPC_OF select USB_OHCI_BIG_ENDIAN_DESC select USB_OHCI_BIG_ENDIAN_MMIO + ---help--- + Enables support for big-endian USB controllers present on the + OpenFirmware platform bus. config USB_OHCI_HCD_PPC_OF_LE - bool "Support little endian HC" - depends on USB_OHCI_HCD_PPC_OF - default n + bool "OHCI support for OF platform bus (little endian)" + depends on USB_OHCI_HCD && PPC_OF select USB_OHCI_LITTLE_ENDIAN + ---help--- + Enables support for little-endian USB controllers present on the + OpenFirmware platform bus. + +config USB_OHCI_HCD_PPC_OF + bool + depends on USB_OHCI_HCD && PPC_OF + default USB_OHCI_HCD_PPC_OF_BE || USB_OHCI_HCD_PPC_OF_LE config USB_OHCI_HCD_PCI bool "OHCI support for PCI-bus USB controllers" diff --git a/drivers/usb/host/ehci-au1xxx.c b/drivers/usb/host/ehci-au1xxx.c index c3a778bd359..59d208d94d4 100644 --- a/drivers/usb/host/ehci-au1xxx.c +++ b/drivers/usb/host/ehci-au1xxx.c @@ -113,6 +113,8 @@ static const struct hc_driver ehci_au1xxx_hc_driver = { .bus_resume = ehci_bus_resume, .relinquish_port = ehci_relinquish_port, .port_handed_over = ehci_port_handed_over, + + .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, }; static int ehci_hcd_au1xxx_drv_probe(struct platform_device *pdev) diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index bf86809c512..991174937db 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -325,6 +325,8 @@ static const struct hc_driver ehci_fsl_hc_driver = { .bus_resume = ehci_bus_resume, .relinquish_port = ehci_relinquish_port, .port_handed_over = ehci_port_handed_over, + + .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, }; static int ehci_fsl_drv_probe(struct platform_device *pdev) diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 2b72473544d..7d03549c333 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -1003,6 +1003,8 @@ idle_timeout: schedule_timeout_uninterruptible(1); goto rescan; case QH_STATE_IDLE: /* fully unlinked */ + if (qh->clearing_tt) + goto idle_timeout; if (list_empty (&qh->qtd_list)) { qh_put (qh); break; @@ -1030,12 +1032,14 @@ ehci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep) struct ehci_hcd *ehci = hcd_to_ehci(hcd); struct ehci_qh *qh; int eptype = usb_endpoint_type(&ep->desc); + int epnum = usb_endpoint_num(&ep->desc); + int is_out = usb_endpoint_dir_out(&ep->desc); + unsigned long flags; if (eptype != USB_ENDPOINT_XFER_BULK && eptype != USB_ENDPOINT_XFER_INT) return; - rescan: - spin_lock_irq(&ehci->lock); + spin_lock_irqsave(&ehci->lock, flags); qh = ep->hcpriv; /* For Bulk and Interrupt endpoints we maintain the toggle state @@ -1044,29 +1048,24 @@ ehci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep) * the toggle bit in the QH. */ if (qh) { + usb_settoggle(qh->dev, epnum, is_out, 0); if (!list_empty(&qh->qtd_list)) { WARN_ONCE(1, "clear_halt for a busy endpoint\n"); - } else if (qh->qh_state == QH_STATE_IDLE) { - qh->hw_token &= ~cpu_to_hc32(ehci, QTD_TOGGLE); - } else { - /* It's not safe to write into the overlay area - * while the QH is active. Unlink it first and - * wait for the unlink to complete. + } else if (qh->qh_state == QH_STATE_LINKED) { + + /* The toggle value in the QH can't be updated + * while the QH is active. Unlink it now; + * re-linking will call qh_refresh(). */ - if (qh->qh_state == QH_STATE_LINKED) { - if (eptype == USB_ENDPOINT_XFER_BULK) { - unlink_async(ehci, qh); - } else { - intr_deschedule(ehci, qh); - (void) qh_schedule(ehci, qh); - } + if (eptype == USB_ENDPOINT_XFER_BULK) { + unlink_async(ehci, qh); + } else { + intr_deschedule(ehci, qh); + (void) qh_schedule(ehci, qh); } - spin_unlock_irq(&ehci->lock); - schedule_timeout_uninterruptible(1); - goto rescan; } } - spin_unlock_irq(&ehci->lock); + spin_unlock_irqrestore(&ehci->lock, flags); } static int ehci_get_frame (struct usb_hcd *hcd) diff --git a/drivers/usb/host/ehci-ixp4xx.c b/drivers/usb/host/ehci-ixp4xx.c index a44bb4a9495..89b7c70c6ed 100644 --- a/drivers/usb/host/ehci-ixp4xx.c +++ b/drivers/usb/host/ehci-ixp4xx.c @@ -61,6 +61,8 @@ static const struct hc_driver ixp4xx_ehci_hc_driver = { #endif .relinquish_port = ehci_relinquish_port, .port_handed_over = ehci_port_handed_over, + + .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, }; static int ixp4xx_ehci_probe(struct platform_device *pdev) diff --git a/drivers/usb/host/ehci-orion.c b/drivers/usb/host/ehci-orion.c index 770dd9aba62..dc2ac613a9d 100644 --- a/drivers/usb/host/ehci-orion.c +++ b/drivers/usb/host/ehci-orion.c @@ -165,6 +165,8 @@ static const struct hc_driver ehci_orion_hc_driver = { .bus_resume = ehci_bus_resume, .relinquish_port = ehci_relinquish_port, .port_handed_over = ehci_port_handed_over, + + .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, }; static void __init diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index f3683e1da16..c2f1b7df918 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -404,6 +404,8 @@ static const struct hc_driver ehci_pci_hc_driver = { .bus_resume = ehci_bus_resume, .relinquish_port = ehci_relinquish_port, .port_handed_over = ehci_port_handed_over, + + .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, }; /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/ehci-ppc-of.c b/drivers/usb/host/ehci-ppc-of.c index fbd272288fc..36f96da129f 100644 --- a/drivers/usb/host/ehci-ppc-of.c +++ b/drivers/usb/host/ehci-ppc-of.c @@ -79,6 +79,8 @@ static const struct hc_driver ehci_ppc_of_hc_driver = { #endif .relinquish_port = ehci_relinquish_port, .port_handed_over = ehci_port_handed_over, + + .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, }; diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c index 93f7035d00a..1dee33b9139 100644 --- a/drivers/usb/host/ehci-ps3.c +++ b/drivers/usb/host/ehci-ps3.c @@ -75,6 +75,8 @@ static const struct hc_driver ps3_ehci_hc_driver = { #endif .relinquish_port = ehci_relinquish_port, .port_handed_over = ehci_port_handed_over, + + .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, }; static int __devinit ps3_ehci_probe(struct ps3_system_bus_device *dev) diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 3192f683f80..9a1384747f3 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -93,6 +93,22 @@ qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd) qh->hw_qtd_next = QTD_NEXT(ehci, qtd->qtd_dma); qh->hw_alt_next = EHCI_LIST_END(ehci); + /* Except for control endpoints, we make hardware maintain data + * toggle (like OHCI) ... here (re)initialize the toggle in the QH, + * and set the pseudo-toggle in udev. Only usb_clear_halt() will + * ever clear it. + */ + if (!(qh->hw_info1 & cpu_to_hc32(ehci, 1 << 14))) { + unsigned is_out, epnum; + + is_out = !(qtd->hw_token & cpu_to_hc32(ehci, 1 << 8)); + epnum = (hc32_to_cpup(ehci, &qh->hw_info1) >> 8) & 0x0f; + if (unlikely (!usb_gettoggle (qh->dev, epnum, is_out))) { + qh->hw_token &= ~cpu_to_hc32(ehci, QTD_TOGGLE); + usb_settoggle (qh->dev, epnum, is_out, 1); + } + } + /* HC must see latest qtd and qh data before we clear ACTIVE+HALT */ wmb (); qh->hw_token &= cpu_to_hc32(ehci, QTD_TOGGLE | QTD_STS_PING); @@ -123,6 +139,55 @@ qh_refresh (struct ehci_hcd *ehci, struct ehci_qh *qh) /*-------------------------------------------------------------------------*/ +static void qh_link_async(struct ehci_hcd *ehci, struct ehci_qh *qh); + +static void ehci_clear_tt_buffer_complete(struct usb_hcd *hcd, + struct usb_host_endpoint *ep) +{ + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + struct ehci_qh *qh = ep->hcpriv; + unsigned long flags; + + spin_lock_irqsave(&ehci->lock, flags); + qh->clearing_tt = 0; + if (qh->qh_state == QH_STATE_IDLE && !list_empty(&qh->qtd_list) + && HC_IS_RUNNING(hcd->state)) + qh_link_async(ehci, qh); + spin_unlock_irqrestore(&ehci->lock, flags); +} + +static void ehci_clear_tt_buffer(struct ehci_hcd *ehci, struct ehci_qh *qh, + struct urb *urb, u32 token) +{ + + /* If an async split transaction gets an error or is unlinked, + * the TT buffer may be left in an indeterminate state. We + * have to clear the TT buffer. + * + * Note: this routine is never called for Isochronous transfers. + */ + if (urb->dev->tt && !usb_pipeint(urb->pipe) && !qh->clearing_tt) { +#ifdef DEBUG + struct usb_device *tt = urb->dev->tt->hub; + dev_dbg(&tt->dev, + "clear tt buffer port %d, a%d ep%d t%08x\n", + urb->dev->ttport, urb->dev->devnum, + usb_pipeendpoint(urb->pipe), token); +#endif /* DEBUG */ + if (!ehci_is_TDI(ehci) + || urb->dev->tt->hub != + ehci_to_hcd(ehci)->self.root_hub) { + if (usb_hub_clear_tt_buffer(urb) == 0) + qh->clearing_tt = 1; + } else { + + /* REVISIT ARC-derived cores don't clear the root + * hub TT buffer in this way... + */ + } + } +} + static int qtd_copy_status ( struct ehci_hcd *ehci, struct urb *urb, @@ -149,6 +214,14 @@ static int qtd_copy_status ( if (token & QTD_STS_BABBLE) { /* FIXME "must" disable babbling device's port too */ status = -EOVERFLOW; + /* CERR nonzero + halt --> stall */ + } else if (QTD_CERR(token)) { + status = -EPIPE; + + /* In theory, more than one of the following bits can be set + * since they are sticky and the transaction is retried. + * Which to test first is rather arbitrary. + */ } else if (token & QTD_STS_MMF) { /* fs/ls interrupt xfer missed the complete-split */ status = -EPROTO; @@ -157,21 +230,15 @@ static int qtd_copy_status ( ? -ENOSR /* hc couldn't read data */ : -ECOMM; /* hc couldn't write data */ } else if (token & QTD_STS_XACT) { - /* timeout, bad crc, wrong PID, etc; retried */ - if (QTD_CERR (token)) - status = -EPIPE; - else { - ehci_dbg (ehci, "devpath %s ep%d%s 3strikes\n", - urb->dev->devpath, - usb_pipeendpoint (urb->pipe), - usb_pipein (urb->pipe) ? "in" : "out"); - status = -EPROTO; - } - /* CERR nonzero + no errors + halt --> stall */ - } else if (QTD_CERR (token)) - status = -EPIPE; - else /* unknown */ + /* timeout, bad CRC, wrong PID, etc */ + ehci_dbg(ehci, "devpath %s ep%d%s 3strikes\n", + urb->dev->devpath, + usb_pipeendpoint(urb->pipe), + usb_pipein(urb->pipe) ? "in" : "out"); + status = -EPROTO; + } else { /* unknown */ status = -EPROTO; + } ehci_vdbg (ehci, "dev%d ep%d%s qtd token %08x --> status %d\n", @@ -179,28 +246,6 @@ static int qtd_copy_status ( usb_pipeendpoint (urb->pipe), usb_pipein (urb->pipe) ? "in" : "out", token, status); - - /* if async CSPLIT failed, try cleaning out the TT buffer */ - if (status != -EPIPE - && urb->dev->tt - && !usb_pipeint(urb->pipe) - && ((token & QTD_STS_MMF) != 0 - || QTD_CERR(token) == 0) - && (!ehci_is_TDI(ehci) - || urb->dev->tt->hub != - ehci_to_hcd(ehci)->self.root_hub)) { -#ifdef DEBUG - struct usb_device *tt = urb->dev->tt->hub; - dev_dbg (&tt->dev, - "clear tt buffer port %d, a%d ep%d t%08x\n", - urb->dev->ttport, urb->dev->devnum, - usb_pipeendpoint (urb->pipe), token); -#endif /* DEBUG */ - /* REVISIT ARC-derived cores don't clear the root - * hub TT buffer in this way... - */ - usb_hub_tt_clear_buffer (urb->dev, urb->pipe); - } } return status; @@ -391,9 +436,16 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) /* qh unlinked; token in overlay may be most current */ if (state == QH_STATE_IDLE && cpu_to_hc32(ehci, qtd->qtd_dma) - == qh->hw_current) + == qh->hw_current) { token = hc32_to_cpu(ehci, qh->hw_token); + /* An unlink may leave an incomplete + * async transaction in the TT buffer. + * We have to clear it. + */ + ehci_clear_tt_buffer(ehci, qh, urb, token); + } + /* force halt for unlinked or blocked qh, so we'll * patch the qh later and so that completions can't * activate it while we "know" it's stopped. @@ -419,6 +471,13 @@ halt: && (qtd->hw_alt_next & EHCI_LIST_END(ehci))) last_status = -EINPROGRESS; + + /* As part of low/full-speed endpoint-halt processing + * we must clear the TT buffer (11.17.5). + */ + if (unlikely(last_status != -EINPROGRESS && + last_status != -EREMOTEIO)) + ehci_clear_tt_buffer(ehci, qh, urb, token); } /* if we're removing something not at the queue head, @@ -834,6 +893,7 @@ done: qh->qh_state = QH_STATE_IDLE; qh->hw_info1 = cpu_to_hc32(ehci, info1); qh->hw_info2 = cpu_to_hc32(ehci, info2); + usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), !is_input, 1); qh_refresh (ehci, qh); return qh; } @@ -847,6 +907,10 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh) __hc32 dma = QH_NEXT(ehci, qh->qh_dma); struct ehci_qh *head; + /* Don't link a QH if there's a Clear-TT-Buffer pending */ + if (unlikely(qh->clearing_tt)) + return; + /* (re)start the async schedule? */ head = ehci->async; timer_action_done (ehci, TIMER_ASYNC_OFF); @@ -864,7 +928,7 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh) } } - /* clear halt and maybe recover from silicon quirk */ + /* clear halt and/or toggle; and maybe recover from silicon quirk */ if (qh->qh_state == QH_STATE_IDLE) qh_refresh (ehci, qh); diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index 9d1babc7ff6..74f7f83b29a 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -1619,11 +1619,14 @@ itd_complete ( desc->status = -EPROTO; /* HC need not update length with this error */ - if (!(t & EHCI_ISOC_BABBLE)) - desc->actual_length = EHCI_ITD_LENGTH (t); + if (!(t & EHCI_ISOC_BABBLE)) { + desc->actual_length = EHCI_ITD_LENGTH(t); + urb->actual_length += desc->actual_length; + } } else if (likely ((t & EHCI_ISOC_ACTIVE) == 0)) { desc->status = 0; - desc->actual_length = EHCI_ITD_LENGTH (t); + desc->actual_length = EHCI_ITD_LENGTH(t); + urb->actual_length += desc->actual_length; } else { /* URB was too late */ desc->status = -EXDEV; @@ -2014,7 +2017,8 @@ sitd_complete ( desc->status = -EPROTO; } else { desc->status = 0; - desc->actual_length = desc->length - SITD_LENGTH (t); + desc->actual_length = desc->length - SITD_LENGTH(t); + urb->actual_length += desc->actual_length; } stream->depth -= stream->interval << 3; diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index 90ad3395bb2..2bfff30f470 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -354,7 +354,9 @@ struct ehci_qh { unsigned short period; /* polling interval */ unsigned short start; /* where polling starts */ #define NO_FRAME ((unsigned short)~0) /* pick new start */ + struct usb_device *dev; /* access to TT */ + unsigned clearing_tt:1; /* Clear-TT-Buf in progress */ } __attribute__ ((aligned (32))); /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/fhci-sched.c b/drivers/usb/host/fhci-sched.c index bb63b68ddb7..62a226b6167 100644 --- a/drivers/usb/host/fhci-sched.c +++ b/drivers/usb/host/fhci-sched.c @@ -576,9 +576,7 @@ irqreturn_t fhci_irq(struct usb_hcd *hcd) out_be16(&usb->fhci->regs->usb_event, usb->saved_msk); } else if (usb->port_status == FHCI_PORT_DISABLED) { - if (fhci_ioports_check_bus_state(fhci) == 1 && - usb->port_status != FHCI_PORT_LOW && - usb->port_status != FHCI_PORT_FULL) + if (fhci_ioports_check_bus_state(fhci) == 1) fhci_device_connected_interrupt(fhci); } usb_er &= ~USB_E_RESET_MASK; @@ -605,9 +603,7 @@ irqreturn_t fhci_irq(struct usb_hcd *hcd) } if (usb_er & USB_E_IDLE_MASK) { - if (usb->port_status == FHCI_PORT_DISABLED && - usb->port_status != FHCI_PORT_LOW && - usb->port_status != FHCI_PORT_FULL) { + if (usb->port_status == FHCI_PORT_DISABLED) { usb_er &= ~USB_E_RESET_MASK; fhci_device_connected_interrupt(fhci); } else if (usb->port_status == diff --git a/drivers/usb/host/isp1760-if.c b/drivers/usb/host/isp1760-if.c index 3fa3a170279..d4feebfc63b 100644 --- a/drivers/usb/host/isp1760-if.c +++ b/drivers/usb/host/isp1760-if.c @@ -361,7 +361,7 @@ static int __devexit isp1760_plat_remove(struct platform_device *pdev) static struct platform_driver isp1760_plat_driver = { .probe = isp1760_plat_probe, - .remove = isp1760_plat_remove, + .remove = __devexit_p(isp1760_plat_remove), .driver = { .name = "isp1760", }, diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index 56976cc0352..e18f74946e6 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -26,7 +26,6 @@ #include <linux/module.h> #include <linux/kernel.h> #include <linux/sched.h> -#include <linux/smp_lock.h> #include <linux/errno.h> #include <linux/init.h> #include <linux/timer.h> diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c index 3c5fe5cee05..90e1a8dedfa 100644 --- a/drivers/usb/misc/iowarrior.c +++ b/drivers/usb/misc/iowarrior.c @@ -18,6 +18,7 @@ #include <linux/init.h> #include <linux/slab.h> #include <linux/sched.h> +#include <linux/smp_lock.h> #include <linux/poll.h> #include <linux/usb/iowarrior.h> diff --git a/drivers/usb/misc/rio500.c b/drivers/usb/misc/rio500.c index deb95bb49fd..d645f3899fe 100644 --- a/drivers/usb/misc/rio500.c +++ b/drivers/usb/misc/rio500.c @@ -32,6 +32,7 @@ #include <linux/kernel.h> #include <linux/signal.h> #include <linux/sched.h> +#include <linux/smp_lock.h> #include <linux/errno.h> #include <linux/random.h> #include <linux/poll.h> diff --git a/drivers/usb/misc/usblcd.c b/drivers/usb/misc/usblcd.c index e0ff9ccd866..29092b8e59c 100644 --- a/drivers/usb/misc/usblcd.c +++ b/drivers/usb/misc/usblcd.c @@ -16,6 +16,7 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/slab.h> +#include <linux/smp_lock.h> #include <linux/errno.h> #include <linux/mutex.h> #include <asm/uaccess.h> diff --git a/drivers/usb/musb/cppi_dma.h b/drivers/usb/musb/cppi_dma.h index 8a39de3e6e4..59bf949e589 100644 --- a/drivers/usb/musb/cppi_dma.h +++ b/drivers/usb/musb/cppi_dma.h @@ -5,7 +5,6 @@ #include <linux/slab.h> #include <linux/list.h> -#include <linux/smp_lock.h> #include <linux/errno.h> #include <linux/dmapool.h> diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c index 180d7daa409..e16ff605c45 100644 --- a/drivers/usb/musb/davinci.c +++ b/drivers/usb/musb/davinci.c @@ -35,13 +35,14 @@ #include <mach/hardware.h> #include <mach/memory.h> #include <mach/gpio.h> +#include <mach/cputype.h> #include <asm/mach-types.h> #include "musb_core.h" #ifdef CONFIG_MACH_DAVINCI_EVM -#define GPIO_nVBUS_DRV 87 +#define GPIO_nVBUS_DRV 144 #endif #include "davinci.h" @@ -329,7 +330,6 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci) mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); WARNING("VBUS error workaround (delay coming)\n"); } else if (is_host_enabled(musb) && drvvbus) { - musb->is_active = 1; MUSB_HST_MODE(musb); musb->xceiv->default_a = 1; musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; @@ -343,7 +343,9 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci) portstate(musb->port1_status &= ~USB_PORT_STAT_POWER); } - /* NOTE: this must complete poweron within 100 msec */ + /* NOTE: this must complete poweron within 100 msec + * (OTG_TIME_A_WAIT_VRISE) but we don't check for that. + */ davinci_source_power(musb, drvvbus, 0); DBG(2, "VBUS %s (%s)%s, devctl %02x\n", drvvbus ? "on" : "off", @@ -411,6 +413,21 @@ int __init musb_platform_init(struct musb *musb) __raw_writel(phy_ctrl, USB_PHY_CTRL); } + /* On dm355, the default-A state machine needs DRVVBUS control. + * If we won't be a host, there's no need to turn it on. + */ + if (cpu_is_davinci_dm355()) { + u32 deepsleep = __raw_readl(DM355_DEEPSLEEP); + + if (is_host_enabled(musb)) { + deepsleep &= ~DRVVBUS_OVERRIDE; + } else { + deepsleep &= ~DRVVBUS_FORCE; + deepsleep |= DRVVBUS_OVERRIDE; + } + __raw_writel(deepsleep, DM355_DEEPSLEEP); + } + /* reset the controller */ musb_writel(tibase, DAVINCI_USB_CTRL_REG, 0x1); @@ -437,6 +454,15 @@ int musb_platform_exit(struct musb *musb) if (is_host_enabled(musb)) del_timer_sync(&otg_workaround); + /* force VBUS off */ + if (cpu_is_davinci_dm355()) { + u32 deepsleep = __raw_readl(DM355_DEEPSLEEP); + + deepsleep &= ~DRVVBUS_FORCE; + deepsleep |= DRVVBUS_OVERRIDE; + __raw_writel(deepsleep, DM355_DEEPSLEEP); + } + davinci_source_power(musb, 0 /*off*/, 1); /* delay, to avoid problems with module reload */ diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index f3772ca3b2c..381d648a36b 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -38,7 +38,6 @@ #include <linux/slab.h> #include <linux/list.h> #include <linux/interrupt.h> -#include <linux/smp_lock.h> #include <linux/errno.h> #include <linux/timer.h> #include <linux/clk.h> diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index 94a2a350a41..cf94511485f 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -373,7 +373,7 @@ static void musb_advance_schedule(struct musb *musb, struct urb *urb, musb_save_toggle(qh, is_in, urb); break; case USB_ENDPOINT_XFER_ISOC: - if (urb->error_count) + if (status == 0 && urb->error_count) status = -EXDEV; break; } @@ -2235,13 +2235,30 @@ static void musb_h_stop(struct usb_hcd *hcd) static int musb_bus_suspend(struct usb_hcd *hcd) { struct musb *musb = hcd_to_musb(hcd); + u8 devctl; - if (musb->xceiv->state == OTG_STATE_A_SUSPEND) + if (!is_host_active(musb)) return 0; - if (is_host_active(musb) && musb->is_active) { - WARNING("trying to suspend as %s is_active=%i\n", - otg_state_string(musb), musb->is_active); + switch (musb->xceiv->state) { + case OTG_STATE_A_SUSPEND: + return 0; + case OTG_STATE_A_WAIT_VRISE: + /* ID could be grounded even if there's no device + * on the other end of the cable. NOTE that the + * A_WAIT_VRISE timers are messy with MUSB... + */ + devctl = musb_readb(musb->mregs, MUSB_DEVCTL); + if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) + musb->xceiv->state = OTG_STATE_A_WAIT_BCON; + break; + default: + break; + } + + if (musb->is_active) { + WARNING("trying to suspend as %s while active\n", + otg_state_string(musb)); return -EBUSY; } else return 0; diff --git a/drivers/usb/otg/Kconfig b/drivers/usb/otg/Kconfig index 69feeec1628..aa884d072f0 100644 --- a/drivers/usb/otg/Kconfig +++ b/drivers/usb/otg/Kconfig @@ -59,18 +59,4 @@ config NOP_USB_XCEIV built-in with usb ip or which are autonomous and doesn't require any phy programming such as ISP1x04 etc. -config USB_LANGWELL_OTG - tristate "Intel Langwell USB OTG dual-role support" - depends on USB && MRST - select USB_OTG - select USB_OTG_UTILS - help - Say Y here if you want to build Intel Langwell USB OTG - transciever driver in kernel. This driver implements role - switch between EHCI host driver and Langwell USB OTG - client driver. - - To compile this driver as a module, choose M here: the - module will be called langwell_otg. - endif # USB || OTG diff --git a/drivers/usb/otg/Makefile b/drivers/usb/otg/Makefile index 6d1abdd3c0a..20816785652 100644 --- a/drivers/usb/otg/Makefile +++ b/drivers/usb/otg/Makefile @@ -9,7 +9,6 @@ obj-$(CONFIG_USB_OTG_UTILS) += otg.o obj-$(CONFIG_USB_GPIO_VBUS) += gpio_vbus.o obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o obj-$(CONFIG_TWL4030_USB) += twl4030-usb.o -obj-$(CONFIG_USB_LANGWELL_OTG) += langwell_otg.o obj-$(CONFIG_NOP_USB_XCEIV) += nop-usb-xceiv.o ccflags-$(CONFIG_USB_DEBUG) += -DDEBUG diff --git a/drivers/usb/otg/langwell_otg.c b/drivers/usb/otg/langwell_otg.c deleted file mode 100644 index 6f628d0e9f3..00000000000 --- a/drivers/usb/otg/langwell_otg.c +++ /dev/null @@ -1,1915 +0,0 @@ -/* - * Intel Langwell USB OTG transceiver driver - * Copyright (C) 2008 - 2009, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - */ -/* This driver helps to switch Langwell OTG controller function between host - * and peripheral. It works with EHCI driver and Langwell client controller - * driver together. - */ -#include <linux/module.h> -#include <linux/init.h> -#include <linux/pci.h> -#include <linux/errno.h> -#include <linux/interrupt.h> -#include <linux/kernel.h> -#include <linux/device.h> -#include <linux/moduleparam.h> -#include <linux/usb/ch9.h> -#include <linux/usb/gadget.h> -#include <linux/usb.h> -#include <linux/usb/otg.h> -#include <linux/notifier.h> -#include <asm/ipc_defs.h> -#include <linux/delay.h> -#include "../core/hcd.h" - -#include <linux/usb/langwell_otg.h> - -#define DRIVER_DESC "Intel Langwell USB OTG transceiver driver" -#define DRIVER_VERSION "3.0.0.32L.0002" - -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_AUTHOR("Henry Yuan <hang.yuan@intel.com>, Hao Wu <hao.wu@intel.com>"); -MODULE_VERSION(DRIVER_VERSION); -MODULE_LICENSE("GPL"); - -static const char driver_name[] = "langwell_otg"; - -static int langwell_otg_probe(struct pci_dev *pdev, - const struct pci_device_id *id); -static void langwell_otg_remove(struct pci_dev *pdev); -static int langwell_otg_suspend(struct pci_dev *pdev, pm_message_t message); -static int langwell_otg_resume(struct pci_dev *pdev); - -static int langwell_otg_set_host(struct otg_transceiver *otg, - struct usb_bus *host); -static int langwell_otg_set_peripheral(struct otg_transceiver *otg, - struct usb_gadget *gadget); -static int langwell_otg_start_srp(struct otg_transceiver *otg); - -static const struct pci_device_id pci_ids[] = {{ - .class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe), - .class_mask = ~0, - .vendor = 0x8086, - .device = 0x0811, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, -}, { /* end: all zeroes */ } -}; - -static struct pci_driver otg_pci_driver = { - .name = (char *) driver_name, - .id_table = pci_ids, - - .probe = langwell_otg_probe, - .remove = langwell_otg_remove, - - .suspend = langwell_otg_suspend, - .resume = langwell_otg_resume, -}; - -static const char *state_string(enum usb_otg_state state) -{ - switch (state) { - case OTG_STATE_A_IDLE: - return "a_idle"; - case OTG_STATE_A_WAIT_VRISE: - return "a_wait_vrise"; - case OTG_STATE_A_WAIT_BCON: - return "a_wait_bcon"; - case OTG_STATE_A_HOST: - return "a_host"; - case OTG_STATE_A_SUSPEND: - return "a_suspend"; - case OTG_STATE_A_PERIPHERAL: - return "a_peripheral"; - case OTG_STATE_A_WAIT_VFALL: - return "a_wait_vfall"; - case OTG_STATE_A_VBUS_ERR: - return "a_vbus_err"; - case OTG_STATE_B_IDLE: - return "b_idle"; - case OTG_STATE_B_SRP_INIT: - return "b_srp_init"; - case OTG_STATE_B_PERIPHERAL: - return "b_peripheral"; - case OTG_STATE_B_WAIT_ACON: - return "b_wait_acon"; - case OTG_STATE_B_HOST: - return "b_host"; - default: - return "UNDEFINED"; - } -} - -/* HSM timers */ -static inline struct langwell_otg_timer *otg_timer_initializer -(void (*function)(unsigned long), unsigned long expires, unsigned long data) -{ - struct langwell_otg_timer *timer; - timer = kmalloc(sizeof(struct langwell_otg_timer), GFP_KERNEL); - timer->function = function; - timer->expires = expires; - timer->data = data; - return timer; -} - -static struct langwell_otg_timer *a_wait_vrise_tmr, *a_wait_bcon_tmr, - *a_aidl_bdis_tmr, *b_ase0_brst_tmr, *b_se0_srp_tmr, *b_srp_res_tmr, - *b_bus_suspend_tmr; - -static struct list_head active_timers; - -static struct langwell_otg *the_transceiver; - -/* host/client notify transceiver when event affects HNP state */ -void langwell_update_transceiver() -{ - otg_dbg("transceiver driver is notified\n"); - queue_work(the_transceiver->qwork, &the_transceiver->work); -} -EXPORT_SYMBOL(langwell_update_transceiver); - -static int langwell_otg_set_host(struct otg_transceiver *otg, - struct usb_bus *host) -{ - otg->host = host; - - return 0; -} - -static int langwell_otg_set_peripheral(struct otg_transceiver *otg, - struct usb_gadget *gadget) -{ - otg->gadget = gadget; - - return 0; -} - -static int langwell_otg_set_power(struct otg_transceiver *otg, - unsigned mA) -{ - return 0; -} - -/* A-device drives vbus, controlled through PMIC CHRGCNTL register*/ -static void langwell_otg_drv_vbus(int on) -{ - struct ipc_pmic_reg_data pmic_data = {0}; - struct ipc_pmic_reg_data battery_data; - - /* Check if battery is attached or not */ - battery_data.pmic_reg_data[0].register_address = 0xd2; - battery_data.ioc = 0; - battery_data.num_entries = 1; - if (ipc_pmic_register_read(&battery_data)) { - otg_dbg("Failed to read PMIC register 0xd2.\n"); - return; - } - - if ((battery_data.pmic_reg_data[0].value & 0x20) == 0) { - otg_dbg("no battery attached\n"); - return; - } - - /* Workaround for battery attachment issue */ - if (battery_data.pmic_reg_data[0].value == 0x34) { - otg_dbg("battery \n"); - return; - } - - otg_dbg("battery attached\n"); - - pmic_data.ioc = 0; - pmic_data.pmic_reg_data[0].register_address = 0xD4; - pmic_data.num_entries = 1; - if (on) - pmic_data.pmic_reg_data[0].value = 0x20; - else - pmic_data.pmic_reg_data[0].value = 0xc0; - - if (ipc_pmic_register_write(&pmic_data, TRUE)) - otg_dbg("Failed to write PMIC.\n"); - -} - -/* charge vbus or discharge vbus through a resistor to ground */ -static void langwell_otg_chrg_vbus(int on) -{ - - u32 val; - - val = readl(the_transceiver->regs + CI_OTGSC); - - if (on) - writel((val & ~OTGSC_INTSTS_MASK) | OTGSC_VC, - the_transceiver->regs + CI_OTGSC); - else - writel((val & ~OTGSC_INTSTS_MASK) | OTGSC_VD, - the_transceiver->regs + CI_OTGSC); - -} - -/* Start SRP */ -static int langwell_otg_start_srp(struct otg_transceiver *otg) -{ - u32 val; - - otg_dbg("Start SRP ->\n"); - - val = readl(the_transceiver->regs + CI_OTGSC); - - writel((val & ~OTGSC_INTSTS_MASK) | OTGSC_HADP, - the_transceiver->regs + CI_OTGSC); - - /* Check if the data plus is finished or not */ - msleep(8); - val = readl(the_transceiver->regs + CI_OTGSC); - if (val & (OTGSC_HADP | OTGSC_DP)) - otg_dbg("DataLine SRP Error\n"); - - /* FIXME: VBus SRP */ - - return 0; -} - - -/* stop SOF via bus_suspend */ -static void langwell_otg_loc_sof(int on) -{ - struct usb_hcd *hcd; - int err; - - otg_dbg("loc_sof -> %d\n", on); - - hcd = bus_to_hcd(the_transceiver->otg.host); - if (on) - err = hcd->driver->bus_resume(hcd); - else - err = hcd->driver->bus_suspend(hcd); - - if (err) - otg_dbg("Failed to resume/suspend bus - %d\n", err); -} - -static void langwell_otg_phy_low_power(int on) -{ - u32 val; - - otg_dbg("phy low power mode-> %d\n", on); - - val = readl(the_transceiver->regs + CI_HOSTPC1); - if (on) - writel(val | HOSTPC1_PHCD, the_transceiver->regs + CI_HOSTPC1); - else - writel(val & ~HOSTPC1_PHCD, the_transceiver->regs + CI_HOSTPC1); -} - -/* Enable/Disable OTG interrupt */ -static void langwell_otg_intr(int on) -{ - u32 val; - - otg_dbg("interrupt -> %d\n", on); - - val = readl(the_transceiver->regs + CI_OTGSC); - if (on) { - val = val | (OTGSC_INTEN_MASK | OTGSC_IDPU); - writel(val, the_transceiver->regs + CI_OTGSC); - } else { - val = val & ~(OTGSC_INTEN_MASK | OTGSC_IDPU); - writel(val, the_transceiver->regs + CI_OTGSC); - } -} - -/* set HAAR: Hardware Assist Auto-Reset */ -static void langwell_otg_HAAR(int on) -{ - u32 val; - - otg_dbg("HAAR -> %d\n", on); - - val = readl(the_transceiver->regs + CI_OTGSC); - if (on) - writel((val & ~OTGSC_INTSTS_MASK) | OTGSC_HAAR, - the_transceiver->regs + CI_OTGSC); - else - writel((val & ~OTGSC_INTSTS_MASK) & ~OTGSC_HAAR, - the_transceiver->regs + CI_OTGSC); -} - -/* set HABA: Hardware Assist B-Disconnect to A-Connect */ -static void langwell_otg_HABA(int on) -{ - u32 val; - - otg_dbg("HABA -> %d\n", on); - - val = readl(the_transceiver->regs + CI_OTGSC); - if (on) - writel((val & ~OTGSC_INTSTS_MASK) | OTGSC_HABA, - the_transceiver->regs + CI_OTGSC); - else - writel((val & ~OTGSC_INTSTS_MASK) & ~OTGSC_HABA, - the_transceiver->regs + CI_OTGSC); -} - -static int langwell_otg_check_se0_srp(int on) -{ - u32 val; - - int delay_time = TB_SE0_SRP * 10; /* step is 100us */ - - otg_dbg("check_se0_srp -> \n"); - - do { - udelay(100); - if (!delay_time--) - break; - val = readl(the_transceiver->regs + CI_PORTSC1); - val &= PORTSC_LS; - } while (!val); - - otg_dbg("check_se0_srp <- \n"); - return val; -} - -/* The timeout callback function to set time out bit */ -static void set_tmout(unsigned long indicator) -{ - *(int *)indicator = 1; -} - -void langwell_otg_nsf_msg(unsigned long indicator) -{ - switch (indicator) { - case 2: - case 4: - case 6: - case 7: - printk(KERN_ERR "OTG:NSF-%lu - deivce not responding\n", - indicator); - break; - case 3: - printk(KERN_ERR "OTG:NSF-%lu - deivce not supported\n", - indicator); - break; - default: - printk(KERN_ERR "Do not have this kind of NSF\n"); - break; - } -} - -/* Initialize timers */ -static void langwell_otg_init_timers(struct otg_hsm *hsm) -{ - /* HSM used timers */ - a_wait_vrise_tmr = otg_timer_initializer(&set_tmout, TA_WAIT_VRISE, - (unsigned long)&hsm->a_wait_vrise_tmout); - a_wait_bcon_tmr = otg_timer_initializer(&set_tmout, TA_WAIT_BCON, - (unsigned long)&hsm->a_wait_bcon_tmout); - a_aidl_bdis_tmr = otg_timer_initializer(&set_tmout, TA_AIDL_BDIS, - (unsigned long)&hsm->a_aidl_bdis_tmout); - b_ase0_brst_tmr = otg_timer_initializer(&set_tmout, TB_ASE0_BRST, - (unsigned long)&hsm->b_ase0_brst_tmout); - b_se0_srp_tmr = otg_timer_initializer(&set_tmout, TB_SE0_SRP, - (unsigned long)&hsm->b_se0_srp); - b_srp_res_tmr = otg_timer_initializer(&set_tmout, TB_SRP_RES, - (unsigned long)&hsm->b_srp_res_tmout); - b_bus_suspend_tmr = otg_timer_initializer(&set_tmout, TB_BUS_SUSPEND, - (unsigned long)&hsm->b_bus_suspend_tmout); -} - -/* Free timers */ -static void langwell_otg_free_timers(void) -{ - kfree(a_wait_vrise_tmr); - kfree(a_wait_bcon_tmr); - kfree(a_aidl_bdis_tmr); - kfree(b_ase0_brst_tmr); - kfree(b_se0_srp_tmr); - kfree(b_srp_res_tmr); - kfree(b_bus_suspend_tmr); -} - -/* Add timer to timer list */ -static void langwell_otg_add_timer(void *gtimer) -{ - struct langwell_otg_timer *timer = (struct langwell_otg_timer *)gtimer; - struct langwell_otg_timer *tmp_timer; - u32 val32; - - /* Check if the timer is already in the active list, - * if so update timer count - */ - list_for_each_entry(tmp_timer, &active_timers, list) - if (tmp_timer == timer) { - timer->count = timer->expires; - return; - } - timer->count = timer->expires; - - if (list_empty(&active_timers)) { - val32 = readl(the_transceiver->regs + CI_OTGSC); - writel(val32 | OTGSC_1MSE, the_transceiver->regs + CI_OTGSC); - } - - list_add_tail(&timer->list, &active_timers); -} - -/* Remove timer from the timer list; clear timeout status */ -static void langwell_otg_del_timer(void *gtimer) -{ - struct langwell_otg_timer *timer = (struct langwell_otg_timer *)gtimer; - struct langwell_otg_timer *tmp_timer, *del_tmp; - u32 val32; - - list_for_each_entry_safe(tmp_timer, del_tmp, &active_timers, list) - if (tmp_timer == timer) - list_del(&timer->list); - - if (list_empty(&active_timers)) { - val32 = readl(the_transceiver->regs + CI_OTGSC); - writel(val32 & ~OTGSC_1MSE, the_transceiver->regs + CI_OTGSC); - } -} - -/* Reduce timer count by 1, and find timeout conditions.*/ -static int langwell_otg_tick_timer(u32 *int_sts) -{ - struct langwell_otg_timer *tmp_timer, *del_tmp; - int expired = 0; - - list_for_each_entry_safe(tmp_timer, del_tmp, &active_timers, list) { - tmp_timer->count--; - /* check if timer expires */ - if (!tmp_timer->count) { - list_del(&tmp_timer->list); - tmp_timer->function(tmp_timer->data); - expired = 1; - } - } - - if (list_empty(&active_timers)) { - otg_dbg("tick timer: disable 1ms int\n"); - *int_sts = *int_sts & ~OTGSC_1MSE; - } - return expired; -} - -static void reset_otg(void) -{ - u32 val; - int delay_time = 1000; - - otg_dbg("reseting OTG controller ...\n"); - val = readl(the_transceiver->regs + CI_USBCMD); - writel(val | USBCMD_RST, the_transceiver->regs + CI_USBCMD); - do { - udelay(100); - if (!delay_time--) - otg_dbg("reset timeout\n"); - val = readl(the_transceiver->regs + CI_USBCMD); - val &= USBCMD_RST; - } while (val != 0); - otg_dbg("reset done.\n"); -} - -static void set_host_mode(void) -{ - u32 val; - - reset_otg(); - val = readl(the_transceiver->regs + CI_USBMODE); - val = (val & (~USBMODE_CM)) | USBMODE_HOST; - writel(val, the_transceiver->regs + CI_USBMODE); -} - -static void set_client_mode(void) -{ - u32 val; - - reset_otg(); - val = readl(the_transceiver->regs + CI_USBMODE); - val = (val & (~USBMODE_CM)) | USBMODE_DEVICE; - writel(val, the_transceiver->regs + CI_USBMODE); -} - -static void init_hsm(void) -{ - struct langwell_otg *langwell = the_transceiver; - u32 val32; - - /* read OTGSC after reset */ - val32 = readl(langwell->regs + CI_OTGSC); - otg_dbg("%s: OTGSC init value = 0x%x\n", __func__, val32); - - /* set init state */ - if (val32 & OTGSC_ID) { - langwell->hsm.id = 1; - langwell->otg.default_a = 0; - set_client_mode(); - langwell->otg.state = OTG_STATE_B_IDLE; - langwell_otg_drv_vbus(0); - } else { - langwell->hsm.id = 0; - langwell->otg.default_a = 1; - set_host_mode(); - langwell->otg.state = OTG_STATE_A_IDLE; - } - - /* set session indicator */ - if (val32 & OTGSC_BSE) - langwell->hsm.b_sess_end = 1; - if (val32 & OTGSC_BSV) - langwell->hsm.b_sess_vld = 1; - if (val32 & OTGSC_ASV) - langwell->hsm.a_sess_vld = 1; - if (val32 & OTGSC_AVV) - langwell->hsm.a_vbus_vld = 1; - - /* defautly power the bus */ - langwell->hsm.a_bus_req = 1; - langwell->hsm.a_bus_drop = 0; - /* defautly don't request bus as B device */ - langwell->hsm.b_bus_req = 0; - /* no system error */ - langwell->hsm.a_clr_err = 0; -} - -static irqreturn_t otg_dummy_irq(int irq, void *_dev) -{ - void __iomem *reg_base = _dev; - u32 val; - u32 int_mask = 0; - - val = readl(reg_base + CI_USBMODE); - if ((val & USBMODE_CM) != USBMODE_DEVICE) - return IRQ_NONE; - - val = readl(reg_base + CI_USBSTS); - int_mask = val & INTR_DUMMY_MASK; - - if (int_mask == 0) - return IRQ_NONE; - - /* clear hsm.b_conn here since host driver can't detect it - * otg_dummy_irq called means B-disconnect happened. - */ - if (the_transceiver->hsm.b_conn) { - the_transceiver->hsm.b_conn = 0; - if (spin_trylock(&the_transceiver->wq_lock)) { - queue_work(the_transceiver->qwork, - &the_transceiver->work); - spin_unlock(&the_transceiver->wq_lock); - } - } - /* Clear interrupts */ - writel(int_mask, reg_base + CI_USBSTS); - return IRQ_HANDLED; -} - -static irqreturn_t otg_irq(int irq, void *_dev) -{ - struct langwell_otg *langwell = _dev; - u32 int_sts, int_en; - u32 int_mask = 0; - int flag = 0; - - int_sts = readl(langwell->regs + CI_OTGSC); - int_en = (int_sts & OTGSC_INTEN_MASK) >> 8; - int_mask = int_sts & int_en; - if (int_mask == 0) - return IRQ_NONE; - - if (int_mask & OTGSC_IDIS) { - otg_dbg("%s: id change int\n", __func__); - langwell->hsm.id = (int_sts & OTGSC_ID) ? 1 : 0; - flag = 1; - } - if (int_mask & OTGSC_DPIS) { - otg_dbg("%s: data pulse int\n", __func__); - langwell->hsm.a_srp_det = (int_sts & OTGSC_DPS) ? 1 : 0; - flag = 1; - } - if (int_mask & OTGSC_BSEIS) { - otg_dbg("%s: b session end int\n", __func__); - langwell->hsm.b_sess_end = (int_sts & OTGSC_BSE) ? 1 : 0; - flag = 1; - } - if (int_mask & OTGSC_BSVIS) { - otg_dbg("%s: b session valid int\n", __func__); - langwell->hsm.b_sess_vld = (int_sts & OTGSC_BSV) ? 1 : 0; - flag = 1; - } - if (int_mask & OTGSC_ASVIS) { - otg_dbg("%s: a session valid int\n", __func__); - langwell->hsm.a_sess_vld = (int_sts & OTGSC_ASV) ? 1 : 0; - flag = 1; - } - if (int_mask & OTGSC_AVVIS) { - otg_dbg("%s: a vbus valid int\n", __func__); - langwell->hsm.a_vbus_vld = (int_sts & OTGSC_AVV) ? 1 : 0; - flag = 1; - } - - if (int_mask & OTGSC_1MSS) { - /* need to schedule otg_work if any timer is expired */ - if (langwell_otg_tick_timer(&int_sts)) - flag = 1; - } - - writel((int_sts & ~OTGSC_INTSTS_MASK) | int_mask, - langwell->regs + CI_OTGSC); - if (flag) - queue_work(langwell->qwork, &langwell->work); - - return IRQ_HANDLED; -} - -static void langwell_otg_work(struct work_struct *work) -{ - struct langwell_otg *langwell = container_of(work, - struct langwell_otg, work); - int retval; - - otg_dbg("%s: old state = %s\n", __func__, - state_string(langwell->otg.state)); - - switch (langwell->otg.state) { - case OTG_STATE_UNDEFINED: - case OTG_STATE_B_IDLE: - if (!langwell->hsm.id) { - langwell_otg_del_timer(b_srp_res_tmr); - langwell->otg.default_a = 1; - langwell->hsm.a_srp_det = 0; - - langwell_otg_chrg_vbus(0); - langwell_otg_drv_vbus(0); - - set_host_mode(); - langwell->otg.state = OTG_STATE_A_IDLE; - queue_work(langwell->qwork, &langwell->work); - } else if (langwell->hsm.b_srp_res_tmout) { - langwell->hsm.b_srp_res_tmout = 0; - langwell->hsm.b_bus_req = 0; - langwell_otg_nsf_msg(6); - } else if (langwell->hsm.b_sess_vld) { - langwell_otg_del_timer(b_srp_res_tmr); - langwell->hsm.b_sess_end = 0; - langwell->hsm.a_bus_suspend = 0; - - langwell_otg_chrg_vbus(0); - if (langwell->client_ops) { - langwell->client_ops->resume(langwell->pdev); - langwell->otg.state = OTG_STATE_B_PERIPHERAL; - } else - otg_dbg("client driver not loaded.\n"); - - } else if (langwell->hsm.b_bus_req && - (langwell->hsm.b_sess_end)) { - /* workaround for b_se0_srp detection */ - retval = langwell_otg_check_se0_srp(0); - if (retval) { - langwell->hsm.b_bus_req = 0; - otg_dbg("LS is not SE0, try again later\n"); - } else { - /* Start SRP */ - langwell_otg_start_srp(&langwell->otg); - langwell_otg_add_timer(b_srp_res_tmr); - } - } - break; - case OTG_STATE_B_SRP_INIT: - if (!langwell->hsm.id) { - langwell->otg.default_a = 1; - langwell->hsm.a_srp_det = 0; - - langwell_otg_drv_vbus(0); - langwell_otg_chrg_vbus(0); - - langwell->otg.state = OTG_STATE_A_IDLE; - queue_work(langwell->qwork, &langwell->work); - } else if (langwell->hsm.b_sess_vld) { - langwell_otg_chrg_vbus(0); - if (langwell->client_ops) { - langwell->client_ops->resume(langwell->pdev); - langwell->otg.state = OTG_STATE_B_PERIPHERAL; - } else - otg_dbg("client driver not loaded.\n"); - } - break; - case OTG_STATE_B_PERIPHERAL: - if (!langwell->hsm.id) { - langwell->otg.default_a = 1; - langwell->hsm.a_srp_det = 0; - - langwell_otg_drv_vbus(0); - langwell_otg_chrg_vbus(0); - set_host_mode(); - - if (langwell->client_ops) { - langwell->client_ops->suspend(langwell->pdev, - PMSG_FREEZE); - } else - otg_dbg("client driver has been removed.\n"); - - langwell->otg.state = OTG_STATE_A_IDLE; - queue_work(langwell->qwork, &langwell->work); - } else if (!langwell->hsm.b_sess_vld) { - langwell->hsm.b_hnp_enable = 0; - - if (langwell->client_ops) { - langwell->client_ops->suspend(langwell->pdev, - PMSG_FREEZE); - } else - otg_dbg("client driver has been removed.\n"); - - langwell->otg.state = OTG_STATE_B_IDLE; - } else if (langwell->hsm.b_bus_req && langwell->hsm.b_hnp_enable - && langwell->hsm.a_bus_suspend) { - - if (langwell->client_ops) { - langwell->client_ops->suspend(langwell->pdev, - PMSG_FREEZE); - } else - otg_dbg("client driver has been removed.\n"); - - langwell_otg_HAAR(1); - langwell->hsm.a_conn = 0; - - if (langwell->host_ops) { - langwell->host_ops->probe(langwell->pdev, - langwell->host_ops->id_table); - langwell->otg.state = OTG_STATE_B_WAIT_ACON; - } else - otg_dbg("host driver not loaded.\n"); - - langwell->hsm.a_bus_resume = 0; - langwell->hsm.b_ase0_brst_tmout = 0; - langwell_otg_add_timer(b_ase0_brst_tmr); - } - break; - - case OTG_STATE_B_WAIT_ACON: - if (!langwell->hsm.id) { - langwell_otg_del_timer(b_ase0_brst_tmr); - langwell->otg.default_a = 1; - langwell->hsm.a_srp_det = 0; - - langwell_otg_drv_vbus(0); - langwell_otg_chrg_vbus(0); - set_host_mode(); - - langwell_otg_HAAR(0); - if (langwell->host_ops) - langwell->host_ops->remove(langwell->pdev); - else - otg_dbg("host driver has been removed.\n"); - langwell->otg.state = OTG_STATE_A_IDLE; - queue_work(langwell->qwork, &langwell->work); - } else if (!langwell->hsm.b_sess_vld) { - langwell_otg_del_timer(b_ase0_brst_tmr); - langwell->hsm.b_hnp_enable = 0; - langwell->hsm.b_bus_req = 0; - langwell_otg_chrg_vbus(0); - langwell_otg_HAAR(0); - - if (langwell->host_ops) - langwell->host_ops->remove(langwell->pdev); - else - otg_dbg("host driver has been removed.\n"); - langwell->otg.state = OTG_STATE_B_IDLE; - } else if (langwell->hsm.a_conn) { - langwell_otg_del_timer(b_ase0_brst_tmr); - langwell_otg_HAAR(0); - langwell->otg.state = OTG_STATE_B_HOST; - queue_work(langwell->qwork, &langwell->work); - } else if (langwell->hsm.a_bus_resume || - langwell->hsm.b_ase0_brst_tmout) { - langwell_otg_del_timer(b_ase0_brst_tmr); - langwell_otg_HAAR(0); - langwell_otg_nsf_msg(7); - - if (langwell->host_ops) - langwell->host_ops->remove(langwell->pdev); - else - otg_dbg("host driver has been removed.\n"); - - langwell->hsm.a_bus_suspend = 0; - langwell->hsm.b_bus_req = 0; - - if (langwell->client_ops) - langwell->client_ops->resume(langwell->pdev); - else - otg_dbg("client driver not loaded.\n"); - - langwell->otg.state = OTG_STATE_B_PERIPHERAL; - } - break; - - case OTG_STATE_B_HOST: - if (!langwell->hsm.id) { - langwell->otg.default_a = 1; - langwell->hsm.a_srp_det = 0; - - langwell_otg_drv_vbus(0); - langwell_otg_chrg_vbus(0); - set_host_mode(); - if (langwell->host_ops) - langwell->host_ops->remove(langwell->pdev); - else - otg_dbg("host driver has been removed.\n"); - langwell->otg.state = OTG_STATE_A_IDLE; - queue_work(langwell->qwork, &langwell->work); - } else if (!langwell->hsm.b_sess_vld) { - langwell->hsm.b_hnp_enable = 0; - langwell->hsm.b_bus_req = 0; - langwell_otg_chrg_vbus(0); - if (langwell->host_ops) - langwell->host_ops->remove(langwell->pdev); - else - otg_dbg("host driver has been removed.\n"); - langwell->otg.state = OTG_STATE_B_IDLE; - } else if ((!langwell->hsm.b_bus_req) || - (!langwell->hsm.a_conn)) { - langwell->hsm.b_bus_req = 0; - langwell_otg_loc_sof(0); - if (langwell->host_ops) - langwell->host_ops->remove(langwell->pdev); - else - otg_dbg("host driver has been removed.\n"); - - langwell->hsm.a_bus_suspend = 0; - - if (langwell->client_ops) - langwell->client_ops->resume(langwell->pdev); - else - otg_dbg("client driver not loaded.\n"); - - langwell->otg.state = OTG_STATE_B_PERIPHERAL; - } - break; - - case OTG_STATE_A_IDLE: - langwell->otg.default_a = 1; - if (langwell->hsm.id) { - langwell->otg.default_a = 0; - langwell->hsm.b_bus_req = 0; - langwell_otg_drv_vbus(0); - langwell_otg_chrg_vbus(0); - - langwell->otg.state = OTG_STATE_B_IDLE; - queue_work(langwell->qwork, &langwell->work); - } else if (langwell->hsm.a_sess_vld) { - langwell_otg_drv_vbus(1); - langwell->hsm.a_srp_det = 1; - langwell->hsm.a_wait_vrise_tmout = 0; - langwell_otg_add_timer(a_wait_vrise_tmr); - langwell->otg.state = OTG_STATE_A_WAIT_VRISE; - queue_work(langwell->qwork, &langwell->work); - } else if (!langwell->hsm.a_bus_drop && - (langwell->hsm.a_srp_det || langwell->hsm.a_bus_req)) { - langwell_otg_drv_vbus(1); - langwell->hsm.a_wait_vrise_tmout = 0; - langwell_otg_add_timer(a_wait_vrise_tmr); - langwell->otg.state = OTG_STATE_A_WAIT_VRISE; - queue_work(langwell->qwork, &langwell->work); - } - break; - case OTG_STATE_A_WAIT_VRISE: - if (langwell->hsm.id) { - langwell_otg_del_timer(a_wait_vrise_tmr); - langwell->hsm.b_bus_req = 0; - langwell->otg.default_a = 0; - langwell_otg_drv_vbus(0); - langwell->otg.state = OTG_STATE_B_IDLE; - } else if (langwell->hsm.a_vbus_vld) { - langwell_otg_del_timer(a_wait_vrise_tmr); - if (langwell->host_ops) - langwell->host_ops->probe(langwell->pdev, - langwell->host_ops->id_table); - else - otg_dbg("host driver not loaded.\n"); - langwell->hsm.b_conn = 0; - langwell->hsm.a_set_b_hnp_en = 0; - langwell->hsm.a_wait_bcon_tmout = 0; - langwell_otg_add_timer(a_wait_bcon_tmr); - langwell->otg.state = OTG_STATE_A_WAIT_BCON; - } else if (langwell->hsm.a_wait_vrise_tmout) { - if (langwell->hsm.a_vbus_vld) { - if (langwell->host_ops) - langwell->host_ops->probe( - langwell->pdev, - langwell->host_ops->id_table); - else - otg_dbg("host driver not loaded.\n"); - langwell->hsm.b_conn = 0; - langwell->hsm.a_set_b_hnp_en = 0; - langwell->hsm.a_wait_bcon_tmout = 0; - langwell_otg_add_timer(a_wait_bcon_tmr); - langwell->otg.state = OTG_STATE_A_WAIT_BCON; - } else { - langwell_otg_drv_vbus(0); - langwell->otg.state = OTG_STATE_A_VBUS_ERR; - } - } - break; - case OTG_STATE_A_WAIT_BCON: - if (langwell->hsm.id) { - langwell_otg_del_timer(a_wait_bcon_tmr); - - langwell->otg.default_a = 0; - langwell->hsm.b_bus_req = 0; - if (langwell->host_ops) - langwell->host_ops->remove(langwell->pdev); - else - otg_dbg("host driver has been removed.\n"); - langwell_otg_drv_vbus(0); - langwell->otg.state = OTG_STATE_B_IDLE; - queue_work(langwell->qwork, &langwell->work); - } else if (!langwell->hsm.a_vbus_vld) { - langwell_otg_del_timer(a_wait_bcon_tmr); - - if (langwell->host_ops) - langwell->host_ops->remove(langwell->pdev); - else - otg_dbg("host driver has been removed.\n"); - langwell_otg_drv_vbus(0); - langwell->otg.state = OTG_STATE_A_VBUS_ERR; - } else if (langwell->hsm.a_bus_drop || - (langwell->hsm.a_wait_bcon_tmout && - !langwell->hsm.a_bus_req)) { - langwell_otg_del_timer(a_wait_bcon_tmr); - - if (langwell->host_ops) - langwell->host_ops->remove(langwell->pdev); - else - otg_dbg("host driver has been removed.\n"); - langwell_otg_drv_vbus(0); - langwell->otg.state = OTG_STATE_A_WAIT_VFALL; - } else if (langwell->hsm.b_conn) { - langwell_otg_del_timer(a_wait_bcon_tmr); - - langwell->hsm.a_suspend_req = 0; - langwell->otg.state = OTG_STATE_A_HOST; - if (!langwell->hsm.a_bus_req && - langwell->hsm.a_set_b_hnp_en) { - /* It is not safe enough to do a fast - * transistion from A_WAIT_BCON to - * A_SUSPEND */ - msleep(10000); - if (langwell->hsm.a_bus_req) - break; - - if (request_irq(langwell->pdev->irq, - otg_dummy_irq, IRQF_SHARED, - driver_name, langwell->regs) != 0) { - otg_dbg("request interrupt %d fail\n", - langwell->pdev->irq); - } - - langwell_otg_HABA(1); - langwell->hsm.b_bus_resume = 0; - langwell->hsm.a_aidl_bdis_tmout = 0; - langwell_otg_add_timer(a_aidl_bdis_tmr); - - langwell_otg_loc_sof(0); - langwell->otg.state = OTG_STATE_A_SUSPEND; - } else if (!langwell->hsm.a_bus_req && - !langwell->hsm.a_set_b_hnp_en) { - struct pci_dev *pdev = langwell->pdev; - if (langwell->host_ops) - langwell->host_ops->remove(pdev); - else - otg_dbg("host driver removed.\n"); - langwell_otg_drv_vbus(0); - langwell->otg.state = OTG_STATE_A_WAIT_VFALL; - } - } - break; - case OTG_STATE_A_HOST: - if (langwell->hsm.id) { - langwell->otg.default_a = 0; - langwell->hsm.b_bus_req = 0; - if (langwell->host_ops) - langwell->host_ops->remove(langwell->pdev); - else - otg_dbg("host driver has been removed.\n"); - langwell_otg_drv_vbus(0); - langwell->otg.state = OTG_STATE_B_IDLE; - queue_work(langwell->qwork, &langwell->work); - } else if (langwell->hsm.a_bus_drop || - (!langwell->hsm.a_set_b_hnp_en && !langwell->hsm.a_bus_req)) { - if (langwell->host_ops) - langwell->host_ops->remove(langwell->pdev); - else - otg_dbg("host driver has been removed.\n"); - langwell_otg_drv_vbus(0); - langwell->otg.state = OTG_STATE_A_WAIT_VFALL; - } else if (!langwell->hsm.a_vbus_vld) { - if (langwell->host_ops) - langwell->host_ops->remove(langwell->pdev); - else - otg_dbg("host driver has been removed.\n"); - langwell_otg_drv_vbus(0); - langwell->otg.state = OTG_STATE_A_VBUS_ERR; - } else if (langwell->hsm.a_set_b_hnp_en - && !langwell->hsm.a_bus_req) { - /* Set HABA to enable hardware assistance to signal - * A-connect after receiver B-disconnect. Hardware - * will then set client mode and enable URE, SLE and - * PCE after the assistance. otg_dummy_irq is used to - * clean these ints when client driver is not resumed. - */ - if (request_irq(langwell->pdev->irq, - otg_dummy_irq, IRQF_SHARED, driver_name, - langwell->regs) != 0) { - otg_dbg("request interrupt %d failed\n", - langwell->pdev->irq); - } - - /* set HABA */ - langwell_otg_HABA(1); - langwell->hsm.b_bus_resume = 0; - langwell->hsm.a_aidl_bdis_tmout = 0; - langwell_otg_add_timer(a_aidl_bdis_tmr); - langwell_otg_loc_sof(0); - langwell->otg.state = OTG_STATE_A_SUSPEND; - } else if (!langwell->hsm.b_conn || !langwell->hsm.a_bus_req) { - langwell->hsm.a_wait_bcon_tmout = 0; - langwell->hsm.a_set_b_hnp_en = 0; - langwell_otg_add_timer(a_wait_bcon_tmr); - langwell->otg.state = OTG_STATE_A_WAIT_BCON; - } - break; - case OTG_STATE_A_SUSPEND: - if (langwell->hsm.id) { - langwell_otg_del_timer(a_aidl_bdis_tmr); - langwell_otg_HABA(0); - free_irq(langwell->pdev->irq, langwell->regs); - langwell->otg.default_a = 0; - langwell->hsm.b_bus_req = 0; - if (langwell->host_ops) - langwell->host_ops->remove(langwell->pdev); - else - otg_dbg("host driver has been removed.\n"); - langwell_otg_drv_vbus(0); - langwell->otg.state = OTG_STATE_B_IDLE; - queue_work(langwell->qwork, &langwell->work); - } else if (langwell->hsm.a_bus_req || - langwell->hsm.b_bus_resume) { - langwell_otg_del_timer(a_aidl_bdis_tmr); - langwell_otg_HABA(0); - free_irq(langwell->pdev->irq, langwell->regs); - langwell->hsm.a_suspend_req = 0; - langwell_otg_loc_sof(1); - langwell->otg.state = OTG_STATE_A_HOST; - } else if (langwell->hsm.a_aidl_bdis_tmout || - langwell->hsm.a_bus_drop) { - langwell_otg_del_timer(a_aidl_bdis_tmr); - langwell_otg_HABA(0); - free_irq(langwell->pdev->irq, langwell->regs); - if (langwell->host_ops) - langwell->host_ops->remove(langwell->pdev); - else - otg_dbg("host driver has been removed.\n"); - langwell_otg_drv_vbus(0); - langwell->otg.state = OTG_STATE_A_WAIT_VFALL; - } else if (!langwell->hsm.b_conn && - langwell->hsm.a_set_b_hnp_en) { - langwell_otg_del_timer(a_aidl_bdis_tmr); - langwell_otg_HABA(0); - free_irq(langwell->pdev->irq, langwell->regs); - - if (langwell->host_ops) - langwell->host_ops->remove(langwell->pdev); - else - otg_dbg("host driver has been removed.\n"); - - langwell->hsm.b_bus_suspend = 0; - langwell->hsm.b_bus_suspend_vld = 0; - langwell->hsm.b_bus_suspend_tmout = 0; - - /* msleep(200); */ - if (langwell->client_ops) - langwell->client_ops->resume(langwell->pdev); - else - otg_dbg("client driver not loaded.\n"); - - langwell_otg_add_timer(b_bus_suspend_tmr); - langwell->otg.state = OTG_STATE_A_PERIPHERAL; - break; - } else if (!langwell->hsm.a_vbus_vld) { - langwell_otg_del_timer(a_aidl_bdis_tmr); - langwell_otg_HABA(0); - free_irq(langwell->pdev->irq, langwell->regs); - if (langwell->host_ops) - langwell->host_ops->remove(langwell->pdev); - else - otg_dbg("host driver has been removed.\n"); - langwell_otg_drv_vbus(0); - langwell->otg.state = OTG_STATE_A_VBUS_ERR; - } - break; - case OTG_STATE_A_PERIPHERAL: - if (langwell->hsm.id) { - langwell_otg_del_timer(b_bus_suspend_tmr); - langwell->otg.default_a = 0; - langwell->hsm.b_bus_req = 0; - if (langwell->client_ops) - langwell->client_ops->suspend(langwell->pdev, - PMSG_FREEZE); - else - otg_dbg("client driver has been removed.\n"); - langwell_otg_drv_vbus(0); - langwell->otg.state = OTG_STATE_B_IDLE; - queue_work(langwell->qwork, &langwell->work); - } else if (!langwell->hsm.a_vbus_vld) { - langwell_otg_del_timer(b_bus_suspend_tmr); - if (langwell->client_ops) - langwell->client_ops->suspend(langwell->pdev, - PMSG_FREEZE); - else - otg_dbg("client driver has been removed.\n"); - langwell_otg_drv_vbus(0); - langwell->otg.state = OTG_STATE_A_VBUS_ERR; - } else if (langwell->hsm.a_bus_drop) { - langwell_otg_del_timer(b_bus_suspend_tmr); - if (langwell->client_ops) - langwell->client_ops->suspend(langwell->pdev, - PMSG_FREEZE); - else - otg_dbg("client driver has been removed.\n"); - langwell_otg_drv_vbus(0); - langwell->otg.state = OTG_STATE_A_WAIT_VFALL; - } else if (langwell->hsm.b_bus_suspend) { - langwell_otg_del_timer(b_bus_suspend_tmr); - if (langwell->client_ops) - langwell->client_ops->suspend(langwell->pdev, - PMSG_FREEZE); - else - otg_dbg("client driver has been removed.\n"); - - if (langwell->host_ops) - langwell->host_ops->probe(langwell->pdev, - langwell->host_ops->id_table); - else - otg_dbg("host driver not loaded.\n"); - langwell->hsm.a_set_b_hnp_en = 0; - langwell->hsm.a_wait_bcon_tmout = 0; - langwell_otg_add_timer(a_wait_bcon_tmr); - langwell->otg.state = OTG_STATE_A_WAIT_BCON; - } else if (langwell->hsm.b_bus_suspend_tmout) { - u32 val; - val = readl(langwell->regs + CI_PORTSC1); - if (!(val & PORTSC_SUSP)) - break; - if (langwell->client_ops) - langwell->client_ops->suspend(langwell->pdev, - PMSG_FREEZE); - else - otg_dbg("client driver has been removed.\n"); - if (langwell->host_ops) - langwell->host_ops->probe(langwell->pdev, - langwell->host_ops->id_table); - else - otg_dbg("host driver not loaded.\n"); - langwell->hsm.a_set_b_hnp_en = 0; - langwell->hsm.a_wait_bcon_tmout = 0; - langwell_otg_add_timer(a_wait_bcon_tmr); - langwell->otg.state = OTG_STATE_A_WAIT_BCON; - } - break; - case OTG_STATE_A_VBUS_ERR: - if (langwell->hsm.id) { - langwell->otg.default_a = 0; - langwell->hsm.a_clr_err = 0; - langwell->hsm.a_srp_det = 0; - langwell->otg.state = OTG_STATE_B_IDLE; - queue_work(langwell->qwork, &langwell->work); - } else if (langwell->hsm.a_clr_err) { - langwell->hsm.a_clr_err = 0; - langwell->hsm.a_srp_det = 0; - reset_otg(); - init_hsm(); - if (langwell->otg.state == OTG_STATE_A_IDLE) - queue_work(langwell->qwork, &langwell->work); - } - break; - case OTG_STATE_A_WAIT_VFALL: - if (langwell->hsm.id) { - langwell->otg.default_a = 0; - langwell->otg.state = OTG_STATE_B_IDLE; - queue_work(langwell->qwork, &langwell->work); - } else if (langwell->hsm.a_bus_req) { - langwell_otg_drv_vbus(1); - langwell->hsm.a_wait_vrise_tmout = 0; - langwell_otg_add_timer(a_wait_vrise_tmr); - langwell->otg.state = OTG_STATE_A_WAIT_VRISE; - } else if (!langwell->hsm.a_sess_vld) { - langwell->hsm.a_srp_det = 0; - langwell_otg_drv_vbus(0); - set_host_mode(); - langwell->otg.state = OTG_STATE_A_IDLE; - } - break; - default: - ; - } - - otg_dbg("%s: new state = %s\n", __func__, - state_string(langwell->otg.state)); -} - - static ssize_t -show_registers(struct device *_dev, struct device_attribute *attr, char *buf) -{ - struct langwell_otg *langwell; - char *next; - unsigned size; - unsigned t; - - langwell = the_transceiver; - next = buf; - size = PAGE_SIZE; - - t = scnprintf(next, size, - "\n" - "USBCMD = 0x%08x \n" - "USBSTS = 0x%08x \n" - "USBINTR = 0x%08x \n" - "ASYNCLISTADDR = 0x%08x \n" - "PORTSC1 = 0x%08x \n" - "HOSTPC1 = 0x%08x \n" - "OTGSC = 0x%08x \n" - "USBMODE = 0x%08x \n", - readl(langwell->regs + 0x30), - readl(langwell->regs + 0x34), - readl(langwell->regs + 0x38), - readl(langwell->regs + 0x48), - readl(langwell->regs + 0x74), - readl(langwell->regs + 0xb4), - readl(langwell->regs + 0xf4), - readl(langwell->regs + 0xf8) - ); - size -= t; - next += t; - - return PAGE_SIZE - size; -} -static DEVICE_ATTR(registers, S_IRUGO, show_registers, NULL); - -static ssize_t -show_hsm(struct device *_dev, struct device_attribute *attr, char *buf) -{ - struct langwell_otg *langwell; - char *next; - unsigned size; - unsigned t; - - langwell = the_transceiver; - next = buf; - size = PAGE_SIZE; - - t = scnprintf(next, size, - "\n" - "current state = %s\n" - "a_bus_resume = \t%d\n" - "a_bus_suspend = \t%d\n" - "a_conn = \t%d\n" - "a_sess_vld = \t%d\n" - "a_srp_det = \t%d\n" - "a_vbus_vld = \t%d\n" - "b_bus_resume = \t%d\n" - "b_bus_suspend = \t%d\n" - "b_conn = \t%d\n" - "b_se0_srp = \t%d\n" - "b_sess_end = \t%d\n" - "b_sess_vld = \t%d\n" - "id = \t%d\n" - "a_set_b_hnp_en = \t%d\n" - "b_srp_done = \t%d\n" - "b_hnp_enable = \t%d\n" - "a_wait_vrise_tmout = \t%d\n" - "a_wait_bcon_tmout = \t%d\n" - "a_aidl_bdis_tmout = \t%d\n" - "b_ase0_brst_tmout = \t%d\n" - "a_bus_drop = \t%d\n" - "a_bus_req = \t%d\n" - "a_clr_err = \t%d\n" - "a_suspend_req = \t%d\n" - "b_bus_req = \t%d\n" - "b_bus_suspend_tmout = \t%d\n" - "b_bus_suspend_vld = \t%d\n", - state_string(langwell->otg.state), - langwell->hsm.a_bus_resume, - langwell->hsm.a_bus_suspend, - langwell->hsm.a_conn, - langwell->hsm.a_sess_vld, - langwell->hsm.a_srp_det, - langwell->hsm.a_vbus_vld, - langwell->hsm.b_bus_resume, - langwell->hsm.b_bus_suspend, - langwell->hsm.b_conn, - langwell->hsm.b_se0_srp, - langwell->hsm.b_sess_end, - langwell->hsm.b_sess_vld, - langwell->hsm.id, - langwell->hsm.a_set_b_hnp_en, - langwell->hsm.b_srp_done, - langwell->hsm.b_hnp_enable, - langwell->hsm.a_wait_vrise_tmout, - langwell->hsm.a_wait_bcon_tmout, - langwell->hsm.a_aidl_bdis_tmout, - langwell->hsm.b_ase0_brst_tmout, - langwell->hsm.a_bus_drop, - langwell->hsm.a_bus_req, - langwell->hsm.a_clr_err, - langwell->hsm.a_suspend_req, - langwell->hsm.b_bus_req, - langwell->hsm.b_bus_suspend_tmout, - langwell->hsm.b_bus_suspend_vld - ); - size -= t; - next += t; - - return PAGE_SIZE - size; -} -static DEVICE_ATTR(hsm, S_IRUGO, show_hsm, NULL); - -static ssize_t -get_a_bus_req(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct langwell_otg *langwell; - char *next; - unsigned size; - unsigned t; - - langwell = the_transceiver; - next = buf; - size = PAGE_SIZE; - - t = scnprintf(next, size, "%d", langwell->hsm.a_bus_req); - size -= t; - next += t; - - return PAGE_SIZE - size; -} - -static ssize_t -set_a_bus_req(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct langwell_otg *langwell; - langwell = the_transceiver; - if (!langwell->otg.default_a) - return -1; - if (count > 2) - return -1; - - if (buf[0] == '0') { - langwell->hsm.a_bus_req = 0; - otg_dbg("a_bus_req = 0\n"); - } else if (buf[0] == '1') { - /* If a_bus_drop is TRUE, a_bus_req can't be set */ - if (langwell->hsm.a_bus_drop) - return -1; - langwell->hsm.a_bus_req = 1; - otg_dbg("a_bus_req = 1\n"); - } - if (spin_trylock(&langwell->wq_lock)) { - queue_work(langwell->qwork, &langwell->work); - spin_unlock(&langwell->wq_lock); - } - return count; -} -static DEVICE_ATTR(a_bus_req, S_IRUGO | S_IWUGO, get_a_bus_req, set_a_bus_req); - -static ssize_t -get_a_bus_drop(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct langwell_otg *langwell; - char *next; - unsigned size; - unsigned t; - - langwell = the_transceiver; - next = buf; - size = PAGE_SIZE; - - t = scnprintf(next, size, "%d", langwell->hsm.a_bus_drop); - size -= t; - next += t; - - return PAGE_SIZE - size; -} - -static ssize_t -set_a_bus_drop(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct langwell_otg *langwell; - langwell = the_transceiver; - if (!langwell->otg.default_a) - return -1; - if (count > 2) - return -1; - - if (buf[0] == '0') { - langwell->hsm.a_bus_drop = 0; - otg_dbg("a_bus_drop = 0\n"); - } else if (buf[0] == '1') { - langwell->hsm.a_bus_drop = 1; - langwell->hsm.a_bus_req = 0; - otg_dbg("a_bus_drop = 1, then a_bus_req = 0\n"); - } - if (spin_trylock(&langwell->wq_lock)) { - queue_work(langwell->qwork, &langwell->work); - spin_unlock(&langwell->wq_lock); - } - return count; -} -static DEVICE_ATTR(a_bus_drop, S_IRUGO | S_IWUGO, - get_a_bus_drop, set_a_bus_drop); - -static ssize_t -get_b_bus_req(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct langwell_otg *langwell; - char *next; - unsigned size; - unsigned t; - - langwell = the_transceiver; - next = buf; - size = PAGE_SIZE; - - t = scnprintf(next, size, "%d", langwell->hsm.b_bus_req); - size -= t; - next += t; - - return PAGE_SIZE - size; -} - -static ssize_t -set_b_bus_req(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct langwell_otg *langwell; - langwell = the_transceiver; - - if (langwell->otg.default_a) - return -1; - - if (count > 2) - return -1; - - if (buf[0] == '0') { - langwell->hsm.b_bus_req = 0; - otg_dbg("b_bus_req = 0\n"); - } else if (buf[0] == '1') { - langwell->hsm.b_bus_req = 1; - otg_dbg("b_bus_req = 1\n"); - } - if (spin_trylock(&langwell->wq_lock)) { - queue_work(langwell->qwork, &langwell->work); - spin_unlock(&langwell->wq_lock); - } - return count; -} -static DEVICE_ATTR(b_bus_req, S_IRUGO | S_IWUGO, get_b_bus_req, set_b_bus_req); - -static ssize_t -set_a_clr_err(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct langwell_otg *langwell; - langwell = the_transceiver; - - if (!langwell->otg.default_a) - return -1; - if (count > 2) - return -1; - - if (buf[0] == '1') { - langwell->hsm.a_clr_err = 1; - otg_dbg("a_clr_err = 1\n"); - } - if (spin_trylock(&langwell->wq_lock)) { - queue_work(langwell->qwork, &langwell->work); - spin_unlock(&langwell->wq_lock); - } - return count; -} -static DEVICE_ATTR(a_clr_err, S_IWUGO, NULL, set_a_clr_err); - -static struct attribute *inputs_attrs[] = { - &dev_attr_a_bus_req.attr, - &dev_attr_a_bus_drop.attr, - &dev_attr_b_bus_req.attr, - &dev_attr_a_clr_err.attr, - NULL, -}; - -static struct attribute_group debug_dev_attr_group = { - .name = "inputs", - .attrs = inputs_attrs, -}; - -int langwell_register_host(struct pci_driver *host_driver) -{ - int ret = 0; - - the_transceiver->host_ops = host_driver; - queue_work(the_transceiver->qwork, &the_transceiver->work); - otg_dbg("host controller driver is registered\n"); - - return ret; -} -EXPORT_SYMBOL(langwell_register_host); - -void langwell_unregister_host(struct pci_driver *host_driver) -{ - if (the_transceiver->host_ops) - the_transceiver->host_ops->remove(the_transceiver->pdev); - the_transceiver->host_ops = NULL; - the_transceiver->hsm.a_bus_drop = 1; - queue_work(the_transceiver->qwork, &the_transceiver->work); - otg_dbg("host controller driver is unregistered\n"); -} -EXPORT_SYMBOL(langwell_unregister_host); - -int langwell_register_peripheral(struct pci_driver *client_driver) -{ - int ret = 0; - - if (client_driver) - ret = client_driver->probe(the_transceiver->pdev, - client_driver->id_table); - if (!ret) { - the_transceiver->client_ops = client_driver; - queue_work(the_transceiver->qwork, &the_transceiver->work); - otg_dbg("client controller driver is registered\n"); - } - - return ret; -} -EXPORT_SYMBOL(langwell_register_peripheral); - -void langwell_unregister_peripheral(struct pci_driver *client_driver) -{ - if (the_transceiver->client_ops) - the_transceiver->client_ops->remove(the_transceiver->pdev); - the_transceiver->client_ops = NULL; - the_transceiver->hsm.b_bus_req = 0; - queue_work(the_transceiver->qwork, &the_transceiver->work); - otg_dbg("client controller driver is unregistered\n"); -} -EXPORT_SYMBOL(langwell_unregister_peripheral); - -static int langwell_otg_probe(struct pci_dev *pdev, - const struct pci_device_id *id) -{ - unsigned long resource, len; - void __iomem *base = NULL; - int retval; - u32 val32; - struct langwell_otg *langwell; - char qname[] = "langwell_otg_queue"; - - retval = 0; - otg_dbg("\notg controller is detected.\n"); - if (pci_enable_device(pdev) < 0) { - retval = -ENODEV; - goto done; - } - - langwell = kzalloc(sizeof *langwell, GFP_KERNEL); - if (langwell == NULL) { - retval = -ENOMEM; - goto done; - } - the_transceiver = langwell; - - /* control register: BAR 0 */ - resource = pci_resource_start(pdev, 0); - len = pci_resource_len(pdev, 0); - if (!request_mem_region(resource, len, driver_name)) { - retval = -EBUSY; - goto err; - } - langwell->region = 1; - - base = ioremap_nocache(resource, len); - if (base == NULL) { - retval = -EFAULT; - goto err; - } - langwell->regs = base; - - if (!pdev->irq) { - otg_dbg("No IRQ.\n"); - retval = -ENODEV; - goto err; - } - - langwell->qwork = create_workqueue(qname); - if (!langwell->qwork) { - otg_dbg("cannot create workqueue %s\n", qname); - retval = -ENOMEM; - goto err; - } - INIT_WORK(&langwell->work, langwell_otg_work); - - /* OTG common part */ - langwell->pdev = pdev; - langwell->otg.dev = &pdev->dev; - langwell->otg.label = driver_name; - langwell->otg.set_host = langwell_otg_set_host; - langwell->otg.set_peripheral = langwell_otg_set_peripheral; - langwell->otg.set_power = langwell_otg_set_power; - langwell->otg.start_srp = langwell_otg_start_srp; - langwell->otg.state = OTG_STATE_UNDEFINED; - if (otg_set_transceiver(&langwell->otg)) { - otg_dbg("can't set transceiver\n"); - retval = -EBUSY; - goto err; - } - - reset_otg(); - init_hsm(); - - spin_lock_init(&langwell->lock); - spin_lock_init(&langwell->wq_lock); - INIT_LIST_HEAD(&active_timers); - langwell_otg_init_timers(&langwell->hsm); - - if (request_irq(pdev->irq, otg_irq, IRQF_SHARED, - driver_name, langwell) != 0) { - otg_dbg("request interrupt %d failed\n", pdev->irq); - retval = -EBUSY; - goto err; - } - - /* enable OTGSC int */ - val32 = OTGSC_DPIE | OTGSC_BSEIE | OTGSC_BSVIE | - OTGSC_ASVIE | OTGSC_AVVIE | OTGSC_IDIE | OTGSC_IDPU; - writel(val32, langwell->regs + CI_OTGSC); - - retval = device_create_file(&pdev->dev, &dev_attr_registers); - if (retval < 0) { - otg_dbg("Can't register sysfs attribute: %d\n", retval); - goto err; - } - - retval = device_create_file(&pdev->dev, &dev_attr_hsm); - if (retval < 0) { - otg_dbg("Can't hsm sysfs attribute: %d\n", retval); - goto err; - } - - retval = sysfs_create_group(&pdev->dev.kobj, &debug_dev_attr_group); - if (retval < 0) { - otg_dbg("Can't register sysfs attr group: %d\n", retval); - goto err; - } - - if (langwell->otg.state == OTG_STATE_A_IDLE) - queue_work(langwell->qwork, &langwell->work); - - return 0; - -err: - if (the_transceiver) - langwell_otg_remove(pdev); -done: - return retval; -} - -static void langwell_otg_remove(struct pci_dev *pdev) -{ - struct langwell_otg *langwell; - - langwell = the_transceiver; - - if (langwell->qwork) { - flush_workqueue(langwell->qwork); - destroy_workqueue(langwell->qwork); - } - langwell_otg_free_timers(); - - /* disable OTGSC interrupt as OTGSC doesn't change in reset */ - writel(0, langwell->regs + CI_OTGSC); - - if (pdev->irq) - free_irq(pdev->irq, langwell); - if (langwell->regs) - iounmap(langwell->regs); - if (langwell->region) - release_mem_region(pci_resource_start(pdev, 0), - pci_resource_len(pdev, 0)); - - otg_set_transceiver(NULL); - pci_disable_device(pdev); - sysfs_remove_group(&pdev->dev.kobj, &debug_dev_attr_group); - device_remove_file(&pdev->dev, &dev_attr_hsm); - device_remove_file(&pdev->dev, &dev_attr_registers); - kfree(langwell); - langwell = NULL; -} - -static void transceiver_suspend(struct pci_dev *pdev) -{ - pci_save_state(pdev); - pci_set_power_state(pdev, PCI_D3hot); - langwell_otg_phy_low_power(1); -} - -static int langwell_otg_suspend(struct pci_dev *pdev, pm_message_t message) -{ - int ret = 0; - struct langwell_otg *langwell; - - langwell = the_transceiver; - - /* Disbale OTG interrupts */ - langwell_otg_intr(0); - - if (pdev->irq) - free_irq(pdev->irq, langwell); - - /* Prevent more otg_work */ - flush_workqueue(langwell->qwork); - spin_lock(&langwell->wq_lock); - - /* start actions */ - switch (langwell->otg.state) { - case OTG_STATE_A_IDLE: - case OTG_STATE_B_IDLE: - case OTG_STATE_A_WAIT_VFALL: - case OTG_STATE_A_VBUS_ERR: - transceiver_suspend(pdev); - break; - case OTG_STATE_A_WAIT_VRISE: - langwell_otg_del_timer(a_wait_vrise_tmr); - langwell->hsm.a_srp_det = 0; - langwell_otg_drv_vbus(0); - langwell->otg.state = OTG_STATE_A_IDLE; - transceiver_suspend(pdev); - break; - case OTG_STATE_A_WAIT_BCON: - langwell_otg_del_timer(a_wait_bcon_tmr); - if (langwell->host_ops) - ret = langwell->host_ops->suspend(pdev, message); - langwell_otg_drv_vbus(0); - break; - case OTG_STATE_A_HOST: - if (langwell->host_ops) - ret = langwell->host_ops->suspend(pdev, message); - langwell_otg_drv_vbus(0); - langwell_otg_phy_low_power(1); - break; - case OTG_STATE_A_SUSPEND: - langwell_otg_del_timer(a_aidl_bdis_tmr); - langwell_otg_HABA(0); - if (langwell->host_ops) - langwell->host_ops->remove(pdev); - else - otg_dbg("host driver has been removed.\n"); - langwell_otg_drv_vbus(0); - transceiver_suspend(pdev); - langwell->otg.state = OTG_STATE_A_WAIT_VFALL; - break; - case OTG_STATE_A_PERIPHERAL: - if (langwell->client_ops) - ret = langwell->client_ops->suspend(pdev, message); - else - otg_dbg("client driver has been removed.\n"); - langwell_otg_drv_vbus(0); - transceiver_suspend(pdev); - langwell->otg.state = OTG_STATE_A_WAIT_VFALL; - break; - case OTG_STATE_B_HOST: - if (langwell->host_ops) - langwell->host_ops->remove(pdev); - else - otg_dbg("host driver has been removed.\n"); - langwell->hsm.b_bus_req = 0; - transceiver_suspend(pdev); - langwell->otg.state = OTG_STATE_B_IDLE; - break; - case OTG_STATE_B_PERIPHERAL: - if (langwell->client_ops) - ret = langwell->client_ops->suspend(pdev, message); - else - otg_dbg("client driver has been removed.\n"); - break; - case OTG_STATE_B_WAIT_ACON: - langwell_otg_del_timer(b_ase0_brst_tmr); - langwell_otg_HAAR(0); - if (langwell->host_ops) - langwell->host_ops->remove(pdev); - else - otg_dbg("host driver has been removed.\n"); - langwell->hsm.b_bus_req = 0; - langwell->otg.state = OTG_STATE_B_IDLE; - transceiver_suspend(pdev); - break; - default: - otg_dbg("error state before suspend\n "); - break; - } - spin_unlock(&langwell->wq_lock); - - return ret; -} - -static void transceiver_resume(struct pci_dev *pdev) -{ - pci_restore_state(pdev); - pci_set_power_state(pdev, PCI_D0); - langwell_otg_phy_low_power(0); -} - -static int langwell_otg_resume(struct pci_dev *pdev) -{ - int ret = 0; - struct langwell_otg *langwell; - - langwell = the_transceiver; - - spin_lock(&langwell->wq_lock); - - switch (langwell->otg.state) { - case OTG_STATE_A_IDLE: - case OTG_STATE_B_IDLE: - case OTG_STATE_A_WAIT_VFALL: - case OTG_STATE_A_VBUS_ERR: - transceiver_resume(pdev); - break; - case OTG_STATE_A_WAIT_BCON: - langwell_otg_add_timer(a_wait_bcon_tmr); - langwell_otg_drv_vbus(1); - if (langwell->host_ops) - ret = langwell->host_ops->resume(pdev); - break; - case OTG_STATE_A_HOST: - langwell_otg_drv_vbus(1); - langwell_otg_phy_low_power(0); - if (langwell->host_ops) - ret = langwell->host_ops->resume(pdev); - break; - case OTG_STATE_B_PERIPHERAL: - if (langwell->client_ops) - ret = langwell->client_ops->resume(pdev); - else - otg_dbg("client driver not loaded.\n"); - break; - default: - otg_dbg("error state before suspend\n "); - break; - } - - if (request_irq(pdev->irq, otg_irq, IRQF_SHARED, - driver_name, the_transceiver) != 0) { - otg_dbg("request interrupt %d failed\n", pdev->irq); - ret = -EBUSY; - } - - /* enable OTG interrupts */ - langwell_otg_intr(1); - - spin_unlock(&langwell->wq_lock); - - queue_work(langwell->qwork, &langwell->work); - - - return ret; -} - -static int __init langwell_otg_init(void) -{ - return pci_register_driver(&otg_pci_driver); -} -module_init(langwell_otg_init); - -static void __exit langwell_otg_cleanup(void) -{ - pci_unregister_driver(&otg_pci_driver); -} -module_exit(langwell_otg_cleanup); diff --git a/drivers/usb/otg/nop-usb-xceiv.c b/drivers/usb/otg/nop-usb-xceiv.c index 9ed5ea56867..af456b48985 100644 --- a/drivers/usb/otg/nop-usb-xceiv.c +++ b/drivers/usb/otg/nop-usb-xceiv.c @@ -53,6 +53,7 @@ EXPORT_SYMBOL(usb_nop_xceiv_register); void usb_nop_xceiv_unregister(void) { platform_device_unregister(pd); + pd = NULL; } EXPORT_SYMBOL(usb_nop_xceiv_unregister); diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c index 247b61bfb7f..0e4f2e41ace 100644 --- a/drivers/usb/serial/console.c +++ b/drivers/usb/serial/console.c @@ -169,9 +169,11 @@ static int usb_console_setup(struct console *co, char *options) kfree(tty); } } - /* So we know not to kill the hardware on a hangup on this - port. We have also bumped the use count by one so it won't go - idle */ + /* Now that any required fake tty operations are completed restore + * the tty port count */ + --port->port.count; + /* The console is special in terms of closing the device so + * indicate this port is now acting as a system console. */ port->console = 1; retval = 0; @@ -204,7 +206,7 @@ static void usb_console_write(struct console *co, dbg("%s - port %d, %d byte(s)", __func__, port->number, count); - if (!port->port.count) { + if (!port->console) { dbg("%s - port not opened", __func__); return; } @@ -300,8 +302,7 @@ void usb_serial_console_exit(void) { if (usbcons_info.port) { unregister_console(&usbcons); - if (usbcons_info.port->port.count) - usbcons_info.port->port.count--; + usbcons_info.port->console = 0; usbcons_info.port = NULL; } } diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index 2b9eeda62bf..e9a40b820fd 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -67,6 +67,8 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */ { USB_DEVICE(0x10B5, 0xAC70) }, /* Nokia CA-42 USB */ { USB_DEVICE(0x10C4, 0x0F91) }, /* Vstabi */ + { USB_DEVICE(0x10C4, 0x1101) }, /* Arkham Technology DS101 Bus Monitor */ + { USB_DEVICE(0x10C4, 0x1601) }, /* Arkham Technology DS101 Adapter */ { USB_DEVICE(0x10C4, 0x800A) }, /* SPORTident BSM7-D-USB main station */ { USB_DEVICE(0x10C4, 0x803B) }, /* Pololu USB-serial converter */ { USB_DEVICE(0x10C4, 0x8053) }, /* Enfora EDG1228 */ diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index 9734085fd2f..59adfe12311 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@ -1228,8 +1228,8 @@ static void cypress_read_int_callback(struct urb *urb) /* precursor to disconnect so just go away */ return; case -EPIPE: - usb_clear_halt(port->serial->dev, 0x81); - break; + /* Can't call usb_clear_halt while in_interrupt */ + /* FALLS THROUGH */ default: /* something ugly is going on... */ dev_err(&urb->dev->dev, diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 3dc3768ca71..60c64cc5be2 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -33,6 +33,7 @@ #include <linux/errno.h> #include <linux/init.h> #include <linux/slab.h> +#include <linux/smp_lock.h> #include <linux/tty.h> #include <linux/tty_driver.h> #include <linux/tty_flip.h> @@ -107,6 +108,7 @@ struct ftdi_sio_quirk { static int ftdi_jtag_probe(struct usb_serial *serial); static int ftdi_mtxorb_hack_setup(struct usb_serial *serial); +static int ftdi_NDI_device_setup(struct usb_serial *serial); static void ftdi_USB_UIRT_setup(struct ftdi_private *priv); static void ftdi_HE_TIRA1_setup(struct ftdi_private *priv); @@ -118,6 +120,10 @@ static struct ftdi_sio_quirk ftdi_mtxorb_hack_quirk = { .probe = ftdi_mtxorb_hack_setup, }; +static struct ftdi_sio_quirk ftdi_NDI_device_quirk = { + .probe = ftdi_NDI_device_setup, +}; + static struct ftdi_sio_quirk ftdi_USB_UIRT_quirk = { .port_probe = ftdi_USB_UIRT_setup, }; @@ -191,6 +197,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_MTXORB_4_PID) }, { USB_DEVICE(FTDI_VID, FTDI_MTXORB_5_PID) }, { USB_DEVICE(FTDI_VID, FTDI_MTXORB_6_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_R2000KU_TRUE_RNG) }, { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0100_PID) }, { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0101_PID) }, { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0102_PID) }, @@ -579,6 +586,9 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_CCSICDU20_0_PID) }, { USB_DEVICE(FTDI_VID, FTDI_CCSICDU40_1_PID) }, { USB_DEVICE(FTDI_VID, FTDI_CCSMACHX_2_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CCSLOAD_N_GO_3_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CCSICDU64_4_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CCSPRIME8_5_PID) }, { USB_DEVICE(FTDI_VID, INSIDE_ACCESSO) }, { USB_DEVICE(INTREPID_VID, INTREPID_VALUECAN_PID) }, { USB_DEVICE(INTREPID_VID, INTREPID_NEOVI_PID) }, @@ -644,6 +654,16 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13S_PID) }, { USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13U_PID) }, { USB_DEVICE(ELEKTOR_VID, ELEKTOR_FT323R_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_NDI_HUC_PID), + .driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk }, + { USB_DEVICE(FTDI_VID, FTDI_NDI_SPECTRA_SCU_PID), + .driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk }, + { USB_DEVICE(FTDI_VID, FTDI_NDI_FUTURE_2_PID), + .driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk }, + { USB_DEVICE(FTDI_VID, FTDI_NDI_FUTURE_3_PID), + .driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk }, + { USB_DEVICE(FTDI_VID, FTDI_NDI_AURORA_SCU_PID), + .driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk }, { USB_DEVICE(TELLDUS_VID, TELLDUS_TELLSTICK_PID) }, { USB_DEVICE(FTDI_VID, FTDI_MAXSTREAM_PID) }, { USB_DEVICE(FTDI_VID, FTDI_PHI_FISCO_PID) }, @@ -660,6 +680,8 @@ static struct usb_device_id id_table_combined [] = { .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, { USB_DEVICE(FTDI_VID, LMI_LM3S_EVAL_BOARD_PID), .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, + { USB_DEVICE(FTDI_VID, FTDI_TURTELIZER_PID), + .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_USB60F) }, { USB_DEVICE(FTDI_VID, FTDI_REU_TINY_PID) }, { USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO4x4_PID) }, @@ -667,7 +689,6 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_DOMINTELL_DUSB_PID) }, { USB_DEVICE(ALTI2_VID, ALTI2_N3_PID) }, { USB_DEVICE(FTDI_VID, DIEBOLD_BCS_SE923_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_NDI_HUC_PID) }, { USB_DEVICE(ATMEL_VID, STK541_PID) }, { USB_DEVICE(DE_VID, STB_PID) }, { USB_DEVICE(DE_VID, WHT_PID) }, @@ -1023,6 +1044,16 @@ static __u32 get_ftdi_divisor(struct tty_struct *tty, case FT2232C: /* FT2232C chip */ case FT232RL: if (baud <= 3000000) { + __u16 product_id = le16_to_cpu( + port->serial->dev->descriptor.idProduct); + if (((FTDI_NDI_HUC_PID == product_id) || + (FTDI_NDI_SPECTRA_SCU_PID == product_id) || + (FTDI_NDI_FUTURE_2_PID == product_id) || + (FTDI_NDI_FUTURE_3_PID == product_id) || + (FTDI_NDI_AURORA_SCU_PID == product_id)) && + (baud == 19200)) { + baud = 1200000; + } div_value = ftdi_232bm_baud_to_divisor(baud); } else { dbg("%s - Baud rate too high!", __func__); @@ -1554,6 +1585,39 @@ static void ftdi_HE_TIRA1_setup(struct ftdi_private *priv) } /* ftdi_HE_TIRA1_setup */ /* + * Module parameter to control latency timer for NDI FTDI-based USB devices. + * If this value is not set in modprobe.conf.local its value will be set to 1ms. + */ +static int ndi_latency_timer = 1; + +/* Setup for the NDI FTDI-based USB devices, which requires hardwired + * baudrate (19200 gets mapped to 1200000). + * + * Called from usbserial:serial_probe. + */ +static int ftdi_NDI_device_setup(struct usb_serial *serial) +{ + struct usb_device *udev = serial->dev; + int latency = ndi_latency_timer; + int rv = 0; + char buf[1]; + + if (latency == 0) + latency = 1; + if (latency > 99) + latency = 99; + + dbg("%s setting NDI device latency to %d", __func__, latency); + dev_info(&udev->dev, "NDI device with a latency value of %d", latency); + + rv = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + FTDI_SIO_SET_LATENCY_TIMER_REQUEST, + FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE, + latency, 0, buf, 0, WDR_TIMEOUT); + return 0; +} + +/* * First port on JTAG adaptors such as Olimex arm-usb-ocd or the FIC/OpenMoko * Neo1973 Debug Board is reserved for JTAG interface and can be accessed from * userspace using openocd. @@ -2121,7 +2185,7 @@ static void ftdi_process_read(struct work_struct *work) /* Note that the error flag is duplicated for every character received since we don't know which character it applied to */ - if (!usb_serial_handle_sysrq_char(port, + if (!usb_serial_handle_sysrq_char(tty, port, data[packet_offset + i])) tty_insert_flip_char(tty, data[packet_offset + i], @@ -2622,3 +2686,5 @@ MODULE_PARM_DESC(vendor, "User specified vendor ID (default=" module_param(product, ushort, 0); MODULE_PARM_DESC(product, "User specified product ID"); +module_param(ndi_latency_timer, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(ndi_latency_timer, "NDI device latency timer override"); diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index f1d440a728a..c9fbd741509 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h @@ -506,6 +506,7 @@ * * Armin Laeuger originally sent the PID for the UM 100 module. */ +#define FTDI_R2000KU_TRUE_RNG 0xFB80 /* R2000KU TRUE RNG */ #define FTDI_ELV_UR100_PID 0xFB58 /* USB-RS232-Umsetzer (UR 100) */ #define FTDI_ELV_UM100_PID 0xFB5A /* USB-Modul UM 100 */ #define FTDI_ELV_UO100_PID 0xFB5B /* USB-Modul UO 100 */ @@ -614,6 +615,9 @@ #define FTDI_CCSICDU20_0_PID 0xF9D0 #define FTDI_CCSICDU40_1_PID 0xF9D1 #define FTDI_CCSMACHX_2_PID 0xF9D2 +#define FTDI_CCSLOAD_N_GO_3_PID 0xF9D3 +#define FTDI_CCSICDU64_4_PID 0xF9D4 +#define FTDI_CCSPRIME8_5_PID 0xF9D5 /* Inside Accesso contactless reader (http://www.insidefr.com) */ #define INSIDE_ACCESSO 0xFAD0 @@ -736,6 +740,15 @@ #define FTDI_PYRAMID_PID 0xE6C8 /* Pyramid Appliance Display */ /* + * NDI (www.ndigital.com) product ids + */ +#define FTDI_NDI_HUC_PID 0xDA70 /* NDI Host USB Converter */ +#define FTDI_NDI_SPECTRA_SCU_PID 0xDA71 /* NDI Spectra SCU */ +#define FTDI_NDI_FUTURE_2_PID 0xDA72 /* NDI future device #2 */ +#define FTDI_NDI_FUTURE_3_PID 0xDA73 /* NDI future device #3 */ +#define FTDI_NDI_AURORA_SCU_PID 0xDA74 /* NDI Aurora SCU */ + +/* * Posiflex inc retail equipment (http://www.posiflex.com.tw) */ #define POSIFLEX_VID 0x0d3a /* Vendor ID */ @@ -848,9 +861,6 @@ #define TML_VID 0x1B91 /* Vendor ID */ #define TML_USB_SERIAL_PID 0x0064 /* USB - Serial Converter */ -/* NDI Polaris System */ -#define FTDI_NDI_HUC_PID 0xDA70 - /* Propox devices */ #define FTDI_PROPOX_JTAGCABLEII_PID 0xD738 @@ -934,6 +944,8 @@ #define MARVELL_VID 0x9e88 #define MARVELL_SHEEVAPLUG_PID 0x9e8f +#define FTDI_TURTELIZER_PID 0xBDC8 /* JTAG/RS-232 adapter by egnite GmBH */ + /* * BmRequestType: 1100 0000b * bRequest: FTDI_E2_READ diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index 932d6241b78..ce57f6a32bd 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c @@ -424,10 +424,17 @@ static void flush_and_resubmit_read_urb(struct usb_serial_port *port) if (!tty) goto done; - /* Push data to tty */ - for (i = 0; i < urb->actual_length; i++, ch++) { - if (!usb_serial_handle_sysrq_char(port, *ch)) - tty_insert_flip_char(tty, *ch, TTY_NORMAL); + /* The per character mucking around with sysrq path it too slow for + stuff like 3G modems, so shortcircuit it in the 99.9999999% of cases + where the USB serial is not a console anyway */ + if (!port->console || !port->sysrq) + tty_insert_flip_string(tty, ch, urb->actual_length); + else { + /* Push data to tty */ + for (i = 0; i < urb->actual_length; i++, ch++) { + if (!usb_serial_handle_sysrq_char(tty, port, *ch)) + tty_insert_flip_char(tty, *ch, TTY_NORMAL); + } } tty_flip_buffer_push(tty); tty_kref_put(tty); @@ -527,11 +534,12 @@ void usb_serial_generic_unthrottle(struct tty_struct *tty) } } -int usb_serial_handle_sysrq_char(struct usb_serial_port *port, unsigned int ch) +int usb_serial_handle_sysrq_char(struct tty_struct *tty, + struct usb_serial_port *port, unsigned int ch) { if (port->sysrq && port->console) { if (ch && time_before(jiffies, port->sysrq)) { - handle_sysrq(ch, tty_port_tty_get(&port->port)); + handle_sysrq(ch, tty); port->sysrq = 0; return 1; } diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index c40f95c1951..c31940a307f 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -26,6 +26,7 @@ #include <linux/errno.h> #include <linux/init.h> #include <linux/slab.h> +#include <linux/smp_lock.h> #include <linux/tty.h> #include <linux/tty_driver.h> #include <linux/tty_flip.h> diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 575816e6ba3..98262dd552b 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -206,6 +206,7 @@ static int option_resume(struct usb_serial *serial); #define NOVATELWIRELESS_PRODUCT_MC950D 0x4400 #define NOVATELWIRELESS_PRODUCT_U727 0x5010 #define NOVATELWIRELESS_PRODUCT_MC760 0x6000 +#define NOVATELWIRELESS_PRODUCT_OVMC760 0x6002 /* FUTURE NOVATEL PRODUCTS */ #define NOVATELWIRELESS_PRODUCT_EVDO_HIGHSPEED 0X6001 @@ -307,11 +308,20 @@ static int option_resume(struct usb_serial *serial); #define DLINK_VENDOR_ID 0x1186 #define DLINK_PRODUCT_DWM_652 0x3e04 +#define QISDA_VENDOR_ID 0x1da5 +#define QISDA_PRODUCT_H21_4512 0x4512 +#define QISDA_PRODUCT_H21_4523 0x4523 +#define QISDA_PRODUCT_H20_4515 0x4515 +#define QISDA_PRODUCT_H20_4519 0x4519 + /* TOSHIBA PRODUCTS */ #define TOSHIBA_VENDOR_ID 0x0930 #define TOSHIBA_PRODUCT_HSDPA_MINICARD 0x1302 +#define ALINK_VENDOR_ID 0x1e0e +#define ALINK_PRODUCT_3GU 0x9200 + static struct usb_device_id option_ids[] = { { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) }, { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) }, @@ -430,6 +440,7 @@ static struct usb_device_id option_ids[] = { { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC727) }, /* Novatel MC727/U727/USB727 */ { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_U727) }, /* Novatel MC727/U727/USB727 */ { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC760) }, /* Novatel MC760/U760/USB760 */ + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_OVMC760) }, /* Novatel Ovation MC760 */ { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_FULLSPEED) }, /* Novatel HSPA product */ { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EVDO_EMBEDDED_FULLSPEED) }, /* Novatel EVDO Embedded product */ { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_EMBEDDED_FULLSPEED) }, /* Novatel HSPA Embedded product */ @@ -529,8 +540,13 @@ static struct usb_device_id option_ids[] = { { 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 */ + { USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H21_4512) }, + { USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H21_4523) }, + { USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H20_4515) }, + { USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H20_4519) }, { USB_DEVICE(TOSHIBA_VENDOR_ID, TOSHIBA_PRODUCT_HSDPA_MINICARD ) }, /* Toshiba 3G HSDPA == Novatel Expedite EU870D MiniCard */ + { USB_DEVICE(ALINK_VENDOR_ID, 0x9000) }, + { USB_DEVICE_AND_INTERFACE_INFO(ALINK_VENDOR_ID, ALINK_PRODUCT_3GU, 0xff, 0xff, 0xff) }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, option_ids); @@ -732,7 +748,6 @@ static int option_write(struct tty_struct *tty, struct usb_serial_port *port, memcpy(this_urb->transfer_buffer, buf, todo); this_urb->transfer_buffer_length = todo; - this_urb->dev = port->serial->dev; err = usb_submit_urb(this_urb, GFP_ATOMIC); if (err) { dbg("usb_submit_urb %p (write bulk) failed " @@ -860,7 +875,6 @@ static void option_instat_callback(struct urb *urb) /* Resubmit urb so we continue receiving IRQ data */ if (status != -ESHUTDOWN && status != -ENOENT) { - urb->dev = serial->dev; err = usb_submit_urb(urb, GFP_ATOMIC); if (err) dbg("%s: resubmit intr urb failed. (%d)", @@ -921,23 +935,11 @@ static int option_open(struct tty_struct *tty, dbg("%s", __func__); - /* Reset low level data toggle and start reading from endpoints */ + /* Start reading from the IN endpoint */ for (i = 0; i < N_IN_URB; i++) { urb = portdata->in_urbs[i]; if (!urb) continue; - if (urb->dev != serial->dev) { - dbg("%s: dev %p != %p", __func__, - urb->dev, serial->dev); - continue; - } - - /* - * make sure endpoint data toggle is synchronized with the - * device - */ - usb_clear_halt(urb->dev, urb->pipe); - err = usb_submit_urb(urb, GFP_KERNEL); if (err) { dbg("%s: submit urb %d failed (%d) %d", @@ -946,16 +948,6 @@ static int option_open(struct tty_struct *tty, } } - /* Reset low level data toggle on out endpoints */ - for (i = 0; i < N_OUT_URB; i++) { - urb = portdata->out_urbs[i]; - if (!urb) - continue; - urb->dev = serial->dev; - /* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), - usb_pipeout(urb->pipe), 0); */ - } - option_send_setup(port); return 0; @@ -1218,7 +1210,6 @@ static int option_resume(struct usb_serial *serial) dbg("%s: No interrupt URB for port %d\n", __func__, i); continue; } - port->interrupt_in_urb->dev = serial->dev; err = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO); dbg("Submitted interrupt URB for port %d (result %d)", i, err); if (err < 0) { diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index ec6c132a25b..7d15bfa7c2d 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -94,6 +94,7 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(YCCABLE_VENDOR_ID, YCCABLE_PRODUCT_ID) }, { USB_DEVICE(SUPERIAL_VENDOR_ID, SUPERIAL_PRODUCT_ID) }, { USB_DEVICE(HP_VENDOR_ID, HP_LD220_PRODUCT_ID) }, + { USB_DEVICE(CRESSI_VENDOR_ID, CRESSI_EDY_PRODUCT_ID) }, { } /* Terminating entry */ }; @@ -971,18 +972,46 @@ exit: __func__, retval); } +static void pl2303_push_data(struct tty_struct *tty, + struct usb_serial_port *port, struct urb *urb, + u8 line_status) +{ + unsigned char *data = urb->transfer_buffer; + /* get tty_flag from status */ + char tty_flag = TTY_NORMAL; + /* break takes precedence over parity, */ + /* which takes precedence over framing errors */ + if (line_status & UART_BREAK_ERROR) + tty_flag = TTY_BREAK; + else if (line_status & UART_PARITY_ERROR) + tty_flag = TTY_PARITY; + else if (line_status & UART_FRAME_ERROR) + tty_flag = TTY_FRAME; + dbg("%s - tty_flag = %d", __func__, tty_flag); + + tty_buffer_request_room(tty, urb->actual_length + 1); + /* overrun is special, not associated with a char */ + if (line_status & UART_OVERRUN_ERROR) + tty_insert_flip_char(tty, 0, TTY_OVERRUN); + if (port->console && port->sysrq) { + int i; + for (i = 0; i < urb->actual_length; ++i) + if (!usb_serial_handle_sysrq_char(tty, port, data[i])) + tty_insert_flip_char(tty, data[i], tty_flag); + } else + tty_insert_flip_string(tty, data, urb->actual_length); + tty_flip_buffer_push(tty); +} + static void pl2303_read_bulk_callback(struct urb *urb) { struct usb_serial_port *port = urb->context; struct pl2303_private *priv = usb_get_serial_port_data(port); struct tty_struct *tty; - unsigned char *data = urb->transfer_buffer; unsigned long flags; - int i; int result; int status = urb->status; u8 line_status; - char tty_flag; dbg("%s - port %d", __func__, port->number); @@ -1010,10 +1039,7 @@ static void pl2303_read_bulk_callback(struct urb *urb) } usb_serial_debug_data(debug, &port->dev, __func__, - urb->actual_length, data); - - /* get tty_flag from status */ - tty_flag = TTY_NORMAL; + urb->actual_length, urb->transfer_buffer); spin_lock_irqsave(&priv->lock, flags); line_status = priv->line_status; @@ -1021,26 +1047,9 @@ static void pl2303_read_bulk_callback(struct urb *urb) spin_unlock_irqrestore(&priv->lock, flags); wake_up_interruptible(&priv->delta_msr_wait); - /* break takes precedence over parity, */ - /* which takes precedence over framing errors */ - if (line_status & UART_BREAK_ERROR) - tty_flag = TTY_BREAK; - else if (line_status & UART_PARITY_ERROR) - tty_flag = TTY_PARITY; - else if (line_status & UART_FRAME_ERROR) - tty_flag = TTY_FRAME; - dbg("%s - tty_flag = %d", __func__, tty_flag); - tty = tty_port_tty_get(&port->port); if (tty && urb->actual_length) { - tty_buffer_request_room(tty, urb->actual_length + 1); - /* overrun is special, not associated with a char */ - if (line_status & UART_OVERRUN_ERROR) - tty_insert_flip_char(tty, 0, TTY_OVERRUN); - for (i = 0; i < urb->actual_length; ++i) - if (!usb_serial_handle_sysrq_char(port, data[i])) - tty_insert_flip_char(tty, data[i], tty_flag); - tty_flip_buffer_push(tty); + pl2303_push_data(tty, port, urb, line_status); } tty_kref_put(tty); /* Schedule the next read _if_ we are still open */ diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h index 1d7a22e3a9f..12aac7d2462 100644 --- a/drivers/usb/serial/pl2303.h +++ b/drivers/usb/serial/pl2303.h @@ -122,3 +122,7 @@ /* Hewlett-Packard LD220-HP POS Pole Display */ #define HP_VENDOR_ID 0x03f0 #define HP_LD220_PRODUCT_ID 0x3524 + +/* Cressi Edy (diving computer) PC interface */ +#define CRESSI_VENDOR_ID 0x04b8 +#define CRESSI_EDY_PRODUCT_ID 0x0521 diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index 032f7aeb40a..f48d05e0acc 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -181,35 +181,50 @@ static const struct sierra_iface_info direct_ip_interface_blacklist = { }; static struct usb_device_id id_table [] = { + { USB_DEVICE(0x0F3D, 0x0112) }, /* Airprime/Sierra PC 5220 */ + { USB_DEVICE(0x03F0, 0x1B1D) }, /* HP ev2200 a.k.a MC5720 */ + { USB_DEVICE(0x03F0, 0x1E1D) }, /* HP hs2300 a.k.a MC8775 */ + { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */ { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */ { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */ - { USB_DEVICE(0x03f0, 0x1b1d) }, /* HP ev2200 a.k.a MC5720 */ { USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */ - { USB_DEVICE(0x1199, 0x0024) }, /* Sierra Wireless MC5727 */ { USB_DEVICE(0x1199, 0x0220) }, /* Sierra Wireless MC5725 */ + { USB_DEVICE(0x1199, 0x0022) }, /* Sierra Wireless EM5725 */ + { USB_DEVICE(0x1199, 0x0024) }, /* Sierra Wireless MC5727 */ + { USB_DEVICE(0x1199, 0x0224) }, /* Sierra Wireless MC5727 */ { USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */ { USB_DEVICE(0x1199, 0x0021) }, /* Sierra Wireless AirCard 597E */ + { USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless AirCard 580 */ { USB_DEVICE(0x1199, 0x0120) }, /* Sierra Wireless USB Dongle 595U */ - /* Sierra Wireless C597 */ + /* Sierra Wireless C597 */ { USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x0023, 0xFF, 0xFF, 0xFF) }, - /* Sierra Wireless Device */ + /* Sierra Wireless T598 */ { USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x0025, 0xFF, 0xFF, 0xFF) }, - { USB_DEVICE(0x1199, 0x0026) }, /* Sierra Wireless Device */ - { USB_DEVICE(0x1199, 0x0027) }, /* Sierra Wireless Device */ - { USB_DEVICE(0x1199, 0x0028) }, /* Sierra Wireless Device */ + { USB_DEVICE(0x1199, 0x0026) }, /* Sierra Wireless T11 */ + { USB_DEVICE(0x1199, 0x0027) }, /* Sierra Wireless AC402 */ + { USB_DEVICE(0x1199, 0x0028) }, /* Sierra Wireless MC5728 */ + { USB_DEVICE(0x1199, 0x0029) }, /* Sierra Wireless Device */ { USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */ - { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 */ { USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */ + { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 */ + { USB_DEVICE(0x1199, 0x6805) }, /* Sierra Wireless MC8765 */ + { USB_DEVICE(0x1199, 0x6808) }, /* Sierra Wireless MC8755 */ + { USB_DEVICE(0x1199, 0x6809) }, /* Sierra Wireless MC8765 */ { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 & AC 875U */ - { USB_DEVICE(0x1199, 0x6813) }, /* Sierra Wireless MC8775 (Lenovo) */ + { USB_DEVICE(0x1199, 0x6813) }, /* Sierra Wireless MC8775 */ { USB_DEVICE(0x1199, 0x6815) }, /* Sierra Wireless MC8775 */ - { USB_DEVICE(0x03f0, 0x1e1d) }, /* HP hs2300 a.k.a MC8775 */ + { USB_DEVICE(0x1199, 0x6816) }, /* Sierra Wireless MC8775 */ { USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */ { USB_DEVICE(0x1199, 0x6821) }, /* Sierra Wireless AirCard 875U */ + { USB_DEVICE(0x1199, 0x6822) }, /* Sierra Wireless AirCard 875E */ { USB_DEVICE(0x1199, 0x6832) }, /* Sierra Wireless MC8780 */ { USB_DEVICE(0x1199, 0x6833) }, /* Sierra Wireless MC8781 */ + { USB_DEVICE(0x1199, 0x6834) }, /* Sierra Wireless MC8780 */ + { USB_DEVICE(0x1199, 0x6835) }, /* Sierra Wireless MC8781 */ + { USB_DEVICE(0x1199, 0x6838) }, /* Sierra Wireless MC8780 */ + { USB_DEVICE(0x1199, 0x6839) }, /* Sierra Wireless MC8781 */ { USB_DEVICE(0x1199, 0x683A) }, /* Sierra Wireless MC8785 */ { USB_DEVICE(0x1199, 0x683B) }, /* Sierra Wireless MC8785 Composite */ /* Sierra Wireless MC8790, MC8791, MC8792 Composite */ @@ -227,16 +242,13 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(0x1199, 0x685A) }, /* Sierra Wireless AirCard 885 E */ /* Sierra Wireless C885 */ { USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x6880, 0xFF, 0xFF, 0xFF)}, - /* Sierra Wireless Device */ + /* Sierra Wireless C888, Air Card 501, USB 303, USB 304 */ { USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x6890, 0xFF, 0xFF, 0xFF)}, - /* Sierra Wireless Device */ + /* Sierra Wireless C22/C33 */ { USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x6891, 0xFF, 0xFF, 0xFF)}, - /* Sierra Wireless Device */ + /* Sierra Wireless HSPA Non-Composite Device */ { USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x6892, 0xFF, 0xFF, 0xFF)}, - - { USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless AirCard 580 */ - { USB_DEVICE(0x0F3D, 0x0112) }, /* Airprime/Sierra PC 5220 */ - + { USB_DEVICE(0x1199, 0x6893) }, /* Sierra Wireless Device */ { USB_DEVICE(0x1199, 0x68A3), /* Sierra Wireless Direct IP modems */ .driver_info = (kernel_ulong_t)&direct_ip_interface_blacklist }, @@ -814,7 +826,7 @@ static int sierra_startup(struct usb_serial *serial) return 0; } -static void sierra_disconnect(struct usb_serial *serial) +static void sierra_release(struct usb_serial *serial) { int i; struct usb_serial_port *port; @@ -830,7 +842,6 @@ static void sierra_disconnect(struct usb_serial *serial) if (!portdata) continue; kfree(portdata); - usb_set_serial_port_data(port, NULL); } } @@ -853,7 +864,7 @@ static struct usb_serial_driver sierra_device = { .tiocmget = sierra_tiocmget, .tiocmset = sierra_tiocmset, .attach = sierra_startup, - .disconnect = sierra_disconnect, + .release = sierra_release, .read_int_callback = sierra_instat_callback, }; diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index 991d8232e37..14971a92699 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -191,7 +191,6 @@ static struct usb_device_id ti_id_table_5052[5+TI_EXTRA_VID_PID_COUNT+1] = { { USB_DEVICE(TI_VENDOR_ID, TI_5152_BOOT_PRODUCT_ID) }, { USB_DEVICE(TI_VENDOR_ID, TI_5052_EEPROM_PRODUCT_ID) }, { USB_DEVICE(TI_VENDOR_ID, TI_5052_FIRMWARE_PRODUCT_ID) }, - { USB_DEVICE(IBM_VENDOR_ID, IBM_4543_PRODUCT_ID) }, }; static struct usb_device_id ti_id_table_combined[14+2*TI_EXTRA_VID_PID_COUNT+1] = { @@ -1658,7 +1657,7 @@ static int ti_do_download(struct usb_device *dev, int pipe, u8 cs = 0; int done; struct ti_firmware_header *header; - int status; + int status = 0; int len; for (pos = sizeof(struct ti_firmware_header); pos < size; pos++) diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index a84216464ca..bd7581b3a48 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -21,6 +21,7 @@ #include <linux/errno.h> #include <linux/init.h> #include <linux/slab.h> +#include <linux/smp_lock.h> #include <linux/tty.h> #include <linux/tty_driver.h> #include <linux/tty_flip.h> @@ -220,7 +221,8 @@ static int serial_open (struct tty_struct *tty, struct file *filp) tty->driver_data = port; tty_port_tty_set(&port->port, tty); - if (port->port.count == 1) { + /* If the console is attached, the device is already open */ + if (port->port.count == 1 && !port->console) { /* lock this module before we call it * this may fail, which means we must bail out, diff --git a/drivers/usb/storage/option_ms.c b/drivers/usb/storage/option_ms.c index d41cc0a970f..773a5cd38c5 100644 --- a/drivers/usb/storage/option_ms.c +++ b/drivers/usb/storage/option_ms.c @@ -118,6 +118,9 @@ static int option_inquiry(struct us_data *us) result = memcmp(buffer+8, "Option", 6); + if (result != 0) + result = memcmp(buffer+8, "ZCOPTION", 8); + /* Read the CSW */ usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 53ea05645ff..a85c818be94 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -16,7 +16,6 @@ #include <linux/compat.h> #include <linux/types.h> #include <linux/errno.h> -#include <linux/smp_lock.h> #include <linux/kernel.h> #include <linux/major.h> #include <linux/slab.h> diff --git a/drivers/video/mx3fb.c b/drivers/video/mx3fb.c index 567fb944bd2..f8778cde218 100644 --- a/drivers/video/mx3fb.c +++ b/drivers/video/mx3fb.c @@ -1365,11 +1365,6 @@ static int init_fb_chan(struct mx3fb_data *mx3fb, struct idmac_channel *ichan) init_completion(&mx3fbi->flip_cmpl); disable_irq(ichan->eof_irq); dev_dbg(mx3fb->dev, "disabling irq %d\n", ichan->eof_irq); - ret = mx3fb_set_par(fbi); - if (ret < 0) - goto esetpar; - - mx3fb_blank(FB_BLANK_UNBLANK, fbi); dev_info(dev, "registered, using mode %s\n", fb_mode); diff --git a/drivers/video/omap/omapfb_main.c b/drivers/video/omap/omapfb_main.c index 4ea99bfc37b..8862233d57b 100644 --- a/drivers/video/omap/omapfb_main.c +++ b/drivers/video/omap/omapfb_main.c @@ -1254,7 +1254,7 @@ static struct fb_ops omapfb_ops = { static ssize_t omapfb_show_caps_num(struct device *dev, struct device_attribute *attr, char *buf) { - struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data; + struct omapfb_device *fbdev = dev_get_drvdata(dev); int plane; size_t size; struct omapfb_caps caps; @@ -1274,7 +1274,7 @@ static ssize_t omapfb_show_caps_num(struct device *dev, static ssize_t omapfb_show_caps_text(struct device *dev, struct device_attribute *attr, char *buf) { - struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data; + struct omapfb_device *fbdev = dev_get_drvdata(dev); int i; struct omapfb_caps caps; int plane; @@ -1321,7 +1321,7 @@ static DEVICE_ATTR(caps_text, 0444, omapfb_show_caps_text, NULL); static ssize_t omapfb_show_panel_name(struct device *dev, struct device_attribute *attr, char *buf) { - struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data; + struct omapfb_device *fbdev = dev_get_drvdata(dev); return snprintf(buf, PAGE_SIZE, "%s\n", fbdev->panel->name); } @@ -1330,7 +1330,7 @@ static ssize_t omapfb_show_bklight_level(struct device *dev, struct device_attribute *attr, char *buf) { - struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data; + struct omapfb_device *fbdev = dev_get_drvdata(dev); int r; if (fbdev->panel->get_bklight_level) { @@ -1345,7 +1345,7 @@ static ssize_t omapfb_store_bklight_level(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { - struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data; + struct omapfb_device *fbdev = dev_get_drvdata(dev); int r; if (fbdev->panel->set_bklight_level) { @@ -1364,7 +1364,7 @@ static ssize_t omapfb_store_bklight_level(struct device *dev, static ssize_t omapfb_show_bklight_max(struct device *dev, struct device_attribute *attr, char *buf) { - struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data; + struct omapfb_device *fbdev = dev_get_drvdata(dev); int r; if (fbdev->panel->get_bklight_level) { @@ -1397,7 +1397,7 @@ static struct attribute_group panel_attr_grp = { static ssize_t omapfb_show_ctrl_name(struct device *dev, struct device_attribute *attr, char *buf) { - struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data; + struct omapfb_device *fbdev = dev_get_drvdata(dev); return snprintf(buf, PAGE_SIZE, "%s\n", fbdev->ctrl->name); } diff --git a/drivers/video/sm501fb.c b/drivers/video/sm501fb.c index 16d4f4c7d52..924d7946278 100644 --- a/drivers/video/sm501fb.c +++ b/drivers/video/sm501fb.c @@ -1540,9 +1540,6 @@ static int sm501fb_init_fb(struct fb_info *fb, if (ret) dev_err(info->dev, "check_var() failed on initial setup?\n"); - /* ensure we've activated our new configuration */ - (fb->fbops->fb_set_par)(fb); - return 0; } diff --git a/drivers/watchdog/bcm47xx_wdt.c b/drivers/watchdog/bcm47xx_wdt.c index 5c7011cda6a..751c003864a 100644 --- a/drivers/watchdog/bcm47xx_wdt.c +++ b/drivers/watchdog/bcm47xx_wdt.c @@ -161,7 +161,7 @@ static long bcm47xx_wdt_ioctl(struct file *file, { void __user *argp = (void __user *)arg; int __user *p = argp; - int new_value, retval = -EINVAL;; + int new_value, retval = -EINVAL; switch (cmd) { case WDIOC_GETSUPPORT: diff --git a/drivers/watchdog/sa1100_wdt.c b/drivers/watchdog/sa1100_wdt.c index ee1caae4d33..016245419fa 100644 --- a/drivers/watchdog/sa1100_wdt.c +++ b/drivers/watchdog/sa1100_wdt.c @@ -38,7 +38,7 @@ static unsigned long oscr_freq; static unsigned long sa1100wdt_users; -static int pre_margin; +static unsigned int pre_margin; static int boot_status; /* @@ -84,6 +84,7 @@ static const struct watchdog_info ident = { .options = WDIOF_CARDRESET | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, .identity = "SA1100/PXA255 Watchdog", + .firmware_version = 1, }; static long sa1100dog_ioctl(struct file *file, unsigned int cmd, @@ -118,7 +119,7 @@ static long sa1100dog_ioctl(struct file *file, unsigned int cmd, if (ret) break; - if (time <= 0 || time > 255) { + if (time <= 0 || (oscr_freq * (long long)time >= 0xffffffff)) { ret = -EINVAL; break; } diff --git a/drivers/watchdog/w83627hf_wdt.c b/drivers/watchdog/w83627hf_wdt.c index 916890abffd..f201accc4e3 100644 --- a/drivers/watchdog/w83627hf_wdt.c +++ b/drivers/watchdog/w83627hf_wdt.c @@ -89,6 +89,11 @@ static void w83627hf_select_wd_register(void) c = ((inb_p(WDT_EFDR) & 0xf7) | 0x04); /* select WDT0 */ outb_p(0x2b, WDT_EFER); outb_p(c, WDT_EFDR); /* set GPIO3 to WDT0 */ + } else if (c == 0x88) { /* W83627EHF */ + outb_p(0x2d, WDT_EFER); /* select GPIO5 */ + c = inb_p(WDT_EFDR) & ~0x01; /* PIN77 -> WDT0# */ + outb_p(0x2d, WDT_EFER); + outb_p(c, WDT_EFDR); /* set GPIO5 to WDT0 */ } outb_p(0x07, WDT_EFER); /* point to logical device number reg */ diff --git a/drivers/watchdog/w83697ug_wdt.c b/drivers/watchdog/w83697ug_wdt.c index 883b5f79673..a6c12dec91a 100644 --- a/drivers/watchdog/w83697ug_wdt.c +++ b/drivers/watchdog/w83697ug_wdt.c @@ -149,8 +149,10 @@ static void wdt_ctrl(int timeout) { spin_lock(&io_lock); - if (w83697ug_select_wd_register() < 0) + if (w83697ug_select_wd_register() < 0) { + spin_unlock(&io_lock); return; + } outb_p(0xF4, WDT_EFER); /* Select CRF4 */ outb_p(timeout, WDT_EFDR); /* Write Timeout counter to CRF4 */ |