Merge tag 'char-misc-4.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc

Pull char/misc driver updates from Greg KH:
 "Here's the "big" char and misc driver update for 4.9-rc1.

  Lots of little things here, all over the driver tree for subsystems
  that flow through me. Nothing major that I can discern, full details
  are in the shortlog.

  All have been in the linux-next tree with no reported issues"

* tag 'char-misc-4.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (144 commits)
  drivers/misc/hpilo: Changes to support new security states in iLO5 FW
  at25: fix debug and error messaging
  misc/genwqe: ensure zero initialization
  vme: fake: remove unexpected unlock in fake_master_set()
  vme: fake: mark symbols static where possible
  spmi: pmic-arb: Return an error code if sanity check fails
  Drivers: hv: get rid of id in struct vmbus_channel
  Drivers: hv: make VMBus bus ids persistent
  mcb: Add a dma_device to mcb_device
  mcb: Enable PCI bus mastering by default
  mei: stop the stall timer worker if not needed
  clk: probe common clock drivers earlier
  vme: fake: fix build for 64-bit dma_addr_t
  ttyprintk: Neaten and simplify printing
  mei: me: add kaby point device ids
  coresight: tmc: mark symbols static where possible
  coresight: perf: deal with error condition properly
  Drivers: hv: hv_util: Avoid dynamic allocation in time synch
  fpga manager: Add hardware dependency to Zynq driver
  Drivers: hv: utils: Support TimeSync version 4.0 protocol samples.
  ...
This commit is contained in:
Linus Torvalds
2016-10-03 19:57:49 -07:00
129 changed files with 4037 additions and 2802 deletions
-28
View File
@@ -429,34 +429,6 @@ config ARM_CHARLCD
line and the Linux version on the second line, but that's
still useful.
config BMP085
tristate
depends on SYSFS
config BMP085_I2C
tristate "BMP085 digital pressure sensor on I2C"
select BMP085
select REGMAP_I2C
depends on I2C && SYSFS
help
Say Y here if you want to support Bosch Sensortec's digital pressure
sensor hooked to an I2C bus.
To compile this driver as a module, choose M here: the
module will be called bmp085-i2c.
config BMP085_SPI
tristate "BMP085 digital pressure sensor on SPI"
select BMP085
select REGMAP_SPI
depends on SPI_MASTER && SYSFS
help
Say Y here if you want to support Bosch Sensortec's digital pressure
sensor hooked to an SPI bus.
To compile this driver as a module, choose M here: the
module will be called bmp085-spi.
config PCH_PHUB
tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) PHUB"
select GENERIC_NET_UTILS
-3
View File
@@ -9,9 +9,6 @@ obj-$(CONFIG_AD525X_DPOT_SPI) += ad525x_dpot-spi.o
obj-$(CONFIG_INTEL_MID_PTI) += pti.o
obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o
obj-$(CONFIG_ATMEL_TCLIB) += atmel_tclib.o
obj-$(CONFIG_BMP085) += bmp085.o
obj-$(CONFIG_BMP085_I2C) += bmp085-i2c.o
obj-$(CONFIG_BMP085_SPI) += bmp085-spi.o
obj-$(CONFIG_DUMMY_IRQ) += dummy-irq.o
obj-$(CONFIG_ICS932S401) += ics932s401.o
obj-$(CONFIG_LKDTM) += lkdtm.o
-83
View File
@@ -1,83 +0,0 @@
/*
* Copyright (c) 2012 Bosch Sensortec GmbH
* Copyright (c) 2012 Unixphere AB
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/err.h>
#include "bmp085.h"
#define BMP085_I2C_ADDRESS 0x77
static const unsigned short normal_i2c[] = { BMP085_I2C_ADDRESS,
I2C_CLIENT_END };
static int bmp085_i2c_detect(struct i2c_client *client,
struct i2c_board_info *info)
{
if (client->addr != BMP085_I2C_ADDRESS)
return -ENODEV;
return bmp085_detect(&client->dev);
}
static int bmp085_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int err;
struct regmap *regmap = devm_regmap_init_i2c(client,
&bmp085_regmap_config);
if (IS_ERR(regmap)) {
err = PTR_ERR(regmap);
dev_err(&client->dev, "Failed to init regmap: %d\n", err);
return err;
}
return bmp085_probe(&client->dev, regmap, client->irq);
}
static int bmp085_i2c_remove(struct i2c_client *client)
{
return bmp085_remove(&client->dev);
}
static const struct i2c_device_id bmp085_id[] = {
{ BMP085_NAME, 0 },
{ "bmp180", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, bmp085_id);
static struct i2c_driver bmp085_i2c_driver = {
.driver = {
.name = BMP085_NAME,
},
.id_table = bmp085_id,
.probe = bmp085_i2c_probe,
.remove = bmp085_i2c_remove,
.detect = bmp085_i2c_detect,
.address_list = normal_i2c
};
module_i2c_driver(bmp085_i2c_driver);
MODULE_AUTHOR("Eric Andersson <eric.andersson@unixphere.com>");
MODULE_DESCRIPTION("BMP085 I2C bus driver");
MODULE_LICENSE("GPL");
-79
View File
@@ -1,79 +0,0 @@
/*
* Copyright (c) 2012 Bosch Sensortec GmbH
* Copyright (c) 2012 Unixphere AB
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/module.h>
#include <linux/spi/spi.h>
#include <linux/err.h>
#include "bmp085.h"
static int bmp085_spi_probe(struct spi_device *client)
{
int err;
struct regmap *regmap;
client->bits_per_word = 8;
err = spi_setup(client);
if (err < 0) {
dev_err(&client->dev, "spi_setup failed!\n");
return err;
}
regmap = devm_regmap_init_spi(client, &bmp085_regmap_config);
if (IS_ERR(regmap)) {
err = PTR_ERR(regmap);
dev_err(&client->dev, "Failed to init regmap: %d\n", err);
return err;
}
return bmp085_probe(&client->dev, regmap, client->irq);
}
static int bmp085_spi_remove(struct spi_device *client)
{
return bmp085_remove(&client->dev);
}
static const struct of_device_id bmp085_of_match[] = {
{ .compatible = "bosch,bmp085", },
{ },
};
MODULE_DEVICE_TABLE(of, bmp085_of_match);
static const struct spi_device_id bmp085_id[] = {
{ "bmp180", 0 },
{ "bmp181", 0 },
{ }
};
MODULE_DEVICE_TABLE(spi, bmp085_id);
static struct spi_driver bmp085_spi_driver = {
.driver = {
.name = BMP085_NAME,
.of_match_table = bmp085_of_match
},
.id_table = bmp085_id,
.probe = bmp085_spi_probe,
.remove = bmp085_spi_remove
};
module_spi_driver(bmp085_spi_driver);
MODULE_AUTHOR("Eric Andersson <eric.andersson@unixphere.com>");
MODULE_DESCRIPTION("BMP085 SPI bus driver");
MODULE_LICENSE("GPL");
File diff suppressed because it is too large Load Diff
-33
View File
@@ -1,33 +0,0 @@
/*
* Copyright (c) 2012 Bosch Sensortec GmbH
* Copyright (c) 2012 Unixphere AB
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _BMP085_H
#define _BMP085_H
#include <linux/regmap.h>
#define BMP085_NAME "bmp085"
extern struct regmap_config bmp085_regmap_config;
int bmp085_probe(struct device *dev, struct regmap *regmap, int irq);
int bmp085_remove(struct device *dev);
int bmp085_detect(struct device *dev);
#endif
+7 -13
View File
@@ -121,9 +121,8 @@ static int at25_ee_read(void *priv, unsigned int offset,
* this chip is clocked very slowly
*/
status = spi_sync(at25->spi, &m);
dev_dbg(&at25->spi->dev,
"read %Zd bytes at %d --> %d\n",
count, offset, (int) status);
dev_dbg(&at25->spi->dev, "read %zu bytes at %d --> %zd\n",
count, offset, status);
mutex_unlock(&at25->lock);
return status;
@@ -167,8 +166,7 @@ static int at25_ee_write(void *priv, unsigned int off, void *val, size_t count)
*cp = AT25_WREN;
status = spi_write(at25->spi, cp, 1);
if (status < 0) {
dev_dbg(&at25->spi->dev, "WREN --> %d\n",
(int) status);
dev_dbg(&at25->spi->dev, "WREN --> %d\n", status);
break;
}
@@ -196,9 +194,8 @@ static int at25_ee_write(void *priv, unsigned int off, void *val, size_t count)
memcpy(cp, buf, segment);
status = spi_write(at25->spi, bounce,
segment + at25->addrlen + 1);
dev_dbg(&at25->spi->dev,
"write %u bytes at %u --> %d\n",
segment, offset, (int) status);
dev_dbg(&at25->spi->dev, "write %u bytes at %u --> %d\n",
segment, offset, status);
if (status < 0)
break;
@@ -225,8 +222,7 @@ static int at25_ee_write(void *priv, unsigned int off, void *val, size_t count)
if ((sr < 0) || (sr & AT25_SR_nRDY)) {
dev_err(&at25->spi->dev,
"write %d bytes offset %d, "
"timeout after %u msecs\n",
"write %u bytes offset %u, timeout after %u msecs\n",
segment, offset,
jiffies_to_msecs(jiffies -
(timeout - EE_TIMEOUT)));
@@ -368,9 +364,7 @@ static int at25_probe(struct spi_device *spi)
return PTR_ERR(at25->nvmem);
dev_info(&spi->dev, "%d %s %s eeprom%s, pagesize %u\n",
(chip.byte_len < 1024)
? chip.byte_len
: (chip.byte_len / 1024),
(chip.byte_len < 1024) ? chip.byte_len : (chip.byte_len / 1024),
(chip.byte_len < 1024) ? "Byte" : "KByte",
at25->chip.name,
(chip.flags & EE_READONLY) ? " (readonly)" : "",
+15
View File
@@ -1350,6 +1350,19 @@ static struct pci_driver genwqe_driver = {
.err_handler = &genwqe_err_handler,
};
/**
* genwqe_devnode() - Set default access mode for genwqe devices.
*
* Default mode should be rw for everybody. Do not change default
* device name.
*/
static char *genwqe_devnode(struct device *dev, umode_t *mode)
{
if (mode)
*mode = 0666;
return NULL;
}
/**
* genwqe_init_module() - Driver registration and initialization
*/
@@ -1363,6 +1376,8 @@ static int __init genwqe_init_module(void)
return -ENOMEM;
}
class_genwqe->devnode = genwqe_devnode;
debugfs_genwqe = debugfs_create_dir(GENWQE_DEVNAME, NULL);
if (!debugfs_genwqe) {
rc = -ENOMEM;
-2
View File
@@ -1048,8 +1048,6 @@ static int setup_ddcb_queue(struct genwqe_dev *cd, struct ddcb_queue *queue)
"[%s] **err: could not allocate DDCB **\n", __func__);
return -ENOMEM;
}
memset(queue->ddcb_vaddr, 0, queue_size);
queue->ddcb_req = kzalloc(sizeof(struct ddcb_requ *) *
queue->ddcb_max, GFP_KERNEL);
if (!queue->ddcb_req) {
+2 -2
View File
@@ -220,8 +220,8 @@ void *__genwqe_alloc_consistent(struct genwqe_dev *cd, size_t size,
if (get_order(size) > MAX_ORDER)
return NULL;
return dma_alloc_coherent(&cd->pci_dev->dev, size, dma_handle,
GFP_KERNEL);
return dma_zalloc_coherent(&cd->pci_dev->dev, size, dma_handle,
GFP_KERNEL);
}
void __genwqe_free_consistent(struct genwqe_dev *cd, size_t size,
+13 -4
View File
@@ -688,7 +688,8 @@ static void ilo_unmap_device(struct pci_dev *pdev, struct ilo_hwinfo *hw)
static int ilo_map_device(struct pci_dev *pdev, struct ilo_hwinfo *hw)
{
int error = -ENOMEM;
int bar;
unsigned long off;
/* map the memory mapped i/o registers */
hw->mmio_vaddr = pci_iomap(pdev, 1, 0);
@@ -698,7 +699,15 @@ static int ilo_map_device(struct pci_dev *pdev, struct ilo_hwinfo *hw)
}
/* map the adapter shared memory region */
hw->ram_vaddr = pci_iomap(pdev, 2, max_ccb * ILOHW_CCB_SZ);
if (pdev->subsystem_device == 0x00E4) {
bar = 5;
/* Last 8k is reserved for CCBs */
off = pci_resource_len(pdev, bar) - 0x2000;
} else {
bar = 2;
off = 0;
}
hw->ram_vaddr = pci_iomap_range(pdev, bar, off, max_ccb * ILOHW_CCB_SZ);
if (hw->ram_vaddr == NULL) {
dev_err(&pdev->dev, "Error mapping shared mem\n");
goto mmio_free;
@@ -717,7 +726,7 @@ ram_free:
mmio_free:
pci_iounmap(pdev, hw->mmio_vaddr);
out:
return error;
return -ENOMEM;
}
static void ilo_remove(struct pci_dev *pdev)
@@ -899,7 +908,7 @@ static void __exit ilo_exit(void)
class_destroy(ilo_class);
}
MODULE_VERSION("1.4.1");
MODULE_VERSION("1.5.0");
MODULE_ALIAS(ILO_NAME);
MODULE_DESCRIPTION(ILO_NAME);
MODULE_AUTHOR("David Altobelli <david.altobelli@hpe.com>");
+76 -267
View File
@@ -47,7 +47,6 @@ const uuid_le mei_amthif_guid = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d,
void mei_amthif_reset_params(struct mei_device *dev)
{
/* reset iamthif parameters. */
dev->iamthif_current_cb = NULL;
dev->iamthif_canceled = false;
dev->iamthif_state = MEI_IAMTHIF_IDLE;
dev->iamthif_stall_timer = 0;
@@ -67,8 +66,12 @@ int mei_amthif_host_init(struct mei_device *dev, struct mei_me_client *me_cl)
struct mei_cl *cl = &dev->iamthif_cl;
int ret;
if (mei_cl_is_connected(cl))
return 0;
mutex_lock(&dev->device_lock);
if (mei_cl_is_connected(cl)) {
ret = 0;
goto out;
}
dev->iamthif_state = MEI_IAMTHIF_IDLE;
@@ -77,179 +80,37 @@ int mei_amthif_host_init(struct mei_device *dev, struct mei_me_client *me_cl)
ret = mei_cl_link(cl);
if (ret < 0) {
dev_err(dev->dev, "amthif: failed cl_link %d\n", ret);
return ret;
goto out;
}
ret = mei_cl_connect(cl, me_cl, NULL);
return ret;
}
/**
* mei_amthif_read - read data from AMTHIF client
*
* @dev: the device structure
* @file: pointer to file object
* @ubuf: pointer to user data in user space
* @length: data length to read
* @offset: data read offset
*
* Locking: called under "dev->device_lock" lock
*
* Return:
* returned data length on success,
* zero if no data to read,
* negative on failure.
*/
int mei_amthif_read(struct mei_device *dev, struct file *file,
char __user *ubuf, size_t length, loff_t *offset)
{
struct mei_cl *cl = file->private_data;
struct mei_cl_cb *cb;
int rets;
int wait_ret;
dev_dbg(dev->dev, "checking amthif data\n");
cb = mei_cl_read_cb(cl, file);
/* Check for if we can block or not*/
if (cb == NULL && file->f_flags & O_NONBLOCK)
return -EAGAIN;
dev_dbg(dev->dev, "waiting for amthif data\n");
while (cb == NULL) {
/* unlock the Mutex */
mutex_unlock(&dev->device_lock);
wait_ret = wait_event_interruptible(cl->rx_wait,
!list_empty(&cl->rd_completed) ||
!mei_cl_is_connected(cl));
/* Locking again the Mutex */
mutex_lock(&dev->device_lock);
if (wait_ret)
return -ERESTARTSYS;
if (!mei_cl_is_connected(cl)) {
rets = -EBUSY;
goto out;
}
cb = mei_cl_read_cb(cl, file);
}
if (cb->status) {
rets = cb->status;
dev_dbg(dev->dev, "read operation failed %d\n", rets);
goto free;
}
dev_dbg(dev->dev, "Got amthif data\n");
/* if the whole message will fit remove it from the list */
if (cb->buf_idx >= *offset && length >= (cb->buf_idx - *offset))
list_del_init(&cb->list);
else if (cb->buf_idx <= *offset) {
/* end of the message has been reached */
list_del_init(&cb->list);
rets = 0;
goto free;
}
/* else means that not full buffer will be read and do not
* remove message from deletion list
*/
dev_dbg(dev->dev, "amthif cb->buf.size - %zu cb->buf_idx - %zu\n",
cb->buf.size, cb->buf_idx);
/* length is being truncated to PAGE_SIZE, however,
* the buf_idx may point beyond */
length = min_t(size_t, length, (cb->buf_idx - *offset));
if (copy_to_user(ubuf, cb->buf.data + *offset, length)) {
dev_dbg(dev->dev, "failed to copy data to userland\n");
rets = -EFAULT;
} else {
rets = length;
if ((*offset + length) < cb->buf_idx) {
*offset += length;
goto out;
}
}
free:
dev_dbg(dev->dev, "free amthif cb memory.\n");
*offset = 0;
mei_io_cb_free(cb);
out:
return rets;
mutex_unlock(&dev->device_lock);
return ret;
}
/**
* mei_amthif_read_start - queue message for sending read credential
*
* @cl: host client
* @file: file pointer of message recipient
* @fp: file pointer of message recipient
*
* Return: 0 on success, <0 on failure.
*/
static int mei_amthif_read_start(struct mei_cl *cl, const struct file *file)
static int mei_amthif_read_start(struct mei_cl *cl, const struct file *fp)
{
struct mei_device *dev = cl->dev;
struct mei_cl_cb *cb;
int rets;
cb = mei_io_cb_init(cl, MEI_FOP_READ, file);
if (!cb) {
rets = -ENOMEM;
goto err;
}
cb = mei_cl_enqueue_ctrl_wr_cb(cl, mei_cl_mtu(cl), MEI_FOP_READ, fp);
if (!cb)
return -ENOMEM;
rets = mei_io_cb_alloc_buf(cb, mei_cl_mtu(cl));
if (rets)
goto err;
list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
cl->rx_flow_ctrl_creds++;
dev->iamthif_state = MEI_IAMTHIF_READING;
dev->iamthif_fp = cb->fp;
dev->iamthif_current_cb = cb;
return 0;
err:
mei_io_cb_free(cb);
return rets;
}
/**
* mei_amthif_send_cmd - send amthif command to the ME
*
* @cl: the host client
* @cb: mei call back struct
*
* Return: 0 on success, <0 on failure.
*/
static int mei_amthif_send_cmd(struct mei_cl *cl, struct mei_cl_cb *cb)
{
struct mei_device *dev;
int ret;
if (!cl->dev || !cb)
return -ENODEV;
dev = cl->dev;
dev->iamthif_state = MEI_IAMTHIF_WRITING;
dev->iamthif_current_cb = cb;
dev->iamthif_fp = cb->fp;
dev->iamthif_canceled = false;
ret = mei_cl_write(cl, cb, false);
if (ret < 0)
return ret;
if (cb->completed)
cb->status = mei_amthif_read_start(cl, cb->fp);
cl->fp = cb->fp;
return 0;
}
@@ -265,20 +126,32 @@ int mei_amthif_run_next_cmd(struct mei_device *dev)
{
struct mei_cl *cl = &dev->iamthif_cl;
struct mei_cl_cb *cb;
int ret;
dev->iamthif_canceled = false;
dev->iamthif_state = MEI_IAMTHIF_IDLE;
dev->iamthif_fp = NULL;
dev_dbg(dev->dev, "complete amthif cmd_list cb.\n");
cb = list_first_entry_or_null(&dev->amthif_cmd_list.list,
typeof(*cb), list);
if (!cb)
if (!cb) {
dev->iamthif_state = MEI_IAMTHIF_IDLE;
cl->fp = NULL;
return 0;
}
list_del_init(&cb->list);
return mei_amthif_send_cmd(cl, cb);
dev->iamthif_state = MEI_IAMTHIF_WRITING;
cl->fp = cb->fp;
ret = mei_cl_write(cl, cb, false);
if (ret < 0)
return ret;
if (cb->completed)
cb->status = mei_amthif_read_start(cl, cb->fp);
return 0;
}
/**
@@ -299,8 +172,7 @@ int mei_amthif_write(struct mei_cl *cl, struct mei_cl_cb *cb)
/*
* The previous request is still in processing, queue this one.
*/
if (dev->iamthif_state > MEI_IAMTHIF_IDLE &&
dev->iamthif_state < MEI_IAMTHIF_READ_COMPLETE)
if (dev->iamthif_state != MEI_IAMTHIF_IDLE)
return 0;
return mei_amthif_run_next_cmd(dev);
@@ -309,7 +181,6 @@ int mei_amthif_write(struct mei_cl *cl, struct mei_cl_cb *cb)
/**
* mei_amthif_poll - the amthif poll function
*
* @dev: the device structure
* @file: pointer to file structure
* @wait: pointer to poll_table structure
*
@@ -317,26 +188,19 @@ int mei_amthif_write(struct mei_cl *cl, struct mei_cl_cb *cb)
*
* Locking: called under "dev->device_lock" lock
*/
unsigned int mei_amthif_poll(struct mei_device *dev,
struct file *file, poll_table *wait)
unsigned int mei_amthif_poll(struct file *file, poll_table *wait)
{
struct mei_cl *cl = file->private_data;
struct mei_cl_cb *cb = mei_cl_read_cb(cl, file);
unsigned int mask = 0;
poll_wait(file, &dev->iamthif_cl.rx_wait, wait);
if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE &&
dev->iamthif_fp == file) {
poll_wait(file, &cl->rx_wait, wait);
if (cb)
mask |= POLLIN | POLLRDNORM;
mei_amthif_run_next_cmd(dev);
}
return mask;
}
/**
* mei_amthif_irq_write - write iamthif command in irq thread context.
*
@@ -393,7 +257,6 @@ int mei_amthif_irq_read_msg(struct mei_cl *cl,
return 0;
dev_dbg(dev->dev, "completed amthif read.\n ");
dev->iamthif_current_cb = NULL;
dev->iamthif_stall_timer = 0;
return 0;
@@ -409,115 +272,63 @@ void mei_amthif_complete(struct mei_cl *cl, struct mei_cl_cb *cb)
{
struct mei_device *dev = cl->dev;
if (cb->fop_type == MEI_FOP_WRITE) {
dev_dbg(dev->dev, "completing amthif call back.\n");
switch (cb->fop_type) {
case MEI_FOP_WRITE:
if (!cb->status) {
dev->iamthif_stall_timer = MEI_IAMTHIF_STALL_TIMER;
mei_schedule_stall_timer(dev);
mei_io_cb_free(cb);
return;
}
/*
* in case of error enqueue the write cb to complete read list
* so it can be propagated to the reader
*/
list_add_tail(&cb->list, &cl->rd_completed);
wake_up_interruptible(&cl->rx_wait);
return;
}
dev->iamthif_state = MEI_IAMTHIF_IDLE;
cl->fp = NULL;
if (!dev->iamthif_canceled) {
/*
* in case of error enqueue the write cb to complete
* read list so it can be propagated to the reader
*/
list_add_tail(&cb->list, &cl->rd_completed);
wake_up_interruptible(&cl->rx_wait);
} else {
mei_io_cb_free(cb);
}
break;
case MEI_FOP_READ:
if (!dev->iamthif_canceled) {
list_add_tail(&cb->list, &cl->rd_completed);
dev_dbg(dev->dev, "amthif read completed\n");
wake_up_interruptible(&cl->rx_wait);
} else {
mei_io_cb_free(cb);
}
if (!dev->iamthif_canceled) {
dev->iamthif_state = MEI_IAMTHIF_READ_COMPLETE;
dev->iamthif_stall_timer = 0;
list_add_tail(&cb->list, &cl->rd_completed);
dev_dbg(dev->dev, "amthif read completed\n");
} else {
mei_amthif_run_next_cmd(dev);
break;
default:
WARN_ON(1);
}
dev_dbg(dev->dev, "completing amthif call back.\n");
wake_up_interruptible(&cl->rx_wait);
}
/**
* mei_clear_list - removes all callbacks associated with file
* from mei_cb_list
*
* @dev: device structure.
* @file: file structure
* @mei_cb_list: callbacks list
*
* mei_clear_list is called to clear resources associated with file
* when application calls close function or Ctrl-C was pressed
*
* Return: true if callback removed from the list, false otherwise
*/
static bool mei_clear_list(struct mei_device *dev,
const struct file *file, struct list_head *mei_cb_list)
static void mei_clear_list(const struct file *file,
struct list_head *mei_cb_list)
{
struct mei_cl *cl = &dev->iamthif_cl;
struct mei_cl_cb *cb, *next;
bool removed = false;
/* list all list member */
list_for_each_entry_safe(cb, next, mei_cb_list, list) {
/* check if list member associated with a file */
if (file == cb->fp) {
/* check if cb equal to current iamthif cb */
if (dev->iamthif_current_cb == cb) {
dev->iamthif_current_cb = NULL;
/* send flow control to iamthif client */
mei_hbm_cl_flow_control_req(dev, cl);
}
/* free all allocated buffers */
list_for_each_entry_safe(cb, next, mei_cb_list, list)
if (file == cb->fp)
mei_io_cb_free(cb);
removed = true;
}
}
return removed;
}
/**
* mei_clear_lists - removes all callbacks associated with file
*
* @dev: device structure
* @file: file structure
*
* mei_clear_lists is called to clear resources associated with file
* when application calls close function or Ctrl-C was pressed
*
* Return: true if callback removed from the list, false otherwise
*/
static bool mei_clear_lists(struct mei_device *dev, const struct file *file)
{
bool removed = false;
struct mei_cl *cl = &dev->iamthif_cl;
/* remove callbacks associated with a file */
mei_clear_list(dev, file, &dev->amthif_cmd_list.list);
if (mei_clear_list(dev, file, &cl->rd_completed))
removed = true;
mei_clear_list(dev, file, &dev->ctrl_rd_list.list);
if (mei_clear_list(dev, file, &dev->ctrl_wr_list.list))
removed = true;
if (mei_clear_list(dev, file, &dev->write_waiting_list.list))
removed = true;
if (mei_clear_list(dev, file, &dev->write_list.list))
removed = true;
/* check if iamthif_current_cb not NULL */
if (dev->iamthif_current_cb && !removed) {
/* check file and iamthif current cb association */
if (dev->iamthif_current_cb->fp == file) {
/* remove cb */
mei_io_cb_free(dev->iamthif_current_cb);
dev->iamthif_current_cb = NULL;
removed = true;
}
}
return removed;
}
/**
@@ -530,23 +341,21 @@ static bool mei_clear_lists(struct mei_device *dev, const struct file *file)
*/
int mei_amthif_release(struct mei_device *dev, struct file *file)
{
struct mei_cl *cl = file->private_data;
if (dev->iamthif_open_count > 0)
dev->iamthif_open_count--;
if (dev->iamthif_fp == file &&
dev->iamthif_state != MEI_IAMTHIF_IDLE) {
if (cl->fp == file && dev->iamthif_state != MEI_IAMTHIF_IDLE) {
dev_dbg(dev->dev, "amthif canceled iamthif state %d\n",
dev->iamthif_state);
dev->iamthif_canceled = true;
if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE) {
dev_dbg(dev->dev, "run next amthif iamthif cb\n");
mei_amthif_run_next_cmd(dev);
}
}
if (mei_clear_lists(dev, file))
dev->iamthif_state = MEI_IAMTHIF_IDLE;
mei_clear_list(file, &dev->amthif_cmd_list.list);
mei_clear_list(file, &cl->rd_completed);
mei_clear_list(file, &dev->ctrl_rd_list.list);
return 0;
}
+5 -6
View File
@@ -126,7 +126,8 @@ ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length)
goto out;
/* wait on event only if there is no other waiter */
if (list_empty(&cl->rd_completed) && !waitqueue_active(&cl->rx_wait)) {
/* synchronized under device mutex */
if (!waitqueue_active(&cl->rx_wait)) {
mutex_unlock(&bus->device_lock);
@@ -142,7 +143,7 @@ ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length)
mutex_lock(&bus->device_lock);
if (!mei_cl_is_connected(cl)) {
rets = -EBUSY;
rets = -ENODEV;
goto out;
}
}
@@ -234,7 +235,7 @@ static void mei_cl_bus_event_work(struct work_struct *work)
/* Prepare for the next read */
if (cldev->events_mask & BIT(MEI_CL_EVENT_RX)) {
mutex_lock(&bus->device_lock);
mei_cl_read_start(cldev->cl, 0, NULL);
mei_cl_read_start(cldev->cl, mei_cl_mtu(cldev->cl), NULL);
mutex_unlock(&bus->device_lock);
}
}
@@ -324,7 +325,7 @@ int mei_cldev_register_event_cb(struct mei_cl_device *cldev,
if (cldev->events_mask & BIT(MEI_CL_EVENT_RX)) {
mutex_lock(&bus->device_lock);
ret = mei_cl_read_start(cldev->cl, 0, NULL);
ret = mei_cl_read_start(cldev->cl, mei_cl_mtu(cldev->cl), NULL);
mutex_unlock(&bus->device_lock);
if (ret && ret != -EBUSY)
return ret;
@@ -983,12 +984,10 @@ void mei_cl_bus_rescan_work(struct work_struct *work)
container_of(work, struct mei_device, bus_rescan_work);
struct mei_me_client *me_cl;
mutex_lock(&bus->device_lock);
me_cl = mei_me_cl_by_uuid(bus, &mei_amthif_guid);
if (me_cl)
mei_amthif_host_init(bus, me_cl);
mei_me_cl_put(me_cl);
mutex_unlock(&bus->device_lock);
mei_cl_bus_rescan(bus);
}
+92 -112
View File
@@ -358,8 +358,9 @@ void mei_io_cb_free(struct mei_cl_cb *cb)
*
* Return: mei_cl_cb pointer or NULL;
*/
struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, enum mei_cb_file_ops type,
const struct file *fp)
static struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl,
enum mei_cb_file_ops type,
const struct file *fp)
{
struct mei_cl_cb *cb;
@@ -419,31 +420,6 @@ static inline void mei_io_list_free(struct mei_cl_cb *list, struct mei_cl *cl)
__mei_io_list_flush(list, cl, true);
}
/**
* mei_io_cb_alloc_buf - allocate callback buffer
*
* @cb: io callback structure
* @length: size of the buffer
*
* Return: 0 on success
* -EINVAL if cb is NULL
* -ENOMEM if allocation failed
*/
int mei_io_cb_alloc_buf(struct mei_cl_cb *cb, size_t length)
{
if (!cb)
return -EINVAL;
if (length == 0)
return 0;
cb->buf.data = kmalloc(length, GFP_KERNEL);
if (!cb->buf.data)
return -ENOMEM;
cb->buf.size = length;
return 0;
}
/**
* mei_cl_alloc_cb - a convenient wrapper for allocating read cb
*
@@ -455,23 +431,58 @@ int mei_io_cb_alloc_buf(struct mei_cl_cb *cb, size_t length)
* Return: cb on success and NULL on failure
*/
struct mei_cl_cb *mei_cl_alloc_cb(struct mei_cl *cl, size_t length,
enum mei_cb_file_ops type,
enum mei_cb_file_ops fop_type,
const struct file *fp)
{
struct mei_cl_cb *cb;
cb = mei_io_cb_init(cl, type, fp);
cb = mei_io_cb_init(cl, fop_type, fp);
if (!cb)
return NULL;
if (mei_io_cb_alloc_buf(cb, length)) {
if (length == 0)
return cb;
cb->buf.data = kmalloc(length, GFP_KERNEL);
if (!cb->buf.data) {
mei_io_cb_free(cb);
return NULL;
}
cb->buf.size = length;
return cb;
}
/**
* mei_cl_enqueue_ctrl_wr_cb - a convenient wrapper for allocating
* and enqueuing of the control commands cb
*
* @cl: host client
* @length: size of the buffer
* @type: operation type
* @fp: associated file pointer (might be NULL)
*
* Return: cb on success and NULL on failure
* Locking: called under "dev->device_lock" lock
*/
struct mei_cl_cb *mei_cl_enqueue_ctrl_wr_cb(struct mei_cl *cl, size_t length,
enum mei_cb_file_ops fop_type,
const struct file *fp)
{
struct mei_cl_cb *cb;
/* for RX always allocate at least client's mtu */
if (length)
length = max_t(size_t, length, mei_cl_mtu(cl));
cb = mei_cl_alloc_cb(cl, length, fop_type, fp);
if (!cb)
return NULL;
list_add_tail(&cb->list, &cl->dev->ctrl_wr_list.list);
return cb;
}
/**
* mei_cl_read_cb - find this cl's callback in the read list
* for a specific file
@@ -754,7 +765,8 @@ void mei_cl_set_disconnected(struct mei_cl *cl)
mei_io_list_flush(&dev->ctrl_rd_list, cl);
mei_io_list_flush(&dev->ctrl_wr_list, cl);
mei_cl_wake_all(cl);
cl->mei_flow_ctrl_creds = 0;
cl->rx_flow_ctrl_creds = 0;
cl->tx_flow_ctrl_creds = 0;
cl->timer_count = 0;
if (!cl->me_cl)
@@ -764,7 +776,7 @@ void mei_cl_set_disconnected(struct mei_cl *cl)
cl->me_cl->connect_count--;
if (cl->me_cl->connect_count == 0)
cl->me_cl->mei_flow_ctrl_creds = 0;
cl->me_cl->tx_flow_ctrl_creds = 0;
mei_me_cl_put(cl->me_cl);
cl->me_cl = NULL;
@@ -814,6 +826,7 @@ static int mei_cl_send_disconnect(struct mei_cl *cl, struct mei_cl_cb *cb)
list_move_tail(&cb->list, &dev->ctrl_rd_list.list);
cl->timer_count = MEI_CONNECT_TIMEOUT;
mei_schedule_stall_timer(dev);
return 0;
}
@@ -867,13 +880,11 @@ static int __mei_cl_disconnect(struct mei_cl *cl)
cl->state = MEI_FILE_DISCONNECTING;
cb = mei_io_cb_init(cl, MEI_FOP_DISCONNECT, NULL);
rets = cb ? 0 : -ENOMEM;
if (rets)
cb = mei_cl_enqueue_ctrl_wr_cb(cl, 0, MEI_FOP_DISCONNECT, NULL);
if (!cb) {
rets = -ENOMEM;
goto out;
cl_dbg(dev, cl, "add disconnect cb to control write list\n");
list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
}
if (mei_hbuf_acquire(dev)) {
rets = mei_cl_send_disconnect(cl, cb);
@@ -1001,6 +1012,7 @@ static int mei_cl_send_connect(struct mei_cl *cl, struct mei_cl_cb *cb)
list_move_tail(&cb->list, &dev->ctrl_rd_list.list);
cl->timer_count = MEI_CONNECT_TIMEOUT;
mei_schedule_stall_timer(dev);
return 0;
}
@@ -1042,14 +1054,14 @@ int mei_cl_irq_connect(struct mei_cl *cl, struct mei_cl_cb *cb,
*
* @cl: host client
* @me_cl: me client
* @file: pointer to file structure
* @fp: pointer to file structure
*
* Locking: called under "dev->device_lock" lock
*
* Return: 0 on success, <0 on failure.
*/
int mei_cl_connect(struct mei_cl *cl, struct mei_me_client *me_cl,
const struct file *file)
const struct file *fp)
{
struct mei_device *dev;
struct mei_cl_cb *cb;
@@ -1076,12 +1088,11 @@ int mei_cl_connect(struct mei_cl *cl, struct mei_me_client *me_cl,
goto nortpm;
}
cb = mei_io_cb_init(cl, MEI_FOP_CONNECT, file);
rets = cb ? 0 : -ENOMEM;
if (rets)
cb = mei_cl_enqueue_ctrl_wr_cb(cl, 0, MEI_FOP_CONNECT, fp);
if (!cb) {
rets = -ENOMEM;
goto out;
list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
}
/* run hbuf acquire last so we don't have to undo */
if (!mei_cl_is_other_connecting(cl) && mei_hbuf_acquire(dev)) {
@@ -1159,50 +1170,42 @@ err:
return ERR_PTR(ret);
}
/**
* mei_cl_flow_ctrl_creds - checks flow_control credits for cl.
* mei_cl_tx_flow_ctrl_creds - checks flow_control credits for cl.
*
* @cl: host client
* @fp: the file pointer associated with the pointer
*
* Return: 1 if mei_flow_ctrl_creds >0, 0 - otherwise.
* Return: 1 if tx_flow_ctrl_creds >0, 0 - otherwise.
*/
static int mei_cl_flow_ctrl_creds(struct mei_cl *cl, const struct file *fp)
static int mei_cl_tx_flow_ctrl_creds(struct mei_cl *cl)
{
int rets;
if (WARN_ON(!cl || !cl->me_cl))
return -EINVAL;
if (cl->mei_flow_ctrl_creds > 0)
if (cl->tx_flow_ctrl_creds > 0)
return 1;
if (mei_cl_is_fixed_address(cl)) {
rets = mei_cl_read_start(cl, mei_cl_mtu(cl), fp);
if (rets && rets != -EBUSY)
return rets;
if (mei_cl_is_fixed_address(cl))
return 1;
}
if (mei_cl_is_single_recv_buf(cl)) {
if (cl->me_cl->mei_flow_ctrl_creds > 0)
if (cl->me_cl->tx_flow_ctrl_creds > 0)
return 1;
}
return 0;
}
/**
* mei_cl_flow_ctrl_reduce - reduces flow_control.
* mei_cl_tx_flow_ctrl_creds_reduce - reduces transmit flow control credits
* for a client
*
* @cl: private data of the file object
* @cl: host client
*
* Return:
* 0 on success
* -EINVAL when ctrl credits are <= 0
*/
static int mei_cl_flow_ctrl_reduce(struct mei_cl *cl)
static int mei_cl_tx_flow_ctrl_creds_reduce(struct mei_cl *cl)
{
if (WARN_ON(!cl || !cl->me_cl))
return -EINVAL;
@@ -1211,13 +1214,13 @@ static int mei_cl_flow_ctrl_reduce(struct mei_cl *cl)
return 0;
if (mei_cl_is_single_recv_buf(cl)) {
if (WARN_ON(cl->me_cl->mei_flow_ctrl_creds <= 0))
if (WARN_ON(cl->me_cl->tx_flow_ctrl_creds <= 0))
return -EINVAL;
cl->me_cl->mei_flow_ctrl_creds--;
cl->me_cl->tx_flow_ctrl_creds--;
} else {
if (WARN_ON(cl->mei_flow_ctrl_creds <= 0))
if (WARN_ON(cl->tx_flow_ctrl_creds <= 0))
return -EINVAL;
cl->mei_flow_ctrl_creds--;
cl->tx_flow_ctrl_creds--;
}
return 0;
}
@@ -1292,7 +1295,7 @@ int mei_cl_irq_notify(struct mei_cl *cl, struct mei_cl_cb *cb,
* mei_cl_notify_request - send notification stop/start request
*
* @cl: host client
* @file: associate request with file
* @fp: associate request with file
* @request: 1 for start or 0 for stop
*
* Locking: called under "dev->device_lock" lock
@@ -1300,7 +1303,7 @@ int mei_cl_irq_notify(struct mei_cl *cl, struct mei_cl_cb *cb,
* Return: 0 on such and error otherwise.
*/
int mei_cl_notify_request(struct mei_cl *cl,
const struct file *file, u8 request)
const struct file *fp, u8 request)
{
struct mei_device *dev;
struct mei_cl_cb *cb;
@@ -1325,7 +1328,7 @@ int mei_cl_notify_request(struct mei_cl *cl,
}
fop_type = mei_cl_notify_req2fop(request);
cb = mei_io_cb_init(cl, fop_type, file);
cb = mei_cl_enqueue_ctrl_wr_cb(cl, 0, fop_type, fp);
if (!cb) {
rets = -ENOMEM;
goto out;
@@ -1336,9 +1339,7 @@ int mei_cl_notify_request(struct mei_cl *cl,
rets = -ENODEV;
goto out;
}
list_add_tail(&cb->list, &dev->ctrl_rd_list.list);
} else {
list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
list_move_tail(&cb->list, &dev->ctrl_rd_list.list);
}
mutex_unlock(&dev->device_lock);
@@ -1435,25 +1436,6 @@ out:
return 0;
}
/**
* mei_cl_is_read_fc_cb - check if read cb is waiting for flow control
* for given host client
*
* @cl: host client
*
* Return: true, if found at least one cb.
*/
static bool mei_cl_is_read_fc_cb(struct mei_cl *cl)
{
struct mei_device *dev = cl->dev;
struct mei_cl_cb *cb;
list_for_each_entry(cb, &dev->ctrl_wr_list.list, list)
if (cb->fop_type == MEI_FOP_READ && cb->cl == cl)
return true;
return false;
}
/**
* mei_cl_read_start - the start read client message function.
*
@@ -1477,26 +1459,22 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length, const struct file *fp)
if (!mei_cl_is_connected(cl))
return -ENODEV;
/* HW currently supports only one pending read */
if (!list_empty(&cl->rd_pending) || mei_cl_is_read_fc_cb(cl))
return -EBUSY;
if (!mei_me_cl_is_active(cl->me_cl)) {
cl_err(dev, cl, "no such me client\n");
return -ENOTTY;
}
/* always allocate at least client max message */
length = max_t(size_t, length, mei_cl_mtu(cl));
cb = mei_cl_alloc_cb(cl, length, MEI_FOP_READ, fp);
if (mei_cl_is_fixed_address(cl) || cl == &dev->iamthif_cl)
return 0;
/* HW currently supports only one pending read */
if (cl->rx_flow_ctrl_creds)
return -EBUSY;
cb = mei_cl_enqueue_ctrl_wr_cb(cl, length, MEI_FOP_READ, fp);
if (!cb)
return -ENOMEM;
if (mei_cl_is_fixed_address(cl)) {
list_add_tail(&cb->list, &cl->rd_pending);
return 0;
}
rets = pm_runtime_get(dev->dev);
if (rets < 0 && rets != -EINPROGRESS) {
pm_runtime_put_noidle(dev->dev);
@@ -1504,16 +1482,15 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length, const struct file *fp)
goto nortpm;
}
rets = 0;
if (mei_hbuf_acquire(dev)) {
rets = mei_hbm_cl_flow_control_req(dev, cl);
if (rets < 0)
goto out;
list_add_tail(&cb->list, &cl->rd_pending);
} else {
rets = 0;
list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
list_move_tail(&cb->list, &cl->rd_pending);
}
cl->rx_flow_ctrl_creds++;
out:
cl_dbg(dev, cl, "rpm: autosuspend\n");
@@ -1557,7 +1534,7 @@ int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
first_chunk = cb->buf_idx == 0;
rets = first_chunk ? mei_cl_flow_ctrl_creds(cl, cb->fp) : 1;
rets = first_chunk ? mei_cl_tx_flow_ctrl_creds(cl) : 1;
if (rets < 0)
return rets;
@@ -1605,7 +1582,7 @@ int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
cb->completed = mei_hdr.msg_complete == 1;
if (first_chunk) {
if (mei_cl_flow_ctrl_reduce(cl))
if (mei_cl_tx_flow_ctrl_creds_reduce(cl))
return -EIO;
}
@@ -1663,7 +1640,7 @@ int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking)
mei_hdr.msg_complete = 0;
mei_hdr.internal = cb->internal;
rets = mei_cl_flow_ctrl_creds(cl, cb->fp);
rets = mei_cl_tx_flow_ctrl_creds(cl);
if (rets < 0)
goto err;
@@ -1691,7 +1668,7 @@ int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking)
if (rets)
goto err;
rets = mei_cl_flow_ctrl_reduce(cl);
rets = mei_cl_tx_flow_ctrl_creds_reduce(cl);
if (rets)
goto err;
@@ -1761,6 +1738,9 @@ void mei_cl_complete(struct mei_cl *cl, struct mei_cl_cb *cb)
case MEI_FOP_READ:
list_add_tail(&cb->list, &cl->rd_completed);
if (!mei_cl_is_fixed_address(cl) &&
!WARN_ON(!cl->rx_flow_ctrl_creds))
cl->rx_flow_ctrl_creds--;
if (!mei_cl_bus_rx_event(cl))
wake_up_interruptible(&cl->rx_wait);
break;
+3 -4
View File
@@ -82,11 +82,7 @@ static inline u8 mei_me_cl_ver(const struct mei_me_client *me_cl)
/*
* MEI IO Functions
*/
struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, enum mei_cb_file_ops type,
const struct file *fp);
void mei_io_cb_free(struct mei_cl_cb *priv_cb);
int mei_io_cb_alloc_buf(struct mei_cl_cb *cb, size_t length);
/**
* mei_io_list_init - Sets up a queue list.
@@ -118,6 +114,9 @@ void mei_cl_read_cb_flush(const struct mei_cl *cl, const struct file *fp);
struct mei_cl_cb *mei_cl_alloc_cb(struct mei_cl *cl, size_t length,
enum mei_cb_file_ops type,
const struct file *fp);
struct mei_cl_cb *mei_cl_enqueue_ctrl_wr_cb(struct mei_cl *cl, size_t length,
enum mei_cb_file_ops type,
const struct file *fp);
int mei_cl_flush_queues(struct mei_cl *cl, const struct file *fp);
/*
+26 -23
View File
@@ -161,6 +161,7 @@ void mei_hbm_cl_hdr(struct mei_cl *cl, u8 hbm_cmd, void *buf, size_t len)
* @dev: the device structure
* @cl: client
* @hbm_cmd: host bus message command
* @buf: message buffer
* @len: buffer length
*
* Return: 0 on success, <0 on failure.
@@ -276,6 +277,7 @@ int mei_hbm_start_req(struct mei_device *dev)
dev->hbm_state = MEI_HBM_STARTING;
dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
mei_schedule_stall_timer(dev);
return 0;
}
@@ -311,6 +313,7 @@ static int mei_hbm_enum_clients_req(struct mei_device *dev)
}
dev->hbm_state = MEI_HBM_ENUM_CLIENTS;
dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
mei_schedule_stall_timer(dev);
return 0;
}
@@ -339,7 +342,7 @@ static int mei_hbm_me_cl_add(struct mei_device *dev,
me_cl->props = res->client_properties;
me_cl->client_id = res->me_addr;
me_cl->mei_flow_ctrl_creds = 0;
me_cl->tx_flow_ctrl_creds = 0;
mei_me_cl_add(dev, me_cl);
@@ -561,6 +564,7 @@ static int mei_hbm_prop_req(struct mei_device *dev, unsigned long start_idx)
}
dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
mei_schedule_stall_timer(dev);
return 0;
}
@@ -636,23 +640,22 @@ int mei_hbm_cl_flow_control_req(struct mei_device *dev, struct mei_cl *cl)
}
/**
* mei_hbm_add_single_flow_creds - adds single buffer credentials.
* mei_hbm_add_single_tx_flow_ctrl_creds - adds single buffer credentials.
*
* @dev: the device structure
* @flow: flow control.
* @fctrl: flow control response bus message
*
* Return: 0 on success, < 0 otherwise
*/
static int mei_hbm_add_single_flow_creds(struct mei_device *dev,
struct hbm_flow_control *flow)
static int mei_hbm_add_single_tx_flow_ctrl_creds(struct mei_device *dev,
struct hbm_flow_control *fctrl)
{
struct mei_me_client *me_cl;
int rets;
me_cl = mei_me_cl_by_id(dev, flow->me_addr);
me_cl = mei_me_cl_by_id(dev, fctrl->me_addr);
if (!me_cl) {
dev_err(dev->dev, "no such me client %d\n",
flow->me_addr);
dev_err(dev->dev, "no such me client %d\n", fctrl->me_addr);
return -ENOENT;
}
@@ -661,9 +664,9 @@ static int mei_hbm_add_single_flow_creds(struct mei_device *dev,
goto out;
}
me_cl->mei_flow_ctrl_creds++;
me_cl->tx_flow_ctrl_creds++;
dev_dbg(dev->dev, "recv flow ctrl msg ME %d (single) creds = %d.\n",
flow->me_addr, me_cl->mei_flow_ctrl_creds);
fctrl->me_addr, me_cl->tx_flow_ctrl_creds);
rets = 0;
out:
@@ -675,24 +678,24 @@ out:
* mei_hbm_cl_flow_control_res - flow control response from me
*
* @dev: the device structure
* @flow_control: flow control response bus message
* @fctrl: flow control response bus message
*/
static void mei_hbm_cl_flow_control_res(struct mei_device *dev,
struct hbm_flow_control *flow_control)
static void mei_hbm_cl_tx_flow_ctrl_creds_res(struct mei_device *dev,
struct hbm_flow_control *fctrl)
{
struct mei_cl *cl;
if (!flow_control->host_addr) {
if (!fctrl->host_addr) {
/* single receive buffer */
mei_hbm_add_single_flow_creds(dev, flow_control);
mei_hbm_add_single_tx_flow_ctrl_creds(dev, fctrl);
return;
}
cl = mei_hbm_cl_find_by_cmd(dev, flow_control);
cl = mei_hbm_cl_find_by_cmd(dev, fctrl);
if (cl) {
cl->mei_flow_ctrl_creds++;
cl->tx_flow_ctrl_creds++;
cl_dbg(dev, cl, "flow control creds = %d.\n",
cl->mei_flow_ctrl_creds);
cl->tx_flow_ctrl_creds);
}
}
@@ -871,10 +874,10 @@ static int mei_hbm_fw_disconnect_req(struct mei_device *dev,
cl->state = MEI_FILE_DISCONNECTING;
cl->timer_count = 0;
cb = mei_io_cb_init(cl, MEI_FOP_DISCONNECT_RSP, NULL);
cb = mei_cl_enqueue_ctrl_wr_cb(cl, 0, MEI_FOP_DISCONNECT_RSP,
NULL);
if (!cb)
return -ENOMEM;
list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
}
return 0;
}
@@ -1022,7 +1025,7 @@ int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
struct mei_hbm_cl_cmd *cl_cmd;
struct hbm_client_connect_request *disconnect_req;
struct hbm_flow_control *flow_control;
struct hbm_flow_control *fctrl;
/* read the message to our buffer */
BUG_ON(hdr->length >= sizeof(dev->rd_msg_buf));
@@ -1102,8 +1105,8 @@ int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
case MEI_FLOW_CONTROL_CMD:
dev_dbg(dev->dev, "hbm: client flow control response: message received.\n");
flow_control = (struct hbm_flow_control *) mei_msg;
mei_hbm_cl_flow_control_res(dev, flow_control);
fctrl = (struct hbm_flow_control *)mei_msg;
mei_hbm_cl_tx_flow_ctrl_creds_res(dev, fctrl);
break;
case MEI_PG_ISOLATION_ENTRY_RES_CMD:
+3
View File
@@ -125,6 +125,9 @@
#define MEI_DEV_ID_BXT_M 0x1A9A /* Broxton M */
#define MEI_DEV_ID_APL_I 0x5A9A /* Apollo Lake I */
#define MEI_DEV_ID_KBP 0xA2BA /* Kaby Point */
#define MEI_DEV_ID_KBP_2 0xA2BB /* Kaby Point 2 */
/*
* MEI HW Section
*/
+3
View File
@@ -18,6 +18,7 @@
#include <linux/kthread.h>
#include <linux/interrupt.h>
#include <linux/pm_runtime.h>
#include "mei_dev.h"
#include "hbm.h"
@@ -1063,6 +1064,8 @@ static int mei_me_hw_reset(struct mei_device *dev, bool intr_enable)
}
}
pm_runtime_set_active(dev->dev);
hcsr = mei_hcsr_read(dev);
/* H_RST may be found lit before reset is started,
* for example if preceding reset flow hasn't completed.
+3
View File
@@ -20,6 +20,7 @@
#include <linux/delay.h>
#include <linux/kthread.h>
#include <linux/irqreturn.h>
#include <linux/pm_runtime.h>
#include <linux/mei.h>
@@ -935,6 +936,8 @@ static int mei_txe_hw_start(struct mei_device *dev)
return ret;
}
pm_runtime_set_active(dev->dev);
/* enable input ready interrupts:
* SEC_IPC_HOST_INT_MASK.IPC_INPUT_READY_INT_MASK
*/
+1 -1
View File
@@ -94,7 +94,7 @@ void mei_cancel_work(struct mei_device *dev)
cancel_work_sync(&dev->reset_work);
cancel_work_sync(&dev->bus_rescan_work);
cancel_delayed_work(&dev->timer_work);
cancel_delayed_work_sync(&dev->timer_work);
}
EXPORT_SYMBOL_GPL(mei_cancel_work);

Some files were not shown because too many files have changed in this diff Show More