1
0
Files
Greg Kroah-Hartman f3e305f585 Merge 4.9.201 into android-4.9-q
Changes in 4.9.201
	CDC-NCM: handle incomplete transfer of MTU
	ipv4: Fix table id reference in fib_sync_down_addr
	net: fix data-race in neigh_event_send()
	net: usb: qmi_wwan: add support for DW5821e with eSIM support
	NFC: fdp: fix incorrect free object
	nfc: netlink: fix double device reference drop
	NFC: st21nfca: fix double free
	qede: fix NULL pointer deref in __qede_remove()
	ALSA: timer: Fix incorrectly assigned timer instance
	ALSA: bebob: fix to detect configured source of sampling clock for Focusrite Saffire Pro i/o series
	ALSA: hda/ca0132 - Fix possible workqueue stall
	mm: thp: handle page cache THP correctly in PageTransCompoundMap
	mm, vmstat: hide /proc/pagetypeinfo from normal users
	dump_stack: avoid the livelock of the dump_lock
	perf tools: Fix time sorting
	drm/radeon: fix si_enable_smc_cac() failed issue
	ceph: fix use-after-free in __ceph_remove_cap()
	iio: imu: adis16480: make sure provided frequency is positive
	netfilter: nf_tables: Align nft_expr private data to 64-bit
	netfilter: ipset: Fix an error code in ip_set_sockfn_get()
	can: usb_8dev: fix use-after-free on disconnect
	can: c_can: c_can_poll(): only read status register after status IRQ
	can: peak_usb: fix a potential out-of-sync while decoding packets
	can: gs_usb: gs_can_open(): prevent memory leak
	can: peak_usb: fix slab info leak
	configfs: Fix bool initialization/comparison
	configfs: stash the data we need into configfs_buffer at open time
	configfs_register_group() shouldn't be (and isn't) called in rmdirable parts
	configfs: new object reprsenting tree fragments
	configfs: provide exclusion between IO and removals
	configfs: fix a deadlock in configfs_symlink()
	usbip: stub_rx: fix static checker warning on unnecessary checks
	usbip: Fix vhci_urb_enqueue() URB null transfer buffer error path
	usbip: fix possibility of dereference by NULLL pointer in vhci_hcd.c
	drivers: usb: usbip: Add missing break statement to switch
	PCI: tegra: Enable Relaxed Ordering only for Tegra20 & Tegra30
	dmaengine: xilinx_dma: Fix control reg update in vdma_channel_set_config
	HID: intel-ish-hid: fix wrong error handling in ishtp_cl_alloc_tx_ring()
	scsi: qla2xxx: fixup incorrect usage of host_byte
	scsi: lpfc: Honor module parameter lpfc_use_adisc
	ipvs: move old_secure_tcp into struct netns_ipvs
	bonding: fix unexpected IFF_BONDING bit unset
	usb: fsl: Check memory resource before releasing it
	usb: gadget: udc: atmel: Fix interrupt storm in FIFO mode.
	usb: gadget: composite: Fix possible double free memory bug
	usb: gadget: configfs: fix concurrent issue between composite APIs
	usb: dwc3: remove the call trace of USBx_GFLADJ
	perf/x86/amd/ibs: Fix reading of the IBS OpData register and thus precise RIP validity
	perf/x86/amd/ibs: Handle erratum #420 only on the affected CPU family (10h)
	USB: Skip endpoints with 0 maxpacket length
	RDMA/iw_cxgb4: Avoid freeing skb twice in arp failure case
	scsi: qla2xxx: stop timer in shutdown path
	fjes: Handle workqueue allocation failure
	net: hisilicon: Fix "Trying to free already-free IRQ"
	NFSv4: Don't allow a cached open with a revoked delegation
	net: ethernet: arc: add the missed clk_disable_unprepare
	igb: Fix constant media auto sense switching when no cable is connected
	e1000: fix memory leaks
	x86/apic: Move pending interrupt check code into it's own function
	x86/apic: Drop logical_smp_processor_id() inline
	x86/apic/32: Avoid bogus LDR warnings
	can: flexcan: disable completely the ECC mechanism
	mm/filemap.c: don't initiate writeback if mapping has no dirty pages
	cgroup,writeback: don't switch wbs immediately on dead wbs if the memcg is dead
	net: prevent load/store tearing on sk->sk_stamp
	drm/i915: kick out cmd_parser specific structs from i915_drv.h
	drm/i915: cleanup use of INSTR_CLIENT_MASK
	drm/i915: return EACCES for check_cmd() failures
	drm/i915: don't whitelist oacontrol in cmd parser
	drm/i915: Use the precomputed value for whether to enable command parsing
	drm/i915/cmdparser: Limit clflush to active cachelines
	drm/i915/gtt: Add read only pages to gen8_pte_encode
	drm/i915/gtt: Read-only pages for insert_entries on bdw+
	drm/i915/gtt: Disable read-only support under GVT
	drm/i915: Prevent writing into a read-only object via a GGTT mmap
	drm/i915/cmdparser: Check reg_table_count before derefencing.
	drm/i915/cmdparser: Do not check past the cmd length.
	drm/i915: Silence smatch for cmdparser
	drm/i915: Move engine->needs_cmd_parser to engine->flags
	drm/i915: Rename gen7 cmdparser tables
	drm/i915: Disable Secure Batches for gen6+
	drm/i915: Remove Master tables from cmdparser
	drm/i915: Add support for mandatory cmdparsing
	drm/i915: Support ro ppgtt mapped cmdparser shadow buffers
	drm/i915: Allow parsing of unsized batches
	drm/i915: Add gen9 BCS cmdparsing
	drm/i915/cmdparser: Use explicit goto for error paths
	drm/i915/cmdparser: Add support for backward jumps
	drm/i915/cmdparser: Ignore Length operands during command matching
	drm/i915: Lower RM timeout to avoid DSI hard hangs
	drm/i915/gen8+: Add RC6 CTX corruption WA
	drm/i915/cmdparser: Fix jump whitelist clearing
	Linux 4.9.201

Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
2019-11-15 20:55:25 +03:00

258 lines
6.0 KiB
C

/*
* ISHTP Ring Buffers
*
* Copyright (c) 2003-2016, Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
#include <linux/slab.h>
#include "client.h"
/**
* ishtp_cl_alloc_rx_ring() - Allocate RX ring buffers
* @cl: client device instance
*
* Allocate and initialize RX ring buffers
*
* Return: 0 on success else -ENOMEM
*/
int ishtp_cl_alloc_rx_ring(struct ishtp_cl *cl)
{
size_t len = cl->device->fw_client->props.max_msg_length;
int j;
struct ishtp_cl_rb *rb;
int ret = 0;
unsigned long flags;
for (j = 0; j < cl->rx_ring_size; ++j) {
rb = ishtp_io_rb_init(cl);
if (!rb) {
ret = -ENOMEM;
goto out;
}
ret = ishtp_io_rb_alloc_buf(rb, len);
if (ret)
goto out;
spin_lock_irqsave(&cl->free_list_spinlock, flags);
list_add_tail(&rb->list, &cl->free_rb_list.list);
spin_unlock_irqrestore(&cl->free_list_spinlock, flags);
}
return 0;
out:
dev_err(&cl->device->dev, "error in allocating Rx buffers\n");
ishtp_cl_free_rx_ring(cl);
return ret;
}
/**
* ishtp_cl_alloc_tx_ring() - Allocate TX ring buffers
* @cl: client device instance
*
* Allocate and initialize TX ring buffers
*
* Return: 0 on success else -ENOMEM
*/
int ishtp_cl_alloc_tx_ring(struct ishtp_cl *cl)
{
size_t len = cl->device->fw_client->props.max_msg_length;
int j;
unsigned long flags;
/* Allocate pool to free Tx bufs */
for (j = 0; j < cl->tx_ring_size; ++j) {
struct ishtp_cl_tx_ring *tx_buf;
tx_buf = kzalloc(sizeof(struct ishtp_cl_tx_ring), GFP_KERNEL);
if (!tx_buf)
goto out;
tx_buf->send_buf.data = kmalloc(len, GFP_KERNEL);
if (!tx_buf->send_buf.data) {
kfree(tx_buf);
goto out;
}
spin_lock_irqsave(&cl->tx_free_list_spinlock, flags);
list_add_tail(&tx_buf->list, &cl->tx_free_list.list);
spin_unlock_irqrestore(&cl->tx_free_list_spinlock, flags);
}
return 0;
out:
dev_err(&cl->device->dev, "error in allocating Tx pool\n");
ishtp_cl_free_tx_ring(cl);
return -ENOMEM;
}
/**
* ishtp_cl_free_rx_ring() - Free RX ring buffers
* @cl: client device instance
*
* Free RX ring buffers
*/
void ishtp_cl_free_rx_ring(struct ishtp_cl *cl)
{
struct ishtp_cl_rb *rb;
unsigned long flags;
/* release allocated memory - pass over free_rb_list */
spin_lock_irqsave(&cl->free_list_spinlock, flags);
while (!list_empty(&cl->free_rb_list.list)) {
rb = list_entry(cl->free_rb_list.list.next, struct ishtp_cl_rb,
list);
list_del(&rb->list);
kfree(rb->buffer.data);
kfree(rb);
}
spin_unlock_irqrestore(&cl->free_list_spinlock, flags);
/* release allocated memory - pass over in_process_list */
spin_lock_irqsave(&cl->in_process_spinlock, flags);
while (!list_empty(&cl->in_process_list.list)) {
rb = list_entry(cl->in_process_list.list.next,
struct ishtp_cl_rb, list);
list_del(&rb->list);
kfree(rb->buffer.data);
kfree(rb);
}
spin_unlock_irqrestore(&cl->in_process_spinlock, flags);
}
/**
* ishtp_cl_free_tx_ring() - Free TX ring buffers
* @cl: client device instance
*
* Free TX ring buffers
*/
void ishtp_cl_free_tx_ring(struct ishtp_cl *cl)
{
struct ishtp_cl_tx_ring *tx_buf;
unsigned long flags;
spin_lock_irqsave(&cl->tx_free_list_spinlock, flags);
/* release allocated memory - pass over tx_free_list */
while (!list_empty(&cl->tx_free_list.list)) {
tx_buf = list_entry(cl->tx_free_list.list.next,
struct ishtp_cl_tx_ring, list);
list_del(&tx_buf->list);
kfree(tx_buf->send_buf.data);
kfree(tx_buf);
}
spin_unlock_irqrestore(&cl->tx_free_list_spinlock, flags);
spin_lock_irqsave(&cl->tx_list_spinlock, flags);
/* release allocated memory - pass over tx_list */
while (!list_empty(&cl->tx_list.list)) {
tx_buf = list_entry(cl->tx_list.list.next,
struct ishtp_cl_tx_ring, list);
list_del(&tx_buf->list);
kfree(tx_buf->send_buf.data);
kfree(tx_buf);
}
spin_unlock_irqrestore(&cl->tx_list_spinlock, flags);
}
/**
* ishtp_io_rb_free() - Free IO request block
* @rb: IO request block
*
* Free io request block memory
*/
void ishtp_io_rb_free(struct ishtp_cl_rb *rb)
{
if (rb == NULL)
return;
kfree(rb->buffer.data);
kfree(rb);
}
/**
* ishtp_io_rb_init() - Allocate and init IO request block
* @cl: client device instance
*
* Allocate and initialize request block
*
* Return: Allocted IO request block pointer
*/
struct ishtp_cl_rb *ishtp_io_rb_init(struct ishtp_cl *cl)
{
struct ishtp_cl_rb *rb;
rb = kzalloc(sizeof(struct ishtp_cl_rb), GFP_KERNEL);
if (!rb)
return NULL;
INIT_LIST_HEAD(&rb->list);
rb->cl = cl;
rb->buf_idx = 0;
return rb;
}
/**
* ishtp_io_rb_alloc_buf() - Allocate and init response buffer
* @rb: IO request block
* @length: length of response buffer
*
* Allocate respose buffer
*
* Return: 0 on success else -ENOMEM
*/
int ishtp_io_rb_alloc_buf(struct ishtp_cl_rb *rb, size_t length)
{
if (!rb)
return -EINVAL;
if (length == 0)
return 0;
rb->buffer.data = kmalloc(length, GFP_KERNEL);
if (!rb->buffer.data)
return -ENOMEM;
rb->buffer.size = length;
return 0;
}
/**
* ishtp_cl_io_rb_recycle() - Recycle IO request blocks
* @rb: IO request block
*
* Re-append rb to its client's free list and send flow control if needed
*
* Return: 0 on success else -EFAULT
*/
int ishtp_cl_io_rb_recycle(struct ishtp_cl_rb *rb)
{
struct ishtp_cl *cl;
int rets = 0;
unsigned long flags;
if (!rb || !rb->cl)
return -EFAULT;
cl = rb->cl;
spin_lock_irqsave(&cl->free_list_spinlock, flags);
list_add_tail(&rb->list, &cl->free_rb_list.list);
spin_unlock_irqrestore(&cl->free_list_spinlock, flags);
/*
* If we returned the first buffer to empty 'free' list,
* send flow control
*/
if (!cl->out_flow_ctrl_creds)
rets = ishtp_cl_read_start(cl);
return rets;
}
EXPORT_SYMBOL(ishtp_cl_io_rb_recycle);