Commit 4e7be68e authored by Jiri Kosina's avatar Jiri Kosina

Merge branch 'for-4.20/i2c-hid' into for-linus

- general cleanups of hid-i2c driver
- SPIODEV device descriptor fixes
parents a600ffe6 9ee3e066
...@@ -3,3 +3,6 @@ ...@@ -3,3 +3,6 @@
# #
obj-$(CONFIG_I2C_HID) += i2c-hid.o obj-$(CONFIG_I2C_HID) += i2c-hid.o
i2c-hid-objs = i2c-hid-core.o
i2c-hid-$(CONFIG_DMI) += i2c-hid-dmi-quirks.o
...@@ -43,6 +43,7 @@ ...@@ -43,6 +43,7 @@
#include <linux/platform_data/i2c-hid.h> #include <linux/platform_data/i2c-hid.h>
#include "../hid-ids.h" #include "../hid-ids.h"
#include "i2c-hid.h"
/* quirks to control the device */ /* quirks to control the device */
#define I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV BIT(0) #define I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV BIT(0)
...@@ -668,6 +669,7 @@ static int i2c_hid_parse(struct hid_device *hid) ...@@ -668,6 +669,7 @@ static int i2c_hid_parse(struct hid_device *hid)
char *rdesc; char *rdesc;
int ret; int ret;
int tries = 3; int tries = 3;
char *use_override;
i2c_hid_dbg(ihid, "entering %s\n", __func__); i2c_hid_dbg(ihid, "entering %s\n", __func__);
...@@ -686,26 +688,37 @@ static int i2c_hid_parse(struct hid_device *hid) ...@@ -686,26 +688,37 @@ static int i2c_hid_parse(struct hid_device *hid)
if (ret) if (ret)
return ret; return ret;
rdesc = kzalloc(rsize, GFP_KERNEL); use_override = i2c_hid_get_dmi_hid_report_desc_override(client->name,
&rsize);
if (!rdesc) { if (use_override) {
dbg_hid("couldn't allocate rdesc memory\n"); rdesc = use_override;
return -ENOMEM; i2c_hid_dbg(ihid, "Using a HID report descriptor override\n");
} } else {
rdesc = kzalloc(rsize, GFP_KERNEL);
i2c_hid_dbg(ihid, "asking HID report descriptor\n");
if (!rdesc) {
ret = i2c_hid_command(client, &hid_report_descr_cmd, rdesc, rsize); dbg_hid("couldn't allocate rdesc memory\n");
if (ret) { return -ENOMEM;
hid_err(hid, "reading report descriptor failed\n"); }
kfree(rdesc);
return -EIO; i2c_hid_dbg(ihid, "asking HID report descriptor\n");
ret = i2c_hid_command(client, &hid_report_descr_cmd,
rdesc, rsize);
if (ret) {
hid_err(hid, "reading report descriptor failed\n");
kfree(rdesc);
return -EIO;
}
} }
i2c_hid_dbg(ihid, "Report Descriptor: %*ph\n", rsize, rdesc); i2c_hid_dbg(ihid, "Report Descriptor: %*ph\n", rsize, rdesc);
ret = hid_parse_report(hid, rdesc, rsize); ret = hid_parse_report(hid, rdesc, rsize);
kfree(rdesc); if (!use_override)
kfree(rdesc);
if (ret) { if (ret) {
dbg_hid("parsing report descriptor failed\n"); dbg_hid("parsing report descriptor failed\n");
return ret; return ret;
...@@ -832,12 +845,19 @@ static int i2c_hid_fetch_hid_descriptor(struct i2c_hid *ihid) ...@@ -832,12 +845,19 @@ static int i2c_hid_fetch_hid_descriptor(struct i2c_hid *ihid)
int ret; int ret;
/* i2c hid fetch using a fixed descriptor size (30 bytes) */ /* i2c hid fetch using a fixed descriptor size (30 bytes) */
i2c_hid_dbg(ihid, "Fetching the HID descriptor\n"); if (i2c_hid_get_dmi_i2c_hid_desc_override(client->name)) {
ret = i2c_hid_command(client, &hid_descr_cmd, ihid->hdesc_buffer, i2c_hid_dbg(ihid, "Using a HID descriptor override\n");
sizeof(struct i2c_hid_desc)); ihid->hdesc =
if (ret) { *i2c_hid_get_dmi_i2c_hid_desc_override(client->name);
dev_err(&client->dev, "hid_descr_cmd failed\n"); } else {
return -ENODEV; i2c_hid_dbg(ihid, "Fetching the HID descriptor\n");
ret = i2c_hid_command(client, &hid_descr_cmd,
ihid->hdesc_buffer,
sizeof(struct i2c_hid_desc));
if (ret) {
dev_err(&client->dev, "hid_descr_cmd failed\n");
return -ENODEV;
}
} }
/* Validate the length of HID descriptor, the 4 first bytes: /* Validate the length of HID descriptor, the 4 first bytes:
......
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0+ */
#ifndef I2C_HID_H
#define I2C_HID_H
#ifdef CONFIG_DMI
struct i2c_hid_desc *i2c_hid_get_dmi_i2c_hid_desc_override(uint8_t *i2c_name);
char *i2c_hid_get_dmi_hid_report_desc_override(uint8_t *i2c_name,
unsigned int *size);
#else
static inline struct i2c_hid_desc
*i2c_hid_get_dmi_i2c_hid_desc_override(uint8_t *i2c_name)
{ return NULL; }
static inline char *i2c_hid_get_dmi_hid_report_desc_override(uint8_t *i2c_name,
unsigned int *size)
{ return NULL; }
#endif
#endif
...@@ -280,14 +280,14 @@ static int write_ipc_from_queue(struct ishtp_device *dev) ...@@ -280,14 +280,14 @@ static int write_ipc_from_queue(struct ishtp_device *dev)
* if tx send list is empty - return 0; * if tx send list is empty - return 0;
* may happen, as RX_COMPLETE handler doesn't check list emptiness. * may happen, as RX_COMPLETE handler doesn't check list emptiness.
*/ */
if (list_empty(&dev->wr_processing_list_head.link)) { if (list_empty(&dev->wr_processing_list)) {
spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags); spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags);
out_ipc_locked = 0; out_ipc_locked = 0;
return 0; return 0;
} }
ipc_link = list_entry(dev->wr_processing_list_head.link.next, ipc_link = list_first_entry(&dev->wr_processing_list,
struct wr_msg_ctl_info, link); struct wr_msg_ctl_info, link);
/* first 4 bytes of the data is the doorbell value (IPC header) */ /* first 4 bytes of the data is the doorbell value (IPC header) */
length = ipc_link->length - sizeof(uint32_t); length = ipc_link->length - sizeof(uint32_t);
doorbell_val = *(uint32_t *)ipc_link->inline_data; doorbell_val = *(uint32_t *)ipc_link->inline_data;
...@@ -338,7 +338,7 @@ static int write_ipc_from_queue(struct ishtp_device *dev) ...@@ -338,7 +338,7 @@ static int write_ipc_from_queue(struct ishtp_device *dev)
ipc_send_compl = ipc_link->ipc_send_compl; ipc_send_compl = ipc_link->ipc_send_compl;
ipc_send_compl_prm = ipc_link->ipc_send_compl_prm; ipc_send_compl_prm = ipc_link->ipc_send_compl_prm;
list_del_init(&ipc_link->link); list_del_init(&ipc_link->link);
list_add_tail(&ipc_link->link, &dev->wr_free_list_head.link); list_add(&ipc_link->link, &dev->wr_free_list);
spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags); spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags);
/* /*
...@@ -372,18 +372,18 @@ static int write_ipc_to_queue(struct ishtp_device *dev, ...@@ -372,18 +372,18 @@ static int write_ipc_to_queue(struct ishtp_device *dev,
unsigned char *msg, int length) unsigned char *msg, int length)
{ {
struct wr_msg_ctl_info *ipc_link; struct wr_msg_ctl_info *ipc_link;
unsigned long flags; unsigned long flags;
if (length > IPC_FULL_MSG_SIZE) if (length > IPC_FULL_MSG_SIZE)
return -EMSGSIZE; return -EMSGSIZE;
spin_lock_irqsave(&dev->wr_processing_spinlock, flags); spin_lock_irqsave(&dev->wr_processing_spinlock, flags);
if (list_empty(&dev->wr_free_list_head.link)) { if (list_empty(&dev->wr_free_list)) {
spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags); spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags);
return -ENOMEM; return -ENOMEM;
} }
ipc_link = list_entry(dev->wr_free_list_head.link.next, ipc_link = list_first_entry(&dev->wr_free_list,
struct wr_msg_ctl_info, link); struct wr_msg_ctl_info, link);
list_del_init(&ipc_link->link); list_del_init(&ipc_link->link);
ipc_link->ipc_send_compl = ipc_send_compl; ipc_link->ipc_send_compl = ipc_send_compl;
...@@ -391,7 +391,7 @@ static int write_ipc_to_queue(struct ishtp_device *dev, ...@@ -391,7 +391,7 @@ static int write_ipc_to_queue(struct ishtp_device *dev,
ipc_link->length = length; ipc_link->length = length;
memcpy(ipc_link->inline_data, msg, length); memcpy(ipc_link->inline_data, msg, length);
list_add_tail(&ipc_link->link, &dev->wr_processing_list_head.link); list_add_tail(&ipc_link->link, &dev->wr_processing_list);
spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags); spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags);
write_ipc_from_queue(dev); write_ipc_from_queue(dev);
...@@ -487,17 +487,13 @@ static int ish_fw_reset_handler(struct ishtp_device *dev) ...@@ -487,17 +487,13 @@ static int ish_fw_reset_handler(struct ishtp_device *dev)
{ {
uint32_t reset_id; uint32_t reset_id;
unsigned long flags; unsigned long flags;
struct wr_msg_ctl_info *processing, *next;
/* Read reset ID */ /* Read reset ID */
reset_id = ish_reg_read(dev, IPC_REG_ISH2HOST_MSG) & 0xFFFF; reset_id = ish_reg_read(dev, IPC_REG_ISH2HOST_MSG) & 0xFFFF;
/* Clear IPC output queue */ /* Clear IPC output queue */
spin_lock_irqsave(&dev->wr_processing_spinlock, flags); spin_lock_irqsave(&dev->wr_processing_spinlock, flags);
list_for_each_entry_safe(processing, next, list_splice_init(&dev->wr_processing_list, &dev->wr_free_list);
&dev->wr_processing_list_head.link, link) {
list_move_tail(&processing->link, &dev->wr_free_list_head.link);
}
spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags); spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags);
/* ISHTP notification in IPC_RESET */ /* ISHTP notification in IPC_RESET */
...@@ -921,9 +917,9 @@ struct ishtp_device *ish_dev_init(struct pci_dev *pdev) ...@@ -921,9 +917,9 @@ struct ishtp_device *ish_dev_init(struct pci_dev *pdev)
spin_lock_init(&dev->out_ipc_spinlock); spin_lock_init(&dev->out_ipc_spinlock);
/* Init IPC processing and free lists */ /* Init IPC processing and free lists */
INIT_LIST_HEAD(&dev->wr_processing_list_head.link); INIT_LIST_HEAD(&dev->wr_processing_list);
INIT_LIST_HEAD(&dev->wr_free_list_head.link); INIT_LIST_HEAD(&dev->wr_free_list);
for (i = 0; i < IPC_TX_FIFO_SIZE; ++i) { for (i = 0; i < IPC_TX_FIFO_SIZE; i++) {
struct wr_msg_ctl_info *tx_buf; struct wr_msg_ctl_info *tx_buf;
tx_buf = devm_kzalloc(&pdev->dev, tx_buf = devm_kzalloc(&pdev->dev,
...@@ -939,7 +935,7 @@ struct ishtp_device *ish_dev_init(struct pci_dev *pdev) ...@@ -939,7 +935,7 @@ struct ishtp_device *ish_dev_init(struct pci_dev *pdev)
i); i);
break; break;
} }
list_add_tail(&tx_buf->link, &dev->wr_free_list_head.link); list_add_tail(&tx_buf->link, &dev->wr_free_list);
} }
dev->ops = &ish_hw_ops; dev->ops = &ish_hw_ops;
......
...@@ -115,18 +115,19 @@ static const struct pci_device_id ish_invalid_pci_ids[] = { ...@@ -115,18 +115,19 @@ static const struct pci_device_id ish_invalid_pci_ids[] = {
*/ */
static int ish_probe(struct pci_dev *pdev, const struct pci_device_id *ent) static int ish_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{ {
struct ishtp_device *dev; int ret;
struct ish_hw *hw; struct ish_hw *hw;
int ret; struct ishtp_device *ishtp;
struct device *dev = &pdev->dev;
/* Check for invalid platforms for ISH support */ /* Check for invalid platforms for ISH support */
if (pci_dev_present(ish_invalid_pci_ids)) if (pci_dev_present(ish_invalid_pci_ids))
return -ENODEV; return -ENODEV;
/* enable pci dev */ /* enable pci dev */
ret = pci_enable_device(pdev); ret = pcim_enable_device(pdev);
if (ret) { if (ret) {
dev_err(&pdev->dev, "ISH: Failed to enable PCI device\n"); dev_err(dev, "ISH: Failed to enable PCI device\n");
return ret; return ret;
} }
...@@ -134,65 +135,44 @@ static int ish_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -134,65 +135,44 @@ static int ish_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
pci_set_master(pdev); pci_set_master(pdev);
/* pci request regions for ISH driver */ /* pci request regions for ISH driver */
ret = pci_request_regions(pdev, KBUILD_MODNAME); ret = pcim_iomap_regions(pdev, 1 << 0, KBUILD_MODNAME);
if (ret) { if (ret) {
dev_err(&pdev->dev, "ISH: Failed to get PCI regions\n"); dev_err(dev, "ISH: Failed to get PCI regions\n");
goto disable_device; return ret;
} }
/* allocates and initializes the ISH dev structure */ /* allocates and initializes the ISH dev structure */
dev = ish_dev_init(pdev); ishtp = ish_dev_init(pdev);
if (!dev) { if (!ishtp) {
ret = -ENOMEM; ret = -ENOMEM;
goto release_regions; return ret;
} }
hw = to_ish_hw(dev); hw = to_ish_hw(ishtp);
dev->print_log = ish_event_tracer; ishtp->print_log = ish_event_tracer;
/* mapping IO device memory */ /* mapping IO device memory */
hw->mem_addr = pci_iomap(pdev, 0, 0); hw->mem_addr = pcim_iomap_table(pdev)[0];
if (!hw->mem_addr) { ishtp->pdev = pdev;
dev_err(&pdev->dev, "ISH: mapping I/O range failure\n");
ret = -ENOMEM;
goto free_device;
}
dev->pdev = pdev;
pdev->dev_flags |= PCI_DEV_FLAGS_NO_D3; pdev->dev_flags |= PCI_DEV_FLAGS_NO_D3;
/* request and enable interrupt */ /* request and enable interrupt */
ret = request_irq(pdev->irq, ish_irq_handler, IRQF_SHARED, ret = devm_request_irq(dev, pdev->irq, ish_irq_handler,
KBUILD_MODNAME, dev); IRQF_SHARED, KBUILD_MODNAME, ishtp);
if (ret) { if (ret) {
dev_err(&pdev->dev, "ISH: request IRQ failure (%d)\n", dev_err(dev, "ISH: request IRQ %d failed\n", pdev->irq);
pdev->irq); return ret;
goto free_device;
} }
dev_set_drvdata(dev->devc, dev); dev_set_drvdata(ishtp->devc, ishtp);
init_waitqueue_head(&dev->suspend_wait); init_waitqueue_head(&ishtp->suspend_wait);
init_waitqueue_head(&dev->resume_wait); init_waitqueue_head(&ishtp->resume_wait);
ret = ish_init(dev); ret = ish_init(ishtp);
if (ret) if (ret)
goto free_irq; return ret;
return 0; return 0;
free_irq:
free_irq(pdev->irq, dev);
free_device:
pci_iounmap(pdev, hw->mem_addr);
release_regions:
pci_release_regions(pdev);
disable_device:
pci_clear_master(pdev);
pci_disable_device(pdev);
dev_err(&pdev->dev, "ISH: PCI driver initialization failed.\n");
return ret;
} }
/** /**
...@@ -204,16 +184,9 @@ static int ish_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -204,16 +184,9 @@ static int ish_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
static void ish_remove(struct pci_dev *pdev) static void ish_remove(struct pci_dev *pdev)
{ {
struct ishtp_device *ishtp_dev = pci_get_drvdata(pdev); struct ishtp_device *ishtp_dev = pci_get_drvdata(pdev);
struct ish_hw *hw = to_ish_hw(ishtp_dev);
ishtp_bus_remove_all_clients(ishtp_dev, false); ishtp_bus_remove_all_clients(ishtp_dev, false);
ish_device_disable(ishtp_dev); ish_device_disable(ishtp_dev);
free_irq(pdev->irq, ishtp_dev);
pci_iounmap(pdev, hw->mem_addr);
pci_release_regions(pdev);
pci_clear_master(pdev);
pci_disable_device(pdev);
} }
static struct device __maybe_unused *ish_resume_device; static struct device __maybe_unused *ish_resume_device;
......
...@@ -320,23 +320,14 @@ static void process_recv(struct ishtp_cl *hid_ishtp_cl, void *recv_buf, ...@@ -320,23 +320,14 @@ static void process_recv(struct ishtp_cl *hid_ishtp_cl, void *recv_buf,
*/ */
static void ish_cl_event_cb(struct ishtp_cl_device *device) static void ish_cl_event_cb(struct ishtp_cl_device *device)
{ {
struct ishtp_cl *hid_ishtp_cl = device->driver_data; struct ishtp_cl *hid_ishtp_cl = ishtp_get_drvdata(device);
struct ishtp_cl_rb *rb_in_proc; struct ishtp_cl_rb *rb_in_proc;
size_t r_length; size_t r_length;
unsigned long flags;
if (!hid_ishtp_cl) if (!hid_ishtp_cl)
return; return;
spin_lock_irqsave(&hid_ishtp_cl->in_process_spinlock, flags); while ((rb_in_proc = ishtp_cl_rx_get_rb(hid_ishtp_cl)) != NULL) {
while (!list_empty(&hid_ishtp_cl->in_process_list.list)) {
rb_in_proc = list_entry(
hid_ishtp_cl->in_process_list.list.next,
struct ishtp_cl_rb, list);
list_del_init(&rb_in_proc->list);
spin_unlock_irqrestore(&hid_ishtp_cl->in_process_spinlock,
flags);
if (!rb_in_proc->buffer.data) if (!rb_in_proc->buffer.data)
return; return;
...@@ -346,9 +337,7 @@ static void ish_cl_event_cb(struct ishtp_cl_device *device) ...@@ -346,9 +337,7 @@ static void ish_cl_event_cb(struct ishtp_cl_device *device)
process_recv(hid_ishtp_cl, rb_in_proc->buffer.data, r_length); process_recv(hid_ishtp_cl, rb_in_proc->buffer.data, r_length);
ishtp_cl_io_rb_recycle(rb_in_proc); ishtp_cl_io_rb_recycle(rb_in_proc);
spin_lock_irqsave(&hid_ishtp_cl->in_process_spinlock, flags);
} }
spin_unlock_irqrestore(&hid_ishtp_cl->in_process_spinlock, flags);
} }
/** /**
...@@ -637,8 +626,8 @@ static int ishtp_get_report_descriptor(struct ishtp_cl *hid_ishtp_cl, ...@@ -637,8 +626,8 @@ static int ishtp_get_report_descriptor(struct ishtp_cl *hid_ishtp_cl,
static int hid_ishtp_cl_init(struct ishtp_cl *hid_ishtp_cl, int reset) static int hid_ishtp_cl_init(struct ishtp_cl *hid_ishtp_cl, int reset)
{ {
struct ishtp_device *dev; struct ishtp_device *dev;
unsigned long flags;
struct ishtp_cl_data *client_data = hid_ishtp_cl->client_data; struct ishtp_cl_data *client_data = hid_ishtp_cl->client_data;
struct ishtp_fw_client *fw_client;
int i; int i;
int rv; int rv;
...@@ -660,16 +649,14 @@ static int hid_ishtp_cl_init(struct ishtp_cl *hid_ishtp_cl, int reset) ...@@ -660,16 +649,14 @@ static int hid_ishtp_cl_init(struct ishtp_cl *hid_ishtp_cl, int reset)
hid_ishtp_cl->rx_ring_size = HID_CL_RX_RING_SIZE; hid_ishtp_cl->rx_ring_size = HID_CL_RX_RING_SIZE;
hid_ishtp_cl->tx_ring_size = HID_CL_TX_RING_SIZE; hid_ishtp_cl->tx_ring_size = HID_CL_TX_RING_SIZE;
spin_lock_irqsave(&dev->fw_clients_lock, flags); fw_client = ishtp_fw_cl_get_client(dev, &hid_ishtp_guid);
i = ishtp_fw_cl_by_uuid(dev, &hid_ishtp_guid); if (!fw_client) {
if (i < 0) {
spin_unlock_irqrestore(&dev->fw_clients_lock, flags);
dev_err(&client_data->cl_device->dev, dev_err(&client_data->cl_device->dev,
"ish client uuid not found\n"); "ish client uuid not found\n");
return i; return -ENOENT;
} }
hid_ishtp_cl->fw_client_id = dev->fw_clients[i].client_id;
spin_unlock_irqrestore(&dev->fw_clients_lock, flags); hid_ishtp_cl->fw_client_id = fw_client->client_id;
hid_ishtp_cl->state = ISHTP_CL_CONNECTING; hid_ishtp_cl->state = ISHTP_CL_CONNECTING;
rv = ishtp_cl_connect(hid_ishtp_cl); rv = ishtp_cl_connect(hid_ishtp_cl);
...@@ -765,7 +752,7 @@ static void hid_ishtp_cl_reset_handler(struct work_struct *work) ...@@ -765,7 +752,7 @@ static void hid_ishtp_cl_reset_handler(struct work_struct *work)
if (!hid_ishtp_cl) if (!hid_ishtp_cl)
return; return;
cl_device->driver_data = hid_ishtp_cl; ishtp_set_drvdata(cl_device, hid_ishtp_cl);
hid_ishtp_cl->client_data = client_data; hid_ishtp_cl->client_data = client_data;
client_data->hid_ishtp_cl = hid_ishtp_cl; client_data->hid_ishtp_cl = hid_ishtp_cl;
...@@ -814,7 +801,7 @@ static int hid_ishtp_cl_probe(struct ishtp_cl_device *cl_device) ...@@ -814,7 +801,7 @@ static int hid_ishtp_cl_probe(struct ishtp_cl_device *cl_device)
if (!hid_ishtp_cl) if (!hid_ishtp_cl)
return -ENOMEM; return -ENOMEM;
cl_device->driver_data = hid_ishtp_cl; ishtp_set_drvdata(cl_device, hid_ishtp_cl);
hid_ishtp_cl->client_data = client_data; hid_ishtp_cl->client_data = client_data;
client_data->hid_ishtp_cl = hid_ishtp_cl; client_data->hid_ishtp_cl = hid_ishtp_cl;
client_data->cl_device = cl_device; client_data->cl_device = cl_device;
...@@ -844,7 +831,7 @@ static int hid_ishtp_cl_probe(struct ishtp_cl_device *cl_device) ...@@ -844,7 +831,7 @@ static int hid_ishtp_cl_probe(struct ishtp_cl_device *cl_device)
*/ */
static int hid_ishtp_cl_remove(struct ishtp_cl_device *cl_device) static int hid_ishtp_cl_remove(struct ishtp_cl_device *cl_device)
{ {
struct ishtp_cl *hid_ishtp_cl = cl_device->driver_data; struct ishtp_cl *hid_ishtp_cl = ishtp_get_drvdata(cl_device);
struct ishtp_cl_data *client_data = hid_ishtp_cl->client_data; struct ishtp_cl_data *client_data = hid_ishtp_cl->client_data;
hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__, hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__,
...@@ -874,7 +861,7 @@ static int hid_ishtp_cl_remove(struct ishtp_cl_device *cl_device) ...@@ -874,7 +861,7 @@ static int hid_ishtp_cl_remove(struct ishtp_cl_device *cl_device)
*/ */
static int hid_ishtp_cl_reset(struct ishtp_cl_device *cl_device) static int hid_ishtp_cl_reset(struct ishtp_cl_device *cl_device)
{ {
struct ishtp_cl *hid_ishtp_cl = cl_device->driver_data; struct ishtp_cl *hid_ishtp_cl = ishtp_get_drvdata(cl_device);
struct ishtp_cl_data *client_data = hid_ishtp_cl->client_data; struct ishtp_cl_data *client_data = hid_ishtp_cl->client_data;
hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__, hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__,
...@@ -898,7 +885,7 @@ static int hid_ishtp_cl_reset(struct ishtp_cl_device *cl_device) ...@@ -898,7 +885,7 @@ static int hid_ishtp_cl_reset(struct ishtp_cl_device *cl_device)
static int hid_ishtp_cl_suspend(struct device *device) static int hid_ishtp_cl_suspend(struct device *device)
{ {
struct ishtp_cl_device *cl_device = to_ishtp_cl_device(device); struct ishtp_cl_device *cl_device = to_ishtp_cl_device(device);
struct ishtp_cl *hid_ishtp_cl = cl_device->driver_data; struct ishtp_cl *hid_ishtp_cl = ishtp_get_drvdata(cl_device);
struct ishtp_cl_data *client_data = hid_ishtp_cl->client_data; struct ishtp_cl_data *client_data = hid_ishtp_cl->client_data;
hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__, hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__,
...@@ -919,7 +906,7 @@ static int hid_ishtp_cl_suspend(struct device *device) ...@@ -919,7 +906,7 @@ static int hid_ishtp_cl_suspend(struct device *device)
static int hid_ishtp_cl_resume(struct device *device) static int hid_ishtp_cl_resume(struct device *device)
{ {
struct ishtp_cl_device *cl_device = to_ishtp_cl_device(device); struct ishtp_cl_device *cl_device = to_ishtp_cl_device(device);
struct ishtp_cl *hid_ishtp_cl = cl_device->driver_data; struct ishtp_cl *hid_ishtp_cl = ishtp_get_drvdata(cl_device);
struct ishtp_cl_data *client_data = hid_ishtp_cl->client_data; struct ishtp_cl_data *client_data = hid_ishtp_cl->client_data;
hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__, hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__,
......
...@@ -148,6 +148,31 @@ int ishtp_fw_cl_by_uuid(struct ishtp_device *dev, const uuid_le *uuid) ...@@ -148,6 +148,31 @@ int ishtp_fw_cl_by_uuid(struct ishtp_device *dev, const uuid_le *uuid)
} }
EXPORT_SYMBOL(ishtp_fw_cl_by_uuid); EXPORT_SYMBOL(ishtp_fw_cl_by_uuid);
/**
* ishtp_fw_cl_get_client() - return client information to client
* @dev: the ishtp device structure
* @uuid: uuid of the client to search
*
* Search firmware client using UUID and reture related client information.
*
* Return: pointer of client information on success, NULL on failure.
*/
struct ishtp_fw_client *ishtp_fw_cl_get_client(struct ishtp_device *dev,
const uuid_le *uuid)
{
int i;
unsigned long flags;
spin_lock_irqsave(&dev->fw_clients_lock, flags);
i = ishtp_fw_cl_by_uuid(dev, uuid);
spin_unlock_irqrestore(&dev->fw_clients_lock, flags);
if (i < 0 || dev->fw_clients[i].props.fixed_address)
return NULL;
return &dev->fw_clients[i];
}
EXPORT_SYMBOL(ishtp_fw_cl_get_client);
/** /**
* ishtp_fw_cl_by_id() - return index to fw_clients for client_id * ishtp_fw_cl_by_id() - return index to fw_clients for client_id
* @dev: the ishtp device structure * @dev: the ishtp device structure
...@@ -563,6 +588,33 @@ void ishtp_put_device(struct ishtp_cl_device *cl_device) ...@@ -563,6 +588,33 @@ void ishtp_put_device(struct ishtp_cl_device *cl_device)
} }
EXPORT_SYMBOL(ishtp_put_device); EXPORT_SYMBOL(ishtp_put_device);
/**
* ishtp_set_drvdata() - set client driver data
* @cl_device: client device instance
* @data: driver data need to be set
*
* Set client driver data to cl_device->driver_data.
*/
void ishtp_set_drvdata(struct ishtp_cl_device *cl_device, void *data)
{
cl_device->driver_data = data;
}
EXPORT_SYMBOL(ishtp_set_drvdata);
/**
* ishtp_get_drvdata() - get client driver data
* @cl_device: client device instance
*
* Get client driver data from cl_device->driver_data.
*
* Return: pointer of driver data
*/
void *ishtp_get_drvdata(struct ishtp_cl_device *cl_device)
{
return cl_device->driver_data;
}
EXPORT_SYMBOL(ishtp_get_drvdata);
/** /**
* ishtp_bus_new_client() - Create a new client * ishtp_bus_new_client() - Create a new client
* @dev: ISHTP device instance * @dev: ISHTP device instance
......
...@@ -101,6 +101,9 @@ void ishtp_reset_compl_handler(struct ishtp_device *dev); ...@@ -101,6 +101,9 @@ void ishtp_reset_compl_handler(struct ishtp_device *dev);
void ishtp_put_device(struct ishtp_cl_device *); void ishtp_put_device(struct ishtp_cl_device *);
void ishtp_get_device(struct ishtp_cl_device *); void ishtp_get_device(struct ishtp_cl_device *);
void ishtp_set_drvdata(struct ishtp_cl_device *cl_device, void *data);
void *ishtp_get_drvdata(struct ishtp_cl_device *cl_device);
int __ishtp_cl_driver_register(struct ishtp_cl_driver *driver, int __ishtp_cl_driver_register(struct ishtp_cl_driver *driver,
struct module *owner); struct module *owner);
#define ishtp_cl_driver_register(driver) \ #define ishtp_cl_driver_register(driver) \
...@@ -110,5 +113,7 @@ void ishtp_cl_driver_unregister(struct ishtp_cl_driver *driver); ...@@ -110,5 +113,7 @@ void ishtp_cl_driver_unregister(struct ishtp_cl_driver *driver);
int ishtp_register_event_cb(struct ishtp_cl_device *device, int ishtp_register_event_cb(struct ishtp_cl_device *device,
void (*read_cb)(struct ishtp_cl_device *)); void (*read_cb)(struct ishtp_cl_device *));
int ishtp_fw_cl_by_uuid(struct ishtp_device *dev, const uuid_le *cuuid); int ishtp_fw_cl_by_uuid(struct ishtp_device *dev, const uuid_le *cuuid);
struct ishtp_fw_client *ishtp_fw_cl_get_client(struct ishtp_device *dev,
const uuid_le *uuid);
#endif /* _LINUX_ISHTP_CL_BUS_H */ #endif /* _LINUX_ISHTP_CL_BUS_H */
...@@ -69,6 +69,8 @@ int ishtp_cl_alloc_tx_ring(struct ishtp_cl *cl) ...@@ -69,6 +69,8 @@ int ishtp_cl_alloc_tx_ring(struct ishtp_cl *cl)
int j; int j;
unsigned long flags; unsigned long flags;
cl->tx_ring_free_size = 0;
/* Allocate pool to free Tx bufs */ /* Allocate pool to free Tx bufs */
for (j = 0; j < cl->tx_ring_size; ++j) { for (j = 0; j < cl->tx_ring_size; ++j) {
struct ishtp_cl_tx_ring *tx_buf; struct ishtp_cl_tx_ring *tx_buf;
...@@ -85,6 +87,7 @@ int ishtp_cl_alloc_tx_ring(struct ishtp_cl *cl) ...@@ -85,6 +87,7 @@ int ishtp_cl_alloc_tx_ring(struct ishtp_cl *cl)
spin_lock_irqsave(&cl->tx_free_list_spinlock, flags); spin_lock_irqsave(&cl->tx_free_list_spinlock, flags);
list_add_tail(&tx_buf->list, &cl->tx_free_list.list); list_add_tail(&tx_buf->list, &cl->tx_free_list.list);
++cl->tx_ring_free_size;
spin_unlock_irqrestore(&cl->tx_free_list_spinlock, flags); spin_unlock_irqrestore(&cl->tx_free_list_spinlock, flags);
} }
return 0; return 0;
...@@ -144,6 +147,7 @@ void ishtp_cl_free_tx_ring(struct ishtp_cl *cl) ...@@ -144,6 +147,7 @@ void ishtp_cl_free_tx_ring(struct ishtp_cl *cl)
tx_buf = list_entry(cl->tx_free_list.list.next, tx_buf = list_entry(cl->tx_free_list.list.next,
struct ishtp_cl_tx_ring, list); struct ishtp_cl_tx_ring, list);
list_del(&tx_buf->list); list_del(&tx_buf->list);
--cl->tx_ring_free_size;
kfree(tx_buf->send_buf.data); kfree(tx_buf->send_buf.data);
kfree(tx_buf); kfree(tx_buf);
} }
...@@ -255,3 +259,48 @@ int ishtp_cl_io_rb_recycle(struct ishtp_cl_rb *rb) ...@@ -255,3 +259,48 @@ int ishtp_cl_io_rb_recycle(struct ishtp_cl_rb *rb)
return rets; return rets;
} }
EXPORT_SYMBOL(ishtp_cl_io_rb_recycle); EXPORT_SYMBOL(ishtp_cl_io_rb_recycle);
/**
* ishtp_cl_tx_empty() -test whether client device tx buffer is empty
* @cl: Pointer to client device instance
*
* Look client device tx buffer list, and check whether this list is empty
*
* Return: true if client tx buffer list is empty else false
*/
bool ishtp_cl_tx_empty(struct ishtp_cl *cl)
{
int tx_list_empty;
unsigned long tx_flags;
spin_lock_irqsave(&cl->tx_list_spinlock, tx_flags);
tx_list_empty = list_empty(&cl->tx_list.list);
spin_unlock_irqrestore(&cl->tx_list_spinlock, tx_flags);
return !!tx_list_empty;
}
EXPORT_SYMBOL(ishtp_cl_tx_empty);
/**
* ishtp_cl_rx_get_rb() -Get a rb from client device rx buffer list
* @cl: Pointer to client device instance
*
* Check client device in-processing buffer list and get a rb from it.
*
* Return: rb pointer if buffer list isn't empty else NULL
*/
struct ishtp_cl_rb *ishtp_cl_rx_get_rb(struct ishtp_cl *cl)
{
unsigned long rx_flags;
struct ishtp_cl_rb *rb;
spin_lock_irqsave(&cl->in_process_spinlock, rx_flags);
rb = list_first_entry_or_null(&cl->in_process_list.list,
struct ishtp_cl_rb, list);
if (rb)
list_del_init(&rb->list);
spin_unlock_irqrestore(&cl->in_process_spinlock, rx_flags);
return rb;
}
EXPORT_SYMBOL(ishtp_cl_rx_get_rb);
...@@ -22,6 +22,25 @@ ...@@ -22,6 +22,25 @@
#include "hbm.h" #include "hbm.h"
#include "client.h" #include "client.h"
int ishtp_cl_get_tx_free_buffer_size(struct ishtp_cl *cl)
{
unsigned long tx_free_flags;
int size;
spin_lock_irqsave(&cl->tx_free_list_spinlock, tx_free_flags);
size = cl->tx_ring_free_size * cl->device->fw_client->props.max_msg_length;
spin_unlock_irqrestore(&cl->tx_free_list_spinlock, tx_free_flags);
return size;
}
EXPORT_SYMBOL(ishtp_cl_get_tx_free_buffer_size);
int ishtp_cl_get_tx_free_rings(struct ishtp_cl *cl)
{
return cl->tx_ring_free_size;
}
EXPORT_SYMBOL(ishtp_cl_get_tx_free_rings);
/** /**
* ishtp_read_list_flush() - Flush read queue * ishtp_read_list_flush() - Flush read queue
* @cl: ishtp client instance * @cl: ishtp client instance
...@@ -90,6 +109,7 @@ static void ishtp_cl_init(struct ishtp_cl *cl, struct ishtp_device *dev) ...@@ -90,6 +109,7 @@ static void ishtp_cl_init(struct ishtp_cl *cl, struct ishtp_device *dev)
cl->rx_ring_size = CL_DEF_RX_RING_SIZE; cl->rx_ring_size = CL_DEF_RX_RING_SIZE;
cl->tx_ring_size = CL_DEF_TX_RING_SIZE; cl->tx_ring_size = CL_DEF_TX_RING_SIZE;
cl->tx_ring_free_size = cl->tx_ring_size;
/* dma */ /* dma */
cl->last_tx_path = CL_TX_PATH_IPC; cl->last_tx_path = CL_TX_PATH_IPC;
...@@ -577,6 +597,8 @@ int ishtp_cl_send(struct ishtp_cl *cl, uint8_t *buf, size_t length) ...@@ -577,6 +597,8 @@ int ishtp_cl_send(struct ishtp_cl *cl, uint8_t *buf, size_t length)
* max ISHTP message size per client * max ISHTP message size per client
*/ */
list_del_init(&cl_msg->list); list_del_init(&cl_msg->list);
--cl->tx_ring_free_size;
spin_unlock_irqrestore(&cl->tx_free_list_spinlock, tx_free_flags); spin_unlock_irqrestore(&cl->tx_free_list_spinlock, tx_free_flags);
memcpy(cl_msg->send_buf.data, buf, length); memcpy(cl_msg->send_buf.data, buf, length);
cl_msg->send_buf.size = length; cl_msg->send_buf.size = length;
...@@ -685,6 +707,7 @@ static void ipc_tx_callback(void *prm) ...@@ -685,6 +707,7 @@ static void ipc_tx_callback(void *prm)
ishtp_write_message(dev, &ishtp_hdr, pmsg); ishtp_write_message(dev, &ishtp_hdr, pmsg);
spin_lock_irqsave(&cl->tx_free_list_spinlock, tx_free_flags); spin_lock_irqsave(&cl->tx_free_list_spinlock, tx_free_flags);
list_add_tail(&cl_msg->list, &cl->tx_free_list.list); list_add_tail(&cl_msg->list, &cl->tx_free_list.list);
++cl->tx_ring_free_size;
spin_unlock_irqrestore(&cl->tx_free_list_spinlock, spin_unlock_irqrestore(&cl->tx_free_list_spinlock,
tx_free_flags); tx_free_flags);
} else { } else {
...@@ -778,6 +801,7 @@ static void ishtp_cl_send_msg_dma(struct ishtp_device *dev, ...@@ -778,6 +801,7 @@ static void ishtp_cl_send_msg_dma(struct ishtp_device *dev,
ishtp_write_message(dev, &hdr, (unsigned char *)&dma_xfer); ishtp_write_message(dev, &hdr, (unsigned char *)&dma_xfer);
spin_lock_irqsave(&cl->tx_free_list_spinlock, tx_free_flags); spin_lock_irqsave(&cl->tx_free_list_spinlock, tx_free_flags);
list_add_tail(&cl_msg->list, &cl->tx_free_list.list); list_add_tail(&cl_msg->list, &cl->tx_free_list.list);
++cl->tx_ring_free_size;
spin_unlock_irqrestore(&cl->tx_free_list_spinlock, tx_free_flags); spin_unlock_irqrestore(&cl->tx_free_list_spinlock, tx_free_flags);
++cl->send_msg_cnt_dma; ++cl->send_msg_cnt_dma;
} }
......
...@@ -84,6 +84,7 @@ struct ishtp_cl { ...@@ -84,6 +84,7 @@ struct ishtp_cl {
/* Client Tx buffers list */ /* Client Tx buffers list */
unsigned int tx_ring_size; unsigned int tx_ring_size;
struct ishtp_cl_tx_ring tx_list, tx_free_list; struct ishtp_cl_tx_ring tx_list, tx_free_list;
int tx_ring_free_size;
spinlock_t tx_list_spinlock; spinlock_t tx_list_spinlock;
spinlock_t tx_free_list_spinlock; spinlock_t tx_free_list_spinlock;
size_t tx_offs; /* Offset in buffer at head of 'tx_list' */ size_t tx_offs; /* Offset in buffer at head of 'tx_list' */
...@@ -137,6 +138,8 @@ int ishtp_cl_alloc_rx_ring(struct ishtp_cl *cl); ...@@ -137,6 +138,8 @@ int ishtp_cl_alloc_rx_ring(struct ishtp_cl *cl);
int ishtp_cl_alloc_tx_ring(struct ishtp_cl *cl); int ishtp_cl_alloc_tx_ring(struct ishtp_cl *cl);
void ishtp_cl_free_rx_ring(struct ishtp_cl *cl); void ishtp_cl_free_rx_ring(struct ishtp_cl *cl);
void ishtp_cl_free_tx_ring(struct ishtp_cl *cl); void ishtp_cl_free_tx_ring(struct ishtp_cl *cl);
int ishtp_cl_get_tx_free_buffer_size(struct ishtp_cl *cl);
int ishtp_cl_get_tx_free_rings(struct ishtp_cl *cl);
/* DMA I/F functions */ /* DMA I/F functions */
void recv_ishtp_cl_msg_dma(struct ishtp_device *dev, void *msg, void recv_ishtp_cl_msg_dma(struct ishtp_device *dev, void *msg,
...@@ -178,5 +181,7 @@ int ishtp_cl_flush_queues(struct ishtp_cl *cl); ...@@ -178,5 +181,7 @@ int ishtp_cl_flush_queues(struct ishtp_cl *cl);
/* exported functions from ISHTP client buffer management scope */ /* exported functions from ISHTP client buffer management scope */
int ishtp_cl_io_rb_recycle(struct ishtp_cl_rb *rb); int ishtp_cl_io_rb_recycle(struct ishtp_cl_rb *rb);
bool ishtp_cl_tx_empty(struct ishtp_cl *cl);
struct ishtp_cl_rb *ishtp_cl_rx_get_rb(struct ishtp_cl *cl);
#endif /* _ISHTP_CLIENT_H_ */ #endif /* _ISHTP_CLIENT_H_ */
...@@ -207,7 +207,7 @@ struct ishtp_device { ...@@ -207,7 +207,7 @@ struct ishtp_device {
struct work_struct bh_hbm_work; struct work_struct bh_hbm_work;
/* IPC write queue */ /* IPC write queue */
struct wr_msg_ctl_info wr_processing_list_head, wr_free_list_head; struct list_head wr_processing_list, wr_free_list;
/* For both processing list and free list */ /* For both processing list and free list */
spinlock_t wr_processing_spinlock; spinlock_t wr_processing_spinlock;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment