diff options
| author | Linux Build Service Account <lnxbuild@localhost> | 2019-12-06 12:51:54 -0800 |
|---|---|---|
| committer | Linux Build Service Account <lnxbuild@localhost> | 2019-12-06 12:51:54 -0800 |
| commit | 33dc678e7692f04ecc1eeddeb1cca8a809bc1727 (patch) | |
| tree | 7ac214cbb1f5256e0738cd6423f01e364b942bd4 /drivers | |
| parent | feb565e67fc2b2f2a95890577120141be5886594 (diff) | |
| parent | 72078891843ce0d5b8e95040d09ba92913916af9 (diff) | |
Merge 72078891843ce0d5b8e95040d09ba92913916af9 on remote branch
Change-Id: I219a5f0e8bd6ee3be3ba0d49230dde908d35dc25
Diffstat (limited to 'drivers')
267 files changed, 4984 insertions, 3593 deletions
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index a000ecb995e6..e59f50576f2a 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -1186,6 +1186,7 @@ void acpi_os_wait_events_complete(void) flush_workqueue(kacpid_wq); flush_workqueue(kacpi_notify_wq); } +EXPORT_SYMBOL(acpi_os_wait_events_complete); struct acpi_hp_work { struct work_struct work; diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 3b0b4bd67b71..4031ec8024ce 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -454,8 +454,9 @@ static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm) decode_osc_support(root, "OS supports", support); status = acpi_pci_osc_support(root, support); if (ACPI_FAILURE(status)) { - dev_info(&device->dev, "_OSC failed (%s); disabling ASPM\n", - acpi_format_exception(status)); + dev_info(&device->dev, "_OSC failed (%s)%s\n", + acpi_format_exception(status), + pcie_aspm_support_enabled() ? "; disabling ASPM" : ""); *no_aspm = 1; return; } diff --git a/drivers/acpi/sbshc.c b/drivers/acpi/sbshc.c index 7a3431018e0a..5008ead4609a 100644 --- a/drivers/acpi/sbshc.c +++ b/drivers/acpi/sbshc.c @@ -196,6 +196,7 @@ int acpi_smbus_unregister_callback(struct acpi_smb_hc *hc) hc->callback = NULL; hc->context = NULL; mutex_unlock(&hc->lock); + acpi_os_wait_events_complete(); return 0; } @@ -292,6 +293,7 @@ static int acpi_smbus_hc_remove(struct acpi_device *device) hc = acpi_driver_data(device); acpi_ec_remove_query_handler(hc->ec, hc->query_bit); + acpi_os_wait_events_complete(); kfree(hc); device->driver_data = NULL; return 0; diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 4a267347a6d9..a44aeda57109 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -1654,6 +1654,21 @@ nothing_to_do: return 1; } +static bool ata_check_nblocks(struct scsi_cmnd *scmd, u32 n_blocks) +{ + struct request *rq = scmd->request; + u32 req_blocks; + + if (!blk_rq_is_passthrough(rq)) + return true; + + req_blocks = blk_rq_bytes(rq) / scmd->device->sector_size; + if (n_blocks > req_blocks) + return false; + + return true; +} + /** * ata_scsi_rw_xlat - Translate SCSI r/w command into an ATA one * @qc: Storage for translated ATA taskfile @@ -1693,6 +1708,8 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc) scsi_10_lba_len(cdb, &block, &n_block); if (cdb[1] & (1 << 3)) tf_flags |= ATA_TFLAG_FUA; + if (!ata_check_nblocks(scmd, n_block)) + goto invalid_fld; break; case READ_6: case WRITE_6: @@ -1705,6 +1722,8 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc) */ if (!n_block) n_block = 256; + if (!ata_check_nblocks(scmd, n_block)) + goto invalid_fld; break; case READ_16: case WRITE_16: @@ -1713,6 +1732,8 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc) scsi_16_lba_len(cdb, &block, &n_block); if (cdb[1] & (1 << 3)) tf_flags |= ATA_TFLAG_FUA; + if (!ata_check_nblocks(scmd, n_block)) + goto invalid_fld; break; default: DPRINTK("no-byte command\n"); diff --git a/drivers/ata/pata_ep93xx.c b/drivers/ata/pata_ep93xx.c index bd6b089c67a3..634c814cbeda 100644 --- a/drivers/ata/pata_ep93xx.c +++ b/drivers/ata/pata_ep93xx.c @@ -659,7 +659,7 @@ static void ep93xx_pata_dma_init(struct ep93xx_pata_data *drv_data) * start of new transfer. */ drv_data->dma_rx_data.port = EP93XX_DMA_IDE; - drv_data->dma_rx_data.direction = DMA_FROM_DEVICE; + drv_data->dma_rx_data.direction = DMA_DEV_TO_MEM; drv_data->dma_rx_data.name = "ep93xx-pata-rx"; drv_data->dma_rx_channel = dma_request_channel(mask, ep93xx_pata_dma_filter, &drv_data->dma_rx_data); @@ -667,7 +667,7 @@ static void ep93xx_pata_dma_init(struct ep93xx_pata_data *drv_data) return; drv_data->dma_tx_data.port = EP93XX_DMA_IDE; - drv_data->dma_tx_data.direction = DMA_TO_DEVICE; + drv_data->dma_tx_data.direction = DMA_MEM_TO_DEV; drv_data->dma_tx_data.name = "ep93xx-pata-tx"; drv_data->dma_tx_channel = dma_request_channel(mask, ep93xx_pata_dma_filter, &drv_data->dma_tx_data); @@ -678,7 +678,7 @@ static void ep93xx_pata_dma_init(struct ep93xx_pata_data *drv_data) /* Configure receive channel direction and source address */ memset(&conf, 0, sizeof(conf)); - conf.direction = DMA_FROM_DEVICE; + conf.direction = DMA_DEV_TO_MEM; conf.src_addr = drv_data->udma_in_phys; conf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; if (dmaengine_slave_config(drv_data->dma_rx_channel, &conf)) { @@ -689,7 +689,7 @@ static void ep93xx_pata_dma_init(struct ep93xx_pata_data *drv_data) /* Configure transmit channel direction and destination address */ memset(&conf, 0, sizeof(conf)); - conf.direction = DMA_TO_DEVICE; + conf.direction = DMA_MEM_TO_DEV; conf.dst_addr = drv_data->udma_out_phys; conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; if (dmaengine_slave_config(drv_data->dma_tx_channel, &conf)) { diff --git a/drivers/atm/zatm.c b/drivers/atm/zatm.c index 94712e1c5cf9..bcdde3e36052 100644 --- a/drivers/atm/zatm.c +++ b/drivers/atm/zatm.c @@ -126,7 +126,7 @@ static unsigned long dummy[2] = {0,0}; #define zin_n(r) inl(zatm_dev->base+r*4) #define zin(r) inl(zatm_dev->base+uPD98401_##r*4) #define zout(v,r) outl(v,zatm_dev->base+uPD98401_##r*4) -#define zwait while (zin(CMR) & uPD98401_BUSY) +#define zwait() do {} while (zin(CMR) & uPD98401_BUSY) /* RX0, RX1, TX0, TX1 */ static const int mbx_entries[NR_MBX] = { 1024,1024,1024,1024 }; @@ -140,7 +140,7 @@ static const int mbx_esize[NR_MBX] = { 16,16,4,4 }; /* entry size in bytes */ static void zpokel(struct zatm_dev *zatm_dev,u32 value,u32 addr) { - zwait; + zwait(); zout(value,CER); zout(uPD98401_IND_ACC | uPD98401_IA_BALL | (uPD98401_IA_TGT_CM << uPD98401_IA_TGT_SHIFT) | addr,CMR); @@ -149,10 +149,10 @@ static void zpokel(struct zatm_dev *zatm_dev,u32 value,u32 addr) static u32 zpeekl(struct zatm_dev *zatm_dev,u32 addr) { - zwait; + zwait(); zout(uPD98401_IND_ACC | uPD98401_IA_BALL | uPD98401_IA_RW | (uPD98401_IA_TGT_CM << uPD98401_IA_TGT_SHIFT) | addr,CMR); - zwait; + zwait(); return zin(CER); } @@ -241,7 +241,7 @@ static void refill_pool(struct atm_dev *dev,int pool) } if (first) { spin_lock_irqsave(&zatm_dev->lock, flags); - zwait; + zwait(); zout(virt_to_bus(first),CER); zout(uPD98401_ADD_BAT | (pool << uPD98401_POOL_SHIFT) | count, CMR); @@ -508,9 +508,9 @@ static int open_rx_first(struct atm_vcc *vcc) } if (zatm_vcc->pool < 0) return -EMSGSIZE; spin_lock_irqsave(&zatm_dev->lock, flags); - zwait; + zwait(); zout(uPD98401_OPEN_CHAN,CMR); - zwait; + zwait(); DPRINTK("0x%x 0x%x\n",zin(CMR),zin(CER)); chan = (zin(CMR) & uPD98401_CHAN_ADDR) >> uPD98401_CHAN_ADDR_SHIFT; spin_unlock_irqrestore(&zatm_dev->lock, flags); @@ -571,21 +571,21 @@ static void close_rx(struct atm_vcc *vcc) pos = vcc->vci >> 1; shift = (1-(vcc->vci & 1)) << 4; zpokel(zatm_dev,zpeekl(zatm_dev,pos) & ~(0xffff << shift),pos); - zwait; + zwait(); zout(uPD98401_NOP,CMR); - zwait; + zwait(); zout(uPD98401_NOP,CMR); spin_unlock_irqrestore(&zatm_dev->lock, flags); } spin_lock_irqsave(&zatm_dev->lock, flags); - zwait; + zwait(); zout(uPD98401_DEACT_CHAN | uPD98401_CHAN_RT | (zatm_vcc->rx_chan << uPD98401_CHAN_ADDR_SHIFT),CMR); - zwait; + zwait(); udelay(10); /* why oh why ... ? */ zout(uPD98401_CLOSE_CHAN | uPD98401_CHAN_RT | (zatm_vcc->rx_chan << uPD98401_CHAN_ADDR_SHIFT),CMR); - zwait; + zwait(); if (!(zin(CMR) & uPD98401_CHAN_ADDR)) printk(KERN_CRIT DEV_LABEL "(itf %d): can't close RX channel " "%d\n",vcc->dev->number,zatm_vcc->rx_chan); @@ -698,7 +698,7 @@ printk("NONONONOO!!!!\n"); skb_queue_tail(&zatm_vcc->tx_queue,skb); DPRINTK("QRP=0x%08lx\n",zpeekl(zatm_dev,zatm_vcc->tx_chan*VC_SIZE/4+ uPD98401_TXVC_QRP)); - zwait; + zwait(); zout(uPD98401_TX_READY | (zatm_vcc->tx_chan << uPD98401_CHAN_ADDR_SHIFT),CMR); spin_unlock_irqrestore(&zatm_dev->lock, flags); @@ -890,12 +890,12 @@ static void close_tx(struct atm_vcc *vcc) } spin_lock_irqsave(&zatm_dev->lock, flags); #if 0 - zwait; + zwait(); zout(uPD98401_DEACT_CHAN | (chan << uPD98401_CHAN_ADDR_SHIFT),CMR); #endif - zwait; + zwait(); zout(uPD98401_CLOSE_CHAN | (chan << uPD98401_CHAN_ADDR_SHIFT),CMR); - zwait; + zwait(); if (!(zin(CMR) & uPD98401_CHAN_ADDR)) printk(KERN_CRIT DEV_LABEL "(itf %d): can't close TX channel " "%d\n",vcc->dev->number,chan); @@ -925,9 +925,9 @@ static int open_tx_first(struct atm_vcc *vcc) zatm_vcc->tx_chan = 0; if (vcc->qos.txtp.traffic_class == ATM_NONE) return 0; spin_lock_irqsave(&zatm_dev->lock, flags); - zwait; + zwait(); zout(uPD98401_OPEN_CHAN,CMR); - zwait; + zwait(); DPRINTK("0x%x 0x%x\n",zin(CMR),zin(CER)); chan = (zin(CMR) & uPD98401_CHAN_ADDR) >> uPD98401_CHAN_ADDR_SHIFT; spin_unlock_irqrestore(&zatm_dev->lock, flags); @@ -1557,7 +1557,7 @@ static void zatm_phy_put(struct atm_dev *dev,unsigned char value, struct zatm_dev *zatm_dev; zatm_dev = ZATM_DEV(dev); - zwait; + zwait(); zout(value,CER); zout(uPD98401_IND_ACC | uPD98401_IA_B0 | (uPD98401_IA_TGT_PHY << uPD98401_IA_TGT_SHIFT) | addr,CMR); @@ -1569,10 +1569,10 @@ static unsigned char zatm_phy_get(struct atm_dev *dev,unsigned long addr) struct zatm_dev *zatm_dev; zatm_dev = ZATM_DEV(dev); - zwait; + zwait(); zout(uPD98401_IND_ACC | uPD98401_IA_B0 | uPD98401_IA_RW | (uPD98401_IA_TGT_PHY << uPD98401_IA_TGT_SHIFT) | addr,CMR); - zwait; + zwait(); return zin(CER) & 0xff; } diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index e5ac568c7c9b..2a5aad29c8a3 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -711,12 +711,27 @@ ssize_t __weak cpu_show_mds(struct device *dev, return sprintf(buf, "Not affected\n"); } +ssize_t __weak cpu_show_tsx_async_abort(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "Not affected\n"); +} + +ssize_t __weak cpu_show_itlb_multihit(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "Not affected\n"); +} + static DEVICE_ATTR(meltdown, 0444, cpu_show_meltdown, NULL); static DEVICE_ATTR(spectre_v1, 0444, cpu_show_spectre_v1, NULL); static DEVICE_ATTR(spectre_v2, 0444, cpu_show_spectre_v2, NULL); static DEVICE_ATTR(spec_store_bypass, 0444, cpu_show_spec_store_bypass, NULL); static DEVICE_ATTR(l1tf, 0444, cpu_show_l1tf, NULL); static DEVICE_ATTR(mds, 0444, cpu_show_mds, NULL); +static DEVICE_ATTR(tsx_async_abort, 0444, cpu_show_tsx_async_abort, NULL); +static DEVICE_ATTR(itlb_multihit, 0444, cpu_show_itlb_multihit, NULL); static struct attribute *cpu_root_vulnerabilities_attrs[] = { &dev_attr_meltdown.attr, @@ -725,6 +740,8 @@ static struct attribute *cpu_root_vulnerabilities_attrs[] = { &dev_attr_spec_store_bypass.attr, &dev_attr_l1tf.attr, &dev_attr_mds.attr, + &dev_attr_tsx_async_abort.attr, + &dev_attr_itlb_multihit.attr, NULL }; diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c index 5fd50a284168..db4354fb2a0d 100644 --- a/drivers/block/amiflop.c +++ b/drivers/block/amiflop.c @@ -1699,11 +1699,41 @@ static const struct block_device_operations floppy_fops = { .check_events = amiga_check_events, }; +static struct gendisk *fd_alloc_disk(int drive) +{ + struct gendisk *disk; + + disk = alloc_disk(1); + if (!disk) + goto out; + + disk->queue = blk_init_queue(do_fd_request, &amiflop_lock); + if (IS_ERR(disk->queue)) { + disk->queue = NULL; + goto out_put_disk; + } + + unit[drive].trackbuf = kmalloc(FLOPPY_MAX_SECTORS * 512, GFP_KERNEL); + if (!unit[drive].trackbuf) + goto out_cleanup_queue; + + return disk; + +out_cleanup_queue: + blk_cleanup_queue(disk->queue); + disk->queue = NULL; +out_put_disk: + put_disk(disk); +out: + unit[drive].type->code = FD_NODRIVE; + return NULL; +} + static int __init fd_probe_drives(void) { int drive,drives,nomem; - printk(KERN_INFO "FD: probing units\nfound "); + pr_info("FD: probing units\nfound"); drives=0; nomem=0; for(drive=0;drive<FD_MAX_UNITS;drive++) { @@ -1711,27 +1741,17 @@ static int __init fd_probe_drives(void) fd_probe(drive); if (unit[drive].type->code == FD_NODRIVE) continue; - disk = alloc_disk(1); + + disk = fd_alloc_disk(drive); if (!disk) { - unit[drive].type->code = FD_NODRIVE; + pr_cont(" no mem for fd%d", drive); + nomem = 1; continue; } unit[drive].gendisk = disk; - - disk->queue = blk_init_queue(do_fd_request, &amiflop_lock); - if (!disk->queue) { - unit[drive].type->code = FD_NODRIVE; - continue; - } - drives++; - if ((unit[drive].trackbuf = kmalloc(FLOPPY_MAX_SECTORS * 512, GFP_KERNEL)) == NULL) { - printk("no mem for "); - unit[drive].type = &drive_types[num_dr_types - 1]; /* FD_NODRIVE */ - drives--; - nomem = 1; - } - printk("fd%d ",drive); + + pr_cont(" fd%d",drive); disk->major = FLOPPY_MAJOR; disk->first_minor = drive; disk->fops = &floppy_fops; @@ -1742,11 +1762,11 @@ static int __init fd_probe_drives(void) } if ((drives > 0) || (nomem == 0)) { if (drives == 0) - printk("no drives"); - printk("\n"); + pr_cont(" no drives"); + pr_cont("\n"); return drives; } - printk("\n"); + pr_cont("\n"); return -ENOMEM; } @@ -1837,30 +1857,6 @@ out_blkdev: return ret; } -#if 0 /* not safe to unload */ -static int __exit amiga_floppy_remove(struct platform_device *pdev) -{ - int i; - - for( i = 0; i < FD_MAX_UNITS; i++) { - if (unit[i].type->code != FD_NODRIVE) { - struct request_queue *q = unit[i].gendisk->queue; - del_gendisk(unit[i].gendisk); - put_disk(unit[i].gendisk); - kfree(unit[i].trackbuf); - if (q) - blk_cleanup_queue(q); - } - } - blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256); - free_irq(IRQ_AMIGA_CIAA_TB, NULL); - free_irq(IRQ_AMIGA_DSKBLK, NULL); - custom.dmacon = DMAF_DISK; /* disable DMA */ - amiga_chip_free(raw_buf); - unregister_blkdev(FLOPPY_MAJOR, "fd"); -} -#endif - static struct platform_driver amiga_floppy_driver = { .driver = { .name = "amiga-floppy", diff --git a/drivers/bluetooth/hci_bcsp.c b/drivers/bluetooth/hci_bcsp.c index 9833b53a8b50..37e46c6b5315 100644 --- a/drivers/bluetooth/hci_bcsp.c +++ b/drivers/bluetooth/hci_bcsp.c @@ -566,6 +566,7 @@ static int bcsp_recv(struct hci_uart *hu, const void *data, int count) if (*ptr == 0xc0) { BT_ERR("Short BCSP packet"); kfree_skb(bcsp->rx_skb); + bcsp->rx_skb = NULL; bcsp->rx_state = BCSP_W4_PKT_START; bcsp->rx_count = 0; } else @@ -581,6 +582,7 @@ static int bcsp_recv(struct hci_uart *hu, const void *data, int count) bcsp->rx_skb->data[2])) != bcsp->rx_skb->data[3]) { BT_ERR("Error in BCSP hdr checksum"); kfree_skb(bcsp->rx_skb); + bcsp->rx_skb = NULL; bcsp->rx_state = BCSP_W4_PKT_DELIMITER; bcsp->rx_count = 0; continue; @@ -615,6 +617,7 @@ static int bcsp_recv(struct hci_uart *hu, const void *data, int count) bscp_get_crc(bcsp)); kfree_skb(bcsp->rx_skb); + bcsp->rx_skb = NULL; bcsp->rx_state = BCSP_W4_PKT_DELIMITER; bcsp->rx_count = 0; continue; diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index dd7f811e5805..116255ad5661 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -246,7 +246,7 @@ static int hci_uart_flush(struct hci_dev *hdev) tty_ldisc_flush(tty); tty_driver_flush_buffer(tty); - if (test_bit(HCI_UART_PROTO_SET, &hu->flags)) + if (test_bit(HCI_UART_PROTO_READY, &hu->flags)) hu->proto->flush(hu); return 0; @@ -531,7 +531,7 @@ static void hci_uart_tty_close(struct tty_struct *tty) cancel_work_sync(&hu->write_work); - if (test_and_clear_bit(HCI_UART_PROTO_SET, &hu->flags)) { + if (test_and_clear_bit(HCI_UART_PROTO_READY, &hu->flags)) { if (hdev) { if (test_bit(HCI_UART_REGISTERED, &hu->flags)) hci_unregister_dev(hdev); @@ -542,6 +542,7 @@ static void hci_uart_tty_close(struct tty_struct *tty) hu->proto = NULL; hci_uart_proto_unlock(hu); } + clear_bit(HCI_UART_PROTO_SET, &hu->flags); cancel_work_sync(&hu->write_work); @@ -573,7 +574,7 @@ static void hci_uart_tty_wakeup(struct tty_struct *tty) if (tty != hu->tty) return; - if (test_bit(HCI_UART_PROTO_SET, &hu->flags)) + if (test_bit(HCI_UART_PROTO_READY, &hu->flags)) hci_uart_tx_wakeup(hu); } @@ -597,7 +598,7 @@ static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data, if (!hu || tty != hu->tty) return; - if (!test_bit(HCI_UART_PROTO_SET, &hu->flags)) + if (!test_bit(HCI_UART_PROTO_READY, &hu->flags)) return; /* It does not need a lock here as it is already protected by a mutex in @@ -692,6 +693,7 @@ static int hci_uart_set_proto(struct hci_uart *hu, int id) return err; } + set_bit(HCI_UART_PROTO_READY, &hu->flags); return 0; } diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h index b3a049afc21e..c08b27c327d6 100644 --- a/drivers/bluetooth/hci_uart.h +++ b/drivers/bluetooth/hci_uart.h @@ -95,6 +95,7 @@ struct hci_uart { /* HCI_UART proto flag bits */ #define HCI_UART_PROTO_SET 0 #define HCI_UART_REGISTERED 1 +#define HCI_UART_PROTO_READY 2 /* TX states */ #define HCI_UART_SENDING 1 diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index df9eab91c2d2..5e0e29ee31d1 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -417,7 +417,7 @@ static void reclaim_dma_bufs(void) } } -static struct port_buffer *alloc_buf(struct virtqueue *vq, size_t buf_size, +static struct port_buffer *alloc_buf(struct virtio_device *vdev, size_t buf_size, int pages) { struct port_buffer *buf; @@ -440,7 +440,7 @@ static struct port_buffer *alloc_buf(struct virtqueue *vq, size_t buf_size, return buf; } - if (is_rproc_serial(vq->vdev)) { + if (is_rproc_serial(vdev)) { /* * Allocate DMA memory from ancestor. When a virtio * device is created by remoteproc, the DMA memory is @@ -450,9 +450,9 @@ static struct port_buffer *alloc_buf(struct virtqueue *vq, size_t buf_size, * DMA_MEMORY_INCLUDES_CHILDREN had been supported * in dma-coherent.c */ - if (!vq->vdev->dev.parent || !vq->vdev->dev.parent->parent) + if (!vdev->dev.parent || !vdev->dev.parent->parent) goto free_buf; - buf->dev = vq->vdev->dev.parent->parent; + buf->dev = vdev->dev.parent->parent; /* Increase device refcnt to avoid freeing it */ get_device(buf->dev); @@ -835,7 +835,7 @@ static ssize_t port_fops_write(struct file *filp, const char __user *ubuf, count = min((size_t)(32 * 1024), count); - buf = alloc_buf(port->out_vq, count, 0); + buf = alloc_buf(port->portdev->vdev, count, 0); if (!buf) return -ENOMEM; @@ -954,7 +954,7 @@ static ssize_t port_fops_splice_write(struct pipe_inode_info *pipe, if (ret < 0) goto error_out; - buf = alloc_buf(port->out_vq, 0, pipe->nrbufs); + buf = alloc_buf(port->portdev->vdev, 0, pipe->nrbufs); if (!buf) { ret = -ENOMEM; goto error_out; @@ -1363,24 +1363,24 @@ static void set_console_size(struct port *port, u16 rows, u16 cols) port->cons.ws.ws_col = cols; } -static unsigned int fill_queue(struct virtqueue *vq, spinlock_t *lock) +static int fill_queue(struct virtqueue *vq, spinlock_t *lock) { struct port_buffer *buf; - unsigned int nr_added_bufs; + int nr_added_bufs; int ret; nr_added_bufs = 0; do { - buf = alloc_buf(vq, PAGE_SIZE, 0); + buf = alloc_buf(vq->vdev, PAGE_SIZE, 0); if (!buf) - break; + return -ENOMEM; spin_lock_irq(lock); ret = add_inbuf(vq, buf); if (ret < 0) { spin_unlock_irq(lock); free_buf(buf, true); - break; + return ret; } nr_added_bufs++; spin_unlock_irq(lock); @@ -1400,7 +1400,6 @@ static int add_port(struct ports_device *portdev, u32 id) char debugfs_name[16]; struct port *port; dev_t devt; - unsigned int nr_added_bufs; int err; port = kmalloc(sizeof(*port), GFP_KERNEL); @@ -1459,11 +1458,13 @@ static int add_port(struct ports_device *portdev, u32 id) spin_lock_init(&port->outvq_lock); init_waitqueue_head(&port->waitqueue); - /* Fill the in_vq with buffers so the host can send us data. */ - nr_added_bufs = fill_queue(port->in_vq, &port->inbuf_lock); - if (!nr_added_bufs) { + /* We can safely ignore ENOSPC because it means + * the queue already has buffers. Buffers are removed + * only by virtcons_remove(), not by unplug_port() + */ + err = fill_queue(port->in_vq, &port->inbuf_lock); + if (err < 0 && err != -ENOSPC) { dev_err(port->dev, "Error allocating inbufs\n"); - err = -ENOMEM; goto free_device; } @@ -1986,19 +1987,40 @@ static void remove_vqs(struct ports_device *portdev) kfree(portdev->out_vqs); } -static void remove_controlq_data(struct ports_device *portdev) +static void virtcons_remove(struct virtio_device *vdev) { - struct port_buffer *buf; - unsigned int len; + struct ports_device *portdev; + struct port *port, *port2; - if (!use_multiport(portdev)) - return; + portdev = vdev->priv; - while ((buf = virtqueue_get_buf(portdev->c_ivq, &len))) - free_buf(buf, true); + spin_lock_irq(&pdrvdata_lock); + list_del(&portdev->list); + spin_unlock_irq(&pdrvdata_lock); - while ((buf = virtqueue_detach_unused_buf(portdev->c_ivq))) - free_buf(buf, true); + /* Disable interrupts for vqs */ + vdev->config->reset(vdev); + /* Finish up work that's lined up */ + if (use_multiport(portdev)) + cancel_work_sync(&portdev->control_work); + else + cancel_work_sync(&portdev->config_work); + + list_for_each_entry_safe(port, port2, &portdev->ports, list) + unplug_port(port); + + unregister_chrdev(portdev->chr_major, "virtio-portsdev"); + + /* + * When yanking out a device, we immediately lose the + * (device-side) queues. So there's no point in keeping the + * guest side around till we drop our final reference. This + * also means that any ports which are in an open state will + * have to just stop using the port, as the vqs are going + * away. + */ + remove_vqs(portdev); + kfree(portdev); } /* @@ -2067,6 +2089,7 @@ static int virtcons_probe(struct virtio_device *vdev) spin_lock_init(&portdev->ports_lock); INIT_LIST_HEAD(&portdev->ports); + INIT_LIST_HEAD(&portdev->list); virtio_device_ready(portdev->vdev); @@ -2074,18 +2097,22 @@ static int virtcons_probe(struct virtio_device *vdev) INIT_WORK(&portdev->control_work, &control_work_handler); if (multiport) { - unsigned int nr_added_bufs; - spin_lock_init(&portdev->c_ivq_lock); spin_lock_init(&portdev->c_ovq_lock); - nr_added_bufs = fill_queue(portdev->c_ivq, - &portdev->c_ivq_lock); - if (!nr_added_bufs) { + err = fill_queue(portdev->c_ivq, &portdev->c_ivq_lock); + if (err < 0) { dev_err(&vdev->dev, "Error allocating buffers for control queue\n"); - err = -ENOMEM; - goto free_vqs; + /* + * The host might want to notify mgmt sw about device + * add failure. + */ + __send_control_msg(portdev, VIRTIO_CONSOLE_BAD_ID, + VIRTIO_CONSOLE_DEVICE_READY, 0); + /* Device was functional: we need full cleanup. */ + virtcons_remove(vdev); + return err; } } else { /* @@ -2116,11 +2143,6 @@ static int virtcons_probe(struct virtio_device *vdev) return 0; -free_vqs: - /* The host might want to notify mgmt sw about device add failure */ - __send_control_msg(portdev, VIRTIO_CONSOLE_BAD_ID, - VIRTIO_CONSOLE_DEVICE_READY, 0); - remove_vqs(portdev); free_chrdev: unregister_chrdev(portdev->chr_major, "virtio-portsdev"); free: @@ -2129,43 +2151,6 @@ fail: return err; } -static void virtcons_remove(struct virtio_device *vdev) -{ - struct ports_device *portdev; - struct port *port, *port2; - - portdev = vdev->priv; - - spin_lock_irq(&pdrvdata_lock); - list_del(&portdev->list); - spin_unlock_irq(&pdrvdata_lock); - - /* Disable interrupts for vqs */ - vdev->config->reset(vdev); - /* Finish up work that's lined up */ - if (use_multiport(portdev)) - cancel_work_sync(&portdev->control_work); - else - cancel_work_sync(&portdev->config_work); - - list_for_each_entry_safe(port, port2, &portdev->ports, list) - unplug_port(port); - - unregister_chrdev(portdev->chr_major, "virtio-portsdev"); - - /* - * When yanking out a device, we immediately lose the - * (device-side) queues. So there's no point in keeping the - * guest side around till we drop our final reference. This - * also means that any ports which are in an open state will - * have to just stop using the port, as the vqs are going - * away. - */ - remove_controlq_data(portdev); - remove_vqs(portdev); - kfree(portdev); -} - static struct virtio_device_id id_table[] = { { VIRTIO_ID_CONSOLE, VIRTIO_DEV_ANY_ID }, { 0 }, @@ -2196,15 +2181,16 @@ static int virtcons_freeze(struct virtio_device *vdev) vdev->config->reset(vdev); - virtqueue_disable_cb(portdev->c_ivq); + if (use_multiport(portdev)) + virtqueue_disable_cb(portdev->c_ivq); cancel_work_sync(&portdev->control_work); cancel_work_sync(&portdev->config_work); /* * Once more: if control_work_handler() was running, it would * enable the cb as the last step. */ - virtqueue_disable_cb(portdev->c_ivq); - remove_controlq_data(portdev); + if (use_multiport(portdev)) + virtqueue_disable_cb(portdev->c_ivq); list_for_each_entry(port, &portdev->ports, list) { virtqueue_disable_cb(port->in_vq); diff --git a/drivers/clk/mmp/clk-of-mmp2.c b/drivers/clk/mmp/clk-of-mmp2.c index f261b1d292c7..8b45cb2caed1 100644 --- a/drivers/clk/mmp/clk-of-mmp2.c +++ b/drivers/clk/mmp/clk-of-mmp2.c @@ -227,8 +227,8 @@ static struct mmp_param_gate_clk apmu_gate_clks[] = { /* The gate clocks has mux parent. */ {MMP2_CLK_SDH0, "sdh0_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT, APMU_SDH0, 0x1b, 0x1b, 0x0, 0, &sdh_lock}, {MMP2_CLK_SDH1, "sdh1_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT, APMU_SDH1, 0x1b, 0x1b, 0x0, 0, &sdh_lock}, - {MMP2_CLK_SDH1, "sdh2_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT, APMU_SDH2, 0x1b, 0x1b, 0x0, 0, &sdh_lock}, - {MMP2_CLK_SDH1, "sdh3_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT, APMU_SDH3, 0x1b, 0x1b, 0x0, 0, &sdh_lock}, + {MMP2_CLK_SDH2, "sdh2_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT, APMU_SDH2, 0x1b, 0x1b, 0x0, 0, &sdh_lock}, + {MMP2_CLK_SDH3, "sdh3_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT, APMU_SDH3, 0x1b, 0x1b, 0x0, 0, &sdh_lock}, {MMP2_CLK_DISP0, "disp0_clk", "disp0_div", CLK_SET_RATE_PARENT, APMU_DISP0, 0x1b, 0x1b, 0x0, 0, &disp0_lock}, {MMP2_CLK_DISP0_SPHY, "disp0_sphy_clk", "disp0_sphy_div", CLK_SET_RATE_PARENT, APMU_DISP0, 0x1024, 0x1024, 0x0, 0, &disp0_lock}, {MMP2_CLK_DISP1, "disp1_clk", "disp1_div", CLK_SET_RATE_PARENT, APMU_DISP1, 0x1b, 0x1b, 0x0, 0, &disp1_lock}, diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index e8fca2cf056b..4c0332386919 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -927,6 +927,9 @@ static ssize_t show(struct kobject *kobj, struct attribute *attr, char *buf) struct freq_attr *fattr = to_attr(attr); ssize_t ret; + if (!fattr->show) + return -EIO; + down_read(&policy->rwsem); if (fattr->show) @@ -946,6 +949,9 @@ static ssize_t store(struct kobject *kobj, struct attribute *attr, struct freq_attr *fattr = to_attr(attr); ssize_t ret = -EINVAL; + if (!fattr->store) + return -EIO; + get_online_cpus(); if (!cpu_online(policy->cpu)) @@ -1738,6 +1744,9 @@ void cpufreq_resume(void) if (!cpufreq_driver) return; + if (unlikely(!cpufreq_suspended)) + return; + cpufreq_suspended = false; if (!has_target()) diff --git a/drivers/crypto/mxs-dcp.c b/drivers/crypto/mxs-dcp.c index fe8cfe24c518..4b82cf9da0ba 100644 --- a/drivers/crypto/mxs-dcp.c +++ b/drivers/crypto/mxs-dcp.c @@ -28,9 +28,24 @@ #define DCP_MAX_CHANS 4 #define DCP_BUF_SZ PAGE_SIZE +#define DCP_SHA_PAY_SZ 64 #define DCP_ALIGNMENT 64 +/* + * Null hashes to align with hw behavior on imx6sl and ull + * these are flipped for consistency with hw output + */ +const uint8_t sha1_null_hash[] = + "\x09\x07\xd8\xaf\x90\x18\x60\x95\xef\xbf" + "\x55\x32\x0d\x4b\x6b\x5e\xee\xa3\x39\xda"; + +const uint8_t sha256_null_hash[] = + "\x55\xb8\x52\x78\x1b\x99\x95\xa4" + "\x4c\x93\x9b\x64\xe4\x41\xae\x27" + "\x24\xb9\x6f\x99\xc8\xf4\xfb\x9a" + "\x14\x1c\xfc\x98\x42\xc4\xb0\xe3"; + /* DCP DMA descriptor. */ struct dcp_dma_desc { uint32_t next_cmd_addr; @@ -48,6 +63,7 @@ struct dcp_coherent_block { uint8_t aes_in_buf[DCP_BUF_SZ]; uint8_t aes_out_buf[DCP_BUF_SZ]; uint8_t sha_in_buf[DCP_BUF_SZ]; + uint8_t sha_out_buf[DCP_SHA_PAY_SZ]; uint8_t aes_key[2 * AES_KEYSIZE_128]; @@ -209,6 +225,12 @@ static int mxs_dcp_run_aes(struct dcp_async_ctx *actx, dma_addr_t dst_phys = dma_map_single(sdcp->dev, sdcp->coh->aes_out_buf, DCP_BUF_SZ, DMA_FROM_DEVICE); + if (actx->fill % AES_BLOCK_SIZE) { + dev_err(sdcp->dev, "Invalid block size!\n"); + ret = -EINVAL; + goto aes_done_run; + } + /* Fill in the DMA descriptor. */ desc->control0 = MXS_DCP_CONTROL0_DECR_SEMAPHORE | MXS_DCP_CONTROL0_INTERRUPT | @@ -238,6 +260,7 @@ static int mxs_dcp_run_aes(struct dcp_async_ctx *actx, ret = mxs_dcp_start_dma(actx); +aes_done_run: dma_unmap_single(sdcp->dev, key_phys, 2 * AES_KEYSIZE_128, DMA_TO_DEVICE); dma_unmap_single(sdcp->dev, src_phys, DCP_BUF_SZ, DMA_TO_DEVICE); @@ -264,13 +287,15 @@ static int mxs_dcp_aes_block_crypt(struct crypto_async_request *arq) uint8_t *out_tmp, *src_buf, *dst_buf = NULL; uint32_t dst_off = 0; + uint32_t last_out_len = 0; uint8_t *key = sdcp->coh->aes_key; int ret = 0; int split = 0; - unsigned int i, len, clen, rem = 0; + unsigned int i, len, clen, rem = 0, tlen = 0; int init = 0; + bool limit_hit = false; actx->fill = 0; @@ -289,6 +314,11 @@ static int mxs_dcp_aes_block_crypt(struct crypto_async_request *arq) for_each_sg(req->src, src, nents, i) { src_buf = sg_virt(src); len = sg_dma_len(src); + tlen += len; + limit_hit = tlen > req->nbytes; + + if (limit_hit) + len = req->nbytes - (tlen - len); do { if (actx->fill + len > out_off) @@ -305,13 +335,15 @@ static int mxs_dcp_aes_block_crypt(struct crypto_async_request *arq) * If we filled the buffer or this is the last SG, * submit the buffer. */ - if (actx->fill == out_off || sg_is_last(src)) { + if (actx->fill == out_off || sg_is_last(src) || + limit_hit) { ret = mxs_dcp_run_aes(actx, req, init); if (ret) return ret; init = 0; out_tmp = out_buf; + last_out_len = actx->fill; while (dst && actx->fill) { if (!split) { dst_buf = sg_virt(dst); @@ -334,6 +366,19 @@ static int mxs_dcp_aes_block_crypt(struct crypto_async_request *arq) } } } while (len); + + if (limit_hit) + break; + } + + /* Copy the IV for CBC for chaining */ + if (!rctx->ecb) { + if (rctx->enc) + memcpy(req->info, out_buf+(last_out_len-AES_BLOCK_SIZE), + AES_BLOCK_SIZE); + else + memcpy(req->info, in_buf+(last_out_len-AES_BLOCK_SIZE), + AES_BLOCK_SIZE); } return ret; @@ -518,8 +563,6 @@ static int mxs_dcp_run_sha(struct ahash_request *req) struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); struct dcp_async_ctx *actx = crypto_ahash_ctx(tfm); struct dcp_sha_req_ctx *rctx = ahash_request_ctx(req); - struct hash_alg_common *halg = crypto_hash_alg_common(tfm); - struct dcp_dma_desc *desc = &sdcp->coh->desc[actx->chan]; dma_addr_t digest_phys = 0; @@ -541,10 +584,23 @@ static int mxs_dcp_run_sha(struct ahash_request *req) desc->payload = 0; desc->status = 0; + /* + * Align driver with hw behavior when generating null hashes + */ + if (rctx->init && rctx->fini && desc->size == 0) { + struct hash_alg_common *halg = crypto_hash_alg_common(tfm); + const uint8_t *sha_buf = + (actx->alg == MXS_DCP_CONTROL1_HASH_SELECT_SHA1) ? + sha1_null_hash : sha256_null_hash; + memcpy(sdcp->coh->sha_out_buf, sha_buf, halg->digestsize); + ret = 0; + goto done_run; + } + /* Set HASH_TERM bit for last transfer block. */ if (rctx->fini) { - digest_phys = dma_map_single(sdcp->dev, req->result, - halg->digestsize, DMA_FROM_DEVICE); + digest_phys = dma_map_single(sdcp->dev, sdcp->coh->sha_out_buf, + DCP_SHA_PAY_SZ, DMA_FROM_DEVICE); desc->control0 |= MXS_DCP_CONTROL0_HASH_TERM; desc->payload = digest_phys; } @@ -552,9 +608,10 @@ static int mxs_dcp_run_sha(struct ahash_request *req) ret = mxs_dcp_start_dma(actx); if (rctx->fini) - dma_unmap_single(sdcp->dev, digest_phys, halg->digestsize, + dma_unmap_single(sdcp->dev, digest_phys, DCP_SHA_PAY_SZ, DMA_FROM_DEVICE); +done_run: dma_unmap_single(sdcp->dev, buf_phys, DCP_BUF_SZ, DMA_TO_DEVICE); return ret; @@ -572,6 +629,7 @@ static int dcp_sha_req_to_buf(struct crypto_async_request *arq) const int nents = sg_nents(req->src); uint8_t *in_buf = sdcp->coh->sha_in_buf; + uint8_t *out_buf = sdcp->coh->sha_out_buf; uint8_t *src_buf; @@ -626,11 +684,9 @@ static int dcp_sha_req_to_buf(struct crypto_async_request *arq) actx->fill = 0; - /* For some reason, the result is flipped. */ - for (i = 0; i < halg->digestsize / 2; i++) { - swap(req->result[i], - req->result[halg->digestsize - i - 1]); - } + /* For some reason the result is flipped */ + for (i = 0; i < halg->digestsize; i++) + req->result[i] = out_buf[halg->digestsize - i - 1]; } return 0; diff --git a/drivers/dma/dma-jz4780.c b/drivers/dma/dma-jz4780.c index 8344b7c91fe3..1d01e3805f9c 100644 --- a/drivers/dma/dma-jz4780.c +++ b/drivers/dma/dma-jz4780.c @@ -576,7 +576,7 @@ static enum dma_status jz4780_dma_tx_status(struct dma_chan *chan, to_jz4780_dma_desc(vdesc), 0); } else if (cookie == jzchan->desc->vdesc.tx.cookie) { txstate->residue = jz4780_dma_desc_residue(jzchan, jzchan->desc, - (jzchan->curr_hwdesc + 1) % jzchan->desc->count); + jzchan->curr_hwdesc + 1); } else txstate->residue = 0; diff --git a/drivers/dma/ioat/init.c b/drivers/dma/ioat/init.c index 106fa9b327d9..92b0a7a042ee 100644 --- a/drivers/dma/ioat/init.c +++ b/drivers/dma/ioat/init.c @@ -128,7 +128,7 @@ static void ioat_init_channel(struct ioatdma_device *ioat_dma, struct ioatdma_chan *ioat_chan, int idx); static void ioat_intr_quirk(struct ioatdma_device *ioat_dma); -static int ioat_enumerate_channels(struct ioatdma_device *ioat_dma); +static void ioat_enumerate_channels(struct ioatdma_device *ioat_dma); static int ioat3_dma_self_test(struct ioatdma_device *ioat_dma); static int ioat_dca_enabled = 1; @@ -593,7 +593,7 @@ static void ioat_dma_remove(struct ioatdma_device *ioat_dma) * ioat_enumerate_channels - find and initialize the device's channels * @ioat_dma: the ioat dma device to be enumerated */ -static int ioat_enumerate_channels(struct ioatdma_device *ioat_dma) +static void ioat_enumerate_channels(struct ioatdma_device *ioat_dma) { struct ioatdma_chan *ioat_chan; struct device *dev = &ioat_dma->pdev->dev; @@ -612,7 +612,7 @@ static int ioat_enumerate_channels(struct ioatdma_device *ioat_dma) xfercap_log = readb(ioat_dma->reg_base + IOAT_XFERCAP_OFFSET); xfercap_log &= 0x1f; /* bits [4:0] valid */ if (xfercap_log == 0) - return 0; + return; dev_dbg(dev, "%s: xfercap = %d\n", __func__, 1 << xfercap_log); for (i = 0; i < dma->chancnt; i++) { @@ -629,7 +629,6 @@ static int ioat_enumerate_channels(struct ioatdma_device *ioat_dma) } } dma->chancnt = i; - return i; } /** diff --git a/drivers/dma/qcom_bam_dma.c b/drivers/dma/qcom_bam_dma.c index 5a250cdc8376..eca5b106d7d4 100644 --- a/drivers/dma/qcom_bam_dma.c +++ b/drivers/dma/qcom_bam_dma.c @@ -671,7 +671,21 @@ static int bam_dma_terminate_all(struct dma_chan *chan) /* remove all transactions, including active transaction */ spin_lock_irqsave(&bchan->vc.lock, flag); + /* + * If we have transactions queued, then some might be committed to the + * hardware in the desc fifo. The only way to reset the desc fifo is + * to do a hardware reset (either by pipe or the entire block). + * bam_chan_init_hw() will trigger a pipe reset, and also reinit the + * pipe. If the pipe is left disabled (default state after pipe reset) + * and is accessed by a connected hardware engine, a fatal error in + * the BAM will occur. There is a small window where this could happen + * with bam_chan_init_hw(), but it is assumed that the caller has + * stopped activity on any attached hardware engine. Make sure to do + * this first so that the BAM hardware doesn't cause memory corruption + * by accessing freed resources. + */ if (bchan->curr_txd) { + bam_chan_init_hw(bchan, bchan->curr_txd->dir); list_add(&bchan->curr_txd->vd.node, &bchan->vc.desc_issued); bchan->curr_txd = NULL; } diff --git a/drivers/dma/timb_dma.c b/drivers/dma/timb_dma.c index 559cd4073698..cf741187c9bb 100644 --- a/drivers/dma/timb_dma.c +++ b/drivers/dma/timb_dma.c @@ -552,7 +552,7 @@ static struct dma_async_tx_descriptor *td_prep_slave_sg(struct dma_chan *chan, } dma_sync_single_for_device(chan2dmadev(chan), td_desc->txd.phys, - td_desc->desc_list_len, DMA_MEM_TO_DEV); + td_desc->desc_list_len, DMA_TO_DEVICE); return &td_desc->txd; } diff --git a/drivers/firmware/efi/cper.c b/drivers/firmware/efi/cper.c index f40f7df4b734..c0e54396f250 100644 --- a/drivers/firmware/efi/cper.c +++ b/drivers/firmware/efi/cper.c @@ -375,7 +375,7 @@ static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie, printk("%s""vendor_id: 0x%04x, device_id: 0x%04x\n", pfx, pcie->device_id.vendor_id, pcie->device_id.device_id); p = pcie->device_id.class_code; - printk("%s""class_code: %02x%02x%02x\n", pfx, p[0], p[1], p[2]); + printk("%s""class_code: %02x%02x%02x\n", pfx, p[2], p[1], p[0]); } if (pcie->validation_bits & CPER_PCIE_VALID_SERIAL_NUMBER) printk("%s""serial number: 0x%04x, 0x%04x\n", pfx, diff --git a/drivers/firmware/google/gsmi.c b/drivers/firmware/google/gsmi.c index f1ab05ea56bb..3c117559f102 100644 --- a/drivers/firmware/google/gsmi.c +++ b/drivers/firmware/google/gsmi.c @@ -480,11 +480,10 @@ static ssize_t eventlog_write(struct file *filp, struct kobject *kobj, if (count < sizeof(u32)) return -EINVAL; param.type = *(u32 *)buf; - count -= sizeof(u32); buf += sizeof(u32); /* The remaining buffer is the data payload */ - if (count > gsmi_dev.data_buf->length) + if ((count - sizeof(u32)) > gsmi_dev.data_buf->length) return -EINVAL; param.data_len = count - sizeof(u32); @@ -504,7 +503,7 @@ static ssize_t eventlog_write(struct file *filp, struct kobject *kobj, spin_unlock_irqrestore(&gsmi_dev.lock, flags); - return rc; + return (rc == 0) ? count : rc; } diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c index 07dc692851d8..5a271b3f9bfb 100644 --- a/drivers/firmware/psci.c +++ b/drivers/firmware/psci.c @@ -58,7 +58,10 @@ bool psci_tos_resident_on(int cpu) return cpu == resident_cpu; } -struct psci_operations psci_ops; +struct psci_operations psci_ops = { + .conduit = PSCI_CONDUIT_NONE, + .smccc_version = SMCCC_VERSION_1_0, +}; typedef unsigned long (psci_fn)(unsigned long, unsigned long, unsigned long, unsigned long); @@ -189,6 +192,22 @@ static unsigned long psci_migrate_info_up_cpu(void) 0, 0, 0); } +static void set_conduit(enum psci_conduit conduit) +{ + switch (conduit) { + case PSCI_CONDUIT_HVC: + invoke_psci_fn = __invoke_psci_fn_hvc; + break; + case PSCI_CONDUIT_SMC: + invoke_psci_fn = __invoke_psci_fn_smc; + break; + default: + WARN(1, "Unexpected PSCI conduit %d\n", conduit); + } + + psci_ops.conduit = conduit; +} + static int get_set_conduit_method(struct device_node *np) { const char *method; @@ -201,9 +220,9 @@ static int get_set_conduit_method(struct device_node *np) } if (!strcmp("hvc", method)) { - invoke_psci_fn = __invoke_psci_fn_hvc; + set_conduit(PSCI_CONDUIT_HVC); } else if (!strcmp("smc", method)) { - invoke_psci_fn = __invoke_psci_fn_smc; + set_conduit(PSCI_CONDUIT_SMC); } else { pr_warn("invalid \"method\" property: %s\n", method); return -EINVAL; @@ -428,6 +447,31 @@ static void __init psci_init_migrate(void) pr_info("Trusted OS resident on physical CPU 0x%lx\n", cpuid); } +static void __init psci_init_smccc(void) +{ + u32 ver = ARM_SMCCC_VERSION_1_0; + int feature; + + feature = psci_features(ARM_SMCCC_VERSION_FUNC_ID); + + if (feature != PSCI_RET_NOT_SUPPORTED) { + u32 ret; + ret = invoke_psci_fn(ARM_SMCCC_VERSION_FUNC_ID, 0, 0, 0); + if (ret == ARM_SMCCC_VERSION_1_1) { + psci_ops.smccc_version = SMCCC_VERSION_1_1; + ver = ret; + } + } + + /* + * Conveniently, the SMCCC and PSCI versions are encoded the + * same way. No, this isn't accidental. + */ + pr_info("SMC Calling Convention v%d.%d\n", + PSCI_VERSION_MAJOR(ver), PSCI_VERSION_MINOR(ver)); + +} + static void __init psci_0_2_set_functions(void) { pr_info("Using standard PSCI v0.2 function IDs\n"); @@ -476,6 +520,7 @@ static int __init psci_probe(void) psci_init_migrate(); if (PSCI_VERSION_MAJOR(ver) >= 1) { + psci_init_smccc(); psci_init_cpu_suspend(); psci_init_system_suspend(); } @@ -589,9 +634,9 @@ int __init psci_acpi_init(void) pr_info("probing for conduit method from ACPI.\n"); if (acpi_psci_use_hvc()) - invoke_psci_fn = __invoke_psci_fn_hvc; + set_conduit(PSCI_CONDUIT_HVC); else - invoke_psci_fn = __invoke_psci_fn_smc; + set_conduit(PSCI_CONDUIT_SMC); return psci_probe(); } diff --git a/drivers/gpio/gpio-syscon.c b/drivers/gpio/gpio-syscon.c index 7b25fdf64802..f579938552cc 100644 --- a/drivers/gpio/gpio-syscon.c +++ b/drivers/gpio/gpio-syscon.c @@ -127,7 +127,7 @@ static int syscon_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int val) BIT(offs % SYSCON_REG_BITS)); } - priv->data->set(chip, offset, val); + chip->set(chip, offset, val); return 0; } diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c index db58c8d664c2..6188b70c2790 100644 --- a/drivers/gpu/drm/i915/i915_cmd_parser.c +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c @@ -50,13 +50,11 @@ * granting userspace undue privileges. There are three categories of privilege. * * First, commands which are explicitly defined as privileged or which should - * only be used by the kernel driver. The parser generally rejects such - * commands, though it may allow some from the drm master process. + * only be used by the kernel driver. The parser rejects such commands * * Second, commands which access registers. To support correct/enhanced * userspace functionality, particularly certain OpenGL extensions, the parser - * provides a whitelist of registers which userspace may safely access (for both - * normal and drm master processes). + * provides a whitelist of registers which userspace may safely access * * Third, commands which access privileged memory (i.e. GGTT, HWS page, etc). * The parser always rejects such commands. @@ -81,9 +79,9 @@ * in the per-ring command tables. * * Other command table entries map fairly directly to high level categories - * mentioned above: rejected, master-only, register whitelist. The parser - * implements a number of checks, including the privileged memory checks, via a - * general bitmasking mechanism. + * mentioned above: rejected, register whitelist. The parser implements a number + * of checks, including the privileged memory checks, via a general bitmasking + * mechanism. */ #define STD_MI_OPCODE_MASK 0xFF800000 @@ -94,7 +92,7 @@ #define CMD(op, opm, f, lm, fl, ...) \ { \ .flags = (fl) | ((f) ? CMD_DESC_FIXED : 0), \ - .cmd = { (op), (opm) }, \ + .cmd = { (op) & (opm), (opm) }, \ .length = { (lm) }, \ __VA_ARGS__ \ } @@ -109,14 +107,13 @@ #define R CMD_DESC_REJECT #define W CMD_DESC_REGISTER #define B CMD_DESC_BITMASK -#define M CMD_DESC_MASTER /* Command Mask Fixed Len Action ---------------------------------------------------------- */ -static const struct drm_i915_cmd_descriptor common_cmds[] = { +static const struct drm_i915_cmd_descriptor gen7_common_cmds[] = { CMD( MI_NOOP, SMI, F, 1, S ), CMD( MI_USER_INTERRUPT, SMI, F, 1, R ), - CMD( MI_WAIT_FOR_EVENT, SMI, F, 1, M ), + CMD( MI_WAIT_FOR_EVENT, SMI, F, 1, R ), CMD( MI_ARB_CHECK, SMI, F, 1, S ), CMD( MI_REPORT_HEAD, SMI, F, 1, S ), CMD( MI_SUSPEND_FLUSH, SMI, F, 1, S ), @@ -146,7 +143,7 @@ static const struct drm_i915_cmd_descriptor common_cmds[] = { CMD( MI_BATCH_BUFFER_START, SMI, !F, 0xFF, S ), }; -static const struct drm_i915_cmd_descriptor render_cmds[] = { +static const struct drm_i915_cmd_descriptor gen7_render_cmds[] = { CMD( MI_FLUSH, SMI, F, 1, S ), CMD( MI_ARB_ON_OFF, SMI, F, 1, R ), CMD( MI_PREDICATE, SMI, F, 1, S ), @@ -213,7 +210,7 @@ static const struct drm_i915_cmd_descriptor hsw_render_cmds[] = { CMD( MI_URB_ATOMIC_ALLOC, SMI, F, 1, S ), CMD( MI_SET_APPID, SMI, F, 1, S ), CMD( MI_RS_CONTEXT, SMI, F, 1, S ), - CMD( MI_LOAD_SCAN_LINES_INCL, SMI, !F, 0x3F, M ), + CMD( MI_LOAD_SCAN_LINES_INCL, SMI, !F, 0x3F, R ), CMD( MI_LOAD_SCAN_LINES_EXCL, SMI, !F, 0x3F, R ), CMD( MI_LOAD_REGISTER_REG, SMI, !F, 0xFF, R ), CMD( MI_RS_STORE_DATA_IMM, SMI, !F, 0xFF, S ), @@ -229,7 +226,7 @@ static const struct drm_i915_cmd_descriptor hsw_render_cmds[] = { CMD( GFX_OP_3DSTATE_BINDING_TABLE_EDIT_PS, S3D, !F, 0x1FF, S ), }; -static const struct drm_i915_cmd_descriptor video_cmds[] = { +static const struct drm_i915_cmd_descriptor gen7_video_cmds[] = { CMD( MI_ARB_ON_OFF, SMI, F, 1, R ), CMD( MI_SET_APPID, SMI, F, 1, S ), CMD( MI_STORE_DWORD_IMM, SMI, !F, 0xFF, B, @@ -273,7 +270,7 @@ static const struct drm_i915_cmd_descriptor video_cmds[] = { CMD( MFX_WAIT, SMFX, F, 1, S ), }; -static const struct drm_i915_cmd_descriptor vecs_cmds[] = { +static const struct drm_i915_cmd_descriptor gen7_vecs_cmds[] = { CMD( MI_ARB_ON_OFF, SMI, F, 1, R ), CMD( MI_SET_APPID, SMI, F, 1, S ), CMD( MI_STORE_DWORD_IMM, SMI, !F, 0xFF, B, @@ -311,7 +308,7 @@ static const struct drm_i915_cmd_descriptor vecs_cmds[] = { }}, ), }; -static const struct drm_i915_cmd_descriptor blt_cmds[] = { +static const struct drm_i915_cmd_descriptor gen7_blt_cmds[] = { CMD( MI_DISPLAY_FLIP, SMI, !F, 0xFF, R ), CMD( MI_STORE_DWORD_IMM, SMI, !F, 0x3FF, B, .bits = {{ @@ -345,10 +342,62 @@ static const struct drm_i915_cmd_descriptor blt_cmds[] = { }; static const struct drm_i915_cmd_descriptor hsw_blt_cmds[] = { - CMD( MI_LOAD_SCAN_LINES_INCL, SMI, !F, 0x3F, M ), + CMD( MI_LOAD_SCAN_LINES_INCL, SMI, !F, 0x3F, R ), CMD( MI_LOAD_SCAN_LINES_EXCL, SMI, !F, 0x3F, R ), }; +/* + * For Gen9 we can still rely on the h/w to enforce cmd security, and only + * need to re-enforce the register access checks. We therefore only need to + * teach the cmdparser how to find the end of each command, and identify + * register accesses. The table doesn't need to reject any commands, and so + * the only commands listed here are: + * 1) Those that touch registers + * 2) Those that do not have the default 8-bit length + * + * Note that the default MI length mask chosen for this table is 0xFF, not + * the 0x3F used on older devices. This is because the vast majority of MI + * cmds on Gen9 use a standard 8-bit Length field. + * All the Gen9 blitter instructions are standard 0xFF length mask, and + * none allow access to non-general registers, so in fact no BLT cmds are + * included in the table at all. + * + */ +static const struct drm_i915_cmd_descriptor gen9_blt_cmds[] = { + CMD( MI_NOOP, SMI, F, 1, S ), + CMD( MI_USER_INTERRUPT, SMI, F, 1, S ), + CMD( MI_WAIT_FOR_EVENT, SMI, F, 1, S ), + CMD( MI_FLUSH, SMI, F, 1, S ), + CMD( MI_ARB_CHECK, SMI, F, 1, S ), + CMD( MI_REPORT_HEAD, SMI, F, 1, S ), + CMD( MI_ARB_ON_OFF, SMI, F, 1, S ), + CMD( MI_SUSPEND_FLUSH, SMI, F, 1, S ), + CMD( MI_LOAD_SCAN_LINES_INCL, SMI, !F, 0x3F, S ), + CMD( MI_LOAD_SCAN_LINES_EXCL, SMI, !F, 0x3F, S ), + CMD( MI_STORE_DWORD_IMM, SMI, !F, 0x3FF, S ), + CMD( MI_LOAD_REGISTER_IMM(1), SMI, !F, 0xFF, W, + .reg = { .offset = 1, .mask = 0x007FFFFC, .step = 2 } ), + CMD( MI_UPDATE_GTT, SMI, !F, 0x3FF, S ), + CMD( MI_STORE_REGISTER_MEM_GEN8, SMI, F, 4, W, + .reg = { .offset = 1, .mask = 0x007FFFFC } ), + CMD( MI_FLUSH_DW, SMI, !F, 0x3F, S ), + CMD( MI_LOAD_REGISTER_MEM_GEN8, SMI, F, 4, W, + .reg = { .offset = 1, .mask = 0x007FFFFC } ), + CMD( MI_LOAD_REGISTER_REG, SMI, !F, 0xFF, W, + .reg = { .offset = 1, .mask = 0x007FFFFC, .step = 1 } ), + + /* + * We allow BB_START but apply further checks. We just sanitize the + * basic fields here. + */ + CMD( MI_BATCH_BUFFER_START_GEN8, SMI, !F, 0xFF, B, + .bits = {{ + .offset = 0, + .mask = ~SMI, + .expected = (MI_BATCH_PPGTT_HSW | 1), + }}, ), +}; + #undef CMD #undef SMI #undef S3D @@ -359,40 +408,44 @@ static const struct drm_i915_cmd_descriptor hsw_blt_cmds[] = { #undef R #undef W #undef B -#undef M -static const struct drm_i915_cmd_table gen7_render_cmds[] = { - { common_cmds, ARRAY_SIZE(common_cmds) }, - { render_cmds, ARRAY_SIZE(render_cmds) }, +static const struct drm_i915_cmd_table gen7_render_cmd_table[] = { + { gen7_common_cmds, ARRAY_SIZE(gen7_common_cmds) }, + { gen7_render_cmds, ARRAY_SIZE(gen7_render_cmds) }, }; -static const struct drm_i915_cmd_table hsw_render_ring_cmds[] = { - { common_cmds, ARRAY_SIZE(common_cmds) }, - { render_cmds, ARRAY_SIZE(render_cmds) }, +static const struct drm_i915_cmd_table hsw_render_ring_cmd_table[] = { + { gen7_common_cmds, ARRAY_SIZE(gen7_common_cmds) }, + { gen7_render_cmds, ARRAY_SIZE(gen7_render_cmds) }, { hsw_render_cmds, ARRAY_SIZE(hsw_render_cmds) }, }; -static const struct drm_i915_cmd_table gen7_video_cmds[] = { - { common_cmds, ARRAY_SIZE(common_cmds) }, - { video_cmds, ARRAY_SIZE(video_cmds) }, +static const struct drm_i915_cmd_table gen7_video_cmd_table[] = { + { gen7_common_cmds, ARRAY_SIZE(gen7_common_cmds) }, + { gen7_video_cmds, ARRAY_SIZE(gen7_video_cmds) }, }; -static const struct drm_i915_cmd_table hsw_vebox_cmds[] = { - { common_cmds, ARRAY_SIZE(common_cmds) }, - { vecs_cmds, ARRAY_SIZE(vecs_cmds) }, +static const struct drm_i915_cmd_table hsw_vebox_cmd_table[] = { + { gen7_common_cmds, ARRAY_SIZE(gen7_common_cmds) }, + { gen7_vecs_cmds, ARRAY_SIZE(gen7_vecs_cmds) }, }; -static const struct drm_i915_cmd_table gen7_blt_cmds[] = { - { common_cmds, ARRAY_SIZE(common_cmds) }, - { blt_cmds, ARRAY_SIZE(blt_cmds) }, +static const struct drm_i915_cmd_table gen7_blt_cmd_table[] = { + { gen7_common_cmds, ARRAY_SIZE(gen7_common_cmds) }, + { gen7_blt_cmds, ARRAY_SIZE(gen7_blt_cmds) }, }; -static const struct drm_i915_cmd_table hsw_blt_ring_cmds[] = { - { common_cmds, ARRAY_SIZE(common_cmds) }, - { blt_cmds, ARRAY_SIZE(blt_cmds) }, +static const struct drm_i915_cmd_table hsw_blt_ring_cmd_table[] = { + { gen7_common_cmds, ARRAY_SIZE(gen7_common_cmds) }, + { gen7_blt_cmds, ARRAY_SIZE(gen7_blt_cmds) }, { hsw_blt_cmds, ARRAY_SIZE(hsw_blt_cmds) }, }; +static const struct drm_i915_cmd_table gen9_blt_cmd_table[] = { + { gen9_blt_cmds, ARRAY_SIZE(gen9_blt_cmds) }, +}; + + /* * Register whitelists, sorted by increasing register offset. */ @@ -426,6 +479,10 @@ struct drm_i915_reg_descriptor { #define REG64(addr) \ REG32(addr), REG32(addr + sizeof(u32)) +#define REG64_IDX(_reg, idx) \ + { .addr = _reg(idx) }, \ + { .addr = _reg ## _UDW(idx) } + static const struct drm_i915_reg_descriptor gen7_render_regs[] = { REG64(GPGPU_THREADS_DISPATCHED), REG64(HS_INVOCATION_COUNT), @@ -479,17 +536,27 @@ static const struct drm_i915_reg_descriptor gen7_blt_regs[] = { REG32(BCS_SWCTRL), }; -static const struct drm_i915_reg_descriptor ivb_master_regs[] = { - REG32(FORCEWAKE_MT), - REG32(DERRMR), - REG32(GEN7_PIPE_DE_LOAD_SL(PIPE_A)), - REG32(GEN7_PIPE_DE_LOAD_SL(PIPE_B)), - REG32(GEN7_PIPE_DE_LOAD_SL(PIPE_C)), -}; - -static const struct drm_i915_reg_descriptor hsw_master_regs[] = { - REG32(FORCEWAKE_MT), - REG32(DERRMR), +static const struct drm_i915_reg_descriptor gen9_blt_regs[] = { + REG64_IDX(RING_TIMESTAMP, RENDER_RING_BASE), + REG64_IDX(RING_TIMESTAMP, BSD_RING_BASE), + REG32(BCS_SWCTRL), + REG64_IDX(RING_TIMESTAMP, BLT_RING_BASE), + REG64_IDX(BCS_GPR, 0), + REG64_IDX(BCS_GPR, 1), + REG64_IDX(BCS_GPR, 2), + REG64_IDX(BCS_GPR, 3), + REG64_IDX(BCS_GPR, 4), + REG64_IDX(BCS_GPR, 5), + REG64_IDX(BCS_GPR, 6), + REG64_IDX(BCS_GPR, 7), + REG64_IDX(BCS_GPR, 8), + REG64_IDX(BCS_GPR, 9), + REG64_IDX(BCS_GPR, 10), + REG64_IDX(BCS_GPR, 11), + REG64_IDX(BCS_GPR, 12), + REG64_IDX(BCS_GPR, 13), + REG64_IDX(BCS_GPR, 14), + REG64_IDX(BCS_GPR, 15), }; #undef REG64 @@ -550,6 +617,17 @@ static u32 gen7_blt_get_cmd_length_mask(u32 cmd_header) return 0; } +static u32 gen9_blt_get_cmd_length_mask(u32 cmd_header) +{ + u32 client = (cmd_header & INSTR_CLIENT_MASK) >> INSTR_CLIENT_SHIFT; + + if (client == INSTR_MI_CLIENT || client == INSTR_BC_CLIENT) + return 0xFF; + + DRM_DEBUG_DRIVER("CMD: Abnormal blt cmd length! 0x%08X\n", cmd_header); + return 0; +} + static bool validate_cmds_sorted(struct intel_engine_cs *ring, const struct drm_i915_cmd_table *cmd_tables, int cmd_table_count) @@ -608,9 +686,7 @@ static bool check_sorted(int ring_id, static bool validate_regs_sorted(struct intel_engine_cs *ring) { - return check_sorted(ring->id, ring->reg_table, ring->reg_count) && - check_sorted(ring->id, ring->master_reg_table, - ring->master_reg_count); + return check_sorted(ring->id, ring->reg_table, ring->reg_count); } struct cmd_node { @@ -691,63 +767,61 @@ int i915_cmd_parser_init_ring(struct intel_engine_cs *ring) int cmd_table_count; int ret; - if (!IS_GEN7(ring->dev)) + if (!IS_GEN7(ring->dev) && !(IS_GEN9(ring->dev) && ring->id == BCS)) return 0; switch (ring->id) { case RCS: if (IS_HASWELL(ring->dev)) { - cmd_tables = hsw_render_ring_cmds; + cmd_tables = hsw_render_ring_cmd_table; cmd_table_count = - ARRAY_SIZE(hsw_render_ring_cmds); + ARRAY_SIZE(hsw_render_ring_cmd_table); } else { - cmd_tables = gen7_render_cmds; - cmd_table_count = ARRAY_SIZE(gen7_render_cmds); + cmd_tables = gen7_render_cmd_table; + cmd_table_count = ARRAY_SIZE(gen7_render_cmd_table); } ring->reg_table = gen7_render_regs; ring->reg_count = ARRAY_SIZE(gen7_render_regs); - if (IS_HASWELL(ring->dev)) { - ring->master_reg_table = hsw_master_regs; - ring->master_reg_count = ARRAY_SIZE(hsw_master_regs); - } else { - ring->master_reg_table = ivb_master_regs; - ring->master_reg_count = ARRAY_SIZE(ivb_master_regs); - } - ring->get_cmd_length_mask = gen7_render_get_cmd_length_mask; break; case VCS: - cmd_tables = gen7_video_cmds; - cmd_table_count = ARRAY_SIZE(gen7_video_cmds); + cmd_tables = gen7_video_cmd_table; + cmd_table_count = ARRAY_SIZE(gen7_video_cmd_table); ring->get_cmd_length_mask = gen7_bsd_get_cmd_length_mask; break; case BCS: - if (IS_HASWELL(ring->dev)) { - cmd_tables = hsw_blt_ring_cmds; - cmd_table_count = ARRAY_SIZE(hsw_blt_ring_cmds); + ring->get_cmd_length_mask = gen7_blt_get_cmd_length_mask; + if (IS_GEN9(ring->dev)) { + cmd_tables = gen9_blt_cmd_table; + cmd_table_count = ARRAY_SIZE(gen9_blt_cmd_table); + ring->get_cmd_length_mask = + gen9_blt_get_cmd_length_mask; + + /* BCS Engine unsafe without parser */ + ring->requires_cmd_parser = 1; + } + else if (IS_HASWELL(ring->dev)) { + cmd_tables = hsw_blt_ring_cmd_table; + cmd_table_count = ARRAY_SIZE(hsw_blt_ring_cmd_table); } else { - cmd_tables = gen7_blt_cmds; - cmd_table_count = ARRAY_SIZE(gen7_blt_cmds); + cmd_tables = gen7_blt_cmd_table; + cmd_table_count = ARRAY_SIZE(gen7_blt_cmd_table); } - ring->reg_table = gen7_blt_regs; - ring->reg_count = ARRAY_SIZE(gen7_blt_regs); - - if (IS_HASWELL(ring->dev)) { - ring->master_reg_table = hsw_master_regs; - ring->master_reg_count = ARRAY_SIZE(hsw_master_regs); + if (IS_GEN9(ring->dev)) { + ring->reg_table = gen9_blt_regs; + ring->reg_count = ARRAY_SIZE(gen9_blt_regs); } else { - ring->master_reg_table = ivb_master_regs; - ring->master_reg_count = ARRAY_SIZE(ivb_master_regs); + ring->reg_table = gen7_blt_regs; + ring->reg_count = ARRAY_SIZE(gen7_blt_regs); } - ring->get_cmd_length_mask = gen7_blt_get_cmd_length_mask; break; case VECS: - cmd_tables = hsw_vebox_cmds; - cmd_table_count = ARRAY_SIZE(hsw_vebox_cmds); + cmd_tables = hsw_vebox_cmd_table; + cmd_table_count = ARRAY_SIZE(hsw_vebox_cmd_table); /* VECS can use the same length_mask function as VCS */ ring->get_cmd_length_mask = gen7_bsd_get_cmd_length_mask; break; @@ -769,7 +843,7 @@ int i915_cmd_parser_init_ring(struct intel_engine_cs *ring) return ret; } - ring->needs_cmd_parser = true; + ring->using_cmd_parser = true; return 0; } @@ -783,7 +857,7 @@ int i915_cmd_parser_init_ring(struct intel_engine_cs *ring) */ void i915_cmd_parser_fini_ring(struct intel_engine_cs *ring) { - if (!ring->needs_cmd_parser) + if (!ring->using_cmd_parser) return; fini_hash_table(ring); @@ -949,30 +1023,9 @@ unpin_src: return ret ? ERR_PTR(ret) : dst; } -/** - * i915_needs_cmd_parser() - should a given ring use software command parsing? - * @ring: the ring in question - * - * Only certain platforms require software batch buffer command parsing, and - * only when enabled via module parameter. - * - * Return: true if the ring requires software command parsing - */ -bool i915_needs_cmd_parser(struct intel_engine_cs *ring) -{ - if (!ring->needs_cmd_parser) - return false; - - if (!USES_PPGTT(ring->dev)) - return false; - - return (i915.enable_cmd_parser == 1); -} - -static bool check_cmd(const struct intel_engine_cs *ring, +static int check_cmd(const struct intel_engine_cs *ring, const struct drm_i915_cmd_descriptor *desc, const u32 *cmd, u32 length, - const bool is_master, bool *oacontrol_set) { if (desc->flags & CMD_DESC_REJECT) { @@ -980,12 +1033,6 @@ static bool check_cmd(const struct intel_engine_cs *ring, return false; } - if ((desc->flags & CMD_DESC_MASTER) && !is_master) { - DRM_DEBUG_DRIVER("CMD: Rejected master-only command: 0x%08X\n", - *cmd); - return false; - } - if (desc->flags & CMD_DESC_REGISTER) { /* * Get the distance between individual register offset @@ -1002,11 +1049,6 @@ static bool check_cmd(const struct intel_engine_cs *ring, find_reg(ring->reg_table, ring->reg_count, reg_addr); - if (!reg && is_master) - reg = find_reg(ring->master_reg_table, - ring->master_reg_count, - reg_addr); - if (!reg) { DRM_DEBUG_DRIVER("CMD: Rejected register 0x%08X in command: 0x%08X (ring=%d)\n", reg_addr, *cmd, ring->id); @@ -1091,16 +1133,113 @@ static bool check_cmd(const struct intel_engine_cs *ring, return true; } +static int check_bbstart(struct intel_context *ctx, + u32 *cmd, u64 offset, u32 length, + u32 batch_len, + u64 batch_start, + u64 shadow_batch_start) +{ + + u64 jump_offset, jump_target; + u32 target_cmd_offset, target_cmd_index; + + /* For igt compatibility on older platforms */ + if (CMDPARSER_USES_GGTT(ctx->i915)) { + DRM_DEBUG("CMD: Rejecting BB_START for ggtt based submission\n"); + return -EACCES; + } + + if (length != 3) { + DRM_DEBUG("CMD: Recursive BB_START with bad length(%u)\n", + length); + return -EINVAL; + } + + jump_target = *(u64*)(cmd+1); + jump_offset = jump_target - batch_start; + + /* + * Any underflow of jump_target is guaranteed to be outside the range + * of a u32, so >= test catches both too large and too small + */ + if (jump_offset >= batch_len) { + DRM_DEBUG("CMD: BB_START to 0x%llx jumps out of BB\n", + jump_target); + return -EINVAL; + } + + /* + * This cannot overflow a u32 because we already checked jump_offset + * is within the BB, and the batch_len is a u32 + */ + target_cmd_offset = lower_32_bits(jump_offset); + target_cmd_index = target_cmd_offset / sizeof(u32); + + *(u64*)(cmd + 1) = shadow_batch_start + target_cmd_offset; + + if (target_cmd_index == offset) + return 0; + + if (ctx->jump_whitelist_cmds <= target_cmd_index) { + DRM_DEBUG("CMD: Rejecting BB_START - truncated whitelist array\n"); + return -EINVAL; + } else if (!test_bit(target_cmd_index, ctx->jump_whitelist)) { + DRM_DEBUG("CMD: BB_START to 0x%llx not a previously executed cmd\n", + jump_target); + return -EINVAL; + } + + return 0; +} + +static void init_whitelist(struct intel_context *ctx, u32 batch_len) +{ + const u32 batch_cmds = DIV_ROUND_UP(batch_len, sizeof(u32)); + const u32 exact_size = BITS_TO_LONGS(batch_cmds); + u32 next_size = BITS_TO_LONGS(roundup_pow_of_two(batch_cmds)); + unsigned long *next_whitelist; + + if (CMDPARSER_USES_GGTT(ctx->i915)) + return; + + if (batch_cmds <= ctx->jump_whitelist_cmds) { + bitmap_zero(ctx->jump_whitelist, batch_cmds); + return; + } + +again: + next_whitelist = kcalloc(next_size, sizeof(long), GFP_KERNEL); + if (next_whitelist) { + kfree(ctx->jump_whitelist); + ctx->jump_whitelist = next_whitelist; + ctx->jump_whitelist_cmds = + next_size * BITS_PER_BYTE * sizeof(long); + return; + } + + if (next_size > exact_size) { + next_size = exact_size; + goto again; + } + + DRM_DEBUG("CMD: Failed to extend whitelist. BB_START may be disallowed\n"); + bitmap_zero(ctx->jump_whitelist, ctx->jump_whitelist_cmds); + + return; +} + #define LENGTH_BIAS 2 /** * i915_parse_cmds() - parse a submitted batch buffer for privilege violations + * @ctx: the context in which the batch is to execute * @ring: the ring on which the batch is to execute * @batch_obj: the batch buffer in question - * @shadow_batch_obj: copy of the batch buffer in question + * @user_batch_start: Canonical base address of original user batch * @batch_start_offset: byte offset in the batch at which execution starts * @batch_len: length of the commands in batch_obj - * @is_master: is the submitting process the drm master? + * @shadow_batch_obj: copy of the batch buffer in question + * @shadow_batch_start: Canonical base address of shadow_batch_obj * * Parses the specified batch buffer looking for privilege violations as * described in the overview. @@ -1108,14 +1247,16 @@ static bool check_cmd(const struct intel_engine_cs *ring, * Return: non-zero if the parser finds violations or otherwise fails; -EACCES * if the batch appears legal but should use hardware parsing */ -int i915_parse_cmds(struct intel_engine_cs *ring, +int i915_parse_cmds(struct intel_context *ctx, + struct intel_engine_cs *ring, struct drm_i915_gem_object *batch_obj, - struct drm_i915_gem_object *shadow_batch_obj, + u64 user_batch_start, u32 batch_start_offset, u32 batch_len, - bool is_master) + struct drm_i915_gem_object *shadow_batch_obj, + u64 shadow_batch_start) { - u32 *cmd, *batch_base, *batch_end; + u32 *cmd, *batch_base, *batch_end, offset = 0; struct drm_i915_cmd_descriptor default_desc = { 0 }; bool oacontrol_set = false; /* OACONTROL tracking. See check_cmd() */ int ret = 0; @@ -1127,6 +1268,8 @@ int i915_parse_cmds(struct intel_engine_cs *ring, return PTR_ERR(batch_base); } + init_whitelist(ctx, batch_len); + /* * We use the batch length as size because the shadow object is as * large or larger and copy_batch() will write MI_NOPs to the extra @@ -1150,16 +1293,6 @@ int i915_parse_cmds(struct intel_engine_cs *ring, break; } - /* - * If the batch buffer contains a chained batch, return an - * error that tells the caller to abort and dispatch the - * workload as a non-secure batch. - */ - if (desc->cmd.value == MI_BATCH_BUFFER_START) { - ret = -EACCES; - break; - } - if (desc->flags & CMD_DESC_FIXED) length = desc->length.fixed; else @@ -1174,13 +1307,23 @@ int i915_parse_cmds(struct intel_engine_cs *ring, break; } - if (!check_cmd(ring, desc, cmd, length, is_master, - &oacontrol_set)) { - ret = -EINVAL; + if (!check_cmd(ring, desc, cmd, length, &oacontrol_set)) { + ret = CMDPARSER_USES_GGTT(ring->dev) ? -EINVAL : -EACCES; break; } + if (desc->cmd.value == MI_BATCH_BUFFER_START) { + ret = check_bbstart(ctx, cmd, offset, length, + batch_len, user_batch_start, + shadow_batch_start); + break; + } + + if (ctx->jump_whitelist_cmds > offset) + set_bit(offset, ctx->jump_whitelist); + cmd += length; + offset += length; } if (oacontrol_set) { @@ -1206,7 +1349,7 @@ int i915_parse_cmds(struct intel_engine_cs *ring, * * Return: the current version number of the cmd parser */ -int i915_cmd_parser_get_version(void) +int i915_cmd_parser_get_version(struct drm_i915_private *dev_priv) { /* * Command parser version history @@ -1218,6 +1361,7 @@ int i915_cmd_parser_get_version(void) * 3. Allow access to the GPGPU_THREADS_DISPATCHED register. * 4. L3 atomic chicken bits of HSW_SCRATCH1 and HSW_ROW_CHICKEN3. * 5. GPGPU dispatch compute indirect registers. + * 10. Gen9 only - Supports the new ppgtt based BLIT parser */ - return 5; + return CMDPARSER_USES_GGTT(dev_priv) ? 5 : 10; } diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 61fcb3b22297..7b61078c2330 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -133,7 +133,7 @@ static int i915_getparam(struct drm_device *dev, void *data, value = 1; break; case I915_PARAM_HAS_SECURE_BATCHES: - value = capable(CAP_SYS_ADMIN); + value = HAS_SECURE_BATCHES(dev_priv) && capable(CAP_SYS_ADMIN); break; case I915_PARAM_HAS_PINNED_BATCHES: value = 1; @@ -145,7 +145,7 @@ static int i915_getparam(struct drm_device *dev, void *data, value = 1; break; case I915_PARAM_CMD_PARSER_VERSION: - value = i915_cmd_parser_get_version(); + value = i915_cmd_parser_get_version(dev_priv); break; case I915_PARAM_HAS_COHERENT_PHYS_GTT: value = 1; diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index a6ad938f44a6..697b2499c7a1 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -698,6 +698,8 @@ static int i915_drm_suspend_late(struct drm_device *drm_dev, bool hibernation) return ret; } + i915_rc6_ctx_wa_suspend(dev_priv); + pci_disable_device(drm_dev->pdev); /* * During hibernation on some platforms the BIOS may try to access @@ -849,6 +851,8 @@ static int i915_drm_resume_early(struct drm_device *dev) intel_uncore_sanitize(dev); intel_power_domains_init_hw(dev_priv); + i915_rc6_ctx_wa_resume(dev_priv); + return ret; } diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 6fca39e1c419..5799356f6b6b 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -891,6 +891,12 @@ struct intel_context { int pin_count; } engine[I915_NUM_RINGS]; + /* jump_whitelist: Bit array for tracking cmds during cmdparsing */ + unsigned long *jump_whitelist; + + /* jump_whitelist_cmds: No of cmd slots available */ + uint32_t jump_whitelist_cmds; + struct list_head link; }; @@ -1153,6 +1159,7 @@ struct intel_gen6_power_mgmt { bool client_boost; bool enabled; + bool ctx_corrupted; struct delayed_work delayed_resume_work; unsigned boosts; @@ -2539,6 +2546,9 @@ struct drm_i915_cmd_table { #define HAS_BSD2(dev) (INTEL_INFO(dev)->ring_mask & BSD2_RING) #define HAS_BLT(dev) (INTEL_INFO(dev)->ring_mask & BLT_RING) #define HAS_VEBOX(dev) (INTEL_INFO(dev)->ring_mask & VEBOX_RING) + +#define HAS_SECURE_BATCHES(dev_priv) (INTEL_INFO(dev_priv)->gen < 6) + #define HAS_LLC(dev) (INTEL_INFO(dev)->has_llc) #define HAS_WT(dev) ((IS_HASWELL(dev) || IS_BROADWELL(dev)) && \ __I915__(dev)->ellc_size) @@ -2553,8 +2563,18 @@ struct drm_i915_cmd_table { #define HAS_OVERLAY(dev) (INTEL_INFO(dev)->has_overlay) #define OVERLAY_NEEDS_PHYSICAL(dev) (INTEL_INFO(dev)->overlay_needs_physical) +/* + * The Gen7 cmdparser copies the scanned buffer to the ggtt for execution + * All later gens can run the final buffer from the ppgtt + */ +#define CMDPARSER_USES_GGTT(dev_priv) IS_GEN7(dev_priv) + /* Early gen2 have a totally busted CS tlb and require pinned batches. */ #define HAS_BROKEN_CS_TLB(dev) (IS_I830(dev) || IS_845G(dev)) + +#define NEEDS_RC6_CTX_CORRUPTION_WA(dev) \ + (IS_BROADWELL(dev) || INTEL_INFO(dev)->gen == 9) + /* * dp aux and gmbus irq on gen4 seems to be able to generate legacy interrupts * even when in MSI mode. This results in spurious interrupt warnings if the @@ -3276,16 +3296,19 @@ void i915_get_extra_instdone(struct drm_device *dev, uint32_t *instdone); const char *i915_cache_level_str(struct drm_i915_private *i915, int type); /* i915_cmd_parser.c */ -int i915_cmd_parser_get_version(void); +int i915_cmd_parser_get_version(struct drm_i915_private *dev_priv); int i915_cmd_parser_init_ring(struct intel_engine_cs *ring); void i915_cmd_parser_fini_ring(struct intel_engine_cs *ring); bool i915_needs_cmd_parser(struct intel_engine_cs *ring); -int i915_parse_cmds(struct intel_engine_cs *ring, +int i915_parse_cmds(struct intel_context *cxt, + struct intel_engine_cs *ring, struct drm_i915_gem_object *batch_obj, - struct drm_i915_gem_object *shadow_batch_obj, + u64 user_batch_start, u32 batch_start_offset, u32 batch_len, - bool is_master); + struct drm_i915_gem_object *shadow_batch_obj, + u64 shadow_batch_start); + /* i915_suspend.c */ extern int i915_save_state(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 0433d25f9d23..20fb0ee1df4f 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -157,6 +157,8 @@ void i915_gem_context_free(struct kref *ctx_ref) if (i915.enable_execlists) intel_lr_context_free(ctx); + kfree(ctx->jump_whitelist); + /* * This context is going away and we need to remove all VMAs still * around. This is to handle imported shared objects for which @@ -246,6 +248,9 @@ __create_hw_context(struct drm_device *dev, ctx->hang_stats.ban_period_seconds = DRM_I915_CTX_BAN_PERIOD; + ctx->jump_whitelist = NULL; + ctx->jump_whitelist_cmds = 0; + return ctx; err_out: diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 8800f410b2d2..56f6f5c5941e 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1121,17 +1121,52 @@ i915_reset_gen7_sol_offsets(struct drm_device *dev, return 0; } +static struct i915_vma* +shadow_batch_pin(struct drm_i915_gem_object *obj, struct i915_address_space *vm) +{ + struct drm_i915_private *dev_priv = to_i915(obj->base.dev); + struct i915_address_space *pin_vm = vm; + u64 flags; + int ret; + + /* + * PPGTT backed shadow buffers must be mapped RO, to prevent + * post-scan tampering + */ + if (CMDPARSER_USES_GGTT(dev_priv)) { + flags = PIN_GLOBAL; + pin_vm = &dev_priv->gtt.base; + } else if (vm->has_read_only) { + flags = PIN_USER; + obj->gt_ro = 1; + } else { + DRM_DEBUG("Cannot prevent post-scan tampering without RO capable vm\n"); + return ERR_PTR(-EINVAL); + } + + ret = i915_gem_object_pin(obj, pin_vm, 0, flags); + if (ret) + return ERR_PTR(ret); + else + return i915_gem_obj_to_vma(obj, pin_vm); +} + static struct drm_i915_gem_object* -i915_gem_execbuffer_parse(struct intel_engine_cs *ring, +i915_gem_execbuffer_parse(struct intel_context *ctx, + struct intel_engine_cs *ring, struct drm_i915_gem_exec_object2 *shadow_exec_entry, struct eb_vmas *eb, + struct i915_address_space *vm, struct drm_i915_gem_object *batch_obj, u32 batch_start_offset, - u32 batch_len, - bool is_master) + u32 batch_len) { struct drm_i915_gem_object *shadow_batch_obj; struct i915_vma *vma; + struct i915_vma *user_vma = list_entry(eb->vmas.prev, + typeof(*user_vma), exec_list); + u64 batch_start; + u64 shadow_batch_start; int ret; shadow_batch_obj = i915_gem_batch_pool_get(&ring->batch_pool, @@ -1139,24 +1174,34 @@ i915_gem_execbuffer_parse(struct intel_engine_cs *ring, if (IS_ERR(shadow_batch_obj)) return shadow_batch_obj; - ret = i915_parse_cmds(ring, + vma = shadow_batch_pin(shadow_batch_obj, vm); + if (IS_ERR(vma)) { + ret = PTR_ERR(vma); + goto err; + } + + batch_start = user_vma->node.start + batch_start_offset; + + shadow_batch_start = vma->node.start; + + ret = i915_parse_cmds(ctx, + ring, batch_obj, - shadow_batch_obj, + batch_start, batch_start_offset, batch_len, - is_master); - if (ret) - goto err; - - ret = i915_gem_obj_ggtt_pin(shadow_batch_obj, 0, 0); - if (ret) + shadow_batch_obj, + shadow_batch_start); + if (ret) { + WARN_ON(vma->pin_count == 0); + vma->pin_count--; goto err; + } i915_gem_object_unpin_pages(shadow_batch_obj); memset(shadow_exec_entry, 0, sizeof(*shadow_exec_entry)); - vma = i915_gem_obj_to_ggtt(shadow_batch_obj); vma->exec_entry = shadow_exec_entry; vma->exec_entry->flags = __EXEC_OBJECT_HAS_PIN; drm_gem_object_reference(&shadow_batch_obj->base); @@ -1168,7 +1213,14 @@ i915_gem_execbuffer_parse(struct intel_engine_cs *ring, err: i915_gem_object_unpin_pages(shadow_batch_obj); - if (ret == -EACCES) /* unhandled chained batch */ + + /* + * Unsafe GGTT-backed buffers can still be submitted safely + * as non-secure. + * For PPGTT backing however, we have no choice but to forcibly + * reject unsafe buffers + */ + if (CMDPARSER_USES_GGTT(batch_obj->base.dev) && (ret == -EACCES)) return batch_obj; else return ERR_PTR(ret); @@ -1320,6 +1372,13 @@ eb_get_batch(struct eb_vmas *eb) return vma->obj; } +static inline bool use_cmdparser(const struct intel_engine_cs *ring, + u32 batch_len) +{ + return ring->requires_cmd_parser || + (ring->using_cmd_parser && batch_len && USES_PPGTT(ring->dev)); +} + static int i915_gem_do_execbuffer(struct drm_device *dev, void *data, struct drm_file *file, @@ -1349,6 +1408,10 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, dispatch_flags = 0; if (args->flags & I915_EXEC_SECURE) { + /* Return -EPERM to trigger fallback code on old binaries. */ + if (!HAS_SECURE_BATCHES(dev_priv)) + return -EPERM; + if (!file->is_master || !capable(CAP_SYS_ADMIN)) return -EPERM; @@ -1487,16 +1550,20 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, } params->args_batch_start_offset = args->batch_start_offset; - if (i915_needs_cmd_parser(ring) && args->batch_len) { + if (use_cmdparser(ring, args->batch_len)) { struct drm_i915_gem_object *parsed_batch_obj; - parsed_batch_obj = i915_gem_execbuffer_parse(ring, + u32 batch_off = args->batch_start_offset; + u32 batch_len = args->batch_len; + if (batch_len == 0) + batch_len = batch_obj->base.size - batch_off; + + parsed_batch_obj = i915_gem_execbuffer_parse(ctx, ring, &shadow_exec_entry, - eb, + eb, vm, batch_obj, - args->batch_start_offset, - args->batch_len, - file->is_master); + batch_off, + batch_len); if (IS_ERR(parsed_batch_obj)) { ret = PTR_ERR(parsed_batch_obj); goto err; @@ -1506,18 +1573,9 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, * parsed_batch_obj == batch_obj means batch not fully parsed: * Accept, but don't promote to secure. */ - if (parsed_batch_obj != batch_obj) { - /* - * Batch parsed and accepted: - * - * Set the DISPATCH_SECURE bit to remove the NON_SECURE - * bit from MI_BATCH_BUFFER_START commands issued in - * the dispatch_execbuffer implementations. We - * specifically don't want that set on batches the - * command parser has accepted. - */ - dispatch_flags |= I915_DISPATCH_SECURE; + if (CMDPARSER_USES_GGTT(dev_priv)) + dispatch_flags |= I915_DISPATCH_SECURE; params->args_batch_start_offset = 0; batch_obj = parsed_batch_obj; } diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index b37fe0df743e..65a53ee398b8 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -119,7 +119,8 @@ static int sanitize_enable_ppgtt(struct drm_device *dev, int enable_ppgtt) (enable_ppgtt == 0 || !has_aliasing_ppgtt)) return 0; - if (enable_ppgtt == 1) + /* Full PPGTT is required by the Gen9 cmdparser */ + if (enable_ppgtt == 1 && INTEL_INFO(dev)->gen != 9) return 1; if (enable_ppgtt == 2 && has_full_ppgtt) @@ -152,7 +153,8 @@ static int ppgtt_bind_vma(struct i915_vma *vma, { u32 pte_flags = 0; - /* Currently applicable only to VLV */ + /* Applicable to VLV, and gen8+ */ + pte_flags = 0; if (vma->obj->gt_ro) pte_flags |= PTE_READ_ONLY; @@ -172,11 +174,14 @@ static void ppgtt_unbind_vma(struct i915_vma *vma) static gen8_pte_t gen8_pte_encode(dma_addr_t addr, enum i915_cache_level level, - bool valid) + bool valid, u32 flags) { gen8_pte_t pte = valid ? _PAGE_PRESENT | _PAGE_RW : 0; pte |= addr; + if (unlikely(flags & PTE_READ_ONLY)) + pte &= ~_PAGE_RW; + switch (level) { case I915_CACHE_NONE: pte |= PPAT_UNCACHED_INDEX; @@ -460,7 +465,7 @@ static void gen8_initialize_pt(struct i915_address_space *vm, gen8_pte_t scratch_pte; scratch_pte = gen8_pte_encode(px_dma(vm->scratch_page), - I915_CACHE_LLC, true); + I915_CACHE_LLC, true, 0); fill_px(vm->dev, pt, scratch_pte); } @@ -757,8 +762,9 @@ static void gen8_ppgtt_clear_range(struct i915_address_space *vm, { struct i915_hw_ppgtt *ppgtt = container_of(vm, struct i915_hw_ppgtt, base); - gen8_pte_t scratch_pte = gen8_pte_encode(px_dma(vm->scratch_page), - I915_CACHE_LLC, use_scratch); + gen8_pte_t scratch_pte = + gen8_pte_encode(px_dma(vm->scratch_page), + I915_CACHE_LLC, use_scratch, 0); if (!USES_FULL_48BIT_PPGTT(vm->dev)) { gen8_ppgtt_clear_pte_range(vm, &ppgtt->pdp, start, length, @@ -779,7 +785,8 @@ gen8_ppgtt_insert_pte_entries(struct i915_address_space *vm, struct i915_page_directory_pointer *pdp, struct sg_page_iter *sg_iter, uint64_t start, - enum i915_cache_level cache_level) + enum i915_cache_level cache_level, + u32 flags) { struct i915_hw_ppgtt *ppgtt = container_of(vm, struct i915_hw_ppgtt, base); @@ -799,7 +806,7 @@ gen8_ppgtt_insert_pte_entries(struct i915_address_space *vm, pt_vaddr[pte] = gen8_pte_encode(sg_page_iter_dma_address(sg_iter), - cache_level, true); + cache_level, true, flags); if (++pte == GEN8_PTES) { kunmap_px(ppgtt, pt_vaddr); pt_vaddr = NULL; @@ -820,7 +827,7 @@ static void gen8_ppgtt_insert_entries(struct i915_address_space *vm, struct sg_table *pages, uint64_t start, enum i915_cache_level cache_level, - u32 unused) + u32 flags) { struct i915_hw_ppgtt *ppgtt = container_of(vm, struct i915_hw_ppgtt, base); @@ -830,7 +837,7 @@ static void gen8_ppgtt_insert_entries(struct i915_address_space *vm, if (!USES_FULL_48BIT_PPGTT(vm->dev)) { gen8_ppgtt_insert_pte_entries(vm, &ppgtt->pdp, &sg_iter, start, - cache_level); + cache_level, flags); } else { struct i915_page_directory_pointer *pdp; uint64_t templ4, pml4e; @@ -838,7 +845,7 @@ static void gen8_ppgtt_insert_entries(struct i915_address_space *vm, gen8_for_each_pml4e(pdp, &ppgtt->pml4, start, length, templ4, pml4e) { gen8_ppgtt_insert_pte_entries(vm, pdp, &sg_iter, - start, cache_level); + start, cache_level, flags); } } } @@ -1447,7 +1454,7 @@ static void gen8_dump_ppgtt(struct i915_hw_ppgtt *ppgtt, struct seq_file *m) uint64_t start = ppgtt->base.start; uint64_t length = ppgtt->base.total; gen8_pte_t scratch_pte = gen8_pte_encode(px_dma(vm->scratch_page), - I915_CACHE_LLC, true); + I915_CACHE_LLC, true, 0); if (!USES_FULL_48BIT_PPGTT(vm->dev)) { gen8_dump_pdp(&ppgtt->pdp, start, length, scratch_pte, m); @@ -1515,6 +1522,14 @@ static int gen8_ppgtt_init(struct i915_hw_ppgtt *ppgtt) ppgtt->base.clear_range = gen8_ppgtt_clear_range; ppgtt->base.unbind_vma = ppgtt_unbind_vma; ppgtt->base.bind_vma = ppgtt_bind_vma; + + /* + * From bdw, there is support for read-only pages in the PPGTT. + * + * XXX GVT is not honouring the lack of RW in the PTE bits. + */ + ppgtt->base.has_read_only = !intel_vgpu_active(ppgtt->base.dev); + ppgtt->debug_dump = gen8_dump_ppgtt; if (USES_FULL_48BIT_PPGTT(ppgtt->base.dev)) { @@ -2343,7 +2358,7 @@ static void gen8_set_pte(void __iomem *addr, gen8_pte_t pte) static void gen8_ggtt_insert_entries(struct i915_address_space *vm, struct sg_table *st, uint64_t start, - enum i915_cache_level level, u32 unused) + enum i915_cache_level level, u32 flags) { struct drm_i915_private *dev_priv = vm->dev->dev_private; unsigned first_entry = start >> PAGE_SHIFT; @@ -2357,7 +2372,7 @@ static void gen8_ggtt_insert_entries(struct i915_address_space *vm, addr = sg_dma_address(sg_iter.sg) + (sg_iter.sg_pgoffset << PAGE_SHIFT); gen8_set_pte(>t_entries[i], - gen8_pte_encode(addr, level, true)); + gen8_pte_encode(addr, level, true, flags)); i++; } @@ -2370,7 +2385,7 @@ static void gen8_ggtt_insert_entries(struct i915_address_space *vm, */ if (i != 0) WARN_ON(readq(>t_entries[i-1]) - != gen8_pte_encode(addr, level, true)); + != gen8_pte_encode(addr, level, true, flags)); /* This next bit makes the above posting read even more important. We * want to flush the TLBs only after we're certain all the PTE updates @@ -2444,7 +2459,7 @@ static void gen8_ggtt_clear_range(struct i915_address_space *vm, scratch_pte = gen8_pte_encode(px_dma(vm->scratch_page), I915_CACHE_LLC, - use_scratch); + use_scratch, 0); for (i = 0; i < num_entries; i++) gen8_set_pte(>t_base[i], scratch_pte); readl(gtt_base); @@ -2510,7 +2525,8 @@ static int ggtt_bind_vma(struct i915_vma *vma, if (ret) return ret; - /* Currently applicable only to VLV */ + /* Applicable to VLV (gen8+ do not support RO in the GGTT) */ + pte_flags = 0; if (obj->gt_ro) pte_flags |= PTE_READ_ONLY; @@ -2653,6 +2669,9 @@ static int i915_gem_setup_global_gtt(struct drm_device *dev, i915_address_space_init(ggtt_vm, dev_priv); ggtt_vm->total += PAGE_SIZE; + /* Only VLV supports read-only GGTT mappings */ + ggtt_vm->has_read_only = IS_VALLEYVIEW(dev_priv); + if (intel_vgpu_active(dev)) { ret = intel_vgt_balloon(dev); if (ret) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h index a216397ead52..d36f2d77576a 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.h +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h @@ -307,6 +307,9 @@ struct i915_address_space { */ struct list_head inactive_list; + /* Some systems support read-only mappings for GGTT and/or PPGTT */ + bool has_read_only:1; + /* FIXME: Need a more generic return type */ gen6_pte_t (*pte_encode)(dma_addr_t addr, enum i915_cache_level level, diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index cace154bbdc0..603d8cdfc5f1 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -170,6 +170,8 @@ #define ECOCHK_PPGTT_WT_HSW (0x2<<3) #define ECOCHK_PPGTT_WB_HSW (0x3<<3) +#define GEN8_RC6_CTX_INFO 0x8504 + #define GAC_ECO_BITS 0x14090 #define ECOBITS_SNB_BIT (1<<13) #define ECOBITS_PPGTT_CACHE64B (3<<8) @@ -511,6 +513,10 @@ */ #define BCS_SWCTRL 0x22200 +/* There are 16 GPR registers */ +#define BCS_GPR(n) (0x22600 + (n) * 8) +#define BCS_GPR_UDW(n) (0x22600 + (n) * 8 + 4) + #define GPGPU_THREADS_DISPATCHED 0x2290 #define HS_INVOCATION_COUNT 0x2300 #define DS_INVOCATION_COUNT 0x2308 @@ -1567,6 +1573,7 @@ enum skl_disp_power_wells { #define RING_IMR(base) ((base)+0xa8) #define RING_HWSTAM(base) ((base)+0x98) #define RING_TIMESTAMP(base) ((base)+0x358) +#define RING_TIMESTAMP_UDW(base) ((base) + 0x358 + 4) #define TAIL_ADDR 0x001FFFF8 #define HEAD_WRAP_COUNT 0xFFE00000 #define HEAD_WRAP_ONE 0x00200000 @@ -5704,6 +5711,10 @@ enum skl_disp_power_wells { #define GAMMA_MODE_MODE_12BIT (2 << 0) #define GAMMA_MODE_MODE_SPLIT (3 << 0) +/* Display Internal Timeout Register */ +#define RM_TIMEOUT 0x42060 +#define MMIO_TIMEOUT_US(us) ((us) << 0) + /* interrupts */ #define DE_MASTER_IRQ_CONTROL (1 << 31) #define DE_SPRITEB_FLIP_DONE (1 << 29) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 4f5d07bb3511..a9166ff48a26 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -10747,6 +10747,10 @@ void intel_mark_busy(struct drm_device *dev) return; intel_runtime_pm_get(dev_priv); + + if (NEEDS_RC6_CTX_CORRUPTION_WA(dev_priv)) + intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL); + i915_update_gfx_val(dev_priv); if (INTEL_INFO(dev)->gen >= 6) gen6_rps_busy(dev_priv); @@ -10765,6 +10769,11 @@ void intel_mark_idle(struct drm_device *dev) if (INTEL_INFO(dev)->gen >= 6) gen6_rps_idle(dev->dev_private); + if (NEEDS_RC6_CTX_CORRUPTION_WA(dev_priv)) { + i915_rc6_ctx_wa_check(dev_priv); + intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL); + } + intel_runtime_pm_put(dev_priv); } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 722aa159cd28..78503e481313 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1410,6 +1410,9 @@ void intel_enable_gt_powersave(struct drm_device *dev); void intel_disable_gt_powersave(struct drm_device *dev); void intel_suspend_gt_powersave(struct drm_device *dev); void intel_reset_gt_powersave(struct drm_device *dev); +bool i915_rc6_ctx_wa_check(struct drm_i915_private *i915); +void i915_rc6_ctx_wa_suspend(struct drm_i915_private *i915); +void i915_rc6_ctx_wa_resume(struct drm_i915_private *i915); void gen6_update_ring_freq(struct drm_device *dev); void gen6_rps_busy(struct drm_i915_private *dev_priv); void gen6_rps_reset_ei(struct drm_i915_private *dev_priv); diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index fd4690ed93c0..81bd84f9156b 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -66,6 +66,14 @@ static void bxt_init_clock_gating(struct drm_device *dev) */ I915_WRITE(GEN8_UCGCTL6, I915_READ(GEN8_UCGCTL6) | GEN8_HDCUNIT_CLOCK_GATE_DISABLE_HDCREQ); + + /* + * Lower the display internal timeout. + * This is needed to avoid any hard hangs when DSI port PLL + * is off and a MMIO access is attempted by any privilege + * application, using batch buffers or any other means. + */ + I915_WRITE(RM_TIMEOUT, MMIO_TIMEOUT_US(950)); } static void i915_pineview_get_mem_freq(struct drm_device *dev) @@ -4591,30 +4599,42 @@ void intel_set_rps(struct drm_device *dev, u8 val) gen6_set_rps(dev, val); } -static void gen9_disable_rps(struct drm_device *dev) +static void gen9_disable_rc6(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; I915_WRITE(GEN6_RC_CONTROL, 0); +} + +static void gen9_disable_rps(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + I915_WRITE(GEN9_PG_ENABLE, 0); } -static void gen6_disable_rps(struct drm_device *dev) +static void gen6_disable_rc6(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; I915_WRITE(GEN6_RC_CONTROL, 0); +} + +static void gen6_disable_rps(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + I915_WRITE(GEN6_RPNSWREQ, 1 << 31); } -static void cherryview_disable_rps(struct drm_device *dev) +static void cherryview_disable_rc6(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; I915_WRITE(GEN6_RC_CONTROL, 0); } -static void valleyview_disable_rps(struct drm_device *dev) +static void valleyview_disable_rc6(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -4818,7 +4838,8 @@ static void gen9_enable_rc6(struct drm_device *dev) I915_WRITE(GEN9_RENDER_PG_IDLE_HYSTERESIS, 25); /* 3a: Enable RC6 */ - if (intel_enable_rc6(dev) & INTEL_RC6_ENABLE) + if (!dev_priv->rps.ctx_corrupted && + intel_enable_rc6(dev) & INTEL_RC6_ENABLE) rc6_mask = GEN6_RC_CTL_RC6_ENABLE; DRM_INFO("RC6 %s\n", (rc6_mask & GEN6_RC_CTL_RC6_ENABLE) ? "on" : "off"); @@ -4841,7 +4862,7 @@ static void gen9_enable_rc6(struct drm_device *dev) * WaRsDisableCoarsePowerGating:skl,bxt - Render/Media PG need to be disabled with RC6. */ if ((IS_BROXTON(dev) && (INTEL_REVID(dev) < BXT_REVID_B0)) || - ((IS_SKL_GT3(dev) || IS_SKL_GT4(dev)) && (INTEL_REVID(dev) <= SKL_REVID_F0))) + INTEL_INFO(dev)->gen == 9) I915_WRITE(GEN9_PG_ENABLE, 0); else I915_WRITE(GEN9_PG_ENABLE, (rc6_mask & GEN6_RC_CTL_RC6_ENABLE) ? @@ -4884,7 +4905,8 @@ static void gen8_enable_rps(struct drm_device *dev) I915_WRITE(GEN6_RC6_THRESHOLD, 50000); /* 50/125ms per EI */ /* 3: Enable RC6 */ - if (intel_enable_rc6(dev) & INTEL_RC6_ENABLE) + if (!dev_priv->rps.ctx_corrupted && + intel_enable_rc6(dev) & INTEL_RC6_ENABLE) rc6_mask = GEN6_RC_CTL_RC6_ENABLE; intel_print_rc6_info(dev, rc6_mask); if (IS_BROADWELL(dev)) @@ -6128,10 +6150,101 @@ static void intel_init_emon(struct drm_device *dev) dev_priv->ips.corr = (lcfuse & LCFUSE_HIV_MASK); } +static bool i915_rc6_ctx_corrupted(struct drm_i915_private *dev_priv) +{ + return !I915_READ(GEN8_RC6_CTX_INFO); +} + +static void i915_rc6_ctx_wa_init(struct drm_i915_private *i915) +{ + if (!NEEDS_RC6_CTX_CORRUPTION_WA(i915)) + return; + + if (i915_rc6_ctx_corrupted(i915)) { + DRM_INFO("RC6 context corrupted, disabling runtime power management\n"); + i915->rps.ctx_corrupted = true; + intel_runtime_pm_get(i915); + } +} + +static void i915_rc6_ctx_wa_cleanup(struct drm_i915_private *i915) +{ + if (i915->rps.ctx_corrupted) { + intel_runtime_pm_put(i915); + i915->rps.ctx_corrupted = false; + } +} + +/** + * i915_rc6_ctx_wa_suspend - system suspend sequence for the RC6 CTX WA + * @i915: i915 device + * + * Perform any steps needed to clean up the RC6 CTX WA before system suspend. + */ +void i915_rc6_ctx_wa_suspend(struct drm_i915_private *i915) +{ + if (i915->rps.ctx_corrupted) + intel_runtime_pm_put(i915); +} + +/** + * i915_rc6_ctx_wa_resume - system resume sequence for the RC6 CTX WA + * @i915: i915 device + * + * Perform any steps needed to re-init the RC6 CTX WA after system resume. + */ +void i915_rc6_ctx_wa_resume(struct drm_i915_private *i915) +{ + if (!i915->rps.ctx_corrupted) + return; + + if (i915_rc6_ctx_corrupted(i915)) { + intel_runtime_pm_get(i915); + return; + } + + DRM_INFO("RC6 context restored, re-enabling runtime power management\n"); + i915->rps.ctx_corrupted = false; +} + +static void intel_disable_rc6(struct drm_device *dev); + +/** + * i915_rc6_ctx_wa_check - check for a new RC6 CTX corruption + * @i915: i915 device + * + * Check if an RC6 CTX corruption has happened since the last check and if so + * disable RC6 and runtime power management. + * + * Return false if no context corruption has happened since the last call of + * this function, true otherwise. +*/ +bool i915_rc6_ctx_wa_check(struct drm_i915_private *i915) +{ + if (!NEEDS_RC6_CTX_CORRUPTION_WA(i915)) + return false; + + if (i915->rps.ctx_corrupted) + return false; + + if (!i915_rc6_ctx_corrupted(i915)) + return false; + + DRM_NOTE("RC6 context corruption, disabling runtime power management\n"); + + intel_disable_rc6(i915->dev); + i915->rps.ctx_corrupted = true; + intel_runtime_pm_get_noresume(i915); + + return true; +} + void intel_init_gt_powersave(struct drm_device *dev) { i915.enable_rc6 = sanitize_rc6_option(dev, i915.enable_rc6); + i915_rc6_ctx_wa_init(to_i915(dev)); + if (IS_CHERRYVIEW(dev)) cherryview_init_gt_powersave(dev); else if (IS_VALLEYVIEW(dev)) @@ -6144,6 +6257,8 @@ void intel_cleanup_gt_powersave(struct drm_device *dev) return; else if (IS_VALLEYVIEW(dev)) valleyview_cleanup_gt_powersave(dev); + + i915_rc6_ctx_wa_cleanup(to_i915(dev)); } static void gen6_suspend_rps(struct drm_device *dev) @@ -6176,6 +6291,38 @@ void intel_suspend_gt_powersave(struct drm_device *dev) gen6_rps_idle(dev_priv); } +static void __intel_disable_rc6(struct drm_device *dev) +{ + if (INTEL_INFO(dev)->gen >= 9) + gen9_disable_rc6(dev); + else if (IS_CHERRYVIEW(dev)) + cherryview_disable_rc6(dev); + else if (IS_VALLEYVIEW(dev)) + valleyview_disable_rc6(dev); + else + gen6_disable_rc6(dev); +} + +static void intel_disable_rc6(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = to_i915(dev); + + mutex_lock(&dev_priv->rps.hw_lock); + __intel_disable_rc6(dev); + mutex_unlock(&dev_priv->rps.hw_lock); +} + +static void intel_disable_rps(struct drm_device *dev) +{ + if (IS_CHERRYVIEW(dev) || IS_VALLEYVIEW(dev)) + return; + + if (INTEL_INFO(dev)->gen >= 9) + gen9_disable_rps(dev); + else + gen6_disable_rps(dev); +} + void intel_disable_gt_powersave(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -6186,16 +6333,12 @@ void intel_disable_gt_powersave(struct drm_device *dev) intel_suspend_gt_powersave(dev); mutex_lock(&dev_priv->rps.hw_lock); - if (INTEL_INFO(dev)->gen >= 9) - gen9_disable_rps(dev); - else if (IS_CHERRYVIEW(dev)) - cherryview_disable_rps(dev); - else if (IS_VALLEYVIEW(dev)) - valleyview_disable_rps(dev); - else - gen6_disable_rps(dev); + + __intel_disable_rc6(dev); + intel_disable_rps(dev); dev_priv->rps.enabled = false; + mutex_unlock(&dev_priv->rps.hw_lock); } } diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 9d48443bca2e..df6547f60a5c 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -2058,6 +2058,8 @@ static void intel_destroy_ringbuffer_obj(struct intel_ringbuffer *ringbuf) static int intel_alloc_ringbuffer_obj(struct drm_device *dev, struct intel_ringbuffer *ringbuf) { + struct drm_i915_private *dev_priv = to_i915(dev); + struct i915_address_space *vm = &dev_priv->gtt.base; struct drm_i915_gem_object *obj; obj = NULL; @@ -2068,8 +2070,12 @@ static int intel_alloc_ringbuffer_obj(struct drm_device *dev, if (obj == NULL) return -ENOMEM; - /* mark ring buffers as read-only from GPU side by default */ - obj->gt_ro = 1; + /* + * Mark ring buffers as read-only from GPU side (so no stray overwrites) + * if supported by the platform's GGTT. + */ + if (vm->has_read_only) + obj->gt_ro = 1; ringbuf->obj = obj; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 49fa41dc0eb6..56c872b89a92 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -314,7 +314,8 @@ struct intel_engine_cs { volatile u32 *cpu_page; } scratch; - bool needs_cmd_parser; + bool using_cmd_parser; + bool requires_cmd_parser; /* * Table of commands the command parser needs to know about diff --git a/drivers/gpu/drm/radeon/si_dpm.c b/drivers/gpu/drm/radeon/si_dpm.c index 892d0a71d766..57724a3afe78 100644 --- a/drivers/gpu/drm/radeon/si_dpm.c +++ b/drivers/gpu/drm/radeon/si_dpm.c @@ -1956,6 +1956,7 @@ static void si_initialize_powertune_defaults(struct radeon_device *rdev) case 0x682C: si_pi->cac_weights = cac_weights_cape_verde_pro; si_pi->dte_data = dte_data_sun_xt; + update_dte_from_pl2 = true; break; case 0x6825: case 0x6827: diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 2729ab3557bb..1107d218b0c5 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -726,6 +726,14 @@ config HID_SPEEDLINK ---help--- Support for Speedlink Vicious and Divine Cezanne mouse. +config HID_STEAM + tristate "Steam Controller support" + depends on HID + ---help--- + Say Y here if you have a Steam Controller if you want to use it + without running the Steam Client. It supports both the wired and + the wireless adaptor. + config HID_STEELSERIES tristate "Steelseries SRW-S1 steering wheel support" depends on HID diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 00011fee08b9..c21ff739fb31 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -85,6 +85,7 @@ obj-$(CONFIG_HID_SAMSUNG) += hid-samsung.o obj-$(CONFIG_HID_SMARTJOYPLUS) += hid-sjoy.o obj-$(CONFIG_HID_SONY) += hid-sony.o obj-$(CONFIG_HID_SPEEDLINK) += hid-speedlink.o +obj-$(CONFIG_HID_STEAM) += hid-steam.o obj-$(CONFIG_HID_STEELSERIES) += hid-steelseries.o obj-$(CONFIG_HID_SUNPLUS) += hid-sunplus.o obj-$(CONFIG_HID_GREENASIA) += hid-gaff.o diff --git a/drivers/hid/hid-axff.c b/drivers/hid/hid-axff.c index a594e478a1e2..843aed4dec80 100644 --- a/drivers/hid/hid-axff.c +++ b/drivers/hid/hid-axff.c @@ -75,13 +75,20 @@ static int axff_init(struct hid_device *hid) { struct axff_device *axff; struct hid_report *report; - struct hid_input *hidinput = list_first_entry(&hid->inputs, struct hid_input, list); + struct hid_input *hidinput; struct list_head *report_list =&hid->report_enum[HID_OUTPUT_REPORT].report_list; - struct input_dev *dev = hidinput->input; + struct input_dev *dev; int field_count = 0; int i, j; int error; + if (list_empty(&hid->inputs)) { + hid_err(hid, "no inputs found\n"); + return -ENODEV; + } + hidinput = list_first_entry(&hid->inputs, struct hid_input, list); + dev = hidinput->input; + if (list_empty(report_list)) { hid_err(hid, "no output reports found\n"); return -ENODEV; diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index a22881befa27..f6476d1cfdb2 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -976,6 +976,7 @@ int hid_open_report(struct hid_device *device) __u8 *start; __u8 *buf; __u8 *end; + __u8 *next; int ret; static int (*dispatch_type[])(struct hid_parser *parser, struct hid_item *item) = { @@ -1029,7 +1030,8 @@ int hid_open_report(struct hid_device *device) device->collection_size = HID_DEFAULT_NUM_COLLECTIONS; ret = -EINVAL; - while ((start = fetch_item(start, end, &item)) != NULL) { + while ((next = fetch_item(start, end, &item)) != NULL) { + start = next; if (item.format != HID_ITEM_FORMAT_SHORT) { hid_err(device, "unexpected long global item\n"); @@ -1058,7 +1060,8 @@ int hid_open_report(struct hid_device *device) } } - hid_err(device, "item fetching failed at offset %d\n", (int)(end - start)); + hid_err(device, "item fetching failed at offset %u/%u\n", + size - (unsigned int)(end - start), size); err: vfree(parser); hid_close_report(device); @@ -2070,6 +2073,9 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP1062) }, { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850) }, { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60) }, + { HID_USB_DEVICE(USB_VENDOR_ID_VALVE, USB_DEVICE_ID_STEAM_CONTROLLER) }, + { HID_USB_DEVICE(USB_VENDOR_ID_VALVE, USB_DEVICE_ID_STEAM_CONTROLLER_WIRELESS) }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_VALVE, USB_DEVICE_ID_STEAM_CONTROLLER_BT) }, { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SMARTJOY_PLUS) }, { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SUPER_JOY_BOX_3) }, { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD) }, diff --git a/drivers/hid/hid-dr.c b/drivers/hid/hid-dr.c index 1d78ba3b799e..fac829d2b19a 100644 --- a/drivers/hid/hid-dr.c +++ b/drivers/hid/hid-dr.c @@ -87,13 +87,19 @@ static int drff_init(struct hid_device *hid) { struct drff_device *drff; struct hid_report *report; - struct hid_input *hidinput = list_first_entry(&hid->inputs, - struct hid_input, list); + struct hid_input *hidinput; struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; - struct input_dev *dev = hidinput->input; + struct input_dev *dev; int error; + if (list_empty(&hid->inputs)) { + hid_err(hid, "no inputs found\n"); + return -ENODEV; + } + hidinput = list_first_entry(&hid->inputs, struct hid_input, list); + dev = hidinput->input; + if (list_empty(report_list)) { hid_err(hid, "no output reports found\n"); return -ENODEV; diff --git a/drivers/hid/hid-emsff.c b/drivers/hid/hid-emsff.c index d82d75bb11f7..80f9a02dfa69 100644 --- a/drivers/hid/hid-emsff.c +++ b/drivers/hid/hid-emsff.c @@ -59,13 +59,19 @@ static int emsff_init(struct hid_device *hid) { struct emsff_device *emsff; struct hid_report *report; - struct hid_input *hidinput = list_first_entry(&hid->inputs, - struct hid_input, list); + struct hid_input *hidinput; struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; - struct input_dev *dev = hidinput->input; + struct input_dev *dev; int error; + if (list_empty(&hid->inputs)) { + hid_err(hid, "no inputs found\n"); + return -ENODEV; + } + hidinput = list_first_entry(&hid->inputs, struct hid_input, list); + dev = hidinput->input; + if (list_empty(report_list)) { hid_err(hid, "no output reports found\n"); return -ENODEV; diff --git a/drivers/hid/hid-gaff.c b/drivers/hid/hid-gaff.c index 2d8cead3adca..5a02c50443cb 100644 --- a/drivers/hid/hid-gaff.c +++ b/drivers/hid/hid-gaff.c @@ -77,14 +77,20 @@ static int gaff_init(struct hid_device *hid) { struct gaff_device *gaff; struct hid_report *report; - struct hid_input *hidinput = list_entry(hid->inputs.next, - struct hid_input, list); + struct hid_input *hidinput; struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; struct list_head *report_ptr = report_list; - struct input_dev *dev = hidinput->input; + struct input_dev *dev; int error; + if (list_empty(&hid->inputs)) { + hid_err(hid, "no inputs found\n"); + return -ENODEV; + } + hidinput = list_entry(hid->inputs.next, struct hid_input, list); + dev = hidinput->input; + if (list_empty(report_list)) { hid_err(hid, "no output reports found\n"); return -ENODEV; diff --git a/drivers/hid/hid-holtekff.c b/drivers/hid/hid-holtekff.c index 9325545fc3ae..3e84551cca9c 100644 --- a/drivers/hid/hid-holtekff.c +++ b/drivers/hid/hid-holtekff.c @@ -140,13 +140,19 @@ static int holtekff_init(struct hid_device *hid) { struct holtekff_device *holtekff; struct hid_report *report; - struct hid_input *hidinput = list_entry(hid->inputs.next, - struct hid_input, list); + struct hid_input *hidinput; struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; - struct input_dev *dev = hidinput->input; + struct input_dev *dev; int error; + if (list_empty(&hid->inputs)) { + hid_err(hid, "no inputs found\n"); + return -ENODEV; + } + hidinput = list_entry(hid->inputs.next, struct hid_input, list); + dev = hidinput->input; + if (list_empty(report_list)) { hid_err(hid, "no output report found\n"); return -ENODEV; diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index e1807296a1a0..b4bc316310bc 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -900,6 +900,11 @@ #define USB_VENDOR_ID_STANTUM_SITRONIX 0x1403 #define USB_DEVICE_ID_MTP_SITRONIX 0x5001 +#define USB_VENDOR_ID_VALVE 0x28de +#define USB_DEVICE_ID_STEAM_CONTROLLER 0x1102 +#define USB_DEVICE_ID_STEAM_CONTROLLER_WIRELESS 0x1142 +#define USB_DEVICE_ID_STEAM_CONTROLLER_BT 0x1106 + #define USB_VENDOR_ID_STEELSERIES 0x1038 #define USB_DEVICE_ID_STEELSERIES_SRWS1 0x1410 diff --git a/drivers/hid/hid-lg2ff.c b/drivers/hid/hid-lg2ff.c index 0e3fb1a7e421..6909d9c2fc67 100644 --- a/drivers/hid/hid-lg2ff.c +++ b/drivers/hid/hid-lg2ff.c @@ -62,11 +62,17 @@ int lg2ff_init(struct hid_device *hid) { struct lg2ff_device *lg2ff; struct hid_report *report; - struct hid_input *hidinput = list_entry(hid->inputs.next, - struct hid_input, list); - struct input_dev *dev = hidinput->input; + struct hid_input *hidinput; + struct input_dev *dev; int error; + if (list_empty(&hid->inputs)) { + hid_err(hid, "no inputs found\n"); + return -ENODEV; + } + hidinput = list_entry(hid->inputs.next, struct hid_input, list); + dev = hidinput->input; + /* Check that the report looks ok */ report = hid_validate_values(hid, HID_OUTPUT_REPORT, 0, 0, 7); if (!report) diff --git a/drivers/hid/hid-lg3ff.c b/drivers/hid/hid-lg3ff.c index 8c2da183d3bc..acf739fc4060 100644 --- a/drivers/hid/hid-lg3ff.c +++ b/drivers/hid/hid-lg3ff.c @@ -129,12 +129,19 @@ static const signed short ff3_joystick_ac[] = { int lg3ff_init(struct hid_device *hid) { - struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); - struct input_dev *dev = hidinput->input; + struct hid_input *hidinput; + struct input_dev *dev; const signed short *ff_bits = ff3_joystick_ac; int error; int i; + if (list_empty(&hid->inputs)) { + hid_err(hid, "no inputs found\n"); + return -ENODEV; + } + hidinput = list_entry(hid->inputs.next, struct hid_input, list); + dev = hidinput->input; + /* Check that the report looks ok */ if (!hid_validate_values(hid, HID_OUTPUT_REPORT, 0, 0, 35)) return -ENODEV; diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c index dae1b9cdd2e5..d8432d9f10f0 100644 --- a/drivers/hid/hid-lg4ff.c +++ b/drivers/hid/hid-lg4ff.c @@ -1158,8 +1158,8 @@ static int lg4ff_handle_multimode_wheel(struct hid_device *hid, u16 *real_produc int lg4ff_init(struct hid_device *hid) { - struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); - struct input_dev *dev = hidinput->input; + struct hid_input *hidinput; + struct input_dev *dev; struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; struct hid_report *report = list_entry(report_list->next, struct hid_report, list); const struct usb_device_descriptor *udesc = &(hid_to_usb_dev(hid)->descriptor); @@ -1171,6 +1171,13 @@ int lg4ff_init(struct hid_device *hid) int mmode_ret, mmode_idx = -1; u16 real_product_id; + if (list_empty(&hid->inputs)) { + hid_err(hid, "no inputs found\n"); + return -ENODEV; + } + hidinput = list_entry(hid->inputs.next, struct hid_input, list); + dev = hidinput->input; + /* Check that the report looks ok */ if (!hid_validate_values(hid, HID_OUTPUT_REPORT, 0, 0, 7)) return -1; diff --git a/drivers/hid/hid-lgff.c b/drivers/hid/hid-lgff.c index e1394af0ae7b..1871cdcd1e0a 100644 --- a/drivers/hid/hid-lgff.c +++ b/drivers/hid/hid-lgff.c @@ -127,12 +127,19 @@ static void hid_lgff_set_autocenter(struct input_dev *dev, u16 magnitude) int lgff_init(struct hid_device* hid) { - struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); - struct input_dev *dev = hidinput->input; + struct hid_input *hidinput; + struct input_dev *dev; const signed short *ff_bits = ff_joystick; int error; int i; + if (list_empty(&hid->inputs)) { + hid_err(hid, "no inputs found\n"); + return -ENODEV; + } + hidinput = list_entry(hid->inputs.next, struct hid_input, list); + dev = hidinput->input; + /* Check that the report looks ok */ if (!hid_validate_values(hid, HID_OUTPUT_REPORT, 0, 0, 7)) return -ENODEV; diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index 6f3d47185bf0..353629aab49a 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -8,7 +8,7 @@ * Copyright (c) 2012 David Dillow <dave@thedillows.org> * Copyright (c) 2006-2013 Jiri Kosina * Copyright (c) 2013 Colin Leitner <colin.leitner@gmail.com> - * Copyright (c) 2014 Frank Praznik <frank.praznik@gmail.com> + * Copyright (c) 2014-2016 Frank Praznik <frank.praznik@gmail.com> */ /* @@ -36,6 +36,8 @@ #include <linux/list.h> #include <linux/idr.h> #include <linux/input/mt.h> +#include <linux/crc32.h> +#include <asm/unaligned.h> #include "hid-ids.h" @@ -46,17 +48,19 @@ #define PS3REMOTE BIT(4) #define DUALSHOCK4_CONTROLLER_USB BIT(5) #define DUALSHOCK4_CONTROLLER_BT BIT(6) -#define MOTION_CONTROLLER_USB BIT(7) -#define MOTION_CONTROLLER_BT BIT(8) -#define NAVIGATION_CONTROLLER_USB BIT(9) -#define NAVIGATION_CONTROLLER_BT BIT(10) +#define DUALSHOCK4_DONGLE BIT(7) +#define MOTION_CONTROLLER_USB BIT(8) +#define MOTION_CONTROLLER_BT BIT(9) +#define NAVIGATION_CONTROLLER_USB BIT(10) +#define NAVIGATION_CONTROLLER_BT BIT(11) #define SIXAXIS_CONTROLLER (SIXAXIS_CONTROLLER_USB | SIXAXIS_CONTROLLER_BT) #define MOTION_CONTROLLER (MOTION_CONTROLLER_USB | MOTION_CONTROLLER_BT) #define NAVIGATION_CONTROLLER (NAVIGATION_CONTROLLER_USB |\ NAVIGATION_CONTROLLER_BT) #define DUALSHOCK4_CONTROLLER (DUALSHOCK4_CONTROLLER_USB |\ - DUALSHOCK4_CONTROLLER_BT) + DUALSHOCK4_CONTROLLER_BT | \ + DUALSHOCK4_DONGLE) #define SONY_LED_SUPPORT (SIXAXIS_CONTROLLER | BUZZ_CONTROLLER |\ DUALSHOCK4_CONTROLLER | MOTION_CONTROLLER |\ NAVIGATION_CONTROLLER) @@ -64,95 +68,14 @@ MOTION_CONTROLLER_BT | NAVIGATION_CONTROLLER) #define SONY_FF_SUPPORT (SIXAXIS_CONTROLLER | DUALSHOCK4_CONTROLLER |\ MOTION_CONTROLLER) +#define SONY_BT_DEVICE (SIXAXIS_CONTROLLER_BT | DUALSHOCK4_CONTROLLER_BT |\ + MOTION_CONTROLLER_BT | NAVIGATION_CONTROLLER_BT) #define MAX_LEDS 4 -/* - * The Sixaxis reports both digital and analog values for each button on the - * controller except for Start, Select and the PS button. The controller ends - * up reporting 27 axes which causes them to spill over into the multi-touch - * axis values. Additionally, the controller only has 20 actual, physical axes - * so there are several unused axes in between the used ones. - */ -static __u8 sixaxis_rdesc[] = { - 0x05, 0x01, /* Usage Page (Desktop), */ - 0x09, 0x04, /* Usage (Joystick), */ - 0xA1, 0x01, /* Collection (Application), */ - 0xA1, 0x02, /* Collection (Logical), */ - 0x85, 0x01, /* Report ID (1), */ - 0x75, 0x08, /* Report Size (8), */ - 0x95, 0x01, /* Report Count (1), */ - 0x15, 0x00, /* Logical Minimum (0), */ - 0x26, 0xFF, 0x00, /* Logical Maximum (255), */ - 0x81, 0x03, /* Input (Constant, Variable), */ - 0x75, 0x01, /* Report Size (1), */ - 0x95, 0x13, /* Report Count (19), */ - 0x15, 0x00, /* Logical Minimum (0), */ - 0x25, 0x01, /* Logical Maximum (1), */ - 0x35, 0x00, /* Physical Minimum (0), */ - 0x45, 0x01, /* Physical Maximum (1), */ - 0x05, 0x09, /* Usage Page (Button), */ - 0x19, 0x01, /* Usage Minimum (01h), */ - 0x29, 0x13, /* Usage Maximum (13h), */ - 0x81, 0x02, /* Input (Variable), */ - 0x75, 0x01, /* Report Size (1), */ - 0x95, 0x0D, /* Report Count (13), */ - 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ - 0x81, 0x03, /* Input (Constant, Variable), */ - 0x15, 0x00, /* Logical Minimum (0), */ - 0x26, 0xFF, 0x00, /* Logical Maximum (255), */ - 0x05, 0x01, /* Usage Page (Desktop), */ - 0x09, 0x01, /* Usage (Pointer), */ - 0xA1, 0x00, /* Collection (Physical), */ - 0x75, 0x08, /* Report Size (8), */ - 0x95, 0x04, /* Report Count (4), */ - 0x35, 0x00, /* Physical Minimum (0), */ - 0x46, 0xFF, 0x00, /* Physical Maximum (255), */ - 0x09, 0x30, /* Usage (X), */ - 0x09, 0x31, /* Usage (Y), */ - 0x09, 0x32, /* Usage (Z), */ - 0x09, 0x35, /* Usage (Rz), */ - 0x81, 0x02, /* Input (Variable), */ - 0xC0, /* End Collection, */ - 0x05, 0x01, /* Usage Page (Desktop), */ - 0x95, 0x13, /* Report Count (19), */ - 0x09, 0x01, /* Usage (Pointer), */ - 0x81, 0x02, /* Input (Variable), */ - 0x95, 0x0C, /* Report Count (12), */ - 0x81, 0x01, /* Input (Constant), */ - 0x75, 0x10, /* Report Size (16), */ - 0x95, 0x04, /* Report Count (4), */ - 0x26, 0xFF, 0x03, /* Logical Maximum (1023), */ - 0x46, 0xFF, 0x03, /* Physical Maximum (1023), */ - 0x09, 0x01, /* Usage (Pointer), */ - 0x81, 0x02, /* Input (Variable), */ - 0xC0, /* End Collection, */ - 0xA1, 0x02, /* Collection (Logical), */ - 0x85, 0x02, /* Report ID (2), */ - 0x75, 0x08, /* Report Size (8), */ - 0x95, 0x30, /* Report Count (48), */ - 0x09, 0x01, /* Usage (Pointer), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0xC0, /* End Collection, */ - 0xA1, 0x02, /* Collection (Logical), */ - 0x85, 0xEE, /* Report ID (238), */ - 0x75, 0x08, /* Report Size (8), */ - 0x95, 0x30, /* Report Count (48), */ - 0x09, 0x01, /* Usage (Pointer), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0xC0, /* End Collection, */ - 0xA1, 0x02, /* Collection (Logical), */ - 0x85, 0xEF, /* Report ID (239), */ - 0x75, 0x08, /* Report Size (8), */ - 0x95, 0x30, /* Report Count (48), */ - 0x09, 0x01, /* Usage (Pointer), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0xC0, /* End Collection, */ - 0xC0 /* End Collection */ -}; /* PS/3 Motion controller */ -static __u8 motion_rdesc[] = { +static u8 motion_rdesc[] = { 0x05, 0x01, /* Usage Page (Desktop), */ 0x09, 0x04, /* Usage (Joystick), */ 0xA1, 0x01, /* Collection (Application), */ @@ -248,568 +171,7 @@ static __u8 motion_rdesc[] = { 0xC0 /* End Collection */ }; -/* PS/3 Navigation controller */ -static __u8 navigation_rdesc[] = { - 0x05, 0x01, /* Usage Page (Desktop), */ - 0x09, 0x04, /* Usage (Joystik), */ - 0xA1, 0x01, /* Collection (Application), */ - 0xA1, 0x02, /* Collection (Logical), */ - 0x85, 0x01, /* Report ID (1), */ - 0x75, 0x08, /* Report Size (8), */ - 0x95, 0x01, /* Report Count (1), */ - 0x15, 0x00, /* Logical Minimum (0), */ - 0x26, 0xFF, 0x00, /* Logical Maximum (255), */ - 0x81, 0x03, /* Input (Constant, Variable), */ - 0x75, 0x01, /* Report Size (1), */ - 0x95, 0x13, /* Report Count (19), */ - 0x15, 0x00, /* Logical Minimum (0), */ - 0x25, 0x01, /* Logical Maximum (1), */ - 0x35, 0x00, /* Physical Minimum (0), */ - 0x45, 0x01, /* Physical Maximum (1), */ - 0x05, 0x09, /* Usage Page (Button), */ - 0x19, 0x01, /* Usage Minimum (01h), */ - 0x29, 0x13, /* Usage Maximum (13h), */ - 0x81, 0x02, /* Input (Variable), */ - 0x75, 0x01, /* Report Size (1), */ - 0x95, 0x0D, /* Report Count (13), */ - 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ - 0x81, 0x03, /* Input (Constant, Variable), */ - 0x15, 0x00, /* Logical Minimum (0), */ - 0x26, 0xFF, 0x00, /* Logical Maximum (255), */ - 0x05, 0x01, /* Usage Page (Desktop), */ - 0x09, 0x01, /* Usage (Pointer), */ - 0xA1, 0x00, /* Collection (Physical), */ - 0x75, 0x08, /* Report Size (8), */ - 0x95, 0x02, /* Report Count (2), */ - 0x35, 0x00, /* Physical Minimum (0), */ - 0x46, 0xFF, 0x00, /* Physical Maximum (255), */ - 0x09, 0x30, /* Usage (X), */ - 0x09, 0x31, /* Usage (Y), */ - 0x81, 0x02, /* Input (Variable), */ - 0xC0, /* End Collection, */ - 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ - 0x95, 0x06, /* Report Count (6), */ - 0x81, 0x03, /* Input (Constant, Variable), */ - 0x05, 0x01, /* Usage Page (Desktop), */ - 0x75, 0x08, /* Report Size (8), */ - 0x95, 0x05, /* Report Count (5), */ - 0x09, 0x01, /* Usage (Pointer), */ - 0x81, 0x02, /* Input (Variable), */ - 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ - 0x95, 0x01, /* Report Count (1), */ - 0x81, 0x02, /* Input (Variable), */ - 0x05, 0x01, /* Usage Page (Desktop), */ - 0x95, 0x01, /* Report Count (1), */ - 0x09, 0x01, /* Usage (Pointer), */ - 0x81, 0x02, /* Input (Variable), */ - 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ - 0x95, 0x1E, /* Report Count (24), */ - 0x81, 0x02, /* Input (Variable), */ - 0x75, 0x08, /* Report Size (8), */ - 0x95, 0x30, /* Report Count (48), */ - 0x09, 0x01, /* Usage (Pointer), */ - 0x91, 0x02, /* Output (Variable), */ - 0x75, 0x08, /* Report Size (8), */ - 0x95, 0x30, /* Report Count (48), */ - 0x09, 0x01, /* Usage (Pointer), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0xC0, /* End Collection, */ - 0xA1, 0x02, /* Collection (Logical), */ - 0x85, 0x02, /* Report ID (2), */ - 0x75, 0x08, /* Report Size (8), */ - 0x95, 0x30, /* Report Count (48), */ - 0x09, 0x01, /* Usage (Pointer), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0xC0, /* End Collection, */ - 0xA1, 0x02, /* Collection (Logical), */ - 0x85, 0xEE, /* Report ID (238), */ - 0x75, 0x08, /* Report Size (8), */ - 0x95, 0x30, /* Report Count (48), */ - 0x09, 0x01, /* Usage (Pointer), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0xC0, /* End Collection, */ - 0xA1, 0x02, /* Collection (Logical), */ - 0x85, 0xEF, /* Report ID (239), */ - 0x75, 0x08, /* Report Size (8), */ - 0x95, 0x30, /* Report Count (48), */ - 0x09, 0x01, /* Usage (Pointer), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0xC0, /* End Collection, */ - 0xC0 /* End Collection */ -}; - -/* - * The default descriptor doesn't provide mapping for the accelerometers - * or orientation sensors. This fixed descriptor maps the accelerometers - * to usage values 0x40, 0x41 and 0x42 and maps the orientation sensors - * to usage values 0x43, 0x44 and 0x45. - */ -static u8 dualshock4_usb_rdesc[] = { - 0x05, 0x01, /* Usage Page (Desktop), */ - 0x09, 0x05, /* Usage (Gamepad), */ - 0xA1, 0x01, /* Collection (Application), */ - 0x85, 0x01, /* Report ID (1), */ - 0x09, 0x30, /* Usage (X), */ - 0x09, 0x31, /* Usage (Y), */ - 0x09, 0x32, /* Usage (Z), */ - 0x09, 0x35, /* Usage (Rz), */ - 0x15, 0x00, /* Logical Minimum (0), */ - 0x26, 0xFF, 0x00, /* Logical Maximum (255), */ - 0x75, 0x08, /* Report Size (8), */ - 0x95, 0x04, /* Report Count (4), */ - 0x81, 0x02, /* Input (Variable), */ - 0x09, 0x39, /* Usage (Hat Switch), */ - 0x15, 0x00, /* Logical Minimum (0), */ - 0x25, 0x07, /* Logical Maximum (7), */ - 0x35, 0x00, /* Physical Minimum (0), */ - 0x46, 0x3B, 0x01, /* Physical Maximum (315), */ - 0x65, 0x14, /* Unit (Degrees), */ - 0x75, 0x04, /* Report Size (4), */ - 0x95, 0x01, /* Report Count (1), */ - 0x81, 0x42, /* Input (Variable, Null State), */ - 0x65, 0x00, /* Unit, */ - 0x05, 0x09, /* Usage Page (Button), */ - 0x19, 0x01, /* Usage Minimum (01h), */ - 0x29, 0x0E, /* Usage Maximum (0Eh), */ - 0x15, 0x00, /* Logical Minimum (0), */ - 0x25, 0x01, /* Logical Maximum (1), */ - 0x75, 0x01, /* Report Size (1), */ - 0x95, 0x0E, /* Report Count (14), */ - 0x81, 0x02, /* Input (Variable), */ - 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ - 0x09, 0x20, /* Usage (20h), */ - 0x75, 0x06, /* Report Size (6), */ - 0x95, 0x01, /* Report Count (1), */ - 0x15, 0x00, /* Logical Minimum (0), */ - 0x25, 0x3F, /* Logical Maximum (63), */ - 0x81, 0x02, /* Input (Variable), */ - 0x05, 0x01, /* Usage Page (Desktop), */ - 0x09, 0x33, /* Usage (Rx), */ - 0x09, 0x34, /* Usage (Ry), */ - 0x15, 0x00, /* Logical Minimum (0), */ - 0x26, 0xFF, 0x00, /* Logical Maximum (255), */ - 0x75, 0x08, /* Report Size (8), */ - 0x95, 0x02, /* Report Count (2), */ - 0x81, 0x02, /* Input (Variable), */ - 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ - 0x09, 0x21, /* Usage (21h), */ - 0x95, 0x03, /* Report Count (3), */ - 0x81, 0x02, /* Input (Variable), */ - 0x05, 0x01, /* Usage Page (Desktop), */ - 0x19, 0x40, /* Usage Minimum (40h), */ - 0x29, 0x42, /* Usage Maximum (42h), */ - 0x16, 0x00, 0x80, /* Logical Minimum (-32768), */ - 0x26, 0x00, 0x7F, /* Logical Maximum (32767), */ - 0x75, 0x10, /* Report Size (16), */ - 0x95, 0x03, /* Report Count (3), */ - 0x81, 0x02, /* Input (Variable), */ - 0x19, 0x43, /* Usage Minimum (43h), */ - 0x29, 0x45, /* Usage Maximum (45h), */ - 0x16, 0x00, 0xE0, /* Logical Minimum (-8192), */ - 0x26, 0xFF, 0x1F, /* Logical Maximum (8191), */ - 0x95, 0x03, /* Report Count (3), */ - 0x81, 0x02, /* Input (Variable), */ - 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ - 0x09, 0x21, /* Usage (21h), */ - 0x15, 0x00, /* Logical Minimum (0), */ - 0x26, 0xFF, 0x00, /* Logical Maximum (255), */ - 0x75, 0x08, /* Report Size (8), */ - 0x95, 0x27, /* Report Count (39), */ - 0x81, 0x02, /* Input (Variable), */ - 0x85, 0x05, /* Report ID (5), */ - 0x09, 0x22, /* Usage (22h), */ - 0x95, 0x1F, /* Report Count (31), */ - 0x91, 0x02, /* Output (Variable), */ - 0x85, 0x04, /* Report ID (4), */ - 0x09, 0x23, /* Usage (23h), */ - 0x95, 0x24, /* Report Count (36), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0x02, /* Report ID (2), */ - 0x09, 0x24, /* Usage (24h), */ - 0x95, 0x24, /* Report Count (36), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0x08, /* Report ID (8), */ - 0x09, 0x25, /* Usage (25h), */ - 0x95, 0x03, /* Report Count (3), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0x10, /* Report ID (16), */ - 0x09, 0x26, /* Usage (26h), */ - 0x95, 0x04, /* Report Count (4), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0x11, /* Report ID (17), */ - 0x09, 0x27, /* Usage (27h), */ - 0x95, 0x02, /* Report Count (2), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0x12, /* Report ID (18), */ - 0x06, 0x02, 0xFF, /* Usage Page (FF02h), */ - 0x09, 0x21, /* Usage (21h), */ - 0x95, 0x0F, /* Report Count (15), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0x13, /* Report ID (19), */ - 0x09, 0x22, /* Usage (22h), */ - 0x95, 0x16, /* Report Count (22), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0x14, /* Report ID (20), */ - 0x06, 0x05, 0xFF, /* Usage Page (FF05h), */ - 0x09, 0x20, /* Usage (20h), */ - 0x95, 0x10, /* Report Count (16), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0x15, /* Report ID (21), */ - 0x09, 0x21, /* Usage (21h), */ - 0x95, 0x2C, /* Report Count (44), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x06, 0x80, 0xFF, /* Usage Page (FF80h), */ - 0x85, 0x80, /* Report ID (128), */ - 0x09, 0x20, /* Usage (20h), */ - 0x95, 0x06, /* Report Count (6), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0x81, /* Report ID (129), */ - 0x09, 0x21, /* Usage (21h), */ - 0x95, 0x06, /* Report Count (6), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0x82, /* Report ID (130), */ - 0x09, 0x22, /* Usage (22h), */ - 0x95, 0x05, /* Report Count (5), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0x83, /* Report ID (131), */ - 0x09, 0x23, /* Usage (23h), */ - 0x95, 0x01, /* Report Count (1), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0x84, /* Report ID (132), */ - 0x09, 0x24, /* Usage (24h), */ - 0x95, 0x04, /* Report Count (4), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0x85, /* Report ID (133), */ - 0x09, 0x25, /* Usage (25h), */ - 0x95, 0x06, /* Report Count (6), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0x86, /* Report ID (134), */ - 0x09, 0x26, /* Usage (26h), */ - 0x95, 0x06, /* Report Count (6), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0x87, /* Report ID (135), */ - 0x09, 0x27, /* Usage (27h), */ - 0x95, 0x23, /* Report Count (35), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0x88, /* Report ID (136), */ - 0x09, 0x28, /* Usage (28h), */ - 0x95, 0x22, /* Report Count (34), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0x89, /* Report ID (137), */ - 0x09, 0x29, /* Usage (29h), */ - 0x95, 0x02, /* Report Count (2), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0x90, /* Report ID (144), */ - 0x09, 0x30, /* Usage (30h), */ - 0x95, 0x05, /* Report Count (5), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0x91, /* Report ID (145), */ - 0x09, 0x31, /* Usage (31h), */ - 0x95, 0x03, /* Report Count (3), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0x92, /* Report ID (146), */ - 0x09, 0x32, /* Usage (32h), */ - 0x95, 0x03, /* Report Count (3), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0x93, /* Report ID (147), */ - 0x09, 0x33, /* Usage (33h), */ - 0x95, 0x0C, /* Report Count (12), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0xA0, /* Report ID (160), */ - 0x09, 0x40, /* Usage (40h), */ - 0x95, 0x06, /* Report Count (6), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0xA1, /* Report ID (161), */ - 0x09, 0x41, /* Usage (41h), */ - 0x95, 0x01, /* Report Count (1), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0xA2, /* Report ID (162), */ - 0x09, 0x42, /* Usage (42h), */ - 0x95, 0x01, /* Report Count (1), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0xA3, /* Report ID (163), */ - 0x09, 0x43, /* Usage (43h), */ - 0x95, 0x30, /* Report Count (48), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0xA4, /* Report ID (164), */ - 0x09, 0x44, /* Usage (44h), */ - 0x95, 0x0D, /* Report Count (13), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0xA5, /* Report ID (165), */ - 0x09, 0x45, /* Usage (45h), */ - 0x95, 0x15, /* Report Count (21), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0xA6, /* Report ID (166), */ - 0x09, 0x46, /* Usage (46h), */ - 0x95, 0x15, /* Report Count (21), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0xF0, /* Report ID (240), */ - 0x09, 0x47, /* Usage (47h), */ - 0x95, 0x3F, /* Report Count (63), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0xF1, /* Report ID (241), */ - 0x09, 0x48, /* Usage (48h), */ - 0x95, 0x3F, /* Report Count (63), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0xF2, /* Report ID (242), */ - 0x09, 0x49, /* Usage (49h), */ - 0x95, 0x0F, /* Report Count (15), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0xA7, /* Report ID (167), */ - 0x09, 0x4A, /* Usage (4Ah), */ - 0x95, 0x01, /* Report Count (1), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0xA8, /* Report ID (168), */ - 0x09, 0x4B, /* Usage (4Bh), */ - 0x95, 0x01, /* Report Count (1), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0xA9, /* Report ID (169), */ - 0x09, 0x4C, /* Usage (4Ch), */ - 0x95, 0x08, /* Report Count (8), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0xAA, /* Report ID (170), */ - 0x09, 0x4E, /* Usage (4Eh), */ - 0x95, 0x01, /* Report Count (1), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0xAB, /* Report ID (171), */ - 0x09, 0x4F, /* Usage (4Fh), */ - 0x95, 0x39, /* Report Count (57), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0xAC, /* Report ID (172), */ - 0x09, 0x50, /* Usage (50h), */ - 0x95, 0x39, /* Report Count (57), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0xAD, /* Report ID (173), */ - 0x09, 0x51, /* Usage (51h), */ - 0x95, 0x0B, /* Report Count (11), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0xAE, /* Report ID (174), */ - 0x09, 0x52, /* Usage (52h), */ - 0x95, 0x01, /* Report Count (1), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0xAF, /* Report ID (175), */ - 0x09, 0x53, /* Usage (53h), */ - 0x95, 0x02, /* Report Count (2), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0xB0, /* Report ID (176), */ - 0x09, 0x54, /* Usage (54h), */ - 0x95, 0x3F, /* Report Count (63), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0xC0 /* End Collection */ -}; - -/* - * The default behavior of the Dualshock 4 is to send reports using report - * type 1 when running over Bluetooth. However, when feature report 2 is - * requested during the controller initialization it starts sending input - * reports in report 17. Since report 17 is undefined in the default HID - * descriptor the button and axis definitions must be moved to report 17 or - * the HID layer won't process the received input. - */ -static u8 dualshock4_bt_rdesc[] = { - 0x05, 0x01, /* Usage Page (Desktop), */ - 0x09, 0x05, /* Usage (Gamepad), */ - 0xA1, 0x01, /* Collection (Application), */ - 0x85, 0x01, /* Report ID (1), */ - 0x75, 0x08, /* Report Size (8), */ - 0x95, 0x0A, /* Report Count (9), */ - 0x81, 0x02, /* Input (Variable), */ - 0x06, 0x04, 0xFF, /* Usage Page (FF04h), */ - 0x85, 0x02, /* Report ID (2), */ - 0x09, 0x24, /* Usage (24h), */ - 0x95, 0x24, /* Report Count (36), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0xA3, /* Report ID (163), */ - 0x09, 0x25, /* Usage (25h), */ - 0x95, 0x30, /* Report Count (48), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0x05, /* Report ID (5), */ - 0x09, 0x26, /* Usage (26h), */ - 0x95, 0x28, /* Report Count (40), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0x06, /* Report ID (6), */ - 0x09, 0x27, /* Usage (27h), */ - 0x95, 0x34, /* Report Count (52), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0x07, /* Report ID (7), */ - 0x09, 0x28, /* Usage (28h), */ - 0x95, 0x30, /* Report Count (48), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0x08, /* Report ID (8), */ - 0x09, 0x29, /* Usage (29h), */ - 0x95, 0x2F, /* Report Count (47), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x06, 0x03, 0xFF, /* Usage Page (FF03h), */ - 0x85, 0x03, /* Report ID (3), */ - 0x09, 0x21, /* Usage (21h), */ - 0x95, 0x26, /* Report Count (38), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0x04, /* Report ID (4), */ - 0x09, 0x22, /* Usage (22h), */ - 0x95, 0x2E, /* Report Count (46), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0xF0, /* Report ID (240), */ - 0x09, 0x47, /* Usage (47h), */ - 0x95, 0x3F, /* Report Count (63), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0xF1, /* Report ID (241), */ - 0x09, 0x48, /* Usage (48h), */ - 0x95, 0x3F, /* Report Count (63), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0xF2, /* Report ID (242), */ - 0x09, 0x49, /* Usage (49h), */ - 0x95, 0x0F, /* Report Count (15), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0x11, /* Report ID (17), */ - 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ - 0x09, 0x20, /* Usage (20h), */ - 0x95, 0x02, /* Report Count (2), */ - 0x81, 0x02, /* Input (Variable), */ - 0x05, 0x01, /* Usage Page (Desktop), */ - 0x09, 0x30, /* Usage (X), */ - 0x09, 0x31, /* Usage (Y), */ - 0x09, 0x32, /* Usage (Z), */ - 0x09, 0x35, /* Usage (Rz), */ - 0x15, 0x00, /* Logical Minimum (0), */ - 0x26, 0xFF, 0x00, /* Logical Maximum (255), */ - 0x75, 0x08, /* Report Size (8), */ - 0x95, 0x04, /* Report Count (4), */ - 0x81, 0x02, /* Input (Variable), */ - 0x09, 0x39, /* Usage (Hat Switch), */ - 0x15, 0x00, /* Logical Minimum (0), */ - 0x25, 0x07, /* Logical Maximum (7), */ - 0x75, 0x04, /* Report Size (4), */ - 0x95, 0x01, /* Report Count (1), */ - 0x81, 0x42, /* Input (Variable, Null State), */ - 0x05, 0x09, /* Usage Page (Button), */ - 0x19, 0x01, /* Usage Minimum (01h), */ - 0x29, 0x0E, /* Usage Maximum (0Eh), */ - 0x15, 0x00, /* Logical Minimum (0), */ - 0x25, 0x01, /* Logical Maximum (1), */ - 0x75, 0x01, /* Report Size (1), */ - 0x95, 0x0E, /* Report Count (14), */ - 0x81, 0x02, /* Input (Variable), */ - 0x75, 0x06, /* Report Size (6), */ - 0x95, 0x01, /* Report Count (1), */ - 0x81, 0x01, /* Input (Constant), */ - 0x05, 0x01, /* Usage Page (Desktop), */ - 0x09, 0x33, /* Usage (Rx), */ - 0x09, 0x34, /* Usage (Ry), */ - 0x15, 0x00, /* Logical Minimum (0), */ - 0x26, 0xFF, 0x00, /* Logical Maximum (255), */ - 0x75, 0x08, /* Report Size (8), */ - 0x95, 0x02, /* Report Count (2), */ - 0x81, 0x02, /* Input (Variable), */ - 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ - 0x09, 0x20, /* Usage (20h), */ - 0x95, 0x03, /* Report Count (3), */ - 0x81, 0x02, /* Input (Variable), */ - 0x05, 0x01, /* Usage Page (Desktop), */ - 0x19, 0x40, /* Usage Minimum (40h), */ - 0x29, 0x42, /* Usage Maximum (42h), */ - 0x16, 0x00, 0x80, /* Logical Minimum (-32768), */ - 0x26, 0x00, 0x7F, /* Logical Maximum (32767), */ - 0x75, 0x10, /* Report Size (16), */ - 0x95, 0x03, /* Report Count (3), */ - 0x81, 0x02, /* Input (Variable), */ - 0x19, 0x43, /* Usage Minimum (43h), */ - 0x29, 0x45, /* Usage Maximum (45h), */ - 0x16, 0x00, 0xE0, /* Logical Minimum (-8192), */ - 0x26, 0xFF, 0x1F, /* Logical Maximum (8191), */ - 0x95, 0x03, /* Report Count (3), */ - 0x81, 0x02, /* Input (Variable), */ - 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ - 0x09, 0x20, /* Usage (20h), */ - 0x15, 0x00, /* Logical Minimum (0), */ - 0x26, 0xFF, 0x00, /* Logical Maximum (255), */ - 0x75, 0x08, /* Report Size (8), */ - 0x95, 0x31, /* Report Count (51), */ - 0x81, 0x02, /* Input (Variable), */ - 0x09, 0x21, /* Usage (21h), */ - 0x75, 0x08, /* Report Size (8), */ - 0x95, 0x4D, /* Report Count (77), */ - 0x91, 0x02, /* Output (Variable), */ - 0x85, 0x12, /* Report ID (18), */ - 0x09, 0x22, /* Usage (22h), */ - 0x95, 0x8D, /* Report Count (141), */ - 0x81, 0x02, /* Input (Variable), */ - 0x09, 0x23, /* Usage (23h), */ - 0x91, 0x02, /* Output (Variable), */ - 0x85, 0x13, /* Report ID (19), */ - 0x09, 0x24, /* Usage (24h), */ - 0x95, 0xCD, /* Report Count (205), */ - 0x81, 0x02, /* Input (Variable), */ - 0x09, 0x25, /* Usage (25h), */ - 0x91, 0x02, /* Output (Variable), */ - 0x85, 0x14, /* Report ID (20), */ - 0x09, 0x26, /* Usage (26h), */ - 0x96, 0x0D, 0x01, /* Report Count (269), */ - 0x81, 0x02, /* Input (Variable), */ - 0x09, 0x27, /* Usage (27h), */ - 0x91, 0x02, /* Output (Variable), */ - 0x85, 0x15, /* Report ID (21), */ - 0x09, 0x28, /* Usage (28h), */ - 0x96, 0x4D, 0x01, /* Report Count (333), */ - 0x81, 0x02, /* Input (Variable), */ - 0x09, 0x29, /* Usage (29h), */ - 0x91, 0x02, /* Output (Variable), */ - 0x85, 0x16, /* Report ID (22), */ - 0x09, 0x2A, /* Usage (2Ah), */ - 0x96, 0x8D, 0x01, /* Report Count (397), */ - 0x81, 0x02, /* Input (Variable), */ - 0x09, 0x2B, /* Usage (2Bh), */ - 0x91, 0x02, /* Output (Variable), */ - 0x85, 0x17, /* Report ID (23), */ - 0x09, 0x2C, /* Usage (2Ch), */ - 0x96, 0xCD, 0x01, /* Report Count (461), */ - 0x81, 0x02, /* Input (Variable), */ - 0x09, 0x2D, /* Usage (2Dh), */ - 0x91, 0x02, /* Output (Variable), */ - 0x85, 0x18, /* Report ID (24), */ - 0x09, 0x2E, /* Usage (2Eh), */ - 0x96, 0x0D, 0x02, /* Report Count (525), */ - 0x81, 0x02, /* Input (Variable), */ - 0x09, 0x2F, /* Usage (2Fh), */ - 0x91, 0x02, /* Output (Variable), */ - 0x85, 0x19, /* Report ID (25), */ - 0x09, 0x30, /* Usage (30h), */ - 0x96, 0x22, 0x02, /* Report Count (546), */ - 0x81, 0x02, /* Input (Variable), */ - 0x09, 0x31, /* Usage (31h), */ - 0x91, 0x02, /* Output (Variable), */ - 0x06, 0x80, 0xFF, /* Usage Page (FF80h), */ - 0x85, 0x82, /* Report ID (130), */ - 0x09, 0x22, /* Usage (22h), */ - 0x95, 0x3F, /* Report Count (63), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0x83, /* Report ID (131), */ - 0x09, 0x23, /* Usage (23h), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0x84, /* Report ID (132), */ - 0x09, 0x24, /* Usage (24h), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0x90, /* Report ID (144), */ - 0x09, 0x30, /* Usage (30h), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0x91, /* Report ID (145), */ - 0x09, 0x31, /* Usage (31h), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0x92, /* Report ID (146), */ - 0x09, 0x32, /* Usage (32h), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0x93, /* Report ID (147), */ - 0x09, 0x33, /* Usage (33h), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0xA0, /* Report ID (160), */ - 0x09, 0x40, /* Usage (40h), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0xA4, /* Report ID (164), */ - 0x09, 0x44, /* Usage (44h), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0xC0 /* End Collection */ -}; - -static __u8 ps3remote_rdesc[] = { +static u8 ps3remote_rdesc[] = { 0x05, 0x01, /* GUsagePage Generic Desktop */ 0x09, 0x05, /* LUsage 0x05 [Game Pad] */ 0xA1, 0x01, /* MCollection Application (mouse, keyboard) */ @@ -817,14 +179,18 @@ static __u8 ps3remote_rdesc[] = { /* Use collection 1 for joypad buttons */ 0xA1, 0x02, /* MCollection Logical (interrelated data) */ - /* Ignore the 1st byte, maybe it is used for a controller - * number but it's not needed for correct operation */ + /* + * Ignore the 1st byte, maybe it is used for a controller + * number but it's not needed for correct operation + */ 0x75, 0x08, /* GReportSize 0x08 [8] */ 0x95, 0x01, /* GReportCount 0x01 [1] */ 0x81, 0x01, /* MInput 0x01 (Const[0] Arr[1] Abs[2]) */ - /* Bytes from 2nd to 4th are a bitmap for joypad buttons, for these - * buttons multiple keypresses are allowed */ + /* + * Bytes from 2nd to 4th are a bitmap for joypad buttons, for these + * buttons multiple keypresses are allowed + */ 0x05, 0x09, /* GUsagePage Button */ 0x19, 0x01, /* LUsageMinimum 0x01 [Button 1 (primary/trigger)] */ 0x29, 0x18, /* LUsageMaximum 0x18 [Button 24] */ @@ -849,8 +215,10 @@ static __u8 ps3remote_rdesc[] = { 0x95, 0x01, /* GReportCount 0x01 [1] */ 0x80, /* MInput */ - /* Ignore bytes from 6th to 11th, 6th to 10th are always constant at - * 0xff and 11th is for press indication */ + /* + * Ignore bytes from 6th to 11th, 6th to 10th are always constant at + * 0xff and 11th is for press indication + */ 0x75, 0x08, /* GReportSize 0x08 [8] */ 0x95, 0x06, /* GReportCount 0x06 [6] */ 0x81, 0x01, /* MInput 0x01 (Const[0] Arr[1] Abs[2]) */ @@ -929,7 +297,7 @@ static const unsigned int buzz_keymap[] = { /* * The controller has 4 remote buzzers, each with one LED and 5 * buttons. - * + * * We use the mapping chosen by the controller, which is: * * Key Offset @@ -943,15 +311,15 @@ static const unsigned int buzz_keymap[] = { * So, for example, the orange button on the third buzzer is mapped to * BTN_TRIGGER_HAPPY14 */ - [ 1] = BTN_TRIGGER_HAPPY1, - [ 2] = BTN_TRIGGER_HAPPY2, - [ 3] = BTN_TRIGGER_HAPPY3, - [ 4] = BTN_TRIGGER_HAPPY4, - [ 5] = BTN_TRIGGER_HAPPY5, - [ 6] = BTN_TRIGGER_HAPPY6, - [ 7] = BTN_TRIGGER_HAPPY7, - [ 8] = BTN_TRIGGER_HAPPY8, - [ 9] = BTN_TRIGGER_HAPPY9, + [1] = BTN_TRIGGER_HAPPY1, + [2] = BTN_TRIGGER_HAPPY2, + [3] = BTN_TRIGGER_HAPPY3, + [4] = BTN_TRIGGER_HAPPY4, + [5] = BTN_TRIGGER_HAPPY5, + [6] = BTN_TRIGGER_HAPPY6, + [7] = BTN_TRIGGER_HAPPY7, + [8] = BTN_TRIGGER_HAPPY8, + [9] = BTN_TRIGGER_HAPPY9, [10] = BTN_TRIGGER_HAPPY10, [11] = BTN_TRIGGER_HAPPY11, [12] = BTN_TRIGGER_HAPPY12, @@ -965,6 +333,97 @@ static const unsigned int buzz_keymap[] = { [20] = BTN_TRIGGER_HAPPY20, }; +/* The Navigation controller is a partial DS3 and uses the same HID report + * and hence the same keymap indices, however not not all axes/buttons + * are physically present. We use the same axis and button mapping as + * the DS3, which uses the Linux gamepad spec. + */ +static const unsigned int navigation_absmap[] = { + [0x30] = ABS_X, + [0x31] = ABS_Y, + [0x33] = ABS_Z, /* L2 */ +}; + +/* Buttons not physically available on the device, but still available + * in the reports are explicitly set to 0 for documentation purposes. + */ +static const unsigned int navigation_keymap[] = { + [0x01] = 0, /* Select */ + [0x02] = BTN_THUMBL, /* L3 */ + [0x03] = 0, /* R3 */ + [0x04] = 0, /* Start */ + [0x05] = BTN_DPAD_UP, /* Up */ + [0x06] = BTN_DPAD_RIGHT, /* Right */ + [0x07] = BTN_DPAD_DOWN, /* Down */ + [0x08] = BTN_DPAD_LEFT, /* Left */ + [0x09] = BTN_TL2, /* L2 */ + [0x0a] = 0, /* R2 */ + [0x0b] = BTN_TL, /* L1 */ + [0x0c] = 0, /* R1 */ + [0x0d] = BTN_NORTH, /* Triangle */ + [0x0e] = BTN_EAST, /* Circle */ + [0x0f] = BTN_SOUTH, /* Cross */ + [0x10] = BTN_WEST, /* Square */ + [0x11] = BTN_MODE, /* PS */ +}; + +static const unsigned int sixaxis_absmap[] = { + [0x30] = ABS_X, + [0x31] = ABS_Y, + [0x32] = ABS_RX, /* right stick X */ + [0x35] = ABS_RY, /* right stick Y */ +}; + +static const unsigned int sixaxis_keymap[] = { + [0x01] = BTN_SELECT, /* Select */ + [0x02] = BTN_THUMBL, /* L3 */ + [0x03] = BTN_THUMBR, /* R3 */ + [0x04] = BTN_START, /* Start */ + [0x05] = BTN_DPAD_UP, /* Up */ + [0x06] = BTN_DPAD_RIGHT, /* Right */ + [0x07] = BTN_DPAD_DOWN, /* Down */ + [0x08] = BTN_DPAD_LEFT, /* Left */ + [0x09] = BTN_TL2, /* L2 */ + [0x0a] = BTN_TR2, /* R2 */ + [0x0b] = BTN_TL, /* L1 */ + [0x0c] = BTN_TR, /* R1 */ + [0x0d] = BTN_NORTH, /* Triangle */ + [0x0e] = BTN_EAST, /* Circle */ + [0x0f] = BTN_SOUTH, /* Cross */ + [0x10] = BTN_WEST, /* Square */ + [0x11] = BTN_MODE, /* PS */ +}; + +static const unsigned int ds4_absmap[] = { + [0x30] = ABS_X, + [0x31] = ABS_Y, + [0x32] = ABS_RX, /* right stick X */ + [0x33] = ABS_Z, /* L2 */ + [0x34] = ABS_RZ, /* R2 */ + [0x35] = ABS_RY, /* right stick Y */ +}; + +static const unsigned int ds4_keymap[] = { + [0x1] = BTN_WEST, /* Square */ + [0x2] = BTN_SOUTH, /* Cross */ + [0x3] = BTN_EAST, /* Circle */ + [0x4] = BTN_NORTH, /* Triangle */ + [0x5] = BTN_TL, /* L1 */ + [0x6] = BTN_TR, /* R1 */ + [0x7] = BTN_TL2, /* L2 */ + [0x8] = BTN_TR2, /* R2 */ + [0x9] = BTN_SELECT, /* Share */ + [0xa] = BTN_START, /* Options */ + [0xb] = BTN_THUMBL, /* L3 */ + [0xc] = BTN_THUMBR, /* R3 */ + [0xd] = BTN_MODE, /* PS */ +}; + +static const struct {int x; int y; } ds4_hat_mapping[] = { + {0, -1}, {1, -1}, {1, 0}, {1, 1}, {0, 1}, {-1, 1}, {-1, 0}, {-1, -1}, + {0, 0} +}; + static enum power_supply_property sony_battery_props[] = { POWER_SUPPLY_PROP_PRESENT, POWER_SUPPLY_PROP_CAPACITY, @@ -973,33 +432,33 @@ static enum power_supply_property sony_battery_props[] = { }; struct sixaxis_led { - __u8 time_enabled; /* the total time the led is active (0xff means forever) */ - __u8 duty_length; /* how long a cycle is in deciseconds (0 means "really fast") */ - __u8 enabled; - __u8 duty_off; /* % of duty_length the led is off (0xff means 100%) */ - __u8 duty_on; /* % of duty_length the led is on (0xff mean 100%) */ + u8 time_enabled; /* the total time the led is active (0xff means forever) */ + u8 duty_length; /* how long a cycle is in deciseconds (0 means "really fast") */ + u8 enabled; + u8 duty_off; /* % of duty_length the led is off (0xff means 100%) */ + u8 duty_on; /* % of duty_length the led is on (0xff mean 100%) */ } __packed; struct sixaxis_rumble { - __u8 padding; - __u8 right_duration; /* Right motor duration (0xff means forever) */ - __u8 right_motor_on; /* Right (small) motor on/off, only supports values of 0 or 1 (off/on) */ - __u8 left_duration; /* Left motor duration (0xff means forever) */ - __u8 left_motor_force; /* left (large) motor, supports force values from 0 to 255 */ + u8 padding; + u8 right_duration; /* Right motor duration (0xff means forever) */ + u8 right_motor_on; /* Right (small) motor on/off, only supports values of 0 or 1 (off/on) */ + u8 left_duration; /* Left motor duration (0xff means forever) */ + u8 left_motor_force; /* left (large) motor, supports force values from 0 to 255 */ } __packed; struct sixaxis_output_report { - __u8 report_id; + u8 report_id; struct sixaxis_rumble rumble; - __u8 padding[4]; - __u8 leds_bitmap; /* bitmap of enabled LEDs: LED_1 = 0x02, LED_2 = 0x04, ... */ + u8 padding[4]; + u8 leds_bitmap; /* bitmap of enabled LEDs: LED_1 = 0x02, LED_2 = 0x04, ... */ struct sixaxis_led led[4]; /* LEDx at (4 - x) */ struct sixaxis_led _reserved; /* LED5, not actually soldered */ } __packed; union sixaxis_output_report_01 { struct sixaxis_output_report data; - __u8 buf[36]; + u8 buf[36]; }; struct motion_output_report_02 { @@ -1009,68 +468,176 @@ struct motion_output_report_02 { u8 rumble; }; -#define DS4_REPORT_0x02_SIZE 37 -#define DS4_REPORT_0x05_SIZE 32 -#define DS4_REPORT_0x11_SIZE 78 -#define DS4_REPORT_0x81_SIZE 7 +#define DS4_FEATURE_REPORT_0x02_SIZE 37 +#define DS4_FEATURE_REPORT_0x05_SIZE 41 +#define DS4_FEATURE_REPORT_0x81_SIZE 7 +#define DS4_INPUT_REPORT_0x11_SIZE 78 +#define DS4_OUTPUT_REPORT_0x05_SIZE 32 +#define DS4_OUTPUT_REPORT_0x11_SIZE 78 #define SIXAXIS_REPORT_0xF2_SIZE 17 #define SIXAXIS_REPORT_0xF5_SIZE 8 #define MOTION_REPORT_0x02_SIZE 49 +/* Offsets relative to USB input report (0x1). Bluetooth (0x11) requires an + * additional +2. + */ +#define DS4_INPUT_REPORT_AXIS_OFFSET 1 +#define DS4_INPUT_REPORT_BUTTON_OFFSET 5 +#define DS4_INPUT_REPORT_TIMESTAMP_OFFSET 10 +#define DS4_INPUT_REPORT_GYRO_X_OFFSET 13 +#define DS4_INPUT_REPORT_BATTERY_OFFSET 30 +#define DS4_INPUT_REPORT_TOUCHPAD_OFFSET 33 + +#define SENSOR_SUFFIX " Motion Sensors" +#define DS4_TOUCHPAD_SUFFIX " Touchpad" + +/* Default to 4ms poll interval, which is same as USB (not adjustable). */ +#define DS4_BT_DEFAULT_POLL_INTERVAL_MS 4 +#define DS4_BT_MAX_POLL_INTERVAL_MS 62 +#define DS4_GYRO_RES_PER_DEG_S 1024 +#define DS4_ACC_RES_PER_G 8192 + +#define SIXAXIS_INPUT_REPORT_ACC_X_OFFSET 41 +#define SIXAXIS_ACC_RES_PER_G 113 + static DEFINE_SPINLOCK(sony_dev_list_lock); static LIST_HEAD(sony_device_list); static DEFINE_IDA(sony_device_id_allocator); +/* Used for calibration of DS4 accelerometer and gyro. */ +struct ds4_calibration_data { + int abs_code; + short bias; + /* Calibration requires scaling against a sensitivity value, which is a + * float. Store sensitivity as a fraction to limit floating point + * calculations until final calibration. + */ + int sens_numer; + int sens_denom; +}; + +enum ds4_dongle_state { + DONGLE_DISCONNECTED, + DONGLE_CALIBRATING, + DONGLE_CONNECTED, + DONGLE_DISABLED +}; + +enum sony_worker { + SONY_WORKER_STATE, + SONY_WORKER_HOTPLUG +}; + struct sony_sc { spinlock_t lock; struct list_head list_node; struct hid_device *hdev; + struct input_dev *touchpad; + struct input_dev *sensor_dev; struct led_classdev *leds[MAX_LEDS]; unsigned long quirks; + struct work_struct hotplug_worker; struct work_struct state_worker; + void (*send_output_report)(struct sony_sc *); struct power_supply *battery; struct power_supply_desc battery_desc; int device_id; - __u8 *output_report_dmabuf; + u8 *output_report_dmabuf; #ifdef CONFIG_SONY_FF - __u8 left; - __u8 right; + u8 left; + u8 right; #endif - __u8 mac_address[6]; - __u8 worker_initialized; - __u8 cable_state; - __u8 battery_charging; - __u8 battery_capacity; - __u8 led_state[MAX_LEDS]; - __u8 led_delay_on[MAX_LEDS]; - __u8 led_delay_off[MAX_LEDS]; - __u8 led_count; + u8 mac_address[6]; + u8 hotplug_worker_initialized; + u8 state_worker_initialized; + u8 defer_initialization; + u8 cable_state; + u8 battery_charging; + u8 battery_capacity; + u8 led_state[MAX_LEDS]; + u8 led_delay_on[MAX_LEDS]; + u8 led_delay_off[MAX_LEDS]; + u8 led_count; + + bool timestamp_initialized; + u16 prev_timestamp; + unsigned int timestamp_us; + + u8 ds4_bt_poll_interval; + enum ds4_dongle_state ds4_dongle_state; + /* DS4 calibration data */ + struct ds4_calibration_data ds4_calib_data[6]; }; -static __u8 *sixaxis_fixup(struct hid_device *hdev, __u8 *rdesc, - unsigned int *rsize) +static void sony_set_leds(struct sony_sc *sc); + +static inline void sony_schedule_work(struct sony_sc *sc, + enum sony_worker which) { - *rsize = sizeof(sixaxis_rdesc); - return sixaxis_rdesc; + unsigned long flags; + + switch (which) { + case SONY_WORKER_STATE: + spin_lock_irqsave(&sc->lock, flags); + if (!sc->defer_initialization && sc->state_worker_initialized) + schedule_work(&sc->state_worker); + spin_unlock_irqrestore(&sc->lock, flags); + break; + case SONY_WORKER_HOTPLUG: + if (sc->hotplug_worker_initialized) + schedule_work(&sc->hotplug_worker); + break; + } } -static u8 *motion_fixup(struct hid_device *hdev, u8 *rdesc, - unsigned int *rsize) +static ssize_t ds4_show_poll_interval(struct device *dev, + struct device_attribute + *attr, char *buf) { - *rsize = sizeof(motion_rdesc); - return motion_rdesc; + struct hid_device *hdev = container_of(dev, struct hid_device, dev); + struct sony_sc *sc = hid_get_drvdata(hdev); + + return snprintf(buf, PAGE_SIZE, "%i\n", sc->ds4_bt_poll_interval); +} + +static ssize_t ds4_store_poll_interval(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct hid_device *hdev = container_of(dev, struct hid_device, dev); + struct sony_sc *sc = hid_get_drvdata(hdev); + unsigned long flags; + u8 interval; + + if (kstrtou8(buf, 0, &interval)) + return -EINVAL; + + if (interval > DS4_BT_MAX_POLL_INTERVAL_MS) + return -EINVAL; + + spin_lock_irqsave(&sc->lock, flags); + sc->ds4_bt_poll_interval = interval; + spin_unlock_irqrestore(&sc->lock, flags); + + sony_schedule_work(sc, SONY_WORKER_STATE); + + return count; } -static u8 *navigation_fixup(struct hid_device *hdev, u8 *rdesc, +static DEVICE_ATTR(bt_poll_interval, 0644, ds4_show_poll_interval, + ds4_store_poll_interval); + + +static u8 *motion_fixup(struct hid_device *hdev, u8 *rdesc, unsigned int *rsize) { - *rsize = sizeof(navigation_rdesc); - return navigation_rdesc; + *rsize = sizeof(motion_rdesc); + return motion_rdesc; } -static __u8 *ps3remote_fixup(struct hid_device *hdev, __u8 *rdesc, +static u8 *ps3remote_fixup(struct hid_device *hdev, u8 *rdesc, unsigned int *rsize) { *rsize = sizeof(ps3remote_rdesc); @@ -1111,7 +678,134 @@ static int ps3remote_mapping(struct hid_device *hdev, struct hid_input *hi, return 1; } -static __u8 *sony_report_fixup(struct hid_device *hdev, __u8 *rdesc, +static int navigation_mapping(struct hid_device *hdev, struct hid_input *hi, + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max) +{ + if ((usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON) { + unsigned int key = usage->hid & HID_USAGE; + + if (key >= ARRAY_SIZE(sixaxis_keymap)) + return -1; + + key = navigation_keymap[key]; + if (!key) + return -1; + + hid_map_usage_clear(hi, usage, bit, max, EV_KEY, key); + return 1; + } else if (usage->hid == HID_GD_POINTER) { + /* See comment in sixaxis_mapping, basically the L2 (and R2) + * triggers are reported through GD Pointer. + * In addition we ignore any analog button 'axes' and only + * support digital buttons. + */ + switch (usage->usage_index) { + case 8: /* L2 */ + usage->hid = HID_GD_Z; + break; + default: + return -1; + } + + hid_map_usage_clear(hi, usage, bit, max, EV_ABS, usage->hid & 0xf); + return 1; + } else if ((usage->hid & HID_USAGE_PAGE) == HID_UP_GENDESK) { + unsigned int abs = usage->hid & HID_USAGE; + + if (abs >= ARRAY_SIZE(navigation_absmap)) + return -1; + + abs = navigation_absmap[abs]; + + hid_map_usage_clear(hi, usage, bit, max, EV_ABS, abs); + return 1; + } + + return -1; +} + + +static int sixaxis_mapping(struct hid_device *hdev, struct hid_input *hi, + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max) +{ + if ((usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON) { + unsigned int key = usage->hid & HID_USAGE; + + if (key >= ARRAY_SIZE(sixaxis_keymap)) + return -1; + + key = sixaxis_keymap[key]; + hid_map_usage_clear(hi, usage, bit, max, EV_KEY, key); + return 1; + } else if (usage->hid == HID_GD_POINTER) { + /* The DS3 provides analog values for most buttons and even + * for HAT axes through GD Pointer. L2 and R2 are reported + * among these as well instead of as GD Z / RZ. Remap L2 + * and R2 and ignore other analog 'button axes' as there is + * no good way for reporting them. + */ + switch (usage->usage_index) { + case 8: /* L2 */ + usage->hid = HID_GD_Z; + break; + case 9: /* R2 */ + usage->hid = HID_GD_RZ; + break; + default: + return -1; + } + + hid_map_usage_clear(hi, usage, bit, max, EV_ABS, usage->hid & 0xf); + return 1; + } else if ((usage->hid & HID_USAGE_PAGE) == HID_UP_GENDESK) { + unsigned int abs = usage->hid & HID_USAGE; + + if (abs >= ARRAY_SIZE(sixaxis_absmap)) + return -1; + + abs = sixaxis_absmap[abs]; + + hid_map_usage_clear(hi, usage, bit, max, EV_ABS, abs); + return 1; + } + + return -1; +} + +static int ds4_mapping(struct hid_device *hdev, struct hid_input *hi, + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max) +{ + if ((usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON) { + unsigned int key = usage->hid & HID_USAGE; + + if (key >= ARRAY_SIZE(ds4_keymap)) + return -1; + + key = ds4_keymap[key]; + hid_map_usage_clear(hi, usage, bit, max, EV_KEY, key); + return 1; + } else if ((usage->hid & HID_USAGE_PAGE) == HID_UP_GENDESK) { + unsigned int abs = usage->hid & HID_USAGE; + + /* Let the HID parser deal with the HAT. */ + if (usage->hid == HID_GD_HATSWITCH) + return 0; + + if (abs >= ARRAY_SIZE(ds4_absmap)) + return -1; + + abs = ds4_absmap[abs]; + hid_map_usage_clear(hi, usage, bit, max, EV_ABS, abs); + return 1; + } + + return 0; +} + +static u8 *sony_report_fixup(struct hid_device *hdev, u8 *rdesc, unsigned int *rsize) { struct sony_sc *sc = hid_get_drvdata(hdev); @@ -1132,42 +826,21 @@ static __u8 *sony_report_fixup(struct hid_device *hdev, __u8 *rdesc, rdesc[55] = 0x06; } - /* - * The default Dualshock 4 USB descriptor doesn't assign - * the gyroscope values to corresponding axes so we need a - * modified one. - */ - if ((sc->quirks & DUALSHOCK4_CONTROLLER_USB) && *rsize == 467) { - hid_info(hdev, "Using modified Dualshock 4 report descriptor with gyroscope axes\n"); - rdesc = dualshock4_usb_rdesc; - *rsize = sizeof(dualshock4_usb_rdesc); - } else if ((sc->quirks & DUALSHOCK4_CONTROLLER_BT) && *rsize == 357) { - hid_info(hdev, "Using modified Dualshock 4 Bluetooth report descriptor\n"); - rdesc = dualshock4_bt_rdesc; - *rsize = sizeof(dualshock4_bt_rdesc); - } - - if (sc->quirks & SIXAXIS_CONTROLLER) - return sixaxis_fixup(hdev, rdesc, rsize); - if (sc->quirks & MOTION_CONTROLLER) return motion_fixup(hdev, rdesc, rsize); - if (sc->quirks & NAVIGATION_CONTROLLER) - return navigation_fixup(hdev, rdesc, rsize); - if (sc->quirks & PS3REMOTE) return ps3remote_fixup(hdev, rdesc, rsize); return rdesc; } -static void sixaxis_parse_report(struct sony_sc *sc, __u8 *rd, int size) +static void sixaxis_parse_report(struct sony_sc *sc, u8 *rd, int size) { - static const __u8 sixaxis_battery_capacity[] = { 0, 1, 25, 50, 75, 100 }; + static const u8 sixaxis_battery_capacity[] = { 0, 1, 25, 50, 75, 100 }; unsigned long flags; int offset; - __u8 cable_state, battery_capacity, battery_charging; + u8 cable_state, battery_capacity, battery_charging; /* * The sixaxis is charging if the battery value is 0xee @@ -1182,7 +855,7 @@ static void sixaxis_parse_report(struct sony_sc *sc, __u8 *rd, int size) battery_charging = !(rd[offset] & 0x01); cable_state = 1; } else { - __u8 index = rd[offset] <= 5 ? rd[offset] : 5; + u8 index = rd[offset] <= 5 ? rd[offset] : 5; battery_capacity = sixaxis_battery_capacity[index]; battery_charging = 0; cable_state = 0; @@ -1193,27 +866,136 @@ static void sixaxis_parse_report(struct sony_sc *sc, __u8 *rd, int size) sc->battery_capacity = battery_capacity; sc->battery_charging = battery_charging; spin_unlock_irqrestore(&sc->lock, flags); + + if (sc->quirks & SIXAXIS_CONTROLLER) { + int val; + + offset = SIXAXIS_INPUT_REPORT_ACC_X_OFFSET; + val = ((rd[offset+1] << 8) | rd[offset]) - 511; + input_report_abs(sc->sensor_dev, ABS_X, val); + + /* Y and Z are swapped and inversed */ + val = 511 - ((rd[offset+5] << 8) | rd[offset+4]); + input_report_abs(sc->sensor_dev, ABS_Y, val); + + val = 511 - ((rd[offset+3] << 8) | rd[offset+2]); + input_report_abs(sc->sensor_dev, ABS_Z, val); + + input_sync(sc->sensor_dev); + } } -static void dualshock4_parse_report(struct sony_sc *sc, __u8 *rd, int size) +static void dualshock4_parse_report(struct sony_sc *sc, u8 *rd, int size) { struct hid_input *hidinput = list_entry(sc->hdev->inputs.next, struct hid_input, list); struct input_dev *input_dev = hidinput->input; unsigned long flags; - int n, offset; - __u8 cable_state, battery_capacity, battery_charging; + int n, m, offset, num_touch_data, max_touch_data; + u8 cable_state, battery_capacity, battery_charging; + u16 timestamp; + + /* When using Bluetooth the header is 2 bytes longer, so skip these. */ + int data_offset = (sc->quirks & DUALSHOCK4_CONTROLLER_BT) ? 2 : 0; + + /* Second bit of third button byte is for the touchpad button. */ + offset = data_offset + DS4_INPUT_REPORT_BUTTON_OFFSET; + input_report_key(sc->touchpad, BTN_LEFT, rd[offset+2] & 0x2); /* - * Battery and touchpad data starts at byte 30 in the USB report and - * 32 in Bluetooth report. + * The default behavior of the Dualshock 4 is to send reports using + * report type 1 when running over Bluetooth. However, when feature + * report 2 is requested during the controller initialization it starts + * sending input reports in report 17. Since report 17 is undefined + * in the default HID descriptor, the HID layer won't generate events. + * While it is possible (and this was done before) to fixup the HID + * descriptor to add this mapping, it was better to do this manually. + * The reason is there were various pieces software both open and closed + * source, relying on the descriptors to be the same across various + * operating systems. If the descriptors wouldn't match some + * applications e.g. games on Wine would not be able to function due + * to different descriptors, which such applications are not parsing. */ - offset = (sc->quirks & DUALSHOCK4_CONTROLLER_USB) ? 30 : 32; + if (rd[0] == 17) { + int value; + + offset = data_offset + DS4_INPUT_REPORT_AXIS_OFFSET; + input_report_abs(input_dev, ABS_X, rd[offset]); + input_report_abs(input_dev, ABS_Y, rd[offset+1]); + input_report_abs(input_dev, ABS_RX, rd[offset+2]); + input_report_abs(input_dev, ABS_RY, rd[offset+3]); + + value = rd[offset+4] & 0xf; + if (value > 7) + value = 8; /* Center 0, 0 */ + input_report_abs(input_dev, ABS_HAT0X, ds4_hat_mapping[value].x); + input_report_abs(input_dev, ABS_HAT0Y, ds4_hat_mapping[value].y); + + input_report_key(input_dev, BTN_WEST, rd[offset+4] & 0x10); + input_report_key(input_dev, BTN_SOUTH, rd[offset+4] & 0x20); + input_report_key(input_dev, BTN_EAST, rd[offset+4] & 0x40); + input_report_key(input_dev, BTN_NORTH, rd[offset+4] & 0x80); + + input_report_key(input_dev, BTN_TL, rd[offset+5] & 0x1); + input_report_key(input_dev, BTN_TR, rd[offset+5] & 0x2); + input_report_key(input_dev, BTN_TL2, rd[offset+5] & 0x4); + input_report_key(input_dev, BTN_TR2, rd[offset+5] & 0x8); + input_report_key(input_dev, BTN_SELECT, rd[offset+5] & 0x10); + input_report_key(input_dev, BTN_START, rd[offset+5] & 0x20); + input_report_key(input_dev, BTN_THUMBL, rd[offset+5] & 0x40); + input_report_key(input_dev, BTN_THUMBR, rd[offset+5] & 0x80); + + input_report_key(input_dev, BTN_MODE, rd[offset+6] & 0x1); + + input_report_abs(input_dev, ABS_Z, rd[offset+7]); + input_report_abs(input_dev, ABS_RZ, rd[offset+8]); + + input_sync(input_dev); + } + + /* Convert timestamp (in 5.33us unit) to timestamp_us */ + offset = data_offset + DS4_INPUT_REPORT_TIMESTAMP_OFFSET; + timestamp = get_unaligned_le16(&rd[offset]); + if (!sc->timestamp_initialized) { + sc->timestamp_us = ((unsigned int)timestamp * 16) / 3; + sc->timestamp_initialized = true; + } else { + u16 delta; + + if (sc->prev_timestamp > timestamp) + delta = (U16_MAX - sc->prev_timestamp + timestamp + 1); + else + delta = timestamp - sc->prev_timestamp; + sc->timestamp_us += (delta * 16) / 3; + } + sc->prev_timestamp = timestamp; + input_event(sc->sensor_dev, EV_MSC, MSC_TIMESTAMP, sc->timestamp_us); + + offset = data_offset + DS4_INPUT_REPORT_GYRO_X_OFFSET; + for (n = 0; n < 6; n++) { + /* Store data in int for more precision during mult_frac. */ + int raw_data = (short)((rd[offset+1] << 8) | rd[offset]); + struct ds4_calibration_data *calib = &sc->ds4_calib_data[n]; + + /* High precision is needed during calibration, but the + * calibrated values are within 32-bit. + * Note: we swap numerator 'x' and 'numer' in mult_frac for + * precision reasons so we don't need 64-bit. + */ + int calib_data = mult_frac(calib->sens_numer, + raw_data - calib->bias, + calib->sens_denom); + + input_report_abs(sc->sensor_dev, calib->abs_code, calib_data); + offset += 2; + } + input_sync(sc->sensor_dev); /* - * The lower 4 bits of byte 30 contain the battery level + * The lower 4 bits of byte 30 (or 32 for BT) contain the battery level * and the 5th bit contains the USB cable state. */ + offset = data_offset + DS4_INPUT_REPORT_BATTERY_OFFSET; cable_state = (rd[offset] >> 4) & 0x01; battery_capacity = rd[offset] & 0x0F; @@ -1240,35 +1022,57 @@ static void dualshock4_parse_report(struct sony_sc *sc, __u8 *rd, int size) sc->battery_charging = battery_charging; spin_unlock_irqrestore(&sc->lock, flags); - offset += 5; - /* - * The Dualshock 4 multi-touch trackpad data starts at offset 35 on USB - * and 37 on Bluetooth. - * The first 7 bits of the first byte is a counter and bit 8 is a touch - * indicator that is 0 when pressed and 1 when not pressed. - * The next 3 bytes are two 12 bit touch coordinates, X and Y. - * The data for the second touch is in the same format and immediatly - * follows the data for the first. + * The Dualshock 4 multi-touch trackpad data starts at offset 33 on USB + * and 35 on Bluetooth. + * The first byte indicates the number of touch data in the report. + * Trackpad data starts 2 bytes later (e.g. 35 for USB). */ - for (n = 0; n < 2; n++) { - __u16 x, y; + offset = data_offset + DS4_INPUT_REPORT_TOUCHPAD_OFFSET; + max_touch_data = (sc->quirks & DUALSHOCK4_CONTROLLER_BT) ? 4 : 3; + if (rd[offset] > 0 && rd[offset] <= max_touch_data) + num_touch_data = rd[offset]; + else + num_touch_data = 1; + offset += 1; + + for (m = 0; m < num_touch_data; m++) { + /* Skip past timestamp */ + offset += 1; + + /* + * The first 7 bits of the first byte is a counter and bit 8 is + * a touch indicator that is 0 when pressed and 1 when not + * pressed. + * The next 3 bytes are two 12 bit touch coordinates, X and Y. + * The data for the second touch is in the same format and + * immediately follows the data for the first. + */ + for (n = 0; n < 2; n++) { + u16 x, y; + bool active; - x = rd[offset+1] | ((rd[offset+2] & 0xF) << 8); - y = ((rd[offset+2] & 0xF0) >> 4) | (rd[offset+3] << 4); + x = rd[offset+1] | ((rd[offset+2] & 0xF) << 8); + y = ((rd[offset+2] & 0xF0) >> 4) | (rd[offset+3] << 4); - input_mt_slot(input_dev, n); - input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, - !(rd[offset] >> 7)); - input_report_abs(input_dev, ABS_MT_POSITION_X, x); - input_report_abs(input_dev, ABS_MT_POSITION_Y, y); + active = !(rd[offset] >> 7); + input_mt_slot(sc->touchpad, n); + input_mt_report_slot_state(sc->touchpad, MT_TOOL_FINGER, active); - offset += 4; + if (active) { + input_report_abs(sc->touchpad, ABS_MT_POSITION_X, x); + input_report_abs(sc->touchpad, ABS_MT_POSITION_Y, y); + } + + offset += 4; + } + input_mt_sync_frame(sc->touchpad); + input_sync(sc->touchpad); } } static int sony_raw_event(struct hid_device *hdev, struct hid_report *report, - __u8 *rd, int size) + u8 *rd, int size) { struct sony_sc *sc = hid_get_drvdata(hdev); @@ -1299,12 +1103,89 @@ static int sony_raw_event(struct hid_device *hdev, struct hid_report *report, } else if ((sc->quirks & NAVIGATION_CONTROLLER) && rd[0] == 0x01 && size == 49) { sixaxis_parse_report(sc, rd, size); - } else if (((sc->quirks & DUALSHOCK4_CONTROLLER_USB) && rd[0] == 0x01 && - size == 64) || ((sc->quirks & DUALSHOCK4_CONTROLLER_BT) - && rd[0] == 0x11 && size == 78)) { + } else if ((sc->quirks & DUALSHOCK4_CONTROLLER_USB) && rd[0] == 0x01 && + size == 64) { + dualshock4_parse_report(sc, rd, size); + } else if (((sc->quirks & DUALSHOCK4_CONTROLLER_BT) && rd[0] == 0x11 && + size == 78)) { + /* CRC check */ + u8 bthdr = 0xA1; + u32 crc; + u32 report_crc; + + crc = crc32_le(0xFFFFFFFF, &bthdr, 1); + crc = ~crc32_le(crc, rd, DS4_INPUT_REPORT_0x11_SIZE-4); + report_crc = get_unaligned_le32(&rd[DS4_INPUT_REPORT_0x11_SIZE-4]); + if (crc != report_crc) { + hid_dbg(sc->hdev, "DualShock 4 input report's CRC check failed, received crc 0x%0x != 0x%0x\n", + report_crc, crc); + return -EILSEQ; + } + + dualshock4_parse_report(sc, rd, size); + } else if ((sc->quirks & DUALSHOCK4_DONGLE) && rd[0] == 0x01 && + size == 64) { + unsigned long flags; + enum ds4_dongle_state dongle_state; + + /* + * In the case of a DS4 USB dongle, bit[2] of byte 31 indicates + * if a DS4 is actually connected (indicated by '0'). + * For non-dongle, this bit is always 0 (connected). + */ + bool connected = (rd[31] & 0x04) ? false : true; + + spin_lock_irqsave(&sc->lock, flags); + dongle_state = sc->ds4_dongle_state; + spin_unlock_irqrestore(&sc->lock, flags); + + /* + * The dongle always sends input reports even when no + * DS4 is attached. When a DS4 is connected, we need to + * obtain calibration data before we can use it. + * The code below tracks dongle state and kicks of + * calibration when needed and only allows us to process + * input if a DS4 is actually connected. + */ + if (dongle_state == DONGLE_DISCONNECTED && connected) { + hid_info(sc->hdev, "DualShock 4 USB dongle: controller connected\n"); + sony_set_leds(sc); + + spin_lock_irqsave(&sc->lock, flags); + sc->ds4_dongle_state = DONGLE_CALIBRATING; + spin_unlock_irqrestore(&sc->lock, flags); + + sony_schedule_work(sc, SONY_WORKER_HOTPLUG); + + /* Don't process the report since we don't have + * calibration data, but let hidraw have it anyway. + */ + return 0; + } else if ((dongle_state == DONGLE_CONNECTED || + dongle_state == DONGLE_DISABLED) && !connected) { + hid_info(sc->hdev, "DualShock 4 USB dongle: controller disconnected\n"); + + spin_lock_irqsave(&sc->lock, flags); + sc->ds4_dongle_state = DONGLE_DISCONNECTED; + spin_unlock_irqrestore(&sc->lock, flags); + + /* Return 0, so hidraw can get the report. */ + return 0; + } else if (dongle_state == DONGLE_CALIBRATING || + dongle_state == DONGLE_DISABLED || + dongle_state == DONGLE_DISCONNECTED) { + /* Return 0, so hidraw can get the report. */ + return 0; + } + dualshock4_parse_report(sc, rd, size); } + if (sc->defer_initialization) { + sc->defer_initialization = 0; + sony_schedule_work(sc, SONY_WORKER_STATE); + } + return 0; } @@ -1340,49 +1221,189 @@ static int sony_mapping(struct hid_device *hdev, struct hid_input *hi, if (sc->quirks & PS3REMOTE) return ps3remote_mapping(hdev, hi, field, usage, bit, max); + if (sc->quirks & NAVIGATION_CONTROLLER) + return navigation_mapping(hdev, hi, field, usage, bit, max); + + if (sc->quirks & SIXAXIS_CONTROLLER) + return sixaxis_mapping(hdev, hi, field, usage, bit, max); + + if (sc->quirks & DUALSHOCK4_CONTROLLER) + return ds4_mapping(hdev, hi, field, usage, bit, max); + + /* Let hid-core decide for the others */ return 0; } -static int sony_register_touchpad(struct hid_input *hi, int touch_count, +static int sony_register_touchpad(struct sony_sc *sc, int touch_count, int w, int h) { - struct input_dev *input_dev = hi->input; + size_t name_sz; + char *name; int ret; - ret = input_mt_init_slots(input_dev, touch_count, 0); + sc->touchpad = input_allocate_device(); + if (!sc->touchpad) + return -ENOMEM; + + input_set_drvdata(sc->touchpad, sc); + sc->touchpad->dev.parent = &sc->hdev->dev; + sc->touchpad->phys = sc->hdev->phys; + sc->touchpad->uniq = sc->hdev->uniq; + sc->touchpad->id.bustype = sc->hdev->bus; + sc->touchpad->id.vendor = sc->hdev->vendor; + sc->touchpad->id.product = sc->hdev->product; + sc->touchpad->id.version = sc->hdev->version; + + /* Append a suffix to the controller name as there are various + * DS4 compatible non-Sony devices with different names. + */ + name_sz = strlen(sc->hdev->name) + sizeof(DS4_TOUCHPAD_SUFFIX); + name = kzalloc(name_sz, GFP_KERNEL); + if (!name) { + ret = -ENOMEM; + goto err; + } + snprintf(name, name_sz, "%s" DS4_TOUCHPAD_SUFFIX, sc->hdev->name); + sc->touchpad->name = name; + + ret = input_mt_init_slots(sc->touchpad, touch_count, INPUT_MT_POINTER); if (ret < 0) - return ret; + goto err; + + /* We map the button underneath the touchpad to BTN_LEFT. */ + __set_bit(EV_KEY, sc->touchpad->evbit); + __set_bit(BTN_LEFT, sc->touchpad->keybit); + __set_bit(INPUT_PROP_BUTTONPAD, sc->touchpad->propbit); - input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, w, 0, 0); - input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, h, 0, 0); + input_set_abs_params(sc->touchpad, ABS_MT_POSITION_X, 0, w, 0, 0); + input_set_abs_params(sc->touchpad, ABS_MT_POSITION_Y, 0, h, 0, 0); + + ret = input_register_device(sc->touchpad); + if (ret < 0) + goto err; return 0; + +err: + kfree(sc->touchpad->name); + sc->touchpad->name = NULL; + + input_free_device(sc->touchpad); + sc->touchpad = NULL; + + return ret; } -static int sony_input_configured(struct hid_device *hdev, - struct hid_input *hidinput) +static void sony_unregister_touchpad(struct sony_sc *sc) { - struct sony_sc *sc = hid_get_drvdata(hdev); + if (!sc->touchpad) + return; + + kfree(sc->touchpad->name); + sc->touchpad->name = NULL; + + input_unregister_device(sc->touchpad); + sc->touchpad = NULL; +} + +static int sony_register_sensors(struct sony_sc *sc) +{ + size_t name_sz; + char *name; int ret; + int range; - /* - * The Dualshock 4 touchpad supports 2 touches and has a - * resolution of 1920x942 (44.86 dots/mm). + sc->sensor_dev = input_allocate_device(); + if (!sc->sensor_dev) + return -ENOMEM; + + input_set_drvdata(sc->sensor_dev, sc); + sc->sensor_dev->dev.parent = &sc->hdev->dev; + sc->sensor_dev->phys = sc->hdev->phys; + sc->sensor_dev->uniq = sc->hdev->uniq; + sc->sensor_dev->id.bustype = sc->hdev->bus; + sc->sensor_dev->id.vendor = sc->hdev->vendor; + sc->sensor_dev->id.product = sc->hdev->product; + sc->sensor_dev->id.version = sc->hdev->version; + + /* Append a suffix to the controller name as there are various + * DS4 compatible non-Sony devices with different names. */ - if (sc->quirks & DUALSHOCK4_CONTROLLER) { - ret = sony_register_touchpad(hidinput, 2, 1920, 942); - if (ret) { - hid_err(sc->hdev, - "Unable to initialize multi-touch slots: %d\n", - ret); - return ret; - } + name_sz = strlen(sc->hdev->name) + sizeof(SENSOR_SUFFIX); + name = kzalloc(name_sz, GFP_KERNEL); + if (!name) { + ret = -ENOMEM; + goto err; } + snprintf(name, name_sz, "%s" SENSOR_SUFFIX, sc->hdev->name); + sc->sensor_dev->name = name; + + if (sc->quirks & SIXAXIS_CONTROLLER) { + /* For the DS3 we only support the accelerometer, which works + * quite well even without calibration. The device also has + * a 1-axis gyro, but it is very difficult to manage from within + * the driver even to get data, the sensor is inaccurate and + * the behavior is very different between hardware revisions. + */ + input_set_abs_params(sc->sensor_dev, ABS_X, -512, 511, 4, 0); + input_set_abs_params(sc->sensor_dev, ABS_Y, -512, 511, 4, 0); + input_set_abs_params(sc->sensor_dev, ABS_Z, -512, 511, 4, 0); + input_abs_set_res(sc->sensor_dev, ABS_X, SIXAXIS_ACC_RES_PER_G); + input_abs_set_res(sc->sensor_dev, ABS_Y, SIXAXIS_ACC_RES_PER_G); + input_abs_set_res(sc->sensor_dev, ABS_Z, SIXAXIS_ACC_RES_PER_G); + } else if (sc->quirks & DUALSHOCK4_CONTROLLER) { + range = DS4_ACC_RES_PER_G*4; + input_set_abs_params(sc->sensor_dev, ABS_X, -range, range, 16, 0); + input_set_abs_params(sc->sensor_dev, ABS_Y, -range, range, 16, 0); + input_set_abs_params(sc->sensor_dev, ABS_Z, -range, range, 16, 0); + input_abs_set_res(sc->sensor_dev, ABS_X, DS4_ACC_RES_PER_G); + input_abs_set_res(sc->sensor_dev, ABS_Y, DS4_ACC_RES_PER_G); + input_abs_set_res(sc->sensor_dev, ABS_Z, DS4_ACC_RES_PER_G); + + range = DS4_GYRO_RES_PER_DEG_S*2048; + input_set_abs_params(sc->sensor_dev, ABS_RX, -range, range, 16, 0); + input_set_abs_params(sc->sensor_dev, ABS_RY, -range, range, 16, 0); + input_set_abs_params(sc->sensor_dev, ABS_RZ, -range, range, 16, 0); + input_abs_set_res(sc->sensor_dev, ABS_RX, DS4_GYRO_RES_PER_DEG_S); + input_abs_set_res(sc->sensor_dev, ABS_RY, DS4_GYRO_RES_PER_DEG_S); + input_abs_set_res(sc->sensor_dev, ABS_RZ, DS4_GYRO_RES_PER_DEG_S); + + __set_bit(EV_MSC, sc->sensor_dev->evbit); + __set_bit(MSC_TIMESTAMP, sc->sensor_dev->mscbit); + } + + __set_bit(INPUT_PROP_ACCELEROMETER, sc->sensor_dev->propbit); + + ret = input_register_device(sc->sensor_dev); + if (ret < 0) + goto err; return 0; + +err: + kfree(sc->sensor_dev->name); + sc->sensor_dev->name = NULL; + + input_free_device(sc->sensor_dev); + sc->sensor_dev = NULL; + + return ret; } +static void sony_unregister_sensors(struct sony_sc *sc) +{ + if (!sc->sensor_dev) + return; + + kfree(sc->sensor_dev->name); + sc->sensor_dev->name = NULL; + + input_unregister_device(sc->sensor_dev); + sc->sensor_dev = NULL; +} + + /* * Sending HID_REQ_GET_REPORT changes the operation mode of the ps3 controller * to "operational". Without this, the ps3 controller will not report any @@ -1392,7 +1413,7 @@ static int sixaxis_set_operational_usb(struct hid_device *hdev) { const int buf_size = max(SIXAXIS_REPORT_0xF2_SIZE, SIXAXIS_REPORT_0xF5_SIZE); - __u8 *buf; + u8 *buf; int ret; buf = kmalloc(buf_size, GFP_KERNEL); @@ -1431,8 +1452,8 @@ out: static int sixaxis_set_operational_bt(struct hid_device *hdev) { - static const __u8 report[] = { 0xf4, 0x42, 0x03, 0x00, 0x00 }; - __u8 *buf; + static const u8 report[] = { 0xf4, 0x42, 0x03, 0x00, 0x00 }; + u8 *buf; int ret; buf = kmemdup(report, sizeof(report), GFP_KERNEL); @@ -1448,29 +1469,179 @@ static int sixaxis_set_operational_bt(struct hid_device *hdev) } /* - * Requesting feature report 0x02 in Bluetooth mode changes the state of the - * controller so that it sends full input reports of type 0x11. + * Request DS4 calibration data for the motion sensors. + * For Bluetooth this also affects the operating mode (see below). */ -static int dualshock4_set_operational_bt(struct hid_device *hdev) +static int dualshock4_get_calibration_data(struct sony_sc *sc) { - __u8 *buf; + u8 *buf; int ret; + short gyro_pitch_bias, gyro_pitch_plus, gyro_pitch_minus; + short gyro_yaw_bias, gyro_yaw_plus, gyro_yaw_minus; + short gyro_roll_bias, gyro_roll_plus, gyro_roll_minus; + short gyro_speed_plus, gyro_speed_minus; + short acc_x_plus, acc_x_minus; + short acc_y_plus, acc_y_minus; + short acc_z_plus, acc_z_minus; + int speed_2x; + int range_2g; + + /* For Bluetooth we use a different request, which supports CRC. + * Note: in Bluetooth mode feature report 0x02 also changes the state + * of the controller, so that it sends input reports of type 0x11. + */ + if (sc->quirks & (DUALSHOCK4_CONTROLLER_USB | DUALSHOCK4_DONGLE)) { + buf = kmalloc(DS4_FEATURE_REPORT_0x02_SIZE, GFP_KERNEL); + if (!buf) + return -ENOMEM; - buf = kmalloc(DS4_REPORT_0x02_SIZE, GFP_KERNEL); - if (!buf) - return -ENOMEM; + ret = hid_hw_raw_request(sc->hdev, 0x02, buf, + DS4_FEATURE_REPORT_0x02_SIZE, + HID_FEATURE_REPORT, + HID_REQ_GET_REPORT); + if (ret < 0) + goto err_stop; + } else { + u8 bthdr = 0xA3; + u32 crc; + u32 report_crc; + int retries; - ret = hid_hw_raw_request(hdev, 0x02, buf, DS4_REPORT_0x02_SIZE, - HID_FEATURE_REPORT, HID_REQ_GET_REPORT); + buf = kmalloc(DS4_FEATURE_REPORT_0x05_SIZE, GFP_KERNEL); + if (!buf) + return -ENOMEM; - kfree(buf); + for (retries = 0; retries < 3; retries++) { + ret = hid_hw_raw_request(sc->hdev, 0x05, buf, + DS4_FEATURE_REPORT_0x05_SIZE, + HID_FEATURE_REPORT, + HID_REQ_GET_REPORT); + if (ret < 0) + goto err_stop; + + /* CRC check */ + crc = crc32_le(0xFFFFFFFF, &bthdr, 1); + crc = ~crc32_le(crc, buf, DS4_FEATURE_REPORT_0x05_SIZE-4); + report_crc = get_unaligned_le32(&buf[DS4_FEATURE_REPORT_0x05_SIZE-4]); + if (crc != report_crc) { + hid_warn(sc->hdev, "DualShock 4 calibration report's CRC check failed, received crc 0x%0x != 0x%0x\n", + report_crc, crc); + if (retries < 2) { + hid_warn(sc->hdev, "Retrying DualShock 4 get calibration report request\n"); + continue; + } else { + ret = -EILSEQ; + goto err_stop; + } + } else { + break; + } + } + } + + gyro_pitch_bias = get_unaligned_le16(&buf[1]); + gyro_yaw_bias = get_unaligned_le16(&buf[3]); + gyro_roll_bias = get_unaligned_le16(&buf[5]); + if (sc->quirks & DUALSHOCK4_CONTROLLER_USB) { + gyro_pitch_plus = get_unaligned_le16(&buf[7]); + gyro_pitch_minus = get_unaligned_le16(&buf[9]); + gyro_yaw_plus = get_unaligned_le16(&buf[11]); + gyro_yaw_minus = get_unaligned_le16(&buf[13]); + gyro_roll_plus = get_unaligned_le16(&buf[15]); + gyro_roll_minus = get_unaligned_le16(&buf[17]); + } else { + /* BT + Dongle */ + gyro_pitch_plus = get_unaligned_le16(&buf[7]); + gyro_yaw_plus = get_unaligned_le16(&buf[9]); + gyro_roll_plus = get_unaligned_le16(&buf[11]); + gyro_pitch_minus = get_unaligned_le16(&buf[13]); + gyro_yaw_minus = get_unaligned_le16(&buf[15]); + gyro_roll_minus = get_unaligned_le16(&buf[17]); + } + gyro_speed_plus = get_unaligned_le16(&buf[19]); + gyro_speed_minus = get_unaligned_le16(&buf[21]); + acc_x_plus = get_unaligned_le16(&buf[23]); + acc_x_minus = get_unaligned_le16(&buf[25]); + acc_y_plus = get_unaligned_le16(&buf[27]); + acc_y_minus = get_unaligned_le16(&buf[29]); + acc_z_plus = get_unaligned_le16(&buf[31]); + acc_z_minus = get_unaligned_le16(&buf[33]); + + /* Set gyroscope calibration and normalization parameters. + * Data values will be normalized to 1/DS4_GYRO_RES_PER_DEG_S degree/s. + */ + speed_2x = (gyro_speed_plus + gyro_speed_minus); + sc->ds4_calib_data[0].abs_code = ABS_RX; + sc->ds4_calib_data[0].bias = gyro_pitch_bias; + sc->ds4_calib_data[0].sens_numer = speed_2x*DS4_GYRO_RES_PER_DEG_S; + sc->ds4_calib_data[0].sens_denom = gyro_pitch_plus - gyro_pitch_minus; + + sc->ds4_calib_data[1].abs_code = ABS_RY; + sc->ds4_calib_data[1].bias = gyro_yaw_bias; + sc->ds4_calib_data[1].sens_numer = speed_2x*DS4_GYRO_RES_PER_DEG_S; + sc->ds4_calib_data[1].sens_denom = gyro_yaw_plus - gyro_yaw_minus; + + sc->ds4_calib_data[2].abs_code = ABS_RZ; + sc->ds4_calib_data[2].bias = gyro_roll_bias; + sc->ds4_calib_data[2].sens_numer = speed_2x*DS4_GYRO_RES_PER_DEG_S; + sc->ds4_calib_data[2].sens_denom = gyro_roll_plus - gyro_roll_minus; + + /* Set accelerometer calibration and normalization parameters. + * Data values will be normalized to 1/DS4_ACC_RES_PER_G G. + */ + range_2g = acc_x_plus - acc_x_minus; + sc->ds4_calib_data[3].abs_code = ABS_X; + sc->ds4_calib_data[3].bias = acc_x_plus - range_2g / 2; + sc->ds4_calib_data[3].sens_numer = 2*DS4_ACC_RES_PER_G; + sc->ds4_calib_data[3].sens_denom = range_2g; + + range_2g = acc_y_plus - acc_y_minus; + sc->ds4_calib_data[4].abs_code = ABS_Y; + sc->ds4_calib_data[4].bias = acc_y_plus - range_2g / 2; + sc->ds4_calib_data[4].sens_numer = 2*DS4_ACC_RES_PER_G; + sc->ds4_calib_data[4].sens_denom = range_2g; + + range_2g = acc_z_plus - acc_z_minus; + sc->ds4_calib_data[5].abs_code = ABS_Z; + sc->ds4_calib_data[5].bias = acc_z_plus - range_2g / 2; + sc->ds4_calib_data[5].sens_numer = 2*DS4_ACC_RES_PER_G; + sc->ds4_calib_data[5].sens_denom = range_2g; +err_stop: + kfree(buf); return ret; } +static void dualshock4_calibration_work(struct work_struct *work) +{ + struct sony_sc *sc = container_of(work, struct sony_sc, hotplug_worker); + unsigned long flags; + enum ds4_dongle_state dongle_state; + int ret; + + ret = dualshock4_get_calibration_data(sc); + if (ret < 0) { + /* This call is very unlikely to fail for the dongle. When it + * fails we are probably in a very bad state, so mark the + * dongle as disabled. We will re-enable the dongle if a new + * DS4 hotplug is detect from sony_raw_event as any issues + * are likely resolved then (the dongle is quite stupid). + */ + hid_err(sc->hdev, "DualShock 4 USB dongle: calibration failed, disabling device\n"); + dongle_state = DONGLE_DISABLED; + } else { + hid_info(sc->hdev, "DualShock 4 USB dongle: calibration completed\n"); + dongle_state = DONGLE_CONNECTED; + } + + spin_lock_irqsave(&sc->lock, flags); + sc->ds4_dongle_state = dongle_state; + spin_unlock_irqrestore(&sc->lock, flags); +} + static void sixaxis_set_leds_from_id(struct sony_sc *sc) { - static const __u8 sixaxis_leds[10][4] = { + static const u8 sixaxis_leds[10][4] = { { 0x01, 0x00, 0x00, 0x00 }, { 0x00, 0x01, 0x00, 0x00 }, { 0x00, 0x00, 0x01, 0x00 }, @@ -1497,11 +1668,11 @@ static void sixaxis_set_leds_from_id(struct sony_sc *sc) static void dualshock4_set_leds_from_id(struct sony_sc *sc) { /* The first 4 color/index entries match what the PS4 assigns */ - static const __u8 color_code[7][3] = { - /* Blue */ { 0x00, 0x00, 0x01 }, - /* Red */ { 0x01, 0x00, 0x00 }, - /* Green */ { 0x00, 0x01, 0x00 }, - /* Pink */ { 0x02, 0x00, 0x01 }, + static const u8 color_code[7][3] = { + /* Blue */ { 0x00, 0x00, 0x40 }, + /* Red */ { 0x40, 0x00, 0x00 }, + /* Green */ { 0x00, 0x40, 0x00 }, + /* Pink */ { 0x20, 0x00, 0x20 }, /* Orange */ { 0x02, 0x01, 0x00 }, /* Teal */ { 0x00, 0x01, 0x01 }, /* White */ { 0x01, 0x01, 0x01 } @@ -1525,7 +1696,7 @@ static void buzz_set_leds(struct sony_sc *sc) &hdev->report_enum[HID_OUTPUT_REPORT].report_list; struct hid_report *report = list_entry(report_list->next, struct hid_report, list); - __s32 *value = report->field[0]->value; + s32 *value = report->field[0]->value; BUILD_BUG_ON(MAX_LEDS < 4); @@ -1542,7 +1713,7 @@ static void buzz_set_leds(struct sony_sc *sc) static void sony_set_leds(struct sony_sc *sc) { if (!(sc->quirks & BUZZ_CONTROLLER)) - schedule_work(&sc->state_worker); + sony_schedule_work(sc, SONY_WORKER_STATE); else buzz_set_leds(sc); } @@ -1619,7 +1790,7 @@ static int sony_led_blink_set(struct led_classdev *led, unsigned long *delay_on, struct hid_device *hdev = container_of(dev, struct hid_device, dev); struct sony_sc *drv_data = hid_get_drvdata(hdev); int n; - __u8 new_on, new_off; + u8 new_on, new_off; if (!drv_data) { hid_err(hdev, "No device data\n"); @@ -1653,7 +1824,7 @@ static int sony_led_blink_set(struct led_classdev *led, unsigned long *delay_on, new_off != drv_data->led_delay_off[n]) { drv_data->led_delay_on[n] = new_on; drv_data->led_delay_off[n] = new_off; - schedule_work(&drv_data->state_worker); + sony_schedule_work(drv_data, SONY_WORKER_STATE); } return 0; @@ -1690,8 +1861,8 @@ static int sony_leds_init(struct sony_sc *sc) const char *name_fmt; static const char * const ds4_name_str[] = { "red", "green", "blue", "global" }; - __u8 max_brightness[MAX_LEDS] = { [0 ... (MAX_LEDS - 1)] = 1 }; - __u8 use_hw_blink[MAX_LEDS] = { 0 }; + u8 max_brightness[MAX_LEDS] = { [0 ... (MAX_LEDS - 1)] = 1 }; + u8 use_hw_blink[MAX_LEDS] = { 0 }; BUG_ON(!(sc->quirks & SONY_LED_SUPPORT)); @@ -1719,7 +1890,7 @@ static int sony_leds_init(struct sony_sc *sc) name_len = 0; name_fmt = "%s:%s"; } else if (sc->quirks & NAVIGATION_CONTROLLER) { - static const __u8 navigation_leds[4] = {0x01, 0x00, 0x00, 0x00}; + static const u8 navigation_leds[4] = {0x01, 0x00, 0x00, 0x00}; memcpy(sc->led_state, navigation_leds, sizeof(navigation_leds)); sc->led_count = 1; @@ -1766,6 +1937,7 @@ static int sony_leds_init(struct sony_sc *sc) led->name = name; led->brightness = sc->led_state[n]; led->max_brightness = max_brightness[n]; + led->flags = LED_CORE_SUSPENDRESUME; led->brightness_get = sony_led_get_brightness; led->brightness_set = sony_led_set_brightness; @@ -1791,12 +1963,12 @@ error_leds: return ret; } -static void sixaxis_state_worker(struct work_struct *work) +static void sixaxis_send_output_report(struct sony_sc *sc) { static const union sixaxis_output_report_01 default_report = { .buf = { 0x01, - 0x00, 0xff, 0x00, 0xff, 0x00, + 0x01, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x27, 0x10, 0x00, 0x32, 0xff, 0x27, 0x10, 0x00, 0x32, @@ -1805,7 +1977,6 @@ static void sixaxis_state_worker(struct work_struct *work) 0x00, 0x00, 0x00, 0x00, 0x00 } }; - struct sony_sc *sc = container_of(work, struct sony_sc, state_worker); struct sixaxis_output_report *report = (struct sixaxis_output_report *)sc->output_report_dmabuf; int n; @@ -1843,28 +2014,36 @@ static void sixaxis_state_worker(struct work_struct *work) } } - hid_hw_raw_request(sc->hdev, report->report_id, (__u8 *)report, + hid_hw_raw_request(sc->hdev, report->report_id, (u8 *)report, sizeof(struct sixaxis_output_report), HID_OUTPUT_REPORT, HID_REQ_SET_REPORT); } -static void dualshock4_state_worker(struct work_struct *work) +static void dualshock4_send_output_report(struct sony_sc *sc) { - struct sony_sc *sc = container_of(work, struct sony_sc, state_worker); struct hid_device *hdev = sc->hdev; - __u8 *buf = sc->output_report_dmabuf; + u8 *buf = sc->output_report_dmabuf; int offset; - if (sc->quirks & DUALSHOCK4_CONTROLLER_USB) { - memset(buf, 0, DS4_REPORT_0x05_SIZE); + /* + * NOTE: The lower 6 bits of buf[1] field of the Bluetooth report + * control the interval at which Dualshock 4 reports data: + * 0x00 - 1ms + * 0x01 - 1ms + * 0x02 - 2ms + * 0x3E - 62ms + * 0x3F - disabled + */ + if (sc->quirks & (DUALSHOCK4_CONTROLLER_USB | DUALSHOCK4_DONGLE)) { + memset(buf, 0, DS4_OUTPUT_REPORT_0x05_SIZE); buf[0] = 0x05; - buf[1] = 0xFF; + buf[1] = 0x07; /* blink + LEDs + motor */ offset = 4; } else { - memset(buf, 0, DS4_REPORT_0x11_SIZE); + memset(buf, 0, DS4_OUTPUT_REPORT_0x11_SIZE); buf[0] = 0x11; - buf[1] = 0x80; - buf[3] = 0x0F; + buf[1] = 0xC0 /* HID + CRC */ | sc->ds4_bt_poll_interval; + buf[3] = 0x07; /* blink + LEDs + motor */ offset = 6; } @@ -1888,16 +2067,22 @@ static void dualshock4_state_worker(struct work_struct *work) buf[offset++] = sc->led_delay_on[3]; buf[offset++] = sc->led_delay_off[3]; - if (sc->quirks & DUALSHOCK4_CONTROLLER_USB) - hid_hw_output_report(hdev, buf, DS4_REPORT_0x05_SIZE); - else - hid_hw_raw_request(hdev, 0x11, buf, DS4_REPORT_0x11_SIZE, - HID_OUTPUT_REPORT, HID_REQ_SET_REPORT); + if (sc->quirks & (DUALSHOCK4_CONTROLLER_USB | DUALSHOCK4_DONGLE)) + hid_hw_output_report(hdev, buf, DS4_OUTPUT_REPORT_0x05_SIZE); + else { + /* CRC generation */ + u8 bthdr = 0xA2; + u32 crc; + + crc = crc32_le(0xFFFFFFFF, &bthdr, 1); + crc = ~crc32_le(crc, buf, DS4_OUTPUT_REPORT_0x11_SIZE-4); + put_unaligned_le32(crc, &buf[74]); + hid_hw_output_report(hdev, buf, DS4_OUTPUT_REPORT_0x11_SIZE); + } } -static void motion_state_worker(struct work_struct *work) +static void motion_send_output_report(struct sony_sc *sc) { - struct sony_sc *sc = container_of(work, struct sony_sc, state_worker); struct hid_device *hdev = sc->hdev; struct motion_output_report_02 *report = (struct motion_output_report_02 *)sc->output_report_dmabuf; @@ -1913,7 +2098,20 @@ static void motion_state_worker(struct work_struct *work) report->rumble = max(sc->right, sc->left); #endif - hid_hw_output_report(hdev, (__u8 *)report, MOTION_REPORT_0x02_SIZE); + hid_hw_output_report(hdev, (u8 *)report, MOTION_REPORT_0x02_SIZE); +} + +static inline void sony_send_output_report(struct sony_sc *sc) +{ + if (sc->send_output_report) + sc->send_output_report(sc); +} + +static void sony_state_worker(struct work_struct *work) +{ + struct sony_sc *sc = container_of(work, struct sony_sc, state_worker); + + sc->send_output_report(sc); } static int sony_allocate_output_report(struct sony_sc *sc) @@ -1924,10 +2122,10 @@ static int sony_allocate_output_report(struct sony_sc *sc) kmalloc(sizeof(union sixaxis_output_report_01), GFP_KERNEL); else if (sc->quirks & DUALSHOCK4_CONTROLLER_BT) - sc->output_report_dmabuf = kmalloc(DS4_REPORT_0x11_SIZE, + sc->output_report_dmabuf = kmalloc(DS4_OUTPUT_REPORT_0x11_SIZE, GFP_KERNEL); - else if (sc->quirks & DUALSHOCK4_CONTROLLER_USB) - sc->output_report_dmabuf = kmalloc(DS4_REPORT_0x05_SIZE, + else if (sc->quirks & (DUALSHOCK4_CONTROLLER_USB | DUALSHOCK4_DONGLE)) + sc->output_report_dmabuf = kmalloc(DS4_OUTPUT_REPORT_0x05_SIZE, GFP_KERNEL); else if (sc->quirks & MOTION_CONTROLLER) sc->output_report_dmabuf = kmalloc(MOTION_REPORT_0x02_SIZE, @@ -1954,15 +2152,21 @@ static int sony_play_effect(struct input_dev *dev, void *data, sc->left = effect->u.rumble.strong_magnitude / 256; sc->right = effect->u.rumble.weak_magnitude / 256; - schedule_work(&sc->state_worker); + sony_schedule_work(sc, SONY_WORKER_STATE); return 0; } static int sony_init_ff(struct sony_sc *sc) { - struct hid_input *hidinput = list_entry(sc->hdev->inputs.next, - struct hid_input, list); - struct input_dev *input_dev = hidinput->input; + struct hid_input *hidinput; + struct input_dev *input_dev; + + if (list_empty(&sc->hdev->inputs)) { + hid_err(sc->hdev, "no inputs found\n"); + return -ENODEV; + } + hidinput = list_entry(sc->hdev->inputs.next, struct hid_input, list); + input_dev = hidinput->input; input_set_capability(input_dev, EV_FF, FF_RUMBLE); return input_ff_create_memless(input_dev, NULL, sony_play_effect); @@ -2017,8 +2221,11 @@ static int sony_battery_get_property(struct power_supply *psy, return ret; } -static int sony_battery_probe(struct sony_sc *sc) +static int sony_battery_probe(struct sony_sc *sc, int append_dev_id) { + const char *battery_str_fmt = append_dev_id ? + "sony_controller_battery_%pMR_%i" : + "sony_controller_battery_%pMR"; struct power_supply_config psy_cfg = { .drv_data = sc, }; struct hid_device *hdev = sc->hdev; int ret; @@ -2034,9 +2241,8 @@ static int sony_battery_probe(struct sony_sc *sc) sc->battery_desc.get_property = sony_battery_get_property; sc->battery_desc.type = POWER_SUPPLY_TYPE_BATTERY; sc->battery_desc.use_for_apm = 0; - sc->battery_desc.name = kasprintf(GFP_KERNEL, - "sony_controller_battery_%pMR", - sc->mac_address); + sc->battery_desc.name = kasprintf(GFP_KERNEL, battery_str_fmt, + sc->mac_address, sc->device_id); if (!sc->battery_desc.name) return -ENOMEM; @@ -2072,7 +2278,21 @@ static void sony_battery_remove(struct sony_sc *sc) * it will show up as two devices. A global list of connected controllers and * their MAC addresses is maintained to ensure that a device is only connected * once. + * + * Some USB-only devices masquerade as Sixaxis controllers and all have the + * same dummy Bluetooth address, so a comparison of the connection type is + * required. Devices are only rejected in the case where two devices have + * matching Bluetooth addresses on different bus types. */ +static inline int sony_compare_connection_type(struct sony_sc *sc0, + struct sony_sc *sc1) +{ + const int sc0_not_bt = !(sc0->quirks & SONY_BT_DEVICE); + const int sc1_not_bt = !(sc1->quirks & SONY_BT_DEVICE); + + return sc0_not_bt == sc1_not_bt; +} + static int sony_check_add_dev_list(struct sony_sc *sc) { struct sony_sc *entry; @@ -2085,9 +2305,14 @@ static int sony_check_add_dev_list(struct sony_sc *sc) ret = memcmp(sc->mac_address, entry->mac_address, sizeof(sc->mac_address)); if (!ret) { - ret = -EEXIST; - hid_info(sc->hdev, "controller with MAC address %pMR already connected\n", + if (sony_compare_connection_type(sc, entry)) { + ret = 1; + } else { + ret = -EEXIST; + hid_info(sc->hdev, + "controller with MAC address %pMR already connected\n", sc->mac_address); + } goto unlock; } } @@ -2133,7 +2358,7 @@ static int sony_get_bt_devaddr(struct sony_sc *sc) static int sony_check_add(struct sony_sc *sc) { - __u8 *buf = NULL; + u8 *buf = NULL; int n, ret; if ((sc->quirks & DUALSHOCK4_CONTROLLER_BT) || @@ -2150,8 +2375,8 @@ static int sony_check_add(struct sony_sc *sc) hid_warn(sc->hdev, "UNIQ does not contain a MAC address; duplicate check skipped\n"); return 0; } - } else if (sc->quirks & DUALSHOCK4_CONTROLLER_USB) { - buf = kmalloc(DS4_REPORT_0x81_SIZE, GFP_KERNEL); + } else if (sc->quirks & (DUALSHOCK4_CONTROLLER_USB | DUALSHOCK4_DONGLE)) { + buf = kmalloc(DS4_FEATURE_REPORT_0x81_SIZE, GFP_KERNEL); if (!buf) return -ENOMEM; @@ -2161,16 +2386,22 @@ static int sony_check_add(struct sony_sc *sc) * offset 1. */ ret = hid_hw_raw_request(sc->hdev, 0x81, buf, - DS4_REPORT_0x81_SIZE, HID_FEATURE_REPORT, + DS4_FEATURE_REPORT_0x81_SIZE, HID_FEATURE_REPORT, HID_REQ_GET_REPORT); - if (ret != DS4_REPORT_0x81_SIZE) { + if (ret != DS4_FEATURE_REPORT_0x81_SIZE) { hid_err(sc->hdev, "failed to retrieve feature report 0x81 with the DualShock 4 MAC address\n"); ret = ret < 0 ? ret : -EINVAL; goto out_free; } memcpy(sc->mac_address, &buf[1], sizeof(sc->mac_address)); + + snprintf(sc->hdev->uniq, sizeof(sc->hdev->uniq), + "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", + sc->mac_address[5], sc->mac_address[4], + sc->mac_address[3], sc->mac_address[2], + sc->mac_address[1], sc->mac_address[0]); } else if ((sc->quirks & SIXAXIS_CONTROLLER_USB) || (sc->quirks & NAVIGATION_CONTROLLER_USB)) { buf = kmalloc(SIXAXIS_REPORT_0xF2_SIZE, GFP_KERNEL); @@ -2198,6 +2429,12 @@ static int sony_check_add(struct sony_sc *sc) */ for (n = 0; n < 6; n++) sc->mac_address[5-n] = buf[4+n]; + + snprintf(sc->hdev->uniq, sizeof(sc->hdev->uniq), + "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", + sc->mac_address[5], sc->mac_address[4], + sc->mac_address[3], sc->mac_address[2], + sc->mac_address[1], sc->mac_address[0]); } else { return 0; } @@ -2243,56 +2480,37 @@ static void sony_release_device_id(struct sony_sc *sc) } } -static inline void sony_init_work(struct sony_sc *sc, - void (*worker)(struct work_struct *)) +static inline void sony_init_output_report(struct sony_sc *sc, + void (*send_output_report)(struct sony_sc *)) { - if (!sc->worker_initialized) - INIT_WORK(&sc->state_worker, worker); + sc->send_output_report = send_output_report; + + if (!sc->state_worker_initialized) + INIT_WORK(&sc->state_worker, sony_state_worker); - sc->worker_initialized = 1; + sc->state_worker_initialized = 1; } static inline void sony_cancel_work_sync(struct sony_sc *sc) { - if (sc->worker_initialized) + unsigned long flags; + + if (sc->hotplug_worker_initialized) + cancel_work_sync(&sc->hotplug_worker); + if (sc->state_worker_initialized) { + spin_lock_irqsave(&sc->lock, flags); + sc->state_worker_initialized = 0; + spin_unlock_irqrestore(&sc->lock, flags); cancel_work_sync(&sc->state_worker); + } } -static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) +static int sony_input_configured(struct hid_device *hdev, + struct hid_input *hidinput) { + struct sony_sc *sc = hid_get_drvdata(hdev); + int append_dev_id; int ret; - unsigned long quirks = id->driver_data; - struct sony_sc *sc; - unsigned int connect_mask = HID_CONNECT_DEFAULT; - - sc = devm_kzalloc(&hdev->dev, sizeof(*sc), GFP_KERNEL); - if (sc == NULL) { - hid_err(hdev, "can't alloc sony descriptor\n"); - return -ENOMEM; - } - - spin_lock_init(&sc->lock); - - sc->quirks = quirks; - hid_set_drvdata(hdev, sc); - sc->hdev = hdev; - - ret = hid_parse(hdev); - if (ret) { - hid_err(hdev, "parse failed\n"); - return ret; - } - - if (sc->quirks & VAIO_RDESC_CONSTANT) - connect_mask |= HID_CONNECT_HIDDEV_FORCE; - else if (sc->quirks & SIXAXIS_CONTROLLER) - connect_mask |= HID_CONNECT_HIDDEV_FORCE; - - ret = hid_hw_start(hdev, connect_mask); - if (ret) { - hid_err(hdev, "hw start failed\n"); - return ret; - } ret = sony_set_device_id(sc); if (ret < 0) { @@ -2300,14 +2518,17 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) goto err_stop; } + ret = append_dev_id = sony_check_add(sc); + if (ret < 0) + goto err_stop; + ret = sony_allocate_output_report(sc); if (ret < 0) { hid_err(hdev, "failed to allocate the output report buffer\n"); goto err_stop; } - if ((sc->quirks & SIXAXIS_CONTROLLER_USB) || - (sc->quirks & NAVIGATION_CONTROLLER_USB)) { + if (sc->quirks & NAVIGATION_CONTROLLER_USB) { /* * The Sony Sixaxis does not handle HID Output Reports on the * Interrupt EP like it could, so we need to force HID Output @@ -2317,48 +2538,132 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) * the Sixaxis does not want the report_id as part of the data * packet, so we have to discard buf[0] when sending the actual * control message, even for numbered reports, humpf! + * + * Additionally, the Sixaxis on USB isn't properly initialized + * until the PS logo button is pressed and as such won't retain + * any state set by an output report, so the initial + * configuration report is deferred until the first input + * report arrives. */ hdev->quirks |= HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP; hdev->quirks |= HID_QUIRK_SKIP_OUTPUT_REPORT_ID; + sc->defer_initialization = 1; + ret = sixaxis_set_operational_usb(hdev); - sony_init_work(sc, sixaxis_state_worker); - } else if ((sc->quirks & SIXAXIS_CONTROLLER_BT) || - (sc->quirks & NAVIGATION_CONTROLLER_BT)) { + if (ret < 0) { + hid_err(hdev, "Failed to set controller into operational mode\n"); + goto err_stop; + } + + sony_init_output_report(sc, sixaxis_send_output_report); + } else if (sc->quirks & NAVIGATION_CONTROLLER_BT) { + /* + * The Navigation controller wants output reports sent on the ctrl + * endpoint when connected via Bluetooth. + */ + hdev->quirks |= HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP; + + ret = sixaxis_set_operational_bt(hdev); + if (ret < 0) { + hid_err(hdev, "Failed to set controller into operational mode\n"); + goto err_stop; + } + + sony_init_output_report(sc, sixaxis_send_output_report); + } else if (sc->quirks & SIXAXIS_CONTROLLER_USB) { + /* + * The Sony Sixaxis does not handle HID Output Reports on the + * Interrupt EP and the device only becomes active when the + * PS button is pressed. See comment for Navigation controller + * above for more details. + */ + hdev->quirks |= HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP; + hdev->quirks |= HID_QUIRK_SKIP_OUTPUT_REPORT_ID; + sc->defer_initialization = 1; + + ret = sixaxis_set_operational_usb(hdev); + if (ret < 0) { + hid_err(hdev, "Failed to set controller into operational mode\n"); + goto err_stop; + } + + ret = sony_register_sensors(sc); + if (ret) { + hid_err(sc->hdev, + "Unable to initialize motion sensors: %d\n", ret); + goto err_stop; + } + + sony_init_output_report(sc, sixaxis_send_output_report); + } else if (sc->quirks & SIXAXIS_CONTROLLER_BT) { /* * The Sixaxis wants output reports sent on the ctrl endpoint * when connected via Bluetooth. */ hdev->quirks |= HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP; + ret = sixaxis_set_operational_bt(hdev); - sony_init_work(sc, sixaxis_state_worker); + if (ret < 0) { + hid_err(hdev, "Failed to set controller into operational mode\n"); + goto err_stop; + } + + ret = sony_register_sensors(sc); + if (ret) { + hid_err(sc->hdev, + "Unable to initialize motion sensors: %d\n", ret); + goto err_stop; + } + + sony_init_output_report(sc, sixaxis_send_output_report); } else if (sc->quirks & DUALSHOCK4_CONTROLLER) { + ret = dualshock4_get_calibration_data(sc); + if (ret < 0) { + hid_err(hdev, "Failed to get calibration data from Dualshock 4\n"); + goto err_stop; + } + + /* + * The Dualshock 4 touchpad supports 2 touches and has a + * resolution of 1920x942 (44.86 dots/mm). + */ + ret = sony_register_touchpad(sc, 2, 1920, 942); + if (ret) { + hid_err(sc->hdev, + "Unable to initialize multi-touch slots: %d\n", + ret); + goto err_stop; + } + + ret = sony_register_sensors(sc); + if (ret) { + hid_err(sc->hdev, + "Unable to initialize motion sensors: %d\n", ret); + goto err_stop; + } + if (sc->quirks & DUALSHOCK4_CONTROLLER_BT) { - /* - * The DualShock 4 wants output reports sent on the ctrl - * endpoint when connected via Bluetooth. - */ - hdev->quirks |= HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP; - ret = dualshock4_set_operational_bt(hdev); - if (ret < 0) { - hid_err(hdev, "failed to set the Dualshock 4 operational mode\n"); - goto err_stop; - } + sc->ds4_bt_poll_interval = DS4_BT_DEFAULT_POLL_INTERVAL_MS; + ret = device_create_file(&sc->hdev->dev, &dev_attr_bt_poll_interval); + if (ret) + hid_warn(sc->hdev, + "can't create sysfs bt_poll_interval attribute err: %d\n", + ret); } - sony_init_work(sc, dualshock4_state_worker); + if (sc->quirks & DUALSHOCK4_DONGLE) { + INIT_WORK(&sc->hotplug_worker, dualshock4_calibration_work); + sc->hotplug_worker_initialized = 1; + sc->ds4_dongle_state = DONGLE_DISCONNECTED; + } + + sony_init_output_report(sc, dualshock4_send_output_report); } else if (sc->quirks & MOTION_CONTROLLER) { - sony_init_work(sc, motion_state_worker); + sony_init_output_report(sc, motion_send_output_report); } else { ret = 0; } - if (ret < 0) - goto err_stop; - - ret = sony_check_add(sc); - if (ret < 0) - goto err_stop; - if (sc->quirks & SONY_LED_SUPPORT) { ret = sony_leds_init(sc); if (ret < 0) @@ -2366,7 +2671,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) } if (sc->quirks & SONY_BATTERY_SUPPORT) { - ret = sony_battery_probe(sc); + ret = sony_battery_probe(sc, append_dev_id); if (ret < 0) goto err_stop; @@ -2388,15 +2693,86 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) err_close: hid_hw_close(hdev); err_stop: + /* Piggy back on the default ds4_bt_ poll_interval to determine + * if we need to remove the file as we don't know for sure if we + * executed that logic. + */ + if (sc->ds4_bt_poll_interval) + device_remove_file(&sc->hdev->dev, &dev_attr_bt_poll_interval); if (sc->quirks & SONY_LED_SUPPORT) sony_leds_remove(sc); if (sc->quirks & SONY_BATTERY_SUPPORT) sony_battery_remove(sc); + if (sc->touchpad) + sony_unregister_touchpad(sc); + if (sc->sensor_dev) + sony_unregister_sensors(sc); sony_cancel_work_sync(sc); kfree(sc->output_report_dmabuf); sony_remove_dev_list(sc); sony_release_device_id(sc); - hid_hw_stop(hdev); + return ret; +} + +static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) +{ + int ret; + unsigned long quirks = id->driver_data; + struct sony_sc *sc; + unsigned int connect_mask = HID_CONNECT_DEFAULT; + + sc = devm_kzalloc(&hdev->dev, sizeof(*sc), GFP_KERNEL); + if (sc == NULL) { + hid_err(hdev, "can't alloc sony descriptor\n"); + return -ENOMEM; + } + + spin_lock_init(&sc->lock); + + sc->quirks = quirks; + hid_set_drvdata(hdev, sc); + sc->hdev = hdev; + + ret = hid_parse(hdev); + if (ret) { + hid_err(hdev, "parse failed\n"); + return ret; + } + + if (sc->quirks & VAIO_RDESC_CONSTANT) + connect_mask |= HID_CONNECT_HIDDEV_FORCE; + else if (sc->quirks & SIXAXIS_CONTROLLER) + connect_mask |= HID_CONNECT_HIDDEV_FORCE; + + /* Patch the hw version on DS3/4 compatible devices, so applications can + * distinguish between the default HID mappings and the mappings defined + * by the Linux game controller spec. This is important for the SDL2 + * library, which has a game controller database, which uses device ids + * in combination with version as a key. + */ + if (sc->quirks & (SIXAXIS_CONTROLLER | DUALSHOCK4_CONTROLLER)) + hdev->version |= 0x8000; + + ret = hid_hw_start(hdev, connect_mask); + if (ret) { + hid_err(hdev, "hw start failed\n"); + return ret; + } + + /* sony_input_configured can fail, but this doesn't result + * in hid_hw_start failures (intended). Check whether + * the HID layer claimed the device else fail. + * We don't know the actual reason for the failure, most + * likely it is due to EEXIST in case of double connection + * of USB and Bluetooth, but could have been due to ENOMEM + * or other reasons as well. + */ + if (!(hdev->claimed & HID_CLAIMED_INPUT)) { + hid_err(hdev, "failed to claim input\n"); + hid_hw_stop(hdev); + return -ENODEV; + } + return ret; } @@ -2404,13 +2780,22 @@ static void sony_remove(struct hid_device *hdev) { struct sony_sc *sc = hid_get_drvdata(hdev); + hid_hw_close(hdev); + if (sc->quirks & SONY_LED_SUPPORT) sony_leds_remove(sc); - if (sc->quirks & SONY_BATTERY_SUPPORT) { - hid_hw_close(hdev); + if (sc->quirks & SONY_BATTERY_SUPPORT) sony_battery_remove(sc); - } + + if (sc->touchpad) + sony_unregister_touchpad(sc); + + if (sc->sensor_dev) + sony_unregister_sensors(sc); + + if (sc->quirks & DUALSHOCK4_CONTROLLER_BT) + device_remove_file(&sc->hdev->dev, &dev_attr_bt_poll_interval); sony_cancel_work_sync(sc); @@ -2423,6 +2808,43 @@ static void sony_remove(struct hid_device *hdev) hid_hw_stop(hdev); } +#ifdef CONFIG_PM + +static int sony_suspend(struct hid_device *hdev, pm_message_t message) +{ +#ifdef CONFIG_SONY_FF + + /* On suspend stop any running force-feedback events */ + if (SONY_FF_SUPPORT) { + struct sony_sc *sc = hid_get_drvdata(hdev); + + sc->left = sc->right = 0; + sony_send_output_report(sc); + } + +#endif + return 0; +} + +static int sony_resume(struct hid_device *hdev) +{ + struct sony_sc *sc = hid_get_drvdata(hdev); + + /* + * The Sixaxis and navigation controllers on USB need to be + * reinitialized on resume or they won't behave properly. + */ + if ((sc->quirks & SIXAXIS_CONTROLLER_USB) || + (sc->quirks & NAVIGATION_CONTROLLER_USB)) { + sixaxis_set_operational_usb(sc->hdev); + sc->defer_initialization = 1; + } + + return 0; +} + +#endif + static const struct hid_device_id sony_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER), .driver_data = SIXAXIS_CONTROLLER_USB }, @@ -2440,8 +2862,10 @@ static const struct hid_device_id sony_devices[] = { .driver_data = VAIO_RDESC_CONSTANT }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGP_MOUSE), .driver_data = VAIO_RDESC_CONSTANT }, - /* Wired Buzz Controller. Reported as Sony Hub from its USB ID and as - * Logitech joystick from the device descriptor. */ + /* + * Wired Buzz Controller. Reported as Sony Hub from its USB ID and as + * Logitech joystick from the device descriptor. + */ { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_BUZZ_CONTROLLER), .driver_data = BUZZ_CONTROLLER }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_WIRELESS_BUZZ_CONTROLLER), @@ -2465,7 +2889,7 @@ static const struct hid_device_id sony_devices[] = { { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER_2), .driver_data = DUALSHOCK4_CONTROLLER_BT }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER_DONGLE), - .driver_data = DUALSHOCK4_CONTROLLER_USB }, + .driver_data = DUALSHOCK4_DONGLE }, { } }; MODULE_DEVICE_TABLE(hid, sony_devices); @@ -2478,7 +2902,13 @@ static struct hid_driver sony_driver = { .probe = sony_probe, .remove = sony_remove, .report_fixup = sony_report_fixup, - .raw_event = sony_raw_event + .raw_event = sony_raw_event, + +#ifdef CONFIG_PM + .suspend = sony_suspend, + .resume = sony_resume, + .reset_resume = sony_resume, +#endif }; static int __init sony_init(void) diff --git a/drivers/hid/hid-steam.c b/drivers/hid/hid-steam.c new file mode 100644 index 000000000000..44e1eefc5b24 --- /dev/null +++ b/drivers/hid/hid-steam.c @@ -0,0 +1,1141 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * HID driver for Valve Steam Controller + * + * Copyright (c) 2018 Rodrigo Rivas Costa <rodrigorivascosta@gmail.com> + * + * Supports both the wired and wireless interfaces. + * + * This controller has a builtin emulation of mouse and keyboard: the right pad + * can be used as a mouse, the shoulder buttons are mouse buttons, A and B + * buttons are ENTER and ESCAPE, and so on. This is implemented as additional + * HID interfaces. + * + * This is known as the "lizard mode", because apparently lizards like to use + * the computer from the coach, without a proper mouse and keyboard. + * + * This driver will disable the lizard mode when the input device is opened + * and re-enable it when the input device is closed, so as not to break user + * mode behaviour. The lizard_mode parameter can be used to change that. + * + * There are a few user space applications (notably Steam Client) that use + * the hidraw interface directly to create input devices (XTest, uinput...). + * In order to avoid breaking them this driver creates a layered hidraw device, + * so it can detect when the client is running and then: + * - it will not send any command to the controller. + * - this input device will be removed, to avoid double input of the same + * user action. + * When the client is closed, this input device will be created again. + * + * For additional functions, such as changing the right-pad margin or switching + * the led, you can use the user-space tool at: + * + * https://github.com/rodrigorc/steamctrl + */ + +#include <linux/device.h> +#include <linux/input.h> +#include <linux/hid.h> +#include <linux/module.h> +#include <linux/workqueue.h> +#include <linux/mutex.h> +#include <linux/rcupdate.h> +#include <linux/delay.h> +#include <linux/power_supply.h> +#include "hid-ids.h" + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Rodrigo Rivas Costa <rodrigorivascosta@gmail.com>"); + +static bool lizard_mode = true; + +static DEFINE_MUTEX(steam_devices_lock); +static LIST_HEAD(steam_devices); + +#define STEAM_QUIRK_WIRELESS BIT(0) + +/* Touch pads are 40 mm in diameter and 65535 units */ +#define STEAM_PAD_RESOLUTION 1638 +/* Trigger runs are about 5 mm and 256 units */ +#define STEAM_TRIGGER_RESOLUTION 51 +/* Joystick runs are about 5 mm and 256 units */ +#define STEAM_JOYSTICK_RESOLUTION 51 + +#define STEAM_PAD_FUZZ 256 + +/* + * Commands that can be sent in a feature report. + * Thanks to Valve for some valuable hints. + */ +#define STEAM_CMD_SET_MAPPINGS 0x80 +#define STEAM_CMD_CLEAR_MAPPINGS 0x81 +#define STEAM_CMD_GET_MAPPINGS 0x82 +#define STEAM_CMD_GET_ATTRIB 0x83 +#define STEAM_CMD_GET_ATTRIB_LABEL 0x84 +#define STEAM_CMD_DEFAULT_MAPPINGS 0x85 +#define STEAM_CMD_FACTORY_RESET 0x86 +#define STEAM_CMD_WRITE_REGISTER 0x87 +#define STEAM_CMD_CLEAR_REGISTER 0x88 +#define STEAM_CMD_READ_REGISTER 0x89 +#define STEAM_CMD_GET_REGISTER_LABEL 0x8a +#define STEAM_CMD_GET_REGISTER_MAX 0x8b +#define STEAM_CMD_GET_REGISTER_DEFAULT 0x8c +#define STEAM_CMD_SET_MODE 0x8d +#define STEAM_CMD_DEFAULT_MOUSE 0x8e +#define STEAM_CMD_FORCEFEEDBAK 0x8f +#define STEAM_CMD_REQUEST_COMM_STATUS 0xb4 +#define STEAM_CMD_GET_SERIAL 0xae + +/* Some useful register ids */ +#define STEAM_REG_LPAD_MODE 0x07 +#define STEAM_REG_RPAD_MODE 0x08 +#define STEAM_REG_RPAD_MARGIN 0x18 +#define STEAM_REG_LED 0x2d +#define STEAM_REG_GYRO_MODE 0x30 + +/* Raw event identifiers */ +#define STEAM_EV_INPUT_DATA 0x01 +#define STEAM_EV_CONNECT 0x03 +#define STEAM_EV_BATTERY 0x04 + +/* Values for GYRO_MODE (bitmask) */ +#define STEAM_GYRO_MODE_OFF 0x0000 +#define STEAM_GYRO_MODE_STEERING 0x0001 +#define STEAM_GYRO_MODE_TILT 0x0002 +#define STEAM_GYRO_MODE_SEND_ORIENTATION 0x0004 +#define STEAM_GYRO_MODE_SEND_RAW_ACCEL 0x0008 +#define STEAM_GYRO_MODE_SEND_RAW_GYRO 0x0010 + +/* Other random constants */ +#define STEAM_SERIAL_LEN 10 + +struct steam_device { + struct list_head list; + spinlock_t lock; + struct hid_device *hdev, *client_hdev; + struct mutex mutex; + bool client_opened; + struct input_dev __rcu *input; + unsigned long quirks; + struct work_struct work_connect; + bool connected; + char serial_no[STEAM_SERIAL_LEN + 1]; + struct power_supply_desc battery_desc; + struct power_supply __rcu *battery; + u8 battery_charge; + u16 voltage; +}; + +static int steam_recv_report(struct steam_device *steam, + u8 *data, int size) +{ + struct hid_report *r; + u8 *buf; + int ret; + + r = steam->hdev->report_enum[HID_FEATURE_REPORT].report_id_hash[0]; + if (hid_report_len(r) < 64) + return -EINVAL; + + buf = hid_alloc_report_buf(r, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + /* + * The report ID is always 0, so strip the first byte from the output. + * hid_report_len() is not counting the report ID, so +1 to the length + * or else we get a EOVERFLOW. We are safe from a buffer overflow + * because hid_alloc_report_buf() allocates +7 bytes. + */ + ret = hid_hw_raw_request(steam->hdev, 0x00, + buf, hid_report_len(r) + 1, + HID_FEATURE_REPORT, HID_REQ_GET_REPORT); + if (ret > 0) + memcpy(data, buf + 1, min(size, ret - 1)); + kfree(buf); + return ret; +} + +static int steam_send_report(struct steam_device *steam, + u8 *cmd, int size) +{ + struct hid_report *r; + u8 *buf; + unsigned int retries = 50; + int ret; + + r = steam->hdev->report_enum[HID_FEATURE_REPORT].report_id_hash[0]; + if (hid_report_len(r) < 64) + return -EINVAL; + + buf = hid_alloc_report_buf(r, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + /* The report ID is always 0 */ + memcpy(buf + 1, cmd, size); + + /* + * Sometimes the wireless controller fails with EPIPE + * when sending a feature report. + * Doing a HID_REQ_GET_REPORT and waiting for a while + * seems to fix that. + */ + do { + ret = hid_hw_raw_request(steam->hdev, 0, + buf, size + 1, + HID_FEATURE_REPORT, HID_REQ_SET_REPORT); + if (ret != -EPIPE) + break; + msleep(20); + } while (--retries); + + kfree(buf); + if (ret < 0) + hid_err(steam->hdev, "%s: error %d (%*ph)\n", __func__, + ret, size, cmd); + return ret; +} + +static inline int steam_send_report_byte(struct steam_device *steam, u8 cmd) +{ + return steam_send_report(steam, &cmd, 1); +} + +static int steam_write_registers(struct steam_device *steam, + /* u8 reg, u16 val */...) +{ + /* Send: 0x87 len (reg valLo valHi)* */ + u8 reg; + u16 val; + u8 cmd[64] = {STEAM_CMD_WRITE_REGISTER, 0x00}; + va_list args; + + va_start(args, steam); + for (;;) { + reg = va_arg(args, int); + if (reg == 0) + break; + val = va_arg(args, int); + cmd[cmd[1] + 2] = reg; + cmd[cmd[1] + 3] = val & 0xff; + cmd[cmd[1] + 4] = val >> 8; + cmd[1] += 3; + } + va_end(args); + + return steam_send_report(steam, cmd, 2 + cmd[1]); +} + +static int steam_get_serial(struct steam_device *steam) +{ + /* + * Send: 0xae 0x15 0x01 + * Recv: 0xae 0x15 0x01 serialnumber (10 chars) + */ + int ret; + u8 cmd[] = {STEAM_CMD_GET_SERIAL, 0x15, 0x01}; + u8 reply[3 + STEAM_SERIAL_LEN + 1]; + + ret = steam_send_report(steam, cmd, sizeof(cmd)); + if (ret < 0) + return ret; + ret = steam_recv_report(steam, reply, sizeof(reply)); + if (ret < 0) + return ret; + if (reply[0] != 0xae || reply[1] != 0x15 || reply[2] != 0x01) + return -EIO; + reply[3 + STEAM_SERIAL_LEN] = 0; + strlcpy(steam->serial_no, reply + 3, sizeof(steam->serial_no)); + return 0; +} + +/* + * This command requests the wireless adaptor to post an event + * with the connection status. Useful if this driver is loaded when + * the controller is already connected. + */ +static inline int steam_request_conn_status(struct steam_device *steam) +{ + return steam_send_report_byte(steam, STEAM_CMD_REQUEST_COMM_STATUS); +} + +static void steam_set_lizard_mode(struct steam_device *steam, bool enable) +{ + if (enable) { + /* enable esc, enter, cursors */ + steam_send_report_byte(steam, STEAM_CMD_DEFAULT_MAPPINGS); + /* enable mouse */ + steam_send_report_byte(steam, STEAM_CMD_DEFAULT_MOUSE); + steam_write_registers(steam, + STEAM_REG_RPAD_MARGIN, 0x01, /* enable margin */ + 0); + } else { + /* disable esc, enter, cursor */ + steam_send_report_byte(steam, STEAM_CMD_CLEAR_MAPPINGS); + steam_write_registers(steam, + STEAM_REG_RPAD_MODE, 0x07, /* disable mouse */ + STEAM_REG_RPAD_MARGIN, 0x00, /* disable margin */ + 0); + } +} + +static int steam_input_open(struct input_dev *dev) +{ + struct steam_device *steam = input_get_drvdata(dev); + + mutex_lock(&steam->mutex); + if (!steam->client_opened && lizard_mode) + steam_set_lizard_mode(steam, false); + mutex_unlock(&steam->mutex); + return 0; +} + +static void steam_input_close(struct input_dev *dev) +{ + struct steam_device *steam = input_get_drvdata(dev); + + mutex_lock(&steam->mutex); + if (!steam->client_opened && lizard_mode) + steam_set_lizard_mode(steam, true); + mutex_unlock(&steam->mutex); +} + +static enum power_supply_property steam_battery_props[] = { + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_SCOPE, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_CAPACITY, +}; + +static int steam_battery_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct steam_device *steam = power_supply_get_drvdata(psy); + unsigned long flags; + s16 volts; + u8 batt; + int ret = 0; + + spin_lock_irqsave(&steam->lock, flags); + volts = steam->voltage; + batt = steam->battery_charge; + spin_unlock_irqrestore(&steam->lock, flags); + + switch (psp) { + case POWER_SUPPLY_PROP_PRESENT: + val->intval = 1; + break; + case POWER_SUPPLY_PROP_SCOPE: + val->intval = POWER_SUPPLY_SCOPE_DEVICE; + break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + val->intval = volts * 1000; /* mV -> uV */ + break; + case POWER_SUPPLY_PROP_CAPACITY: + val->intval = batt; + break; + default: + ret = -EINVAL; + break; + } + return ret; +} + +static int steam_battery_register(struct steam_device *steam) +{ + struct power_supply *battery; + struct power_supply_config battery_cfg = { .drv_data = steam, }; + unsigned long flags; + int ret; + + steam->battery_desc.type = POWER_SUPPLY_TYPE_BATTERY; + steam->battery_desc.properties = steam_battery_props; + steam->battery_desc.num_properties = ARRAY_SIZE(steam_battery_props); + steam->battery_desc.get_property = steam_battery_get_property; + steam->battery_desc.name = devm_kasprintf(&steam->hdev->dev, + GFP_KERNEL, "steam-controller-%s-battery", + steam->serial_no); + if (!steam->battery_desc.name) + return -ENOMEM; + + /* avoid the warning of 0% battery while waiting for the first info */ + spin_lock_irqsave(&steam->lock, flags); + steam->voltage = 3000; + steam->battery_charge = 100; + spin_unlock_irqrestore(&steam->lock, flags); + + battery = power_supply_register(&steam->hdev->dev, + &steam->battery_desc, &battery_cfg); + if (IS_ERR(battery)) { + ret = PTR_ERR(battery); + hid_err(steam->hdev, + "%s:power_supply_register failed with error %d\n", + __func__, ret); + return ret; + } + rcu_assign_pointer(steam->battery, battery); + power_supply_powers(battery, &steam->hdev->dev); + return 0; +} + +static int steam_input_register(struct steam_device *steam) +{ + struct hid_device *hdev = steam->hdev; + struct input_dev *input; + int ret; + + rcu_read_lock(); + input = rcu_dereference(steam->input); + rcu_read_unlock(); + if (input) { + dbg_hid("%s: already connected\n", __func__); + return 0; + } + + input = input_allocate_device(); + if (!input) + return -ENOMEM; + + input_set_drvdata(input, steam); + input->dev.parent = &hdev->dev; + input->open = steam_input_open; + input->close = steam_input_close; + + input->name = (steam->quirks & STEAM_QUIRK_WIRELESS) ? + "Wireless Steam Controller" : + "Steam Controller"; + input->phys = hdev->phys; + input->uniq = steam->serial_no; + input->id.bustype = hdev->bus; + input->id.vendor = hdev->vendor; + input->id.product = hdev->product; + input->id.version = hdev->version; + + input_set_capability(input, EV_KEY, BTN_TR2); + input_set_capability(input, EV_KEY, BTN_TL2); + input_set_capability(input, EV_KEY, BTN_TR); + input_set_capability(input, EV_KEY, BTN_TL); + input_set_capability(input, EV_KEY, BTN_Y); + input_set_capability(input, EV_KEY, BTN_B); + input_set_capability(input, EV_KEY, BTN_X); + input_set_capability(input, EV_KEY, BTN_A); + input_set_capability(input, EV_KEY, BTN_DPAD_UP); + input_set_capability(input, EV_KEY, BTN_DPAD_RIGHT); + input_set_capability(input, EV_KEY, BTN_DPAD_LEFT); + input_set_capability(input, EV_KEY, BTN_DPAD_DOWN); + input_set_capability(input, EV_KEY, BTN_SELECT); + input_set_capability(input, EV_KEY, BTN_MODE); + input_set_capability(input, EV_KEY, BTN_START); + input_set_capability(input, EV_KEY, BTN_GEAR_DOWN); + input_set_capability(input, EV_KEY, BTN_GEAR_UP); + input_set_capability(input, EV_KEY, BTN_THUMBR); + input_set_capability(input, EV_KEY, BTN_THUMBL); + input_set_capability(input, EV_KEY, BTN_THUMB); + input_set_capability(input, EV_KEY, BTN_THUMB2); + + input_set_abs_params(input, ABS_HAT2Y, 0, 255, 0, 0); + input_set_abs_params(input, ABS_HAT2X, 0, 255, 0, 0); + input_set_abs_params(input, ABS_X, -32767, 32767, 0, 0); + input_set_abs_params(input, ABS_Y, -32767, 32767, 0, 0); + input_set_abs_params(input, ABS_RX, -32767, 32767, + STEAM_PAD_FUZZ, 0); + input_set_abs_params(input, ABS_RY, -32767, 32767, + STEAM_PAD_FUZZ, 0); + input_set_abs_params(input, ABS_HAT0X, -32767, 32767, + STEAM_PAD_FUZZ, 0); + input_set_abs_params(input, ABS_HAT0Y, -32767, 32767, + STEAM_PAD_FUZZ, 0); + input_abs_set_res(input, ABS_X, STEAM_JOYSTICK_RESOLUTION); + input_abs_set_res(input, ABS_Y, STEAM_JOYSTICK_RESOLUTION); + input_abs_set_res(input, ABS_RX, STEAM_PAD_RESOLUTION); + input_abs_set_res(input, ABS_RY, STEAM_PAD_RESOLUTION); + input_abs_set_res(input, ABS_HAT0X, STEAM_PAD_RESOLUTION); + input_abs_set_res(input, ABS_HAT0Y, STEAM_PAD_RESOLUTION); + input_abs_set_res(input, ABS_HAT2Y, STEAM_TRIGGER_RESOLUTION); + input_abs_set_res(input, ABS_HAT2X, STEAM_TRIGGER_RESOLUTION); + + ret = input_register_device(input); + if (ret) + goto input_register_fail; + + rcu_assign_pointer(steam->input, input); + return 0; + +input_register_fail: + input_free_device(input); + return ret; +} + +static void steam_input_unregister(struct steam_device *steam) +{ + struct input_dev *input; + rcu_read_lock(); + input = rcu_dereference(steam->input); + rcu_read_unlock(); + if (!input) + return; + RCU_INIT_POINTER(steam->input, NULL); + synchronize_rcu(); + input_unregister_device(input); +} + +static void steam_battery_unregister(struct steam_device *steam) +{ + struct power_supply *battery; + + rcu_read_lock(); + battery = rcu_dereference(steam->battery); + rcu_read_unlock(); + + if (!battery) + return; + RCU_INIT_POINTER(steam->battery, NULL); + synchronize_rcu(); + power_supply_unregister(battery); +} + +static int steam_register(struct steam_device *steam) +{ + int ret; + bool client_opened; + + /* + * This function can be called several times in a row with the + * wireless adaptor, without steam_unregister() between them, because + * another client send a get_connection_status command, for example. + * The battery and serial number are set just once per device. + */ + if (!steam->serial_no[0]) { + /* + * Unlikely, but getting the serial could fail, and it is not so + * important, so make up a serial number and go on. + */ + mutex_lock(&steam->mutex); + if (steam_get_serial(steam) < 0) + strlcpy(steam->serial_no, "XXXXXXXXXX", + sizeof(steam->serial_no)); + mutex_unlock(&steam->mutex); + + hid_info(steam->hdev, "Steam Controller '%s' connected", + steam->serial_no); + + /* ignore battery errors, we can live without it */ + if (steam->quirks & STEAM_QUIRK_WIRELESS) + steam_battery_register(steam); + + mutex_lock(&steam_devices_lock); + list_add(&steam->list, &steam_devices); + mutex_unlock(&steam_devices_lock); + } + + mutex_lock(&steam->mutex); + client_opened = steam->client_opened; + if (!client_opened) + steam_set_lizard_mode(steam, lizard_mode); + mutex_unlock(&steam->mutex); + + if (!client_opened) + ret = steam_input_register(steam); + else + ret = 0; + + return ret; +} + +static void steam_unregister(struct steam_device *steam) +{ + steam_battery_unregister(steam); + steam_input_unregister(steam); + if (steam->serial_no[0]) { + hid_info(steam->hdev, "Steam Controller '%s' disconnected", + steam->serial_no); + mutex_lock(&steam_devices_lock); + list_del(&steam->list); + mutex_unlock(&steam_devices_lock); + steam->serial_no[0] = 0; + } +} + +static void steam_work_connect_cb(struct work_struct *work) +{ + struct steam_device *steam = container_of(work, struct steam_device, + work_connect); + unsigned long flags; + bool connected; + int ret; + + spin_lock_irqsave(&steam->lock, flags); + connected = steam->connected; + spin_unlock_irqrestore(&steam->lock, flags); + + if (connected) { + ret = steam_register(steam); + if (ret) { + hid_err(steam->hdev, + "%s:steam_register failed with error %d\n", + __func__, ret); + } + } else { + steam_unregister(steam); + } +} + +static bool steam_is_valve_interface(struct hid_device *hdev) +{ + struct hid_report_enum *rep_enum; + + /* + * The wired device creates 3 interfaces: + * 0: emulated mouse. + * 1: emulated keyboard. + * 2: the real game pad. + * The wireless device creates 5 interfaces: + * 0: emulated keyboard. + * 1-4: slots where up to 4 real game pads will be connected to. + * We know which one is the real gamepad interface because they are the + * only ones with a feature report. + */ + rep_enum = &hdev->report_enum[HID_FEATURE_REPORT]; + return !list_empty(&rep_enum->report_list); +} + +static int steam_client_ll_parse(struct hid_device *hdev) +{ + struct steam_device *steam = hdev->driver_data; + + return hid_parse_report(hdev, steam->hdev->dev_rdesc, + steam->hdev->dev_rsize); +} + +static int steam_client_ll_start(struct hid_device *hdev) +{ + return 0; +} + +static void steam_client_ll_stop(struct hid_device *hdev) +{ +} + +static int steam_client_ll_open(struct hid_device *hdev) +{ + struct steam_device *steam = hdev->driver_data; + + mutex_lock(&steam->mutex); + steam->client_opened = true; + mutex_unlock(&steam->mutex); + + steam_input_unregister(steam); + + return 0; +} + +static void steam_client_ll_close(struct hid_device *hdev) +{ + struct steam_device *steam = hdev->driver_data; + + unsigned long flags; + bool connected; + + spin_lock_irqsave(&steam->lock, flags); + connected = steam->connected; + spin_unlock_irqrestore(&steam->lock, flags); + + mutex_lock(&steam->mutex); + steam->client_opened = false; + if (connected) + steam_set_lizard_mode(steam, lizard_mode); + mutex_unlock(&steam->mutex); + + if (connected) + steam_input_register(steam); +} + +static int steam_client_ll_raw_request(struct hid_device *hdev, + unsigned char reportnum, u8 *buf, + size_t count, unsigned char report_type, + int reqtype) +{ + struct steam_device *steam = hdev->driver_data; + + return hid_hw_raw_request(steam->hdev, reportnum, buf, count, + report_type, reqtype); +} + +static struct hid_ll_driver steam_client_ll_driver = { + .parse = steam_client_ll_parse, + .start = steam_client_ll_start, + .stop = steam_client_ll_stop, + .open = steam_client_ll_open, + .close = steam_client_ll_close, + .raw_request = steam_client_ll_raw_request, +}; + +static struct hid_device *steam_create_client_hid(struct hid_device *hdev) +{ + struct hid_device *client_hdev; + + client_hdev = hid_allocate_device(); + if (IS_ERR(client_hdev)) + return client_hdev; + + client_hdev->ll_driver = &steam_client_ll_driver; + client_hdev->dev.parent = hdev->dev.parent; + client_hdev->bus = hdev->bus; + client_hdev->vendor = hdev->vendor; + client_hdev->product = hdev->product; + client_hdev->version = hdev->version; + client_hdev->type = hdev->type; + client_hdev->country = hdev->country; + strlcpy(client_hdev->name, hdev->name, + sizeof(client_hdev->name)); + strlcpy(client_hdev->phys, hdev->phys, + sizeof(client_hdev->phys)); + /* + * Since we use the same device info than the real interface to + * trick userspace, we will be calling steam_probe recursively. + * We need to recognize the client interface somehow. + */ + client_hdev->group = HID_GROUP_STEAM; + return client_hdev; +} + +static int steam_probe(struct hid_device *hdev, + const struct hid_device_id *id) +{ + struct steam_device *steam; + int ret; + + ret = hid_parse(hdev); + if (ret) { + hid_err(hdev, + "%s:parse of hid interface failed\n", __func__); + return ret; + } + + /* + * The virtual client_dev is only used for hidraw. + * Also avoid the recursive probe. + */ + if (hdev->group == HID_GROUP_STEAM) + return hid_hw_start(hdev, HID_CONNECT_HIDRAW); + /* + * The non-valve interfaces (mouse and keyboard emulation) are + * connected without changes. + */ + if (!steam_is_valve_interface(hdev)) + return hid_hw_start(hdev, HID_CONNECT_DEFAULT); + + steam = devm_kzalloc(&hdev->dev, sizeof(*steam), GFP_KERNEL); + if (!steam) { + ret = -ENOMEM; + goto steam_alloc_fail; + } + steam->hdev = hdev; + hid_set_drvdata(hdev, steam); + spin_lock_init(&steam->lock); + mutex_init(&steam->mutex); + steam->quirks = id->driver_data; + INIT_WORK(&steam->work_connect, steam_work_connect_cb); + + steam->client_hdev = steam_create_client_hid(hdev); + if (IS_ERR(steam->client_hdev)) { + ret = PTR_ERR(steam->client_hdev); + goto client_hdev_fail; + } + steam->client_hdev->driver_data = steam; + + /* + * With the real steam controller interface, do not connect hidraw. + * Instead, create the client_hid and connect that. + */ + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_HIDRAW); + if (ret) + goto hid_hw_start_fail; + + ret = hid_add_device(steam->client_hdev); + if (ret) + goto client_hdev_add_fail; + + ret = hid_hw_open(hdev); + if (ret) { + hid_err(hdev, + "%s:hid_hw_open\n", + __func__); + goto hid_hw_open_fail; + } + + if (steam->quirks & STEAM_QUIRK_WIRELESS) { + hid_info(hdev, "Steam wireless receiver connected"); + steam_request_conn_status(steam); + } else { + ret = steam_register(steam); + if (ret) { + hid_err(hdev, + "%s:steam_register failed with error %d\n", + __func__, ret); + goto input_register_fail; + } + } + + return 0; + +input_register_fail: +hid_hw_open_fail: +client_hdev_add_fail: + hid_hw_stop(hdev); +hid_hw_start_fail: + hid_destroy_device(steam->client_hdev); +client_hdev_fail: + cancel_work_sync(&steam->work_connect); +steam_alloc_fail: + hid_err(hdev, "%s: failed with error %d\n", + __func__, ret); + return ret; +} + +static void steam_remove(struct hid_device *hdev) +{ + struct steam_device *steam = hid_get_drvdata(hdev); + + if (!steam || hdev->group == HID_GROUP_STEAM) { + hid_hw_stop(hdev); + return; + } + + hid_destroy_device(steam->client_hdev); + steam->client_opened = false; + cancel_work_sync(&steam->work_connect); + if (steam->quirks & STEAM_QUIRK_WIRELESS) { + hid_info(hdev, "Steam wireless receiver disconnected"); + } + hid_hw_close(hdev); + hid_hw_stop(hdev); + steam_unregister(steam); +} + +static void steam_do_connect_event(struct steam_device *steam, bool connected) +{ + unsigned long flags; + bool changed; + + spin_lock_irqsave(&steam->lock, flags); + changed = steam->connected != connected; + steam->connected = connected; + spin_unlock_irqrestore(&steam->lock, flags); + + if (changed && schedule_work(&steam->work_connect) == 0) + dbg_hid("%s: connected=%d event already queued\n", + __func__, connected); +} + +/* + * Some input data in the protocol has the opposite sign. + * Clamp the values to 32767..-32767 so that the range is + * symmetrical and can be negated safely. + */ +static inline s16 steam_le16(u8 *data) +{ + s16 x = (s16) le16_to_cpup((__le16 *)data); + + return x == -32768 ? -32767 : x; +} + +/* + * The size for this message payload is 60. + * The known values are: + * (* values are not sent through wireless) + * (* accelerator/gyro is disabled by default) + * Offset| Type | Mapped to |Meaning + * -------+-------+-----------+-------------------------- + * 4-7 | u32 | -- | sequence number + * 8-10 | 24bit | see below | buttons + * 11 | u8 | ABS_HAT2Y | left trigger + * 12 | u8 | ABS_HAT2X | right trigger + * 13-15 | -- | -- | always 0 + * 16-17 | s16 | ABS_X/ABS_HAT0X | X value + * 18-19 | s16 | ABS_Y/ABS_HAT0Y | Y value + * 20-21 | s16 | ABS_RX | right-pad X value + * 22-23 | s16 | ABS_RY | right-pad Y value + * 24-25 | s16 | -- | * left trigger + * 26-27 | s16 | -- | * right trigger + * 28-29 | s16 | -- | * accelerometer X value + * 30-31 | s16 | -- | * accelerometer Y value + * 32-33 | s16 | -- | * accelerometer Z value + * 34-35 | s16 | -- | gyro X value + * 36-36 | s16 | -- | gyro Y value + * 38-39 | s16 | -- | gyro Z value + * 40-41 | s16 | -- | quaternion W value + * 42-43 | s16 | -- | quaternion X value + * 44-45 | s16 | -- | quaternion Y value + * 46-47 | s16 | -- | quaternion Z value + * 48-49 | -- | -- | always 0 + * 50-51 | s16 | -- | * left trigger (uncalibrated) + * 52-53 | s16 | -- | * right trigger (uncalibrated) + * 54-55 | s16 | -- | * joystick X value (uncalibrated) + * 56-57 | s16 | -- | * joystick Y value (uncalibrated) + * 58-59 | s16 | -- | * left-pad X value + * 60-61 | s16 | -- | * left-pad Y value + * 62-63 | u16 | -- | * battery voltage + * + * The buttons are: + * Bit | Mapped to | Description + * ------+------------+-------------------------------- + * 8.0 | BTN_TR2 | right trigger fully pressed + * 8.1 | BTN_TL2 | left trigger fully pressed + * 8.2 | BTN_TR | right shoulder + * 8.3 | BTN_TL | left shoulder + * 8.4 | BTN_Y | button Y + * 8.5 | BTN_B | button B + * 8.6 | BTN_X | button X + * 8.7 | BTN_A | button A + * 9.0 | BTN_DPAD_UP | lef-pad up + * 9.1 | BTN_DPAD_RIGHT | lef-pad right + * 9.2 | BTN_DPAD_LEFT | lef-pad left + * 9.3 | BTN_DPAD_DOWN | lef-pad down + * 9.4 | BTN_SELECT | menu left + * 9.5 | BTN_MODE | steam logo + * 9.6 | BTN_START | menu right + * 9.7 | BTN_GEAR_DOWN | left back lever + * 10.0 | BTN_GEAR_UP | right back lever + * 10.1 | -- | left-pad clicked + * 10.2 | BTN_THUMBR | right-pad clicked + * 10.3 | BTN_THUMB | left-pad touched (but see explanation below) + * 10.4 | BTN_THUMB2 | right-pad touched + * 10.5 | -- | unknown + * 10.6 | BTN_THUMBL | joystick clicked + * 10.7 | -- | lpad_and_joy + */ + +static void steam_do_input_event(struct steam_device *steam, + struct input_dev *input, u8 *data) +{ + /* 24 bits of buttons */ + u8 b8, b9, b10; + s16 x, y; + bool lpad_touched, lpad_and_joy; + + b8 = data[8]; + b9 = data[9]; + b10 = data[10]; + + input_report_abs(input, ABS_HAT2Y, data[11]); + input_report_abs(input, ABS_HAT2X, data[12]); + + /* + * These two bits tells how to interpret the values X and Y. + * lpad_and_joy tells that the joystick and the lpad are used at the + * same time. + * lpad_touched tells whether X/Y are to be read as lpad coord or + * joystick values. + * (lpad_touched || lpad_and_joy) tells if the lpad is really touched. + */ + lpad_touched = b10 & BIT(3); + lpad_and_joy = b10 & BIT(7); + x = steam_le16(data + 16); + y = -steam_le16(data + 18); + + input_report_abs(input, lpad_touched ? ABS_HAT0X : ABS_X, x); + input_report_abs(input, lpad_touched ? ABS_HAT0Y : ABS_Y, y); + /* Check if joystick is centered */ + if (lpad_touched && !lpad_and_joy) { + input_report_abs(input, ABS_X, 0); + input_report_abs(input, ABS_Y, 0); + } + /* Check if lpad is untouched */ + if (!(lpad_touched || lpad_and_joy)) { + input_report_abs(input, ABS_HAT0X, 0); + input_report_abs(input, ABS_HAT0Y, 0); + } + + input_report_abs(input, ABS_RX, steam_le16(data + 20)); + input_report_abs(input, ABS_RY, -steam_le16(data + 22)); + + input_event(input, EV_KEY, BTN_TR2, !!(b8 & BIT(0))); + input_event(input, EV_KEY, BTN_TL2, !!(b8 & BIT(1))); + input_event(input, EV_KEY, BTN_TR, !!(b8 & BIT(2))); + input_event(input, EV_KEY, BTN_TL, !!(b8 & BIT(3))); + input_event(input, EV_KEY, BTN_Y, !!(b8 & BIT(4))); + input_event(input, EV_KEY, BTN_B, !!(b8 & BIT(5))); + input_event(input, EV_KEY, BTN_X, !!(b8 & BIT(6))); + input_event(input, EV_KEY, BTN_A, !!(b8 & BIT(7))); + input_event(input, EV_KEY, BTN_SELECT, !!(b9 & BIT(4))); + input_event(input, EV_KEY, BTN_MODE, !!(b9 & BIT(5))); + input_event(input, EV_KEY, BTN_START, !!(b9 & BIT(6))); + input_event(input, EV_KEY, BTN_GEAR_DOWN, !!(b9 & BIT(7))); + input_event(input, EV_KEY, BTN_GEAR_UP, !!(b10 & BIT(0))); + input_event(input, EV_KEY, BTN_THUMBR, !!(b10 & BIT(2))); + input_event(input, EV_KEY, BTN_THUMBL, !!(b10 & BIT(6))); + input_event(input, EV_KEY, BTN_THUMB, lpad_touched || lpad_and_joy); + input_event(input, EV_KEY, BTN_THUMB2, !!(b10 & BIT(4))); + input_event(input, EV_KEY, BTN_DPAD_UP, !!(b9 & BIT(0))); + input_event(input, EV_KEY, BTN_DPAD_RIGHT, !!(b9 & BIT(1))); + input_event(input, EV_KEY, BTN_DPAD_LEFT, !!(b9 & BIT(2))); + input_event(input, EV_KEY, BTN_DPAD_DOWN, !!(b9 & BIT(3))); + + input_sync(input); +} + +/* + * The size for this message payload is 11. + * The known values are: + * Offset| Type | Meaning + * -------+-------+--------------------------- + * 4-7 | u32 | sequence number + * 8-11 | -- | always 0 + * 12-13 | u16 | voltage (mV) + * 14 | u8 | battery percent + */ +static void steam_do_battery_event(struct steam_device *steam, + struct power_supply *battery, u8 *data) +{ + unsigned long flags; + + s16 volts = steam_le16(data + 12); + u8 batt = data[14]; + + /* Creating the battery may have failed */ + rcu_read_lock(); + battery = rcu_dereference(steam->battery); + if (likely(battery)) { + spin_lock_irqsave(&steam->lock, flags); + steam->voltage = volts; + steam->battery_charge = batt; + spin_unlock_irqrestore(&steam->lock, flags); + power_supply_changed(battery); + } + rcu_read_unlock(); +} + +static int steam_raw_event(struct hid_device *hdev, + struct hid_report *report, u8 *data, + int size) +{ + struct steam_device *steam = hid_get_drvdata(hdev); + struct input_dev *input; + struct power_supply *battery; + + if (!steam) + return 0; + + if (steam->client_opened) + hid_input_report(steam->client_hdev, HID_FEATURE_REPORT, + data, size, 0); + /* + * All messages are size=64, all values little-endian. + * The format is: + * Offset| Meaning + * -------+-------------------------------------------- + * 0-1 | always 0x01, 0x00, maybe protocol version? + * 2 | type of message + * 3 | length of the real payload (not checked) + * 4-n | payload data, depends on the type + * + * There are these known types of message: + * 0x01: input data (60 bytes) + * 0x03: wireless connect/disconnect (1 byte) + * 0x04: battery status (11 bytes) + */ + + if (size != 64 || data[0] != 1 || data[1] != 0) + return 0; + + switch (data[2]) { + case STEAM_EV_INPUT_DATA: + if (steam->client_opened) + return 0; + rcu_read_lock(); + input = rcu_dereference(steam->input); + if (likely(input)) + steam_do_input_event(steam, input, data); + rcu_read_unlock(); + break; + case STEAM_EV_CONNECT: + /* + * The payload of this event is a single byte: + * 0x01: disconnected. + * 0x02: connected. + */ + switch (data[4]) { + case 0x01: + steam_do_connect_event(steam, false); + break; + case 0x02: + steam_do_connect_event(steam, true); + break; + } + break; + case STEAM_EV_BATTERY: + if (steam->quirks & STEAM_QUIRK_WIRELESS) { + rcu_read_lock(); + battery = rcu_dereference(steam->battery); + if (likely(battery)) { + steam_do_battery_event(steam, battery, data); + } else { + dbg_hid( + "%s: battery data without connect event\n", + __func__); + steam_do_connect_event(steam, true); + } + rcu_read_unlock(); + } + break; + } + return 0; +} + +static int steam_param_set_lizard_mode(const char *val, + const struct kernel_param *kp) +{ + struct steam_device *steam; + int ret; + + ret = param_set_bool(val, kp); + if (ret) + return ret; + + mutex_lock(&steam_devices_lock); + list_for_each_entry(steam, &steam_devices, list) { + mutex_lock(&steam->mutex); + if (!steam->client_opened) + steam_set_lizard_mode(steam, lizard_mode); + mutex_unlock(&steam->mutex); + } + mutex_unlock(&steam_devices_lock); + return 0; +} + +static const struct kernel_param_ops steam_lizard_mode_ops = { + .set = steam_param_set_lizard_mode, + .get = param_get_bool, +}; + +module_param_cb(lizard_mode, &steam_lizard_mode_ops, &lizard_mode, 0644); +MODULE_PARM_DESC(lizard_mode, + "Enable mouse and keyboard emulation (lizard mode) when the gamepad is not in use"); + +static const struct hid_device_id steam_controllers[] = { + { /* Wired Steam Controller */ + HID_USB_DEVICE(USB_VENDOR_ID_VALVE, + USB_DEVICE_ID_STEAM_CONTROLLER) + }, + { /* Wireless Steam Controller */ + HID_USB_DEVICE(USB_VENDOR_ID_VALVE, + USB_DEVICE_ID_STEAM_CONTROLLER_WIRELESS), + .driver_data = STEAM_QUIRK_WIRELESS + }, + {} +}; + +MODULE_DEVICE_TABLE(hid, steam_controllers); + +static struct hid_driver steam_controller_driver = { + .name = "hid-steam", + .id_table = steam_controllers, + .probe = steam_probe, + .remove = steam_remove, + .raw_event = steam_raw_event, +}; + +module_hid_driver(steam_controller_driver);
\ No newline at end of file diff --git a/drivers/hid/hid-tmff.c b/drivers/hid/hid-tmff.c index cfa0cb22c9b3..d98e471a5f7b 100644 --- a/drivers/hid/hid-tmff.c +++ b/drivers/hid/hid-tmff.c @@ -136,12 +136,18 @@ static int tmff_init(struct hid_device *hid, const signed short *ff_bits) struct tmff_device *tmff; struct hid_report *report; struct list_head *report_list; - struct hid_input *hidinput = list_entry(hid->inputs.next, - struct hid_input, list); - struct input_dev *input_dev = hidinput->input; + struct hid_input *hidinput; + struct input_dev *input_dev; int error; int i; + if (list_empty(&hid->inputs)) { + hid_err(hid, "no inputs found\n"); + return -ENODEV; + } + hidinput = list_entry(hid->inputs.next, struct hid_input, list); + input_dev = hidinput->input; + tmff = kzalloc(sizeof(struct tmff_device), GFP_KERNEL); if (!tmff) return -ENOMEM; diff --git a/drivers/hid/hid-zpff.c b/drivers/hid/hid-zpff.c index a29756c6ca02..4e7e01be99b1 100644 --- a/drivers/hid/hid-zpff.c +++ b/drivers/hid/hid-zpff.c @@ -66,11 +66,17 @@ static int zpff_init(struct hid_device *hid) { struct zpff_device *zpff; struct hid_report *report; - struct hid_input *hidinput = list_entry(hid->inputs.next, - struct hid_input, list); - struct input_dev *dev = hidinput->input; + struct hid_input *hidinput; + struct input_dev *dev; int i, error; + if (list_empty(&hid->inputs)) { + hid_err(hid, "no inputs found\n"); + return -ENODEV; + } + hidinput = list_entry(hid->inputs.next, struct hid_input, list); + dev = hidinput->input; + for (i = 0; i < 4; i++) { report = hid_validate_values(hid, HID_OUTPUT_REPORT, 0, i, 1); if (!report) diff --git a/drivers/hwmon/pwm-fan.c b/drivers/hwmon/pwm-fan.c index 3e23003f78b0..993c61e95d30 100644 --- a/drivers/hwmon/pwm-fan.c +++ b/drivers/hwmon/pwm-fan.c @@ -227,8 +227,12 @@ static int pwm_fan_probe(struct platform_device *pdev) ctx->pwm = devm_of_pwm_get(&pdev->dev, pdev->dev.of_node, NULL); if (IS_ERR(ctx->pwm)) { - dev_err(&pdev->dev, "Could not get PWM\n"); - return PTR_ERR(ctx->pwm); + ret = PTR_ERR(ctx->pwm); + + if (ret != -EPROBE_DEFER) + dev_err(&pdev->dev, "Could not get PWM: %d\n", ret); + + return ret; } platform_set_drvdata(pdev, ctx); diff --git a/drivers/iio/accel/bmc150-accel-core.c b/drivers/iio/accel/bmc150-accel-core.c index c7122919a8c0..ec7ddf867349 100644 --- a/drivers/iio/accel/bmc150-accel-core.c +++ b/drivers/iio/accel/bmc150-accel-core.c @@ -126,7 +126,7 @@ #define BMC150_ACCEL_SLEEP_1_SEC 0x0F #define BMC150_ACCEL_REG_TEMP 0x08 -#define BMC150_ACCEL_TEMP_CENTER_VAL 24 +#define BMC150_ACCEL_TEMP_CENTER_VAL 23 #define BMC150_ACCEL_AXIS_TO_REG(axis) (BMC150_ACCEL_REG_XOUT_L + (axis * 2)) #define BMC150_AUTO_SUSPEND_DELAY_MS 2000 diff --git a/drivers/iio/dac/mcp4922.c b/drivers/iio/dac/mcp4922.c index 3854d201a5d6..68dd0be1ac07 100644 --- a/drivers/iio/dac/mcp4922.c +++ b/drivers/iio/dac/mcp4922.c @@ -94,17 +94,22 @@ static int mcp4922_write_raw(struct iio_dev *indio_dev, long mask) { struct mcp4922_state *state = iio_priv(indio_dev); + int ret; if (val2 != 0) return -EINVAL; switch (mask) { case IIO_CHAN_INFO_RAW: - if (val > GENMASK(chan->scan_type.realbits-1, 0)) + if (val < 0 || val > GENMASK(chan->scan_type.realbits - 1, 0)) return -EINVAL; val <<= chan->scan_type.shift; - state->value[chan->channel] = val; - return mcp4922_spi_write(state, chan->channel, val); + + ret = mcp4922_spi_write(state, chan->channel, val); + if (!ret) + state->value[chan->channel] = val; + return ret; + default: return -EINVAL; } diff --git a/drivers/iio/imu/adis16480.c b/drivers/iio/imu/adis16480.c index 1880105cc8c4..778a46247f8d 100644 --- a/drivers/iio/imu/adis16480.c +++ b/drivers/iio/imu/adis16480.c @@ -266,8 +266,11 @@ static int adis16480_set_freq(struct iio_dev *indio_dev, int val, int val2) struct adis16480 *st = iio_priv(indio_dev); unsigned int t; + if (val < 0 || val2 < 0) + return -EINVAL; + t = val * 1000 + val2 / 1000; - if (t <= 0) + if (t == 0) return -EINVAL; t = 2460000 / t; diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 1454290078de..8ad9c6b04769 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -1976,9 +1976,10 @@ static int iw_conn_req_handler(struct iw_cm_id *cm_id, conn_id->cm_id.iw = NULL; cma_exch(conn_id, RDMA_CM_DESTROYING); mutex_unlock(&conn_id->handler_mutex); + mutex_unlock(&listen_id->handler_mutex); cma_deref_id(conn_id); rdma_destroy_id(&conn_id->id); - goto out; + return ret; } mutex_unlock(&conn_id->handler_mutex); diff --git a/drivers/infiniband/hw/mthca/mthca_main.c b/drivers/infiniband/hw/mthca/mthca_main.c index ded76c101dde..834b06aacc2b 100644 --- a/drivers/infiniband/hw/mthca/mthca_main.c +++ b/drivers/infiniband/hw/mthca/mthca_main.c @@ -989,7 +989,8 @@ static int __mthca_init_one(struct pci_dev *pdev, int hca_type) goto err_free_dev; } - if (mthca_cmd_init(mdev)) { + err = mthca_cmd_init(mdev); + if (err) { mthca_err(mdev, "Failed to init command interface, aborting.\n"); goto err_free_dev; } diff --git a/drivers/input/ff-memless.c b/drivers/input/ff-memless.c index fcc6c3368182..ea3f0f5eb534 100644 --- a/drivers/input/ff-memless.c +++ b/drivers/input/ff-memless.c @@ -501,6 +501,15 @@ static void ml_ff_destroy(struct ff_device *ff) { struct ml_device *ml = ff->private; + /* + * Even though we stop all playing effects when tearing down + * an input device (via input_device_flush() that calls into + * input_ff_flush() that stops and erases all effects), we + * do not actually stop the timer, and therefore we should + * do it here. + */ + del_timer_sync(&ml->timer); + kfree(ml->private); } diff --git a/drivers/input/touchscreen/st1232.c b/drivers/input/touchscreen/st1232.c index e943678ce54c..f1c574d6be17 100644 --- a/drivers/input/touchscreen/st1232.c +++ b/drivers/input/touchscreen/st1232.c @@ -203,6 +203,7 @@ static int st1232_ts_probe(struct i2c_client *client, input_dev->id.bustype = BUS_I2C; input_dev->dev.parent = &client->dev; + __set_bit(INPUT_PROP_DIRECT, input_dev->propbit); __set_bit(EV_SYN, input_dev->evbit); __set_bit(EV_KEY, input_dev->evbit); __set_bit(EV_ABS, input_dev->evbit); diff --git a/drivers/isdn/mISDN/tei.c b/drivers/isdn/mISDN/tei.c index 592f597d8951..8261afbbafb0 100644 --- a/drivers/isdn/mISDN/tei.c +++ b/drivers/isdn/mISDN/tei.c @@ -1180,8 +1180,7 @@ static int ctrl_teimanager(struct manager *mgr, void *arg) { /* currently we only have one option */ - int *val = (int *)arg; - int ret = 0; + unsigned int *val = (unsigned int *)arg; switch (val[0]) { case IMCLEAR_L2: @@ -1197,9 +1196,9 @@ ctrl_teimanager(struct manager *mgr, void *arg) test_and_clear_bit(OPTION_L1_HOLD, &mgr->options); break; default: - ret = -EINVAL; + return -EINVAL; } - return ret; + return 0; } /* This function does create a L2 for fixed TEI in NT Mode */ diff --git a/drivers/macintosh/windfarm_smu_sat.c b/drivers/macintosh/windfarm_smu_sat.c index ad6223e88340..3d310dd60a0b 100644 --- a/drivers/macintosh/windfarm_smu_sat.c +++ b/drivers/macintosh/windfarm_smu_sat.c @@ -22,14 +22,6 @@ #define VERSION "1.0" -#define DEBUG - -#ifdef DEBUG -#define DBG(args...) printk(args) -#else -#define DBG(args...) do { } while(0) -#endif - /* If the cache is older than 800ms we'll refetch it */ #define MAX_AGE msecs_to_jiffies(800) @@ -106,13 +98,10 @@ struct smu_sdbp_header *smu_sat_get_sdb_partition(unsigned int sat_id, int id, buf[i+2] = data[3]; buf[i+3] = data[2]; } -#ifdef DEBUG - DBG(KERN_DEBUG "sat %d partition %x:", sat_id, id); - for (i = 0; i < len; ++i) - DBG(" %x", buf[i]); - DBG("\n"); -#endif + printk(KERN_DEBUG "sat %d partition %x:", sat_id, id); + print_hex_dump(KERN_DEBUG, " ", DUMP_PREFIX_OFFSET, + 16, 1, buf, len, false); if (size) *size = len; return (struct smu_sdbp_header *) buf; @@ -132,13 +121,13 @@ static int wf_sat_read_cache(struct wf_sat *sat) if (err < 0) return err; sat->last_read = jiffies; + #ifdef LOTSA_DEBUG { int i; - DBG(KERN_DEBUG "wf_sat_get: data is"); - for (i = 0; i < 16; ++i) - DBG(" %.2x", sat->cache[i]); - DBG("\n"); + printk(KERN_DEBUG "wf_sat_get: data is"); + print_hex_dump(KERN_DEBUG, " ", DUMP_PREFIX_OFFSET, + 16, 1, sat->cache, 16, false); } #endif return 0; diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c index adef364c2b8e..0fbb7f0c3d16 100644 --- a/drivers/md/bcache/super.c +++ b/drivers/md/bcache/super.c @@ -902,6 +902,7 @@ static void cached_dev_detach_finish(struct work_struct *w) bch_write_bdev_super(dc, &cl); closure_sync(&cl); + calc_cached_dev_sectors(dc->disk.c); bcache_device_detach(&dc->disk); list_move(&dc->list, &uncached_devices); diff --git a/drivers/md/dm-bio-prison.c b/drivers/md/dm-bio-prison.c index 03af174485d3..fa2432a89bac 100644 --- a/drivers/md/dm-bio-prison.c +++ b/drivers/md/dm-bio-prison.c @@ -32,7 +32,7 @@ static struct kmem_cache *_cell_cache; */ struct dm_bio_prison *dm_bio_prison_create(void) { - struct dm_bio_prison *prison = kmalloc(sizeof(*prison), GFP_KERNEL); + struct dm_bio_prison *prison = kzalloc(sizeof(*prison), GFP_KERNEL); if (!prison) return NULL; diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c index 1b84d2890fbf..ad9a470e5382 100644 --- a/drivers/md/dm-io.c +++ b/drivers/md/dm-io.c @@ -50,7 +50,7 @@ struct dm_io_client *dm_io_client_create(void) struct dm_io_client *client; unsigned min_ios = dm_get_reserved_bio_based_ios(); - client = kmalloc(sizeof(*client), GFP_KERNEL); + client = kzalloc(sizeof(*client), GFP_KERNEL); if (!client) return ERR_PTR(-ENOMEM); diff --git a/drivers/md/dm-kcopyd.c b/drivers/md/dm-kcopyd.c index 04248394843e..09df2c688ba9 100644 --- a/drivers/md/dm-kcopyd.c +++ b/drivers/md/dm-kcopyd.c @@ -827,7 +827,7 @@ struct dm_kcopyd_client *dm_kcopyd_client_create(struct dm_kcopyd_throttle *thro int r = -ENOMEM; struct dm_kcopyd_client *kc; - kc = kmalloc(sizeof(*kc), GFP_KERNEL); + kc = kzalloc(sizeof(*kc), GFP_KERNEL); if (!kc) return ERR_PTR(-ENOMEM); diff --git a/drivers/md/dm-region-hash.c b/drivers/md/dm-region-hash.c index 74cb7b991d41..a93a4e683999 100644 --- a/drivers/md/dm-region-hash.c +++ b/drivers/md/dm-region-hash.c @@ -179,7 +179,7 @@ struct dm_region_hash *dm_region_hash_create( ; nr_buckets >>= 1; - rh = kmalloc(sizeof(*rh), GFP_KERNEL); + rh = kzalloc(sizeof(*rh), GFP_KERNEL); if (!rh) { DMERR("unable to allocate region hash memory"); return ERR_PTR(-ENOMEM); diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c index 2a855e5429ab..55e158553700 100644 --- a/drivers/md/dm-snap.c +++ b/drivers/md/dm-snap.c @@ -19,7 +19,6 @@ #include <linux/vmalloc.h> #include <linux/log2.h> #include <linux/dm-kcopyd.h> -#include <linux/semaphore.h> #include "dm.h" @@ -48,7 +47,7 @@ struct dm_exception_table { }; struct dm_snapshot { - struct rw_semaphore lock; + struct mutex lock; struct dm_dev *origin; struct dm_dev *cow; @@ -106,8 +105,8 @@ struct dm_snapshot { /* The on disk metadata handler */ struct dm_exception_store *store; - /* Maximum number of in-flight COW jobs. */ - struct semaphore cow_count; + unsigned in_progress; + wait_queue_head_t in_progress_wait; struct dm_kcopyd_client *kcopyd_client; @@ -158,8 +157,8 @@ struct dm_snapshot { */ #define DEFAULT_COW_THRESHOLD 2048 -static int cow_threshold = DEFAULT_COW_THRESHOLD; -module_param_named(snapshot_cow_threshold, cow_threshold, int, 0644); +static unsigned cow_threshold = DEFAULT_COW_THRESHOLD; +module_param_named(snapshot_cow_threshold, cow_threshold, uint, 0644); MODULE_PARM_DESC(snapshot_cow_threshold, "Maximum number of chunks being copied on write"); DECLARE_DM_KCOPYD_THROTTLE_WITH_MODULE_PARM(snapshot_copy_throttle, @@ -456,9 +455,9 @@ static int __find_snapshots_sharing_cow(struct dm_snapshot *snap, if (!bdev_equal(s->cow->bdev, snap->cow->bdev)) continue; - down_read(&s->lock); + mutex_lock(&s->lock); active = s->active; - up_read(&s->lock); + mutex_unlock(&s->lock); if (active) { if (snap_src) @@ -926,7 +925,7 @@ static int remove_single_exception_chunk(struct dm_snapshot *s) int r; chunk_t old_chunk = s->first_merging_chunk + s->num_merging_chunks - 1; - down_write(&s->lock); + mutex_lock(&s->lock); /* * Process chunks (and associated exceptions) in reverse order @@ -941,7 +940,7 @@ static int remove_single_exception_chunk(struct dm_snapshot *s) b = __release_queued_bios_after_merge(s); out: - up_write(&s->lock); + mutex_unlock(&s->lock); if (b) flush_bios(b); @@ -1000,9 +999,9 @@ static void snapshot_merge_next_chunks(struct dm_snapshot *s) if (linear_chunks < 0) { DMERR("Read error in exception store: " "shutting down merge"); - down_write(&s->lock); + mutex_lock(&s->lock); s->merge_failed = 1; - up_write(&s->lock); + mutex_unlock(&s->lock); } goto shut; } @@ -1043,10 +1042,10 @@ static void snapshot_merge_next_chunks(struct dm_snapshot *s) previous_count = read_pending_exceptions_done_count(); } - down_write(&s->lock); + mutex_lock(&s->lock); s->first_merging_chunk = old_chunk; s->num_merging_chunks = linear_chunks; - up_write(&s->lock); + mutex_unlock(&s->lock); /* Wait until writes to all 'linear_chunks' drain */ for (i = 0; i < linear_chunks; i++) @@ -1088,10 +1087,10 @@ static void merge_callback(int read_err, unsigned long write_err, void *context) return; shut: - down_write(&s->lock); + mutex_lock(&s->lock); s->merge_failed = 1; b = __release_queued_bios_after_merge(s); - up_write(&s->lock); + mutex_unlock(&s->lock); error_bios(b); merge_shutdown(s); @@ -1137,7 +1136,7 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv) origin_mode = FMODE_WRITE; } - s = kmalloc(sizeof(*s), GFP_KERNEL); + s = kzalloc(sizeof(*s), GFP_KERNEL); if (!s) { ti->error = "Cannot allocate private snapshot structure"; r = -ENOMEM; @@ -1190,7 +1189,7 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv) s->exception_start_sequence = 0; s->exception_complete_sequence = 0; INIT_LIST_HEAD(&s->out_of_order_list); - init_rwsem(&s->lock); + mutex_init(&s->lock); INIT_LIST_HEAD(&s->list); spin_lock_init(&s->pe_lock); s->state_bits = 0; @@ -1206,7 +1205,7 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv) goto bad_hash_tables; } - sema_init(&s->cow_count, (cow_threshold > 0) ? cow_threshold : INT_MAX); + init_waitqueue_head(&s->in_progress_wait); s->kcopyd_client = dm_kcopyd_client_create(&dm_kcopyd_throttle); if (IS_ERR(s->kcopyd_client)) { @@ -1357,9 +1356,9 @@ static void snapshot_dtr(struct dm_target *ti) /* Check whether exception handover must be cancelled */ (void) __find_snapshots_sharing_cow(s, &snap_src, &snap_dest, NULL); if (snap_src && snap_dest && (s == snap_src)) { - down_write(&snap_dest->lock); + mutex_lock(&snap_dest->lock); snap_dest->valid = 0; - up_write(&snap_dest->lock); + mutex_unlock(&snap_dest->lock); DMERR("Cancelling snapshot handover."); } up_read(&_origins_lock); @@ -1390,13 +1389,62 @@ static void snapshot_dtr(struct dm_target *ti) dm_exception_store_destroy(s->store); + mutex_destroy(&s->lock); + dm_put_device(ti, s->cow); dm_put_device(ti, s->origin); + WARN_ON(s->in_progress); + kfree(s); } +static void account_start_copy(struct dm_snapshot *s) +{ + spin_lock(&s->in_progress_wait.lock); + s->in_progress++; + spin_unlock(&s->in_progress_wait.lock); +} + +static void account_end_copy(struct dm_snapshot *s) +{ + spin_lock(&s->in_progress_wait.lock); + BUG_ON(!s->in_progress); + s->in_progress--; + if (likely(s->in_progress <= cow_threshold) && + unlikely(waitqueue_active(&s->in_progress_wait))) + wake_up_locked(&s->in_progress_wait); + spin_unlock(&s->in_progress_wait.lock); +} + +static bool wait_for_in_progress(struct dm_snapshot *s, bool unlock_origins) +{ + if (unlikely(s->in_progress > cow_threshold)) { + spin_lock(&s->in_progress_wait.lock); + if (likely(s->in_progress > cow_threshold)) { + /* + * NOTE: this throttle doesn't account for whether + * the caller is servicing an IO that will trigger a COW + * so excess throttling may result for chunks not required + * to be COW'd. But if cow_threshold was reached, extra + * throttling is unlikely to negatively impact performance. + */ + DECLARE_WAITQUEUE(wait, current); + __add_wait_queue(&s->in_progress_wait, &wait); + __set_current_state(TASK_UNINTERRUPTIBLE); + spin_unlock(&s->in_progress_wait.lock); + if (unlock_origins) + up_read(&_origins_lock); + io_schedule(); + remove_wait_queue(&s->in_progress_wait, &wait); + return false; + } + spin_unlock(&s->in_progress_wait.lock); + } + return true; +} + /* * Flush a list of buffers. */ @@ -1412,7 +1460,7 @@ static void flush_bios(struct bio *bio) } } -static int do_origin(struct dm_dev *origin, struct bio *bio); +static int do_origin(struct dm_dev *origin, struct bio *bio, bool limit); /* * Flush a list of buffers. @@ -1425,7 +1473,7 @@ static void retry_origin_bios(struct dm_snapshot *s, struct bio *bio) while (bio) { n = bio->bi_next; bio->bi_next = NULL; - r = do_origin(s->origin, bio); + r = do_origin(s->origin, bio, false); if (r == DM_MAPIO_REMAPPED) generic_make_request(bio); bio = n; @@ -1477,7 +1525,7 @@ static void pending_complete(void *context, int success) if (!success) { /* Read/write error - snapshot is unusable */ - down_write(&s->lock); + mutex_lock(&s->lock); __invalidate_snapshot(s, -EIO); error = 1; goto out; @@ -1485,14 +1533,14 @@ static void pending_complete(void *context, int success) e = alloc_completed_exception(GFP_NOIO); if (!e) { - down_write(&s->lock); + mutex_lock(&s->lock); __invalidate_snapshot(s, -ENOMEM); error = 1; goto out; } *e = pe->e; - down_write(&s->lock); + mutex_lock(&s->lock); if (!s->valid) { free_completed_exception(e); error = 1; @@ -1517,7 +1565,7 @@ out: full_bio->bi_end_io = pe->full_bio_end_io; increment_pending_exceptions_done_count(); - up_write(&s->lock); + mutex_unlock(&s->lock); /* Submit any pending write bios */ if (error) { @@ -1579,7 +1627,7 @@ static void copy_callback(int read_err, unsigned long write_err, void *context) } list_add(&pe->out_of_order_entry, lh); } - up(&s->cow_count); + account_end_copy(s); } /* @@ -1603,7 +1651,7 @@ static void start_copy(struct dm_snap_pending_exception *pe) dest.count = src.count; /* Hand over to kcopyd */ - down(&s->cow_count); + account_start_copy(s); dm_kcopyd_copy(s->kcopyd_client, &src, 1, &dest, 0, copy_callback, pe); } @@ -1623,7 +1671,7 @@ static void start_full_bio(struct dm_snap_pending_exception *pe, pe->full_bio = bio; pe->full_bio_end_io = bio->bi_end_io; - down(&s->cow_count); + account_start_copy(s); callback_data = dm_kcopyd_prepare_callback(s->kcopyd_client, copy_callback, pe); @@ -1714,9 +1762,12 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio) if (!s->valid) return -EIO; - /* FIXME: should only take write lock if we need - * to copy an exception */ - down_write(&s->lock); + if (bio_data_dir(bio) == WRITE) { + while (unlikely(!wait_for_in_progress(s, false))) + ; /* wait_for_in_progress() has slept */ + } + + mutex_lock(&s->lock); if (!s->valid || (unlikely(s->snapshot_overflowed) && bio_rw(bio) == WRITE)) { r = -EIO; @@ -1738,9 +1789,9 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio) if (bio_rw(bio) == WRITE) { pe = __lookup_pending_exception(s, chunk); if (!pe) { - up_write(&s->lock); + mutex_unlock(&s->lock); pe = alloc_pending_exception(s); - down_write(&s->lock); + mutex_lock(&s->lock); if (!s->valid || s->snapshot_overflowed) { free_pending_exception(pe); @@ -1775,7 +1826,7 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio) bio->bi_iter.bi_size == (s->store->chunk_size << SECTOR_SHIFT)) { pe->started = 1; - up_write(&s->lock); + mutex_unlock(&s->lock); start_full_bio(pe, bio); goto out; } @@ -1785,7 +1836,7 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio) if (!pe->started) { /* this is protected by snap->lock */ pe->started = 1; - up_write(&s->lock); + mutex_unlock(&s->lock); start_copy(pe); goto out; } @@ -1795,7 +1846,7 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio) } out_unlock: - up_write(&s->lock); + mutex_unlock(&s->lock); out: return r; } @@ -1831,7 +1882,7 @@ static int snapshot_merge_map(struct dm_target *ti, struct bio *bio) chunk = sector_to_chunk(s->store, bio->bi_iter.bi_sector); - down_write(&s->lock); + mutex_lock(&s->lock); /* Full merging snapshots are redirected to the origin */ if (!s->valid) @@ -1862,12 +1913,12 @@ redirect_to_origin: bio->bi_bdev = s->origin->bdev; if (bio_rw(bio) == WRITE) { - up_write(&s->lock); - return do_origin(s->origin, bio); + mutex_unlock(&s->lock); + return do_origin(s->origin, bio, false); } out_unlock: - up_write(&s->lock); + mutex_unlock(&s->lock); return r; } @@ -1898,7 +1949,7 @@ static int snapshot_preresume(struct dm_target *ti) down_read(&_origins_lock); (void) __find_snapshots_sharing_cow(s, &snap_src, &snap_dest, NULL); if (snap_src && snap_dest) { - down_read(&snap_src->lock); + mutex_lock(&snap_src->lock); if (s == snap_src) { DMERR("Unable to resume snapshot source until " "handover completes."); @@ -1908,7 +1959,7 @@ static int snapshot_preresume(struct dm_target *ti) "source is suspended."); r = -EINVAL; } - up_read(&snap_src->lock); + mutex_unlock(&snap_src->lock); } up_read(&_origins_lock); @@ -1954,11 +2005,11 @@ static void snapshot_resume(struct dm_target *ti) (void) __find_snapshots_sharing_cow(s, &snap_src, &snap_dest, NULL); if (snap_src && snap_dest) { - down_write(&snap_src->lock); - down_write_nested(&snap_dest->lock, SINGLE_DEPTH_NESTING); + mutex_lock(&snap_src->lock); + mutex_lock_nested(&snap_dest->lock, SINGLE_DEPTH_NESTING); __handover_exceptions(snap_src, snap_dest); - up_write(&snap_dest->lock); - up_write(&snap_src->lock); + mutex_unlock(&snap_dest->lock); + mutex_unlock(&snap_src->lock); } up_read(&_origins_lock); @@ -1973,9 +2024,9 @@ static void snapshot_resume(struct dm_target *ti) /* Now we have correct chunk size, reregister */ reregister_snapshot(s); - down_write(&s->lock); + mutex_lock(&s->lock); s->active = 1; - up_write(&s->lock); + mutex_unlock(&s->lock); } static uint32_t get_origin_minimum_chunksize(struct block_device *bdev) @@ -2015,7 +2066,7 @@ static void snapshot_status(struct dm_target *ti, status_type_t type, switch (type) { case STATUSTYPE_INFO: - down_write(&snap->lock); + mutex_lock(&snap->lock); if (!snap->valid) DMEMIT("Invalid"); @@ -2040,7 +2091,7 @@ static void snapshot_status(struct dm_target *ti, status_type_t type, DMEMIT("Unknown"); } - up_write(&snap->lock); + mutex_unlock(&snap->lock); break; @@ -2106,7 +2157,7 @@ static int __origin_write(struct list_head *snapshots, sector_t sector, if (dm_target_is_snapshot_merge(snap->ti)) continue; - down_write(&snap->lock); + mutex_lock(&snap->lock); /* Only deal with valid and active snapshots */ if (!snap->valid || !snap->active) @@ -2133,9 +2184,9 @@ static int __origin_write(struct list_head *snapshots, sector_t sector, pe = __lookup_pending_exception(snap, chunk); if (!pe) { - up_write(&snap->lock); + mutex_unlock(&snap->lock); pe = alloc_pending_exception(snap); - down_write(&snap->lock); + mutex_lock(&snap->lock); if (!snap->valid) { free_pending_exception(pe); @@ -2178,7 +2229,7 @@ static int __origin_write(struct list_head *snapshots, sector_t sector, } next_snapshot: - up_write(&snap->lock); + mutex_unlock(&snap->lock); if (pe_to_start_now) { start_copy(pe_to_start_now); @@ -2199,15 +2250,24 @@ next_snapshot: /* * Called on a write from the origin driver. */ -static int do_origin(struct dm_dev *origin, struct bio *bio) +static int do_origin(struct dm_dev *origin, struct bio *bio, bool limit) { struct origin *o; int r = DM_MAPIO_REMAPPED; +again: down_read(&_origins_lock); o = __lookup_origin(origin->bdev); - if (o) + if (o) { + if (limit) { + struct dm_snapshot *s; + list_for_each_entry(s, &o->snapshots, list) + if (unlikely(!wait_for_in_progress(s, true))) + goto again; + } + r = __origin_write(&o->snapshots, bio->bi_iter.bi_sector, bio); + } up_read(&_origins_lock); return r; @@ -2320,7 +2380,7 @@ static int origin_map(struct dm_target *ti, struct bio *bio) dm_accept_partial_bio(bio, available_sectors); /* Only tell snapshots if this is a write */ - return do_origin(o->dev, bio); + return do_origin(o->dev, bio, true); } /* diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c index ccb76fc5cb69..aa05a2fca354 100644 --- a/drivers/md/dm-thin.c +++ b/drivers/md/dm-thin.c @@ -2882,7 +2882,7 @@ static struct pool *pool_create(struct mapped_device *pool_md, return (struct pool *)pmd; } - pool = kmalloc(sizeof(*pool), GFP_KERNEL); + pool = kzalloc(sizeof(*pool), GFP_KERNEL); if (!pool) { *error = "Error allocating memory for pool"; err_p = ERR_PTR(-ENOMEM); diff --git a/drivers/md/dm.c b/drivers/md/dm.c index f002d2ce9c9f..44904c374b38 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -2949,9 +2949,7 @@ static void __dm_destroy(struct mapped_device *md, bool wait) set_bit(DMF_FREEING, &md->flags); spin_unlock(&_minor_lock); - spin_lock_irq(q->queue_lock); - queue_flag_set(QUEUE_FLAG_DYING, q); - spin_unlock_irq(q->queue_lock); + blk_set_queue_dying(q); if (dm_request_based(md) && md->kworker_task) flush_kthread_worker(&md->kworker); diff --git a/drivers/media/pci/ivtv/ivtv-yuv.c b/drivers/media/pci/ivtv/ivtv-yuv.c index 9cd995f418e0..1d67407ffbf6 100644 --- a/drivers/media/pci/ivtv/ivtv-yuv.c +++ b/drivers/media/pci/ivtv/ivtv-yuv.c @@ -936,7 +936,7 @@ static void ivtv_yuv_init(struct ivtv *itv) } /* We need a buffer for blanking when Y plane is offset - non-fatal if we can't get one */ - yi->blanking_ptr = kzalloc(720 * 16, GFP_KERNEL|__GFP_NOWARN); + yi->blanking_ptr = kzalloc(720 * 16, GFP_ATOMIC|__GFP_NOWARN); if (yi->blanking_ptr) { yi->blanking_dmaptr = pci_map_single(itv->pdev, yi->blanking_ptr, 720*16, PCI_DMA_TODEVICE); } else { diff --git a/drivers/media/pci/meye/meye.c b/drivers/media/pci/meye/meye.c index ba887e8e1b17..a85c5199ccd3 100644 --- a/drivers/media/pci/meye/meye.c +++ b/drivers/media/pci/meye/meye.c @@ -1469,7 +1469,7 @@ static int meye_mmap(struct file *file, struct vm_area_struct *vma) unsigned long page, pos; mutex_lock(&meye.lock); - if (size > gbuffers * gbufsize) { + if (size > gbuffers * gbufsize || offset > gbuffers * gbufsize - size) { mutex_unlock(&meye.lock); return -EINVAL; } diff --git a/drivers/media/platform/davinci/isif.c b/drivers/media/platform/davinci/isif.c index 99faea2e84c6..78e37cf3470f 100644 --- a/drivers/media/platform/davinci/isif.c +++ b/drivers/media/platform/davinci/isif.c @@ -1106,7 +1106,8 @@ fail_nobase_res: while (i >= 0) { res = platform_get_resource(pdev, IORESOURCE_MEM, i); - release_mem_region(res->start, resource_size(res)); + if (res) + release_mem_region(res->start, resource_size(res)); i--; } vpfe_unregister_ccdc_device(&isif_hw_dev); diff --git a/drivers/media/platform/davinci/vpbe_display.c b/drivers/media/platform/davinci/vpbe_display.c index 6d91422c4e4c..a9cd8c7a7b34 100644 --- a/drivers/media/platform/davinci/vpbe_display.c +++ b/drivers/media/platform/davinci/vpbe_display.c @@ -520,7 +520,7 @@ vpbe_disp_calculate_scale_factor(struct vpbe_display *disp_dev, else if (v_scale == 4) layer_info->v_zoom = ZOOM_X4; if (v_exp) - layer_info->h_exp = V_EXP_6_OVER_5; + layer_info->v_exp = V_EXP_6_OVER_5; } else { /* no scaling, only cropping. Set display area to crop area */ cfg->ysize = expected_ysize; diff --git a/drivers/media/platform/vivid/vivid-kthread-cap.c b/drivers/media/platform/vivid/vivid-kthread-cap.c index 81ba454a6d95..1e34ee16b792 100644 --- a/drivers/media/platform/vivid/vivid-kthread-cap.c +++ b/drivers/media/platform/vivid/vivid-kthread-cap.c @@ -763,7 +763,11 @@ static int vivid_thread_vid_cap(void *data) if (kthread_should_stop()) break; - mutex_lock(&dev->mutex); + if (!mutex_trylock(&dev->mutex)) { + schedule_timeout_uninterruptible(1); + continue; + } + cur_jiffies = jiffies; if (dev->cap_seq_resync) { dev->jiffies_vid_cap = cur_jiffies; @@ -916,8 +920,6 @@ void vivid_stop_generating_vid_cap(struct vivid_dev *dev, bool *pstreaming) /* shutdown control thread */ vivid_grab_controls(dev, false); - mutex_unlock(&dev->mutex); kthread_stop(dev->kthread_vid_cap); dev->kthread_vid_cap = NULL; - mutex_lock(&dev->mutex); } diff --git a/drivers/media/platform/vivid/vivid-kthread-out.c b/drivers/media/platform/vivid/vivid-kthread-out.c index 2c5dbdcb576a..ba38602680d6 100644 --- a/drivers/media/platform/vivid/vivid-kthread-out.c +++ b/drivers/media/platform/vivid/vivid-kthread-out.c @@ -147,7 +147,11 @@ static int vivid_thread_vid_out(void *data) if (kthread_should_stop()) break; - mutex_lock(&dev->mutex); + if (!mutex_trylock(&dev->mutex)) { + schedule_timeout_uninterruptible(1); + continue; + } + cur_jiffies = jiffies; if (dev->out_seq_resync) { dev->jiffies_vid_out = cur_jiffies; @@ -301,8 +305,6 @@ void vivid_stop_generating_vid_out(struct vivid_dev *dev, bool *pstreaming) /* shutdown control thread */ vivid_grab_controls(dev, false); - mutex_unlock(&dev->mutex); kthread_stop(dev->kthread_vid_out); dev->kthread_vid_out = NULL; - mutex_lock(&dev->mutex); } diff --git a/drivers/media/platform/vivid/vivid-sdr-cap.c b/drivers/media/platform/vivid/vivid-sdr-cap.c index 082c401764ce..4866f42c8027 100644 --- a/drivers/media/platform/vivid/vivid-sdr-cap.c +++ b/drivers/media/platform/vivid/vivid-sdr-cap.c @@ -151,7 +151,11 @@ static int vivid_thread_sdr_cap(void *data) if (kthread_should_stop()) break; - mutex_lock(&dev->mutex); + if (!mutex_trylock(&dev->mutex)) { + schedule_timeout_uninterruptible(1); + continue; + } + cur_jiffies = jiffies; if (dev->sdr_cap_seq_resync) { dev->jiffies_sdr_cap = cur_jiffies; @@ -311,10 +315,8 @@ static void sdr_cap_stop_streaming(struct vb2_queue *vq) } /* shutdown control thread */ - mutex_unlock(&dev->mutex); kthread_stop(dev->kthread_sdr_cap); dev->kthread_sdr_cap = NULL; - mutex_lock(&dev->mutex); } const struct vb2_ops vivid_sdr_cap_qops = { diff --git a/drivers/media/platform/vivid/vivid-vid-cap.c b/drivers/media/platform/vivid/vivid-vid-cap.c index 9eb0bc4a8d97..9240c375d540 100644 --- a/drivers/media/platform/vivid/vivid-vid-cap.c +++ b/drivers/media/platform/vivid/vivid-vid-cap.c @@ -253,9 +253,6 @@ static int vid_cap_start_streaming(struct vb2_queue *vq, unsigned count) if (vb2_is_streaming(&dev->vb_vid_out_q)) dev->can_loop_video = vivid_vid_can_loop(dev); - if (dev->kthread_vid_cap) - return 0; - dev->vid_cap_seq_count = 0; dprintk(dev, 1, "%s\n", __func__); for (i = 0; i < VIDEO_MAX_FRAME; i++) diff --git a/drivers/media/platform/vivid/vivid-vid-out.c b/drivers/media/platform/vivid/vivid-vid-out.c index b77acb6a7013..ffe5531dfc81 100644 --- a/drivers/media/platform/vivid/vivid-vid-out.c +++ b/drivers/media/platform/vivid/vivid-vid-out.c @@ -173,9 +173,6 @@ static int vid_out_start_streaming(struct vb2_queue *vq, unsigned count) if (vb2_is_streaming(&dev->vb_vid_cap_q)) dev->can_loop_video = vivid_vid_can_loop(dev); - if (dev->kthread_vid_out) - return 0; - dev->vid_out_seq_count = 0; dprintk(dev, 1, "%s\n", __func__); if (dev->start_streaming_error) { diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index 7a16e9ea041c..0a8d529e12cc 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -1644,8 +1644,7 @@ static void imon_incoming_packet(struct imon_context *ictx, spin_unlock_irqrestore(&ictx->kc_lock, flags); /* send touchscreen events through input subsystem if touchpad data */ - if (ictx->display_type == IMON_DISPLAY_TYPE_VGA && len == 8 && - buf[7] == 0x86) { + if (ictx->touch && len == 8 && buf[7] == 0x86) { imon_touch_event(ictx, buf); return; diff --git a/drivers/media/usb/b2c2/flexcop-usb.c b/drivers/media/usb/b2c2/flexcop-usb.c index 0bd969063392..83d3a5cf272f 100644 --- a/drivers/media/usb/b2c2/flexcop-usb.c +++ b/drivers/media/usb/b2c2/flexcop-usb.c @@ -508,6 +508,9 @@ static int flexcop_usb_probe(struct usb_interface *intf, struct flexcop_device *fc = NULL; int ret; + if (intf->cur_altsetting->desc.bNumEndpoints < 1) + return -ENODEV; + if ((fc = flexcop_device_kmalloc(sizeof(struct flexcop_usb))) == NULL) { err("out of memory\n"); return -ENOMEM; diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index d0d8f08e37c8..de80925ee4cb 100644 --- a/drivers/media/usb/cx231xx/cx231xx-video.c +++ b/drivers/media/usb/cx231xx/cx231xx-video.c @@ -1346,7 +1346,7 @@ int cx231xx_g_register(struct file *file, void *priv, ret = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, (u16)reg->reg, value, 4); reg->val = value[0] | value[1] << 8 | - value[2] << 16 | value[3] << 24; + value[2] << 16 | (u32)value[3] << 24; reg->size = 4; break; case 1: /* AFE - read byte */ diff --git a/drivers/media/usb/dvb-usb/cxusb.c b/drivers/media/usb/dvb-usb/cxusb.c index d00b27ed73a6..72bde33211b2 100644 --- a/drivers/media/usb/dvb-usb/cxusb.c +++ b/drivers/media/usb/dvb-usb/cxusb.c @@ -435,7 +435,8 @@ static int cxusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state) u8 ircode[4]; int i; - cxusb_ctrl_msg(d, CMD_GET_IR_CODE, NULL, 0, ircode, 4); + if (cxusb_ctrl_msg(d, CMD_GET_IR_CODE, NULL, 0, ircode, 4) < 0) + return 0; *event = 0; *state = REMOTE_NO_KEY_PRESSED; diff --git a/drivers/mfd/max8997.c b/drivers/mfd/max8997.c index 156ed6f92aa3..2d9ae7cf948f 100644 --- a/drivers/mfd/max8997.c +++ b/drivers/mfd/max8997.c @@ -156,12 +156,6 @@ static struct max8997_platform_data *max8997_i2c_parse_dt_pdata( pd->ono = irq_of_parse_and_map(dev->of_node, 1); - /* - * ToDo: the 'wakeup' member in the platform data is more of a linux - * specfic information. Hence, there is no binding for that yet and - * not parsed here. - */ - return pd; } @@ -249,7 +243,7 @@ static int max8997_i2c_probe(struct i2c_client *i2c, */ /* MAX8997 has a power button input. */ - device_init_wakeup(max8997->dev, pdata->wakeup); + device_init_wakeup(max8997->dev, true); return ret; diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c index 8d74806b83c1..1494e7cbd593 100644 --- a/drivers/mfd/mc13xxx-core.c +++ b/drivers/mfd/mc13xxx-core.c @@ -278,7 +278,8 @@ int mc13xxx_adc_do_conversion(struct mc13xxx *mc13xxx, unsigned int mode, if (ret) goto out; - adc0 = MC13XXX_ADC0_ADINC1 | MC13XXX_ADC0_ADINC2; + adc0 = MC13XXX_ADC0_ADINC1 | MC13XXX_ADC0_ADINC2 | + MC13XXX_ADC0_CHRGRAWDIV; adc1 = MC13XXX_ADC1_ADEN | MC13XXX_ADC1_ADTRIGIGN | MC13XXX_ADC1_ASC; if (channel > 7) diff --git a/drivers/misc/genwqe/card_utils.c b/drivers/misc/genwqe/card_utils.c index d4c719683a8a..d8961f35a9ec 100644 --- a/drivers/misc/genwqe/card_utils.c +++ b/drivers/misc/genwqe/card_utils.c @@ -298,7 +298,7 @@ static int genwqe_sgl_size(int num_pages) int genwqe_alloc_sync_sgl(struct genwqe_dev *cd, struct genwqe_sgl *sgl, void __user *user_addr, size_t user_size) { - int rc; + int ret = -ENOMEM; struct pci_dev *pci_dev = cd->pci_dev; sgl->fpage_offs = offset_in_page((unsigned long)user_addr); @@ -317,7 +317,7 @@ int genwqe_alloc_sync_sgl(struct genwqe_dev *cd, struct genwqe_sgl *sgl, if (get_order(sgl->sgl_size) > MAX_ORDER) { dev_err(&pci_dev->dev, "[%s] err: too much memory requested!\n", __func__); - return -ENOMEM; + return ret; } sgl->sgl = __genwqe_alloc_consistent(cd, sgl->sgl_size, @@ -325,7 +325,7 @@ int genwqe_alloc_sync_sgl(struct genwqe_dev *cd, struct genwqe_sgl *sgl, if (sgl->sgl == NULL) { dev_err(&pci_dev->dev, "[%s] err: no memory available!\n", __func__); - return -ENOMEM; + return ret; } /* Only use buffering on incomplete pages */ @@ -338,7 +338,7 @@ int genwqe_alloc_sync_sgl(struct genwqe_dev *cd, struct genwqe_sgl *sgl, /* Sync with user memory */ if (copy_from_user(sgl->fpage + sgl->fpage_offs, user_addr, sgl->fpage_size)) { - rc = -EFAULT; + ret = -EFAULT; goto err_out; } } @@ -351,7 +351,7 @@ int genwqe_alloc_sync_sgl(struct genwqe_dev *cd, struct genwqe_sgl *sgl, /* Sync with user memory */ if (copy_from_user(sgl->lpage, user_addr + user_size - sgl->lpage_size, sgl->lpage_size)) { - rc = -EFAULT; + ret = -EFAULT; goto err_out2; } } @@ -373,7 +373,8 @@ int genwqe_alloc_sync_sgl(struct genwqe_dev *cd, struct genwqe_sgl *sgl, sgl->sgl = NULL; sgl->sgl_dma_addr = 0; sgl->sgl_size = 0; - return -ENOMEM; + + return ret; } int genwqe_setup_sgl(struct genwqe_dev *cd, struct genwqe_sgl *sgl, diff --git a/drivers/misc/kgdbts.c b/drivers/misc/kgdbts.c index bb3a76ad80da..fc8cb855c6e6 100644 --- a/drivers/misc/kgdbts.c +++ b/drivers/misc/kgdbts.c @@ -979,6 +979,12 @@ static void kgdbts_run_tests(void) int nmi_sleep = 0; int i; + verbose = 0; + if (strstr(config, "V1")) + verbose = 1; + if (strstr(config, "V2")) + verbose = 2; + ptr = strchr(config, 'F'); if (ptr) fork_test = simple_strtol(ptr + 1, NULL, 10); @@ -1062,13 +1068,6 @@ static int kgdbts_option_setup(char *opt) return -ENOSPC; } strcpy(config, opt); - - verbose = 0; - if (strstr(config, "V1")) - verbose = 1; - if (strstr(config, "V2")) - verbose = 2; - return 0; } @@ -1080,9 +1079,6 @@ static int configure_kgdbts(void) if (!strlen(config) || isspace(config[0])) goto noconfig; - err = kgdbts_option_setup(config); - if (err) - goto noconfig; final_ack = 0; run_plant_and_detach_test(1); diff --git a/drivers/misc/mic/scif/scif_fence.c b/drivers/misc/mic/scif/scif_fence.c index 7f2c96f57066..6821d9d41585 100644 --- a/drivers/misc/mic/scif/scif_fence.c +++ b/drivers/misc/mic/scif/scif_fence.c @@ -271,7 +271,7 @@ static int _scif_prog_signal(scif_epd_t epd, dma_addr_t dst, u64 val) dma_fail: if (!x100) dma_pool_free(ep->remote_dev->signal_pool, status, - status->src_dma_addr); + src - offsetof(struct scif_status, val)); alloc_fail: return err; } diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 38ed503c637b..153c229054fe 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -2920,8 +2920,7 @@ static void mmc_blk_packed_hdr_wrq_prep(struct mmc_queue_req *mqrq, do_data_tag = (card->ext_csd.data_tag_unit_size) && (prq->cmd_flags & REQ_META) && (rq_data_dir(prq) == WRITE) && - ((brq->data.blocks * brq->data.blksz) >= - card->ext_csd.data_tag_unit_size); + blk_rq_bytes(prq) >= card->ext_csd.data_tag_unit_size; /* Argument of CMD23 */ packed_cmd_hdr[(i * 2)] = cpu_to_le32( (do_rel_wr ? MMC_CMD23_ARG_REL_WR : 0) | diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c index 0bf0d0e9dbdb..5ef25463494f 100644 --- a/drivers/mmc/host/mtk-sd.c +++ b/drivers/mmc/host/mtk-sd.c @@ -846,6 +846,7 @@ static void msdc_start_command(struct msdc_host *host, WARN_ON(host->cmd); host->cmd = cmd; + mod_delayed_work(system_wq, &host->req_timeout, DAT_TIMEOUT); if (!msdc_cmd_is_ready(host, mrq, cmd)) return; @@ -857,7 +858,6 @@ static void msdc_start_command(struct msdc_host *host, cmd->error = 0; rawcmd = msdc_cmd_prepare_raw_cmd(host, mrq, cmd); - mod_delayed_work(system_wq, &host->req_timeout, DAT_TIMEOUT); sdr_set_bits(host->base + MSDC_INTEN, cmd_ints_mask); writel(cmd->arg, host->base + SDC_ARG); diff --git a/drivers/mmc/host/sdhci-of-at91.c b/drivers/mmc/host/sdhci-of-at91.c index 4e374a05319c..91d695ee60ac 100644 --- a/drivers/mmc/host/sdhci-of-at91.c +++ b/drivers/mmc/host/sdhci-of-at91.c @@ -145,7 +145,7 @@ static int sdhci_at91_probe(struct platform_device *pdev) sdhci_get_of_property(pdev); /* HS200 is broken at this moment */ - host->quirks2 = SDHCI_QUIRK2_BROKEN_HS200; + host->quirks2 |= SDHCI_QUIRK2_BROKEN_HS200; ret = sdhci_add_host(host); if (ret) diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c index e46b4e983666..77e7542fa8e4 100644 --- a/drivers/mtd/maps/physmap_of.c +++ b/drivers/mtd/maps/physmap_of.c @@ -28,7 +28,6 @@ struct of_flash_list { struct mtd_info *mtd; struct map_info map; - struct resource *res; }; struct of_flash { @@ -53,18 +52,10 @@ static int of_flash_remove(struct platform_device *dev) mtd_concat_destroy(info->cmtd); } - for (i = 0; i < info->list_size; i++) { + for (i = 0; i < info->list_size; i++) if (info->list[i].mtd) map_destroy(info->list[i].mtd); - if (info->list[i].map.virt) - iounmap(info->list[i].map.virt); - - if (info->list[i].res) { - release_resource(info->list[i].res); - kfree(info->list[i].res); - } - } return 0; } @@ -223,10 +214,11 @@ static int of_flash_probe(struct platform_device *dev) err = -EBUSY; res_size = resource_size(&res); - info->list[i].res = request_mem_region(res.start, res_size, - dev_name(&dev->dev)); - if (!info->list[i].res) + info->list[i].map.virt = devm_ioremap_resource(&dev->dev, &res); + if (IS_ERR(info->list[i].map.virt)) { + err = PTR_ERR(info->list[i].map.virt); goto err_out; + } err = -ENXIO; width = of_get_property(dp, "bank-width", NULL); @@ -242,15 +234,6 @@ static int of_flash_probe(struct platform_device *dev) info->list[i].map.bankwidth = be32_to_cpup(width); info->list[i].map.device_node = dp; - err = -ENOMEM; - info->list[i].map.virt = ioremap(info->list[i].map.phys, - info->list[i].map.size); - if (!info->list[i].map.virt) { - dev_err(&dev->dev, "Failed to ioremap() flash" - " region\n"); - goto err_out; - } - simple_map_init(&info->list[i].map); /* diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c index 1f2785ee909f..c00a180306e5 100644 --- a/drivers/mtd/nand/sh_flctl.c +++ b/drivers/mtd/nand/sh_flctl.c @@ -428,7 +428,7 @@ static void read_fiforeg(struct sh_flctl *flctl, int rlen, int offset) /* initiate DMA transfer */ if (flctl->chan_fifo0_rx && rlen >= 32 && - flctl_dma_fifo0_transfer(flctl, buf, rlen, DMA_DEV_TO_MEM) > 0) + flctl_dma_fifo0_transfer(flctl, buf, rlen, DMA_FROM_DEVICE) > 0) goto convert; /* DMA success */ /* do polling transfer */ @@ -487,7 +487,7 @@ static void write_ec_fiforeg(struct sh_flctl *flctl, int rlen, /* initiate DMA transfer */ if (flctl->chan_fifo0_tx && rlen >= 32 && - flctl_dma_fifo0_transfer(flctl, buf, rlen, DMA_MEM_TO_DEV) > 0) + flctl_dma_fifo0_transfer(flctl, buf, rlen, DMA_TO_DEVICE) > 0) return; /* DMA success */ /* do polling transfer */ diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index fd6aff9f0052..e31b4c7d2522 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1719,7 +1719,8 @@ err_detach: slave_disable_netpoll(new_slave); err_close: - slave_dev->priv_flags &= ~IFF_BONDING; + if (!netif_is_bond_master(slave_dev)) + slave_dev->priv_flags &= ~IFF_BONDING; dev_close(slave_dev); err_restore_mac: @@ -1915,7 +1916,8 @@ static int __bond_release_one(struct net_device *bond_dev, dev_set_mtu(slave_dev, slave->original_mtu); - slave_dev->priv_flags &= ~IFF_BONDING; + if (!netif_is_bond_master(slave_dev)) + slave_dev->priv_flags &= ~IFF_BONDING; bond_free_slave(slave); @@ -3889,7 +3891,7 @@ out: * this to-be-skipped slave to send a packet out. */ old_arr = rtnl_dereference(bond->slave_arr); - for (idx = 0; idx < old_arr->count; idx++) { + for (idx = 0; old_arr != NULL && idx < old_arr->count; idx++) { if (skipslave == old_arr->arr[idx]) { old_arr->arr[idx] = old_arr->arr[old_arr->count-1]; diff --git a/drivers/net/can/c_can/c_can.c b/drivers/net/can/c_can/c_can.c index e3dccd3200d5..7d35f6737499 100644 --- a/drivers/net/can/c_can/c_can.c +++ b/drivers/net/can/c_can/c_can.c @@ -97,6 +97,9 @@ #define BTR_TSEG2_SHIFT 12 #define BTR_TSEG2_MASK (0x7 << BTR_TSEG2_SHIFT) +/* interrupt register */ +#define INT_STS_PENDING 0x8000 + /* brp extension register */ #define BRP_EXT_BRPE_MASK 0x0f #define BRP_EXT_BRPE_SHIFT 0 @@ -1029,10 +1032,16 @@ static int c_can_poll(struct napi_struct *napi, int quota) u16 curr, last = priv->last_status; int work_done = 0; - priv->last_status = curr = priv->read_reg(priv, C_CAN_STS_REG); - /* Ack status on C_CAN. D_CAN is self clearing */ - if (priv->type != BOSCH_D_CAN) - priv->write_reg(priv, C_CAN_STS_REG, LEC_UNUSED); + /* Only read the status register if a status interrupt was pending */ + if (atomic_xchg(&priv->sie_pending, 0)) { + priv->last_status = curr = priv->read_reg(priv, C_CAN_STS_REG); + /* Ack status on C_CAN. D_CAN is self clearing */ + if (priv->type != BOSCH_D_CAN) + priv->write_reg(priv, C_CAN_STS_REG, LEC_UNUSED); + } else { + /* no change detected ... */ + curr = last; + } /* handle state changes */ if ((curr & STATUS_EWARN) && (!(last & STATUS_EWARN))) { @@ -1083,10 +1092,16 @@ static irqreturn_t c_can_isr(int irq, void *dev_id) { struct net_device *dev = (struct net_device *)dev_id; struct c_can_priv *priv = netdev_priv(dev); + int reg_int; - if (!priv->read_reg(priv, C_CAN_INT_REG)) + reg_int = priv->read_reg(priv, C_CAN_INT_REG); + if (!reg_int) return IRQ_NONE; + /* save for later use */ + if (reg_int & INT_STS_PENDING) + atomic_set(&priv->sie_pending, 1); + /* disable all interrupts and schedule the NAPI */ c_can_irq_control(priv, false); napi_schedule(&priv->napi); diff --git a/drivers/net/can/c_can/c_can.h b/drivers/net/can/c_can/c_can.h index 8acdc7fa4792..d5567a7c1c6d 100644 --- a/drivers/net/can/c_can/c_can.h +++ b/drivers/net/can/c_can/c_can.h @@ -198,6 +198,7 @@ struct c_can_priv { struct net_device *dev; struct device *device; atomic_t tx_active; + atomic_t sie_pending; unsigned long tx_dir; int last_status; u16 (*read_reg) (const struct c_can_priv *priv, enum reg index); diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c index baef09b9449f..6b866d0451b2 100644 --- a/drivers/net/can/flexcan.c +++ b/drivers/net/can/flexcan.c @@ -923,6 +923,7 @@ static int flexcan_chip_start(struct net_device *dev) reg_mecr = flexcan_read(®s->mecr); reg_mecr &= ~FLEXCAN_MECR_ECRWRDIS; flexcan_write(reg_mecr, ®s->mecr); + reg_mecr |= FLEXCAN_MECR_ECCDIS; reg_mecr &= ~(FLEXCAN_MECR_NCEFAFRZ | FLEXCAN_MECR_HANCEI_MSK | FLEXCAN_MECR_FANCEI_MSK); flexcan_write(reg_mecr, ®s->mecr); diff --git a/drivers/net/can/slcan.c b/drivers/net/can/slcan.c index 9a3f15cb7ef4..9b9dfa167ffb 100644 --- a/drivers/net/can/slcan.c +++ b/drivers/net/can/slcan.c @@ -613,6 +613,7 @@ err_free_chan: sl->tty = NULL; tty->disc_data = NULL; clear_bit(SLF_INUSE, &sl->flags); + free_netdev(sl->dev); err_exit: rtnl_unlock(); diff --git a/drivers/net/can/usb/gs_usb.c b/drivers/net/can/usb/gs_usb.c index b227f81e4a7e..6982ab8777b7 100644 --- a/drivers/net/can/usb/gs_usb.c +++ b/drivers/net/can/usb/gs_usb.c @@ -617,6 +617,7 @@ static int gs_can_open(struct net_device *netdev) rc); usb_unanchor_urb(urb); + usb_free_urb(urb); break; } diff --git a/drivers/net/can/usb/peak_usb/pcan_usb.c b/drivers/net/can/usb/peak_usb/pcan_usb.c index 838545ce468d..e626c2afbbb1 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb.c @@ -108,7 +108,7 @@ struct pcan_usb_msg_context { u8 *end; u8 rec_cnt; u8 rec_idx; - u8 rec_data_idx; + u8 rec_ts_idx; struct net_device *netdev; struct pcan_usb *pdev; }; @@ -552,10 +552,15 @@ static int pcan_usb_decode_status(struct pcan_usb_msg_context *mc, mc->ptr += PCAN_USB_CMD_ARGS; if (status_len & PCAN_USB_STATUSLEN_TIMESTAMP) { - int err = pcan_usb_decode_ts(mc, !mc->rec_idx); + int err = pcan_usb_decode_ts(mc, !mc->rec_ts_idx); if (err) return err; + + /* Next packet in the buffer will have a timestamp on a single + * byte + */ + mc->rec_ts_idx++; } switch (f) { @@ -638,10 +643,13 @@ static int pcan_usb_decode_data(struct pcan_usb_msg_context *mc, u8 status_len) cf->can_dlc = get_can_dlc(rec_len); - /* first data packet timestamp is a word */ - if (pcan_usb_decode_ts(mc, !mc->rec_data_idx)) + /* Only first packet timestamp is a word */ + if (pcan_usb_decode_ts(mc, !mc->rec_ts_idx)) goto decode_failed; + /* Next packet in the buffer will have a timestamp on a single byte */ + mc->rec_ts_idx++; + /* read data */ memset(cf->data, 0x0, sizeof(cf->data)); if (status_len & PCAN_USB_STATUSLEN_RTR) { @@ -695,7 +703,6 @@ static int pcan_usb_decode_msg(struct peak_usb_device *dev, u8 *ibuf, u32 lbuf) /* handle normal can frames here */ } else { err = pcan_usb_decode_data(&mc, sl); - mc.rec_data_idx++; } } diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.c b/drivers/net/can/usb/peak_usb/pcan_usb_core.c index b1d68f49b398..8c47cc8dc896 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_core.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.c @@ -776,7 +776,7 @@ static int peak_usb_create_dev(const struct peak_usb_adapter *peak_usb_adapter, dev = netdev_priv(netdev); /* allocate a buffer large enough to send commands */ - dev->cmd_buf = kmalloc(PCAN_USB_MAX_CMD_LEN, GFP_KERNEL); + dev->cmd_buf = kzalloc(PCAN_USB_MAX_CMD_LEN, GFP_KERNEL); if (!dev->cmd_buf) { err = -ENOMEM; goto lbl_free_candev; diff --git a/drivers/net/can/usb/usb_8dev.c b/drivers/net/can/usb/usb_8dev.c index 522286cc0f9c..50d9b945089e 100644 --- a/drivers/net/can/usb/usb_8dev.c +++ b/drivers/net/can/usb/usb_8dev.c @@ -1010,9 +1010,8 @@ static void usb_8dev_disconnect(struct usb_interface *intf) netdev_info(priv->netdev, "device disconnected\n"); unregister_netdev(priv->netdev); - free_candev(priv->netdev); - unlink_all_urbs(priv); + free_candev(priv->netdev); } } diff --git a/drivers/net/ethernet/amd/am79c961a.c b/drivers/net/ethernet/amd/am79c961a.c index 87e727b921dc..1ad401fed469 100644 --- a/drivers/net/ethernet/amd/am79c961a.c +++ b/drivers/net/ethernet/amd/am79c961a.c @@ -440,7 +440,7 @@ static void am79c961_timeout(struct net_device *dev) /* * Transmit a packet */ -static int +static netdev_tx_t am79c961_sendpacket(struct sk_buff *skb, struct net_device *dev) { struct dev_priv *priv = netdev_priv(dev); diff --git a/drivers/net/ethernet/amd/atarilance.c b/drivers/net/ethernet/amd/atarilance.c index b10964e8cb54..a1dc65136d9f 100644 --- a/drivers/net/ethernet/amd/atarilance.c +++ b/drivers/net/ethernet/amd/atarilance.c @@ -339,7 +339,8 @@ static unsigned long lance_probe1( struct net_device *dev, struct lance_addr *init_rec ); static int lance_open( struct net_device *dev ); static void lance_init_ring( struct net_device *dev ); -static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ); +static netdev_tx_t lance_start_xmit(struct sk_buff *skb, + struct net_device *dev); static irqreturn_t lance_interrupt( int irq, void *dev_id ); static int lance_rx( struct net_device *dev ); static int lance_close( struct net_device *dev ); @@ -770,7 +771,8 @@ static void lance_tx_timeout (struct net_device *dev) /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */ -static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ) +static netdev_tx_t +lance_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct lance_private *lp = netdev_priv(dev); struct lance_ioreg *IO = lp->iobase; diff --git a/drivers/net/ethernet/amd/declance.c b/drivers/net/ethernet/amd/declance.c index b584b78237df..5e994f981fea 100644 --- a/drivers/net/ethernet/amd/declance.c +++ b/drivers/net/ethernet/amd/declance.c @@ -893,7 +893,7 @@ static void lance_tx_timeout(struct net_device *dev) netif_wake_queue(dev); } -static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t lance_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct lance_private *lp = netdev_priv(dev); volatile struct lance_regs *ll = lp->ll; diff --git a/drivers/net/ethernet/amd/sun3lance.c b/drivers/net/ethernet/amd/sun3lance.c index 3d8c6b2cdea4..09271665712d 100644 --- a/drivers/net/ethernet/amd/sun3lance.c +++ b/drivers/net/ethernet/amd/sun3lance.c @@ -235,7 +235,8 @@ struct lance_private { static int lance_probe( struct net_device *dev); static int lance_open( struct net_device *dev ); static void lance_init_ring( struct net_device *dev ); -static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ); +static netdev_tx_t lance_start_xmit(struct sk_buff *skb, + struct net_device *dev); static irqreturn_t lance_interrupt( int irq, void *dev_id); static int lance_rx( struct net_device *dev ); static int lance_close( struct net_device *dev ); @@ -511,7 +512,8 @@ static void lance_init_ring( struct net_device *dev ) } -static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ) +static netdev_tx_t +lance_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct lance_private *lp = netdev_priv(dev); int entry, len; diff --git a/drivers/net/ethernet/amd/sunlance.c b/drivers/net/ethernet/amd/sunlance.c index 8914170fccff..babb0a5fb8de 100644 --- a/drivers/net/ethernet/amd/sunlance.c +++ b/drivers/net/ethernet/amd/sunlance.c @@ -1106,7 +1106,7 @@ static void lance_tx_timeout(struct net_device *dev) netif_wake_queue(dev); } -static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t lance_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct lance_private *lp = netdev_priv(dev); int entry, skblen, len; diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c index 64034ff081a0..23fc244eb8a4 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c @@ -1390,7 +1390,7 @@ static int xgbe_close(struct net_device *netdev) return 0; } -static int xgbe_xmit(struct sk_buff *skb, struct net_device *netdev) +static netdev_tx_t xgbe_xmit(struct sk_buff *skb, struct net_device *netdev) { struct xgbe_prv_data *pdata = netdev_priv(netdev); struct xgbe_hw_if *hw_if = &pdata->hw_if; @@ -1399,7 +1399,7 @@ static int xgbe_xmit(struct sk_buff *skb, struct net_device *netdev) struct xgbe_ring *ring; struct xgbe_packet_data *packet; struct netdev_queue *txq; - int ret; + netdev_tx_t ret; DBGPR("-->xgbe_xmit: skb->len = %d\n", skb->len); diff --git a/drivers/net/ethernet/broadcom/bcm63xx_enet.c b/drivers/net/ethernet/broadcom/bcm63xx_enet.c index ec5834087e4b..c01ab06863b3 100644 --- a/drivers/net/ethernet/broadcom/bcm63xx_enet.c +++ b/drivers/net/ethernet/broadcom/bcm63xx_enet.c @@ -571,12 +571,13 @@ static irqreturn_t bcm_enet_isr_dma(int irq, void *dev_id) /* * tx request callback */ -static int bcm_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t +bcm_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct bcm_enet_priv *priv; struct bcm_enet_desc *desc; u32 len_stat; - int ret; + netdev_tx_t ret; priv = netdev_priv(dev); diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index d450d8b3708c..82960603da33 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -3532,6 +3532,16 @@ static void bnx2x_drv_info_iscsi_stat(struct bnx2x *bp) */ static void bnx2x_config_mf_bw(struct bnx2x *bp) { + /* Workaround for MFW bug. + * MFW is not supposed to generate BW attention in + * single function mode. + */ + if (!IS_MF(bp)) { + DP(BNX2X_MSG_MCP, + "Ignoring MF BW config in single function mode\n"); + return; + } + if (bp->link_vars.link_up) { bnx2x_cmng_fns_init(bp, true, CMNG_FNS_MINMAX); bnx2x_link_sync_notify(bp); diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index 04fe570275cd..34fae5576b60 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -1074,7 +1074,7 @@ static int bcmgenet_power_down(struct bcmgenet_priv *priv, break; } - return 0; + return ret; } static void bcmgenet_power_up(struct bcmgenet_priv *priv, diff --git a/drivers/net/ethernet/broadcom/sb1250-mac.c b/drivers/net/ethernet/broadcom/sb1250-mac.c index f557a2aaec23..73a7c8a50470 100644 --- a/drivers/net/ethernet/broadcom/sb1250-mac.c +++ b/drivers/net/ethernet/broadcom/sb1250-mac.c @@ -300,7 +300,7 @@ static enum sbmac_state sbmac_set_channel_state(struct sbmac_softc *, static void sbmac_promiscuous_mode(struct sbmac_softc *sc, int onoff); static uint64_t sbmac_addr2reg(unsigned char *ptr); static irqreturn_t sbmac_intr(int irq, void *dev_instance); -static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t sbmac_start_tx(struct sk_buff *skb, struct net_device *dev); static void sbmac_setmulti(struct sbmac_softc *sc); static int sbmac_init(struct platform_device *pldev, long long base); static int sbmac_set_speed(struct sbmac_softc *s, enum sbmac_speed speed); @@ -2033,7 +2033,7 @@ static irqreturn_t sbmac_intr(int irq,void *dev_instance) * Return value: * nothing ********************************************************************* */ -static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t sbmac_start_tx(struct sk_buff *skb, struct net_device *dev) { struct sbmac_softc *sc = netdev_priv(dev); unsigned long flags; diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c index 052c660aca80..658609c1bdab 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c @@ -266,8 +266,8 @@ void cxgb4_dcb_handle_fw_update(struct adapter *adap, enum cxgb4_dcb_state_input input = ((pcmd->u.dcb.control.all_syncd_pkd & FW_PORT_CMD_ALL_SYNCD_F) - ? CXGB4_DCB_STATE_FW_ALLSYNCED - : CXGB4_DCB_STATE_FW_INCOMPLETE); + ? CXGB4_DCB_INPUT_FW_ALLSYNCED + : CXGB4_DCB_INPUT_FW_INCOMPLETE); if (dcb->dcb_version != FW_PORT_DCB_VER_UNKNOWN) { dcb_running_version = FW_PORT_CMD_DCB_VERSION_G( diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.h index ccf24d3dc982..2c418c405c50 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.h @@ -67,7 +67,7 @@ do { \ if ((__dcb)->dcb_version == FW_PORT_DCB_VER_IEEE) \ cxgb4_dcb_state_fsm((__dev), \ - CXGB4_DCB_STATE_FW_ALLSYNCED); \ + CXGB4_DCB_INPUT_FW_ALLSYNCED); \ } while (0) /* States we can be in for a port's Data Center Bridging. diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index de23f23b41de..832ad1bd1f29 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -3482,7 +3482,7 @@ int t4_fwcache(struct adapter *adap, enum fw_params_param_dev_fwcache op) c.param[0].mnem = cpu_to_be32(FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) | FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_FWCACHE)); - c.param[0].val = (__force __be32)op; + c.param[0].val = cpu_to_be32(op); return t4_wr_mbox(adap, adap->mbox, &c, sizeof(c), NULL); } diff --git a/drivers/net/ethernet/hisilicon/hip04_eth.c b/drivers/net/ethernet/hisilicon/hip04_eth.c index def831c89d35..2a7dfac20546 100644 --- a/drivers/net/ethernet/hisilicon/hip04_eth.c +++ b/drivers/net/ethernet/hisilicon/hip04_eth.c @@ -174,6 +174,7 @@ struct hip04_priv { dma_addr_t rx_phys[RX_DESC_NUM]; unsigned int rx_head; unsigned int rx_buf_size; + unsigned int rx_cnt_remaining; struct device_node *phy_node; struct phy_device *phy; @@ -487,7 +488,6 @@ static int hip04_rx_poll(struct napi_struct *napi, int budget) struct hip04_priv *priv = container_of(napi, struct hip04_priv, napi); struct net_device *ndev = priv->ndev; struct net_device_stats *stats = &ndev->stats; - unsigned int cnt = hip04_recv_cnt(priv); struct rx_desc *desc; struct sk_buff *skb; unsigned char *buf; @@ -500,8 +500,8 @@ static int hip04_rx_poll(struct napi_struct *napi, int budget) /* clean up tx descriptors */ tx_remaining = hip04_tx_reclaim(ndev, false); - - while (cnt && !last) { + priv->rx_cnt_remaining += hip04_recv_cnt(priv); + while (priv->rx_cnt_remaining && !last) { buf = priv->rx_buf[priv->rx_head]; skb = build_skb(buf, priv->rx_buf_size); if (unlikely(!skb)) @@ -544,11 +544,13 @@ static int hip04_rx_poll(struct napi_struct *napi, int budget) hip04_set_recv_desc(priv, phys); priv->rx_head = RX_NEXT(priv->rx_head); - if (rx >= budget) + if (rx >= budget) { + --priv->rx_cnt_remaining; goto done; + } - if (--cnt == 0) - cnt = hip04_recv_cnt(priv); + if (--priv->rx_cnt_remaining == 0) + priv->rx_cnt_remaining += hip04_recv_cnt(priv); } if (!(priv->reg_inten & RCV_INT)) { @@ -633,6 +635,7 @@ static int hip04_mac_open(struct net_device *ndev) int i; priv->rx_head = 0; + priv->rx_cnt_remaining = 0; priv->tx_head = 0; priv->tx_tail = 0; hip04_reset_ppe(priv); @@ -947,7 +950,6 @@ static int hip04_remove(struct platform_device *pdev) hip04_free_ring(ndev, d); unregister_netdev(ndev); - free_irq(ndev->irq, ndev); of_node_put(priv->phy_node); cancel_work_sync(&priv->tx_timeout_task); free_netdev(ndev); diff --git a/drivers/net/ethernet/intel/e1000/e1000_ethtool.c b/drivers/net/ethernet/intel/e1000/e1000_ethtool.c index d70b2e5d5222..cbb0bdf85177 100644 --- a/drivers/net/ethernet/intel/e1000/e1000_ethtool.c +++ b/drivers/net/ethernet/intel/e1000/e1000_ethtool.c @@ -628,6 +628,7 @@ static int e1000_set_ringparam(struct net_device *netdev, for (i = 0; i < adapter->num_rx_queues; i++) rxdr[i].count = rxdr->count; + err = 0; if (netif_running(adapter->netdev)) { /* Try to get new resources before deleting old */ err = e1000_setup_all_rx_resources(adapter); @@ -648,14 +649,13 @@ static int e1000_set_ringparam(struct net_device *netdev, adapter->rx_ring = rxdr; adapter->tx_ring = txdr; err = e1000_up(adapter); - if (err) - goto err_setup; } kfree(tx_old); kfree(rx_old); clear_bit(__E1000_RESETTING, &adapter->flags); - return 0; + return err; + err_setup_tx: e1000_free_all_rx_resources(adapter); err_setup_rx: @@ -667,7 +667,6 @@ err_alloc_rx: err_alloc_tx: if (netif_running(adapter->netdev)) e1000_up(adapter); -err_setup: clear_bit(__E1000_RESETTING, &adapter->flags); return err; } diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 22c43a776c6c..756c4ea17655 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -10828,6 +10828,7 @@ static void i40e_remove(struct pci_dev *pdev) mutex_destroy(&hw->aq.asq_mutex); /* Clear all dynamic memory lists of rings, q_vectors, and VSIs */ + rtnl_lock(); i40e_clear_interrupt_scheme(pf); for (i = 0; i < pf->num_alloc_vsi; i++) { if (pf->vsi[i]) { @@ -10836,6 +10837,7 @@ static void i40e_remove(struct pci_dev *pdev) pf->vsi[i] = NULL; } } + rtnl_unlock(); for (i = 0; i < I40E_MAX_VEB; i++) { kfree(pf->veb[i]); @@ -10982,7 +10984,13 @@ static void i40e_shutdown(struct pci_dev *pdev) wr32(hw, I40E_PFPM_WUFC, (pf->wol_en ? I40E_PFPM_WUFC_MAG_MASK : 0)); + /* Since we're going to destroy queues during the + * i40e_clear_interrupt_scheme() we should hold the RTNL lock for this + * whole section + */ + rtnl_lock(); i40e_clear_interrupt_scheme(pf); + rtnl_unlock(); if (system_state == SYSTEM_POWER_OFF) { pci_wake_from_d3(pdev, pf->wol_en); diff --git a/drivers/net/ethernet/intel/i40e/i40e_ptp.c b/drivers/net/ethernet/intel/i40e/i40e_ptp.c index 565ca7c835bc..e22ebe460b13 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ptp.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ptp.c @@ -605,7 +605,8 @@ static long i40e_ptp_create_clock(struct i40e_pf *pf) if (!IS_ERR_OR_NULL(pf->ptp_clock)) return 0; - strncpy(pf->ptp_caps.name, i40e_driver_name, sizeof(pf->ptp_caps.name)); + strncpy(pf->ptp_caps.name, i40e_driver_name, + sizeof(pf->ptp_caps.name) - 1); pf->ptp_caps.owner = THIS_MODULE; pf->ptp_caps.max_adj = 999999999; pf->ptp_caps.n_ext_ts = 0; diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index e116d9a99b8e..cdb263875efb 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -1677,6 +1677,16 @@ static int i40e_vc_del_mac_addr_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) ret = I40E_ERR_INVALID_MAC_ADDR; goto error_param; } + + if (vf->pf_set_mac && + ether_addr_equal(al->list[i].addr, + vf->default_lan_addr.addr)) { + dev_err(&pf->pdev->dev, + "MAC addr %pM has been set by PF, cannot delete it for VF %d, reset VF to change MAC addr\n", + vf->default_lan_addr.addr, vf->vf_id); + ret = I40E_ERR_PARAM; + goto error_param; + } } vsi = pf->vsi[vf->lan_vsi_idx]; diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index 70ed5e5c3514..9404f38d9d0d 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -1673,7 +1673,8 @@ static void igb_check_swap_media(struct igb_adapter *adapter) if ((hw->phy.media_type == e1000_media_type_copper) && (!(connsw & E1000_CONNSW_AUTOSENSE_EN))) { swap_now = true; - } else if (!(connsw & E1000_CONNSW_SERDESD)) { + } else if ((hw->phy.media_type != e1000_media_type_copper) && + !(connsw & E1000_CONNSW_SERDESD)) { /* copper signal takes time to appear */ if (adapter->copper_tries < 4) { adapter->copper_tries++; diff --git a/drivers/net/ethernet/intel/igb/igb_ptp.c b/drivers/net/ethernet/intel/igb/igb_ptp.c index c44df87c38de..5e65d8a78c3e 100644 --- a/drivers/net/ethernet/intel/igb/igb_ptp.c +++ b/drivers/net/ethernet/intel/igb/igb_ptp.c @@ -65,9 +65,15 @@ * * The 40 bit 82580 SYSTIM overflows every * 2^40 * 10^-9 / 60 = 18.3 minutes. + * + * SYSTIM is converted to real time using a timecounter. As + * timecounter_cyc2time() allows old timestamps, the timecounter + * needs to be updated at least once per half of the SYSTIM interval. + * Scheduling of delayed work is not very accurate, so we aim for 8 + * minutes to be sure the actual interval is shorter than 9.16 minutes. */ -#define IGB_SYSTIM_OVERFLOW_PERIOD (HZ * 60 * 9) +#define IGB_SYSTIM_OVERFLOW_PERIOD (HZ * 60 * 8) #define IGB_PTP_TX_TIMEOUT (HZ * 15) #define INCPERIOD_82576 (1 << E1000_TIMINCA_16NS_SHIFT) #define INCVALUE_82576_MASK ((1 << E1000_TIMINCA_16NS_SHIFT) - 1) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index a5b443171b8b..4521181aa0ed 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -4532,6 +4532,7 @@ static void ixgbe_fdir_filter_restore(struct ixgbe_adapter *adapter) struct ixgbe_hw *hw = &adapter->hw; struct hlist_node *node2; struct ixgbe_fdir_filter *filter; + u64 action; spin_lock(&adapter->fdir_perfect_lock); @@ -4540,12 +4541,17 @@ static void ixgbe_fdir_filter_restore(struct ixgbe_adapter *adapter) hlist_for_each_entry_safe(filter, node2, &adapter->fdir_filter_list, fdir_node) { + action = filter->action; + if (action != IXGBE_FDIR_DROP_QUEUE && action != 0) + action = + (action >> ETHTOOL_RX_FLOW_SPEC_RING_VF_OFF) - 1; + ixgbe_fdir_write_perfect_filter_82599(hw, &filter->filter, filter->sw_idx, - (filter->action == IXGBE_FDIR_DROP_QUEUE) ? + (action == IXGBE_FDIR_DROP_QUEUE) ? IXGBE_FDIR_DROP_QUEUE : - adapter->rx_ring[filter->action]->reg_idx); + adapter->rx_ring[action]->reg_idx); } spin_unlock(&adapter->fdir_perfect_lock); diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c index fcd1e6b3950d..b52491f09a4d 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c @@ -1667,6 +1667,7 @@ static int mlx4_en_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd, err = mlx4_en_get_flow(dev, cmd, cmd->fs.location); break; case ETHTOOL_GRXCLSRLALL: + cmd->data = MAX_NUM_OF_FS_RULES; while ((!err || err == -ENOENT) && priority < cmd->rule_cnt) { err = mlx4_en_get_flow(dev, cmd, i); if (!err) diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c index 37dfdb1329f4..170a49a6803e 100644 --- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c +++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c @@ -463,12 +463,31 @@ void mlx4_init_quotas(struct mlx4_dev *dev) priv->mfunc.master.res_tracker.res_alloc[RES_MPT].quota[pf]; } -static int get_max_gauranteed_vfs_counter(struct mlx4_dev *dev) +static int +mlx4_calc_res_counter_guaranteed(struct mlx4_dev *dev, + struct resource_allocator *res_alloc, + int vf) { - /* reduce the sink counter */ - return (dev->caps.max_counters - 1 - - (MLX4_PF_COUNTERS_PER_PORT * MLX4_MAX_PORTS)) - / MLX4_MAX_PORTS; + struct mlx4_active_ports actv_ports; + int ports, counters_guaranteed; + + /* For master, only allocate according to the number of phys ports */ + if (vf == mlx4_master_func_num(dev)) + return MLX4_PF_COUNTERS_PER_PORT * dev->caps.num_ports; + + /* calculate real number of ports for the VF */ + actv_ports = mlx4_get_active_ports(dev, vf); + ports = bitmap_weight(actv_ports.ports, dev->caps.num_ports); + counters_guaranteed = ports * MLX4_VF_COUNTERS_PER_PORT; + + /* If we do not have enough counters for this VF, do not + * allocate any for it. '-1' to reduce the sink counter. + */ + if ((res_alloc->res_reserved + counters_guaranteed) > + (dev->caps.max_counters - 1)) + return 0; + + return counters_guaranteed; } int mlx4_init_resource_tracker(struct mlx4_dev *dev) @@ -476,7 +495,6 @@ int mlx4_init_resource_tracker(struct mlx4_dev *dev) struct mlx4_priv *priv = mlx4_priv(dev); int i, j; int t; - int max_vfs_guarantee_counter = get_max_gauranteed_vfs_counter(dev); priv->mfunc.master.res_tracker.slave_list = kzalloc(dev->num_slaves * sizeof(struct slave_list), @@ -593,16 +611,8 @@ int mlx4_init_resource_tracker(struct mlx4_dev *dev) break; case RES_COUNTER: res_alloc->quota[t] = dev->caps.max_counters; - if (t == mlx4_master_func_num(dev)) - res_alloc->guaranteed[t] = - MLX4_PF_COUNTERS_PER_PORT * - MLX4_MAX_PORTS; - else if (t <= max_vfs_guarantee_counter) - res_alloc->guaranteed[t] = - MLX4_VF_COUNTERS_PER_PORT * - MLX4_MAX_PORTS; - else - res_alloc->guaranteed[t] = 0; + res_alloc->guaranteed[t] = + mlx4_calc_res_counter_guaranteed(dev, res_alloc, t); res_alloc->res_free -= res_alloc->guaranteed[t]; break; default: diff --git a/drivers/net/ethernet/micrel/ks8695net.c b/drivers/net/ethernet/micrel/ks8695net.c index a8522d8af95d..2126286b72e9 100644 --- a/drivers/net/ethernet/micrel/ks8695net.c +++ b/drivers/net/ethernet/micrel/ks8695net.c @@ -1156,7 +1156,7 @@ ks8695_timeout(struct net_device *ndev) * sk_buff and adds it to the TX ring. It then kicks the TX DMA * engine to ensure transmission begins. */ -static int +static netdev_tx_t ks8695_start_xmit(struct sk_buff *skb, struct net_device *ndev) { struct ks8695_priv *ksp = netdev_priv(ndev); diff --git a/drivers/net/ethernet/micrel/ks8851_mll.c b/drivers/net/ethernet/micrel/ks8851_mll.c index 2fc5cd56c0a8..8dc1f0277117 100644 --- a/drivers/net/ethernet/micrel/ks8851_mll.c +++ b/drivers/net/ethernet/micrel/ks8851_mll.c @@ -1020,9 +1020,9 @@ static void ks_write_qmu(struct ks_net *ks, u8 *pdata, u16 len) * spin_lock_irqsave is required because tx and rx should be mutual exclusive. * So while tx is in-progress, prevent IRQ interrupt from happenning. */ -static int ks_start_xmit(struct sk_buff *skb, struct net_device *netdev) +static netdev_tx_t ks_start_xmit(struct sk_buff *skb, struct net_device *netdev) { - int retv = NETDEV_TX_OK; + netdev_tx_t retv = NETDEV_TX_OK; struct ks_net *ks = netdev_priv(netdev); disable_irq(netdev->irq); diff --git a/drivers/net/ethernet/qlogic/qede/qede_main.c b/drivers/net/ethernet/qlogic/qede/qede_main.c index f4657a2e730a..8b63c9d183a2 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_main.c +++ b/drivers/net/ethernet/qlogic/qede/qede_main.c @@ -1465,8 +1465,16 @@ enum qede_remove_mode { static void __qede_remove(struct pci_dev *pdev, enum qede_remove_mode mode) { struct net_device *ndev = pci_get_drvdata(pdev); - struct qede_dev *edev = netdev_priv(ndev); - struct qed_dev *cdev = edev->cdev; + struct qede_dev *edev; + struct qed_dev *cdev; + + if (!ndev) { + dev_info(&pdev->dev, "Device has already been removed\n"); + return; + } + + edev = netdev_priv(ndev); + cdev = edev->cdev; DP_INFO(edev, "Starting qede_remove\n"); diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.c index a72bcddf160a..178e7236eeb5 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.c @@ -883,7 +883,7 @@ static u8 qlcnic_dcb_get_capability(struct net_device *netdev, int capid, struct qlcnic_adapter *adapter = netdev_priv(netdev); if (!test_bit(QLCNIC_DCB_STATE, &adapter->dcb->state)) - return 0; + return 1; switch (capid) { case DCB_CAP_ATTR_PG: diff --git a/drivers/net/ethernet/sfc/ptp.c b/drivers/net/ethernet/sfc/ptp.c index c771e0af4e06..ffb2544f8574 100644 --- a/drivers/net/ethernet/sfc/ptp.c +++ b/drivers/net/ethernet/sfc/ptp.c @@ -1320,7 +1320,8 @@ void efx_ptp_remove(struct efx_nic *efx) (void)efx_ptp_disable(efx); cancel_work_sync(&efx->ptp_data->work); - cancel_work_sync(&efx->ptp_data->pps_work); + if (efx->ptp_data->pps_workwq) + cancel_work_sync(&efx->ptp_data->pps_work); skb_queue_purge(&efx->ptp_data->rxq); skb_queue_purge(&efx->ptp_data->txq); diff --git a/drivers/net/ethernet/smsc/smc911x.c b/drivers/net/ethernet/smsc/smc911x.c index bd64eb982e52..37fb6dfc1087 100644 --- a/drivers/net/ethernet/smsc/smc911x.c +++ b/drivers/net/ethernet/smsc/smc911x.c @@ -511,7 +511,8 @@ static void smc911x_hardware_send_pkt(struct net_device *dev) * now, or set the card to generates an interrupt when ready * for the packet. */ -static int smc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t +smc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct smc911x_local *lp = netdev_priv(dev); unsigned int free; diff --git a/drivers/net/ethernet/smsc/smc91x.c b/drivers/net/ethernet/smsc/smc91x.c index 23a038810083..7405f537beca 100644 --- a/drivers/net/ethernet/smsc/smc91x.c +++ b/drivers/net/ethernet/smsc/smc91x.c @@ -637,7 +637,8 @@ done: if (!THROTTLE_TX_PKTS) * now, or set the card to generates an interrupt when ready * for the packet. */ -static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t +smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct smc_local *lp = netdev_priv(dev); void __iomem *ioaddr = lp->base; diff --git a/drivers/net/ethernet/smsc/smsc911x.c b/drivers/net/ethernet/smsc/smsc911x.c index 219a99b7a631..b62bf77a64f4 100644 --- a/drivers/net/ethernet/smsc/smsc911x.c +++ b/drivers/net/ethernet/smsc/smsc911x.c @@ -1677,7 +1677,8 @@ static int smsc911x_stop(struct net_device *dev) } /* Entry point for transmitting a packet */ -static int smsc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t +smsc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct smsc911x_data *pdata = netdev_priv(dev); unsigned int freespace; diff --git a/drivers/net/ethernet/toshiba/ps3_gelic_net.c b/drivers/net/ethernet/toshiba/ps3_gelic_net.c index 79f0ec4e51ac..964df98b54ea 100644 --- a/drivers/net/ethernet/toshiba/ps3_gelic_net.c +++ b/drivers/net/ethernet/toshiba/ps3_gelic_net.c @@ -845,9 +845,9 @@ static int gelic_card_kick_txdma(struct gelic_card *card, * @skb: packet to send out * @netdev: interface device structure * - * returns 0 on success, <0 on failure + * returns NETDEV_TX_OK on success, NETDEV_TX_BUSY on failure */ -int gelic_net_xmit(struct sk_buff *skb, struct net_device *netdev) +netdev_tx_t gelic_net_xmit(struct sk_buff *skb, struct net_device *netdev) { struct gelic_card *card = netdev_card(netdev); struct gelic_descr *descr; diff --git a/drivers/net/ethernet/toshiba/ps3_gelic_net.h b/drivers/net/ethernet/toshiba/ps3_gelic_net.h index 8505196be9f5..d123644bd720 100644 --- a/drivers/net/ethernet/toshiba/ps3_gelic_net.h +++ b/drivers/net/ethernet/toshiba/ps3_gelic_net.h @@ -370,7 +370,7 @@ void gelic_card_up(struct gelic_card *card); void gelic_card_down(struct gelic_card *card); int gelic_net_open(struct net_device *netdev); int gelic_net_stop(struct net_device *netdev); -int gelic_net_xmit(struct sk_buff *skb, struct net_device *netdev); +netdev_tx_t gelic_net_xmit(struct sk_buff *skb, struct net_device *netdev); void gelic_net_set_multi(struct net_device *netdev); void gelic_net_tx_timeout(struct net_device *netdev); int gelic_net_change_mtu(struct net_device *netdev, int new_mtu); diff --git a/drivers/net/ethernet/toshiba/spider_net.c b/drivers/net/ethernet/toshiba/spider_net.c index 3c54a2cae5df..8e53211aedd8 100644 --- a/drivers/net/ethernet/toshiba/spider_net.c +++ b/drivers/net/ethernet/toshiba/spider_net.c @@ -881,9 +881,9 @@ out: * @skb: packet to send out * @netdev: interface device structure * - * returns 0 on success, !0 on failure + * returns NETDEV_TX_OK on success, NETDEV_TX_BUSY on failure */ -static int +static netdev_tx_t spider_net_xmit(struct sk_buff *skb, struct net_device *netdev) { int cnt; diff --git a/drivers/net/ethernet/toshiba/tc35815.c b/drivers/net/ethernet/toshiba/tc35815.c index 868fb6306df0..3e33c165a427 100644 --- a/drivers/net/ethernet/toshiba/tc35815.c +++ b/drivers/net/ethernet/toshiba/tc35815.c @@ -475,7 +475,8 @@ static void free_rxbuf_skb(struct pci_dev *hwdev, struct sk_buff *skb, dma_addr_ /* Index to functions, as function prototypes. */ static int tc35815_open(struct net_device *dev); -static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t tc35815_send_packet(struct sk_buff *skb, + struct net_device *dev); static irqreturn_t tc35815_interrupt(int irq, void *dev_id); static int tc35815_rx(struct net_device *dev, int limit); static int tc35815_poll(struct napi_struct *napi, int budget); @@ -1279,7 +1280,8 @@ tc35815_open(struct net_device *dev) * invariant will hold if you make sure that the netif_*_queue() * calls are done at the proper times. */ -static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t +tc35815_send_packet(struct sk_buff *skb, struct net_device *dev) { struct tc35815_local *lp = netdev_priv(dev); struct TxFD *txfd; diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c index 5a1068df7038..ed6a88cf3281 100644 --- a/drivers/net/ethernet/xilinx/ll_temac_main.c +++ b/drivers/net/ethernet/xilinx/ll_temac_main.c @@ -673,7 +673,8 @@ static inline int temac_check_tx_bd_space(struct temac_local *lp, int num_frag) return 0; } -static int temac_start_xmit(struct sk_buff *skb, struct net_device *ndev) +static netdev_tx_t +temac_start_xmit(struct sk_buff *skb, struct net_device *ndev) { struct temac_local *lp = netdev_priv(ndev); struct cdmac_bd *cur_p; diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c index f1e969128a4e..7f1a57bb2ab1 100644 --- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c +++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c @@ -656,7 +656,8 @@ static inline int axienet_check_tx_bd_space(struct axienet_local *lp, * start the transmission. Additionally if checksum offloading is supported, * it populates AXI Stream Control fields with appropriate values. */ -static int axienet_start_xmit(struct sk_buff *skb, struct net_device *ndev) +static netdev_tx_t +axienet_start_xmit(struct sk_buff *skb, struct net_device *ndev) { u32 ii; u32 num_frag; diff --git a/drivers/net/ethernet/xilinx/xilinx_emaclite.c b/drivers/net/ethernet/xilinx/xilinx_emaclite.c index 4cb8b85cbf2c..909a008f9927 100644 --- a/drivers/net/ethernet/xilinx/xilinx_emaclite.c +++ b/drivers/net/ethernet/xilinx/xilinx_emaclite.c @@ -1008,9 +1008,10 @@ static int xemaclite_close(struct net_device *dev) * deferred and the Tx queue is stopped so that the deferred socket buffer can * be transmitted when the Emaclite device is free to transmit data. * - * Return: 0, always. + * Return: NETDEV_TX_OK, always. */ -static int xemaclite_send(struct sk_buff *orig_skb, struct net_device *dev) +static netdev_tx_t +xemaclite_send(struct sk_buff *orig_skb, struct net_device *dev) { struct net_local *lp = netdev_priv(dev); struct sk_buff *new_skb; @@ -1031,7 +1032,7 @@ static int xemaclite_send(struct sk_buff *orig_skb, struct net_device *dev) /* Take the time stamp now, since we can't do this in an ISR. */ skb_tx_timestamp(new_skb); spin_unlock_irqrestore(&lp->reset_lock, flags); - return 0; + return NETDEV_TX_OK; } spin_unlock_irqrestore(&lp->reset_lock, flags); @@ -1040,7 +1041,7 @@ static int xemaclite_send(struct sk_buff *orig_skb, struct net_device *dev) dev->stats.tx_bytes += len; dev_consume_skb_any(new_skb); - return 0; + return NETDEV_TX_OK; } /** diff --git a/drivers/net/ntb_netdev.c b/drivers/net/ntb_netdev.c index a9acf7156855..03009f1becdd 100644 --- a/drivers/net/ntb_netdev.c +++ b/drivers/net/ntb_netdev.c @@ -236,7 +236,7 @@ static void ntb_netdev_tx_timer(unsigned long data) struct ntb_netdev *dev = netdev_priv(ndev); if (ntb_transport_tx_free_entry(dev->qp) < tx_stop) { - mod_timer(&dev->tx_timer, jiffies + msecs_to_jiffies(tx_time)); + mod_timer(&dev->tx_timer, jiffies + usecs_to_jiffies(tx_time)); } else { /* Make sure anybody stopping the queue after this sees the new * value of ntb_transport_tx_free_entry() diff --git a/drivers/net/slip/slip.c b/drivers/net/slip/slip.c index a17d86a57734..d34bdd2f7ac7 100644 --- a/drivers/net/slip/slip.c +++ b/drivers/net/slip/slip.c @@ -860,6 +860,7 @@ err_free_chan: sl->tty = NULL; tty->disc_data = NULL; clear_bit(SLF_INUSE, &sl->flags); + free_netdev(sl->dev); err_exit: rtnl_unlock(); diff --git a/drivers/net/usb/ax88172a.c b/drivers/net/usb/ax88172a.c index 5f18fcb8dcc7..6b1d03b73eeb 100644 --- a/drivers/net/usb/ax88172a.c +++ b/drivers/net/usb/ax88172a.c @@ -243,7 +243,7 @@ static int ax88172a_bind(struct usbnet *dev, struct usb_interface *intf) /* Get the MAC address */ ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf); - if (ret < 0) { + if (ret < ETH_ALEN) { netdev_err(dev->net, "Failed to read MAC address: %d\n", ret); goto free; } diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c index 442efbccd005..bab13ccfb085 100644 --- a/drivers/net/usb/cdc_ncm.c +++ b/drivers/net/usb/cdc_ncm.c @@ -533,8 +533,8 @@ static void cdc_ncm_set_dgram_size(struct usbnet *dev, int new_size) /* read current mtu value from device */ err = usbnet_read_cmd(dev, USB_CDC_GET_MAX_DATAGRAM_SIZE, USB_TYPE_CLASS | USB_DIR_IN | USB_RECIP_INTERFACE, - 0, iface_no, &max_datagram_size, 2); - if (err < 0) { + 0, iface_no, &max_datagram_size, sizeof(max_datagram_size)); + if (err != sizeof(max_datagram_size)) { dev_dbg(&dev->intf->dev, "GET_MAX_DATAGRAM_SIZE failed\n"); goto out; } @@ -545,7 +545,7 @@ static void cdc_ncm_set_dgram_size(struct usbnet *dev, int new_size) max_datagram_size = cpu_to_le16(ctx->max_datagram_size); err = usbnet_write_cmd(dev, USB_CDC_SET_MAX_DATAGRAM_SIZE, USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_INTERFACE, - 0, iface_no, &max_datagram_size, 2); + 0, iface_no, &max_datagram_size, sizeof(max_datagram_size)); if (err < 0) dev_dbg(&dev->intf->dev, "SET_MAX_DATAGRAM_SIZE failed\n"); diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c index 45a6a7cae4bf..fc922f812280 100644 --- a/drivers/net/usb/lan78xx.c +++ b/drivers/net/usb/lan78xx.c @@ -2246,6 +2246,11 @@ static int lan78xx_bind(struct lan78xx_net *dev, struct usb_interface *intf) int i; ret = lan78xx_get_endpoints(dev, intf); + if (ret) { + netdev_warn(dev->net, "lan78xx_get_endpoints failed: %d\n", + ret); + return ret; + } dev->data[0] = (unsigned long)kzalloc(sizeof(*pdata), GFP_KERNEL); diff --git a/drivers/net/usb/sr9800.c b/drivers/net/usb/sr9800.c index 004c955c1fd1..da0ae16f5c74 100644 --- a/drivers/net/usb/sr9800.c +++ b/drivers/net/usb/sr9800.c @@ -336,7 +336,7 @@ static void sr_set_multicast(struct net_device *net) static int sr_mdio_read(struct net_device *net, int phy_id, int loc) { struct usbnet *dev = netdev_priv(net); - __le16 res; + __le16 res = 0; mutex_lock(&dev->phy_mutex); sr_set_sw_mii(dev); diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 835129152fc4..536fee1e4b70 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -2006,8 +2006,11 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, ttl = info->key.ttl; tos = info->key.tos; - if (info->options_len) + if (info->options_len) { + if (info->options_len < sizeof(*md)) + goto drop; md = ip_tunnel_info_opts(info); + } } else { md->gbp = skb->mark; } diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 17c40f06f13e..82d24f2b9c19 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -5484,7 +5484,7 @@ static int proc_BSSList_open( struct inode *inode, struct file *file ) { we have to add a spin lock... */ rc = readBSSListRid(ai, doLoseSync, &BSSList_rid); while(rc == 0 && BSSList_rid.index != cpu_to_le16(0xffff)) { - ptr += sprintf(ptr, "%pM %*s rssi = %d", + ptr += sprintf(ptr, "%pM %.*s rssi = %d", BSSList_rid.bssid, (int)BSSList_rid.ssidLen, BSSList_rid.ssid, diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index bc13e9135152..85ef500f71a8 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -862,6 +862,7 @@ struct ath10k { struct completion install_key_done; + int last_wmi_vdev_start_status; struct completion vdev_setup_done; struct completion vdev_delete_done; diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 803ec58ff20d..924f7f2fe6e6 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -958,7 +958,7 @@ static inline int ath10k_vdev_setup_sync(struct ath10k *ar) if (time_left == 0) return -ETIMEDOUT; - return 0; + return ar->last_wmi_vdev_start_status; } static int ath10k_monitor_vdev_start(struct ath10k *ar, int vdev_id) diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index b72dcce0a59b..7b8f9dd664ad 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -2458,7 +2458,8 @@ int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) status->freq, status->band, status->signal, status->rate_idx); - ieee80211_rx(ar->hw, skb); + ieee80211_rx_ni(ar->hw, skb); + return 0; } @@ -3207,18 +3208,31 @@ void ath10k_wmi_event_vdev_start_resp(struct ath10k *ar, struct sk_buff *skb) { struct wmi_vdev_start_ev_arg arg = {}; int ret; + u32 status; ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_START_RESP_EVENTID\n"); + ar->last_wmi_vdev_start_status = 0; + ret = ath10k_wmi_pull_vdev_start(ar, skb, &arg); if (ret) { ath10k_warn(ar, "failed to parse vdev start event: %d\n", ret); - return; + ar->last_wmi_vdev_start_status = ret; + goto out; } - if (WARN_ON(__le32_to_cpu(arg.status))) - return; + status = __le32_to_cpu(arg.status); + if (WARN_ON_ONCE(status)) { + ath10k_warn(ar, "vdev-start-response reports status error: %d (%s)\n", + status, (status == WMI_VDEV_START_CHAN_INVALID) ? + "chan-invalid" : "unknown"); + /* Setup is done one way or another though, so we should still + * do the completion, so don't return here. + */ + ar->last_wmi_vdev_start_status = -EINVAL; + } +out: complete(&ar->vdev_setup_done); } diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 4892c7d3cce3..5f8d7e353d1a 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -6341,11 +6341,17 @@ struct wmi_ch_info_ev_arg { __le32 mac_clk_mhz; }; +/* From 10.4 firmware, not sure all have the same values. */ +enum wmi_vdev_start_status { + WMI_VDEV_START_OK = 0, + WMI_VDEV_START_CHAN_INVALID, +}; + struct wmi_vdev_start_ev_arg { __le32 vdev_id; __le32 req_id; __le32 resp_type; /* %WMI_VDEV_RESP_ */ - __le32 status; + __le32 status; /* See wmi_vdev_start_status enum above */ }; struct wmi_peer_kick_ev_arg { diff --git a/drivers/net/wireless/ath/ath6kl/usb.c b/drivers/net/wireless/ath/ath6kl/usb.c index 9da3594fd010..fc22c5f47927 100644 --- a/drivers/net/wireless/ath/ath6kl/usb.c +++ b/drivers/net/wireless/ath/ath6kl/usb.c @@ -132,6 +132,10 @@ ath6kl_usb_alloc_urb_from_pipe(struct ath6kl_usb_pipe *pipe) struct ath6kl_urb_context *urb_context = NULL; unsigned long flags; + /* bail if this pipe is not initialized */ + if (!pipe->ar_usb) + return NULL; + spin_lock_irqsave(&pipe->ar_usb->cs_lock, flags); if (!list_empty(&pipe->urb_list_head)) { urb_context = @@ -150,6 +154,10 @@ static void ath6kl_usb_free_urb_to_pipe(struct ath6kl_usb_pipe *pipe, { unsigned long flags; + /* bail if this pipe is not initialized */ + if (!pipe->ar_usb) + return; + spin_lock_irqsave(&pipe->ar_usb->cs_lock, flags); pipe->urb_cnt++; diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index ef493271c712..c876dc2437b0 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -4114,7 +4114,7 @@ static void ar9003_hw_thermometer_apply(struct ath_hw *ah) static void ar9003_hw_thermo_cal_apply(struct ath_hw *ah) { - u32 data, ko, kg; + u32 data = 0, ko, kg; if (!AR_SREV_9462_20_OR_LATER(ah)) return; diff --git a/drivers/net/wireless/ath/ath9k/common-spectral.c b/drivers/net/wireless/ath/ath9k/common-spectral.c index 03945731eb65..ec805fe6dddb 100644 --- a/drivers/net/wireless/ath/ath9k/common-spectral.c +++ b/drivers/net/wireless/ath/ath9k/common-spectral.c @@ -411,7 +411,7 @@ ath_cmn_process_ht20_40_fft(struct ath_rx_status *rs, ath_dbg(common, SPECTRAL_SCAN, "Calculated new upper max 0x%X at %i\n", - tmp_mag, i); + tmp_mag, fft_sample_40.upper_max_index); } else for (i = dc_pos; i < SPECTRAL_HT20_40_NUM_BINS; i++) { if (fft_sample_40.data[i] == (upper_mag >> max_exp)) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c index e6c8b0d5afe0..7dae935701a7 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c @@ -1469,10 +1469,12 @@ int brcmf_p2p_notify_action_tx_complete(struct brcmf_if *ifp, return 0; if (e->event_code == BRCMF_E_ACTION_FRAME_COMPLETE) { - if (e->status == BRCMF_E_STATUS_SUCCESS) + if (e->status == BRCMF_E_STATUS_SUCCESS) { set_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED, &p2p->status); - else { + if (!p2p->wait_for_offchan_complete) + complete(&p2p->send_af_done); + } else { set_bit(BRCMF_P2P_STATUS_ACTION_TX_NOACK, &p2p->status); /* If there is no ack, we don't need to wait for * WLC_E_ACTION_FRAME_OFFCHAN_COMPLETE event @@ -1523,6 +1525,17 @@ static s32 brcmf_p2p_tx_action_frame(struct brcmf_p2p_info *p2p, p2p->af_sent_channel = le32_to_cpu(af_params->channel); p2p->af_tx_sent_jiffies = jiffies; + if (test_bit(BRCMF_P2P_STATUS_DISCOVER_LISTEN, &p2p->status) && + p2p->af_sent_channel == + ieee80211_frequency_to_channel(p2p->remain_on_channel.center_freq)) + p2p->wait_for_offchan_complete = false; + else + p2p->wait_for_offchan_complete = true; + + brcmf_dbg(TRACE, "Waiting for %s tx completion event\n", + (p2p->wait_for_offchan_complete) ? + "off-channel" : "on-channel"); + timeout = wait_for_completion_timeout(&p2p->send_af_done, msecs_to_jiffies(P2P_AF_MAX_WAIT_TIME)); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/p2p.h b/drivers/net/wireless/brcm80211/brcmfmac/p2p.h index 5d49059021a9..59e902adfc08 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/p2p.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.h @@ -125,6 +125,7 @@ struct afx_hdl { * @gon_req_action: about to send go negotiation requets frame. * @block_gon_req_tx: drop tx go negotiation requets frame. * @p2pdev_dynamically: is p2p device if created by module param or supplicant. + * @wait_for_offchan_complete: wait for off-channel tx completion event. */ struct brcmf_p2p_info { struct brcmf_cfg80211_info *cfg; @@ -146,6 +147,7 @@ struct brcmf_p2p_info { bool gon_req_action; bool block_gon_req_tx; bool p2pdev_dynamically; + bool wait_for_offchan_complete; }; s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg, bool p2pdev_forced); diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c index 61ae2768132a..a4e1eec96c60 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c @@ -502,6 +502,7 @@ brcms_ops_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) } spin_lock_bh(&wl->lock); + wl->wlc->vif = vif; wl->mute_tx = false; brcms_c_mute(wl->wlc, false); if (vif->type == NL80211_IFTYPE_STATION) @@ -519,6 +520,11 @@ brcms_ops_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) static void brcms_ops_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { + struct brcms_info *wl = hw->priv; + + spin_lock_bh(&wl->lock); + wl->wlc->vif = NULL; + spin_unlock_bh(&wl->lock); } static int brcms_ops_config(struct ieee80211_hw *hw, u32 changed) @@ -840,8 +846,8 @@ brcms_ops_ampdu_action(struct ieee80211_hw *hw, status = brcms_c_aggregatable(wl->wlc, tid); spin_unlock_bh(&wl->lock); if (!status) { - brcms_err(wl->wlc->hw->d11core, - "START: tid %d is not agg\'able\n", tid); + brcms_dbg_ht(wl->wlc->hw->d11core, + "START: tid %d is not agg\'able\n", tid); return -EINVAL; } ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); @@ -937,6 +943,25 @@ static void brcms_ops_set_tsf(struct ieee80211_hw *hw, spin_unlock_bh(&wl->lock); } +static int brcms_ops_beacon_set_tim(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, bool set) +{ + struct brcms_info *wl = hw->priv; + struct sk_buff *beacon = NULL; + u16 tim_offset = 0; + + spin_lock_bh(&wl->lock); + if (wl->wlc->vif) + beacon = ieee80211_beacon_get_tim(hw, wl->wlc->vif, + &tim_offset, NULL); + if (beacon) + brcms_c_set_new_beacon(wl->wlc, beacon, tim_offset, + wl->wlc->vif->bss_conf.dtim_period); + spin_unlock_bh(&wl->lock); + + return 0; +} + static const struct ieee80211_ops brcms_ops = { .tx = brcms_ops_tx, .start = brcms_ops_start, @@ -955,6 +980,7 @@ static const struct ieee80211_ops brcms_ops = { .flush = brcms_ops_flush, .get_tsf = brcms_ops_get_tsf, .set_tsf = brcms_ops_set_tsf, + .set_tim = brcms_ops_beacon_set_tim, }; void brcms_dpc(unsigned long data) diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.h b/drivers/net/wireless/brcm80211/brcmsmac/main.h index c4d135cff04a..9f76b880814e 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/main.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/main.h @@ -563,6 +563,7 @@ struct brcms_c_info { struct wiphy *wiphy; struct scb pri_scb; + struct ieee80211_vif *vif; struct sk_buff *beacon; u16 beacon_tim_offset; diff --git a/drivers/net/wireless/cnss2/bus.c b/drivers/net/wireless/cnss2/bus.c index e33eb647d9bb..5d77d8db4d53 100644 --- a/drivers/net/wireless/cnss2/bus.c +++ b/drivers/net/wireless/cnss2/bus.c @@ -304,7 +304,7 @@ int cnss_bus_dev_shutdown(struct cnss_plat_data *plat_priv) case CNSS_BUS_PCI: return cnss_pci_dev_shutdown(plat_priv->bus_priv); case CNSS_BUS_USB: - return 0; + return cnss_usb_dev_shutdown(plat_priv->bus_priv); case CNSS_BUS_SDIO: return cnss_sdio_dev_shutdown(plat_priv->bus_priv); default: diff --git a/drivers/net/wireless/cnss2/main.c b/drivers/net/wireless/cnss2/main.c index 4507f57f5bd8..d49e384a577b 100644 --- a/drivers/net/wireless/cnss2/main.c +++ b/drivers/net/wireless/cnss2/main.c @@ -1790,6 +1790,8 @@ static ssize_t cnss_fs_ready_store(struct device *dev, case QCN7605_DEVICE_ID: case QCN7605_COMPOSITE_DEVICE_ID: case QCN7605_STANDALONE_DEVICE_ID: + case QCN7605_VER20_STANDALONE_DEVICE_ID: + case QCN7605_VER20_COMPOSITE_DEVICE_ID: break; default: cnss_pr_err("Not supported for device ID 0x%lx\n", diff --git a/drivers/net/wireless/cnss2/usb.c b/drivers/net/wireless/cnss2/usb.c index c647e0f8e9ba..c42ef2210a41 100644 --- a/drivers/net/wireless/cnss2/usb.c +++ b/drivers/net/wireless/cnss2/usb.c @@ -54,7 +54,8 @@ int cnss_usb_dev_powerup(struct cnss_plat_data *plat_priv) case QCN7605_STANDALONE_DEVICE_ID: case QCN7605_VER20_STANDALONE_DEVICE_ID: case QCN7605_VER20_COMPOSITE_DEVICE_ID: - ret = cnss_qcn7605_usb_powerup(plat_priv); + if (test_bit(CNSS_DEV_REMOVED, &plat_priv->driver_state)) + ret = cnss_qcn7605_usb_powerup(plat_priv); break; default: cnss_pr_err("Unknown device_id found: %lu\n", @@ -160,7 +161,6 @@ int cnss_usb_unregister_driver_hdlr(struct cnss_usb_data *usb_priv) set_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state); cnss_usb_dev_shutdown(usb_priv); usb_priv->driver_ops = NULL; - usb_priv->plat_priv = NULL; return 0; } diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 1e074eaf613d..c6c2d3304dba 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -365,11 +365,20 @@ mwifiex_cfg80211_set_tx_power(struct wiphy *wiphy, struct mwifiex_power_cfg power_cfg; int dbm = MBM_TO_DBM(mbm); - if (type == NL80211_TX_POWER_FIXED) { + switch (type) { + case NL80211_TX_POWER_FIXED: power_cfg.is_power_auto = 0; + power_cfg.is_power_fixed = 1; power_cfg.power_level = dbm; - } else { + break; + case NL80211_TX_POWER_LIMITED: + power_cfg.is_power_auto = 0; + power_cfg.is_power_fixed = 0; + power_cfg.power_level = dbm; + break; + case NL80211_TX_POWER_AUTOMATIC: power_cfg.is_power_auto = 1; + break; } priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); diff --git a/drivers/net/wireless/mwifiex/ioctl.h b/drivers/net/wireless/mwifiex/ioctl.h index 4f0174c64946..4cb700160396 100644 --- a/drivers/net/wireless/mwifiex/ioctl.h +++ b/drivers/net/wireless/mwifiex/ioctl.h @@ -256,6 +256,7 @@ struct mwifiex_ds_encrypt_key { struct mwifiex_power_cfg { u32 is_power_auto; + u32 is_power_fixed; u32 power_level; }; diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index 12eedb33db7b..992f9feaea92 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -666,6 +666,9 @@ int mwifiex_set_tx_power(struct mwifiex_private *priv, txp_cfg = (struct host_cmd_ds_txpwr_cfg *) buf; txp_cfg->action = cpu_to_le16(HostCmd_ACT_GEN_SET); if (!power_cfg->is_power_auto) { + u16 dbm_min = power_cfg->is_power_fixed ? + dbm : priv->min_tx_power_level; + txp_cfg->mode = cpu_to_le32(1); pg_tlv = (struct mwifiex_types_power_group *) (buf + sizeof(struct host_cmd_ds_txpwr_cfg)); @@ -680,7 +683,7 @@ int mwifiex_set_tx_power(struct mwifiex_private *priv, pg->last_rate_code = 0x03; pg->modulation_class = MOD_CLASS_HR_DSSS; pg->power_step = 0; - pg->power_min = (s8) dbm; + pg->power_min = (s8) dbm_min; pg->power_max = (s8) dbm; pg++; /* Power group for modulation class OFDM */ @@ -688,7 +691,7 @@ int mwifiex_set_tx_power(struct mwifiex_private *priv, pg->last_rate_code = 0x07; pg->modulation_class = MOD_CLASS_OFDM; pg->power_step = 0; - pg->power_min = (s8) dbm; + pg->power_min = (s8) dbm_min; pg->power_max = (s8) dbm; pg++; /* Power group for modulation class HTBW20 */ @@ -696,7 +699,7 @@ int mwifiex_set_tx_power(struct mwifiex_private *priv, pg->last_rate_code = 0x20; pg->modulation_class = MOD_CLASS_HT; pg->power_step = 0; - pg->power_min = (s8) dbm; + pg->power_min = (s8) dbm_min; pg->power_max = (s8) dbm; pg->ht_bandwidth = HT_BW_20; pg++; @@ -705,7 +708,7 @@ int mwifiex_set_tx_power(struct mwifiex_private *priv, pg->last_rate_code = 0x20; pg->modulation_class = MOD_CLASS_HT; pg->power_step = 0; - pg->power_min = (s8) dbm; + pg->power_min = (s8) dbm_min; pg->power_max = (s8) dbm; pg->ht_bandwidth = HT_BW_40; } diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8187/leds.c b/drivers/net/wireless/realtek/rtl818x/rtl8187/leds.c index c2d5b495c179..c089540116fa 100644 --- a/drivers/net/wireless/realtek/rtl818x/rtl8187/leds.c +++ b/drivers/net/wireless/realtek/rtl818x/rtl8187/leds.c @@ -146,7 +146,7 @@ static int rtl8187_register_led(struct ieee80211_hw *dev, led->dev = dev; led->ledpin = ledpin; led->is_radio = is_radio; - strncpy(led->name, name, sizeof(led->name)); + strlcpy(led->name, name, sizeof(led->name)); led->led_dev.name = led->name; led->led_dev.default_trigger = default_trigger; diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c index 7d820c395375..52def14d55d3 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -5331,6 +5331,7 @@ static int rtl8xxxu_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, break; case WLAN_CIPHER_SUITE_TKIP: key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; + break; default: return -EOPNOTSUPP; } diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/fw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/fw.c index 62ef8209718f..5bf3712a4d49 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/fw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/fw.c @@ -234,7 +234,7 @@ static int _rtl92d_fw_init(struct ieee80211_hw *hw) rtl_read_byte(rtlpriv, FW_MAC1_READY)); } RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG, - "Polling FW ready fail!! REG_MCUFWDL:0x%08ul\n", + "Polling FW ready fail!! REG_MCUFWDL:0x%08x\n", rtl_read_dword(rtlpriv, REG_MCUFWDL)); return -1; } diff --git a/drivers/net/wireless/ti/wlcore/vendor_cmd.c b/drivers/net/wireless/ti/wlcore/vendor_cmd.c index fd4e9ba176c9..332a3a5c1c90 100644 --- a/drivers/net/wireless/ti/wlcore/vendor_cmd.c +++ b/drivers/net/wireless/ti/wlcore/vendor_cmd.c @@ -66,7 +66,7 @@ wlcore_vendor_cmd_smart_config_start(struct wiphy *wiphy, out: mutex_unlock(&wl->mutex); - return 0; + return ret; } static int diff --git a/drivers/nfc/fdp/i2c.c b/drivers/nfc/fdp/i2c.c index 2d043415f326..dc2f3d5b2a36 100644 --- a/drivers/nfc/fdp/i2c.c +++ b/drivers/nfc/fdp/i2c.c @@ -278,7 +278,7 @@ static void fdp_nci_i2c_read_device_properties(struct device *dev, *fw_vsc_cfg, len); if (r) { - devm_kfree(dev, fw_vsc_cfg); + devm_kfree(dev, *fw_vsc_cfg); goto vsc_read_err; } } else { diff --git a/drivers/nfc/st21nfca/core.c b/drivers/nfc/st21nfca/core.c index dd8b150fbffa..1826cd330468 100644 --- a/drivers/nfc/st21nfca/core.c +++ b/drivers/nfc/st21nfca/core.c @@ -726,6 +726,7 @@ static int st21nfca_hci_complete_target_discovered(struct nfc_hci_dev *hdev, NFC_PROTO_FELICA_MASK; } else { kfree_skb(nfcid_skb); + nfcid_skb = NULL; /* P2P in type A */ r = nfc_hci_get_param(hdev, ST21NFCA_RF_READER_F_GATE, ST21NFCA_RF_READER_F_NFCID1, diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.c b/drivers/ntb/hw/intel/ntb_hw_intel.c index a198f8298258..2898b39c065e 100644 --- a/drivers/ntb/hw/intel/ntb_hw_intel.c +++ b/drivers/ntb/hw/intel/ntb_hw_intel.c @@ -330,7 +330,7 @@ static inline int ndev_db_clear_mask(struct intel_ntb_dev *ndev, u64 db_bits, return 0; } -static inline int ndev_vec_mask(struct intel_ntb_dev *ndev, int db_vector) +static inline u64 ndev_vec_mask(struct intel_ntb_dev *ndev, int db_vector) { u64 shift, mask; diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index 931cc33e46f0..5d6d1bb4f110 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -457,7 +457,7 @@ static struct nvmem_device *nvmem_find(const char *name) d = bus_find_device(&nvmem_bus_type, NULL, (void *)name, nvmem_match); if (!d) - return NULL; + return ERR_PTR(-ENOENT); return to_nvmem_device(d); } diff --git a/drivers/of/base.c b/drivers/of/base.c index c6e019208d17..27783223ca5c 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -2125,7 +2125,7 @@ struct device_node *of_find_next_cache_node(const struct device_node *np) /* OF on pmac has nodes instead of properties named "l2-cache" * beneath CPU nodes. */ - if (!strcmp(np->type, "cpu")) + if (IS_ENABLED(CONFIG_PPC_PMAC) && !strcmp(np->type, "cpu")) for_each_child_of_node(np, child) if (!strcmp(child->type, "cache")) return child; diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c index 2eac3df7dd29..af9e4785b7a6 100644 --- a/drivers/of/unittest.c +++ b/drivers/of/unittest.c @@ -924,6 +924,7 @@ static int __init unittest_data_add(void) of_fdt_unflatten_tree(unittest_data, &unittest_data_node); if (!unittest_data_node) { pr_warn("%s: No tree to attach; not running tests\n", __func__); + kfree(unittest_data); return -ENODATA; } of_node_set_flag(unittest_data_node, OF_DETACHED); diff --git a/drivers/pci/host/pci-keystone.c b/drivers/pci/host/pci-keystone.c index fb682e8af74d..bdb808ba90d2 100644 --- a/drivers/pci/host/pci-keystone.c +++ b/drivers/pci/host/pci-keystone.c @@ -42,6 +42,7 @@ #define PCIE_RC_K2HK 0xb008 #define PCIE_RC_K2E 0xb009 #define PCIE_RC_K2L 0xb00a +#define PCIE_RC_K2G 0xb00b #define to_keystone_pcie(x) container_of(x, struct keystone_pcie, pp) @@ -56,6 +57,8 @@ static void quirk_limit_mrrs(struct pci_dev *dev) .class = PCI_CLASS_BRIDGE_PCI << 8, .class_mask = ~0, }, { PCI_DEVICE(PCI_VENDOR_ID_TI, PCIE_RC_K2L), .class = PCI_CLASS_BRIDGE_PCI << 8, .class_mask = ~0, }, + { PCI_DEVICE(PCI_VENDOR_ID_TI, PCIE_RC_K2G), + .class = PCI_CLASS_BRIDGE_PCI << 8, .class_mask = ~0, }, { 0, }, }; diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c index 30323114c53c..9865793b538a 100644 --- a/drivers/pci/host/pci-tegra.c +++ b/drivers/pci/host/pci-tegra.c @@ -586,12 +586,15 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA, 0x0bf1, tegra_pcie_fixup_class); DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA, 0x0e1c, tegra_pcie_fixup_class); DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA, 0x0e1d, tegra_pcie_fixup_class); -/* Tegra PCIE requires relaxed ordering */ +/* Tegra20 and Tegra30 PCIE requires relaxed ordering */ static void tegra_pcie_relax_enable(struct pci_dev *dev) { pcie_capability_set_word(dev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_RELAX_EN); } -DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, tegra_pcie_relax_enable); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, 0x0bf0, tegra_pcie_relax_enable); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, 0x0bf1, tegra_pcie_relax_enable); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, 0x0e1c, tegra_pcie_relax_enable); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, 0x0e1d, tegra_pcie_relax_enable); static int tegra_pcie_setup(int nr, struct pci_sys_data *sys) { diff --git a/drivers/pinctrl/pinctrl-at91-pio4.c b/drivers/pinctrl/pinctrl-at91-pio4.c index 9aa82a4e9e25..b4420a0bf7d6 100644 --- a/drivers/pinctrl/pinctrl-at91-pio4.c +++ b/drivers/pinctrl/pinctrl-at91-pio4.c @@ -477,7 +477,6 @@ static int atmel_pctl_dt_subnode_to_map(struct pinctrl_dev *pctldev, unsigned num_pins, num_configs, reserve; unsigned long *configs; struct property *pins; - bool has_config; u32 pinfunc; int ret, i; @@ -493,9 +492,6 @@ static int atmel_pctl_dt_subnode_to_map(struct pinctrl_dev *pctldev, return ret; } - if (num_configs) - has_config = true; - num_pins = pins->length / sizeof(u32); if (!num_pins) { dev_err(pctldev->dev, "no pins found in node %s\n", @@ -508,7 +504,7 @@ static int atmel_pctl_dt_subnode_to_map(struct pinctrl_dev *pctldev, * map for each pin. */ reserve = 1; - if (has_config && num_pins >= 1) + if (num_configs) reserve++; reserve *= num_pins; ret = pinctrl_utils_reserve_map(pctldev, map, reserved_maps, num_maps, @@ -531,7 +527,7 @@ static int atmel_pctl_dt_subnode_to_map(struct pinctrl_dev *pctldev, pinctrl_utils_add_map_mux(pctldev, map, reserved_maps, num_maps, group, func); - if (has_config) { + if (num_configs) { ret = pinctrl_utils_add_map_configs(pctldev, map, reserved_maps, num_maps, group, configs, num_configs, diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c index 0d2fc0cff35e..52bbd34f7d0d 100644 --- a/drivers/pinctrl/pinctrl-at91.c +++ b/drivers/pinctrl/pinctrl-at91.c @@ -1556,16 +1556,6 @@ void at91_pinctrl_gpio_resume(void) #define gpio_irq_set_wake NULL #endif /* CONFIG_PM */ -static struct irq_chip gpio_irqchip = { - .name = "GPIO", - .irq_ack = gpio_irq_ack, - .irq_disable = gpio_irq_mask, - .irq_mask = gpio_irq_mask, - .irq_unmask = gpio_irq_unmask, - /* .irq_set_type is set dynamically */ - .irq_set_wake = gpio_irq_set_wake, -}; - static void gpio_irq_handler(struct irq_desc *desc) { struct irq_chip *chip = irq_desc_get_chip(desc); @@ -1608,12 +1598,22 @@ static int at91_gpio_of_irq_setup(struct platform_device *pdev, struct gpio_chip *gpiochip_prev = NULL; struct at91_gpio_chip *prev = NULL; struct irq_data *d = irq_get_irq_data(at91_gpio->pioc_virq); + struct irq_chip *gpio_irqchip; int ret, i; + gpio_irqchip = devm_kzalloc(&pdev->dev, sizeof(*gpio_irqchip), GFP_KERNEL); + if (!gpio_irqchip) + return -ENOMEM; + at91_gpio->pioc_hwirq = irqd_to_hwirq(d); - /* Setup proper .irq_set_type function */ - gpio_irqchip.irq_set_type = at91_gpio->ops->irq_type; + gpio_irqchip->name = "GPIO"; + gpio_irqchip->irq_ack = gpio_irq_ack; + gpio_irqchip->irq_disable = gpio_irq_mask; + gpio_irqchip->irq_mask = gpio_irq_mask; + gpio_irqchip->irq_unmask = gpio_irq_unmask; + gpio_irqchip->irq_set_wake = gpio_irq_set_wake, + gpio_irqchip->irq_set_type = at91_gpio->ops->irq_type; /* Disable irqs of this PIO controller */ writel_relaxed(~0, at91_gpio->regbase + PIO_IDR); @@ -1624,7 +1624,7 @@ static int at91_gpio_of_irq_setup(struct platform_device *pdev, * interrupt. */ ret = gpiochip_irqchip_add(&at91_gpio->chip, - &gpio_irqchip, + gpio_irqchip, 0, handle_edge_irq, IRQ_TYPE_EDGE_BOTH); @@ -1642,7 +1642,7 @@ static int at91_gpio_of_irq_setup(struct platform_device *pdev, if (!gpiochip_prev) { /* Then register the chain on the parent IRQ */ gpiochip_set_chained_irqchip(&at91_gpio->chip, - &gpio_irqchip, + gpio_irqchip, at91_gpio->pioc_virq, gpio_irq_handler); return 0; diff --git a/drivers/pinctrl/pinctrl-zynq.c b/drivers/pinctrl/pinctrl-zynq.c index d57b5eca7b98..ad12205dd796 100644 --- a/drivers/pinctrl/pinctrl-zynq.c +++ b/drivers/pinctrl/pinctrl-zynq.c @@ -967,15 +967,12 @@ enum zynq_io_standards { zynq_iostd_max }; -/** - * enum zynq_pin_config_param - possible pin configuration parameters - * @PIN_CONFIG_IOSTANDARD: if the pin can select an IO standard, the argument to +/* + * PIN_CONFIG_IOSTANDARD: if the pin can select an IO standard, the argument to * this parameter (on a custom format) tells the driver which alternative * IO standard to use. */ -enum zynq_pin_config_param { - PIN_CONFIG_IOSTANDARD = PIN_CONFIG_END + 1, -}; +#define PIN_CONFIG_IOSTANDARD (PIN_CONFIG_END + 1) static const struct pinconf_generic_params zynq_dt_params[] = { {"io-standard", PIN_CONFIG_IOSTANDARD, zynq_iostd_lvcmos18}, diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c index 1a3727aa28a8..d18d8129e417 100644 --- a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c +++ b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c @@ -1041,10 +1041,23 @@ static int pmic_gpio_probe(struct platform_device *pdev) goto err_chip; } - ret = gpiochip_add_pin_range(&state->chip, dev_name(dev), 0, 0, npins); - if (ret) { - dev_err(dev, "failed to add pin range\n"); - goto err_range; + /* + * For DeviceTree-supported systems, the gpio core checks the + * pinctrl's device node for the "gpio-ranges" property. + * If it is present, it takes care of adding the pin ranges + * for the driver. In this case the driver can skip ahead. + * + * In order to remain compatible with older, existing DeviceTree + * files which don't set the "gpio-ranges" property or systems that + * utilize ACPI the driver has to call gpiochip_add_pin_range(). + */ + if (!of_property_read_bool(dev->of_node, "gpio-ranges")) { + ret = gpiochip_add_pin_range(&state->chip, dev_name(dev), 0, 0, + npins); + if (ret) { + dev_err(dev, "failed to add pin range\n"); + goto err_range; + } } return 0; diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 953974b5a9a9..6487453c68b5 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -566,6 +566,7 @@ config ASUS_WMI config ASUS_NB_WMI tristate "Asus Notebook WMI Driver" depends on ASUS_WMI + depends on SERIO_I8042 || SERIO_I8042 = n ---help--- This is a driver for newer Asus notebooks. It adds extra features like wireless radio and bluetooth control, leds, hotkeys, backlight... diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c index a284a2b42bcd..cccf250cd1e3 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c @@ -27,6 +27,7 @@ #include <linux/input/sparse-keymap.h> #include <linux/fb.h> #include <linux/dmi.h> +#include <linux/i8042.h> #include "asus-wmi.h" @@ -55,8 +56,34 @@ MODULE_PARM_DESC(wapf, "WAPF value"); static struct quirk_entry *quirks; +static bool asus_q500a_i8042_filter(unsigned char data, unsigned char str, + struct serio *port) +{ + static bool extended; + bool ret = false; + + if (str & I8042_STR_AUXDATA) + return false; + + if (unlikely(data == 0xe1)) { + extended = true; + ret = true; + } else if (unlikely(extended)) { + extended = false; + ret = true; + } + + return ret; +} + static struct quirk_entry quirk_asus_unknown = { .wapf = 0, + .wmi_backlight_set_devstate = true, +}; + +static struct quirk_entry quirk_asus_q500a = { + .i8042_filter = asus_q500a_i8042_filter, + .wmi_backlight_set_devstate = true, }; /* @@ -67,15 +94,42 @@ static struct quirk_entry quirk_asus_unknown = { static struct quirk_entry quirk_asus_x55u = { .wapf = 4, .wmi_backlight_power = true, + .wmi_backlight_set_devstate = true, .no_display_toggle = true, }; static struct quirk_entry quirk_asus_wapf4 = { .wapf = 4, + .wmi_backlight_set_devstate = true, }; static struct quirk_entry quirk_asus_x200ca = { .wapf = 2, + .wmi_backlight_set_devstate = true, +}; + +static struct quirk_entry quirk_no_rfkill = { + .no_rfkill = true, +}; + +static struct quirk_entry quirk_no_rfkill_wapf4 = { + .wapf = 4, + .no_rfkill = true, +}; + +static struct quirk_entry quirk_asus_ux303ub = { + .wmi_backlight_native = true, + .wmi_backlight_set_devstate = true, +}; + +static struct quirk_entry quirk_asus_x550lb = { + .wmi_backlight_set_devstate = true, + .xusb2pr = 0x01D9, +}; + +static struct quirk_entry quirk_asus_forceals = { + .wmi_backlight_set_devstate = true, + .wmi_force_als_set = true, }; static int dmi_matched(const struct dmi_system_id *dmi) @@ -87,6 +141,15 @@ static int dmi_matched(const struct dmi_system_id *dmi) static const struct dmi_system_id asus_quirks[] = { { .callback = dmi_matched, + .ident = "ASUSTeK COMPUTER INC. Q500A", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "Q500A"), + }, + .driver_data = &quirk_asus_q500a, + }, + { + .callback = dmi_matched, .ident = "ASUSTeK COMPUTER INC. U32U", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), @@ -160,7 +223,7 @@ static const struct dmi_system_id asus_quirks[] = { DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), DMI_MATCH(DMI_PRODUCT_NAME, "X456UF"), }, - .driver_data = &quirk_asus_wapf4, + .driver_data = &quirk_no_rfkill_wapf4, }, { .callback = dmi_matched, @@ -315,11 +378,85 @@ static const struct dmi_system_id asus_quirks[] = { }, .driver_data = &quirk_asus_x200ca, }, + { + .callback = dmi_matched, + .ident = "ASUSTeK COMPUTER INC. X555UB", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "X555UB"), + }, + .driver_data = &quirk_no_rfkill, + }, + { + .callback = dmi_matched, + .ident = "ASUSTeK COMPUTER INC. N552VW", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "N552VW"), + }, + .driver_data = &quirk_no_rfkill, + }, + { + .callback = dmi_matched, + .ident = "ASUSTeK COMPUTER INC. U303LB", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "U303LB"), + }, + .driver_data = &quirk_no_rfkill, + }, + { + .callback = dmi_matched, + .ident = "ASUSTeK COMPUTER INC. Z550MA", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "Z550MA"), + }, + .driver_data = &quirk_no_rfkill, + }, + { + .callback = dmi_matched, + .ident = "ASUSTeK COMPUTER INC. UX303UB", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "UX303UB"), + }, + .driver_data = &quirk_asus_ux303ub, + }, + { + .callback = dmi_matched, + .ident = "ASUSTeK COMPUTER INC. UX330UAK", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "UX330UAK"), + }, + .driver_data = &quirk_asus_forceals, + }, + { + .callback = dmi_matched, + .ident = "ASUSTeK COMPUTER INC. X550LB", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "X550LB"), + }, + .driver_data = &quirk_asus_x550lb, + }, + { + .callback = dmi_matched, + .ident = "ASUSTeK COMPUTER INC. UX430UQ", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "UX430UQ"), + }, + .driver_data = &quirk_asus_forceals, + }, {}, }; static void asus_nb_wmi_quirks(struct asus_wmi_driver *driver) { + int ret; + quirks = &quirk_asus_unknown; dmi_check_system(asus_quirks); @@ -331,6 +468,15 @@ static void asus_nb_wmi_quirks(struct asus_wmi_driver *driver) quirks->wapf = wapf; else wapf = quirks->wapf; + + if (quirks->i8042_filter) { + ret = i8042_install_filter(quirks->i8042_filter); + if (ret) { + pr_warn("Unable to install key filter\n"); + return; + } + pr_info("Using i8042 filter function for receiving events\n"); + } } static const struct key_entry asus_nb_wmi_keymap[] = { diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 7c1defaef3f5..63b5b6838e8b 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -117,6 +117,7 @@ MODULE_LICENSE("GPL"); #define ASUS_WMI_DEVID_LED6 0x00020016 /* Backlight and Brightness */ +#define ASUS_WMI_DEVID_ALS_ENABLE 0x00050001 /* Ambient Light Sensor */ #define ASUS_WMI_DEVID_BACKLIGHT 0x00050011 #define ASUS_WMI_DEVID_BRIGHTNESS 0x00050012 #define ASUS_WMI_DEVID_KBD_BACKLIGHT 0x00050021 @@ -158,6 +159,9 @@ MODULE_LICENSE("GPL"); #define ASUS_FAN_CTRL_MANUAL 1 #define ASUS_FAN_CTRL_AUTO 2 +#define USB_INTEL_XUSB2PR 0xD0 +#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI 0x9c31 + struct bios_args { u32 arg0; u32 arg1; @@ -1082,6 +1086,38 @@ exit: return result; } +static void asus_wmi_set_xusb2pr(struct asus_wmi *asus) +{ + struct pci_dev *xhci_pdev; + u32 orig_ports_available; + u32 ports_available = asus->driver->quirks->xusb2pr; + + xhci_pdev = pci_get_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI, + NULL); + + if (!xhci_pdev) + return; + + pci_read_config_dword(xhci_pdev, USB_INTEL_XUSB2PR, + &orig_ports_available); + + pci_write_config_dword(xhci_pdev, USB_INTEL_XUSB2PR, + cpu_to_le32(ports_available)); + + pr_info("set USB_INTEL_XUSB2PR old: 0x%04x, new: 0x%04x\n", + orig_ports_available, ports_available); +} + +/* + * Some devices dont support or have borcken get_als method + * but still support set method. + */ +static void asus_wmi_set_als(void) +{ + asus_wmi_set_devstate(ASUS_WMI_DEVID_ALS_ENABLE, 1, NULL); +} + /* * Hwmon device */ @@ -1733,6 +1769,7 @@ ASUS_WMI_CREATE_DEVICE_ATTR(touchpad, 0644, ASUS_WMI_DEVID_TOUCHPAD); ASUS_WMI_CREATE_DEVICE_ATTR(camera, 0644, ASUS_WMI_DEVID_CAMERA); ASUS_WMI_CREATE_DEVICE_ATTR(cardr, 0644, ASUS_WMI_DEVID_CARDREADER); ASUS_WMI_CREATE_DEVICE_ATTR(lid_resume, 0644, ASUS_WMI_DEVID_LID_RESUME); +ASUS_WMI_CREATE_DEVICE_ATTR(als_enable, 0644, ASUS_WMI_DEVID_ALS_ENABLE); static ssize_t store_cpufv(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -1759,6 +1796,7 @@ static struct attribute *platform_attributes[] = { &dev_attr_cardr.attr, &dev_attr_touchpad.attr, &dev_attr_lid_resume.attr, + &dev_attr_als_enable.attr, NULL }; @@ -1779,6 +1817,8 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj, devid = ASUS_WMI_DEVID_TOUCHPAD; else if (attr == &dev_attr_lid_resume.attr) devid = ASUS_WMI_DEVID_LID_RESUME; + else if (attr == &dev_attr_als_enable.attr) + devid = ASUS_WMI_DEVID_ALS_ENABLE; if (devid != -1) ok = !(asus_wmi_get_devstate_simple(asus, devid) < 0); @@ -2067,9 +2107,14 @@ static int asus_wmi_add(struct platform_device *pdev) if (err) goto fail_leds; - err = asus_wmi_rfkill_init(asus); - if (err) - goto fail_rfkill; + if (!asus->driver->quirks->no_rfkill) { + err = asus_wmi_rfkill_init(asus); + if (err) + goto fail_rfkill; + } + + if (asus->driver->quirks->wmi_force_als_set) + asus_wmi_set_als(); /* Some Asus desktop boards export an acpi-video backlight interface, stop this from showing up */ @@ -2080,11 +2125,17 @@ static int asus_wmi_add(struct platform_device *pdev) if (asus->driver->quirks->wmi_backlight_power) acpi_video_set_dmi_backlight_type(acpi_backlight_vendor); + if (asus->driver->quirks->wmi_backlight_native) + acpi_video_set_dmi_backlight_type(acpi_backlight_native); + + if (asus->driver->quirks->xusb2pr) + asus_wmi_set_xusb2pr(asus); + if (acpi_video_get_backlight_type() == acpi_backlight_vendor) { err = asus_wmi_backlight_init(asus); if (err && err != -ENODEV) goto fail_backlight; - } else + } else if (asus->driver->quirks->wmi_backlight_set_devstate) err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BACKLIGHT, 2, NULL); status = wmi_install_notify_handler(asus->driver->event_guid, diff --git a/drivers/platform/x86/asus-wmi.h b/drivers/platform/x86/asus-wmi.h index 4da4c8bafe70..53bab79780e2 100644 --- a/drivers/platform/x86/asus-wmi.h +++ b/drivers/platform/x86/asus-wmi.h @@ -28,6 +28,7 @@ #define _ASUS_WMI_H_ #include <linux/platform_device.h> +#include <linux/i8042.h> #define ASUS_WMI_KEY_IGNORE (-1) #define ASUS_WMI_BRN_DOWN 0x20 @@ -38,10 +39,14 @@ struct key_entry; struct asus_wmi; struct quirk_entry { + bool no_rfkill; bool hotplug_wireless; bool scalar_panel_brightness; bool store_backlight_power; bool wmi_backlight_power; + bool wmi_backlight_native; + bool wmi_backlight_set_devstate; + bool wmi_force_als_set; int wapf; /* * For machines with AMD graphic chips, it will send out WMI event @@ -50,6 +55,10 @@ struct quirk_entry { * and let the ACPI interrupt to send out the key event. */ int no_display_toggle; + u32 xusb2pr; + + bool (*i8042_filter)(unsigned char data, unsigned char str, + struct serio *serio); }; struct asus_wmi_driver { diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c index 3830dade5d69..d91111200dde 100644 --- a/drivers/power/ab8500_fg.c +++ b/drivers/power/ab8500_fg.c @@ -2447,17 +2447,14 @@ static ssize_t charge_full_store(struct ab8500_fg *di, const char *buf, size_t count) { unsigned long charge_full; - ssize_t ret; + int ret; ret = kstrtoul(buf, 10, &charge_full); + if (ret) + return ret; - dev_dbg(di->dev, "Ret %zd charge_full %lu", ret, charge_full); - - if (!ret) { - di->bat_cap.max_mah = (int) charge_full; - ret = count; - } - return ret; + di->bat_cap.max_mah = (int) charge_full; + return count; } static ssize_t charge_now_show(struct ab8500_fg *di, char *buf) @@ -2469,20 +2466,16 @@ static ssize_t charge_now_store(struct ab8500_fg *di, const char *buf, size_t count) { unsigned long charge_now; - ssize_t ret; + int ret; ret = kstrtoul(buf, 10, &charge_now); + if (ret) + return ret; - dev_dbg(di->dev, "Ret %zd charge_now %lu was %d", - ret, charge_now, di->bat_cap.prev_mah); - - if (!ret) { - di->bat_cap.user_mah = (int) charge_now; - di->flags.user_cap = true; - ret = count; - queue_delayed_work(di->fg_wq, &di->fg_periodic_work, 0); - } - return ret; + di->bat_cap.user_mah = (int) charge_now; + di->flags.user_cap = true; + queue_delayed_work(di->fg_wq, &di->fg_periodic_work, 0); + return count; } static struct ab8500_fg_sysfs_entry charge_full_attr = diff --git a/drivers/power/max8998_charger.c b/drivers/power/max8998_charger.c index b64cf0f14142..66438029bdd0 100644 --- a/drivers/power/max8998_charger.c +++ b/drivers/power/max8998_charger.c @@ -85,7 +85,7 @@ static const struct power_supply_desc max8998_battery_desc = { static int max8998_battery_probe(struct platform_device *pdev) { struct max8998_dev *iodev = dev_get_drvdata(pdev->dev.parent); - struct max8998_platform_data *pdata = dev_get_platdata(iodev->dev); + struct max8998_platform_data *pdata = iodev->pdata; struct power_supply_config psy_cfg = {}; struct max8998_battery_data *max8998; struct i2c_client *i2c; diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c index bcd4dc304f27..5b1f147b11cb 100644 --- a/drivers/power/twl4030_charger.c +++ b/drivers/power/twl4030_charger.c @@ -449,7 +449,8 @@ static void twl4030_current_worker(struct work_struct *data) if (v < USB_MIN_VOLT) { /* Back up and stop adjusting. */ - bci->usb_cur -= USB_CUR_STEP; + if (bci->usb_cur >= USB_CUR_STEP) + bci->usb_cur -= USB_CUR_STEP; bci->usb_cur_target = bci->usb_cur; } else if (bci->usb_cur >= bci->usb_cur_target || bci->usb_cur + USB_CUR_STEP > USB_MAX_CURRENT) { @@ -468,6 +469,7 @@ static void twl4030_current_worker(struct work_struct *data) static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable) { int ret; + u32 reg; if (bci->usb_mode == CHARGE_OFF) enable = false; @@ -481,14 +483,38 @@ static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable) bci->usb_enabled = 1; } - if (bci->usb_mode == CHARGE_AUTO) + if (bci->usb_mode == CHARGE_AUTO) { + /* Enable interrupts now. */ + reg = ~(u32)(TWL4030_ICHGLOW | TWL4030_ICHGEOC | + TWL4030_TBATOR2 | TWL4030_TBATOR1 | + TWL4030_BATSTS); + ret = twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, reg, + TWL4030_INTERRUPTS_BCIIMR1A); + if (ret < 0) { + dev_err(bci->dev, + "failed to unmask interrupts: %d\n", + ret); + return ret; + } /* forcing the field BCIAUTOUSB (BOOT_BCI[1]) to 1 */ ret = twl4030_clear_set_boot_bci(0, TWL4030_BCIAUTOUSB); + } /* forcing USBFASTMCHG(BCIMFSTS4[2]) to 1 */ ret = twl4030_clear_set(TWL_MODULE_MAIN_CHARGE, 0, TWL4030_USBFASTMCHG, TWL4030_BCIMFSTS4); if (bci->usb_mode == CHARGE_LINEAR) { + /* Enable interrupts now. */ + reg = ~(u32)(TWL4030_ICHGLOW | TWL4030_TBATOR2 | + TWL4030_TBATOR1 | TWL4030_BATSTS); + ret = twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, reg, + TWL4030_INTERRUPTS_BCIIMR1A); + if (ret < 0) { + dev_err(bci->dev, + "failed to unmask interrupts: %d\n", + ret); + return ret; + } twl4030_clear_set_boot_bci(TWL4030_BCIAUTOAC|TWL4030_CVENAC, 0); /* Watch dog key: WOVF acknowledge */ ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0x33, diff --git a/drivers/regulator/pfuze100-regulator.c b/drivers/regulator/pfuze100-regulator.c index c68556bf6f39..ec185502dceb 100644 --- a/drivers/regulator/pfuze100-regulator.c +++ b/drivers/regulator/pfuze100-regulator.c @@ -609,7 +609,13 @@ static int pfuze100_regulator_probe(struct i2c_client *client, /* SW2~SW4 high bit check and modify the voltage value table */ if (i >= sw_check_start && i <= sw_check_end) { - regmap_read(pfuze_chip->regmap, desc->vsel_reg, &val); + ret = regmap_read(pfuze_chip->regmap, + desc->vsel_reg, &val); + if (ret) { + dev_err(&client->dev, "Fails to read from the register.\n"); + return ret; + } + if (val & sw_hi) { if (pfuze_chip->chip_id == PFUZE3000) { desc->volt_table = pfuze3000_sw2hi; diff --git a/drivers/regulator/ti-abb-regulator.c b/drivers/regulator/ti-abb-regulator.c index d2f994298753..6d17357b3a24 100644 --- a/drivers/regulator/ti-abb-regulator.c +++ b/drivers/regulator/ti-abb-regulator.c @@ -173,19 +173,14 @@ static int ti_abb_wait_txdone(struct device *dev, struct ti_abb *abb) while (timeout++ <= abb->settling_time) { status = ti_abb_check_txdone(abb); if (status) - break; + return 0; udelay(1); } - if (timeout > abb->settling_time) { - dev_warn_ratelimited(dev, - "%s:TRANXDONE timeout(%duS) int=0x%08x\n", - __func__, timeout, readl(abb->int_base)); - return -ETIMEDOUT; - } - - return 0; + dev_warn_ratelimited(dev, "%s:TRANXDONE timeout(%duS) int=0x%08x\n", + __func__, timeout, readl(abb->int_base)); + return -ETIMEDOUT; } /** @@ -205,19 +200,14 @@ static int ti_abb_clear_all_txdone(struct device *dev, const struct ti_abb *abb) status = ti_abb_check_txdone(abb); if (!status) - break; + return 0; udelay(1); } - if (timeout > abb->settling_time) { - dev_warn_ratelimited(dev, - "%s:TRANXDONE timeout(%duS) int=0x%08x\n", - __func__, timeout, readl(abb->int_base)); - return -ETIMEDOUT; - } - - return 0; + dev_warn_ratelimited(dev, "%s:TRANXDONE timeout(%duS) int=0x%08x\n", + __func__, timeout, readl(abb->int_base)); + return -ETIMEDOUT; } /** diff --git a/drivers/rtc/rtc-s35390a.c b/drivers/rtc/rtc-s35390a.c index 00662dd28d66..9a931efd50d3 100644 --- a/drivers/rtc/rtc-s35390a.c +++ b/drivers/rtc/rtc-s35390a.c @@ -106,7 +106,7 @@ static int s35390a_get_reg(struct s35390a *s35390a, int reg, char *buf, int len) */ static int s35390a_reset(struct s35390a *s35390a, char *status1) { - char buf; + u8 buf; int ret; unsigned initcount = 0; diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 22045e7d78ac..97211f7f0cf0 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -996,7 +996,10 @@ static int __qeth_l2_open(struct net_device *dev) if (qdio_stop_irq(card->data.ccwdev, 0) >= 0) { napi_enable(&card->napi); + local_bh_disable(); napi_schedule(&card->napi); + /* kick-start the NAPI softirq: */ + local_bh_enable(); } else rc = -EIO; return rc; diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 2cc9bc1ef1e3..0d71d2e6419a 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -3031,7 +3031,10 @@ static int __qeth_l3_open(struct net_device *dev) if (qdio_stop_irq(card->data.ccwdev, 0) >= 0) { napi_enable(&card->napi); + local_bh_disable(); napi_schedule(&card->napi); + /* kick-start the NAPI softirq: */ + local_bh_enable(); } else rc = -EIO; return rc; diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 433c5e3d5733..070359a7eea1 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -1013,7 +1013,7 @@ config SCSI_SNI_53C710 config 53C700_LE_ON_BE bool - depends on SCSI_LASI700 + depends on SCSI_LASI700 || SCSI_SNI_53C710 default y config SCSI_STEX diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c index 5ee7f44cf869..830b2d2dcf20 100644 --- a/drivers/scsi/dc395x.c +++ b/drivers/scsi/dc395x.c @@ -1972,6 +1972,11 @@ static void sg_update_list(struct ScsiReqBlk *srb, u32 left) xferred -= psge->length; } else { /* Partial SG entry done */ + pci_dma_sync_single_for_cpu(srb->dcb-> + acb->dev, + srb->sg_bus_addr, + SEGMENTX_LEN, + PCI_DMA_TODEVICE); psge->length -= xferred; psge->address += xferred; srb->sg_index = idx; @@ -3450,14 +3455,12 @@ static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, } } - if (dir != PCI_DMA_NONE && scsi_sg_count(cmd)) - pci_dma_sync_sg_for_cpu(acb->dev, scsi_sglist(cmd), - scsi_sg_count(cmd), dir); - ckc_only = 0; /* Check Error Conditions */ ckc_e: + pci_unmap_srb(acb, srb); + if (cmd->cmnd[0] == INQUIRY) { unsigned char *base = NULL; struct ScsiInqData *ptr; @@ -3511,7 +3514,6 @@ static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, cmd, cmd->result); srb_free_insert(acb, srb); } - pci_unmap_srb(acb, srb); cmd->scsi_done(cmd); waiting_process_next(acb); diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c index 02cb76fd4420..6bbf2945a3e0 100644 --- a/drivers/scsi/ips.c +++ b/drivers/scsi/ips.c @@ -3500,6 +3500,7 @@ ips_send_cmd(ips_ha_t * ha, ips_scb_t * scb) case START_STOP: scb->scsi_cmd->result = DID_OK << 16; + break; case TEST_UNIT_READY: case INQUIRY: diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c index 609dafd661d1..da4583a2fa23 100644 --- a/drivers/scsi/isci/host.c +++ b/drivers/scsi/isci/host.c @@ -2717,9 +2717,9 @@ enum sci_status sci_controller_continue_io(struct isci_request *ireq) * the task management request. * @task_request: the handle to the task request object to start. */ -enum sci_task_status sci_controller_start_task(struct isci_host *ihost, - struct isci_remote_device *idev, - struct isci_request *ireq) +enum sci_status sci_controller_start_task(struct isci_host *ihost, + struct isci_remote_device *idev, + struct isci_request *ireq) { enum sci_status status; @@ -2728,7 +2728,7 @@ enum sci_task_status sci_controller_start_task(struct isci_host *ihost, "%s: SCIC Controller starting task from invalid " "state\n", __func__); - return SCI_TASK_FAILURE_INVALID_STATE; + return SCI_FAILURE_INVALID_STATE; } status = sci_remote_device_start_task(ihost, idev, ireq); diff --git a/drivers/scsi/isci/host.h b/drivers/scsi/isci/host.h index 22a9bb1abae1..15dc6e0d8deb 100644 --- a/drivers/scsi/isci/host.h +++ b/drivers/scsi/isci/host.h @@ -490,7 +490,7 @@ enum sci_status sci_controller_start_io( struct isci_remote_device *idev, struct isci_request *ireq); -enum sci_task_status sci_controller_start_task( +enum sci_status sci_controller_start_task( struct isci_host *ihost, struct isci_remote_device *idev, struct isci_request *ireq); diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c index cfd0084f1cd2..224c9c60834c 100644 --- a/drivers/scsi/isci/request.c +++ b/drivers/scsi/isci/request.c @@ -1626,9 +1626,9 @@ static enum sci_status atapi_d2h_reg_frame_handler(struct isci_request *ireq, if (status == SCI_SUCCESS) { if (ireq->stp.rsp.status & ATA_ERR) - status = SCI_IO_FAILURE_RESPONSE_VALID; + status = SCI_FAILURE_IO_RESPONSE_VALID; } else { - status = SCI_IO_FAILURE_RESPONSE_VALID; + status = SCI_FAILURE_IO_RESPONSE_VALID; } if (status != SCI_SUCCESS) { diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index 6dcaed0c1fc8..fb6eba331ac6 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -258,7 +258,7 @@ static int isci_task_execute_tmf(struct isci_host *ihost, struct isci_tmf *tmf, unsigned long timeout_ms) { DECLARE_COMPLETION_ONSTACK(completion); - enum sci_task_status status = SCI_TASK_FAILURE; + enum sci_status status = SCI_FAILURE; struct isci_request *ireq; int ret = TMF_RESP_FUNC_FAILED; unsigned long flags; @@ -301,7 +301,7 @@ static int isci_task_execute_tmf(struct isci_host *ihost, /* start the TMF io. */ status = sci_controller_start_task(ihost, idev, ireq); - if (status != SCI_TASK_SUCCESS) { + if (status != SCI_SUCCESS) { dev_dbg(&ihost->pdev->dev, "%s: start_io failed - status = 0x%x, request = %p\n", __func__, diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 0b8af186e707..fccb8991bd5b 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -788,7 +788,8 @@ static int iscsi_sw_tcp_host_get_param(struct Scsi_Host *shost, return rc; return iscsi_conn_get_addr_param((struct sockaddr_storage *) - &addr, param, buf); + &addr, + (enum iscsi_param)param, buf); default: return iscsi_host_get_param(shost, param, buf); } diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index 400eee9d7783..d44f18f773c0 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c @@ -2049,14 +2049,11 @@ static int sas_rediscover_dev(struct domain_device *dev, int phy_id, bool last) return res; } - /* delete the old link */ - if (SAS_ADDR(phy->attached_sas_addr) && - SAS_ADDR(sas_addr) != SAS_ADDR(phy->attached_sas_addr)) { - SAS_DPRINTK("ex %016llx phy 0x%x replace %016llx\n", - SAS_ADDR(dev->sas_addr), phy_id, - SAS_ADDR(phy->attached_sas_addr)); - sas_unregister_devs_sas_addr(dev, phy_id, last); - } + /* we always have to delete the old device when we went here */ + SAS_DPRINTK("ex %016llx phy 0x%x replace %016llx\n", + SAS_ADDR(dev->sas_addr), phy_id, + SAS_ADDR(phy->attached_sas_addr)); + sas_unregister_devs_sas_addr(dev, phy_id, last); return sas_discover_new(dev, phy_id); } diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 82a690924f5e..7ca8c2522c92 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -1124,6 +1124,7 @@ stop_rr_fcf_flogi: phba->fcf.fcf_flag &= ~FCF_DISCOVERY; phba->hba_flag &= ~(FCF_RR_INPROG | HBA_DEVLOSS_TMO); spin_unlock_irq(&phba->hbalock); + phba->fcf.fcf_redisc_attempted = 0; /* reset */ goto out; } if (!rc) { @@ -1138,6 +1139,7 @@ stop_rr_fcf_flogi: phba->fcf.fcf_flag &= ~FCF_DISCOVERY; phba->hba_flag &= ~(FCF_RR_INPROG | HBA_DEVLOSS_TMO); spin_unlock_irq(&phba->hbalock); + phba->fcf.fcf_redisc_attempted = 0; /* reset */ goto out; } } diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index a67950908db1..d50db2004d21 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -1966,6 +1966,26 @@ int lpfc_sli4_fcf_rr_next_proc(struct lpfc_vport *vport, uint16_t fcf_index) "failover and change port state:x%x/x%x\n", phba->pport->port_state, LPFC_VPORT_UNKNOWN); phba->pport->port_state = LPFC_VPORT_UNKNOWN; + + if (!phba->fcf.fcf_redisc_attempted) { + lpfc_unregister_fcf(phba); + + rc = lpfc_sli4_redisc_fcf_table(phba); + if (!rc) { + lpfc_printf_log(phba, KERN_INFO, LOG_FIP, + "3195 Rediscover FCF table\n"); + phba->fcf.fcf_redisc_attempted = 1; + lpfc_sli4_clear_fcf_rr_bmask(phba); + } else { + lpfc_printf_log(phba, KERN_WARNING, LOG_FIP, + "3196 Rediscover FCF table " + "failed. Status:x%x\n", rc); + } + } else { + lpfc_printf_log(phba, KERN_WARNING, LOG_FIP, + "3197 Already rediscover FCF table " + "attempted. No more retry\n"); + } goto stop_flogi_current_fcf; } else { lpfc_printf_log(phba, KERN_INFO, LOG_FIP | LOG_ELS, diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 60c21093f865..7e06fd6127cc 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -4376,7 +4376,7 @@ lpfc_sli4_async_fip_evt(struct lpfc_hba *phba, break; } /* If fast FCF failover rescan event is pending, do nothing */ - if (phba->fcf.fcf_flag & FCF_REDISC_EVT) { + if (phba->fcf.fcf_flag & (FCF_REDISC_EVT | FCF_REDISC_PEND)) { spin_unlock_irq(&phba->hbalock); break; } diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index 193733e8c823..3a4613f9fb9f 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -759,9 +759,9 @@ lpfc_disc_set_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) if (!(vport->fc_flag & FC_PT2PT)) { /* Check config parameter use-adisc or FCP-2 */ - if ((vport->cfg_use_adisc && (vport->fc_flag & FC_RSCN_MODE)) || + if (vport->cfg_use_adisc && ((vport->fc_flag & FC_RSCN_MODE) || ((ndlp->nlp_fcp_info & NLP_FCP_2_DEVICE) && - (ndlp->nlp_type & NLP_FCP_TARGET))) { + (ndlp->nlp_type & NLP_FCP_TARGET)))) { spin_lock_irq(shost->host_lock); ndlp->nlp_flag |= NLP_NPR_ADISC; spin_unlock_irq(shost->host_lock); diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index ad4f16ab7f7a..523a1058078a 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -16350,15 +16350,8 @@ next_priority: goto initial_priority; lpfc_printf_log(phba, KERN_WARNING, LOG_FIP, "2844 No roundrobin failover FCF available\n"); - if (next_fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX) - return LPFC_FCOE_FCF_NEXT_NONE; - else { - lpfc_printf_log(phba, KERN_WARNING, LOG_FIP, - "3063 Only FCF available idx %d, flag %x\n", - next_fcf_index, - phba->fcf.fcf_pri[next_fcf_index].fcf_rec.flag); - return next_fcf_index; - } + + return LPFC_FCOE_FCF_NEXT_NONE; } if (next_fcf_index < LPFC_SLI4_FCF_TBL_INDX_MAX && diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index 1e916e16ce98..0ecf92c8a288 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h @@ -237,6 +237,7 @@ struct lpfc_fcf { #define FCF_REDISC_EVT 0x100 /* FCF rediscovery event to worker thread */ #define FCF_REDISC_FOV 0x200 /* Post FCF rediscovery fast failover */ #define FCF_REDISC_PROG (FCF_REDISC_PEND | FCF_REDISC_EVT) + uint16_t fcf_redisc_attempted; uint32_t addr_mode; uint32_t eligible_fcf_cnt; struct lpfc_fcf_rec current_rec; diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 5e0bac8de638..7be968f60b59 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -3585,12 +3585,12 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr) /* * The cur_state should not last for more than max_wait secs */ - for (i = 0; i < (max_wait * 1000); i++) { + for (i = 0; i < max_wait; i++) { curr_abs_state = instance->instancet-> read_fw_status_reg(instance->reg_set); if (abs_state == curr_abs_state) { - msleep(1); + msleep(1000); } else break; } diff --git a/drivers/scsi/mpt3sas/mpt3sas_config.c b/drivers/scsi/mpt3sas/mpt3sas_config.c index a6914ec99cc0..56dc0e3be2ba 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_config.c +++ b/drivers/scsi/mpt3sas/mpt3sas_config.c @@ -677,10 +677,6 @@ mpt3sas_config_set_manufacturing_pg11(struct MPT3SAS_ADAPTER *ioc, r = _config_request(ioc, &mpi_request, mpi_reply, MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sizeof(*config_page)); - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, - sizeof(*config_page)); out: return r; } diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index 7d67a68bcc62..8735e4257028 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -3254,6 +3254,40 @@ _scsih_tm_tr_complete(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, return _scsih_check_for_pending_tm(ioc, smid); } +/** _scsih_allow_scmd_to_device - check whether scmd needs to + * issue to IOC or not. + * @ioc: per adapter object + * @scmd: pointer to scsi command object + * + * Returns true if scmd can be issued to IOC otherwise returns false. + */ +inline bool _scsih_allow_scmd_to_device(struct MPT3SAS_ADAPTER *ioc, + struct scsi_cmnd *scmd) +{ + + if (ioc->pci_error_recovery) + return false; + + if (ioc->hba_mpi_version_belonged == MPI2_VERSION) { + if (ioc->remove_host) + return false; + + return true; + } + + if (ioc->remove_host) { + + switch (scmd->cmnd[0]) { + case SYNCHRONIZE_CACHE: + case START_STOP: + return true; + default: + return false; + } + } + + return true; +} /** * _scsih_sas_control_complete - completion routine @@ -3880,7 +3914,7 @@ scsih_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *scmd) return 0; } - if (ioc->pci_error_recovery || ioc->remove_host) { + if (!(_scsih_allow_scmd_to_device(ioc, scmd))) { scmd->result = DID_NO_CONNECT << 16; scmd->scsi_done(scmd); return 0; diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c index 04e67a190652..b3490b4a046a 100644 --- a/drivers/scsi/pm8001/pm8001_hwi.c +++ b/drivers/scsi/pm8001/pm8001_hwi.c @@ -1479,6 +1479,12 @@ u32 pm8001_mpi_msg_consume(struct pm8001_hba_info *pm8001_ha, } else { u32 producer_index; void *pi_virt = circularQ->pi_virt; + /* spurious interrupt during setup if + * kexec-ing and driver doing a doorbell access + * with the pre-kexec oq interrupt setup + */ + if (!pi_virt) + break; /* Update the producer index from SPC */ producer_index = pm8001_read_32(pi_virt); circularQ->producer_index = cpu_to_le32(producer_index); diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c index 949198c01ced..3862d8b1defe 100644 --- a/drivers/scsi/pm8001/pm8001_sas.c +++ b/drivers/scsi/pm8001/pm8001_sas.c @@ -371,6 +371,13 @@ static int pm8001_task_exec(struct sas_task *task, return 0; } pm8001_ha = pm8001_find_ha_by_dev(task->dev); + if (pm8001_ha->controller_fatal_error) { + struct task_status_struct *ts = &t->task_status; + + ts->resp = SAS_TASK_UNDELIVERED; + t->task_done(t); + return 0; + } PM8001_IO_DBG(pm8001_ha, pm8001_printk("pm8001_task_exec device \n ")); spin_lock_irqsave(&pm8001_ha->lock, flags); do { @@ -463,7 +470,7 @@ err_out: dev_printk(KERN_ERR, pm8001_ha->dev, "pm8001 exec failed[%d]!\n", rc); if (!sas_protocol_ata(t->task_proto)) if (n_elem) - dma_unmap_sg(pm8001_ha->dev, t->scatter, n_elem, + dma_unmap_sg(pm8001_ha->dev, t->scatter, t->num_scatter, t->data_dir); out_done: spin_unlock_irqrestore(&pm8001_ha->lock, flags); diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h index 6628cc38316c..d8768ac41ebb 100644 --- a/drivers/scsi/pm8001/pm8001_sas.h +++ b/drivers/scsi/pm8001/pm8001_sas.h @@ -531,6 +531,7 @@ struct pm8001_hba_info { u32 logging_level; u32 fw_status; u32 smp_exp_mode; + bool controller_fatal_error; const struct firmware *fw_image; struct isr_param irq_vector[PM8001_MAX_MSIX_VEC]; }; diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c index eb4fee61df72..9edd61c063a1 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.c +++ b/drivers/scsi/pm8001/pm80xx_hwi.c @@ -572,6 +572,9 @@ static void update_main_config_table(struct pm8001_hba_info *pm8001_ha) pm8001_ha->main_cfg_tbl.pm80xx_tbl.pcs_event_log_size); pm8001_mw32(address, MAIN_PCS_EVENT_LOG_OPTION, pm8001_ha->main_cfg_tbl.pm80xx_tbl.pcs_event_log_severity); + /* Update Fatal error interrupt vector */ + pm8001_ha->main_cfg_tbl.pm80xx_tbl.fatal_err_interrupt |= + ((pm8001_ha->number_of_intr - 1) << 8); pm8001_mw32(address, MAIN_FATAL_ERROR_INTERRUPT, pm8001_ha->main_cfg_tbl.pm80xx_tbl.fatal_err_interrupt); pm8001_mw32(address, MAIN_EVENT_CRC_CHECK, @@ -1099,6 +1102,9 @@ static int pm80xx_chip_init(struct pm8001_hba_info *pm8001_ha) return -EBUSY; } + /* Initialize the controller fatal error flag */ + pm8001_ha->controller_fatal_error = false; + /* Initialize pci space address eg: mpi offset */ init_pci_device_addresses(pm8001_ha); init_default_table_values(pm8001_ha); @@ -1207,13 +1213,17 @@ pm80xx_chip_soft_rst(struct pm8001_hba_info *pm8001_ha) u32 bootloader_state; u32 ibutton0, ibutton1; - /* Check if MPI is in ready state to reset */ - if (mpi_uninit_check(pm8001_ha) != 0) { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("MPI state is not ready\n")); - return -1; + /* Process MPI table uninitialization only if FW is ready */ + if (!pm8001_ha->controller_fatal_error) { + /* Check if MPI is in ready state to reset */ + if (mpi_uninit_check(pm8001_ha) != 0) { + regval = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1); + PM8001_FAIL_DBG(pm8001_ha, pm8001_printk( + "MPI state is not ready scratch1 :0x%x\n", + regval)); + return -1; + } } - /* checked for reset register normal state; 0x0 */ regval = pm8001_cr32(pm8001_ha, 0, SPC_REG_SOFT_RESET); PM8001_INIT_DBG(pm8001_ha, @@ -3717,6 +3727,46 @@ static void process_one_iomb(struct pm8001_hba_info *pm8001_ha, void *piomb) } } +static void print_scratchpad_registers(struct pm8001_hba_info *pm8001_ha) +{ + PM8001_FAIL_DBG(pm8001_ha, + pm8001_printk("MSGU_SCRATCH_PAD_0: 0x%x\n", + pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_0))); + PM8001_FAIL_DBG(pm8001_ha, + pm8001_printk("MSGU_SCRATCH_PAD_1:0x%x\n", + pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1))); + PM8001_FAIL_DBG(pm8001_ha, + pm8001_printk("MSGU_SCRATCH_PAD_2: 0x%x\n", + pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_2))); + PM8001_FAIL_DBG(pm8001_ha, + pm8001_printk("MSGU_SCRATCH_PAD_3: 0x%x\n", + pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_3))); + PM8001_FAIL_DBG(pm8001_ha, + pm8001_printk("MSGU_HOST_SCRATCH_PAD_0: 0x%x\n", + pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_0))); + PM8001_FAIL_DBG(pm8001_ha, + pm8001_printk("MSGU_HOST_SCRATCH_PAD_1: 0x%x\n", + pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_1))); + PM8001_FAIL_DBG(pm8001_ha, + pm8001_printk("MSGU_HOST_SCRATCH_PAD_2: 0x%x\n", + pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_2))); + PM8001_FAIL_DBG(pm8001_ha, + pm8001_printk("MSGU_HOST_SCRATCH_PAD_3: 0x%x\n", + pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_3))); + PM8001_FAIL_DBG(pm8001_ha, + pm8001_printk("MSGU_HOST_SCRATCH_PAD_4: 0x%x\n", + pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_4))); + PM8001_FAIL_DBG(pm8001_ha, + pm8001_printk("MSGU_HOST_SCRATCH_PAD_5: 0x%x\n", + pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_5))); + PM8001_FAIL_DBG(pm8001_ha, + pm8001_printk("MSGU_RSVD_SCRATCH_PAD_0: 0x%x\n", + pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_6))); + PM8001_FAIL_DBG(pm8001_ha, + pm8001_printk("MSGU_RSVD_SCRATCH_PAD_1: 0x%x\n", + pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_7))); +} + static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec) { struct outbound_queue_table *circularQ; @@ -3724,10 +3774,28 @@ static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec) u8 uninitialized_var(bc); u32 ret = MPI_IO_STATUS_FAIL; unsigned long flags; + u32 regval; + if (vec == (pm8001_ha->number_of_intr - 1)) { + regval = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1); + if ((regval & SCRATCH_PAD_MIPSALL_READY) != + SCRATCH_PAD_MIPSALL_READY) { + pm8001_ha->controller_fatal_error = true; + PM8001_FAIL_DBG(pm8001_ha, pm8001_printk( + "Firmware Fatal error! Regval:0x%x\n", regval)); + print_scratchpad_registers(pm8001_ha); + return ret; + } + } spin_lock_irqsave(&pm8001_ha->lock, flags); circularQ = &pm8001_ha->outbnd_q_tbl[vec]; do { + /* spurious interrupt during setup if kexec-ing and + * driver doing a doorbell access w/ the pre-kexec oq + * interrupt setup. + */ + if (!circularQ->pi_virt) + break; ret = pm8001_mpi_msg_consume(pm8001_ha, circularQ, &pMsg1, &bc); if (MPI_IO_STATUS_SUCCESS == ret) { /* process the outbound message */ diff --git a/drivers/scsi/pm8001/pm80xx_hwi.h b/drivers/scsi/pm8001/pm80xx_hwi.h index 7a443bad6163..411b414a9a0e 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.h +++ b/drivers/scsi/pm8001/pm80xx_hwi.h @@ -1288,6 +1288,9 @@ typedef struct SASProtocolTimerConfig SASProtocolTimerConfig_t; #define SCRATCH_PAD_BOOT_LOAD_SUCCESS 0x0 #define SCRATCH_PAD_IOP0_READY 0xC00 #define SCRATCH_PAD_IOP1_READY 0x3000 +#define SCRATCH_PAD_MIPSALL_READY (SCRATCH_PAD_IOP1_READY | \ + SCRATCH_PAD_IOP0_READY | \ + SCRATCH_PAD_RAAE_READY) /* boot loader state */ #define SCRATCH_PAD1_BOOTSTATE_MASK 0x70 /* Bit 4-6 */ diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c index c26acde797f0..2d5375d67736 100644 --- a/drivers/scsi/qla2xxx/qla_bsg.c +++ b/drivers/scsi/qla2xxx/qla_bsg.c @@ -252,7 +252,7 @@ qla2x00_process_els(struct fc_bsg_job *bsg_job) srb_t *sp; const char *type; int req_sg_cnt, rsp_sg_cnt; - int rval = (DRIVER_ERROR << 16); + int rval = (DID_ERROR << 16); uint16_t nextlid = 0; if (bsg_job->request->msgcode == FC_BSG_RPT_ELS) { @@ -426,7 +426,7 @@ qla2x00_process_ct(struct fc_bsg_job *bsg_job) struct Scsi_Host *host = bsg_job->shost; scsi_qla_host_t *vha = shost_priv(host); struct qla_hw_data *ha = vha->hw; - int rval = (DRIVER_ERROR << 16); + int rval = (DID_ERROR << 16); int req_sg_cnt, rsp_sg_cnt; uint16_t loop_id; struct fc_port *fcport; @@ -1910,7 +1910,7 @@ qlafx00_mgmt_cmd(struct fc_bsg_job *bsg_job) struct Scsi_Host *host = bsg_job->shost; scsi_qla_host_t *vha = shost_priv(host); struct qla_hw_data *ha = vha->hw; - int rval = (DRIVER_ERROR << 16); + int rval = (DID_ERROR << 16); struct qla_mt_iocb_rqst_fx00 *piocb_rqst; srb_t *sp; int req_sg_cnt = 0, rsp_sg_cnt = 0; diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index ff5df33fc740..611a127f08d8 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -2962,6 +2962,10 @@ qla2x00_shutdown(struct pci_dev *pdev) /* Stop currently executing firmware. */ qla2x00_try_to_stop_firmware(vha); + /* Disable timer */ + if (vha->timer_active) + qla2x00_stop_timer(vha); + /* Turn adapter off line */ vha->flags.online = 0; diff --git a/drivers/scsi/sni_53c710.c b/drivers/scsi/sni_53c710.c index 76278072147e..b0f5220ae23a 100644 --- a/drivers/scsi/sni_53c710.c +++ b/drivers/scsi/sni_53c710.c @@ -78,10 +78,8 @@ static int snirm710_probe(struct platform_device *dev) base = res->start; hostdata = kzalloc(sizeof(*hostdata), GFP_KERNEL); - if (!hostdata) { - dev_printk(KERN_ERR, dev, "Failed to allocate host data\n"); + if (!hostdata) return -ENOMEM; - } hostdata->dev = &dev->dev; dma_set_mask(&dev->dev, DMA_BIT_MASK(32)); diff --git a/drivers/scsi/sym53c8xx_2/sym_hipd.c b/drivers/scsi/sym53c8xx_2/sym_hipd.c index c6425e3df5a0..f1c771437752 100644 --- a/drivers/scsi/sym53c8xx_2/sym_hipd.c +++ b/drivers/scsi/sym53c8xx_2/sym_hipd.c @@ -4371,6 +4371,13 @@ static void sym_nego_rejected(struct sym_hcb *np, struct sym_tcb *tp, struct sym OUTB(np, HS_PRT, HS_BUSY); } +#define sym_printk(lvl, tp, cp, fmt, v...) do { \ + if (cp) \ + scmd_printk(lvl, cp->cmd, fmt, ##v); \ + else \ + starget_printk(lvl, tp->starget, fmt, ##v); \ +} while (0) + /* * chip exception handler for programmed interrupts. */ @@ -4416,7 +4423,7 @@ static void sym_int_sir(struct sym_hcb *np) * been selected with ATN. We do not want to handle that. */ case SIR_SEL_ATN_NO_MSG_OUT: - scmd_printk(KERN_WARNING, cp->cmd, + sym_printk(KERN_WARNING, tp, cp, "No MSG OUT phase after selection with ATN\n"); goto out_stuck; /* @@ -4424,7 +4431,7 @@ static void sym_int_sir(struct sym_hcb *np) * having reselected the initiator. */ case SIR_RESEL_NO_MSG_IN: - scmd_printk(KERN_WARNING, cp->cmd, + sym_printk(KERN_WARNING, tp, cp, "No MSG IN phase after reselection\n"); goto out_stuck; /* @@ -4432,7 +4439,7 @@ static void sym_int_sir(struct sym_hcb *np) * an IDENTIFY. */ case SIR_RESEL_NO_IDENTIFY: - scmd_printk(KERN_WARNING, cp->cmd, + sym_printk(KERN_WARNING, tp, cp, "No IDENTIFY after reselection\n"); goto out_stuck; /* @@ -4461,7 +4468,7 @@ static void sym_int_sir(struct sym_hcb *np) case SIR_RESEL_ABORTED: np->lastmsg = np->msgout[0]; np->msgout[0] = M_NOOP; - scmd_printk(KERN_WARNING, cp->cmd, + sym_printk(KERN_WARNING, tp, cp, "message %x sent on bad reselection\n", np->lastmsg); goto out; /* diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index 83b53cd956aa..79fa237f76c4 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -301,7 +301,7 @@ static void omap2_mcspi_set_fifo(const struct spi_device *spi, struct omap2_mcspi_cs *cs = spi->controller_state; struct omap2_mcspi *mcspi; unsigned int wcnt; - int max_fifo_depth, fifo_depth, bytes_per_word; + int max_fifo_depth, bytes_per_word; u32 chconf, xferlevel; mcspi = spi_master_get_devdata(master); @@ -317,10 +317,6 @@ static void omap2_mcspi_set_fifo(const struct spi_device *spi, else max_fifo_depth = OMAP2_MCSPI_MAX_FIFODEPTH; - fifo_depth = gcd(t->len, max_fifo_depth); - if (fifo_depth < 2 || fifo_depth % bytes_per_word != 0) - goto disable_fifo; - wcnt = t->len / bytes_per_word; if (wcnt > OMAP2_MCSPI_MAX_FIFOWCNT) goto disable_fifo; @@ -328,16 +324,17 @@ static void omap2_mcspi_set_fifo(const struct spi_device *spi, xferlevel = wcnt << 16; if (t->rx_buf != NULL) { chconf |= OMAP2_MCSPI_CHCONF_FFER; - xferlevel |= (fifo_depth - 1) << 8; + xferlevel |= (bytes_per_word - 1) << 8; } + if (t->tx_buf != NULL) { chconf |= OMAP2_MCSPI_CHCONF_FFET; - xferlevel |= fifo_depth - 1; + xferlevel |= bytes_per_word - 1; } mcspi_write_reg(master, OMAP2_MCSPI_XFERLEVEL, xferlevel); mcspi_write_chconf0(spi, chconf); - mcspi->fifo_depth = fifo_depth; + mcspi->fifo_depth = max_fifo_depth; return; } @@ -569,7 +566,6 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) struct dma_slave_config cfg; enum dma_slave_buswidth width; unsigned es; - u32 burst; void __iomem *chstat_reg; void __iomem *irqstat_reg; int wait_res; @@ -591,22 +587,14 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) } count = xfer->len; - burst = 1; - - if (mcspi->fifo_depth > 0) { - if (count > mcspi->fifo_depth) - burst = mcspi->fifo_depth / es; - else - burst = count / es; - } memset(&cfg, 0, sizeof(cfg)); cfg.src_addr = cs->phys + OMAP2_MCSPI_RX0; cfg.dst_addr = cs->phys + OMAP2_MCSPI_TX0; cfg.src_addr_width = width; cfg.dst_addr_width = width; - cfg.src_maxburst = burst; - cfg.dst_maxburst = burst; + cfg.src_maxburst = 1; + cfg.dst_maxburst = 1; rx = xfer->rx_buf; tx = xfer->tx_buf; diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c index 035767c02072..f42ae9efb255 100644 --- a/drivers/spi/spi-rockchip.c +++ b/drivers/spi/spi-rockchip.c @@ -444,6 +444,9 @@ static void rockchip_spi_prepare_dma(struct rockchip_spi *rs) struct dma_slave_config rxconf, txconf; struct dma_async_tx_descriptor *rxdesc, *txdesc; + memset(&rxconf, 0, sizeof(rxconf)); + memset(&txconf, 0, sizeof(txconf)); + spin_lock_irqsave(&rs->lock, flags); rs->state &= ~RXBUSY; rs->state &= ~TXBUSY; diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index 03b566848da6..b4f136d04a2b 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -1198,8 +1198,8 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) i = platform_get_irq(pdev, 0); if (i < 0) { - dev_err(&pdev->dev, "cannot get platform IRQ\n"); - ret = -ENOENT; + dev_err(&pdev->dev, "cannot get IRQ\n"); + ret = i; goto err1; } diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c index e5ca8f150617..85996fa95089 100644 --- a/drivers/spi/spidev.c +++ b/drivers/spi/spidev.c @@ -716,11 +716,9 @@ static int spidev_probe(struct spi_device *spi) * compatible string, it is a Linux implementation thing * rather than a description of the hardware. */ - if (spi->dev.of_node && !of_match_device(spidev_dt_ids, &spi->dev)) { - dev_err(&spi->dev, "buggy DT: spidev listed directly in DT\n"); - WARN_ON(spi->dev.of_node && - !of_match_device(spidev_dt_ids, &spi->dev)); - } + WARN(spi->dev.of_node && + of_device_is_compatible(spi->dev.of_node, "spidev"), + "%pOF: buggy DT: spidev listed directly in DT\n", spi->dev.of_node); /* Allocate driver data */ spidev = kzalloc(sizeof(*spidev), GFP_KERNEL); diff --git a/drivers/staging/android/ion/ion_system_heap.c b/drivers/staging/android/ion/ion_system_heap.c index d7bfa5ac943b..a3d7ab5474fd 100644 --- a/drivers/staging/android/ion/ion_system_heap.c +++ b/drivers/staging/android/ion/ion_system_heap.c @@ -348,7 +348,7 @@ static int ion_system_heap_allocate(struct ion_heap *heap, struct sg_table table_sync; struct scatterlist *sg; struct scatterlist *sg_sync; - int ret; + int ret = 0; struct list_head pages; struct list_head pages_from_pool; struct page_info *info, *tmp_info; diff --git a/drivers/staging/comedi/drivers/usbduxfast.c b/drivers/staging/comedi/drivers/usbduxfast.c index 10f94ec34536..cab8a4027aeb 100644 --- a/drivers/staging/comedi/drivers/usbduxfast.c +++ b/drivers/staging/comedi/drivers/usbduxfast.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2014 Bernd Porr, mail@berndporr.me.uk + * Copyright (C) 2004-2019 Bernd Porr, mail@berndporr.me.uk * * 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 @@ -17,7 +17,7 @@ * Description: University of Stirling USB DAQ & INCITE Technology Limited * Devices: [ITL] USB-DUX-FAST (usbduxfast) * Author: Bernd Porr <mail@berndporr.me.uk> - * Updated: 10 Oct 2014 + * Updated: 16 Nov 2019 * Status: stable */ @@ -31,6 +31,7 @@ * * * Revision history: + * 1.0: Fixed a rounding error in usbduxfast_ai_cmdtest * 0.9: Dropping the first data packet which seems to be from the last transfer. * Buffer overflows in the FX2 are handed over to comedi. * 0.92: Dropping now 4 packets. The quad buffer has to be emptied. @@ -359,6 +360,7 @@ static int usbduxfast_ai_cmdtest(struct comedi_device *dev, struct comedi_cmd *cmd) { int err = 0; + int err2 = 0; unsigned int steps; unsigned int arg; @@ -408,11 +410,16 @@ static int usbduxfast_ai_cmdtest(struct comedi_device *dev, */ steps = (cmd->convert_arg * 30) / 1000; if (cmd->chanlist_len != 1) - err |= comedi_check_trigger_arg_min(&steps, - MIN_SAMPLING_PERIOD); - err |= comedi_check_trigger_arg_max(&steps, MAX_SAMPLING_PERIOD); - arg = (steps * 1000) / 30; - err |= comedi_check_trigger_arg_is(&cmd->convert_arg, arg); + err2 |= comedi_check_trigger_arg_min(&steps, + MIN_SAMPLING_PERIOD); + else + err2 |= comedi_check_trigger_arg_min(&steps, 1); + err2 |= comedi_check_trigger_arg_max(&steps, MAX_SAMPLING_PERIOD); + if (err2) { + err |= err2; + arg = (steps * 1000) / 30; + err |= comedi_check_trigger_arg_is(&cmd->convert_arg, arg); + } if (cmd->stop_src == TRIG_COUNT) err |= comedi_check_trigger_arg_min(&cmd->stop_arg, 1); diff --git a/drivers/staging/rdma/hfi1/pcie.c b/drivers/staging/rdma/hfi1/pcie.c index a956044459a2..ea4df848d840 100644 --- a/drivers/staging/rdma/hfi1/pcie.c +++ b/drivers/staging/rdma/hfi1/pcie.c @@ -389,7 +389,8 @@ int pcie_speeds(struct hfi1_devdata *dd) /* * bus->max_bus_speed is set from the bridge's linkcap Max Link Speed */ - if (dd->pcidev->bus->max_bus_speed != PCIE_SPEED_8_0GT) { + if (dd->pcidev->bus->max_bus_speed == PCIE_SPEED_2_5GT || + dd->pcidev->bus->max_bus_speed == PCIE_SPEED_5_0GT) { dd_dev_info(dd, "Parent PCIe bridge does not support Gen3\n"); dd->link_gen3_capable = 0; } diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index bb6a6c35324a..4198ed4ac607 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -1057,27 +1057,6 @@ passthrough_parse_cdb(struct se_cmd *cmd, unsigned char *cdb = cmd->t_task_cdb; /* - * Clear a lun set in the cdb if the initiator talking to use spoke - * and old standards version, as we can't assume the underlying device - * won't choke up on it. - */ - switch (cdb[0]) { - case READ_10: /* SBC - RDProtect */ - case READ_12: /* SBC - RDProtect */ - case READ_16: /* SBC - RDProtect */ - case SEND_DIAGNOSTIC: /* SPC - SELF-TEST Code */ - case VERIFY: /* SBC - VRProtect */ - case VERIFY_16: /* SBC - VRProtect */ - case WRITE_VERIFY: /* SBC - VRProtect */ - case WRITE_VERIFY_12: /* SBC - VRProtect */ - case MAINTENANCE_IN: /* SPC - Parameter Data Format for SA RTPG */ - break; - default: - cdb[1] &= 0x1f; /* clear logical unit number */ - break; - } - - /* * For REPORT LUNS we always need to emulate the response, for everything * else, pass it up. */ diff --git a/drivers/thermal/rcar_thermal.c b/drivers/thermal/rcar_thermal.c index 13d01edc7a04..487c5cd7516c 100644 --- a/drivers/thermal/rcar_thermal.c +++ b/drivers/thermal/rcar_thermal.c @@ -350,8 +350,8 @@ static irqreturn_t rcar_thermal_irq(int irq, void *data) rcar_thermal_for_each_priv(priv, common) { if (rcar_thermal_had_changed(priv, status)) { rcar_thermal_irq_disable(priv); - schedule_delayed_work(&priv->work, - msecs_to_jiffies(300)); + queue_delayed_work(system_freezable_wq, &priv->work, + msecs_to_jiffies(300)); } } diff --git a/drivers/thunderbolt/nhi.c b/drivers/thunderbolt/nhi.c index 6713fd1958e7..3a39d7d0175a 100644 --- a/drivers/thunderbolt/nhi.c +++ b/drivers/thunderbolt/nhi.c @@ -94,9 +94,20 @@ static void __iomem *ring_options_base(struct tb_ring *ring) return io; } -static void ring_iowrite16desc(struct tb_ring *ring, u32 value, u32 offset) +static void ring_iowrite_cons(struct tb_ring *ring, u16 cons) { - iowrite16(value, ring_desc_base(ring) + offset); + /* + * The other 16-bits in the register is read-only and writes to it + * are ignored by the hardware so we can save one ioread32() by + * filling the read-only bits with zeroes. + */ + iowrite32(cons, ring_desc_base(ring) + 8); +} + +static void ring_iowrite_prod(struct tb_ring *ring, u16 prod) +{ + /* See ring_iowrite_cons() above for explanation */ + iowrite32(prod << 16, ring_desc_base(ring) + 8); } static void ring_iowrite32desc(struct tb_ring *ring, u32 value, u32 offset) @@ -148,7 +159,10 @@ static void ring_write_descriptors(struct tb_ring *ring) descriptor->sof = frame->sof; } ring->head = (ring->head + 1) % ring->size; - ring_iowrite16desc(ring, ring->head, ring->is_tx ? 10 : 8); + if (ring->is_tx) + ring_iowrite_prod(ring, ring->head); + else + ring_iowrite_cons(ring, ring->head); } } @@ -368,7 +382,7 @@ void ring_stop(struct tb_ring *ring) ring_iowrite32options(ring, 0, 0); ring_iowrite64desc(ring, 0, 0); - ring_iowrite16desc(ring, 0, ring->is_tx ? 10 : 8); + ring_iowrite32desc(ring, 0, 8); ring_iowrite32desc(ring, 0, 12); ring->head = 0; ring->tail = 0; diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c index daa4a65ef6ff..fe870170db74 100644 --- a/drivers/tty/serial/mxs-auart.c +++ b/drivers/tty/serial/mxs-auart.c @@ -1248,8 +1248,9 @@ static int mxs_auart_request_gpio_irq(struct mxs_auart_port *s) /* * If something went wrong, rollback. + * Be careful: i may be unsigned. */ - while (err && (--i >= 0)) + while (err && (i-- > 0)) if (irq[i] >= 0) free_irq(irq[i], s); diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index 032f3c13b8c4..a3dfefa33e3c 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -332,6 +332,7 @@ struct sc16is7xx_port { struct kthread_worker kworker; struct task_struct *kworker_task; struct kthread_work irq_work; + struct mutex efr_lock; struct sc16is7xx_one p[0]; }; @@ -496,6 +497,21 @@ static int sc16is7xx_set_baud(struct uart_port *port, int baud) div /= 4; } + /* In an amazing feat of design, the Enhanced Features Register shares + * the address of the Interrupt Identification Register, and is + * switched in by writing a magic value (0xbf) to the Line Control + * Register. Any interrupt firing during this time will see the EFR + * where it expects the IIR to be, leading to "Unexpected interrupt" + * messages. + * + * Prevent this possibility by claiming a mutex while accessing the + * EFR, and claiming the same mutex from within the interrupt handler. + * This is similar to disabling the interrupt, but that doesn't work + * because the bulk of the interrupt processing is run as a workqueue + * job in thread context. + */ + mutex_lock(&s->efr_lock); + lcr = sc16is7xx_port_read(port, SC16IS7XX_LCR_REG); /* Open the LCR divisors for configuration */ @@ -511,6 +527,8 @@ static int sc16is7xx_set_baud(struct uart_port *port, int baud) /* Put LCR back to the normal mode */ sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr); + mutex_unlock(&s->efr_lock); + sc16is7xx_port_update(port, SC16IS7XX_MCR_REG, SC16IS7XX_MCR_CLKSEL_BIT, prescaler); @@ -693,6 +711,8 @@ static void sc16is7xx_ist(struct kthread_work *ws) { struct sc16is7xx_port *s = to_sc16is7xx_port(ws, irq_work); + mutex_lock(&s->efr_lock); + while (1) { bool keep_polling = false; int i; @@ -702,6 +722,8 @@ static void sc16is7xx_ist(struct kthread_work *ws) if (!keep_polling) break; } + + mutex_unlock(&s->efr_lock); } static irqreturn_t sc16is7xx_irq(int irq, void *dev_id) @@ -888,6 +910,9 @@ static void sc16is7xx_set_termios(struct uart_port *port, if (!(termios->c_cflag & CREAD)) port->ignore_status_mask |= SC16IS7XX_LSR_BRK_ERROR_MASK; + /* As above, claim the mutex while accessing the EFR. */ + mutex_lock(&s->efr_lock); + sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, SC16IS7XX_LCR_CONF_MODE_B); @@ -909,6 +934,8 @@ static void sc16is7xx_set_termios(struct uart_port *port, /* Update LCR register */ sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr); + mutex_unlock(&s->efr_lock); + /* Get baud rate generator configuration */ baud = uart_get_baud_rate(port, termios, old, port->uartclk / 16 / 4 / 0xffff, @@ -1172,6 +1199,7 @@ static int sc16is7xx_probe(struct device *dev, s->regmap = regmap; s->devtype = devtype; dev_set_drvdata(dev, s); + mutex_init(&s->efr_lock); init_kthread_worker(&s->kworker); init_kthread_work(&s->irq_work, sc16is7xx_ist); diff --git a/drivers/tty/serial/serial_mctrl_gpio.c b/drivers/tty/serial/serial_mctrl_gpio.c index 02147361eaa9..2b5329a3d716 100644 --- a/drivers/tty/serial/serial_mctrl_gpio.c +++ b/drivers/tty/serial/serial_mctrl_gpio.c @@ -67,6 +67,9 @@ EXPORT_SYMBOL_GPL(mctrl_gpio_set); struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios, enum mctrl_gpio_idx gidx) { + if (gpios == NULL) + return NULL; + return gpios->gpio[gidx]; } EXPORT_SYMBOL_GPL(mctrl_gpio_to_gpiod); diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c index 6fc39fbfc275..b5145e8bdf0a 100644 --- a/drivers/tty/synclink_gt.c +++ b/drivers/tty/synclink_gt.c @@ -1192,14 +1192,13 @@ static long slgt_compat_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { struct slgt_info *info = tty->driver_data; - int rc = -ENOIOCTLCMD; + int rc; if (sanity_check(info, tty->name, "compat_ioctl")) return -ENODEV; DBGINFO(("%s compat_ioctl() cmd=%08X\n", info->device_name, cmd)); switch (cmd) { - case MGSL_IOCSPARAMS32: rc = set_params32(info, compat_ptr(arg)); break; @@ -1219,18 +1218,11 @@ static long slgt_compat_ioctl(struct tty_struct *tty, case MGSL_IOCWAITGPIO: case MGSL_IOCGXSYNC: case MGSL_IOCGXCTRL: - case MGSL_IOCSTXIDLE: - case MGSL_IOCTXENABLE: - case MGSL_IOCRXENABLE: - case MGSL_IOCTXABORT: - case TIOCMIWAIT: - case MGSL_IOCSIF: - case MGSL_IOCSXSYNC: - case MGSL_IOCSXCTRL: - rc = ioctl(tty, cmd, arg); + rc = ioctl(tty, cmd, (unsigned long)compat_ptr(arg)); break; + default: + rc = ioctl(tty, cmd, arg); } - DBGINFO(("%s compat_ioctl() cmd=%08X rc=%d\n", info->device_name, cmd, rc)); return rc; } diff --git a/drivers/usb/chipidea/otg.c b/drivers/usb/chipidea/otg.c index f36a1ac3bfbd..b8650210be0f 100644 --- a/drivers/usb/chipidea/otg.c +++ b/drivers/usb/chipidea/otg.c @@ -206,14 +206,17 @@ static void ci_otg_work(struct work_struct *work) } pm_runtime_get_sync(ci->dev); + if (ci->id_event) { ci->id_event = false; ci_handle_id_switch(ci); - } else if (ci->b_sess_valid_event) { + } + + if (ci->b_sess_valid_event) { ci->b_sess_valid_event = false; ci_handle_vbus_change(ci); - } else - dev_err(ci->dev, "unexpected event occurs at %s\n", __func__); + } + pm_runtime_put_sync(ci->dev); enable_irq(ci->irq); diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index 126987c9da75..eb82ee0a3ba8 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -314,6 +314,11 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, /* Validate the wMaxPacketSize field */ maxp = usb_endpoint_maxp(&endpoint->desc); + if (maxp == 0) { + dev_warn(ddev, "config %d interface %d altsetting %d endpoint 0x%X has wMaxPacketSize 0, skipping\n", + cfgno, inum, asnum, d->bEndpointAddress); + goto skip_to_next_endpoint_or_interface_descriptor; + } /* Find the highest legal maxpacket size for this endpoint */ i = 0; /* additional transactions per microframe */ diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 63f7364ac2ce..655279ed6dba 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -107,6 +107,8 @@ EXPORT_SYMBOL_GPL(ehci_cf_port_reset_rwsem); static void hub_release(struct kref *kref); static int usb_reset_and_verify_device(struct usb_device *udev); static int hub_port_disable(struct usb_hub *hub, int port1, int set_state); +static bool hub_port_warm_reset_required(struct usb_hub *hub, int port1, + u16 portstatus); static inline char *portspeed(struct usb_hub *hub, int portstatus) { @@ -1103,6 +1105,11 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) USB_PORT_FEAT_ENABLE); } + /* Make sure a warm-reset request is handled by port_event */ + if (type == HUB_RESUME && + hub_port_warm_reset_required(hub, port1, portstatus)) + set_bit(port1, hub->event_bits); + /* * Add debounce if USB3 link is in polling/link training state. * Link will automatically transition to Enabled state after diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index a31322ed9447..6b0c4187aae1 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -90,6 +90,8 @@ struct gadget_info { bool unbinding; char b_vendor_code; char qw_sign[OS_STRING_QW_SIGN_LEN]; + spinlock_t spinlock; + bool unbind; #ifdef CONFIG_USB_CONFIGFS_UEVENT bool connected; bool sw_connected; @@ -1289,6 +1291,7 @@ static int configfs_composite_bind(struct usb_gadget *gadget, int ret; /* the gi->lock is hold by the caller */ + gi->unbind = 0; cdev->gadget = gadget; set_gadget_data(gadget, cdev); ret = composite_dev_prepare(composite, cdev); @@ -1475,19 +1478,118 @@ static void configfs_composite_unbind(struct usb_gadget *gadget) { struct usb_composite_dev *cdev; struct gadget_info *gi; + unsigned long flags; /* the gi->lock is hold by the caller */ cdev = get_gadget_data(gadget); gi = container_of(cdev, struct gadget_info, cdev); + spin_lock_irqsave(&gi->spinlock, flags); + gi->unbind = 1; + spin_unlock_irqrestore(&gi->spinlock, flags); kfree(otg_desc[0]); otg_desc[0] = NULL; purge_configs_funcs(gi); composite_dev_cleanup(cdev); usb_ep_autoconfig_reset(cdev->gadget); + spin_lock_irqsave(&gi->spinlock, flags); cdev->gadget = NULL; set_gadget_data(gadget, NULL); + spin_unlock_irqrestore(&gi->spinlock, flags); +} + +#if !IS_ENABLED(CONFIG_USB_CONFIGFS_UEVENT) +static int configfs_composite_setup(struct usb_gadget *gadget, + const struct usb_ctrlrequest *ctrl) +{ + struct usb_composite_dev *cdev; + struct gadget_info *gi; + unsigned long flags; + int ret; + + cdev = get_gadget_data(gadget); + if (!cdev) + return 0; + + gi = container_of(cdev, struct gadget_info, cdev); + spin_lock_irqsave(&gi->spinlock, flags); + cdev = get_gadget_data(gadget); + if (!cdev || gi->unbind) { + spin_unlock_irqrestore(&gi->spinlock, flags); + return 0; + } + + ret = composite_setup(gadget, ctrl); + spin_unlock_irqrestore(&gi->spinlock, flags); + return ret; +} + +static void configfs_composite_disconnect(struct usb_gadget *gadget) +{ + struct usb_composite_dev *cdev; + struct gadget_info *gi; + unsigned long flags; + + cdev = get_gadget_data(gadget); + if (!cdev) + return; + + gi = container_of(cdev, struct gadget_info, cdev); + spin_lock_irqsave(&gi->spinlock, flags); + cdev = get_gadget_data(gadget); + if (!cdev || gi->unbind) { + spin_unlock_irqrestore(&gi->spinlock, flags); + return; + } + + composite_disconnect(gadget); + spin_unlock_irqrestore(&gi->spinlock, flags); +} +#endif + +static void configfs_composite_suspend(struct usb_gadget *gadget) +{ + struct usb_composite_dev *cdev; + struct gadget_info *gi; + unsigned long flags; + + cdev = get_gadget_data(gadget); + if (!cdev) + return; + + gi = container_of(cdev, struct gadget_info, cdev); + spin_lock_irqsave(&gi->spinlock, flags); + cdev = get_gadget_data(gadget); + if (!cdev || gi->unbind) { + spin_unlock_irqrestore(&gi->spinlock, flags); + return; + } + + composite_suspend(gadget); + spin_unlock_irqrestore(&gi->spinlock, flags); +} + +static void configfs_composite_resume(struct usb_gadget *gadget) +{ + struct usb_composite_dev *cdev; + struct gadget_info *gi; + unsigned long flags; + + cdev = get_gadget_data(gadget); + if (!cdev) + return; + + gi = container_of(cdev, struct gadget_info, cdev); + spin_lock_irqsave(&gi->spinlock, flags); + cdev = get_gadget_data(gadget); + if (!cdev || gi->unbind) { + spin_unlock_irqrestore(&gi->spinlock, flags); + return; + } + + composite_resume(gadget); + spin_unlock_irqrestore(&gi->spinlock, flags); } #ifdef CONFIG_USB_CONFIGFS_UEVENT @@ -1579,12 +1681,12 @@ static const struct usb_gadget_driver configfs_driver_template = { .reset = android_disconnect, .disconnect = android_disconnect, #else - .setup = composite_setup, - .reset = composite_disconnect, - .disconnect = composite_disconnect, + .setup = configfs_composite_setup, + .reset = configfs_composite_disconnect, + .disconnect = configfs_composite_disconnect, #endif - .suspend = composite_suspend, - .resume = composite_resume, + .suspend = configfs_composite_suspend, + .resume = configfs_composite_resume, .max_speed = USB_SPEED_SUPER, .driver = { @@ -1714,6 +1816,7 @@ static struct config_group *gadgets_make( mutex_init(&gi->lock); INIT_LIST_HEAD(&gi->string_list); INIT_LIST_HEAD(&gi->available_func); + spin_lock_init(&gi->spinlock); composite_init_dev(&gi->cdev); gi->cdev.desc.bLength = USB_DT_DEVICE_SIZE; diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c index 01656f1c6d65..a49ff1f5c0f9 100644 --- a/drivers/usb/gadget/function/uvc_configfs.c +++ b/drivers/usb/gadget/function/uvc_configfs.c @@ -564,6 +564,7 @@ static int uvcg_control_class_allow_link(struct config_item *src, unlock: mutex_unlock(&opts->lock); out: + config_item_put(header); mutex_unlock(su_mutex); return ret; } @@ -605,6 +606,7 @@ static int uvcg_control_class_drop_link(struct config_item *src, unlock: mutex_unlock(&opts->lock); out: + config_item_put(header); mutex_unlock(su_mutex); return ret; } @@ -805,6 +807,7 @@ static int uvcg_streaming_header_allow_link(struct config_item *src, format_ptr->fmt = target_fmt; list_add_tail(&format_ptr->entry, &src_hdr->formats); ++src_hdr->num_fmt; + ++target_fmt->linked; out: mutex_unlock(&opts->lock); @@ -843,6 +846,8 @@ static int uvcg_streaming_header_drop_link(struct config_item *src, break; } + --target_fmt->linked; + out: mutex_unlock(&opts->lock); mutex_unlock(su_mutex); @@ -2087,6 +2092,7 @@ static int uvcg_streaming_class_allow_link(struct config_item *src, unlock: mutex_unlock(&opts->lock); out: + config_item_put(header); mutex_unlock(su_mutex); return ret; } @@ -2131,6 +2137,7 @@ static int uvcg_streaming_class_drop_link(struct config_item *src, unlock: mutex_unlock(&opts->lock); out: + config_item_put(header); mutex_unlock(su_mutex); return ret; } diff --git a/drivers/usb/gadget/function/uvc_video.c b/drivers/usb/gadget/function/uvc_video.c index 0f01c04d7cbd..d6bab12b0b47 100644 --- a/drivers/usb/gadget/function/uvc_video.c +++ b/drivers/usb/gadget/function/uvc_video.c @@ -129,6 +129,21 @@ uvc_video_encode_isoc(struct usb_request *req, struct uvc_video *video, * Request handling */ +static int uvcg_video_ep_queue(struct uvc_video *video, struct usb_request *req) +{ + int ret; + + ret = usb_ep_queue(video->ep, req, GFP_ATOMIC); + if (ret < 0) { + printk(KERN_INFO "Failed to queue request (%d).\n", ret); + /* Isochronous endpoints can't be halted. */ + if (usb_endpoint_xfer_bulk(video->ep->desc)) + usb_ep_set_halt(video->ep); + } + + return ret; +} + /* * I somehow feel that synchronisation won't be easy to achieve here. We have * three events that control USB requests submission: @@ -193,14 +208,13 @@ uvc_video_complete(struct usb_ep *ep, struct usb_request *req) video->encode(req, video, buf); - if ((ret = usb_ep_queue(ep, req, GFP_ATOMIC)) < 0) { - printk(KERN_INFO "Failed to queue request (%d).\n", ret); - usb_ep_set_halt(ep); - spin_unlock_irqrestore(&video->queue.irqlock, flags); + ret = uvcg_video_ep_queue(video, req); + spin_unlock_irqrestore(&video->queue.irqlock, flags); + + if (ret < 0) { uvcg_queue_cancel(queue, 0); goto requeue; } - spin_unlock_irqrestore(&video->queue.irqlock, flags); return; @@ -320,15 +334,13 @@ int uvcg_video_pump(struct uvc_video *video) video->encode(req, video, buf); /* Queue the USB request */ - ret = usb_ep_queue(video->ep, req, GFP_ATOMIC); + ret = uvcg_video_ep_queue(video, req); + spin_unlock_irqrestore(&queue->irqlock, flags); + if (ret < 0) { - printk(KERN_INFO "Failed to queue request (%d)\n", ret); - usb_ep_set_halt(video->ep); - spin_unlock_irqrestore(&queue->irqlock, flags); uvcg_queue_cancel(queue, 0); break; } - spin_unlock_irqrestore(&queue->irqlock, flags); } spin_lock_irqsave(&video->req_lock, flags); diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c b/drivers/usb/gadget/udc/atmel_usba_udc.c index 585cb8734f50..668ac5e8681b 100644 --- a/drivers/usb/gadget/udc/atmel_usba_udc.c +++ b/drivers/usb/gadget/udc/atmel_usba_udc.c @@ -403,9 +403,11 @@ static void submit_request(struct usba_ep *ep, struct usba_request *req) next_fifo_transaction(ep, req); if (req->last_transaction) { usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY); - usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE); + if (ep_is_control(ep)) + usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE); } else { - usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE); + if (ep_is_control(ep)) + usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE); usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY); } } diff --git a/drivers/usb/gadget/udc/fotg210-udc.c b/drivers/usb/gadget/udc/fotg210-udc.c index 95df2b3bb6a1..76e991557116 100644 --- a/drivers/usb/gadget/udc/fotg210-udc.c +++ b/drivers/usb/gadget/udc/fotg210-udc.c @@ -744,7 +744,7 @@ static void fotg210_get_status(struct fotg210_udc *fotg210, fotg210->ep0_req->length = 2; spin_unlock(&fotg210->lock); - fotg210_ep_queue(fotg210->gadget.ep0, fotg210->ep0_req, GFP_KERNEL); + fotg210_ep_queue(fotg210->gadget.ep0, fotg210->ep0_req, GFP_ATOMIC); spin_lock(&fotg210->lock); } diff --git a/drivers/usb/gadget/udc/fsl_udc_core.c b/drivers/usb/gadget/udc/fsl_udc_core.c index 8991a4070792..bd98557caa28 100644 --- a/drivers/usb/gadget/udc/fsl_udc_core.c +++ b/drivers/usb/gadget/udc/fsl_udc_core.c @@ -2570,7 +2570,7 @@ static int fsl_udc_remove(struct platform_device *pdev) dma_pool_destroy(udc_controller->td_pool); free_irq(udc_controller->irq, udc_controller); iounmap(dr_regs); - if (pdata->operating_mode == FSL_USB2_DR_DEVICE) + if (res && (pdata->operating_mode == FSL_USB2_DR_DEVICE)) release_mem_region(res->start, resource_size(res)); /* free udc --wait for the release() finished */ diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c index 993f4da065c3..8b7d43c282f8 100644 --- a/drivers/usb/misc/appledisplay.c +++ b/drivers/usb/misc/appledisplay.c @@ -161,8 +161,11 @@ static int appledisplay_bl_update_status(struct backlight_device *bd) pdata->msgdata, 2, ACD_USB_TIMEOUT); mutex_unlock(&pdata->sysfslock); - - return retval; + + if (retval < 0) + return retval; + else + return 0; } static int appledisplay_bl_get_brightness(struct backlight_device *bd) @@ -180,7 +183,12 @@ static int appledisplay_bl_get_brightness(struct backlight_device *bd) 0, pdata->msgdata, 2, ACD_USB_TIMEOUT); - brightness = pdata->msgdata[1]; + if (retval < 2) { + if (retval >= 0) + retval = -EMSGSIZE; + } else { + brightness = pdata->msgdata[1]; + } mutex_unlock(&pdata->sysfslock); if (retval < 0) @@ -326,6 +334,7 @@ error: if (pdata) { if (pdata->urb) { usb_kill_urb(pdata->urb); + cancel_delayed_work_sync(&pdata->work); if (pdata->urbdata) usb_free_coherent(pdata->udev, ACD_URB_BUFFER_LEN, pdata->urbdata, pdata->urb->transfer_dma); diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c index 7da242bbe37b..8f5f8ad98632 100644 --- a/drivers/usb/misc/ldusb.c +++ b/drivers/usb/misc/ldusb.c @@ -499,11 +499,11 @@ static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count, retval = -EFAULT; goto unlock_exit; } - dev->ring_tail = (dev->ring_tail+1) % ring_buffer_size; - retval = bytes_to_read; spin_lock_irq(&dev->rbsl); + dev->ring_tail = (dev->ring_tail + 1) % ring_buffer_size; + if (dev->buffer_overflow) { dev->buffer_overflow = 0; spin_unlock_irq(&dev->rbsl); @@ -584,7 +584,7 @@ static ssize_t ld_usb_write(struct file *file, const char __user *buffer, 1 << 8, 0, dev->interrupt_out_buffer, bytes_to_write, - USB_CTRL_SET_TIMEOUT * HZ); + USB_CTRL_SET_TIMEOUT); if (retval < 0) dev_err(&dev->intf->dev, "Couldn't submit HID_REQ_SET_REPORT %d\n", diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c index 32b41eb07f00..8350ecfbcf21 100644 --- a/drivers/usb/misc/legousbtower.c +++ b/drivers/usb/misc/legousbtower.c @@ -910,7 +910,7 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device get_version_reply, sizeof(*get_version_reply), 1000); - if (result < sizeof(*get_version_reply)) { + if (result != sizeof(*get_version_reply)) { if (result >= 0) result = -EIO; dev_err(idev, "get version request failed: %d\n", result); diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index e3ea0fdd3913..205f31200264 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -121,6 +121,7 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x10C4, 0x8341) }, /* Siemens MC35PU GPRS Modem */ { USB_DEVICE(0x10C4, 0x8382) }, /* Cygnal Integrated Products, Inc. */ { USB_DEVICE(0x10C4, 0x83A8) }, /* Amber Wireless AMB2560 */ + { USB_DEVICE(0x10C4, 0x83AA) }, /* Mark-10 Digital Force Gauge */ { USB_DEVICE(0x10C4, 0x83D8) }, /* DekTec DTA Plus VHF/UHF Booster/Attenuator */ { USB_DEVICE(0x10C4, 0x8411) }, /* Kyocera GPS Module */ { USB_DEVICE(0x10C4, 0x8418) }, /* IRZ Automation Teleport SG-10 GSM/GPRS Modem */ diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index 244acb1299a9..e92cd1eceefa 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@ -773,7 +773,7 @@ send: usb_fill_int_urb(port->interrupt_out_urb, port->serial->dev, usb_sndintpipe(port->serial->dev, port->interrupt_out_endpointAddress), - port->interrupt_out_buffer, port->interrupt_out_size, + port->interrupt_out_buffer, actual_size, cypress_write_int_callback, port, priv->write_urb_interval); result = usb_submit_urb(port->interrupt_out_urb, GFP_ATOMIC); if (result) { diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index 286b43c79d38..1927f41ccafc 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -1941,10 +1941,6 @@ static int mos7720_startup(struct usb_serial *serial) } } - /* setting configuration feature to one */ - usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - (__u8)0x03, 0x00, 0x01, 0x00, NULL, 0x00, 5000); - #ifdef CONFIG_USB_SERIAL_MOS7715_PARPORT if (product == MOSCHIP_DEVICE_ID_7715) { ret_val = mos7715_parport_init(serial); diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 58ba6904a087..4add6bc38d64 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -131,11 +131,15 @@ /* This driver also supports * ATEN UC2324 device using Moschip MCS7840 * ATEN UC2322 device using Moschip MCS7820 + * MOXA UPort 2210 device using Moschip MCS7820 */ #define USB_VENDOR_ID_ATENINTL 0x0557 #define ATENINTL_DEVICE_ID_UC2324 0x2011 #define ATENINTL_DEVICE_ID_UC2322 0x7820 +#define USB_VENDOR_ID_MOXA 0x110a +#define MOXA_DEVICE_ID_2210 0x2210 + /* Interrupt Routine Defines */ #define SERIAL_IIR_RLS 0x06 @@ -206,6 +210,7 @@ static const struct usb_device_id id_table[] = { {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL2_4)}, {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2324)}, {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2322)}, + {USB_DEVICE(USB_VENDOR_ID_MOXA, MOXA_DEVICE_ID_2210)}, {} /* terminating entry */ }; MODULE_DEVICE_TABLE(usb, id_table); @@ -2089,6 +2094,7 @@ static int mos7840_probe(struct usb_serial *serial, const struct usb_device_id *id) { u16 product = le16_to_cpu(serial->dev->descriptor.idProduct); + u16 vid = le16_to_cpu(serial->dev->descriptor.idVendor); u8 *buf; int device_type; @@ -2098,6 +2104,11 @@ static int mos7840_probe(struct usb_serial *serial, goto out; } + if (vid == USB_VENDOR_ID_MOXA && product == MOXA_DEVICE_ID_2210) { + device_type = MOSCHIP_DEVICE_ID_7820; + goto out; + } + buf = kzalloc(VENDOR_READ_LENGTH, GFP_KERNEL); if (!buf) return -ENOMEM; @@ -2350,11 +2361,6 @@ out: goto error; } else dev_dbg(&port->dev, "ZLP_REG5 Writing success status%d\n", status); - - /* setting configuration feature to one */ - usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - 0x03, 0x00, 0x01, 0x00, NULL, 0x00, - MOS_WDR_TIMEOUT); } return 0; error: diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 00a6e62a68a8..084332a5855e 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -200,6 +200,7 @@ static void option_instat_callback(struct urb *urb); #define DELL_PRODUCT_5804_MINICARD_ATT 0x819b /* Novatel E371 */ #define DELL_PRODUCT_5821E 0x81d7 +#define DELL_PRODUCT_5821E_ESIM 0x81e0 #define KYOCERA_VENDOR_ID 0x0c88 #define KYOCERA_PRODUCT_KPC650 0x17da @@ -1043,6 +1044,8 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(DELL_VENDOR_ID, DELL_PRODUCT_5804_MINICARD_ATT, 0xff, 0xff, 0xff) }, { USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5821E), .driver_info = RSVD(0) | RSVD(1) | RSVD(6) }, + { USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5821E_ESIM), + .driver_info = RSVD(0) | RSVD(1) | RSVD(6) }, { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_E100A) }, /* ADU-E100, ADU-310 */ { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_500A) }, { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_620UW) }, @@ -1987,6 +1990,10 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(0x03f0, 0xa31d, 0xff, 0x06, 0x13) }, { USB_DEVICE_AND_INTERFACE_INFO(0x03f0, 0xa31d, 0xff, 0x06, 0x14) }, { USB_DEVICE_AND_INTERFACE_INFO(0x03f0, 0xa31d, 0xff, 0x06, 0x1b) }, + { USB_DEVICE(0x0489, 0xe0b4), /* Foxconn T77W968 */ + .driver_info = RSVD(0) | RSVD(1) | RSVD(6) }, + { USB_DEVICE(0x0489, 0xe0b5), /* Foxconn T77W968 ESIM */ + .driver_info = RSVD(0) | RSVD(1) | RSVD(6) }, { USB_DEVICE(0x1508, 0x1001), /* Fibocom NL668 */ .driver_info = RSVD(4) | RSVD(5) | RSVD(6) }, { USB_DEVICE(0x2cb7, 0x0104), /* Fibocom NL678 series */ diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index d3ea90bef84d..345211f1a491 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@ -604,6 +604,10 @@ static int firm_send_command(struct usb_serial_port *port, __u8 command, command_port = port->serial->port[COMMAND_PORT]; command_info = usb_get_serial_port_data(command_port); + + if (command_port->bulk_out_size < datasize + 1) + return -EIO; + mutex_lock(&command_info->mutex); command_info->command_finished = false; @@ -677,6 +681,7 @@ static void firm_setup_port(struct tty_struct *tty) struct device *dev = &port->dev; struct whiteheat_port_settings port_settings; unsigned int cflag = tty->termios.c_cflag; + speed_t baud; port_settings.port = port->port_number + 1; @@ -737,11 +742,13 @@ static void firm_setup_port(struct tty_struct *tty) dev_dbg(dev, "%s - XON = %2x, XOFF = %2x\n", __func__, port_settings.xon, port_settings.xoff); /* get the baud rate wanted */ - port_settings.baud = tty_get_baud_rate(tty); - dev_dbg(dev, "%s - baud rate = %d\n", __func__, port_settings.baud); + baud = tty_get_baud_rate(tty); + port_settings.baud = cpu_to_le32(baud); + dev_dbg(dev, "%s - baud rate = %u\n", __func__, baud); /* fixme: should set validated settings */ - tty_encode_baud_rate(tty, port_settings.baud, port_settings.baud); + tty_encode_baud_rate(tty, baud, baud); + /* handle any settings that aren't specified in the tty structure */ port_settings.lloop = 0; diff --git a/drivers/usb/serial/whiteheat.h b/drivers/usb/serial/whiteheat.h index 38065df4d2d8..30169c859a74 100644 --- a/drivers/usb/serial/whiteheat.h +++ b/drivers/usb/serial/whiteheat.h @@ -91,7 +91,7 @@ struct whiteheat_simple { struct whiteheat_port_settings { __u8 port; /* port number (1 to N) */ - __u32 baud; /* any value 7 - 460800, firmware calculates + __le32 baud; /* any value 7 - 460800, firmware calculates best fit; arrives little endian */ __u8 bits; /* 5, 6, 7, or 8 */ __u8 stop; /* 1 or 2, default 1 (2 = 1.5 if bits = 5) */ diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c index e657b111b320..a7cc0bc68deb 100644 --- a/drivers/usb/storage/uas.c +++ b/drivers/usb/storage/uas.c @@ -772,30 +772,10 @@ static int uas_slave_alloc(struct scsi_device *sdev) { struct uas_dev_info *devinfo = (struct uas_dev_info *)sdev->host->hostdata; - int maxp; sdev->hostdata = devinfo; /* - * We have two requirements here. We must satisfy the requirements - * of the physical HC and the demands of the protocol, as we - * definitely want no additional memory allocation in this path - * ruling out using bounce buffers. - * - * For a transmission on USB to continue we must never send - * a package that is smaller than maxpacket. Hence the length of each - * scatterlist element except the last must be divisible by the - * Bulk maxpacket value. - * If the HC does not ensure that through SG, - * the upper layer must do that. We must assume nothing - * about the capabilities off the HC, so we use the most - * pessimistic requirement. - */ - - maxp = usb_maxpacket(devinfo->udev, devinfo->data_in_pipe, 0); - blk_queue_virt_boundary(sdev->request_queue, maxp - 1); - - /* * The protocol has no requirements on alignment in the strict sense. * Controllers may or may not have alignment restrictions. * As this is not exported, we use an extremely conservative guess. diff --git a/drivers/usb/usbip/vhci_hcd.c b/drivers/usb/usbip/vhci_hcd.c index 4d68a1e9e878..3476d02967f7 100644 --- a/drivers/usb/usbip/vhci_hcd.c +++ b/drivers/usb/usbip/vhci_hcd.c @@ -303,6 +303,7 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, default: break; } + break; default: usbip_dbg_vhci_rh(" ClearPortFeature: default %x\n", wValue); diff --git a/drivers/vfio/pci/vfio_pci_config.c b/drivers/vfio/pci/vfio_pci_config.c index c55c632a3b24..ad5929fbceb1 100644 --- a/drivers/vfio/pci/vfio_pci_config.c +++ b/drivers/vfio/pci/vfio_pci_config.c @@ -1130,8 +1130,10 @@ static int vfio_msi_cap_len(struct vfio_pci_device *vdev, u8 pos) return -ENOMEM; ret = init_pci_cap_msi_perm(vdev->msi_perm, len, flags); - if (ret) + if (ret) { + kfree(vdev->msi_perm); return ret; + } return len; } diff --git a/drivers/vhost/vsock.c b/drivers/vhost/vsock.c index 72e914de473e..81754c33c3a9 100644 --- a/drivers/vhost/vsock.c +++ b/drivers/vhost/vsock.c @@ -21,6 +21,14 @@ #include "vhost.h" #define VHOST_VSOCK_DEFAULT_HOST_CID 2 +/* Max number of bytes transferred before requeueing the job. + * Using this limit prevents one virtqueue from starving others. */ +#define VHOST_VSOCK_WEIGHT 0x80000 +/* Max number of packets transferred before requeueing the job. + * Using this limit prevents one virtqueue from starving others with + * small pkts. + */ +#define VHOST_VSOCK_PKT_WEIGHT 256 enum { VHOST_VSOCK_FEATURES = VHOST_FEATURES, @@ -529,7 +537,8 @@ static int vhost_vsock_dev_open(struct inode *inode, struct file *file) vsock->vqs[VSOCK_VQ_TX].handle_kick = vhost_vsock_handle_tx_kick; vsock->vqs[VSOCK_VQ_RX].handle_kick = vhost_vsock_handle_rx_kick; - vhost_dev_init(&vsock->dev, vqs, ARRAY_SIZE(vsock->vqs)); + vhost_dev_init(&vsock->dev, vqs, ARRAY_SIZE(vsock->vqs), + VHOST_VSOCK_PKT_WEIGHT, VHOST_VSOCK_WEIGHT); file->private_data = vsock; spin_lock_init(&vsock->send_pkt_list_lock); diff --git a/drivers/video/backlight/lm3639_bl.c b/drivers/video/backlight/lm3639_bl.c index cd50df5807ea..086611c7bc03 100644 --- a/drivers/video/backlight/lm3639_bl.c +++ b/drivers/video/backlight/lm3639_bl.c @@ -400,10 +400,8 @@ static int lm3639_remove(struct i2c_client *client) regmap_write(pchip->regmap, REG_ENABLE, 0x00); - if (&pchip->cdev_torch) - led_classdev_unregister(&pchip->cdev_torch); - if (&pchip->cdev_flash) - led_classdev_unregister(&pchip->cdev_flash); + led_classdev_unregister(&pchip->cdev_torch); + led_classdev_unregister(&pchip->cdev_flash); if (pchip->bled) device_remove_file(&(pchip->bled->dev), &dev_attr_bled_mode); return 0; diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig index 3f7f92a90795..759aaeb6a196 100644 --- a/drivers/video/fbdev/Kconfig +++ b/drivers/video/fbdev/Kconfig @@ -1991,16 +1991,6 @@ config FB_SH_MOBILE_LCDC ---help--- Frame buffer driver for the on-chip SH-Mobile LCD controller. -config FB_SH_MOBILE_HDMI - tristate "SuperH Mobile HDMI controller support" - depends on FB_SH_MOBILE_LCDC - select FB_MODE_HELPERS - select SOUND - select SND - select SND_SOC - ---help--- - Driver for the on-chip SH-Mobile HDMI controller. - config FB_TMIO tristate "Toshiba Mobile IO FrameBuffer support" depends on FB && (MFD_TMIO || COMPILE_TEST) diff --git a/drivers/video/fbdev/Makefile b/drivers/video/fbdev/Makefile index 238e851c0705..3cc5aa98b0e0 100644 --- a/drivers/video/fbdev/Makefile +++ b/drivers/video/fbdev/Makefile @@ -118,7 +118,6 @@ obj-$(CONFIG_FB_UDL) += udlfb.o obj-$(CONFIG_FB_SMSCUFX) += smscufx.o obj-$(CONFIG_FB_XILINX) += xilinxfb.o obj-$(CONFIG_SH_MIPI_DSI) += sh_mipi_dsi.o -obj-$(CONFIG_FB_SH_MOBILE_HDMI) += sh_mobile_hdmi.o obj-$(CONFIG_FB_SH_MOBILE_MERAM) += sh_mobile_meram.o obj-$(CONFIG_FB_SH_MOBILE_LCDC) += sh_mobile_lcdcfb.o obj-$(CONFIG_FB_OMAP) += omap/ diff --git a/drivers/video/fbdev/core/fbmon.c b/drivers/video/fbdev/core/fbmon.c index 47c3191ec313..0a5b3f844654 100644 --- a/drivers/video/fbdev/core/fbmon.c +++ b/drivers/video/fbdev/core/fbmon.c @@ -997,97 +997,6 @@ void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs) DPRINTK("========================================\n"); } -/** - * fb_edid_add_monspecs() - add monitor video modes from E-EDID data - * @edid: 128 byte array with an E-EDID block - * @spacs: monitor specs to be extended - */ -void fb_edid_add_monspecs(unsigned char *edid, struct fb_monspecs *specs) -{ - unsigned char *block; - struct fb_videomode *m; - int num = 0, i; - u8 svd[64], edt[(128 - 4) / DETAILED_TIMING_DESCRIPTION_SIZE]; - u8 pos = 4, svd_n = 0; - - if (!edid) - return; - - if (!edid_checksum(edid)) - return; - - if (edid[0] != 0x2 || - edid[2] < 4 || edid[2] > 128 - DETAILED_TIMING_DESCRIPTION_SIZE) - return; - - DPRINTK(" Short Video Descriptors\n"); - - while (pos < edid[2]) { - u8 len = edid[pos] & 0x1f, type = (edid[pos] >> 5) & 7; - pr_debug("Data block %u of %u bytes\n", type, len); - if (type == 2) { - for (i = pos; i < pos + len; i++) { - u8 idx = edid[pos + i] & 0x7f; - svd[svd_n++] = idx; - pr_debug("N%sative mode #%d\n", - edid[pos + i] & 0x80 ? "" : "on-n", idx); - } - } else if (type == 3 && len >= 3) { - /* Check Vendor Specific Data Block. For HDMI, - it is always 00-0C-03 for HDMI Licensing, LLC. */ - if (edid[pos + 1] == 3 && edid[pos + 2] == 0xc && - edid[pos + 3] == 0) - specs->misc |= FB_MISC_HDMI; - } - pos += len + 1; - } - - block = edid + edid[2]; - - DPRINTK(" Extended Detailed Timings\n"); - - for (i = 0; i < (128 - edid[2]) / DETAILED_TIMING_DESCRIPTION_SIZE; - i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) - if (PIXEL_CLOCK) - edt[num++] = block - edid; - - /* Yikes, EDID data is totally useless */ - if (!(num + svd_n)) - return; - - m = kzalloc((specs->modedb_len + num + svd_n) * - sizeof(struct fb_videomode), GFP_KERNEL); - - if (!m) - return; - - memcpy(m, specs->modedb, specs->modedb_len * sizeof(struct fb_videomode)); - - for (i = specs->modedb_len; i < specs->modedb_len + num; i++) { - get_detailed_timing(edid + edt[i - specs->modedb_len], &m[i]); - if (i == specs->modedb_len) - m[i].flag |= FB_MODE_IS_FIRST; - pr_debug("Adding %ux%u@%u\n", m[i].xres, m[i].yres, m[i].refresh); - } - - for (i = specs->modedb_len + num; i < specs->modedb_len + num + svd_n; i++) { - int idx = svd[i - specs->modedb_len - num]; - if (!idx || idx >= ARRAY_SIZE(cea_modes)) { - pr_warning("Reserved SVD code %d\n", idx); - } else if (!cea_modes[idx].xres) { - pr_warning("Unimplemented SVD code %d\n", idx); - } else { - memcpy(&m[i], cea_modes + idx, sizeof(m[i])); - pr_debug("Adding SVD #%d: %ux%u@%u\n", idx, - m[i].xres, m[i].yres, m[i].refresh); - } - } - - kfree(specs->modedb); - specs->modedb = m; - specs->modedb_len = specs->modedb_len + num + svd_n; -} - /* * VESA Generalized Timing Formula (GTF) */ @@ -1498,9 +1407,6 @@ void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs) { specs = NULL; } -void fb_edid_add_monspecs(unsigned char *edid, struct fb_monspecs *specs) -{ -} void fb_destroy_modedb(struct fb_videomode *modedb) { } @@ -1608,7 +1514,6 @@ EXPORT_SYMBOL(fb_firmware_edid); EXPORT_SYMBOL(fb_parse_edid); EXPORT_SYMBOL(fb_edid_to_monspecs); -EXPORT_SYMBOL(fb_edid_add_monspecs); EXPORT_SYMBOL(fb_get_mode); EXPORT_SYMBOL(fb_validate_mode); EXPORT_SYMBOL(fb_destroy_modedb); diff --git a/drivers/video/fbdev/core/modedb.c b/drivers/video/fbdev/core/modedb.c index 455a15f70172..a9d76e1b4378 100644 --- a/drivers/video/fbdev/core/modedb.c +++ b/drivers/video/fbdev/core/modedb.c @@ -289,63 +289,6 @@ static const struct fb_videomode modedb[] = { }; #ifdef CONFIG_FB_MODE_HELPERS -const struct fb_videomode cea_modes[65] = { - /* #1: 640x480p@59.94/60Hz */ - [1] = { - NULL, 60, 640, 480, 39722, 48, 16, 33, 10, 96, 2, 0, - FB_VMODE_NONINTERLACED, 0, - }, - /* #3: 720x480p@59.94/60Hz */ - [3] = { - NULL, 60, 720, 480, 37037, 60, 16, 30, 9, 62, 6, 0, - FB_VMODE_NONINTERLACED, 0, - }, - /* #5: 1920x1080i@59.94/60Hz */ - [5] = { - NULL, 60, 1920, 1080, 13763, 148, 88, 15, 2, 44, 5, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, - FB_VMODE_INTERLACED, 0, - }, - /* #7: 720(1440)x480iH@59.94/60Hz */ - [7] = { - NULL, 60, 1440, 480, 18554/*37108*/, 114, 38, 15, 4, 124, 3, 0, - FB_VMODE_INTERLACED, 0, - }, - /* #9: 720(1440)x240pH@59.94/60Hz */ - [9] = { - NULL, 60, 1440, 240, 18554, 114, 38, 16, 4, 124, 3, 0, - FB_VMODE_NONINTERLACED, 0, - }, - /* #18: 720x576pH@50Hz */ - [18] = { - NULL, 50, 720, 576, 37037, 68, 12, 39, 5, 64, 5, 0, - FB_VMODE_NONINTERLACED, 0, - }, - /* #19: 1280x720p@50Hz */ - [19] = { - NULL, 50, 1280, 720, 13468, 220, 440, 20, 5, 40, 5, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, - FB_VMODE_NONINTERLACED, 0, - }, - /* #20: 1920x1080i@50Hz */ - [20] = { - NULL, 50, 1920, 1080, 13480, 148, 528, 15, 5, 528, 5, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, - FB_VMODE_INTERLACED, 0, - }, - /* #32: 1920x1080p@23.98/24Hz */ - [32] = { - NULL, 24, 1920, 1080, 13468, 148, 638, 36, 4, 44, 5, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, - FB_VMODE_NONINTERLACED, 0, - }, - /* #35: (2880)x480p4x@59.94/60Hz */ - [35] = { - NULL, 60, 2880, 480, 9250, 240, 64, 30, 9, 248, 6, 0, - FB_VMODE_NONINTERLACED, 0, - }, -}; - const struct fb_videomode vesa_modes[] = { /* 0 640x350-85 VESA */ { NULL, 85, 640, 350, 31746, 96, 32, 60, 32, 64, 3, diff --git a/drivers/video/fbdev/sbuslib.c b/drivers/video/fbdev/sbuslib.c index 31c301d6be62..52e161dbd204 100644 --- a/drivers/video/fbdev/sbuslib.c +++ b/drivers/video/fbdev/sbuslib.c @@ -105,11 +105,11 @@ int sbusfb_ioctl_helper(unsigned long cmd, unsigned long arg, struct fbtype __user *f = (struct fbtype __user *) arg; if (put_user(type, &f->fb_type) || - __put_user(info->var.yres, &f->fb_height) || - __put_user(info->var.xres, &f->fb_width) || - __put_user(fb_depth, &f->fb_depth) || - __put_user(0, &f->fb_cmsize) || - __put_user(fb_size, &f->fb_cmsize)) + put_user(info->var.yres, &f->fb_height) || + put_user(info->var.xres, &f->fb_width) || + put_user(fb_depth, &f->fb_depth) || + put_user(0, &f->fb_cmsize) || + put_user(fb_size, &f->fb_cmsize)) return -EFAULT; return 0; } @@ -124,10 +124,10 @@ int sbusfb_ioctl_helper(unsigned long cmd, unsigned long arg, unsigned int index, count, i; if (get_user(index, &c->index) || - __get_user(count, &c->count) || - __get_user(ured, &c->red) || - __get_user(ugreen, &c->green) || - __get_user(ublue, &c->blue)) + get_user(count, &c->count) || + get_user(ured, &c->red) || + get_user(ugreen, &c->green) || + get_user(ublue, &c->blue)) return -EFAULT; cmap.len = 1; @@ -164,13 +164,13 @@ int sbusfb_ioctl_helper(unsigned long cmd, unsigned long arg, u8 red, green, blue; if (get_user(index, &c->index) || - __get_user(count, &c->count) || - __get_user(ured, &c->red) || - __get_user(ugreen, &c->green) || - __get_user(ublue, &c->blue)) + get_user(count, &c->count) || + get_user(ured, &c->red) || + get_user(ugreen, &c->green) || + get_user(ublue, &c->blue)) return -EFAULT; - if (index + count > cmap->len) + if (index > cmap->len || count > cmap->len - index) return -EINVAL; for (i = 0; i < count; i++) { diff --git a/drivers/video/fbdev/sh_mobile_hdmi.c b/drivers/video/fbdev/sh_mobile_hdmi.c deleted file mode 100644 index 7c72a3f02056..000000000000 --- a/drivers/video/fbdev/sh_mobile_hdmi.c +++ /dev/null @@ -1,1489 +0,0 @@ -/* - * SH-Mobile High-Definition Multimedia Interface (HDMI) driver - * for SLISHDMI13T and SLIPHDMIT IP cores - * - * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/clk.h> -#include <linux/console.h> -#include <linux/delay.h> -#include <linux/err.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/io.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/pm_runtime.h> -#include <linux/slab.h> -#include <linux/types.h> -#include <linux/workqueue.h> -#include <sound/soc.h> -#include <sound/soc-dapm.h> -#include <sound/initval.h> - -#include <video/sh_mobile_hdmi.h> -#include <video/sh_mobile_lcdc.h> - -#include "sh_mobile_lcdcfb.h" - -/* HDMI Core Control Register (HTOP0) */ -#define HDMI_SYSTEM_CTRL 0x00 /* System control */ -#define HDMI_L_R_DATA_SWAP_CTRL_RPKT 0x01 /* L/R data swap control, - bits 19..16 of 20-bit N for Audio Clock Regeneration packet */ -#define HDMI_20_BIT_N_FOR_AUDIO_RPKT_15_8 0x02 /* bits 15..8 of 20-bit N for Audio Clock Regeneration packet */ -#define HDMI_20_BIT_N_FOR_AUDIO_RPKT_7_0 0x03 /* bits 7..0 of 20-bit N for Audio Clock Regeneration packet */ -#define HDMI_SPDIF_AUDIO_SAMP_FREQ_CTS 0x04 /* SPDIF audio sampling frequency, - bits 19..16 of Internal CTS */ -#define HDMI_INTERNAL_CTS_15_8 0x05 /* bits 15..8 of Internal CTS */ -#define HDMI_INTERNAL_CTS_7_0 0x06 /* bits 7..0 of Internal CTS */ -#define HDMI_EXTERNAL_CTS_19_16 0x07 /* External CTS */ -#define HDMI_EXTERNAL_CTS_15_8 0x08 /* External CTS */ -#define HDMI_EXTERNAL_CTS_7_0 0x09 /* External CTS */ -#define HDMI_AUDIO_SETTING_1 0x0A /* Audio setting.1 */ -#define HDMI_AUDIO_SETTING_2 0x0B /* Audio setting.2 */ -#define HDMI_I2S_AUDIO_SET 0x0C /* I2S audio setting */ -#define HDMI_DSD_AUDIO_SET 0x0D /* DSD audio setting */ -#define HDMI_DEBUG_MONITOR_1 0x0E /* Debug monitor.1 */ -#define HDMI_DEBUG_MONITOR_2 0x0F /* Debug monitor.2 */ -#define HDMI_I2S_INPUT_PIN_SWAP 0x10 /* I2S input pin swap */ -#define HDMI_AUDIO_STATUS_BITS_SETTING_1 0x11 /* Audio status bits setting.1 */ -#define HDMI_AUDIO_STATUS_BITS_SETTING_2 0x12 /* Audio status bits setting.2 */ -#define HDMI_CATEGORY_CODE 0x13 /* Category code */ -#define HDMI_SOURCE_NUM_AUDIO_WORD_LEN 0x14 /* Source number/Audio word length */ -#define HDMI_AUDIO_VIDEO_SETTING_1 0x15 /* Audio/Video setting.1 */ -#define HDMI_VIDEO_SETTING_1 0x16 /* Video setting.1 */ -#define HDMI_DEEP_COLOR_MODES 0x17 /* Deep Color Modes */ - -/* 12 16- and 10-bit Color space conversion parameters: 0x18..0x2f */ -#define HDMI_COLOR_SPACE_CONVERSION_PARAMETERS 0x18 - -#define HDMI_EXTERNAL_VIDEO_PARAM_SETTINGS 0x30 /* External video parameter settings */ -#define HDMI_EXTERNAL_H_TOTAL_7_0 0x31 /* External horizontal total (LSB) */ -#define HDMI_EXTERNAL_H_TOTAL_11_8 0x32 /* External horizontal total (MSB) */ -#define HDMI_EXTERNAL_H_BLANK_7_0 0x33 /* External horizontal blank (LSB) */ -#define HDMI_EXTERNAL_H_BLANK_9_8 0x34 /* External horizontal blank (MSB) */ -#define HDMI_EXTERNAL_H_DELAY_7_0 0x35 /* External horizontal delay (LSB) */ -#define HDMI_EXTERNAL_H_DELAY_9_8 0x36 /* External horizontal delay (MSB) */ -#define HDMI_EXTERNAL_H_DURATION_7_0 0x37 /* External horizontal duration (LSB) */ -#define HDMI_EXTERNAL_H_DURATION_9_8 0x38 /* External horizontal duration (MSB) */ -#define HDMI_EXTERNAL_V_TOTAL_7_0 0x39 /* External vertical total (LSB) */ -#define HDMI_EXTERNAL_V_TOTAL_9_8 0x3A /* External vertical total (MSB) */ -#define HDMI_AUDIO_VIDEO_SETTING_2 0x3B /* Audio/Video setting.2 */ -#define HDMI_EXTERNAL_V_BLANK 0x3D /* External vertical blank */ -#define HDMI_EXTERNAL_V_DELAY 0x3E /* External vertical delay */ -#define HDMI_EXTERNAL_V_DURATION 0x3F /* External vertical duration */ -#define HDMI_CTRL_PKT_MANUAL_SEND_CONTROL 0x40 /* Control packet manual send control */ -#define HDMI_CTRL_PKT_AUTO_SEND 0x41 /* Control packet auto send with VSYNC control */ -#define HDMI_AUTO_CHECKSUM_OPTION 0x42 /* Auto checksum option */ -#define HDMI_VIDEO_SETTING_2 0x45 /* Video setting.2 */ -#define HDMI_OUTPUT_OPTION 0x46 /* Output option */ -#define HDMI_SLIPHDMIT_PARAM_OPTION 0x51 /* SLIPHDMIT parameter option */ -#define HDMI_HSYNC_PMENT_AT_EMB_7_0 0x52 /* HSYNC placement at embedded sync (LSB) */ -#define HDMI_HSYNC_PMENT_AT_EMB_15_8 0x53 /* HSYNC placement at embedded sync (MSB) */ -#define HDMI_VSYNC_PMENT_AT_EMB_7_0 0x54 /* VSYNC placement at embedded sync (LSB) */ -#define HDMI_VSYNC_PMENT_AT_EMB_14_8 0x55 /* VSYNC placement at embedded sync (MSB) */ -#define HDMI_SLIPHDMIT_PARAM_SETTINGS_1 0x56 /* SLIPHDMIT parameter settings.1 */ -#define HDMI_SLIPHDMIT_PARAM_SETTINGS_2 0x57 /* SLIPHDMIT parameter settings.2 */ -#define HDMI_SLIPHDMIT_PARAM_SETTINGS_3 0x58 /* SLIPHDMIT parameter settings.3 */ -#define HDMI_SLIPHDMIT_PARAM_SETTINGS_5 0x59 /* SLIPHDMIT parameter settings.5 */ -#define HDMI_SLIPHDMIT_PARAM_SETTINGS_6 0x5A /* SLIPHDMIT parameter settings.6 */ -#define HDMI_SLIPHDMIT_PARAM_SETTINGS_7 0x5B /* SLIPHDMIT parameter settings.7 */ -#define HDMI_SLIPHDMIT_PARAM_SETTINGS_8 0x5C /* SLIPHDMIT parameter settings.8 */ -#define HDMI_SLIPHDMIT_PARAM_SETTINGS_9 0x5D /* SLIPHDMIT parameter settings.9 */ -#define HDMI_SLIPHDMIT_PARAM_SETTINGS_10 0x5E /* SLIPHDMIT parameter settings.10 */ -#define HDMI_CTRL_PKT_BUF_INDEX 0x5F /* Control packet buffer index */ -#define HDMI_CTRL_PKT_BUF_ACCESS_HB0 0x60 /* Control packet data buffer access window - HB0 */ -#define HDMI_CTRL_PKT_BUF_ACCESS_HB1 0x61 /* Control packet data buffer access window - HB1 */ -#define HDMI_CTRL_PKT_BUF_ACCESS_HB2 0x62 /* Control packet data buffer access window - HB2 */ -#define HDMI_CTRL_PKT_BUF_ACCESS_PB0 0x63 /* Control packet data buffer access window - PB0 */ -#define HDMI_CTRL_PKT_BUF_ACCESS_PB1 0x64 /* Control packet data buffer access window - PB1 */ -#define HDMI_CTRL_PKT_BUF_ACCESS_PB2 0x65 /* Control packet data buffer access window - PB2 */ -#define HDMI_CTRL_PKT_BUF_ACCESS_PB3 0x66 /* Control packet data buffer access window - PB3 */ -#define HDMI_CTRL_PKT_BUF_ACCESS_PB4 0x67 /* Control packet data buffer access window - PB4 */ -#define HDMI_CTRL_PKT_BUF_ACCESS_PB5 0x68 /* Control packet data buffer access window - PB5 */ -#define HDMI_CTRL_PKT_BUF_ACCESS_PB6 0x69 /* Control packet data buffer access window - PB6 */ -#define HDMI_CTRL_PKT_BUF_ACCESS_PB7 0x6A /* Control packet data buffer access window - PB7 */ -#define HDMI_CTRL_PKT_BUF_ACCESS_PB8 0x6B /* Control packet data buffer access window - PB8 */ -#define HDMI_CTRL_PKT_BUF_ACCESS_PB9 0x6C /* Control packet data buffer access window - PB9 */ -#define HDMI_CTRL_PKT_BUF_ACCESS_PB10 0x6D /* Control packet data buffer access window - PB10 */ -#define HDMI_CTRL_PKT_BUF_ACCESS_PB11 0x6E /* Control packet data buffer access window - PB11 */ -#define HDMI_CTRL_PKT_BUF_ACCESS_PB12 0x6F /* Control packet data buffer access window - PB12 */ -#define HDMI_CTRL_PKT_BUF_ACCESS_PB13 0x70 /* Control packet data buffer access window - PB13 */ -#define HDMI_CTRL_PKT_BUF_ACCESS_PB14 0x71 /* Control packet data buffer access window - PB14 */ -#define HDMI_CTRL_PKT_BUF_ACCESS_PB15 0x72 /* Control packet data buffer access window - PB15 */ -#define HDMI_CTRL_PKT_BUF_ACCESS_PB16 0x73 /* Control packet data buffer access window - PB16 */ -#define HDMI_CTRL_PKT_BUF_ACCESS_PB17 0x74 /* Control packet data buffer access window - PB17 */ -#define HDMI_CTRL_PKT_BUF_ACCESS_PB18 0x75 /* Control packet data buffer access window - PB18 */ -#define HDMI_CTRL_PKT_BUF_ACCESS_PB19 0x76 /* Control packet data buffer access window - PB19 */ -#define HDMI_CTRL_PKT_BUF_ACCESS_PB20 0x77 /* Control packet data buffer access window - PB20 */ -#define HDMI_CTRL_PKT_BUF_ACCESS_PB21 0x78 /* Control packet data buffer access window - PB21 */ -#define HDMI_CTRL_PKT_BUF_ACCESS_PB22 0x79 /* Control packet data buffer access window - PB22 */ -#define HDMI_CTRL_PKT_BUF_ACCESS_PB23 0x7A /* Control packet data buffer access window - PB23 */ -#define HDMI_CTRL_PKT_BUF_ACCESS_PB24 0x7B /* Control packet data buffer access window - PB24 */ -#define HDMI_CTRL_PKT_BUF_ACCESS_PB25 0x7C /* Control packet data buffer access window - PB25 */ -#define HDMI_CTRL_PKT_BUF_ACCESS_PB26 0x7D /* Control packet data buffer access window - PB26 */ -#define HDMI_CTRL_PKT_BUF_ACCESS_PB27 0x7E /* Control packet data buffer access window - PB27 */ -#define HDMI_EDID_KSV_FIFO_ACCESS_WINDOW 0x80 /* EDID/KSV FIFO access window */ -#define HDMI_DDC_BUS_ACCESS_FREQ_CTRL_7_0 0x81 /* DDC bus access frequency control (LSB) */ -#define HDMI_DDC_BUS_ACCESS_FREQ_CTRL_15_8 0x82 /* DDC bus access frequency control (MSB) */ -#define HDMI_INTERRUPT_MASK_1 0x92 /* Interrupt mask.1 */ -#define HDMI_INTERRUPT_MASK_2 0x93 /* Interrupt mask.2 */ -#define HDMI_INTERRUPT_STATUS_1 0x94 /* Interrupt status.1 */ -#define HDMI_INTERRUPT_STATUS_2 0x95 /* Interrupt status.2 */ -#define HDMI_INTERRUPT_MASK_3 0x96 /* Interrupt mask.3 */ -#define HDMI_INTERRUPT_MASK_4 0x97 /* Interrupt mask.4 */ -#define HDMI_INTERRUPT_STATUS_3 0x98 /* Interrupt status.3 */ -#define HDMI_INTERRUPT_STATUS_4 0x99 /* Interrupt status.4 */ -#define HDMI_SOFTWARE_HDCP_CONTROL_1 0x9A /* Software HDCP control.1 */ -#define HDMI_FRAME_COUNTER 0x9C /* Frame counter */ -#define HDMI_FRAME_COUNTER_FOR_RI_CHECK 0x9D /* Frame counter for Ri check */ -#define HDMI_HDCP_CONTROL 0xAF /* HDCP control */ -#define HDMI_RI_FRAME_COUNT_REGISTER 0xB2 /* Ri frame count register */ -#define HDMI_DDC_BUS_CONTROL 0xB7 /* DDC bus control */ -#define HDMI_HDCP_STATUS 0xB8 /* HDCP status */ -#define HDMI_SHA0 0xB9 /* sha0 */ -#define HDMI_SHA1 0xBA /* sha1 */ -#define HDMI_SHA2 0xBB /* sha2 */ -#define HDMI_SHA3 0xBC /* sha3 */ -#define HDMI_SHA4 0xBD /* sha4 */ -#define HDMI_BCAPS_READ 0xBE /* BCAPS read / debug */ -#define HDMI_AKSV_BKSV_7_0_MONITOR 0xBF /* AKSV/BKSV[7:0] monitor */ -#define HDMI_AKSV_BKSV_15_8_MONITOR 0xC0 /* AKSV/BKSV[15:8] monitor */ -#define HDMI_AKSV_BKSV_23_16_MONITOR 0xC1 /* AKSV/BKSV[23:16] monitor */ -#define HDMI_AKSV_BKSV_31_24_MONITOR 0xC2 /* AKSV/BKSV[31:24] monitor */ -#define HDMI_AKSV_BKSV_39_32_MONITOR 0xC3 /* AKSV/BKSV[39:32] monitor */ -#define HDMI_EDID_SEGMENT_POINTER 0xC4 /* EDID segment pointer */ -#define HDMI_EDID_WORD_ADDRESS 0xC5 /* EDID word address */ -#define HDMI_EDID_DATA_FIFO_ADDRESS 0xC6 /* EDID data FIFO address */ -#define HDMI_NUM_OF_HDMI_DEVICES 0xC7 /* Number of HDMI devices */ -#define HDMI_HDCP_ERROR_CODE 0xC8 /* HDCP error code */ -#define HDMI_100MS_TIMER_SET 0xC9 /* 100ms timer setting */ -#define HDMI_5SEC_TIMER_SET 0xCA /* 5sec timer setting */ -#define HDMI_RI_READ_COUNT 0xCB /* Ri read count */ -#define HDMI_AN_SEED 0xCC /* An seed */ -#define HDMI_MAX_NUM_OF_RCIVRS_ALLOWED 0xCD /* Maximum number of receivers allowed */ -#define HDMI_HDCP_MEMORY_ACCESS_CONTROL_1 0xCE /* HDCP memory access control.1 */ -#define HDMI_HDCP_MEMORY_ACCESS_CONTROL_2 0xCF /* HDCP memory access control.2 */ -#define HDMI_HDCP_CONTROL_2 0xD0 /* HDCP Control 2 */ -#define HDMI_HDCP_KEY_MEMORY_CONTROL 0xD2 /* HDCP Key Memory Control */ -#define HDMI_COLOR_SPACE_CONV_CONFIG_1 0xD3 /* Color space conversion configuration.1 */ -#define HDMI_VIDEO_SETTING_3 0xD4 /* Video setting.3 */ -#define HDMI_RI_7_0 0xD5 /* Ri[7:0] */ -#define HDMI_RI_15_8 0xD6 /* Ri[15:8] */ -#define HDMI_PJ 0xD7 /* Pj */ -#define HDMI_SHA_RD 0xD8 /* sha_rd */ -#define HDMI_RI_7_0_SAVED 0xD9 /* Ri[7:0] saved */ -#define HDMI_RI_15_8_SAVED 0xDA /* Ri[15:8] saved */ -#define HDMI_PJ_SAVED 0xDB /* Pj saved */ -#define HDMI_NUM_OF_DEVICES 0xDC /* Number of devices */ -#define HDMI_HOT_PLUG_MSENS_STATUS 0xDF /* Hot plug/MSENS status */ -#define HDMI_BCAPS_WRITE 0xE0 /* bcaps */ -#define HDMI_BSTAT_7_0 0xE1 /* bstat[7:0] */ -#define HDMI_BSTAT_15_8 0xE2 /* bstat[15:8] */ -#define HDMI_BKSV_7_0 0xE3 /* bksv[7:0] */ -#define HDMI_BKSV_15_8 0xE4 /* bksv[15:8] */ -#define HDMI_BKSV_23_16 0xE5 /* bksv[23:16] */ -#define HDMI_BKSV_31_24 0xE6 /* bksv[31:24] */ -#define HDMI_BKSV_39_32 0xE7 /* bksv[39:32] */ -#define HDMI_AN_7_0 0xE8 /* An[7:0] */ -#define HDMI_AN_15_8 0xE9 /* An [15:8] */ -#define HDMI_AN_23_16 0xEA /* An [23:16] */ -#define HDMI_AN_31_24 0xEB /* An [31:24] */ -#define HDMI_AN_39_32 0xEC /* An [39:32] */ -#define HDMI_AN_47_40 0xED /* An [47:40] */ -#define HDMI_AN_55_48 0xEE /* An [55:48] */ -#define HDMI_AN_63_56 0xEF /* An [63:56] */ -#define HDMI_PRODUCT_ID 0xF0 /* Product ID */ -#define HDMI_REVISION_ID 0xF1 /* Revision ID */ -#define HDMI_TEST_MODE 0xFE /* Test mode */ - -/* HDMI Control Register (HTOP1) */ -#define HDMI_HTOP1_TEST_MODE 0x0000 /* Test mode */ -#define HDMI_HTOP1_VIDEO_INPUT 0x0008 /* VideoInput */ -#define HDMI_HTOP1_CORE_RSTN 0x000C /* CoreResetn */ -#define HDMI_HTOP1_PLLBW 0x0018 /* PLLBW */ -#define HDMI_HTOP1_CLK_TO_PHY 0x001C /* Clk to Phy */ -#define HDMI_HTOP1_VIDEO_INPUT2 0x0020 /* VideoInput2 */ -#define HDMI_HTOP1_TISEMP0_1 0x0024 /* tisemp0-1 */ -#define HDMI_HTOP1_TISEMP2_C 0x0028 /* tisemp2-c */ -#define HDMI_HTOP1_TISIDRV 0x002C /* tisidrv */ -#define HDMI_HTOP1_TISEN 0x0034 /* tisen */ -#define HDMI_HTOP1_TISDREN 0x0038 /* tisdren */ -#define HDMI_HTOP1_CISRANGE 0x003C /* cisrange */ -#define HDMI_HTOP1_ENABLE_SELECTOR 0x0040 /* Enable Selector */ -#define HDMI_HTOP1_MACRO_RESET 0x0044 /* Macro reset */ -#define HDMI_HTOP1_PLL_CALIBRATION 0x0048 /* PLL calibration */ -#define HDMI_HTOP1_RE_CALIBRATION 0x004C /* Re-calibration */ -#define HDMI_HTOP1_CURRENT 0x0050 /* Current */ -#define HDMI_HTOP1_PLL_LOCK_DETECT 0x0054 /* PLL lock detect */ -#define HDMI_HTOP1_PHY_TEST_MODE 0x0058 /* PHY Test Mode */ -#define HDMI_HTOP1_CLK_SET 0x0080 /* Clock Set */ -#define HDMI_HTOP1_DDC_FAIL_SAFE 0x0084 /* DDC fail safe */ -#define HDMI_HTOP1_PRBS 0x0088 /* PRBS */ -#define HDMI_HTOP1_EDID_AINC_CONTROL 0x008C /* EDID ainc Control */ -#define HDMI_HTOP1_HTOP_DCL_MODE 0x00FC /* Deep Coloer Mode */ -#define HDMI_HTOP1_HTOP_DCL_FRC_COEF0 0x0100 /* Deep Color:FRC COEF0 */ -#define HDMI_HTOP1_HTOP_DCL_FRC_COEF1 0x0104 /* Deep Color:FRC COEF1 */ -#define HDMI_HTOP1_HTOP_DCL_FRC_COEF2 0x0108 /* Deep Color:FRC COEF2 */ -#define HDMI_HTOP1_HTOP_DCL_FRC_COEF3 0x010C /* Deep Color:FRC COEF3 */ -#define HDMI_HTOP1_HTOP_DCL_FRC_COEF0_C 0x0110 /* Deep Color:FRC COEF0C */ -#define HDMI_HTOP1_HTOP_DCL_FRC_COEF1_C 0x0114 /* Deep Color:FRC COEF1C */ -#define HDMI_HTOP1_HTOP_DCL_FRC_COEF2_C 0x0118 /* Deep Color:FRC COEF2C */ -#define HDMI_HTOP1_HTOP_DCL_FRC_COEF3_C 0x011C /* Deep Color:FRC COEF3C */ -#define HDMI_HTOP1_HTOP_DCL_FRC_MODE 0x0120 /* Deep Color:FRC Mode */ -#define HDMI_HTOP1_HTOP_DCL_RECT_START1 0x0124 /* Deep Color:Rect Start1 */ -#define HDMI_HTOP1_HTOP_DCL_RECT_SIZE1 0x0128 /* Deep Color:Rect Size1 */ -#define HDMI_HTOP1_HTOP_DCL_RECT_START2 0x012C /* Deep Color:Rect Start2 */ -#define HDMI_HTOP1_HTOP_DCL_RECT_SIZE2 0x0130 /* Deep Color:Rect Size2 */ -#define HDMI_HTOP1_HTOP_DCL_RECT_START3 0x0134 /* Deep Color:Rect Start3 */ -#define HDMI_HTOP1_HTOP_DCL_RECT_SIZE3 0x0138 /* Deep Color:Rect Size3 */ -#define HDMI_HTOP1_HTOP_DCL_RECT_START4 0x013C /* Deep Color:Rect Start4 */ -#define HDMI_HTOP1_HTOP_DCL_RECT_SIZE4 0x0140 /* Deep Color:Rect Size4 */ -#define HDMI_HTOP1_HTOP_DCL_FIL_PARA_Y1_1 0x0144 /* Deep Color:Fil Para Y1_1 */ -#define HDMI_HTOP1_HTOP_DCL_FIL_PARA_Y1_2 0x0148 /* Deep Color:Fil Para Y1_2 */ -#define HDMI_HTOP1_HTOP_DCL_FIL_PARA_CB1_1 0x014C /* Deep Color:Fil Para CB1_1 */ -#define HDMI_HTOP1_HTOP_DCL_FIL_PARA_CB1_2 0x0150 /* Deep Color:Fil Para CB1_2 */ -#define HDMI_HTOP1_HTOP_DCL_FIL_PARA_CR1_1 0x0154 /* Deep Color:Fil Para CR1_1 */ -#define HDMI_HTOP1_HTOP_DCL_FIL_PARA_CR1_2 0x0158 /* Deep Color:Fil Para CR1_2 */ -#define HDMI_HTOP1_HTOP_DCL_FIL_PARA_Y2_1 0x015C /* Deep Color:Fil Para Y2_1 */ -#define HDMI_HTOP1_HTOP_DCL_FIL_PARA_Y2_2 0x0160 /* Deep Color:Fil Para Y2_2 */ -#define HDMI_HTOP1_HTOP_DCL_FIL_PARA_CB2_1 0x0164 /* Deep Color:Fil Para CB2_1 */ -#define HDMI_HTOP1_HTOP_DCL_FIL_PARA_CB2_2 0x0168 /* Deep Color:Fil Para CB2_2 */ -#define HDMI_HTOP1_HTOP_DCL_FIL_PARA_CR2_1 0x016C /* Deep Color:Fil Para CR2_1 */ -#define HDMI_HTOP1_HTOP_DCL_FIL_PARA_CR2_2 0x0170 /* Deep Color:Fil Para CR2_2 */ -#define HDMI_HTOP1_HTOP_DCL_COR_PARA_Y1 0x0174 /* Deep Color:Cor Para Y1 */ -#define HDMI_HTOP1_HTOP_DCL_COR_PARA_CB1 0x0178 /* Deep Color:Cor Para CB1 */ -#define HDMI_HTOP1_HTOP_DCL_COR_PARA_CR1 0x017C /* Deep Color:Cor Para CR1 */ -#define HDMI_HTOP1_HTOP_DCL_COR_PARA_Y2 0x0180 /* Deep Color:Cor Para Y2 */ -#define HDMI_HTOP1_HTOP_DCL_COR_PARA_CB2 0x0184 /* Deep Color:Cor Para CB2 */ -#define HDMI_HTOP1_HTOP_DCL_COR_PARA_CR2 0x0188 /* Deep Color:Cor Para CR2 */ -#define HDMI_HTOP1_EDID_DATA_READ 0x0200 /* EDID Data Read 128Byte:0x03FC */ - -enum hotplug_state { - HDMI_HOTPLUG_DISCONNECTED, - HDMI_HOTPLUG_CONNECTED, - HDMI_HOTPLUG_EDID_DONE, -}; - -struct sh_hdmi { - struct sh_mobile_lcdc_entity entity; - - void __iomem *base; - void __iomem *htop1; - enum hotplug_state hp_state; /* hot-plug status */ - u8 preprogrammed_vic; /* use a pre-programmed VIC or - the external mode */ - u8 edid_block_addr; - u8 edid_segment_nr; - u8 edid_blocks; - int irq; - struct clk *hdmi_clk; - struct device *dev; - struct delayed_work edid_work; - struct fb_videomode mode; - struct fb_monspecs monspec; - - /* register access functions */ - void (*write)(struct sh_hdmi *hdmi, u8 data, u8 reg); - u8 (*read)(struct sh_hdmi *hdmi, u8 reg); -}; - -#define entity_to_sh_hdmi(e) container_of(e, struct sh_hdmi, entity) - -static void __hdmi_write8(struct sh_hdmi *hdmi, u8 data, u8 reg) -{ - iowrite8(data, hdmi->base + reg); -} - -static u8 __hdmi_read8(struct sh_hdmi *hdmi, u8 reg) -{ - return ioread8(hdmi->base + reg); -} - -static void __hdmi_write32(struct sh_hdmi *hdmi, u8 data, u8 reg) -{ - iowrite32((u32)data, hdmi->base + (reg * 4)); - udelay(100); -} - -static u8 __hdmi_read32(struct sh_hdmi *hdmi, u8 reg) -{ - return (u8)ioread32(hdmi->base + (reg * 4)); -} - -static void hdmi_write(struct sh_hdmi *hdmi, u8 data, u8 reg) -{ - hdmi->write(hdmi, data, reg); -} - -static u8 hdmi_read(struct sh_hdmi *hdmi, u8 reg) -{ - return hdmi->read(hdmi, reg); -} - -static void hdmi_bit_set(struct sh_hdmi *hdmi, u8 mask, u8 data, u8 reg) -{ - u8 val = hdmi_read(hdmi, reg); - - val &= ~mask; - val |= (data & mask); - - hdmi_write(hdmi, val, reg); -} - -static void hdmi_htop1_write(struct sh_hdmi *hdmi, u32 data, u32 reg) -{ - iowrite32(data, hdmi->htop1 + reg); - udelay(100); -} - -static u32 hdmi_htop1_read(struct sh_hdmi *hdmi, u32 reg) -{ - return ioread32(hdmi->htop1 + reg); -} - -/* - * HDMI sound - */ -static unsigned int sh_hdmi_snd_read(struct snd_soc_codec *codec, - unsigned int reg) -{ - struct sh_hdmi *hdmi = snd_soc_codec_get_drvdata(codec); - - return hdmi_read(hdmi, reg); -} - -static int sh_hdmi_snd_write(struct snd_soc_codec *codec, - unsigned int reg, - unsigned int value) -{ - struct sh_hdmi *hdmi = snd_soc_codec_get_drvdata(codec); - - hdmi_write(hdmi, value, reg); - return 0; -} - -static struct snd_soc_dai_driver sh_hdmi_dai = { - .name = "sh_mobile_hdmi-hifi", - .playback = { - .stream_name = "Playback", - .channels_min = 2, - .channels_max = 8, - .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | - SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | - SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | - SNDRV_PCM_RATE_192000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, - }, -}; - -static int sh_hdmi_snd_probe(struct snd_soc_codec *codec) -{ - dev_info(codec->dev, "SH Mobile HDMI Audio Codec"); - - return 0; -} - -static struct snd_soc_codec_driver soc_codec_dev_sh_hdmi = { - .probe = sh_hdmi_snd_probe, - .read = sh_hdmi_snd_read, - .write = sh_hdmi_snd_write, -}; - -/* - * HDMI video - */ - -/* External video parameter settings */ -static void sh_hdmi_external_video_param(struct sh_hdmi *hdmi) -{ - struct fb_videomode *mode = &hdmi->mode; - u16 htotal, hblank, hdelay, vtotal, vblank, vdelay, voffset; - u8 sync = 0; - - htotal = mode->xres + mode->right_margin + mode->left_margin - + mode->hsync_len; - hdelay = mode->hsync_len + mode->left_margin; - hblank = mode->right_margin + hdelay; - - /* - * Vertical timing looks a bit different in Figure 18, - * but let's try the same first by setting offset = 0 - */ - vtotal = mode->yres + mode->upper_margin + mode->lower_margin - + mode->vsync_len; - vdelay = mode->vsync_len + mode->upper_margin; - vblank = mode->lower_margin + vdelay; - voffset = min(mode->upper_margin / 2, 6U); - - /* - * [3]: VSYNC polarity: Positive - * [2]: HSYNC polarity: Positive - * [1]: Interlace/Progressive: Progressive - * [0]: External video settings enable: used. - */ - if (mode->sync & FB_SYNC_HOR_HIGH_ACT) - sync |= 4; - if (mode->sync & FB_SYNC_VERT_HIGH_ACT) - sync |= 8; - - dev_dbg(hdmi->dev, "H: %u, %u, %u, %u; V: %u, %u, %u, %u; sync 0x%x\n", - htotal, hblank, hdelay, mode->hsync_len, - vtotal, vblank, vdelay, mode->vsync_len, sync); - - hdmi_write(hdmi, sync | (voffset << 4), HDMI_EXTERNAL_VIDEO_PARAM_SETTINGS); - - hdmi_write(hdmi, htotal, HDMI_EXTERNAL_H_TOTAL_7_0); - hdmi_write(hdmi, htotal >> 8, HDMI_EXTERNAL_H_TOTAL_11_8); - - hdmi_write(hdmi, hblank, HDMI_EXTERNAL_H_BLANK_7_0); - hdmi_write(hdmi, hblank >> 8, HDMI_EXTERNAL_H_BLANK_9_8); - - hdmi_write(hdmi, hdelay, HDMI_EXTERNAL_H_DELAY_7_0); - hdmi_write(hdmi, hdelay >> 8, HDMI_EXTERNAL_H_DELAY_9_8); - - hdmi_write(hdmi, mode->hsync_len, HDMI_EXTERNAL_H_DURATION_7_0); - hdmi_write(hdmi, mode->hsync_len >> 8, HDMI_EXTERNAL_H_DURATION_9_8); - - hdmi_write(hdmi, vtotal, HDMI_EXTERNAL_V_TOTAL_7_0); - hdmi_write(hdmi, vtotal >> 8, HDMI_EXTERNAL_V_TOTAL_9_8); - - hdmi_write(hdmi, vblank, HDMI_EXTERNAL_V_BLANK); - - hdmi_write(hdmi, vdelay, HDMI_EXTERNAL_V_DELAY); - - hdmi_write(hdmi, mode->vsync_len, HDMI_EXTERNAL_V_DURATION); - - /* Set bit 0 of HDMI_EXTERNAL_VIDEO_PARAM_SETTINGS here for external mode */ - if (!hdmi->preprogrammed_vic) - hdmi_write(hdmi, sync | 1 | (voffset << 4), - HDMI_EXTERNAL_VIDEO_PARAM_SETTINGS); -} - -/** - * sh_hdmi_video_config() - */ -static void sh_hdmi_video_config(struct sh_hdmi *hdmi) -{ - /* - * [7:4]: Audio sampling frequency: 48kHz - * [3:1]: Input video format: RGB and YCbCr 4:4:4 (Y on Green) - * [0]: Internal/External DE select: internal - */ - hdmi_write(hdmi, 0x20, HDMI_AUDIO_VIDEO_SETTING_1); - - /* - * [7:6]: Video output format: RGB 4:4:4 - * [5:4]: Input video data width: 8 bit - * [3:1]: EAV/SAV location: channel 1 - * [0]: Video input color space: RGB - */ - hdmi_write(hdmi, 0x34, HDMI_VIDEO_SETTING_1); - - /* - * [7:6]: Together with bit [6] of HDMI_AUDIO_VIDEO_SETTING_2, which is - * left at 0 by default, this configures 24bpp and sets the Color Depth - * (CD) field in the General Control Packet - */ - hdmi_write(hdmi, 0x20, HDMI_DEEP_COLOR_MODES); -} - -/** - * sh_hdmi_audio_config() - */ -static void sh_hdmi_audio_config(struct sh_hdmi *hdmi) -{ - u8 data; - struct sh_mobile_hdmi_info *pdata = dev_get_platdata(hdmi->dev); - - /* - * [7:4] L/R data swap control - * [3:0] appropriate N[19:16] - */ - hdmi_write(hdmi, 0x00, HDMI_L_R_DATA_SWAP_CTRL_RPKT); - /* appropriate N[15:8] */ - hdmi_write(hdmi, 0x18, HDMI_20_BIT_N_FOR_AUDIO_RPKT_15_8); - /* appropriate N[7:0] */ - hdmi_write(hdmi, 0x00, HDMI_20_BIT_N_FOR_AUDIO_RPKT_7_0); - - /* [7:4] 48 kHz SPDIF not used */ - hdmi_write(hdmi, 0x20, HDMI_SPDIF_AUDIO_SAMP_FREQ_CTS); - - /* - * [6:5] set required down sampling rate if required - * [4:3] set required audio source - */ - switch (pdata->flags & HDMI_SND_SRC_MASK) { - default: - /* fall through */ - case HDMI_SND_SRC_I2S: - data = 0x0 << 3; - break; - case HDMI_SND_SRC_SPDIF: - data = 0x1 << 3; - break; - case HDMI_SND_SRC_DSD: - data = 0x2 << 3; - break; - case HDMI_SND_SRC_HBR: - data = 0x3 << 3; - break; - } - hdmi_write(hdmi, data, HDMI_AUDIO_SETTING_1); - - /* [3:0] set sending channel number for channel status */ - hdmi_write(hdmi, 0x40, HDMI_AUDIO_SETTING_2); - - /* - * [5:2] set valid I2S source input pin - * [1:0] set input I2S source mode - */ - hdmi_write(hdmi, 0x04, HDMI_I2S_AUDIO_SET); - - /* [7:4] set valid DSD source input pin */ - hdmi_write(hdmi, 0x00, HDMI_DSD_AUDIO_SET); - - /* [7:0] set appropriate I2S input pin swap settings if required */ - hdmi_write(hdmi, 0x00, HDMI_I2S_INPUT_PIN_SWAP); - - /* - * [7] set validity bit for channel status - * [3:0] set original sample frequency for channel status - */ - hdmi_write(hdmi, 0x00, HDMI_AUDIO_STATUS_BITS_SETTING_1); - - /* - * [7] set value for channel status - * [6] set value for channel status - * [5] set copyright bit for channel status - * [4:2] set additional information for channel status - * [1:0] set clock accuracy for channel status - */ - hdmi_write(hdmi, 0x00, HDMI_AUDIO_STATUS_BITS_SETTING_2); - - /* [7:0] set category code for channel status */ - hdmi_write(hdmi, 0x00, HDMI_CATEGORY_CODE); - - /* - * [7:4] set source number for channel status - * [3:0] set word length for channel status - */ - hdmi_write(hdmi, 0x00, HDMI_SOURCE_NUM_AUDIO_WORD_LEN); - - /* [7:4] set sample frequency for channel status */ - hdmi_write(hdmi, 0x20, HDMI_AUDIO_VIDEO_SETTING_1); -} - -/** - * sh_hdmi_phy_config() - configure the HDMI PHY for the used video mode - */ -static void sh_hdmi_phy_config(struct sh_hdmi *hdmi) -{ - if (hdmi->mode.pixclock < 10000) { - /* for 1080p8bit 148MHz */ - hdmi_write(hdmi, 0x1d, HDMI_SLIPHDMIT_PARAM_SETTINGS_1); - hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_2); - hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_3); - hdmi_write(hdmi, 0x4c, HDMI_SLIPHDMIT_PARAM_SETTINGS_5); - hdmi_write(hdmi, 0x1e, HDMI_SLIPHDMIT_PARAM_SETTINGS_6); - hdmi_write(hdmi, 0x48, HDMI_SLIPHDMIT_PARAM_SETTINGS_7); - hdmi_write(hdmi, 0x0e, HDMI_SLIPHDMIT_PARAM_SETTINGS_8); - hdmi_write(hdmi, 0x25, HDMI_SLIPHDMIT_PARAM_SETTINGS_9); - hdmi_write(hdmi, 0x04, HDMI_SLIPHDMIT_PARAM_SETTINGS_10); - } else if (hdmi->mode.pixclock < 30000) { - /* 720p, 8bit, 74.25MHz. Might need to be adjusted for other formats */ - /* - * [1:0] Speed_A - * [3:2] Speed_B - * [4] PLLA_Bypass - * [6] DRV_TEST_EN - * [7] DRV_TEST_IN - */ - hdmi_write(hdmi, 0x0f, HDMI_SLIPHDMIT_PARAM_SETTINGS_1); - /* PLLB_CONFIG[17], PLLA_CONFIG[17] - not in PHY datasheet */ - hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_2); - /* - * [2:0] BGR_I_OFFSET - * [6:4] BGR_V_OFFSET - */ - hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_3); - /* PLLA_CONFIG[7:0]: VCO gain, VCO offset, LPF resistance[0] */ - hdmi_write(hdmi, 0x44, HDMI_SLIPHDMIT_PARAM_SETTINGS_5); - /* - * PLLA_CONFIG[15:8]: regulator voltage[0], CP current, - * LPF capacitance, LPF resistance[1] - */ - hdmi_write(hdmi, 0x32, HDMI_SLIPHDMIT_PARAM_SETTINGS_6); - /* PLLB_CONFIG[7:0]: LPF resistance[0], VCO offset, VCO gain */ - hdmi_write(hdmi, 0x4A, HDMI_SLIPHDMIT_PARAM_SETTINGS_7); - /* - * PLLB_CONFIG[15:8]: regulator voltage[0], CP current, - * LPF capacitance, LPF resistance[1] - */ - hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_8); - /* DRV_CONFIG, PE_CONFIG */ - hdmi_write(hdmi, 0x25, HDMI_SLIPHDMIT_PARAM_SETTINGS_9); - /* - * [2:0] AMON_SEL (4 == LPF voltage) - * [4] PLLA_CONFIG[16] - * [5] PLLB_CONFIG[16] - */ - hdmi_write(hdmi, 0x04, HDMI_SLIPHDMIT_PARAM_SETTINGS_10); - } else { - /* for 480p8bit 27MHz */ - hdmi_write(hdmi, 0x19, HDMI_SLIPHDMIT_PARAM_SETTINGS_1); - hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_2); - hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_3); - hdmi_write(hdmi, 0x44, HDMI_SLIPHDMIT_PARAM_SETTINGS_5); - hdmi_write(hdmi, 0x32, HDMI_SLIPHDMIT_PARAM_SETTINGS_6); - hdmi_write(hdmi, 0x48, HDMI_SLIPHDMIT_PARAM_SETTINGS_7); - hdmi_write(hdmi, 0x0F, HDMI_SLIPHDMIT_PARAM_SETTINGS_8); - hdmi_write(hdmi, 0x20, HDMI_SLIPHDMIT_PARAM_SETTINGS_9); - hdmi_write(hdmi, 0x04, HDMI_SLIPHDMIT_PARAM_SETTINGS_10); - } -} - -/** - * sh_hdmi_avi_infoframe_setup() - Auxiliary Video Information InfoFrame CONTROL PACKET - */ -static void sh_hdmi_avi_infoframe_setup(struct sh_hdmi *hdmi) -{ - u8 vic; - - /* AVI InfoFrame */ - hdmi_write(hdmi, 0x06, HDMI_CTRL_PKT_BUF_INDEX); - - /* Packet Type = 0x82 */ - hdmi_write(hdmi, 0x82, HDMI_CTRL_PKT_BUF_ACCESS_HB0); - - /* Version = 0x02 */ - hdmi_write(hdmi, 0x02, HDMI_CTRL_PKT_BUF_ACCESS_HB1); - - /* Length = 13 (0x0D) */ - hdmi_write(hdmi, 0x0D, HDMI_CTRL_PKT_BUF_ACCESS_HB2); - - /* N. A. Checksum */ - hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB0); - - /* - * Y = RGB - * A0 = No Data - * B = Bar Data not valid - * S = No Data - */ - hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB1); - - /* - * [7:6] C = Colorimetry: no data - * [5:4] M = 2: 16:9, 1: 4:3 Picture Aspect Ratio - * [3:0] R = 8: Active Frame Aspect Ratio: same as picture aspect ratio - */ - hdmi_write(hdmi, 0x28, HDMI_CTRL_PKT_BUF_ACCESS_PB2); - - /* - * ITC = No Data - * EC = xvYCC601 - * Q = Default (depends on video format) - * SC = No Known non_uniform Scaling - */ - hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB3); - - /* - * VIC should be ignored if external config is used, so, we could just use 0, - * but play safe and use a valid value in any case just in case - */ - if (hdmi->preprogrammed_vic) - vic = hdmi->preprogrammed_vic; - else - vic = 4; - hdmi_write(hdmi, vic, HDMI_CTRL_PKT_BUF_ACCESS_PB4); - - /* PR = No Repetition */ - hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB5); - - /* Line Number of End of Top Bar (lower 8 bits) */ - hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB6); - - /* Line Number of End of Top Bar (upper 8 bits) */ - hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB7); - - /* Line Number of Start of Bottom Bar (lower 8 bits) */ - hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB8); - - /* Line Number of Start of Bottom Bar (upper 8 bits) */ - hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB9); - - /* Pixel Number of End of Left Bar (lower 8 bits) */ - hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB10); - - /* Pixel Number of End of Left Bar (upper 8 bits) */ - hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB11); - - /* Pixel Number of Start of Right Bar (lower 8 bits) */ - hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB12); - - /* Pixel Number of Start of Right Bar (upper 8 bits) */ - hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB13); -} - -/** - * sh_hdmi_audio_infoframe_setup() - Audio InfoFrame of CONTROL PACKET - */ -static void sh_hdmi_audio_infoframe_setup(struct sh_hdmi *hdmi) -{ - /* Audio InfoFrame */ - hdmi_write(hdmi, 0x08, HDMI_CTRL_PKT_BUF_INDEX); - - /* Packet Type = 0x84 */ - hdmi_write(hdmi, 0x84, HDMI_CTRL_PKT_BUF_ACCESS_HB0); - - /* Version Number = 0x01 */ - hdmi_write(hdmi, 0x01, HDMI_CTRL_PKT_BUF_ACCESS_HB1); - - /* 0 Length = 10 (0x0A) */ - hdmi_write(hdmi, 0x0A, HDMI_CTRL_PKT_BUF_ACCESS_HB2); - - /* n. a. Checksum */ - hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB0); - - /* Audio Channel Count = Refer to Stream Header */ - hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB1); - - /* Refer to Stream Header */ - hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB2); - - /* Format depends on coding type (i.e. CT0...CT3) */ - hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB3); - - /* Speaker Channel Allocation = Front Right + Front Left */ - hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB4); - - /* Level Shift Value = 0 dB, Down - mix is permitted or no information */ - hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB5); - - /* Reserved (0) */ - hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB6); - hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB7); - hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB8); - hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB9); - hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB10); -} - -/** - * sh_hdmi_configure() - Initialise HDMI for output - */ -static void sh_hdmi_configure(struct sh_hdmi *hdmi) -{ - /* Configure video format */ - sh_hdmi_video_config(hdmi); - - /* Configure audio format */ - sh_hdmi_audio_config(hdmi); - - /* Configure PHY */ - sh_hdmi_phy_config(hdmi); - - /* Auxiliary Video Information (AVI) InfoFrame */ - sh_hdmi_avi_infoframe_setup(hdmi); - - /* Audio InfoFrame */ - sh_hdmi_audio_infoframe_setup(hdmi); - - /* - * Control packet auto send with VSYNC control: auto send - * General control, Gamut metadata, ISRC, and ACP packets - */ - hdmi_write(hdmi, 0x8E, HDMI_CTRL_PKT_AUTO_SEND); - - /* FIXME */ - msleep(10); - - /* PS mode b->d, reset PLLA and PLLB */ - hdmi_bit_set(hdmi, 0xFC, 0x4C, HDMI_SYSTEM_CTRL); - - udelay(10); - - hdmi_bit_set(hdmi, 0xFC, 0x40, HDMI_SYSTEM_CTRL); -} - -static unsigned long sh_hdmi_rate_error(struct sh_hdmi *hdmi, - const struct fb_videomode *mode, - unsigned long *hdmi_rate, unsigned long *parent_rate) -{ - unsigned long target = PICOS2KHZ(mode->pixclock) * 1000, rate_error; - struct sh_mobile_hdmi_info *pdata = dev_get_platdata(hdmi->dev); - - *hdmi_rate = clk_round_rate(hdmi->hdmi_clk, target); - if ((long)*hdmi_rate < 0) - *hdmi_rate = clk_get_rate(hdmi->hdmi_clk); - - rate_error = (long)*hdmi_rate > 0 ? abs(*hdmi_rate - target) : ULONG_MAX; - if (rate_error && pdata->clk_optimize_parent) - rate_error = pdata->clk_optimize_parent(target, hdmi_rate, parent_rate); - else if (clk_get_parent(hdmi->hdmi_clk)) - *parent_rate = clk_get_rate(clk_get_parent(hdmi->hdmi_clk)); - - dev_dbg(hdmi->dev, "%u-%u-%u-%u x %u-%u-%u-%u\n", - mode->left_margin, mode->xres, - mode->right_margin, mode->hsync_len, - mode->upper_margin, mode->yres, - mode->lower_margin, mode->vsync_len); - - dev_dbg(hdmi->dev, "\t@%lu(+/-%lu)Hz, e=%lu / 1000, r=%uHz, p=%luHz\n", target, - rate_error, rate_error ? 10000 / (10 * target / rate_error) : 0, - mode->refresh, *parent_rate); - - return rate_error; -} - -static int sh_hdmi_read_edid(struct sh_hdmi *hdmi, unsigned long *hdmi_rate, - unsigned long *parent_rate) -{ - struct sh_mobile_lcdc_chan *ch = hdmi->entity.lcdc; - const struct fb_videomode *mode, *found = NULL; - unsigned int f_width = 0, f_height = 0, f_refresh = 0; - unsigned long found_rate_error = ULONG_MAX; /* silly compiler... */ - bool scanning = false, preferred_bad = false; - bool use_edid_mode = false; - u8 edid[128]; - char *forced; - int i; - - /* Read EDID */ - dev_dbg(hdmi->dev, "Read back EDID code:"); - for (i = 0; i < 128; i++) { - edid[i] = (hdmi->htop1) ? - (u8)hdmi_htop1_read(hdmi, HDMI_HTOP1_EDID_DATA_READ + (i * 4)) : - hdmi_read(hdmi, HDMI_EDID_KSV_FIFO_ACCESS_WINDOW); -#ifdef DEBUG - if ((i % 16) == 0) { - printk(KERN_CONT "\n"); - printk(KERN_DEBUG "%02X | %02X", i, edid[i]); - } else { - printk(KERN_CONT " %02X", edid[i]); - } -#endif - } -#ifdef DEBUG - printk(KERN_CONT "\n"); -#endif - - if (!hdmi->edid_blocks) { - fb_edid_to_monspecs(edid, &hdmi->monspec); - hdmi->edid_blocks = edid[126] + 1; - - dev_dbg(hdmi->dev, "%d main modes, %d extension blocks\n", - hdmi->monspec.modedb_len, hdmi->edid_blocks - 1); - } else { - dev_dbg(hdmi->dev, "Extension %u detected, DTD start %u\n", - edid[0], edid[2]); - fb_edid_add_monspecs(edid, &hdmi->monspec); - } - - if (hdmi->edid_blocks > hdmi->edid_segment_nr * 2 + - (hdmi->edid_block_addr >> 7) + 1) { - /* More blocks to read */ - if (hdmi->edid_block_addr) { - hdmi->edid_block_addr = 0; - hdmi->edid_segment_nr++; - } else { - hdmi->edid_block_addr = 0x80; - } - /* Set EDID word address */ - hdmi_write(hdmi, hdmi->edid_block_addr, HDMI_EDID_WORD_ADDRESS); - /* Enable EDID interrupt */ - hdmi_write(hdmi, 0xC6, HDMI_INTERRUPT_MASK_1); - /* Set EDID segment pointer - starts reading EDID */ - hdmi_write(hdmi, hdmi->edid_segment_nr, HDMI_EDID_SEGMENT_POINTER); - return -EAGAIN; - } - - /* All E-EDID blocks ready */ - dev_dbg(hdmi->dev, "%d main and extended modes\n", hdmi->monspec.modedb_len); - - fb_get_options("sh_mobile_lcdc", &forced); - if (forced && *forced) { - /* Only primitive parsing so far */ - i = sscanf(forced, "%ux%u@%u", - &f_width, &f_height, &f_refresh); - if (i < 2) { - f_width = 0; - f_height = 0; - } else { - /* The user wants us to use the EDID data */ - scanning = true; - } - dev_dbg(hdmi->dev, "Forced mode %ux%u@%uHz\n", - f_width, f_height, f_refresh); - } - - /* Walk monitor modes to find the best or the exact match */ - for (i = 0, mode = hdmi->monspec.modedb; - i < hdmi->monspec.modedb_len && scanning; - i++, mode++) { - unsigned long rate_error; - - if (!f_width && !f_height) { - /* - * A parameter string "video=sh_mobile_lcdc:0x0" means - * use the preferred EDID mode. If it is rejected by - * .fb_check_var(), keep looking, until an acceptable - * one is found. - */ - if ((mode->flag & FB_MODE_IS_FIRST) || preferred_bad) - scanning = false; - else - continue; - } else if (f_width != mode->xres || f_height != mode->yres) { - /* No interest in unmatching modes */ - continue; - } - - rate_error = sh_hdmi_rate_error(hdmi, mode, hdmi_rate, parent_rate); - - if (scanning) { - if (f_refresh == mode->refresh || (!f_refresh && !rate_error)) - /* - * Exact match if either the refresh rate - * matches or it hasn't been specified and we've - * found a mode, for which we can configure the - * clock precisely - */ - scanning = false; - else if (found && found_rate_error <= rate_error) - /* - * We otherwise search for the closest matching - * clock rate - either if no refresh rate has - * been specified or we cannot find an exactly - * matching one - */ - continue; - } - - /* Check if supported: sufficient fb memory, supported clock-rate */ - if (ch && ch->notify && - ch->notify(ch, SH_MOBILE_LCDC_EVENT_DISPLAY_MODE, mode, - NULL)) { - scanning = true; - preferred_bad = true; - continue; - } - - found = mode; - found_rate_error = rate_error; - use_edid_mode = true; - } - - /* - * TODO 1: if no default mode is present, postpone running the config - * until after the LCDC channel is initialized. - * TODO 2: consider registering the HDMI platform device from the LCDC - * driver. - */ - if (!found && hdmi->entity.def_mode.xres != 0) { - found = &hdmi->entity.def_mode; - found_rate_error = sh_hdmi_rate_error(hdmi, found, hdmi_rate, - parent_rate); - } - - /* No cookie today */ - if (!found) - return -ENXIO; - - if (found->xres == 640 && found->yres == 480 && found->refresh == 60) - hdmi->preprogrammed_vic = 1; - else if (found->xres == 720 && found->yres == 480 && found->refresh == 60) - hdmi->preprogrammed_vic = 2; - else if (found->xres == 720 && found->yres == 576 && found->refresh == 50) - hdmi->preprogrammed_vic = 17; - else if (found->xres == 1280 && found->yres == 720 && found->refresh == 60) - hdmi->preprogrammed_vic = 4; - else if (found->xres == 1920 && found->yres == 1080 && found->refresh == 24) - hdmi->preprogrammed_vic = 32; - else if (found->xres == 1920 && found->yres == 1080 && found->refresh == 50) - hdmi->preprogrammed_vic = 31; - else if (found->xres == 1920 && found->yres == 1080 && found->refresh == 60) - hdmi->preprogrammed_vic = 16; - else - hdmi->preprogrammed_vic = 0; - - dev_dbg(hdmi->dev, "Using %s %s mode %ux%u@%uHz (%luHz), " - "clock error %luHz\n", use_edid_mode ? "EDID" : "default", - hdmi->preprogrammed_vic ? "VIC" : "external", found->xres, - found->yres, found->refresh, PICOS2KHZ(found->pixclock) * 1000, - found_rate_error); - - hdmi->mode = *found; - sh_hdmi_external_video_param(hdmi); - - return 0; -} - -static irqreturn_t sh_hdmi_hotplug(int irq, void *dev_id) -{ - struct sh_hdmi *hdmi = dev_id; - u8 status1, status2, mask1, mask2; - - /* mode_b and PLLA and PLLB reset */ - hdmi_bit_set(hdmi, 0xFC, 0x2C, HDMI_SYSTEM_CTRL); - - /* How long shall reset be held? */ - udelay(10); - - /* mode_b and PLLA and PLLB reset release */ - hdmi_bit_set(hdmi, 0xFC, 0x20, HDMI_SYSTEM_CTRL); - - status1 = hdmi_read(hdmi, HDMI_INTERRUPT_STATUS_1); - status2 = hdmi_read(hdmi, HDMI_INTERRUPT_STATUS_2); - - mask1 = hdmi_read(hdmi, HDMI_INTERRUPT_MASK_1); - mask2 = hdmi_read(hdmi, HDMI_INTERRUPT_MASK_2); - - /* Correct would be to ack only set bits, but the datasheet requires 0xff */ - hdmi_write(hdmi, 0xFF, HDMI_INTERRUPT_STATUS_1); - hdmi_write(hdmi, 0xFF, HDMI_INTERRUPT_STATUS_2); - - if (printk_ratelimit()) - dev_dbg(hdmi->dev, "IRQ #%d: Status #1: 0x%x & 0x%x, #2: 0x%x & 0x%x\n", - irq, status1, mask1, status2, mask2); - - if (!((status1 & mask1) | (status2 & mask2))) { - return IRQ_NONE; - } else if (status1 & 0xc0) { - u8 msens; - - /* Datasheet specifies 10ms... */ - udelay(500); - - msens = hdmi_read(hdmi, HDMI_HOT_PLUG_MSENS_STATUS); - dev_dbg(hdmi->dev, "MSENS 0x%x\n", msens); - /* Check, if hot plug & MSENS pin status are both high */ - if ((msens & 0xC0) == 0xC0) { - /* Display plug in */ - hdmi->edid_segment_nr = 0; - hdmi->edid_block_addr = 0; - hdmi->edid_blocks = 0; - hdmi->hp_state = HDMI_HOTPLUG_CONNECTED; - - /* Set EDID word address */ - hdmi_write(hdmi, 0x00, HDMI_EDID_WORD_ADDRESS); - /* Enable EDID interrupt */ - hdmi_write(hdmi, 0xC6, HDMI_INTERRUPT_MASK_1); - /* Set EDID segment pointer - starts reading EDID */ - hdmi_write(hdmi, 0x00, HDMI_EDID_SEGMENT_POINTER); - } else if (!(status1 & 0x80)) { - /* Display unplug, beware multiple interrupts */ - if (hdmi->hp_state != HDMI_HOTPLUG_DISCONNECTED) { - hdmi->hp_state = HDMI_HOTPLUG_DISCONNECTED; - schedule_delayed_work(&hdmi->edid_work, 0); - } - /* display_off will switch back to mode_a */ - } - } else if (status1 & 2) { - /* EDID error interrupt: retry */ - /* Set EDID word address */ - hdmi_write(hdmi, hdmi->edid_block_addr, HDMI_EDID_WORD_ADDRESS); - /* Set EDID segment pointer */ - hdmi_write(hdmi, hdmi->edid_segment_nr, HDMI_EDID_SEGMENT_POINTER); - } else if (status1 & 4) { - /* Disable EDID interrupt */ - hdmi_write(hdmi, 0xC0, HDMI_INTERRUPT_MASK_1); - schedule_delayed_work(&hdmi->edid_work, msecs_to_jiffies(10)); - } - - return IRQ_HANDLED; -} - -static int sh_hdmi_display_on(struct sh_mobile_lcdc_entity *entity) -{ - struct sh_hdmi *hdmi = entity_to_sh_hdmi(entity); - - dev_dbg(hdmi->dev, "%s(%p): state %x\n", __func__, hdmi, - hdmi->hp_state); - - /* - * hp_state can be set to - * HDMI_HOTPLUG_DISCONNECTED: on monitor unplug - * HDMI_HOTPLUG_CONNECTED: on monitor plug-in - * HDMI_HOTPLUG_EDID_DONE: on EDID read completion - */ - if (hdmi->hp_state == HDMI_HOTPLUG_EDID_DONE) { - /* PS mode d->e. All functions are active */ - hdmi_bit_set(hdmi, 0xFC, 0x80, HDMI_SYSTEM_CTRL); - dev_dbg(hdmi->dev, "HDMI running\n"); - } - - return hdmi->hp_state == HDMI_HOTPLUG_DISCONNECTED - ? SH_MOBILE_LCDC_DISPLAY_DISCONNECTED - : SH_MOBILE_LCDC_DISPLAY_CONNECTED; -} - -static void sh_hdmi_display_off(struct sh_mobile_lcdc_entity *entity) -{ - struct sh_hdmi *hdmi = entity_to_sh_hdmi(entity); - - dev_dbg(hdmi->dev, "%s(%p)\n", __func__, hdmi); - /* PS mode e->a */ - hdmi_bit_set(hdmi, 0xFC, 0x10, HDMI_SYSTEM_CTRL); -} - -static const struct sh_mobile_lcdc_entity_ops sh_hdmi_ops = { - .display_on = sh_hdmi_display_on, - .display_off = sh_hdmi_display_off, -}; - -/** - * sh_hdmi_clk_configure() - set HDMI clock frequency and enable the clock - * @hdmi: driver context - * @hdmi_rate: HDMI clock frequency in Hz - * @parent_rate: if != 0 - set parent clock rate for optimal precision - * return: configured positive rate if successful - * 0 if couldn't set the rate, but managed to enable the - * clock, negative error, if couldn't enable the clock - */ -static long sh_hdmi_clk_configure(struct sh_hdmi *hdmi, unsigned long hdmi_rate, - unsigned long parent_rate) -{ - int ret; - - if (parent_rate && clk_get_parent(hdmi->hdmi_clk)) { - ret = clk_set_rate(clk_get_parent(hdmi->hdmi_clk), parent_rate); - if (ret < 0) { - dev_warn(hdmi->dev, "Cannot set parent rate %ld: %d\n", parent_rate, ret); - hdmi_rate = clk_round_rate(hdmi->hdmi_clk, hdmi_rate); - } else { - dev_dbg(hdmi->dev, "HDMI set parent frequency %lu\n", parent_rate); - } - } - - ret = clk_set_rate(hdmi->hdmi_clk, hdmi_rate); - if (ret < 0) { - dev_warn(hdmi->dev, "Cannot set rate %ld: %d\n", hdmi_rate, ret); - hdmi_rate = 0; - } else { - dev_dbg(hdmi->dev, "HDMI set frequency %lu\n", hdmi_rate); - } - - return hdmi_rate; -} - -/* Hotplug interrupt occurred, read EDID */ -static void sh_hdmi_edid_work_fn(struct work_struct *work) -{ - struct sh_hdmi *hdmi = container_of(work, struct sh_hdmi, edid_work.work); - struct sh_mobile_lcdc_chan *ch = hdmi->entity.lcdc; - int ret; - - dev_dbg(hdmi->dev, "%s(%p): begin, hotplug status %d\n", __func__, hdmi, - hdmi->hp_state); - - if (hdmi->hp_state == HDMI_HOTPLUG_CONNECTED) { - unsigned long parent_rate = 0, hdmi_rate; - - ret = sh_hdmi_read_edid(hdmi, &hdmi_rate, &parent_rate); - if (ret < 0) - goto out; - - hdmi->hp_state = HDMI_HOTPLUG_EDID_DONE; - - /* Reconfigure the clock */ - ret = sh_hdmi_clk_configure(hdmi, hdmi_rate, parent_rate); - if (ret < 0) - goto out; - - msleep(10); - sh_hdmi_configure(hdmi); - /* Switched to another (d) power-save mode */ - msleep(10); - - if (ch && ch->notify) - ch->notify(ch, SH_MOBILE_LCDC_EVENT_DISPLAY_CONNECT, - &hdmi->mode, &hdmi->monspec); - } else { - hdmi->monspec.modedb_len = 0; - fb_destroy_modedb(hdmi->monspec.modedb); - hdmi->monspec.modedb = NULL; - - if (ch && ch->notify) - ch->notify(ch, SH_MOBILE_LCDC_EVENT_DISPLAY_DISCONNECT, - NULL, NULL); - - ret = 0; - } - -out: - if (ret < 0 && ret != -EAGAIN) - hdmi->hp_state = HDMI_HOTPLUG_DISCONNECTED; - - dev_dbg(hdmi->dev, "%s(%p): end\n", __func__, hdmi); -} - -static void sh_hdmi_htop1_init(struct sh_hdmi *hdmi) -{ - hdmi_htop1_write(hdmi, 0x00000000, HDMI_HTOP1_HTOP_DCL_MODE); - hdmi_htop1_write(hdmi, 0x0000000b, 0x0010); - hdmi_htop1_write(hdmi, 0x00006710, HDMI_HTOP1_HTOP_DCL_FRC_MODE); - hdmi_htop1_write(hdmi, 0x01020406, HDMI_HTOP1_HTOP_DCL_FIL_PARA_Y1_1); - hdmi_htop1_write(hdmi, 0x07080806, HDMI_HTOP1_HTOP_DCL_FIL_PARA_Y1_2); - hdmi_htop1_write(hdmi, 0x01020406, HDMI_HTOP1_HTOP_DCL_FIL_PARA_CB1_1); - hdmi_htop1_write(hdmi, 0x07080806, HDMI_HTOP1_HTOP_DCL_FIL_PARA_CB1_2); - hdmi_htop1_write(hdmi, 0x01020406, HDMI_HTOP1_HTOP_DCL_FIL_PARA_CR1_1); - hdmi_htop1_write(hdmi, 0x07080806, HDMI_HTOP1_HTOP_DCL_FIL_PARA_CR1_2); - hdmi_htop1_write(hdmi, 0x01020406, HDMI_HTOP1_HTOP_DCL_FIL_PARA_Y2_1); - hdmi_htop1_write(hdmi, 0x07080806, HDMI_HTOP1_HTOP_DCL_FIL_PARA_Y2_2); - hdmi_htop1_write(hdmi, 0x01020406, HDMI_HTOP1_HTOP_DCL_FIL_PARA_CB2_1); - hdmi_htop1_write(hdmi, 0x07080806, HDMI_HTOP1_HTOP_DCL_FIL_PARA_CB2_2); - hdmi_htop1_write(hdmi, 0x01020406, HDMI_HTOP1_HTOP_DCL_FIL_PARA_CR2_1); - hdmi_htop1_write(hdmi, 0x07080806, HDMI_HTOP1_HTOP_DCL_FIL_PARA_CR2_2); - hdmi_htop1_write(hdmi, 0x00000000, HDMI_HTOP1_HTOP_DCL_COR_PARA_Y1); - hdmi_htop1_write(hdmi, 0x00000000, HDMI_HTOP1_HTOP_DCL_COR_PARA_CB1); - hdmi_htop1_write(hdmi, 0x00000000, HDMI_HTOP1_HTOP_DCL_COR_PARA_CR1); - hdmi_htop1_write(hdmi, 0x00000000, HDMI_HTOP1_HTOP_DCL_COR_PARA_Y2); - hdmi_htop1_write(hdmi, 0x00000000, HDMI_HTOP1_HTOP_DCL_COR_PARA_CB2); - hdmi_htop1_write(hdmi, 0x00000000, HDMI_HTOP1_HTOP_DCL_COR_PARA_CR2); - hdmi_htop1_write(hdmi, 0x00000008, HDMI_HTOP1_CURRENT); - hdmi_htop1_write(hdmi, 0x00000000, HDMI_HTOP1_TISEMP0_1); - hdmi_htop1_write(hdmi, 0x00000000, HDMI_HTOP1_TISEMP2_C); - hdmi_htop1_write(hdmi, 0x00000000, HDMI_HTOP1_PHY_TEST_MODE); - hdmi_htop1_write(hdmi, 0x00000081, HDMI_HTOP1_TISIDRV); - hdmi_htop1_write(hdmi, 0x00000000, HDMI_HTOP1_PLLBW); - hdmi_htop1_write(hdmi, 0x0000000f, HDMI_HTOP1_TISEN); - hdmi_htop1_write(hdmi, 0x0000000f, HDMI_HTOP1_TISDREN); - hdmi_htop1_write(hdmi, 0x00000003, HDMI_HTOP1_ENABLE_SELECTOR); - hdmi_htop1_write(hdmi, 0x00000001, HDMI_HTOP1_MACRO_RESET); - hdmi_htop1_write(hdmi, 0x00000016, HDMI_HTOP1_CISRANGE); - msleep(100); - hdmi_htop1_write(hdmi, 0x00000001, HDMI_HTOP1_ENABLE_SELECTOR); - msleep(100); - hdmi_htop1_write(hdmi, 0x00000003, HDMI_HTOP1_ENABLE_SELECTOR); - hdmi_htop1_write(hdmi, 0x00000001, HDMI_HTOP1_MACRO_RESET); - hdmi_htop1_write(hdmi, 0x0000000f, HDMI_HTOP1_TISEN); - hdmi_htop1_write(hdmi, 0x0000000f, HDMI_HTOP1_TISDREN); - hdmi_htop1_write(hdmi, 0x00000000, HDMI_HTOP1_VIDEO_INPUT); - hdmi_htop1_write(hdmi, 0x00000000, HDMI_HTOP1_CLK_TO_PHY); - hdmi_htop1_write(hdmi, 0x00000000, HDMI_HTOP1_VIDEO_INPUT2); - hdmi_htop1_write(hdmi, 0x0000000a, HDMI_HTOP1_CLK_SET); -} - -static int __init sh_hdmi_probe(struct platform_device *pdev) -{ - struct sh_mobile_hdmi_info *pdata = dev_get_platdata(&pdev->dev); - struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - struct resource *htop1_res; - int irq = platform_get_irq(pdev, 0), ret; - struct sh_hdmi *hdmi; - long rate; - - if (!res || !pdata || irq < 0) - return -ENODEV; - - htop1_res = NULL; - if (pdata->flags & HDMI_HAS_HTOP1) { - htop1_res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (!htop1_res) { - dev_err(&pdev->dev, "htop1 needs register base\n"); - return -EINVAL; - } - } - - hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL); - if (!hdmi) { - dev_err(&pdev->dev, "Cannot allocate device data\n"); - return -ENOMEM; - } - - hdmi->dev = &pdev->dev; - hdmi->entity.owner = THIS_MODULE; - hdmi->entity.ops = &sh_hdmi_ops; - hdmi->irq = irq; - - hdmi->hdmi_clk = clk_get(&pdev->dev, "ick"); - if (IS_ERR(hdmi->hdmi_clk)) { - ret = PTR_ERR(hdmi->hdmi_clk); - dev_err(&pdev->dev, "Unable to get clock: %d\n", ret); - return ret; - } - - /* select register access functions */ - if (pdata->flags & HDMI_32BIT_REG) { - hdmi->write = __hdmi_write32; - hdmi->read = __hdmi_read32; - } else { - hdmi->write = __hdmi_write8; - hdmi->read = __hdmi_read8; - } - - /* An arbitrary relaxed pixclock just to get things started: from standard 480p */ - rate = clk_round_rate(hdmi->hdmi_clk, PICOS2KHZ(37037)); - if (rate > 0) - rate = sh_hdmi_clk_configure(hdmi, rate, 0); - - if (rate < 0) { - ret = rate; - goto erate; - } - - ret = clk_prepare_enable(hdmi->hdmi_clk); - if (ret < 0) { - dev_err(hdmi->dev, "Cannot enable clock: %d\n", ret); - goto erate; - } - - dev_dbg(&pdev->dev, "Enabled HDMI clock at %luHz\n", rate); - - if (!request_mem_region(res->start, resource_size(res), dev_name(&pdev->dev))) { - dev_err(&pdev->dev, "HDMI register region already claimed\n"); - ret = -EBUSY; - goto ereqreg; - } - - hdmi->base = ioremap(res->start, resource_size(res)); - if (!hdmi->base) { - dev_err(&pdev->dev, "HDMI register region already claimed\n"); - ret = -ENOMEM; - goto emap; - } - - platform_set_drvdata(pdev, &hdmi->entity); - - INIT_DELAYED_WORK(&hdmi->edid_work, sh_hdmi_edid_work_fn); - - pm_runtime_enable(&pdev->dev); - pm_runtime_get_sync(&pdev->dev); - - /* init interrupt polarity */ - if (pdata->flags & HDMI_OUTPUT_PUSH_PULL) - hdmi_bit_set(hdmi, 0x02, 0x02, HDMI_SYSTEM_CTRL); - - if (pdata->flags & HDMI_OUTPUT_POLARITY_HI) - hdmi_bit_set(hdmi, 0x01, 0x01, HDMI_SYSTEM_CTRL); - - /* enable htop1 register if needed */ - if (htop1_res) { - hdmi->htop1 = ioremap(htop1_res->start, resource_size(htop1_res)); - if (!hdmi->htop1) { - dev_err(&pdev->dev, "control register region already claimed\n"); - ret = -ENOMEM; - goto emap_htop1; - } - sh_hdmi_htop1_init(hdmi); - } - - /* Product and revision IDs are 0 in sh-mobile version */ - dev_info(&pdev->dev, "Detected HDMI controller 0x%x:0x%x\n", - hdmi_read(hdmi, HDMI_PRODUCT_ID), hdmi_read(hdmi, HDMI_REVISION_ID)); - - ret = request_irq(irq, sh_hdmi_hotplug, 0, - dev_name(&pdev->dev), hdmi); - if (ret < 0) { - dev_err(&pdev->dev, "Unable to request irq: %d\n", ret); - goto ereqirq; - } - - ret = snd_soc_register_codec(&pdev->dev, - &soc_codec_dev_sh_hdmi, &sh_hdmi_dai, 1); - if (ret < 0) { - dev_err(&pdev->dev, "codec registration failed\n"); - goto ecodec; - } - - return 0; - -ecodec: - free_irq(irq, hdmi); -ereqirq: - if (hdmi->htop1) - iounmap(hdmi->htop1); -emap_htop1: - pm_runtime_put(&pdev->dev); - pm_runtime_disable(&pdev->dev); - iounmap(hdmi->base); -emap: - release_mem_region(res->start, resource_size(res)); -ereqreg: - clk_disable_unprepare(hdmi->hdmi_clk); -erate: - clk_put(hdmi->hdmi_clk); - - return ret; -} - -static int __exit sh_hdmi_remove(struct platform_device *pdev) -{ - struct sh_hdmi *hdmi = entity_to_sh_hdmi(platform_get_drvdata(pdev)); - struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - - snd_soc_unregister_codec(&pdev->dev); - - /* No new work will be scheduled, wait for running ISR */ - free_irq(hdmi->irq, hdmi); - /* Wait for already scheduled work */ - cancel_delayed_work_sync(&hdmi->edid_work); - pm_runtime_put(&pdev->dev); - pm_runtime_disable(&pdev->dev); - clk_disable_unprepare(hdmi->hdmi_clk); - clk_put(hdmi->hdmi_clk); - if (hdmi->htop1) - iounmap(hdmi->htop1); - iounmap(hdmi->base); - release_mem_region(res->start, resource_size(res)); - - return 0; -} - -static int sh_hdmi_suspend(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - struct sh_hdmi *hdmi = entity_to_sh_hdmi(platform_get_drvdata(pdev)); - - disable_irq(hdmi->irq); - /* Wait for already scheduled work */ - cancel_delayed_work_sync(&hdmi->edid_work); - return 0; -} - -static int sh_hdmi_resume(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - struct sh_mobile_hdmi_info *pdata = dev_get_platdata(dev); - struct sh_hdmi *hdmi = entity_to_sh_hdmi(platform_get_drvdata(pdev)); - - /* Re-init interrupt polarity */ - if (pdata->flags & HDMI_OUTPUT_PUSH_PULL) - hdmi_bit_set(hdmi, 0x02, 0x02, HDMI_SYSTEM_CTRL); - - if (pdata->flags & HDMI_OUTPUT_POLARITY_HI) - hdmi_bit_set(hdmi, 0x01, 0x01, HDMI_SYSTEM_CTRL); - - /* Re-init htop1 */ - if (hdmi->htop1) - sh_hdmi_htop1_init(hdmi); - - /* Now it's safe to enable interrupts again */ - enable_irq(hdmi->irq); - return 0; -} - -static const struct dev_pm_ops sh_hdmi_pm_ops = { - .suspend = sh_hdmi_suspend, - .resume = sh_hdmi_resume, -}; - -static struct platform_driver sh_hdmi_driver = { - .remove = __exit_p(sh_hdmi_remove), - .driver = { - .name = "sh-mobile-hdmi", - .pm = &sh_hdmi_pm_ops, - }, -}; - -module_platform_driver_probe(sh_hdmi_driver, sh_hdmi_probe); - -MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>"); -MODULE_DESCRIPTION("SuperH / ARM-shmobile HDMI driver"); -MODULE_LICENSE("GPL v2"); |
