Char/Misc driver patches for 3.18-rc1

Here's the big set of driver patches for char/misc drivers.  Nothing
 major in here, the shortlog below goes into the details.  All have been
 in the linux-next tree for a while with no issues.
 
 Signed-off-by: Greg Kroah-Hartman <[email protected]>
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2
 
 iEYEABECAAYFAlQ0ZXYACgkQMUfUDdst+ymiEgCgrKcYUluvdrbjdkhrENk332YN
 lcUAoMzgQpbkYhswrDNQet7NtAbFN9LV
 =ZPDy
 -----END PGP SIGNATURE-----

Merge tag 'char-misc-3.18-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 set of driver patches for char/misc drivers.  Nothing
  major in here, the shortlog goes into the details.  All have been in
  the linux-next tree for a while with no issues"

* tag 'char-misc-3.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (80 commits)
  mei: mei_txe_fw_sts can be static
  mei: fix kernel-doc warnings
  mei: fix KDoc documentation formatting
  mei: drop me_client_presentation_num
  mei: trivial: fix errors in prints in comments
  mei: remove include to pci header from mei module files
  mei: push pci cfg structure me hw
  mei: remove the reference to pdev from mei_device
  mei: move fw_status back to hw ops handlers
  mei: get rid of most of the pci dependencies in mei
  mei: push all standard settings into mei_device_init
  mei: move mei_hbm_hdr function from hbm.h the hbm.c
  mei: kill error message for allocation failure
  mei: nfc: fix style warning
  mei: fix style warning: Missing a blank line after declarations
  mei: pg: fix cat and paste error in comments
  mei: debugfs: add single buffer indicator
  mei: debugfs: adjust print buffer
  mei: add hbm and pg state in devstate debugfs print
  Drivers: hv: vmbus: Enable interrupt driven flow control
  ...
This commit is contained in:
Linus Torvalds 2014-10-08 06:55:41 -04:00
commit ef0625b70d
63 changed files with 2794 additions and 1345 deletions

View file

@ -18,7 +18,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
@ -159,12 +159,11 @@ static int eeprom_probe(struct i2c_client *client,
{
struct i2c_adapter *adapter = client->adapter;
struct eeprom_data *data;
int err;
if (!(data = kzalloc(sizeof(struct eeprom_data), GFP_KERNEL))) {
err = -ENOMEM;
goto exit;
}
data = devm_kzalloc(&client->dev, sizeof(struct eeprom_data),
GFP_KERNEL);
if (!data)
return -ENOMEM;
memset(data->data, 0xff, EEPROM_SIZE);
i2c_set_clientdata(client, data);
@ -190,22 +189,12 @@ static int eeprom_probe(struct i2c_client *client,
}
/* create the sysfs eeprom file */
err = sysfs_create_bin_file(&client->dev.kobj, &eeprom_attr);
if (err)
goto exit_kfree;
return 0;
exit_kfree:
kfree(data);
exit:
return err;
return sysfs_create_bin_file(&client->dev.kobj, &eeprom_attr);
}
static int eeprom_remove(struct i2c_client *client)
{
sysfs_remove_bin_file(&client->dev.kobj, &eeprom_attr);
kfree(i2c_get_clientdata(client));
return 0;
}

View file

@ -5,7 +5,7 @@
*
* Author: Frank Haverkamp <haver@linux.vnet.ibm.com>
* Author: Joerg-Stephan Vogt <jsvogt@de.ibm.com>
* Author: Michael Jung <mijung@de.ibm.com>
* Author: Michael Jung <mijung@gmx.net>
* Author: Michael Ruettger <michael@ibmra.de>
*
* This program is free software; you can redistribute it and/or modify
@ -45,10 +45,10 @@
MODULE_AUTHOR("Frank Haverkamp <[email protected]>");
MODULE_AUTHOR("Michael Ruettger <[email protected]>");
MODULE_AUTHOR("Joerg-Stephan Vogt <[email protected]>");
MODULE_AUTHOR("Michal Jung <[email protected]>");
MODULE_AUTHOR("Michael Jung <[email protected]>");
MODULE_DESCRIPTION("GenWQE Card");
MODULE_VERSION(DRV_VERS_STRING);
MODULE_VERSION(DRV_VERSION);
MODULE_LICENSE("GPL");
static char genwqe_driver_name[] = GENWQE_DEVNAME;
@ -346,8 +346,13 @@ static bool genwqe_setup_vf_jtimer(struct genwqe_dev *cd)
unsigned int vf;
u32 T = genwqe_T_psec(cd);
u64 x;
int totalvfs;
for (vf = 0; vf < pci_sriov_get_totalvfs(pci_dev); vf++) {
totalvfs = pci_sriov_get_totalvfs(pci_dev);
if (totalvfs <= 0)
return false;
for (vf = 0; vf < totalvfs; vf++) {
if (cd->vf_jobtimeout_msec[vf] == 0)
continue;
@ -383,8 +388,9 @@ static int genwqe_ffdc_buffs_alloc(struct genwqe_dev *cd)
/* currently support only the debug units mentioned here */
cd->ffdc[type].entries = e;
cd->ffdc[type].regs = kmalloc(e * sizeof(struct genwqe_reg),
GFP_KERNEL);
cd->ffdc[type].regs =
kmalloc_array(e, sizeof(struct genwqe_reg),
GFP_KERNEL);
/*
* regs == NULL is ok, the using code treats this as no regs,
* Printing warning is ok in this case.
@ -723,8 +729,8 @@ static u64 genwqe_fir_checking(struct genwqe_dev *cd)
__genwqe_writeq(cd, sfir_addr, sfir);
dev_dbg(&pci_dev->dev,
"[HM] Clearing 2ndary FIR 0x%08x "
"with 0x%016llx\n", sfir_addr, sfir);
"[HM] Clearing 2ndary FIR 0x%08x with 0x%016llx\n",
sfir_addr, sfir);
/*
* note, these cannot be error-Firs
@ -740,9 +746,8 @@ static u64 genwqe_fir_checking(struct genwqe_dev *cd)
__genwqe_writeq(cd, fir_clr_addr, mask);
dev_dbg(&pci_dev->dev,
"[HM] Clearing primary FIR 0x%08x "
"with 0x%016llx\n", fir_clr_addr,
mask);
"[HM] Clearing primary FIR 0x%08x with 0x%016llx\n",
fir_clr_addr, mask);
}
}
}
@ -1125,6 +1130,8 @@ static int genwqe_pci_setup(struct genwqe_dev *cd)
}
cd->num_vfs = pci_sriov_get_totalvfs(pci_dev);
if (cd->num_vfs < 0)
cd->num_vfs = 0;
err = genwqe_read_ids(cd);
if (err)
@ -1202,8 +1209,8 @@ static int genwqe_probe(struct pci_dev *pci_dev,
err = genwqe_health_check_start(cd);
if (err < 0) {
dev_err(&pci_dev->dev,
"err: cannot start health checking! "
"(err=%d)\n", err);
"err: cannot start health checking! (err=%d)\n",
err);
goto out_stop_services;
}
}
@ -1313,11 +1320,14 @@ static void genwqe_err_resume(struct pci_dev *pci_dev)
static int genwqe_sriov_configure(struct pci_dev *dev, int numvfs)
{
int rc;
struct genwqe_dev *cd = dev_get_drvdata(&dev->dev);
if (numvfs > 0) {
genwqe_setup_vf_jtimer(cd);
pci_enable_sriov(dev, numvfs);
rc = pci_enable_sriov(dev, numvfs);
if (rc < 0)
return rc;
return numvfs;
}
if (numvfs == 0) {

View file

@ -8,7 +8,7 @@
*
* Author: Frank Haverkamp <haver@linux.vnet.ibm.com>
* Author: Joerg-Stephan Vogt <jsvogt@de.ibm.com>
* Author: Michael Jung <mijung@de.ibm.com>
* Author: Michael Jung <mijung@gmx.net>
* Author: Michael Ruettger <michael@ibmra.de>
*
* This program is free software; you can redistribute it and/or modify
@ -201,7 +201,8 @@ static inline void genwqe_mapping_init(struct dma_mapping *m,
* @ddcb_seq: Sequence number of last DDCB
* @ddcbs_in_flight: Currently enqueued DDCBs
* @ddcbs_completed: Number of already completed DDCBs
* @busy: Number of -EBUSY returns
* @return_on_busy: Number of -EBUSY returns on full queue
* @wait_on_busy: Number of waits on full queue
* @ddcb_daddr: DMA address of first DDCB in the queue
* @ddcb_vaddr: Kernel virtual address of first DDCB in the queue
* @ddcb_req: Associated requests (one per DDCB)
@ -218,7 +219,8 @@ struct ddcb_queue {
unsigned int ddcbs_in_flight; /* number of ddcbs in processing */
unsigned int ddcbs_completed;
unsigned int ddcbs_max_in_flight;
unsigned int busy; /* how many times -EBUSY? */
unsigned int return_on_busy; /* how many times -EBUSY? */
unsigned int wait_on_busy;
dma_addr_t ddcb_daddr; /* DMA address */
struct ddcb *ddcb_vaddr; /* kernel virtual addr for DDCBs */
@ -226,7 +228,7 @@ struct ddcb_queue {
wait_queue_head_t *ddcb_waitqs; /* waitqueue per ddcb */
spinlock_t ddcb_lock; /* exclusive access to queue */
wait_queue_head_t ddcb_waitq; /* wait for ddcb processing */
wait_queue_head_t busy_waitq; /* wait for ddcb processing */
/* registers or the respective queue to be used */
u32 IO_QUEUE_CONFIG;
@ -306,7 +308,7 @@ struct genwqe_dev {
struct pci_dev *pci_dev; /* PCI device */
void __iomem *mmio; /* BAR-0 MMIO start */
unsigned long mmio_len;
u16 num_vfs;
int num_vfs;
u32 vf_jobtimeout_msec[GENWQE_MAX_VFS];
int is_privileged; /* access to all regs possible */
@ -508,7 +510,7 @@ static inline bool dma_mapping_used(struct dma_mapping *m)
* buildup and teardown.
*/
int __genwqe_execute_ddcb(struct genwqe_dev *cd,
struct genwqe_ddcb_cmd *cmd);
struct genwqe_ddcb_cmd *cmd, unsigned int f_flags);
/**
* __genwqe_execute_raw_ddcb() - Execute DDCB request without addr translation
@ -520,9 +522,12 @@ int __genwqe_execute_ddcb(struct genwqe_dev *cd,
* modification.
*/
int __genwqe_execute_raw_ddcb(struct genwqe_dev *cd,
struct genwqe_ddcb_cmd *cmd);
struct genwqe_ddcb_cmd *cmd,
unsigned int f_flags);
int __genwqe_enqueue_ddcb(struct genwqe_dev *cd,
struct ddcb_requ *req,
unsigned int f_flags);
int __genwqe_enqueue_ddcb(struct genwqe_dev *cd, struct ddcb_requ *req);
int __genwqe_wait_ddcb(struct genwqe_dev *cd, struct ddcb_requ *req);
int __genwqe_purge_ddcb(struct genwqe_dev *cd, struct ddcb_requ *req);

View file

@ -5,7 +5,7 @@
*
* Author: Frank Haverkamp <haver@linux.vnet.ibm.com>
* Author: Joerg-Stephan Vogt <jsvogt@de.ibm.com>
* Author: Michael Jung <mijung@de.ibm.com>
* Author: Michael Jung <mijung@gmx.net>
* Author: Michael Ruettger <michael@ibmra.de>
*
* This program is free software; you can redistribute it and/or modify
@ -185,8 +185,7 @@ static void print_ddcb_info(struct genwqe_dev *cd, struct ddcb_queue *queue)
pddcb = queue->ddcb_vaddr;
for (i = 0; i < queue->ddcb_max; i++) {
dev_err(&pci_dev->dev,
" %c %-3d: RETC=%03x SEQ=%04x "
"HSI=%02X SHI=%02x PRIV=%06llx CMD=%03x\n",
" %c %-3d: RETC=%03x SEQ=%04x HSI=%02X SHI=%02x PRIV=%06llx CMD=%03x\n",
i == queue->ddcb_act ? '>' : ' ',
i,
be16_to_cpu(pddcb->retc_16),
@ -214,6 +213,7 @@ struct genwqe_ddcb_cmd *ddcb_requ_alloc(void)
void ddcb_requ_free(struct genwqe_ddcb_cmd *cmd)
{
struct ddcb_requ *req = container_of(cmd, struct ddcb_requ, cmd);
kfree(req);
}
@ -306,7 +306,7 @@ static int enqueue_ddcb(struct genwqe_dev *cd, struct ddcb_queue *queue,
new = (old | DDCB_NEXT_BE32);
wmb();
wmb(); /* need to ensure write ordering */
icrc_hsi_shi = cmpxchg(&prev_ddcb->icrc_hsi_shi_32, old, new);
if (icrc_hsi_shi == old)
@ -317,7 +317,7 @@ static int enqueue_ddcb(struct genwqe_dev *cd, struct ddcb_queue *queue,
ddcb_mark_tapped(pddcb);
num = (u64)ddcb_no << 8;
wmb();
wmb(); /* need to ensure write ordering */
__genwqe_writeq(cd, queue->IO_QUEUE_OFFSET, num); /* start queue */
return RET_DDCB_TAPPED;
@ -390,8 +390,9 @@ static int genwqe_check_ddcb_queue(struct genwqe_dev *cd,
0x00000000)
goto go_home; /* not completed, continue waiting */
/* Note: DDCB could be purged */
wmb(); /* Add sync to decouple prev. read operations */
/* Note: DDCB could be purged */
req = queue->ddcb_req[queue->ddcb_act];
if (req == NULL) {
/* this occurs if DDCB is purged, not an error */
@ -416,9 +417,7 @@ static int genwqe_check_ddcb_queue(struct genwqe_dev *cd,
status = __genwqe_readq(cd, queue->IO_QUEUE_STATUS);
dev_err(&pci_dev->dev,
"[%s] SEQN=%04x HSI=%02x RETC=%03x "
" Q_ERRCNTS=%016llx Q_STATUS=%016llx\n"
" DDCB_DMA_ADDR=%016llx\n",
"[%s] SEQN=%04x HSI=%02x RETC=%03x Q_ERRCNTS=%016llx Q_STATUS=%016llx DDCB_DMA_ADDR=%016llx\n",
__func__, be16_to_cpu(pddcb->seqnum_16),
pddcb->hsi, retc_16, errcnts, status,
queue->ddcb_daddr + ddcb_offs);
@ -439,8 +438,7 @@ static int genwqe_check_ddcb_queue(struct genwqe_dev *cd,
vcrc_16 = be16_to_cpu(pddcb->vcrc_16);
if (vcrc != vcrc_16) {
printk_ratelimited(KERN_ERR
"%s %s: err: wrong VCRC pre=%02x vcrc_len=%d "
"bytes vcrc_data=%04x is not vcrc_card=%04x\n",
"%s %s: err: wrong VCRC pre=%02x vcrc_len=%d bytes vcrc_data=%04x is not vcrc_card=%04x\n",
GENWQE_DEVNAME, dev_name(&pci_dev->dev),
pddcb->pre, VCRC_LENGTH(req->cmd.asv_length),
vcrc, vcrc_16);
@ -450,8 +448,10 @@ static int genwqe_check_ddcb_queue(struct genwqe_dev *cd,
queue->ddcbs_completed++;
queue->ddcbs_in_flight--;
/* wake up process waiting for this DDCB */
/* wake up process waiting for this DDCB, and
processes on the busy queue */
wake_up_interruptible(&queue->ddcb_waitqs[queue->ddcb_act]);
wake_up_interruptible(&queue->busy_waitq);
pick_next_one:
queue->ddcb_act = (queue->ddcb_act + 1) % queue->ddcb_max;
@ -717,8 +717,7 @@ go_home:
genwqe_hexdump(pci_dev, pddcb, sizeof(*pddcb));
dev_err(&pci_dev->dev,
"[%s] err: DDCB#%d not purged and not completed "
"after %d seconds QSTAT=%016llx!!\n",
"[%s] err: DDCB#%d not purged and not completed after %d seconds QSTAT=%016llx!!\n",
__func__, req->num, genwqe_ddcb_software_timeout,
queue_status);
@ -740,7 +739,7 @@ int genwqe_init_debug_data(struct genwqe_dev *cd, struct genwqe_debug_data *d)
}
len = sizeof(d->driver_version);
snprintf(d->driver_version, len, "%s", DRV_VERS_STRING);
snprintf(d->driver_version, len, "%s", DRV_VERSION);
d->slu_unitcfg = cd->slu_unitcfg;
d->app_unitcfg = cd->app_unitcfg;
return 0;
@ -748,14 +747,16 @@ int genwqe_init_debug_data(struct genwqe_dev *cd, struct genwqe_debug_data *d)
/**
* __genwqe_enqueue_ddcb() - Enqueue a DDCB
* @cd: pointer to genwqe device descriptor
* @req: pointer to DDCB execution request
* @cd: pointer to genwqe device descriptor
* @req: pointer to DDCB execution request
* @f_flags: file mode: blocking, non-blocking
*
* Return: 0 if enqueuing succeeded
* -EIO if card is unusable/PCIe problems
* -EBUSY if enqueuing failed
*/
int __genwqe_enqueue_ddcb(struct genwqe_dev *cd, struct ddcb_requ *req)
int __genwqe_enqueue_ddcb(struct genwqe_dev *cd, struct ddcb_requ *req,
unsigned int f_flags)
{
struct ddcb *pddcb;
unsigned long flags;
@ -763,6 +764,7 @@ int __genwqe_enqueue_ddcb(struct genwqe_dev *cd, struct ddcb_requ *req)
struct pci_dev *pci_dev = cd->pci_dev;
u16 icrc;
retry:
if (cd->card_state != GENWQE_CARD_USED) {
printk_ratelimited(KERN_ERR
"%s %s: [%s] Card is unusable/PCIe problem Req#%d\n",
@ -788,9 +790,24 @@ int __genwqe_enqueue_ddcb(struct genwqe_dev *cd, struct ddcb_requ *req)
pddcb = get_next_ddcb(cd, queue, &req->num); /* get ptr and num */
if (pddcb == NULL) {
int rc;
spin_unlock_irqrestore(&queue->ddcb_lock, flags);
queue->busy++;
return -EBUSY;
if (f_flags & O_NONBLOCK) {
queue->return_on_busy++;
return -EBUSY;
}
queue->wait_on_busy++;
rc = wait_event_interruptible(queue->busy_waitq,
queue_free_ddcbs(queue) != 0);
dev_dbg(&pci_dev->dev, "[%s] waiting for free DDCB: rc=%d\n",
__func__, rc);
if (rc == -ERESTARTSYS)
return rc; /* interrupted by a signal */
goto retry;
}
if (queue->ddcb_req[req->num] != NULL) {
@ -893,9 +910,11 @@ int __genwqe_enqueue_ddcb(struct genwqe_dev *cd, struct ddcb_requ *req)
* __genwqe_execute_raw_ddcb() - Setup and execute DDCB
* @cd: pointer to genwqe device descriptor
* @req: user provided DDCB request
* @f_flags: file mode: blocking, non-blocking
*/
int __genwqe_execute_raw_ddcb(struct genwqe_dev *cd,
struct genwqe_ddcb_cmd *cmd)
struct genwqe_ddcb_cmd *cmd,
unsigned int f_flags)
{
int rc = 0;
struct pci_dev *pci_dev = cd->pci_dev;
@ -911,7 +930,7 @@ int __genwqe_execute_raw_ddcb(struct genwqe_dev *cd,
__func__, cmd->asiv_length);
return -EINVAL;
}
rc = __genwqe_enqueue_ddcb(cd, req);
rc = __genwqe_enqueue_ddcb(cd, req, f_flags);
if (rc != 0)
return rc;
@ -1017,7 +1036,8 @@ static int setup_ddcb_queue(struct genwqe_dev *cd, struct ddcb_queue *queue)
queue->ddcbs_in_flight = 0; /* statistics */
queue->ddcbs_max_in_flight = 0;
queue->ddcbs_completed = 0;
queue->busy = 0;
queue->return_on_busy = 0;
queue->wait_on_busy = 0;
queue->ddcb_seq = 0x100; /* start sequence number */
queue->ddcb_max = genwqe_ddcb_max; /* module parameter */
@ -1057,7 +1077,7 @@ static int setup_ddcb_queue(struct genwqe_dev *cd, struct ddcb_queue *queue)
queue->ddcb_next = 0; /* queue is empty */
spin_lock_init(&queue->ddcb_lock);
init_waitqueue_head(&queue->ddcb_waitq);
init_waitqueue_head(&queue->busy_waitq);
val64 = ((u64)(queue->ddcb_max - 1) << 8); /* lastptr */
__genwqe_writeq(cd, queue->IO_QUEUE_CONFIG, 0x07); /* iCRC/vCRC */
@ -1251,10 +1271,8 @@ int genwqe_setup_service_layer(struct genwqe_dev *cd)
}
rc = genwqe_set_interrupt_capability(cd, GENWQE_MSI_IRQS);
if (rc) {
rc = -ENODEV;
if (rc)
goto stop_kthread;
}
/*
* We must have all wait-queues initialized when we enable the
@ -1307,6 +1325,7 @@ static int queue_wake_up_all(struct genwqe_dev *cd)
for (i = 0; i < queue->ddcb_max; i++)
wake_up_interruptible(&queue->ddcb_waitqs[queue->ddcb_act]);
wake_up_interruptible(&queue->busy_waitq);
spin_unlock_irqrestore(&queue->ddcb_lock, flags);
return 0;
@ -1346,8 +1365,8 @@ int genwqe_finish_queue(struct genwqe_dev *cd)
break;
dev_dbg(&pci_dev->dev,
" DEBUG [%d/%d] waiting for queue to get empty: "
"%d requests!\n", i, waitmax, in_flight);
" DEBUG [%d/%d] waiting for queue to get empty: %d requests!\n",
i, waitmax, in_flight);
/*
* Severe severe error situation: The card itself has

View file

@ -8,7 +8,7 @@
*
* Author: Frank Haverkamp <haver@linux.vnet.ibm.com>
* Author: Joerg-Stephan Vogt <jsvogt@de.ibm.com>
* Author: Michael Jung <mijung@de.ibm.com>
* Author: Michael Jung <mijung@gmx.net>
* Author: Michael Ruettger <michael@ibmra.de>
*
* This program is free software; you can redistribute it and/or modify

View file

@ -5,7 +5,7 @@
*
* Author: Frank Haverkamp <haver@linux.vnet.ibm.com>
* Author: Joerg-Stephan Vogt <jsvogt@de.ibm.com>
* Author: Michael Jung <mijung@de.ibm.com>
* Author: Michael Jung <mijung@gmx.net>
* Author: Michael Ruettger <michael@ibmra.de>
*
* This program is free software; you can redistribute it and/or modify
@ -244,14 +244,16 @@ static int genwqe_ddcb_info_show(struct seq_file *s, void *unused)
" ddcbs_in_flight: %u\n"
" ddcbs_max_in_flight: %u\n"
" ddcbs_completed: %u\n"
" busy: %u\n"
" return_on_busy: %u\n"
" wait_on_busy: %u\n"
" irqs_processed: %u\n",
queue->ddcb_max, (long long)queue->ddcb_daddr,
(long long)queue->ddcb_daddr +
(queue->ddcb_max * DDCB_LENGTH),
(long long)queue->ddcb_vaddr, queue->ddcbs_in_flight,
queue->ddcbs_max_in_flight, queue->ddcbs_completed,
queue->busy, cd->irqs_processed);
queue->return_on_busy, queue->wait_on_busy,
cd->irqs_processed);
/* Hardware State */
seq_printf(s, " 0x%08x 0x%016llx IO_QUEUE_CONFIG\n"
@ -323,7 +325,7 @@ static int genwqe_info_show(struct seq_file *s, void *unused)
" Base Clock : %u MHz\n"
" Arch/SVN Release: %u/%llx\n"
" Bitstream : %llx\n",
GENWQE_DEVNAME, DRV_VERS_STRING, dev_name(&pci_dev->dev),
GENWQE_DEVNAME, DRV_VERSION, dev_name(&pci_dev->dev),
genwqe_is_privileged(cd) ?
"Physical" : "Virtual or no SR-IOV",
cd->card_idx, slu_id, app_id,

View file

@ -5,7 +5,7 @@
*
* Author: Frank Haverkamp <haver@linux.vnet.ibm.com>
* Author: Joerg-Stephan Vogt <jsvogt@de.ibm.com>
* Author: Michael Jung <mijung@de.ibm.com>
* Author: Michael Jung <mijung@gmx.net>
* Author: Michael Ruettger <michael@ibmra.de>
*
* This program is free software; you can redistribute it and/or modify
@ -213,9 +213,9 @@ static void genwqe_remove_mappings(struct genwqe_file *cfile)
* GENWQE_MAPPING_SGL_TEMP should be removed by tidy up code.
*/
dev_err(&pci_dev->dev,
"[%s] %d. cleanup mapping: u_vaddr=%p "
"u_kaddr=%016lx dma_addr=%lx\n", __func__, i++,
dma_map->u_vaddr, (unsigned long)dma_map->k_vaddr,
"[%s] %d. cleanup mapping: u_vaddr=%p u_kaddr=%016lx dma_addr=%lx\n",
__func__, i++, dma_map->u_vaddr,
(unsigned long)dma_map->k_vaddr,
(unsigned long)dma_map->dma_addr);
if (dma_map->type == GENWQE_MAPPING_RAW) {
@ -346,6 +346,7 @@ static int genwqe_open(struct inode *inode, struct file *filp)
static int genwqe_fasync(int fd, struct file *filp, int mode)
{
struct genwqe_file *cdev = (struct genwqe_file *)filp->private_data;
return fasync_helper(fd, filp, mode, &cdev->async_queue);
}
@ -515,6 +516,7 @@ static int do_flash_update(struct genwqe_file *cfile,
u32 crc;
u8 cmdopts;
struct genwqe_dev *cd = cfile->cd;
struct file *filp = cfile->filp;
struct pci_dev *pci_dev = cd->pci_dev;
if ((load->size & 0x3) != 0)
@ -609,7 +611,7 @@ static int do_flash_update(struct genwqe_file *cfile,
/* For Genwqe5 we get back the calculated CRC */
*(u64 *)&req->asv[0] = 0ULL; /* 0x80 */
rc = __genwqe_execute_raw_ddcb(cd, req);
rc = __genwqe_execute_raw_ddcb(cd, req, filp->f_flags);
load->retc = req->retc;
load->attn = req->attn;
@ -649,6 +651,7 @@ static int do_flash_read(struct genwqe_file *cfile,
u8 *xbuf;
u8 cmdopts;
struct genwqe_dev *cd = cfile->cd;
struct file *filp = cfile->filp;
struct pci_dev *pci_dev = cd->pci_dev;
struct genwqe_ddcb_cmd *cmd;
@ -726,7 +729,7 @@ static int do_flash_read(struct genwqe_file *cfile,
/* we only get back the calculated CRC */
*(u64 *)&cmd->asv[0] = 0ULL; /* 0x80 */
rc = __genwqe_execute_raw_ddcb(cd, cmd);
rc = __genwqe_execute_raw_ddcb(cd, cmd, filp->f_flags);
load->retc = cmd->retc;
load->attn = cmd->attn;
@ -987,13 +990,14 @@ static int genwqe_execute_ddcb(struct genwqe_file *cfile,
{
int rc;
struct genwqe_dev *cd = cfile->cd;
struct file *filp = cfile->filp;
struct ddcb_requ *req = container_of(cmd, struct ddcb_requ, cmd);
rc = ddcb_cmd_fixups(cfile, req);
if (rc != 0)
return rc;
rc = __genwqe_execute_raw_ddcb(cd, cmd);
rc = __genwqe_execute_raw_ddcb(cd, cmd, filp->f_flags);
ddcb_cmd_cleanup(cfile, req);
return rc;
}
@ -1005,6 +1009,7 @@ static int do_execute_ddcb(struct genwqe_file *cfile,
struct genwqe_ddcb_cmd *cmd;
struct ddcb_requ *req;
struct genwqe_dev *cd = cfile->cd;
struct file *filp = cfile->filp;
cmd = ddcb_requ_alloc();
if (cmd == NULL)
@ -1020,7 +1025,7 @@ static int do_execute_ddcb(struct genwqe_file *cfile,
if (!raw)
rc = genwqe_execute_ddcb(cfile, cmd);
else
rc = __genwqe_execute_raw_ddcb(cd, cmd);
rc = __genwqe_execute_raw_ddcb(cd, cmd, filp->f_flags);
/* Copy back only the modifed fields. Do not copy ASIV
back since the copy got modified by the driver. */

View file

@ -5,7 +5,7 @@
*
* Author: Frank Haverkamp <haver@linux.vnet.ibm.com>
* Author: Joerg-Stephan Vogt <jsvogt@de.ibm.com>
* Author: Michael Jung <mijung@de.ibm.com>
* Author: Michael Jung <mijung@gmx.net>
* Author: Michael Ruettger <michael@ibmra.de>
*
* This program is free software; you can redistribute it and/or modify
@ -91,13 +91,6 @@ static ssize_t type_show(struct device *dev, struct device_attribute *attr,
}
static DEVICE_ATTR_RO(type);
static ssize_t driver_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
return sprintf(buf, "%s\n", DRV_VERS_STRING);
}
static DEVICE_ATTR_RO(driver);
static ssize_t tempsens_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
@ -256,7 +249,6 @@ static struct attribute *genwqe_attributes[] = {
&dev_attr_next_bitstream.attr,
&dev_attr_curr_bitstream.attr,
&dev_attr_base_clock.attr,
&dev_attr_driver.attr,
&dev_attr_type.attr,
&dev_attr_version.attr,
&dev_attr_appid.attr,
@ -268,7 +260,6 @@ static struct attribute *genwqe_attributes[] = {
};
static struct attribute *genwqe_normal_attributes[] = {
&dev_attr_driver.attr,
&dev_attr_type.attr,
&dev_attr_version.attr,
&dev_attr_appid.attr,

View file

@ -5,7 +5,7 @@
*
* Author: Frank Haverkamp <haver@linux.vnet.ibm.com>
* Author: Joerg-Stephan Vogt <jsvogt@de.ibm.com>
* Author: Michael Jung <mijung@de.ibm.com>
* Author: Michael Jung <mijung@gmx.net>
* Author: Michael Ruettger <michael@ibmra.de>
*
* This program is free software; you can redistribute it and/or modify
@ -150,6 +150,7 @@ int genwqe_read_app_id(struct genwqe_dev *cd, char *app_name, int len)
memset(app_name, 0, len);
for (i = 0, j = 0; j < min(len, 4); j++) {
char ch = (char)((app_id >> (24 - j*8)) & 0xff);
if (ch == ' ')
continue;
app_name[i++] = isprint(ch) ? ch : 'X';
@ -304,8 +305,7 @@ int genwqe_alloc_sync_sgl(struct genwqe_dev *cd, struct genwqe_sgl *sgl,
sgl->nr_pages = DIV_ROUND_UP(sgl->fpage_offs + user_size, PAGE_SIZE);
sgl->lpage_size = (user_size - sgl->fpage_size) % PAGE_SIZE;
dev_dbg(&pci_dev->dev, "[%s] uaddr=%p usize=%8ld nr_pages=%ld "
"fpage_offs=%lx fpage_size=%ld lpage_size=%ld\n",
dev_dbg(&pci_dev->dev, "[%s] uaddr=%p usize=%8ld nr_pages=%ld fpage_offs=%lx fpage_size=%ld lpage_size=%ld\n",
__func__, user_addr, user_size, sgl->nr_pages,
sgl->fpage_offs, sgl->fpage_size, sgl->lpage_size);
@ -662,6 +662,7 @@ int genwqe_user_vunmap(struct genwqe_dev *cd, struct dma_mapping *m,
u8 genwqe_card_type(struct genwqe_dev *cd)
{
u64 card_type = cd->slu_unitcfg;
return (u8)((card_type & IO_SLU_UNITCFG_TYPE_MASK) >> 20);
}

View file

@ -8,7 +8,7 @@
*
* Author: Frank Haverkamp <haver@linux.vnet.ibm.com>
* Author: Joerg-Stephan Vogt <jsvogt@de.ibm.com>
* Author: Michael Jung <mijung@de.ibm.com>
* Author: Michael Jung <mijung@gmx.net>
* Author: Michael Ruettger <michael@ibmra.de>
*
* This program is free software; you can redistribute it and/or modify
@ -36,7 +36,7 @@
#include <asm/byteorder.h>
#include <linux/genwqe/genwqe_card.h>
#define DRV_VERS_STRING "2.0.21"
#define DRV_VERSION "2.0.25"
/*
* Static minor number assignement, until we decide/implement

View file

@ -247,3 +247,4 @@ module_spi_driver(lattice_ecp3_driver);
MODULE_AUTHOR("Stefan Roese <[email protected]>");
MODULE_DESCRIPTION("Lattice ECP3 FPGA configuration via SPI");
MODULE_LICENSE("GPL");
MODULE_FIRMWARE(FIRMWARE_NAME);

View file

@ -20,7 +20,6 @@
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/aio.h>
#include <linux/pci.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>
#include <linux/list.h>
@ -29,6 +28,7 @@
#include <linux/uuid.h>
#include <linux/jiffies.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/mei.h>
@ -64,31 +64,32 @@ void mei_amthif_reset_params(struct mei_device *dev)
*
* @dev: the device structure
*
* Return: 0 on success, <0 on failure.
*/
int mei_amthif_host_init(struct mei_device *dev)
{
struct mei_cl *cl = &dev->iamthif_cl;
struct mei_me_client *me_cl;
unsigned char *msg_buf;
int ret, i;
int ret;
dev->iamthif_state = MEI_IAMTHIF_IDLE;
mei_cl_init(cl, dev);
i = mei_me_cl_by_uuid(dev, &mei_amthif_guid);
if (i < 0) {
dev_info(&dev->pdev->dev,
"amthif: failed to find the client %d\n", i);
me_cl = mei_me_cl_by_uuid(dev, &mei_amthif_guid);
if (!me_cl) {
dev_info(dev->dev, "amthif: failed to find the client");
return -ENOTTY;
}
cl->me_client_id = dev->me_clients[i].client_id;
cl->me_client_id = me_cl->client_id;
cl->cl_uuid = me_cl->props.protocol_name;
/* Assign iamthif_mtu to the value received from ME */
dev->iamthif_mtu = dev->me_clients[i].props.max_msg_length;
dev_dbg(&dev->pdev->dev, "IAMTHIF_MTU = %d\n",
dev->me_clients[i].props.max_msg_length);
dev->iamthif_mtu = me_cl->props.max_msg_length;
dev_dbg(dev->dev, "IAMTHIF_MTU = %d\n", dev->iamthif_mtu);
kfree(dev->iamthif_msg_buf);
dev->iamthif_msg_buf = NULL;
@ -96,17 +97,15 @@ int mei_amthif_host_init(struct mei_device *dev)
/* allocate storage for ME message buffer */
msg_buf = kcalloc(dev->iamthif_mtu,
sizeof(unsigned char), GFP_KERNEL);
if (!msg_buf) {
dev_err(&dev->pdev->dev, "amthif: memory allocation for ME message buffer failed.\n");
if (!msg_buf)
return -ENOMEM;
}
dev->iamthif_msg_buf = msg_buf;
ret = mei_cl_link(cl, MEI_IAMTHIF_HOST_CLIENT_ID);
if (ret < 0) {
dev_err(&dev->pdev->dev,
dev_err(dev->dev,
"amthif: failed link client %d\n", ret);
return ret;
}
@ -124,18 +123,16 @@ int mei_amthif_host_init(struct mei_device *dev)
* @dev: the device structure
* @file: pointer to file object
*
* returns returned a list entry on success, NULL on failure.
* Return: returned a list entry on success, NULL on failure.
*/
struct mei_cl_cb *mei_amthif_find_read_list_entry(struct mei_device *dev,
struct file *file)
{
struct mei_cl_cb *cb;
list_for_each_entry(cb, &dev->amthif_rd_complete_list.list, list) {
if (cb->cl && cb->cl == &dev->iamthif_cl &&
cb->file_object == file)
list_for_each_entry(cb, &dev->amthif_rd_complete_list.list, list)
if (cb->file_object == file)
return cb;
}
return NULL;
}
@ -144,15 +141,14 @@ struct mei_cl_cb *mei_amthif_find_read_list_entry(struct mei_device *dev,
* mei_amthif_read - read data from AMTHIF client
*
* @dev: the device structure
* @if_num: minor number
* @file: pointer to file object
* @*ubuf: pointer to user data in user space
* @ubuf: pointer to user data in user space
* @length: data length to read
* @offset: data read offset
*
* Locking: called under "dev->device_lock" lock
*
* returns
* Return:
* returned data length on success,
* zero if no data to read,
* negative on failure.
@ -160,25 +156,19 @@ struct mei_cl_cb *mei_amthif_find_read_list_entry(struct mei_device *dev,
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;
unsigned long timeout;
int rets;
int wait_ret;
struct mei_cl_cb *cb = NULL;
struct mei_cl *cl = file->private_data;
unsigned long timeout;
int i;
/* Only possible if we are in timeout */
if (!cl || cl != &dev->iamthif_cl) {
dev_dbg(&dev->pdev->dev, "bad file ext.\n");
if (!cl) {
dev_err(dev->dev, "bad file ext.\n");
return -ETIME;
}
i = mei_me_cl_by_id(dev, dev->iamthif_cl.me_client_id);
if (i < 0) {
dev_dbg(&dev->pdev->dev, "amthif client not found.\n");
return -ENOTTY;
}
dev_dbg(&dev->pdev->dev, "checking amthif data\n");
dev_dbg(dev->dev, "checking amthif data\n");
cb = mei_amthif_find_read_list_entry(dev, file);
/* Check for if we can block or not*/
@ -186,7 +176,7 @@ int mei_amthif_read(struct mei_device *dev, struct file *file,
return -EAGAIN;
dev_dbg(&dev->pdev->dev, "waiting for amthif data\n");
dev_dbg(dev->dev, "waiting for amthif data\n");
while (cb == NULL) {
/* unlock the Mutex */
mutex_unlock(&dev->device_lock);
@ -200,21 +190,21 @@ int mei_amthif_read(struct mei_device *dev, struct file *file,
if (wait_ret)
return -ERESTARTSYS;
dev_dbg(&dev->pdev->dev, "woke up from sleep\n");
dev_dbg(dev->dev, "woke up from sleep\n");
}
dev_dbg(&dev->pdev->dev, "Got amthif data\n");
dev_dbg(dev->dev, "Got amthif data\n");
dev->iamthif_timer = 0;
if (cb) {
timeout = cb->read_time +
mei_secs_to_jiffies(MEI_IAMTHIF_READ_TIMER);
dev_dbg(&dev->pdev->dev, "amthif timeout = %lud\n",
dev_dbg(dev->dev, "amthif timeout = %lud\n",
timeout);
if (time_after(jiffies, timeout)) {
dev_dbg(&dev->pdev->dev, "amthif Time out\n");
dev_dbg(dev->dev, "amthif Time out\n");
/* 15 sec for the message has expired */
list_del(&cb->list);
rets = -ETIME;
@ -234,16 +224,16 @@ int mei_amthif_read(struct mei_device *dev, struct file *file,
* remove message from deletion list
*/
dev_dbg(&dev->pdev->dev, "amthif cb->response_buffer size - %d\n",
dev_dbg(dev->dev, "amthif cb->response_buffer size - %d\n",
cb->response_buffer.size);
dev_dbg(&dev->pdev->dev, "amthif cb->buf_idx - %lu\n", cb->buf_idx);
dev_dbg(dev->dev, "amthif cb->buf_idx - %lu\n", 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->response_buffer.data + *offset, length)) {
dev_dbg(&dev->pdev->dev, "failed to copy data to userland\n");
dev_dbg(dev->dev, "failed to copy data to userland\n");
rets = -EFAULT;
} else {
rets = length;
@ -253,7 +243,7 @@ int mei_amthif_read(struct mei_device *dev, struct file *file,
}
}
free:
dev_dbg(&dev->pdev->dev, "free amthif cb memory.\n");
dev_dbg(dev->dev, "free amthif cb memory.\n");
*offset = 0;
mei_io_cb_free(cb);
out:
@ -266,7 +256,7 @@ out:
* @dev: the device structure
* @cb: mei call back struct
*
* returns 0 on success, <0 on failure.
* Return: 0 on success, <0 on failure.
*
*/
static int mei_amthif_send_cmd(struct mei_device *dev, struct mei_cl_cb *cb)
@ -277,7 +267,7 @@ static int mei_amthif_send_cmd(struct mei_device *dev, struct mei_cl_cb *cb)
if (!dev || !cb)
return -ENODEV;
dev_dbg(&dev->pdev->dev, "write data to amthif client.\n");
dev_dbg(dev->dev, "write data to amthif client.\n");
dev->iamthif_state = MEI_IAMTHIF_WRITING;
dev->iamthif_current_cb = cb;
@ -316,12 +306,12 @@ static int mei_amthif_send_cmd(struct mei_device *dev, struct mei_cl_cb *cb)
return -EIO;
dev->iamthif_flow_control_pending = true;
dev->iamthif_state = MEI_IAMTHIF_FLOW_CONTROL;
dev_dbg(&dev->pdev->dev, "add amthif cb to write waiting list\n");
dev_dbg(dev->dev, "add amthif cb to write waiting list\n");
dev->iamthif_current_cb = cb;
dev->iamthif_file_object = cb->file_object;
list_add_tail(&cb->list, &dev->write_waiting_list.list);
} else {
dev_dbg(&dev->pdev->dev, "message does not complete, so add amthif cb to write list.\n");
dev_dbg(dev->dev, "message does not complete, so add amthif cb to write list.\n");
list_add_tail(&cb->list, &dev->write_list.list);
}
} else {
@ -336,7 +326,7 @@ static int mei_amthif_send_cmd(struct mei_device *dev, struct mei_cl_cb *cb)
* @dev: the device structure
* @cb: mei call back struct
*
* returns 0 on success, <0 on failure.
* Return: 0 on success, <0 on failure.
*
*/
int mei_amthif_write(struct mei_device *dev, struct mei_cl_cb *cb)
@ -354,25 +344,23 @@ int mei_amthif_write(struct mei_device *dev, struct mei_cl_cb *cb)
if (!list_empty(&dev->amthif_cmd_list.list) ||
dev->iamthif_state != MEI_IAMTHIF_IDLE) {
dev_dbg(&dev->pdev->dev,
dev_dbg(dev->dev,
"amthif state = %d\n", dev->iamthif_state);
dev_dbg(&dev->pdev->dev, "AMTHIF: add cb to the wait list\n");
dev_dbg(dev->dev, "AMTHIF: add cb to the wait list\n");
list_add_tail(&cb->list, &dev->amthif_cmd_list.list);
return 0;
}
return mei_amthif_send_cmd(dev, cb);
}
/**
* mei_amthif_run_next_cmd
* mei_amthif_run_next_cmd - send next amt command from queue
*
* @dev: the device structure
*
* returns 0 on success, <0 on failure.
*/
void mei_amthif_run_next_cmd(struct mei_device *dev)
{
struct mei_cl_cb *pos = NULL;
struct mei_cl_cb *next = NULL;
struct mei_cl_cb *cb;
struct mei_cl_cb *next;
int status;
if (!dev)
@ -386,21 +374,17 @@ void mei_amthif_run_next_cmd(struct mei_device *dev)
dev->iamthif_timer = 0;
dev->iamthif_file_object = NULL;
dev_dbg(&dev->pdev->dev, "complete amthif cmd_list cb.\n");
dev_dbg(dev->dev, "complete amthif cmd_list cb.\n");
list_for_each_entry_safe(pos, next, &dev->amthif_cmd_list.list, list) {
list_del(&pos->list);
if (pos->cl && pos->cl == &dev->iamthif_cl) {
status = mei_amthif_send_cmd(dev, pos);
if (status) {
dev_dbg(&dev->pdev->dev,
"amthif write failed status = %d\n",
list_for_each_entry_safe(cb, next, &dev->amthif_cmd_list.list, list) {
list_del(&cb->list);
if (!cb->cl)
continue;
status = mei_amthif_send_cmd(dev, cb);
if (status)
dev_warn(dev->dev, "amthif write failed status = %d\n",
status);
return;
}
break;
}
break;
}
}
@ -421,7 +405,7 @@ unsigned int mei_amthif_poll(struct mei_device *dev,
dev->iamthif_file_object == file) {
mask |= (POLLIN | POLLRDNORM);
dev_dbg(&dev->pdev->dev, "run next amthif cb\n");
dev_dbg(dev->dev, "run next amthif cb\n");
mei_amthif_run_next_cmd(dev);
}
mutex_unlock(&dev->device_lock);
@ -434,12 +418,11 @@ unsigned int mei_amthif_poll(struct mei_device *dev,
/**
* mei_amthif_irq_write - write iamthif command in irq thread context.
*
* @dev: the device structure.
* @cb_pos: callback block.
* @cl: private data of the file object.
* @cb: callback block.
* @cmpl_list: complete list.
*
* returns 0, OK; otherwise, error.
* Return: 0, OK; otherwise, error.
*/
int mei_amthif_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
struct mei_cl_cb *cmpl_list)
@ -481,7 +464,7 @@ int mei_amthif_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
return 0;
}
dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(&mei_hdr));
dev_dbg(dev->dev, MEI_HDR_FMT, MEI_HDR_PRM(&mei_hdr));
rets = mei_write_message(dev, &mei_hdr,
dev->iamthif_msg_buf + dev->iamthif_msg_buf_index);
@ -514,14 +497,14 @@ int mei_amthif_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
}
/**
* mei_amthif_irq_read_message - read routine after ISR to
* mei_amthif_irq_read_msg - read routine after ISR to
* handle the read amthif message
*
* @dev: the device structure
* @mei_hdr: header of amthif message
* @complete_list: An instance of our list structure
*
* returns 0 on success, <0 on failure.
* Return: 0 on success, <0 on failure.
*/
int mei_amthif_irq_read_msg(struct mei_device *dev,
struct mei_msg_hdr *mei_hdr,
@ -543,10 +526,10 @@ int mei_amthif_irq_read_msg(struct mei_device *dev,
if (!mei_hdr->msg_complete)
return 0;
dev_dbg(&dev->pdev->dev, "amthif_message_buffer_index =%d\n",
dev_dbg(dev->dev, "amthif_message_buffer_index =%d\n",
mei_hdr->length);
dev_dbg(&dev->pdev->dev, "completed amthif read.\n ");
dev_dbg(dev->dev, "completed amthif read.\n ");
if (!dev->iamthif_current_cb)
return -ENODEV;
@ -559,10 +542,10 @@ int mei_amthif_irq_read_msg(struct mei_device *dev,
dev->iamthif_stall_timer = 0;
cb->buf_idx = dev->iamthif_msg_buf_index;
cb->read_time = jiffies;
if (dev->iamthif_ioctl && cb->cl == &dev->iamthif_cl) {
if (dev->iamthif_ioctl) {
/* found the iamthif cb */
dev_dbg(&dev->pdev->dev, "complete the amthif read cb.\n ");
dev_dbg(&dev->pdev->dev, "add the amthif read cb to complete.\n ");
dev_dbg(dev->dev, "complete the amthif read cb.\n ");
dev_dbg(dev->dev, "add the amthif read cb to complete.\n ");
list_add_tail(&cb->list, &complete_list->list);
}
return 0;
@ -574,7 +557,7 @@ int mei_amthif_irq_read_msg(struct mei_device *dev,
* @dev: the device structure.
* @slots: free slots.
*
* returns 0, OK; otherwise, error.
* Return: 0, OK; otherwise, error.
*/
int mei_amthif_irq_read(struct mei_device *dev, s32 *slots)
{
@ -586,11 +569,11 @@ int mei_amthif_irq_read(struct mei_device *dev, s32 *slots)
*slots -= msg_slots;
if (mei_hbm_cl_flow_control_req(dev, &dev->iamthif_cl)) {
dev_dbg(&dev->pdev->dev, "iamthif flow control failed\n");
dev_dbg(dev->dev, "iamthif flow control failed\n");
return -EIO;
}
dev_dbg(&dev->pdev->dev, "iamthif flow control success\n");
dev_dbg(dev->dev, "iamthif flow control success\n");
dev->iamthif_state = MEI_IAMTHIF_READING;
dev->iamthif_flow_control_pending = false;
dev->iamthif_msg_buf_index = 0;
@ -604,7 +587,7 @@ int mei_amthif_irq_read(struct mei_device *dev, s32 *slots)
* mei_amthif_complete - complete amthif callback.
*
* @dev: the device structure.
* @cb_pos: callback block.
* @cb: callback block.
*/
void mei_amthif_complete(struct mei_device *dev, struct mei_cl_cb *cb)
{
@ -615,15 +598,15 @@ void mei_amthif_complete(struct mei_device *dev, struct mei_cl_cb *cb)
dev->iamthif_msg_buf,
dev->iamthif_msg_buf_index);
list_add_tail(&cb->list, &dev->amthif_rd_complete_list.list);
dev_dbg(&dev->pdev->dev, "amthif read completed\n");
dev_dbg(dev->dev, "amthif read completed\n");
dev->iamthif_timer = jiffies;
dev_dbg(&dev->pdev->dev, "dev->iamthif_timer = %ld\n",
dev_dbg(dev->dev, "dev->iamthif_timer = %ld\n",
dev->iamthif_timer);
} else {
mei_amthif_run_next_cmd(dev);
}
dev_dbg(&dev->pdev->dev, "completing amthif call back.\n");
dev_dbg(dev->dev, "completing amthif call back.\n");
wake_up_interruptible(&dev->iamthif_cl.wait);
}
@ -638,7 +621,7 @@ void mei_amthif_complete(struct mei_device *dev, struct mei_cl_cb *cb)
* mei_clear_list is called to clear resources associated with file
* when application calls close function or Ctrl-C was pressed
*
* returns true if callback removed from the list, false otherwise
* 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)
@ -678,7 +661,7 @@ static bool mei_clear_list(struct mei_device *dev,
* mei_clear_lists is called to clear resources associated with file
* when application calls close function or Ctrl-C was pressed
*
* returns true if callback removed from the list, false otherwise
* Return: true if callback removed from the list, false otherwise
*/
static bool mei_clear_lists(struct mei_device *dev, struct file *file)
{
@ -719,7 +702,7 @@ static bool mei_clear_lists(struct mei_device *dev, struct file *file)
* @dev: device structure
* @file: pointer to file structure
*
* returns 0 on success, <0 on error
* Return: 0 on success, <0 on error
*/
int mei_amthif_release(struct mei_device *dev, struct file *file)
{
@ -729,11 +712,11 @@ int mei_amthif_release(struct mei_device *dev, struct file *file)
if (dev->iamthif_file_object == file &&
dev->iamthif_state != MEI_IAMTHIF_IDLE) {
dev_dbg(&dev->pdev->dev, "amthif canceled iamthif state %d\n",
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->pdev->dev, "run next amthif iamthif cb\n");
dev_dbg(dev->dev, "run next amthif iamthif cb\n");
mei_amthif_run_next_cmd(dev);
}
}

View file

@ -22,7 +22,6 @@
#include <linux/slab.h>
#include <linux/mutex.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/mei_cl_bus.h>
#include "mei_dev.h"
@ -70,7 +69,7 @@ static int mei_cl_device_probe(struct device *dev)
dev_dbg(dev, "Device probe\n");
strncpy(id.name, dev_name(dev), sizeof(id.name));
strlcpy(id.name, dev_name(dev), sizeof(id.name));
return driver->probe(device, &id);
}
@ -147,7 +146,7 @@ static struct mei_cl *mei_bus_find_mei_cl_by_uuid(struct mei_device *dev,
struct mei_cl *cl;
list_for_each_entry(cl, &dev->device_list, device_link) {
if (!uuid_le_cmp(uuid, cl->device_uuid))
if (!uuid_le_cmp(uuid, cl->cl_uuid))
return cl;
}
@ -172,7 +171,7 @@ struct mei_cl_device *mei_cl_add_device(struct mei_device *dev,
device->cl = cl;
device->ops = ops;
device->dev.parent = &dev->pdev->dev;
device->dev.parent = dev->dev;
device->dev.bus = &mei_cl_bus_type;
device->dev.type = &mei_cl_device_type;
@ -180,7 +179,7 @@ struct mei_cl_device *mei_cl_add_device(struct mei_device *dev,
status = device_register(&device->dev);
if (status) {
dev_err(&dev->pdev->dev, "Failed to register MEI device\n");
dev_err(dev->dev, "Failed to register MEI device\n");
kfree(device);
return NULL;
}
@ -229,8 +228,8 @@ static int ___mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length,
bool blocking)
{
struct mei_device *dev;
struct mei_me_client *me_cl;
struct mei_cl_cb *cb;
int id;
int rets;
if (WARN_ON(!cl || !cl->dev))
@ -242,11 +241,11 @@ static int ___mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length,
return -ENODEV;
/* Check if we have an ME client device */
id = mei_me_cl_by_id(dev, cl->me_client_id);
if (id < 0)
return id;
me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id);
if (!me_cl)
return -ENOTTY;
if (length > dev->me_clients[id].props.max_msg_length)
if (length > me_cl->props.max_msg_length)
return -EFBIG;
cb = mei_io_cb_init(cl, NULL);
@ -430,7 +429,7 @@ int mei_cl_enable_device(struct mei_cl_device *device)
err = mei_cl_connect(cl, NULL);
if (err < 0) {
mutex_unlock(&dev->device_lock);
dev_err(&dev->pdev->dev, "Could not connect to the ME client");
dev_err(dev->dev, "Could not connect to the ME client");
return err;
}
@ -462,7 +461,7 @@ int mei_cl_disable_device(struct mei_cl_device *device)
if (cl->state != MEI_FILE_CONNECTED) {
mutex_unlock(&dev->device_lock);
dev_err(&dev->pdev->dev, "Already disconnected");
dev_err(dev->dev, "Already disconnected");
return 0;
}
@ -472,7 +471,7 @@ int mei_cl_disable_device(struct mei_cl_device *device)
err = mei_cl_disconnect(cl);
if (err < 0) {
mutex_unlock(&dev->device_lock);
dev_err(&dev->pdev->dev,
dev_err(dev->dev,
"Could not disconnect from the ME client");
return err;

View file

@ -14,10 +14,10 @@
*
*/
#include <linux/pci.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/pm_runtime.h>
#include <linux/mei.h>
@ -27,47 +27,90 @@
#include "client.h"
/**
* mei_me_cl_by_uuid - locate index of me client
* mei_me_cl_by_uuid - locate me client by uuid
*
* @dev: mei device
* @uuid: me client uuid
*
* Locking: called under "dev->device_lock" lock
*
* returns me client index or -ENOENT if not found
* Return: me client or NULL if not found
*/
int mei_me_cl_by_uuid(const struct mei_device *dev, const uuid_le *uuid)
struct mei_me_client *mei_me_cl_by_uuid(const struct mei_device *dev,
const uuid_le *uuid)
{
int i;
struct mei_me_client *me_cl;
for (i = 0; i < dev->me_clients_num; ++i)
if (uuid_le_cmp(*uuid,
dev->me_clients[i].props.protocol_name) == 0)
return i;
list_for_each_entry(me_cl, &dev->me_clients, list)
if (uuid_le_cmp(*uuid, me_cl->props.protocol_name) == 0)
return me_cl;
return -ENOENT;
return NULL;
}
/**
* mei_me_cl_by_id return index to me_clients for client_id
* mei_me_cl_by_id - locate me client by client id
*
* @dev: the device structure
* @client_id: me client id
*
* Locking: called under "dev->device_lock" lock
*
* returns index on success, -ENOENT on failure.
* Return: me client or NULL if not found
*/
int mei_me_cl_by_id(struct mei_device *dev, u8 client_id)
struct mei_me_client *mei_me_cl_by_id(struct mei_device *dev, u8 client_id)
{
int i;
for (i = 0; i < dev->me_clients_num; i++)
if (dev->me_clients[i].client_id == client_id)
return i;
struct mei_me_client *me_cl;
return -ENOENT;
list_for_each_entry(me_cl, &dev->me_clients, list)
if (me_cl->client_id == client_id)
return me_cl;
return NULL;
}
/**
* mei_me_cl_by_uuid_id - locate me client by client id and uuid
*
* @dev: the device structure
* @uuid: me client uuid
* @client_id: me client id
*
* Locking: called under "dev->device_lock" lock
*
* Return: me client or NULL if not found
*/
struct mei_me_client *mei_me_cl_by_uuid_id(struct mei_device *dev,
const uuid_le *uuid, u8 client_id)
{
struct mei_me_client *me_cl;
list_for_each_entry(me_cl, &dev->me_clients, list)
if (uuid_le_cmp(*uuid, me_cl->props.protocol_name) == 0 &&
me_cl->client_id == client_id)
return me_cl;
return NULL;
}
/**
* mei_me_cl_remove - remove me client matching uuid and client_id
*
* @dev: the device structure
* @uuid: me client uuid
* @client_id: me client address
*/
void mei_me_cl_remove(struct mei_device *dev, const uuid_le *uuid, u8 client_id)
{
struct mei_me_client *me_cl, *next;
list_for_each_entry_safe(me_cl, next, &dev->me_clients, list) {
if (uuid_le_cmp(*uuid, me_cl->props.protocol_name) == 0 &&
me_cl->client_id == client_id) {
list_del(&me_cl->list);
kfree(me_cl);
break;
}
}
}
@ -77,7 +120,7 @@ int mei_me_cl_by_id(struct mei_device *dev, u8 client_id)
* @cl1: host client 1
* @cl2: host client 2
*
* returns true - if the clients has same host and me ids
* Return: true - if the clients has same host and me ids
* false - otherwise
*/
static inline bool mei_cl_cmp_id(const struct mei_cl *cl1,
@ -117,7 +160,7 @@ static void __mei_io_list_flush(struct mei_cl_cb *list,
* @list: An instance of our list structure
* @cl: host client
*/
static inline void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl)
void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl)
{
__mei_io_list_flush(list, cl, false);
}
@ -152,10 +195,10 @@ void mei_io_cb_free(struct mei_cl_cb *cb)
/**
* mei_io_cb_init - allocate and initialize io callback
*
* @cl - mei client
* @cl: mei client
* @fp: pointer to file structure
*
* returns mei_cl_cb pointer or NULL;
* Return: mei_cl_cb pointer or NULL;
*/
struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, struct file *fp)
{
@ -179,7 +222,7 @@ struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, struct file *fp)
* @cb: io callback structure
* @length: size of the buffer
*
* returns 0 on success
* Return: 0 on success
* -EINVAL if cb is NULL
* -ENOMEM if allocation failed
*/
@ -203,7 +246,7 @@ int mei_io_cb_alloc_req_buf(struct mei_cl_cb *cb, size_t length)
* @cb: io callback structure
* @length: size of the buffer
*
* returns 0 on success
* Return: 0 on success
* -EINVAL if cb is NULL
* -ENOMEM if allocation failed
*/
@ -228,6 +271,8 @@ int mei_io_cb_alloc_resp_buf(struct mei_cl_cb *cb, size_t length)
* mei_cl_flush_queues - flushes queue lists belonging to cl.
*
* @cl: host client
*
* Return: 0 on success, -EINVAL if cl or cl->dev is NULL.
*/
int mei_cl_flush_queues(struct mei_cl *cl)
{
@ -273,7 +318,7 @@ void mei_cl_init(struct mei_cl *cl, struct mei_device *dev)
* mei_cl_allocate - allocates cl structure and sets it up.
*
* @dev: mei device
* returns The allocated file or NULL on failure
* Return: The allocated file or NULL on failure
*/
struct mei_cl *mei_cl_allocate(struct mei_device *dev)
{
@ -293,7 +338,7 @@ struct mei_cl *mei_cl_allocate(struct mei_device *dev)
*
* @cl: host client
*
* returns cb on success, NULL on error
* Return: cb on success, NULL on error
*/
struct mei_cl_cb *mei_cl_find_read_cb(struct mei_cl *cl)
{
@ -311,7 +356,7 @@ struct mei_cl_cb *mei_cl_find_read_cb(struct mei_cl *cl)
* @cl - host client
* @id - fixed host id or -1 for generic one
*
* returns 0 on success
* Return: 0 on success
* -EINVAL on incorrect values
* -ENONET if client not found
*/
@ -331,13 +376,13 @@ int mei_cl_link(struct mei_cl *cl, int id)
MEI_CLIENTS_MAX);
if (id >= MEI_CLIENTS_MAX) {
dev_err(&dev->pdev->dev, "id exceeded %d", MEI_CLIENTS_MAX);
dev_err(dev->dev, "id exceeded %d", MEI_CLIENTS_MAX);
return -EMFILE;
}
open_handle_count = dev->open_handle_count + dev->iamthif_open_count;
if (open_handle_count >= MEI_MAX_OPEN_HANDLE_COUNT) {
dev_err(&dev->pdev->dev, "open_handle_count exceeded %d",
dev_err(dev->dev, "open_handle_count exceeded %d",
MEI_MAX_OPEN_HANDLE_COUNT);
return -EMFILE;
}
@ -359,6 +404,8 @@ int mei_cl_link(struct mei_cl *cl, int id)
* mei_cl_unlink - remove me_cl from the list
*
* @cl: host client
*
* Return: always 0
*/
int mei_cl_unlink(struct mei_cl *cl)
{
@ -395,19 +442,19 @@ void mei_host_client_init(struct work_struct *work)
{
struct mei_device *dev = container_of(work,
struct mei_device, init_work);
struct mei_client_properties *client_props;
int i;
struct mei_me_client *me_cl;
struct mei_client_properties *props;
mutex_lock(&dev->device_lock);
for (i = 0; i < dev->me_clients_num; i++) {
client_props = &dev->me_clients[i].props;
list_for_each_entry(me_cl, &dev->me_clients, list) {
props = &me_cl->props;
if (!uuid_le_cmp(client_props->protocol_name, mei_amthif_guid))
if (!uuid_le_cmp(props->protocol_name, mei_amthif_guid))
mei_amthif_host_init(dev);
else if (!uuid_le_cmp(client_props->protocol_name, mei_wd_guid))
else if (!uuid_le_cmp(props->protocol_name, mei_wd_guid))
mei_wd_host_init(dev);
else if (!uuid_le_cmp(client_props->protocol_name, mei_nfc_guid))
else if (!uuid_le_cmp(props->protocol_name, mei_nfc_guid))
mei_nfc_host_init(dev);
}
@ -417,27 +464,27 @@ void mei_host_client_init(struct work_struct *work)
mutex_unlock(&dev->device_lock);
pm_runtime_mark_last_busy(&dev->pdev->dev);
dev_dbg(&dev->pdev->dev, "rpm: autosuspend\n");
pm_runtime_autosuspend(&dev->pdev->dev);
pm_runtime_mark_last_busy(dev->dev);
dev_dbg(dev->dev, "rpm: autosuspend\n");
pm_runtime_autosuspend(dev->dev);
}
/**
* mei_hbuf_acquire: try to acquire host buffer
* mei_hbuf_acquire - try to acquire host buffer
*
* @dev: the device structure
* returns true if host buffer was acquired
* Return: true if host buffer was acquired
*/
bool mei_hbuf_acquire(struct mei_device *dev)
{
if (mei_pg_state(dev) == MEI_PG_ON ||
dev->pg_event == MEI_PG_EVENT_WAIT) {
dev_dbg(&dev->pdev->dev, "device is in pg\n");
dev_dbg(dev->dev, "device is in pg\n");
return false;
}
if (!dev->hbuf_is_ready) {
dev_dbg(&dev->pdev->dev, "hbuf is not ready\n");
dev_dbg(dev->dev, "hbuf is not ready\n");
return false;
}
@ -453,7 +500,7 @@ bool mei_hbuf_acquire(struct mei_device *dev)
*
* Locking: called under "dev->device_lock" lock
*
* returns 0 on success, <0 on failure.
* Return: 0 on success, <0 on failure.
*/
int mei_cl_disconnect(struct mei_cl *cl)
{
@ -471,9 +518,9 @@ int mei_cl_disconnect(struct mei_cl *cl)
if (cl->state != MEI_FILE_DISCONNECTING)
return 0;
rets = pm_runtime_get(&dev->pdev->dev);
rets = pm_runtime_get(dev->dev);
if (rets < 0 && rets != -EINPROGRESS) {
pm_runtime_put_noidle(&dev->pdev->dev);
pm_runtime_put_noidle(dev->dev);
cl_err(dev, cl, "rpm: get failed %d\n", rets);
return rets;
}
@ -484,7 +531,8 @@ int mei_cl_disconnect(struct mei_cl *cl)
goto free;
}
cb->fop_type = MEI_FOP_CLOSE;
cb->fop_type = MEI_FOP_DISCONNECT;
if (mei_hbuf_acquire(dev)) {
if (mei_hbm_cl_disconnect_req(dev, cl)) {
rets = -ENODEV;
@ -501,7 +549,7 @@ int mei_cl_disconnect(struct mei_cl *cl)
}
mutex_unlock(&dev->device_lock);
wait_event_timeout(dev->wait_recvd_msg,
wait_event_timeout(cl->wait,
MEI_FILE_DISCONNECTED == cl->state,
mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT));
@ -519,8 +567,8 @@ int mei_cl_disconnect(struct mei_cl *cl)
mei_io_list_flush(&dev->ctrl_wr_list, cl);
free:
cl_dbg(dev, cl, "rpm: autosuspend\n");
pm_runtime_mark_last_busy(&dev->pdev->dev);
pm_runtime_put_autosuspend(&dev->pdev->dev);
pm_runtime_mark_last_busy(dev->dev);
pm_runtime_put_autosuspend(dev->dev);
mei_io_cb_free(cb);
return rets;
@ -533,7 +581,7 @@ free:
*
* @cl: private data of the file object
*
* returns true if other client is connected, false - otherwise.
* Return: true if other client is connected, false - otherwise.
*/
bool mei_cl_is_other_connecting(struct mei_cl *cl)
{
@ -560,10 +608,11 @@ bool mei_cl_is_other_connecting(struct mei_cl *cl)
* mei_cl_connect - connect host client to the me one
*
* @cl: host client
* @file: pointer to file structure
*
* Locking: called under "dev->device_lock" lock
*
* returns 0 on success, <0 on failure.
* Return: 0 on success, <0 on failure.
*/
int mei_cl_connect(struct mei_cl *cl, struct file *file)
{
@ -576,9 +625,9 @@ int mei_cl_connect(struct mei_cl *cl, struct file *file)
dev = cl->dev;
rets = pm_runtime_get(&dev->pdev->dev);
rets = pm_runtime_get(dev->dev);
if (rets < 0 && rets != -EINPROGRESS) {
pm_runtime_put_noidle(&dev->pdev->dev);
pm_runtime_put_noidle(dev->dev);
cl_err(dev, cl, "rpm: get failed %d\n", rets);
return rets;
}
@ -606,7 +655,7 @@ int mei_cl_connect(struct mei_cl *cl, struct file *file)
}
mutex_unlock(&dev->device_lock);
wait_event_timeout(dev->wait_recvd_msg,
wait_event_timeout(cl->wait,
(cl->state == MEI_FILE_CONNECTED ||
cl->state == MEI_FILE_DISCONNECTED),
mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT));
@ -626,8 +675,8 @@ int mei_cl_connect(struct mei_cl *cl, struct file *file)
out:
cl_dbg(dev, cl, "rpm: autosuspend\n");
pm_runtime_mark_last_busy(&dev->pdev->dev);
pm_runtime_put_autosuspend(&dev->pdev->dev);
pm_runtime_mark_last_busy(dev->dev);
pm_runtime_put_autosuspend(dev->dev);
mei_io_cb_free(cb);
return rets;
@ -638,7 +687,7 @@ out:
*
* @cl: private data of the file object
*
* returns 1 if mei_flow_ctrl_creds >0, 0 - otherwise.
* Return: 1 if mei_flow_ctrl_creds >0, 0 - otherwise.
* -ENOENT if mei_cl is not present
* -EINVAL if single_recv_buf == 0
*/
@ -646,26 +695,21 @@ int mei_cl_flow_ctrl_creds(struct mei_cl *cl)
{
struct mei_device *dev;
struct mei_me_client *me_cl;
int id;
if (WARN_ON(!cl || !cl->dev))
return -EINVAL;
dev = cl->dev;
if (!dev->me_clients_num)
return 0;
if (cl->mei_flow_ctrl_creds > 0)
return 1;
id = mei_me_cl_by_id(dev, cl->me_client_id);
if (id < 0) {
me_cl = mei_me_cl_by_id(dev, cl->me_client_id);
if (!me_cl) {
cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
return id;
return -ENOENT;
}
me_cl = &dev->me_clients[id];
if (me_cl->mei_flow_ctrl_creds) {
if (WARN_ON(me_cl->props.single_recv_buf == 0))
return -EINVAL;
@ -679,7 +723,7 @@ int mei_cl_flow_ctrl_creds(struct mei_cl *cl)
*
* @cl: private data of the file object
*
* @returns
* Return:
* 0 on success
* -ENOENT when me client is not found
* -EINVAL when ctrl credits are <= 0
@ -688,21 +732,19 @@ int mei_cl_flow_ctrl_reduce(struct mei_cl *cl)
{
struct mei_device *dev;
struct mei_me_client *me_cl;
int id;
if (WARN_ON(!cl || !cl->dev))
return -EINVAL;
dev = cl->dev;
id = mei_me_cl_by_id(dev, cl->me_client_id);
if (id < 0) {
me_cl = mei_me_cl_by_id(dev, cl->me_client_id);
if (!me_cl) {
cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
return id;
return -ENOENT;
}
me_cl = &dev->me_clients[id];
if (me_cl->props.single_recv_buf != 0) {
if (me_cl->props.single_recv_buf) {
if (WARN_ON(me_cl->mei_flow_ctrl_creds <= 0))
return -EINVAL;
me_cl->mei_flow_ctrl_creds--;
@ -718,15 +760,16 @@ int mei_cl_flow_ctrl_reduce(struct mei_cl *cl)
* mei_cl_read_start - the start read client message function.
*
* @cl: host client
* @length: number of bytes to read
*
* returns 0 on success, <0 on failure.
* Return: 0 on success, <0 on failure.
*/
int mei_cl_read_start(struct mei_cl *cl, size_t length)
{
struct mei_device *dev;
struct mei_cl_cb *cb;
struct mei_me_client *me_cl;
int rets;
int i;
if (WARN_ON(!cl || !cl->dev))
return -ENODEV;
@ -740,15 +783,15 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length)
cl_dbg(dev, cl, "read is pending.\n");
return -EBUSY;
}
i = mei_me_cl_by_id(dev, cl->me_client_id);
if (i < 0) {
me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id);
if (!me_cl) {
cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
return -ENOTTY;
}
rets = pm_runtime_get(&dev->pdev->dev);
rets = pm_runtime_get(dev->dev);
if (rets < 0 && rets != -EINPROGRESS) {
pm_runtime_put_noidle(&dev->pdev->dev);
pm_runtime_put_noidle(dev->dev);
cl_err(dev, cl, "rpm: get failed %d\n", rets);
return rets;
}
@ -760,7 +803,7 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length)
}
/* always allocate at least client max message */
length = max_t(size_t, length, dev->me_clients[i].props.max_msg_length);
length = max_t(size_t, length, me_cl->props.max_msg_length);
rets = mei_io_cb_alloc_resp_buf(cb, length);
if (rets)
goto out;
@ -780,8 +823,8 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length)
out:
cl_dbg(dev, cl, "rpm: autosuspend\n");
pm_runtime_mark_last_busy(&dev->pdev->dev);
pm_runtime_put_autosuspend(&dev->pdev->dev);
pm_runtime_mark_last_busy(dev->dev);
pm_runtime_put_autosuspend(dev->dev);
if (rets)
mei_io_cb_free(cb);
@ -797,7 +840,7 @@ out:
* @cb: callback block.
* @cmpl_list: complete list.
*
* returns 0, OK; otherwise error.
* Return: 0, OK; otherwise error.
*/
int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
struct mei_cl_cb *cmpl_list)
@ -874,12 +917,13 @@ int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
/**
* mei_cl_write - submit a write cb to mei device
assumes device_lock is locked
* assumes device_lock is locked
*
* @cl: host client
* @cl: write callback with filled data
* @cb: write callback with filled data
* @blocking: block until completed
*
* returns number of bytes sent on success, <0 on failure.
* Return: number of bytes sent on success, <0 on failure.
*/
int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking)
{
@ -900,11 +944,11 @@ int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking)
buf = &cb->request_buffer;
cl_dbg(dev, cl, "mei_cl_write %d\n", buf->size);
cl_dbg(dev, cl, "size=%d\n", buf->size);
rets = pm_runtime_get(&dev->pdev->dev);
rets = pm_runtime_get(dev->dev);
if (rets < 0 && rets != -EINPROGRESS) {
pm_runtime_put_noidle(&dev->pdev->dev);
pm_runtime_put_noidle(dev->dev);
cl_err(dev, cl, "rpm: get failed %d\n", rets);
return rets;
}
@ -979,8 +1023,8 @@ out:
rets = buf->size;
err:
cl_dbg(dev, cl, "rpm: autosuspend\n");
pm_runtime_mark_last_busy(&dev->pdev->dev);
pm_runtime_put_autosuspend(&dev->pdev->dev);
pm_runtime_mark_last_busy(dev->dev);
pm_runtime_put_autosuspend(dev->dev);
return rets;
}
@ -1016,7 +1060,7 @@ void mei_cl_complete(struct mei_cl *cl, struct mei_cl_cb *cb)
/**
* mei_cl_all_disconnect - disconnect forcefully all connected clients
*
* @dev - mei device
* @dev: mei device
*/
void mei_cl_all_disconnect(struct mei_device *dev)
@ -1034,11 +1078,12 @@ void mei_cl_all_disconnect(struct mei_device *dev)
/**
* mei_cl_all_wakeup - wake up all readers and writers they can be interrupted
*
* @dev - mei device
* @dev: mei device
*/
void mei_cl_all_wakeup(struct mei_device *dev)
{
struct mei_cl *cl;
list_for_each_entry(cl, &dev->file_list, link) {
if (waitqueue_active(&cl->rx_wait)) {
cl_dbg(dev, cl, "Waking up reading client!\n");
@ -1053,8 +1098,8 @@ void mei_cl_all_wakeup(struct mei_device *dev)
/**
* mei_cl_all_write_clear - clear all pending writes
* @dev - mei device
*
* @dev: mei device
*/
void mei_cl_all_write_clear(struct mei_device *dev)
{

View file

@ -24,8 +24,15 @@
#include "mei_dev.h"
int mei_me_cl_by_uuid(const struct mei_device *dev, const uuid_le *cuuid);
int mei_me_cl_by_id(struct mei_device *dev, u8 client_id);
struct mei_me_client *mei_me_cl_by_uuid(const struct mei_device *dev,
const uuid_le *cuuid);
struct mei_me_client *mei_me_cl_by_id(struct mei_device *dev, u8 client_id);
struct mei_me_client *mei_me_cl_by_uuid_id(struct mei_device *dev,
const uuid_le *uuid, u8 client_id);
void mei_me_cl_remove(struct mei_device *dev,
const uuid_le *uuid, u8 client_id);
/*
* MEI IO Functions
@ -45,6 +52,8 @@ static inline void mei_io_list_init(struct mei_cl_cb *list)
{
INIT_LIST_HEAD(&list->list);
}
void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl);
/*
* MEI Host Client Functions
*/
@ -101,9 +110,9 @@ void mei_cl_all_write_clear(struct mei_device *dev);
#define MEI_CL_PRM(cl) (cl)->host_client_id, (cl)->me_client_id
#define cl_dbg(dev, cl, format, arg...) \
dev_dbg(&(dev)->pdev->dev, MEI_CL_FMT format, MEI_CL_PRM(cl), ##arg)
dev_dbg((dev)->dev, MEI_CL_FMT format, MEI_CL_PRM(cl), ##arg)
#define cl_err(dev, cl, format, arg...) \
dev_err(&(dev)->pdev->dev, MEI_CL_FMT format, MEI_CL_PRM(cl), ##arg)
dev_err((dev)->dev, MEI_CL_FMT format, MEI_CL_PRM(cl), ##arg)
#endif /* _MEI_CLIENT_H_ */

View file

@ -17,7 +17,6 @@
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/debugfs.h>
#include <linux/pci.h>
#include <linux/mei.h>
@ -28,39 +27,47 @@ static ssize_t mei_dbgfs_read_meclients(struct file *fp, char __user *ubuf,
size_t cnt, loff_t *ppos)
{
struct mei_device *dev = fp->private_data;
struct mei_me_client *cl;
const size_t bufsz = 1024;
char *buf = kzalloc(bufsz, GFP_KERNEL);
int i;
struct mei_me_client *me_cl;
size_t bufsz = 1;
char *buf;
int i = 0;
int pos = 0;
int ret;
if (!buf)
return -ENOMEM;
pos += scnprintf(buf + pos, bufsz - pos,
" |id|addr| UUID |con|msg len|\n");
#define HDR " |id|addr| UUID |con|msg len|sb|\n"
mutex_lock(&dev->device_lock);
list_for_each_entry(me_cl, &dev->me_clients, list)
bufsz++;
bufsz *= sizeof(HDR) + 1;
buf = kzalloc(bufsz, GFP_KERNEL);
if (!buf) {
mutex_unlock(&dev->device_lock);
return -ENOMEM;
}
pos += scnprintf(buf + pos, bufsz - pos, HDR);
/* if the driver is not enabled the list won't be consistent */
if (dev->dev_state != MEI_DEV_ENABLED)
goto out;
for (i = 0; i < dev->me_clients_num; i++) {
cl = &dev->me_clients[i];
list_for_each_entry(me_cl, &dev->me_clients, list) {
/* skip me clients that cannot be connected */
if (cl->props.max_number_of_connections == 0)
if (me_cl->props.max_number_of_connections == 0)
continue;
pos += scnprintf(buf + pos, bufsz - pos,
"%2d|%2d|%4d|%pUl|%3d|%7d|\n",
i, cl->client_id,
cl->props.fixed_address,
&cl->props.protocol_name,
cl->props.max_number_of_connections,
cl->props.max_msg_length);
"%2d|%2d|%4d|%pUl|%3d|%7d|%2d|\n",
i++, me_cl->client_id,
me_cl->props.fixed_address,
&me_cl->props.protocol_name,
me_cl->props.max_number_of_connections,
me_cl->props.max_msg_length,
me_cl->props.single_recv_buf);
}
out:
mutex_unlock(&dev->device_lock);
@ -98,7 +105,7 @@ static ssize_t mei_dbgfs_read_active(struct file *fp, char __user *ubuf,
mutex_lock(&dev->device_lock);
/* if the driver is not enabled the list won't b consitent */
/* if the driver is not enabled the list won't be consistent */
if (dev->dev_state != MEI_DEV_ENABLED)
goto out;
@ -135,8 +142,13 @@ static ssize_t mei_dbgfs_read_devstate(struct file *fp, char __user *ubuf,
if (!buf)
return -ENOMEM;
pos += scnprintf(buf + pos, bufsz - pos, "%s\n",
pos += scnprintf(buf + pos, bufsz - pos, "dev: %s\n",
mei_dev_state_str(dev->dev_state));
pos += scnprintf(buf + pos, bufsz - pos, "hbm: %s\n",
mei_hbm_state_str(dev->hbm_state));
pos += scnprintf(buf + pos, bufsz - pos, "pg: %s, %s\n",
mei_pg_is_enabled(dev) ? "ENABLED" : "DISABLED",
mei_pg_state_str(mei_pg_state(dev)));
ret = simple_read_from_buffer(ubuf, cnt, ppos, buf, pos);
kfree(buf);
return ret;
@ -149,7 +161,8 @@ static const struct file_operations mei_dbgfs_fops_devstate = {
/**
* mei_dbgfs_deregister - Remove the debugfs files and directories
* @mei - pointer to mei device private data
*
* @dev: the mei device structure
*/
void mei_dbgfs_deregister(struct mei_device *dev)
{
@ -160,12 +173,17 @@ void mei_dbgfs_deregister(struct mei_device *dev)
}
/**
* Add the debugfs files
* mei_dbgfs_register - Add the debugfs files
*
* @dev: the mei device structure
* @name: the mei device name
*
* Return: 0 on success, <0 on failure.
*/
int mei_dbgfs_register(struct mei_device *dev, const char *name)
{
struct dentry *dir, *f;
dir = debugfs_create_dir(name, NULL);
if (!dir)
return -ENOMEM;
@ -173,19 +191,19 @@ int mei_dbgfs_register(struct mei_device *dev, const char *name)
f = debugfs_create_file("meclients", S_IRUSR, dir,
dev, &mei_dbgfs_fops_meclients);
if (!f) {
dev_err(&dev->pdev->dev, "meclients: registration failed\n");
dev_err(dev->dev, "meclients: registration failed\n");
goto err;
}
f = debugfs_create_file("active", S_IRUSR, dir,
dev, &mei_dbgfs_fops_active);
if (!f) {
dev_err(&dev->pdev->dev, "meclients: registration failed\n");
dev_err(dev->dev, "meclients: registration failed\n");
goto err;
}
f = debugfs_create_file("devstate", S_IRUSR, dir,
dev, &mei_dbgfs_fops_devstate);
if (!f) {
dev_err(&dev->pdev->dev, "devstate: registration failed\n");
dev_err(dev->dev, "devstate: registration failed\n");
goto err;
}
dev->dbgfs_dir = dir;

File diff suppressed because it is too large Load diff

View file

@ -25,29 +25,24 @@ struct mei_cl;
* enum mei_hbm_state - host bus message protocol state
*
* @MEI_HBM_IDLE : protocol not started
* @MEI_HBM_START : start request message was sent
* @MEI_HBM_STARTING : start request message was sent
* @MEI_HBM_STARTED : start reply message was received
* @MEI_HBM_ENUM_CLIENTS : enumeration request was sent
* @MEI_HBM_CLIENT_PROPERTIES : acquiring clients properties
* @MEI_HBM_STOPPED : stopping exchange
*/
enum mei_hbm_state {
MEI_HBM_IDLE = 0,
MEI_HBM_START,
MEI_HBM_STARTING,
MEI_HBM_STARTED,
MEI_HBM_ENUM_CLIENTS,
MEI_HBM_CLIENT_PROPERTIES,
MEI_HBM_STOPPED,
};
int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr);
const char *mei_hbm_state_str(enum mei_hbm_state state);
static inline void mei_hbm_hdr(struct mei_msg_hdr *hdr, size_t length)
{
hdr->host_addr = 0;
hdr->me_addr = 0;
hdr->length = length;
hdr->msg_complete = 1;
hdr->reserved = 0;
}
int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr);
void mei_hbm_idle(struct mei_device *dev);
void mei_hbm_reset(struct mei_device *dev);

View file

@ -28,10 +28,10 @@
/**
* mei_me_reg_read - Reads 32bit data from the mei device
*
* @dev: the device structure
* @hw: the me hardware structure
* @offset: offset from which to read the data
*
* returns register value (u32)
* Return: register value (u32)
*/
static inline u32 mei_me_reg_read(const struct mei_me_hw *hw,
unsigned long offset)
@ -43,7 +43,7 @@ static inline u32 mei_me_reg_read(const struct mei_me_hw *hw,
/**
* mei_me_reg_write - Writes 32bit data to the mei device
*
* @dev: the device structure
* @hw: the me hardware structure
* @offset: offset from which to write the data
* @value: register value to write (u32)
*/
@ -59,7 +59,7 @@ static inline void mei_me_reg_write(const struct mei_me_hw *hw,
*
* @dev: the device structure
*
* returns ME_CB_RW register value (u32)
* Return: ME_CB_RW register value (u32)
*/
static u32 mei_me_mecbrw_read(const struct mei_device *dev)
{
@ -68,9 +68,9 @@ static u32 mei_me_mecbrw_read(const struct mei_device *dev)
/**
* mei_me_mecsr_read - Reads 32bit data from the ME CSR
*
* @dev: the device structure
* @hw: the me hardware structure
*
* returns ME_CSR_HA register value (u32)
* Return: ME_CSR_HA register value (u32)
*/
static inline u32 mei_me_mecsr_read(const struct mei_me_hw *hw)
{
@ -80,9 +80,9 @@ static inline u32 mei_me_mecsr_read(const struct mei_me_hw *hw)
/**
* mei_hcsr_read - Reads 32bit data from the host CSR
*
* @dev: the device structure
* @hw: the me hardware structure
*
* returns H_CSR register value (u32)
* Return: H_CSR register value (u32)
*/
static inline u32 mei_hcsr_read(const struct mei_me_hw *hw)
{
@ -93,7 +93,8 @@ static inline u32 mei_hcsr_read(const struct mei_me_hw *hw)
* mei_hcsr_set - writes H_CSR register to the mei device,
* and ignores the H_IS bit for it is write-one-to-zero.
*
* @dev: the device structure
* @hw: the me hardware structure
* @hcsr: new register value
*/
static inline void mei_hcsr_set(struct mei_me_hw *hw, u32 hcsr)
{
@ -101,6 +102,36 @@ static inline void mei_hcsr_set(struct mei_me_hw *hw, u32 hcsr)
mei_me_reg_write(hw, H_CSR, hcsr);
}
/**
* mei_me_fw_status - read fw status register from pci config space
*
* @dev: mei device
* @fw_status: fw status register values
*
* Return: 0 on success, error otherwise
*/
static int mei_me_fw_status(struct mei_device *dev,
struct mei_fw_status *fw_status)
{
struct pci_dev *pdev = to_pci_dev(dev->dev);
struct mei_me_hw *hw = to_me_hw(dev);
const struct mei_fw_status *fw_src = &hw->cfg->fw_status;
int ret;
int i;
if (!fw_status)
return -EINVAL;
fw_status->count = fw_src->count;
for (i = 0; i < fw_src->count && i < MEI_FW_STATUS_MAX; i++) {
ret = pci_read_config_dword(pdev,
fw_src->status[i], &fw_status->status[i]);
if (ret)
return ret;
}
return 0;
}
/**
* mei_me_hw_config - configure hw dependent settings
@ -121,17 +152,19 @@ static void mei_me_hw_config(struct mei_device *dev)
* mei_me_pg_state - translate internal pg state
* to the mei power gating state
*
* @hw - me hardware
* returns: MEI_PG_OFF if aliveness is on and MEI_PG_ON otherwise
* @dev: mei device
*
* Return: MEI_PG_OFF if aliveness is on and MEI_PG_ON otherwise
*/
static inline enum mei_pg_state mei_me_pg_state(struct mei_device *dev)
{
struct mei_me_hw *hw = to_me_hw(dev);
return hw->pg_state;
}
/**
* mei_clear_interrupts - clear and stop interrupts
* mei_me_intr_clear - clear and stop interrupts
*
* @dev: the device structure
*/
@ -139,6 +172,7 @@ static void mei_me_intr_clear(struct mei_device *dev)
{
struct mei_me_hw *hw = to_me_hw(dev);
u32 hcsr = mei_hcsr_read(hw);
if ((hcsr & H_IS) == H_IS)
mei_me_reg_write(hw, H_CSR, hcsr);
}
@ -151,12 +185,13 @@ static void mei_me_intr_enable(struct mei_device *dev)
{
struct mei_me_hw *hw = to_me_hw(dev);
u32 hcsr = mei_hcsr_read(hw);
hcsr |= H_IE;
mei_hcsr_set(hw, hcsr);
}
/**
* mei_disable_interrupts - disables mei device interrupts
* mei_me_intr_disable - disables mei device interrupts
*
* @dev: the device structure
*/
@ -164,6 +199,7 @@ static void mei_me_intr_disable(struct mei_device *dev)
{
struct mei_me_hw *hw = to_me_hw(dev);
u32 hcsr = mei_hcsr_read(hw);
hcsr &= ~H_IE;
mei_hcsr_set(hw, hcsr);
}
@ -190,6 +226,8 @@ static void mei_me_hw_reset_release(struct mei_device *dev)
*
* @dev: the device structure
* @intr_enable: if interrupt should be enabled after reset.
*
* Return: always 0
*/
static int mei_me_hw_reset(struct mei_device *dev, bool intr_enable)
{
@ -213,10 +251,10 @@ static int mei_me_hw_reset(struct mei_device *dev, bool intr_enable)
hcsr = mei_hcsr_read(hw);
if ((hcsr & H_RST) == 0)
dev_warn(&dev->pdev->dev, "H_RST is not set = 0x%08X", hcsr);
dev_warn(dev->dev, "H_RST is not set = 0x%08X", hcsr);
if ((hcsr & H_RDY) == H_RDY)
dev_warn(&dev->pdev->dev, "H_RDY is not cleared 0x%08X", hcsr);
dev_warn(dev->dev, "H_RDY is not cleared 0x%08X", hcsr);
if (intr_enable == false)
mei_me_hw_reset_release(dev);
@ -227,26 +265,27 @@ static int mei_me_hw_reset(struct mei_device *dev, bool intr_enable)
/**
* mei_me_host_set_ready - enable device
*
* @dev - mei device
* returns bool
* @dev: mei device
*/
static void mei_me_host_set_ready(struct mei_device *dev)
{
struct mei_me_hw *hw = to_me_hw(dev);
hw->host_hw_state = mei_hcsr_read(hw);
hw->host_hw_state |= H_IE | H_IG | H_RDY;
mei_hcsr_set(hw, hw->host_hw_state);
}
/**
* mei_me_host_is_ready - check whether the host has turned ready
*
* @dev - mei device
* returns bool
* @dev: mei device
* Return: bool
*/
static bool mei_me_host_is_ready(struct mei_device *dev)
{
struct mei_me_hw *hw = to_me_hw(dev);
hw->host_hw_state = mei_hcsr_read(hw);
return (hw->host_hw_state & H_RDY) == H_RDY;
}
@ -254,43 +293,53 @@ static bool mei_me_host_is_ready(struct mei_device *dev)
/**
* mei_me_hw_is_ready - check whether the me(hw) has turned ready
*
* @dev - mei device
* returns bool
* @dev: mei device
* Return: bool
*/
static bool mei_me_hw_is_ready(struct mei_device *dev)
{
struct mei_me_hw *hw = to_me_hw(dev);
hw->me_hw_state = mei_me_mecsr_read(hw);
return (hw->me_hw_state & ME_RDY_HRA) == ME_RDY_HRA;
}
/**
* mei_me_hw_ready_wait - wait until the me(hw) has turned ready
* or timeout is reached
*
* @dev: mei device
* Return: 0 on success, error otherwise
*/
static int mei_me_hw_ready_wait(struct mei_device *dev)
{
int err;
mutex_unlock(&dev->device_lock);
err = wait_event_interruptible_timeout(dev->wait_hw_ready,
wait_event_timeout(dev->wait_hw_ready,
dev->recvd_hw_ready,
mei_secs_to_jiffies(MEI_HW_READY_TIMEOUT));
mutex_lock(&dev->device_lock);
if (!err && !dev->recvd_hw_ready) {
if (!err)
err = -ETIME;
dev_err(&dev->pdev->dev,
"wait hw ready failed. status = %d\n", err);
return err;
if (!dev->recvd_hw_ready) {
dev_err(dev->dev, "wait hw ready failed\n");
return -ETIME;
}
dev->recvd_hw_ready = false;
return 0;
}
/**
* mei_me_hw_start - hw start routine
*
* @dev: mei device
* Return: 0 on success, error otherwise
*/
static int mei_me_hw_start(struct mei_device *dev)
{
int ret = mei_me_hw_ready_wait(dev);
if (ret)
return ret;
dev_dbg(&dev->pdev->dev, "hw is ready\n");
dev_dbg(dev->dev, "hw is ready\n");
mei_me_host_set_ready(dev);
return ret;
@ -302,7 +351,7 @@ static int mei_me_hw_start(struct mei_device *dev)
*
* @dev: the device structure
*
* returns number of filled slots
* Return: number of filled slots
*/
static unsigned char mei_hbuf_filled_slots(struct mei_device *dev)
{
@ -322,7 +371,7 @@ static unsigned char mei_hbuf_filled_slots(struct mei_device *dev)
*
* @dev: the device structure
*
* returns true if empty, false - otherwise.
* Return: true if empty, false - otherwise.
*/
static bool mei_me_hbuf_is_empty(struct mei_device *dev)
{
@ -334,7 +383,7 @@ static bool mei_me_hbuf_is_empty(struct mei_device *dev)
*
* @dev: the device structure
*
* returns -EOVERFLOW if overflow, otherwise empty slots count
* Return: -EOVERFLOW if overflow, otherwise empty slots count
*/
static int mei_me_hbuf_empty_slots(struct mei_device *dev)
{
@ -350,6 +399,13 @@ static int mei_me_hbuf_empty_slots(struct mei_device *dev)
return empty_slots;
}
/**
* mei_me_hbuf_max_len - returns size of hw buffer.
*
* @dev: the device structure
*
* Return: size of hw buffer in bytes
*/
static size_t mei_me_hbuf_max_len(const struct mei_device *dev)
{
return dev->hbuf_depth * sizeof(u32) - sizeof(struct mei_msg_hdr);
@ -363,7 +419,7 @@ static size_t mei_me_hbuf_max_len(const struct mei_device *dev)
* @header: mei HECI header of message
* @buf: message payload will be written
*
* This function returns -EIO if write has failed
* Return: -EIO if write has failed
*/
static int mei_me_write_message(struct mei_device *dev,
struct mei_msg_hdr *header,
@ -378,10 +434,10 @@ static int mei_me_write_message(struct mei_device *dev,
int i;
int empty_slots;
dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(header));
dev_dbg(dev->dev, MEI_HDR_FMT, MEI_HDR_PRM(header));
empty_slots = mei_hbuf_empty_slots(dev);
dev_dbg(&dev->pdev->dev, "empty slots = %hu.\n", empty_slots);
dev_dbg(dev->dev, "empty slots = %hu.\n", empty_slots);
dw_cnt = mei_data2slots(length);
if (empty_slots < 0 || dw_cnt > empty_slots)
@ -395,6 +451,7 @@ static int mei_me_write_message(struct mei_device *dev,
rem = length & 0x3;
if (rem > 0) {
u32 reg = 0;
memcpy(&reg, &buf[length - rem], rem);
mei_me_reg_write(hw, H_CB_WW, reg);
}
@ -412,7 +469,7 @@ static int mei_me_write_message(struct mei_device *dev,
*
* @dev: the device structure
*
* returns -EOVERFLOW if overflow, otherwise filled slots count
* Return: -EOVERFLOW if overflow, otherwise filled slots count
*/
static int mei_me_count_full_read_slots(struct mei_device *dev)
{
@ -430,7 +487,7 @@ static int mei_me_count_full_read_slots(struct mei_device *dev)
if (filled_slots > buffer_depth)
return -EOVERFLOW;
dev_dbg(&dev->pdev->dev, "filled_slots =%08x\n", filled_slots);
dev_dbg(dev->dev, "filled_slots =%08x\n", filled_slots);
return (int)filled_slots;
}
@ -440,6 +497,8 @@ static int mei_me_count_full_read_slots(struct mei_device *dev)
* @dev: the device structure
* @buffer: message buffer will be written
* @buffer_length: message size will be read
*
* Return: always 0
*/
static int mei_me_read_slots(struct mei_device *dev, unsigned char *buffer,
unsigned long buffer_length)
@ -453,6 +512,7 @@ static int mei_me_read_slots(struct mei_device *dev, unsigned char *buffer,
if (buffer_length > 0) {
u32 reg = mei_me_mecbrw_read(dev);
memcpy(reg_buf, &reg, buffer_length);
}
@ -462,7 +522,7 @@ static int mei_me_read_slots(struct mei_device *dev, unsigned char *buffer,
}
/**
* mei_me_pg_enter - write pg enter register to mei device.
* mei_me_pg_enter - write pg enter register
*
* @dev: the device structure
*/
@ -470,12 +530,13 @@ static void mei_me_pg_enter(struct mei_device *dev)
{
struct mei_me_hw *hw = to_me_hw(dev);
u32 reg = mei_me_reg_read(hw, H_HPG_CSR);
reg |= H_HPG_CSR_PGI;
mei_me_reg_write(hw, H_HPG_CSR, reg);
}
/**
* mei_me_pg_enter - write pg enter register to mei device.
* mei_me_pg_exit - write pg exit register
*
* @dev: the device structure
*/
@ -495,7 +556,7 @@ static void mei_me_pg_exit(struct mei_device *dev)
*
* @dev: the device structure
*
* returns 0 on success an error code otherwise
* Return: 0 on success an error code otherwise
*/
int mei_me_pg_set_sync(struct mei_device *dev)
{
@ -532,7 +593,7 @@ int mei_me_pg_set_sync(struct mei_device *dev)
*
* @dev: the device structure
*
* returns 0 on success an error code otherwise
* Return: 0 on success an error code otherwise
*/
int mei_me_pg_unset_sync(struct mei_device *dev)
{
@ -569,7 +630,7 @@ reply:
*
* @dev: the device structure
*
* returns: true is pg supported, false otherwise
* Return: true is pg supported, false otherwise
*/
static bool mei_me_pg_is_enabled(struct mei_device *dev)
{
@ -579,17 +640,13 @@ static bool mei_me_pg_is_enabled(struct mei_device *dev)
if ((reg & ME_PGIC_HRA) == 0)
goto notsupported;
if (dev->version.major_version < HBM_MAJOR_VERSION_PGI)
goto notsupported;
if (dev->version.major_version == HBM_MAJOR_VERSION_PGI &&
dev->version.minor_version < HBM_MINOR_VERSION_PGI)
if (!dev->hbm_f_pg_supported)
goto notsupported;
return true;
notsupported:
dev_dbg(&dev->pdev->dev, "pg: not supported: HGP = %d hbm version %d.%d ?= %d.%d\n",
dev_dbg(dev->dev, "pg: not supported: HGP = %d hbm version %d.%d ?= %d.%d\n",
!!(reg & ME_PGIC_HRA),
dev->version.major_version,
dev->version.minor_version,
@ -605,7 +662,7 @@ notsupported:
* @irq: The irq number
* @dev_id: pointer to the device structure
*
* returns irqreturn_t
* Return: irqreturn_t
*/
irqreturn_t mei_me_irq_quick_handler(int irq, void *dev_id)
@ -630,7 +687,7 @@ irqreturn_t mei_me_irq_quick_handler(int irq, void *dev_id)
* @irq: The irq number
* @dev_id: pointer to the device structure
*
* returns irqreturn_t
* Return: irqreturn_t
*
*/
irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id)
@ -640,19 +697,19 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id)
s32 slots;
int rets = 0;
dev_dbg(&dev->pdev->dev, "function called after ISR to handle the interrupt processing.\n");
dev_dbg(dev->dev, "function called after ISR to handle the interrupt processing.\n");
/* initialize our complete list */
mutex_lock(&dev->device_lock);
mei_io_list_init(&complete_list);
/* Ack the interrupt here
* In case of MSI we don't go through the quick handler */
if (pci_dev_msi_enabled(dev->pdev))
if (pci_dev_msi_enabled(to_pci_dev(dev->dev)))
mei_clear_interrupts(dev);
/* check if ME wants a reset */
if (!mei_hw_is_ready(dev) && dev->dev_state != MEI_DEV_RESETTING) {
dev_warn(&dev->pdev->dev, "FW not ready: resetting.\n");
dev_warn(dev->dev, "FW not ready: resetting.\n");
schedule_work(&dev->reset_work);
goto end;
}
@ -661,19 +718,19 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id)
if (!mei_host_is_ready(dev)) {
if (mei_hw_is_ready(dev)) {
mei_me_hw_reset_release(dev);
dev_dbg(&dev->pdev->dev, "we need to start the dev.\n");
dev_dbg(dev->dev, "we need to start the dev.\n");
dev->recvd_hw_ready = true;
wake_up_interruptible(&dev->wait_hw_ready);
wake_up(&dev->wait_hw_ready);
} else {
dev_dbg(&dev->pdev->dev, "Spurious Interrupt\n");
dev_dbg(dev->dev, "Spurious Interrupt\n");
}
goto end;
}
/* check slots available for reading */
slots = mei_count_full_read_slots(dev);
while (slots > 0) {
dev_dbg(&dev->pdev->dev, "slots to read = %08x\n", slots);
dev_dbg(dev->dev, "slots to read = %08x\n", slots);
rets = mei_irq_read_handler(dev, &complete_list, &slots);
/* There is a race between ME write and interrupt delivery:
* Not all data is always available immediately after the
@ -683,7 +740,7 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id)
break;
if (rets && dev->dev_state != MEI_DEV_RESETTING) {
dev_err(&dev->pdev->dev, "mei_irq_read_handler ret = %d.\n",
dev_err(dev->dev, "mei_irq_read_handler ret = %d.\n",
rets);
schedule_work(&dev->reset_work);
goto end;
@ -705,13 +762,14 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id)
mei_irq_compl_handler(dev, &complete_list);
end:
dev_dbg(&dev->pdev->dev, "interrupt thread end ret = %d\n", rets);
dev_dbg(dev->dev, "interrupt thread end ret = %d\n", rets);
mutex_unlock(&dev->device_lock);
return IRQ_HANDLED;
}
static const struct mei_hw_ops mei_me_hw_ops = {
.fw_status = mei_me_fw_status,
.pg_state = mei_me_pg_state,
.host_is_ready = mei_me_host_is_ready,
@ -741,6 +799,7 @@ static const struct mei_hw_ops mei_me_hw_ops = {
static bool mei_me_fw_type_nm(struct pci_dev *pdev)
{
u32 reg;
pci_read_config_dword(pdev, PCI_CFG_HFS_2, &reg);
/* make sure that bit 9 (NM) is up and bit 10 (DM) is down */
return (reg & 0x600) == 0x200;
@ -809,23 +868,22 @@ const struct mei_cfg mei_me_lpt_cfg = {
* @pdev: The pci device structure
* @cfg: per device generation config
*
* returns The mei_device_device pointer on success, NULL on failure.
* Return: The mei_device_device pointer on success, NULL on failure.
*/
struct mei_device *mei_me_dev_init(struct pci_dev *pdev,
const struct mei_cfg *cfg)
{
struct mei_device *dev;
struct mei_me_hw *hw;
dev = kzalloc(sizeof(struct mei_device) +
sizeof(struct mei_me_hw), GFP_KERNEL);
if (!dev)
return NULL;
hw = to_me_hw(dev);
mei_device_init(dev, cfg);
dev->ops = &mei_me_hw_ops;
dev->pdev = pdev;
mei_device_init(dev, &pdev->dev, &mei_me_hw_ops);
hw->cfg = cfg;
return dev;
}

View file

@ -19,14 +19,44 @@
#ifndef _MEI_INTERFACE_H_
#define _MEI_INTERFACE_H_
#include <linux/mei.h>
#include <linux/irqreturn.h>
#include <linux/pci.h>
#include <linux/mei.h>
#include "mei_dev.h"
#include "client.h"
/*
* mei_cfg - mei device configuration
*
* @fw_status: FW status
* @quirk_probe: device exclusion quirk
*/
struct mei_cfg {
const struct mei_fw_status fw_status;
bool (*quirk_probe)(struct pci_dev *pdev);
};
#define MEI_PCI_DEVICE(dev, cfg) \
.vendor = PCI_VENDOR_ID_INTEL, .device = (dev), \
.subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, \
.driver_data = (kernel_ulong_t)&(cfg)
#define MEI_ME_RPM_TIMEOUT 500 /* ms */
/**
* struct mei_me_hw - me hw specific data
*
* @cfg: per device generation config and ops
* @mem_addr: io memory address
* @host_hw_state: cached host state
* @me_hw_state: cached me (fw) state
* @pg_state: power gating state
*/
struct mei_me_hw {
const struct mei_cfg *cfg;
void __iomem *mem_addr;
/*
* hw states of host and fw(ME)

View file

@ -28,11 +28,12 @@
#include "hbm.h"
/**
* mei_txe_reg_read - Reads 32bit data from the device
* mei_txe_reg_read - Reads 32bit data from the txe device
*
* @base_addr: registers base address
* @offset: register offset
*
* Return: register value
*/
static inline u32 mei_txe_reg_read(void __iomem *base_addr,
unsigned long offset)
@ -41,7 +42,7 @@ static inline u32 mei_txe_reg_read(void __iomem *base_addr,
}
/**
* mei_txe_reg_write - Writes 32bit data to the device
* mei_txe_reg_write - Writes 32bit data to the txe device
*
* @base_addr: registers base address
* @offset: register offset
@ -56,10 +57,12 @@ static inline void mei_txe_reg_write(void __iomem *base_addr,
/**
* mei_txe_sec_reg_read_silent - Reads 32bit data from the SeC BAR
*
* @dev: the device structure
* @hw: the txe hardware structure
* @offset: register offset
*
* Doesn't check for aliveness while Reads 32bit data from the SeC BAR
*
* Return: register value
*/
static inline u32 mei_txe_sec_reg_read_silent(struct mei_txe_hw *hw,
unsigned long offset)
@ -70,10 +73,12 @@ static inline u32 mei_txe_sec_reg_read_silent(struct mei_txe_hw *hw,
/**
* mei_txe_sec_reg_read - Reads 32bit data from the SeC BAR
*
* @dev: the device structure
* @hw: the txe hardware structure
* @offset: register offset
*
* Reads 32bit data from the SeC BAR and shout loud if aliveness is not set
*
* Return: register value
*/
static inline u32 mei_txe_sec_reg_read(struct mei_txe_hw *hw,
unsigned long offset)
@ -85,7 +90,7 @@ static inline u32 mei_txe_sec_reg_read(struct mei_txe_hw *hw,
* mei_txe_sec_reg_write_silent - Writes 32bit data to the SeC BAR
* doesn't check for aliveness
*
* @dev: the device structure
* @hw: the txe hardware structure
* @offset: register offset
* @value: value to write
*
@ -100,7 +105,7 @@ static inline void mei_txe_sec_reg_write_silent(struct mei_txe_hw *hw,
/**
* mei_txe_sec_reg_write - Writes 32bit data to the SeC BAR
*
* @dev: the device structure
* @hw: the txe hardware structure
* @offset: register offset
* @value: value to write
*
@ -115,9 +120,10 @@ static inline void mei_txe_sec_reg_write(struct mei_txe_hw *hw,
/**
* mei_txe_br_reg_read - Reads 32bit data from the Bridge BAR
*
* @hw: the device structure
* @hw: the txe hardware structure
* @offset: offset from which to read the data
*
* Return: the byte read.
*/
static inline u32 mei_txe_br_reg_read(struct mei_txe_hw *hw,
unsigned long offset)
@ -128,7 +134,7 @@ static inline u32 mei_txe_br_reg_read(struct mei_txe_hw *hw,
/**
* mei_txe_br_reg_write - Writes 32bit data to the Bridge BAR
*
* @hw: the device structure
* @hw: the txe hardware structure
* @offset: offset from which to write the data
* @value: the byte to write
*/
@ -147,7 +153,10 @@ static inline void mei_txe_br_reg_write(struct mei_txe_hw *hw,
* Request for aliveness change and returns true if the change is
* really needed and false if aliveness is already
* in the requested state
* Requires device lock to be held
*
* Locking: called under "dev->device_lock" lock
*
* Return: true if request was send
*/
static bool mei_txe_aliveness_set(struct mei_device *dev, u32 req)
{
@ -155,7 +164,7 @@ static bool mei_txe_aliveness_set(struct mei_device *dev, u32 req)
struct mei_txe_hw *hw = to_txe_hw(dev);
bool do_req = hw->aliveness != req;
dev_dbg(&dev->pdev->dev, "Aliveness current=%d request=%d\n",
dev_dbg(dev->dev, "Aliveness current=%d request=%d\n",
hw->aliveness, req);
if (do_req) {
dev->pg_event = MEI_PG_EVENT_WAIT;
@ -172,26 +181,31 @@ static bool mei_txe_aliveness_set(struct mei_device *dev, u32 req)
*
* Extract HICR_HOST_ALIVENESS_RESP_ACK bit from
* from HICR_HOST_ALIVENESS_REQ register value
*
* Return: SICR_HOST_ALIVENESS_REQ_REQUESTED bit value
*/
static u32 mei_txe_aliveness_req_get(struct mei_device *dev)
{
struct mei_txe_hw *hw = to_txe_hw(dev);
u32 reg;
reg = mei_txe_br_reg_read(hw, SICR_HOST_ALIVENESS_REQ_REG);
return reg & SICR_HOST_ALIVENESS_REQ_REQUESTED;
}
/**
* mei_txe_aliveness_get - get aliveness response register value
*
* @dev: the device structure
*
* Extract HICR_HOST_ALIVENESS_RESP_ACK bit
* from HICR_HOST_ALIVENESS_RESP register value
* Return: HICR_HOST_ALIVENESS_RESP_ACK bit from HICR_HOST_ALIVENESS_RESP
* register
*/
static u32 mei_txe_aliveness_get(struct mei_device *dev)
{
struct mei_txe_hw *hw = to_txe_hw(dev);
u32 reg;
reg = mei_txe_br_reg_read(hw, HICR_HOST_ALIVENESS_RESP_REG);
return reg & HICR_HOST_ALIVENESS_RESP_ACK;
}
@ -203,7 +217,8 @@ static u32 mei_txe_aliveness_get(struct mei_device *dev)
* @expected: expected aliveness value
*
* Polls for HICR_HOST_ALIVENESS_RESP.ALIVENESS_RESP to be set
* returns > 0 if the expected value was received, -ETIME otherwise
*
* Return: > 0 if the expected value was received, -ETIME otherwise
*/
static int mei_txe_aliveness_poll(struct mei_device *dev, u32 expected)
{
@ -214,7 +229,7 @@ static int mei_txe_aliveness_poll(struct mei_device *dev, u32 expected)
hw->aliveness = mei_txe_aliveness_get(dev);
if (hw->aliveness == expected) {
dev->pg_event = MEI_PG_EVENT_IDLE;
dev_dbg(&dev->pdev->dev,
dev_dbg(dev->dev,
"aliveness settled after %d msecs\n", t);
return t;
}
@ -225,7 +240,7 @@ static int mei_txe_aliveness_poll(struct mei_device *dev, u32 expected)
} while (t < SEC_ALIVENESS_WAIT_TIMEOUT);
dev->pg_event = MEI_PG_EVENT_IDLE;
dev_err(&dev->pdev->dev, "aliveness timed out\n");
dev_err(dev->dev, "aliveness timed out\n");
return -ETIME;
}
@ -236,7 +251,8 @@ static int mei_txe_aliveness_poll(struct mei_device *dev, u32 expected)
* @expected: expected aliveness value
*
* Waits for HICR_HOST_ALIVENESS_RESP.ALIVENESS_RESP to be set
* returns returns 0 on success and < 0 otherwise
*
* Return: 0 on success and < 0 otherwise
*/
static int mei_txe_aliveness_wait(struct mei_device *dev, u32 expected)
{
@ -259,10 +275,10 @@ static int mei_txe_aliveness_wait(struct mei_device *dev, u32 expected)
ret = hw->aliveness == expected ? 0 : -ETIME;
if (ret)
dev_warn(&dev->pdev->dev, "aliveness timed out = %ld aliveness = %d event = %d\n",
dev_warn(dev->dev, "aliveness timed out = %ld aliveness = %d event = %d\n",
err, hw->aliveness, dev->pg_event);
else
dev_dbg(&dev->pdev->dev, "aliveness settled after = %d msec aliveness = %d event = %d\n",
dev_dbg(dev->dev, "aliveness settled after = %d msec aliveness = %d event = %d\n",
jiffies_to_msecs(timeout - err),
hw->aliveness, dev->pg_event);
@ -274,8 +290,9 @@ static int mei_txe_aliveness_wait(struct mei_device *dev, u32 expected)
* mei_txe_aliveness_set_sync - sets an wait for aliveness to complete
*
* @dev: the device structure
* @req: requested aliveness value
*
* returns returns 0 on success and < 0 otherwise
* Return: 0 on success and < 0 otherwise
*/
int mei_txe_aliveness_set_sync(struct mei_device *dev, u32 req)
{
@ -289,7 +306,7 @@ int mei_txe_aliveness_set_sync(struct mei_device *dev, u32 req)
*
* @dev: the device structure
*
* returns: true is pg supported, false otherwise
* Return: true is pg supported, false otherwise
*/
static bool mei_txe_pg_is_enabled(struct mei_device *dev)
{
@ -302,11 +319,12 @@ static bool mei_txe_pg_is_enabled(struct mei_device *dev)
*
* @dev: the device structure
*
* returns: MEI_PG_OFF if aliveness is on and MEI_PG_ON otherwise
* Return: MEI_PG_OFF if aliveness is on and MEI_PG_ON otherwise
*/
static inline enum mei_pg_state mei_txe_pg_state(struct mei_device *dev)
{
struct mei_txe_hw *hw = to_txe_hw(dev);
return hw->aliveness ? MEI_PG_OFF : MEI_PG_ON;
}
@ -326,9 +344,10 @@ static void mei_txe_input_ready_interrupt_enable(struct mei_device *dev)
}
/**
* mei_txe_input_doorbell_set
* - Sets bit 0 in SEC_IPC_INPUT_DOORBELL.IPC_INPUT_DOORBELL.
* @dev: the device structure
* mei_txe_input_doorbell_set - sets bit 0 in
* SEC_IPC_INPUT_DOORBELL.IPC_INPUT_DOORBELL.
*
* @hw: the txe hardware structure
*/
static void mei_txe_input_doorbell_set(struct mei_txe_hw *hw)
{
@ -340,7 +359,7 @@ static void mei_txe_input_doorbell_set(struct mei_txe_hw *hw)
/**
* mei_txe_output_ready_set - Sets the SICR_SEC_IPC_OUTPUT_STATUS bit to 1
*
* @dev: the device structure
* @hw: the txe hardware structure
*/
static void mei_txe_output_ready_set(struct mei_txe_hw *hw)
{
@ -353,11 +372,14 @@ static void mei_txe_output_ready_set(struct mei_txe_hw *hw)
* mei_txe_is_input_ready - check if TXE is ready for receiving data
*
* @dev: the device structure
*
* Return: true if INPUT STATUS READY bit is set
*/
static bool mei_txe_is_input_ready(struct mei_device *dev)
{
struct mei_txe_hw *hw = to_txe_hw(dev);
u32 status;
status = mei_txe_sec_reg_read(hw, SEC_IPC_INPUT_STATUS_REG);
return !!(SEC_IPC_INPUT_STATUS_RDY & status);
}
@ -370,6 +392,7 @@ static bool mei_txe_is_input_ready(struct mei_device *dev)
static inline void mei_txe_intr_clear(struct mei_device *dev)
{
struct mei_txe_hw *hw = to_txe_hw(dev);
mei_txe_sec_reg_write_silent(hw, SEC_IPC_HOST_INT_STATUS_REG,
SEC_IPC_HOST_INT_STATUS_PENDING);
mei_txe_br_reg_write(hw, HISR_REG, HISR_INT_STS_MSK);
@ -384,6 +407,7 @@ static inline void mei_txe_intr_clear(struct mei_device *dev)
static void mei_txe_intr_disable(struct mei_device *dev)
{
struct mei_txe_hw *hw = to_txe_hw(dev);
mei_txe_br_reg_write(hw, HHIER_REG, 0);
mei_txe_br_reg_write(hw, HIER_REG, 0);
}
@ -395,6 +419,7 @@ static void mei_txe_intr_disable(struct mei_device *dev)
static void mei_txe_intr_enable(struct mei_device *dev)
{
struct mei_txe_hw *hw = to_txe_hw(dev);
mei_txe_br_reg_write(hw, HHIER_REG, IPC_HHIER_MSK);
mei_txe_br_reg_write(hw, HIER_REG, HIER_INT_EN_MSK);
}
@ -407,6 +432,8 @@ static void mei_txe_intr_enable(struct mei_device *dev)
*
* Checks if there are pending interrupts
* only Aliveness, Readiness, Input ready, and Output doorbell are relevant
*
* Return: true if there are pending interrupts
*/
static bool mei_txe_pending_interrupts(struct mei_device *dev)
{
@ -418,7 +445,7 @@ static bool mei_txe_pending_interrupts(struct mei_device *dev)
TXE_INTR_OUT_DB));
if (ret) {
dev_dbg(&dev->pdev->dev,
dev_dbg(dev->dev,
"Pending Interrupts InReady=%01d Readiness=%01d, Aliveness=%01d, OutDoor=%01d\n",
!!(hw->intr_cause & TXE_INTR_IN_READY),
!!(hw->intr_cause & TXE_INTR_READINESS),
@ -440,6 +467,7 @@ static void mei_txe_input_payload_write(struct mei_device *dev,
unsigned long idx, u32 value)
{
struct mei_txe_hw *hw = to_txe_hw(dev);
mei_txe_sec_reg_write(hw, SEC_IPC_INPUT_PAYLOAD_REG +
(idx * sizeof(u32)), value);
}
@ -451,12 +479,13 @@ static void mei_txe_input_payload_write(struct mei_device *dev,
* @dev: the device structure
* @idx: index in the device buffer
*
* returns register value at index
* Return: register value at index
*/
static u32 mei_txe_out_data_read(const struct mei_device *dev,
unsigned long idx)
{
struct mei_txe_hw *hw = to_txe_hw(dev);
return mei_txe_br_reg_read(hw,
BRIDGE_IPC_OUTPUT_PAYLOAD_REG + (idx * sizeof(u32)));
}
@ -464,26 +493,28 @@ static u32 mei_txe_out_data_read(const struct mei_device *dev,
/* Readiness */
/**
* mei_txe_readiness_set_host_rdy
* mei_txe_readiness_set_host_rdy - set host readiness bit
*
* @dev: the device structure
*/
static void mei_txe_readiness_set_host_rdy(struct mei_device *dev)
{
struct mei_txe_hw *hw = to_txe_hw(dev);
mei_txe_br_reg_write(hw,
SICR_HOST_IPC_READINESS_REQ_REG,
SICR_HOST_IPC_READINESS_HOST_RDY);
}
/**
* mei_txe_readiness_clear
* mei_txe_readiness_clear - clear host readiness bit
*
* @dev: the device structure
*/
static void mei_txe_readiness_clear(struct mei_device *dev)
{
struct mei_txe_hw *hw = to_txe_hw(dev);
mei_txe_br_reg_write(hw, SICR_HOST_IPC_READINESS_REQ_REG,
SICR_HOST_IPC_READINESS_RDY_CLR);
}
@ -492,10 +523,13 @@ static void mei_txe_readiness_clear(struct mei_device *dev)
* the HICR_SEC_IPC_READINESS register value
*
* @dev: the device structure
*
* Return: the HICR_SEC_IPC_READINESS register value
*/
static u32 mei_txe_readiness_get(struct mei_device *dev)
{
struct mei_txe_hw *hw = to_txe_hw(dev);
return mei_txe_br_reg_read(hw, HICR_SEC_IPC_READINESS_REG);
}
@ -504,7 +538,9 @@ static u32 mei_txe_readiness_get(struct mei_device *dev)
* mei_txe_readiness_is_sec_rdy - check readiness
* for HICR_SEC_IPC_READINESS_SEC_RDY
*
* @readiness - cached readiness state
* @readiness: cached readiness state
*
* Return: true if readiness bit is set
*/
static inline bool mei_txe_readiness_is_sec_rdy(u32 readiness)
{
@ -515,10 +551,13 @@ static inline bool mei_txe_readiness_is_sec_rdy(u32 readiness)
* mei_txe_hw_is_ready - check if the hw is ready
*
* @dev: the device structure
*
* Return: true if sec is ready
*/
static bool mei_txe_hw_is_ready(struct mei_device *dev)
{
u32 readiness = mei_txe_readiness_get(dev);
return mei_txe_readiness_is_sec_rdy(readiness);
}
@ -526,11 +565,14 @@ static bool mei_txe_hw_is_ready(struct mei_device *dev)
* mei_txe_host_is_ready - check if the host is ready
*
* @dev: the device structure
*
* Return: true if host is ready
*/
static inline bool mei_txe_host_is_ready(struct mei_device *dev)
{
struct mei_txe_hw *hw = to_txe_hw(dev);
u32 reg = mei_txe_br_reg_read(hw, HICR_SEC_IPC_READINESS_REG);
return !!(reg & HICR_SEC_IPC_READINESS_HOST_RDY);
}
@ -539,7 +581,7 @@ static inline bool mei_txe_host_is_ready(struct mei_device *dev)
*
* @dev: the device structure
*
* returns 0 on success and -ETIME on timeout
* Return: 0 on success and -ETIME on timeout
*/
static int mei_txe_readiness_wait(struct mei_device *dev)
{
@ -551,7 +593,7 @@ static int mei_txe_readiness_wait(struct mei_device *dev)
msecs_to_jiffies(SEC_RESET_WAIT_TIMEOUT));
mutex_lock(&dev->device_lock);
if (!dev->recvd_hw_ready) {
dev_err(&dev->pdev->dev, "wait for readiness failed\n");
dev_err(dev->dev, "wait for readiness failed\n");
return -ETIME;
}
@ -559,6 +601,42 @@ static int mei_txe_readiness_wait(struct mei_device *dev)
return 0;
}
static const struct mei_fw_status mei_txe_fw_sts = {
.count = 2,
.status[0] = PCI_CFG_TXE_FW_STS0,
.status[1] = PCI_CFG_TXE_FW_STS1
};
/**
* mei_txe_fw_status - read fw status register from pci config space
*
* @dev: mei device
* @fw_status: fw status register values
*
* Return: 0 on success, error otherwise
*/
static int mei_txe_fw_status(struct mei_device *dev,
struct mei_fw_status *fw_status)
{
const struct mei_fw_status *fw_src = &mei_txe_fw_sts;
struct pci_dev *pdev = to_pci_dev(dev->dev);
int ret;
int i;
if (!fw_status)
return -EINVAL;
fw_status->count = fw_src->count;
for (i = 0; i < fw_src->count && i < MEI_FW_STATUS_MAX; i++) {
ret = pci_read_config_dword(pdev,
fw_src->status[i], &fw_status->status[i]);
if (ret)
return ret;
}
return 0;
}
/**
* mei_txe_hw_config - configure hardware at the start of the devices
*
@ -571,13 +649,14 @@ static void mei_txe_hw_config(struct mei_device *dev)
{
struct mei_txe_hw *hw = to_txe_hw(dev);
/* Doesn't change in runtime */
dev->hbuf_depth = PAYLOAD_SIZE / 4;
hw->aliveness = mei_txe_aliveness_get(dev);
hw->readiness = mei_txe_readiness_get(dev);
dev_dbg(&dev->pdev->dev, "aliveness_resp = 0x%08x, readiness = 0x%08x.\n",
dev_dbg(dev->dev, "aliveness_resp = 0x%08x, readiness = 0x%08x.\n",
hw->aliveness, hw->readiness);
}
@ -588,7 +667,8 @@ static void mei_txe_hw_config(struct mei_device *dev)
* @dev: the device structure
* @header: header of message
* @buf: message buffer will be written
* returns 1 if success, 0 - otherwise.
*
* Return: 0 if success, <0 - otherwise.
*/
static int mei_txe_write(struct mei_device *dev,
@ -607,7 +687,7 @@ static int mei_txe_write(struct mei_device *dev,
length = header->length;
dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(header));
dev_dbg(dev->dev, MEI_HDR_FMT, MEI_HDR_PRM(header));
dw_cnt = mei_data2slots(length);
if (dw_cnt > slots)
@ -621,8 +701,9 @@ static int mei_txe_write(struct mei_device *dev,
if (!mei_txe_is_input_ready(dev)) {
struct mei_fw_status fw_status;
mei_fw_status(dev, &fw_status);
dev_err(&dev->pdev->dev, "Input is not ready " FW_STS_FMT "\n",
dev_err(dev->dev, "Input is not ready " FW_STS_FMT "\n",
FW_STS_PRM(fw_status));
return -EAGAIN;
}
@ -635,6 +716,7 @@ static int mei_txe_write(struct mei_device *dev,
rem = length & 0x3;
if (rem > 0) {
u32 reg = 0;
memcpy(&reg, &buf[length - rem], rem);
mei_txe_input_payload_write(dev, i + 1, reg);
}
@ -653,7 +735,7 @@ static int mei_txe_write(struct mei_device *dev,
*
* @dev: the device structure
*
* returns the PAYLOAD_SIZE - 4
* Return: the PAYLOAD_SIZE - 4
*/
static size_t mei_txe_hbuf_max_len(const struct mei_device *dev)
{
@ -665,11 +747,12 @@ static size_t mei_txe_hbuf_max_len(const struct mei_device *dev)
*
* @dev: the device structure
*
* returns always hbuf_depth
* Return: always hbuf_depth
*/
static int mei_txe_hbuf_empty_slots(struct mei_device *dev)
{
struct mei_txe_hw *hw = to_txe_hw(dev);
return hw->slots;
}
@ -678,7 +761,7 @@ static int mei_txe_hbuf_empty_slots(struct mei_device *dev)
*
* @dev: the device structure
*
* returns always buffer size in dwords count
* Return: always buffer size in dwords count
*/
static int mei_txe_count_full_read_slots(struct mei_device *dev)
{
@ -691,7 +774,7 @@ static int mei_txe_count_full_read_slots(struct mei_device *dev)
*
* @dev: the device structure
*
* returns mei message header
* Return: mei message header
*/
static u32 mei_txe_read_hdr(const struct mei_device *dev)
@ -705,33 +788,35 @@ static u32 mei_txe_read_hdr(const struct mei_device *dev)
* @buf: message buffer will be written
* @len: message size will be read
*
* returns -EINVAL on error wrong argument and 0 on success
* Return: -EINVAL on error wrong argument and 0 on success
*/
static int mei_txe_read(struct mei_device *dev,
unsigned char *buf, unsigned long len)
{
struct mei_txe_hw *hw = to_txe_hw(dev);
u32 *reg_buf, reg;
u32 rem;
u32 i;
u32 *reg_buf = (u32 *)buf;
u32 rem = len & 0x3;
if (WARN_ON(!buf || !len))
return -EINVAL;
dev_dbg(&dev->pdev->dev,
"buffer-length = %lu buf[0]0x%08X\n",
reg_buf = (u32 *)buf;
rem = len & 0x3;
dev_dbg(dev->dev, "buffer-length = %lu buf[0]0x%08X\n",
len, mei_txe_out_data_read(dev, 0));
for (i = 0; i < len / 4; i++) {
/* skip header: index starts from 1 */
u32 reg = mei_txe_out_data_read(dev, i + 1);
dev_dbg(&dev->pdev->dev, "buf[%d] = 0x%08X\n", i, reg);
reg = mei_txe_out_data_read(dev, i + 1);
dev_dbg(dev->dev, "buf[%d] = 0x%08X\n", i, reg);
*reg_buf++ = reg;
}
if (rem) {
u32 reg = mei_txe_out_data_read(dev, i + 1);
reg = mei_txe_out_data_read(dev, i + 1);
memcpy(reg_buf, &reg, rem);
}
@ -745,7 +830,7 @@ static int mei_txe_read(struct mei_device *dev,
* @dev: the device structure
* @intr_enable: if interrupt should be enabled after reset.
*
* returns 0 on success and < 0 in case of error
* Return: 0 on success and < 0 in case of error
*/
static int mei_txe_hw_reset(struct mei_device *dev, bool intr_enable)
{
@ -771,8 +856,7 @@ static int mei_txe_hw_reset(struct mei_device *dev, bool intr_enable)
*/
if (aliveness_req != hw->aliveness)
if (mei_txe_aliveness_poll(dev, aliveness_req) < 0) {
dev_err(&dev->pdev->dev,
"wait for aliveness settle failed ... bailing out\n");
dev_err(dev->dev, "wait for aliveness settle failed ... bailing out\n");
return -EIO;
}
@ -782,14 +866,13 @@ static int mei_txe_hw_reset(struct mei_device *dev, bool intr_enable)
if (aliveness_req) {
mei_txe_aliveness_set(dev, 0);
if (mei_txe_aliveness_poll(dev, 0) < 0) {
dev_err(&dev->pdev->dev,
"wait for aliveness failed ... bailing out\n");
dev_err(dev->dev, "wait for aliveness failed ... bailing out\n");
return -EIO;
}
}
/*
* Set rediness RDY_CLR bit
* Set readiness RDY_CLR bit
*/
mei_txe_readiness_clear(dev);
@ -801,7 +884,7 @@ static int mei_txe_hw_reset(struct mei_device *dev, bool intr_enable)
*
* @dev: the device structure
*
* returns 0 on success and < 0 in case of error
* Return: 0 on success an error code otherwise
*/
static int mei_txe_hw_start(struct mei_device *dev)
{
@ -815,7 +898,7 @@ static int mei_txe_hw_start(struct mei_device *dev)
ret = mei_txe_readiness_wait(dev);
if (ret < 0) {
dev_err(&dev->pdev->dev, "wating for readiness failed\n");
dev_err(dev->dev, "waiting for readiness failed\n");
return ret;
}
@ -831,7 +914,7 @@ static int mei_txe_hw_start(struct mei_device *dev)
ret = mei_txe_aliveness_set_sync(dev, 1);
if (ret < 0) {
dev_err(&dev->pdev->dev, "wait for aliveness failed ... bailing out\n");
dev_err(dev->dev, "wait for aliveness failed ... bailing out\n");
return ret;
}
@ -857,6 +940,8 @@ static int mei_txe_hw_start(struct mei_device *dev)
*
* @dev: the device structure
* @do_ack: acknowledge interrupts
*
* Return: true if found interrupts to process.
*/
static bool mei_txe_check_and_ack_intrs(struct mei_device *dev, bool do_ack)
{
@ -912,7 +997,8 @@ out:
* @irq: The irq number
* @dev_id: pointer to the device structure
*
* returns irqreturn_t
* Return: IRQ_WAKE_THREAD if interrupt is designed for the device
* IRQ_NONE otherwise
*/
irqreturn_t mei_txe_irq_quick_handler(int irq, void *dev_id)
{
@ -930,8 +1016,7 @@ irqreturn_t mei_txe_irq_quick_handler(int irq, void *dev_id)
* @irq: The irq number
* @dev_id: pointer to the device structure
*
* returns irqreturn_t
*
* Return: IRQ_HANDLED
*/
irqreturn_t mei_txe_irq_thread_handler(int irq, void *dev_id)
{
@ -941,7 +1026,7 @@ irqreturn_t mei_txe_irq_thread_handler(int irq, void *dev_id)
s32 slots;
int rets = 0;
dev_dbg(&dev->pdev->dev, "irq thread: Interrupt Registers HHISR|HISR|SEC=%02X|%04X|%02X\n",
dev_dbg(dev->dev, "irq thread: Interrupt Registers HHISR|HISR|SEC=%02X|%04X|%02X\n",
mei_txe_br_reg_read(hw, HHISR_REG),
mei_txe_br_reg_read(hw, HISR_REG),
mei_txe_sec_reg_read_silent(hw, SEC_IPC_HOST_INT_STATUS_REG));
@ -951,7 +1036,7 @@ irqreturn_t mei_txe_irq_thread_handler(int irq, void *dev_id)
mutex_lock(&dev->device_lock);
mei_io_list_init(&complete_list);
if (pci_dev_msi_enabled(dev->pdev))
if (pci_dev_msi_enabled(to_pci_dev(dev->dev)))
mei_txe_check_and_ack_intrs(dev, true);
/* show irq events */
@ -965,17 +1050,17 @@ irqreturn_t mei_txe_irq_thread_handler(int irq, void *dev_id)
* or TXE driver resetting the HECI interface.
*/
if (test_and_clear_bit(TXE_INTR_READINESS_BIT, &hw->intr_cause)) {
dev_dbg(&dev->pdev->dev, "Readiness Interrupt was received...\n");
dev_dbg(dev->dev, "Readiness Interrupt was received...\n");
/* Check if SeC is going through reset */
if (mei_txe_readiness_is_sec_rdy(hw->readiness)) {
dev_dbg(&dev->pdev->dev, "we need to start the dev.\n");
dev_dbg(dev->dev, "we need to start the dev.\n");
dev->recvd_hw_ready = true;
} else {
dev->recvd_hw_ready = false;
if (dev->dev_state != MEI_DEV_RESETTING) {
dev_warn(&dev->pdev->dev, "FW not ready: resetting.\n");
dev_warn(dev->dev, "FW not ready: resetting.\n");
schedule_work(&dev->reset_work);
goto end;
@ -992,7 +1077,7 @@ irqreturn_t mei_txe_irq_thread_handler(int irq, void *dev_id)
if (test_and_clear_bit(TXE_INTR_ALIVENESS_BIT, &hw->intr_cause)) {
/* Clear the interrupt cause */
dev_dbg(&dev->pdev->dev,
dev_dbg(dev->dev,
"Aliveness Interrupt: Status: %d\n", hw->aliveness);
dev->pg_event = MEI_PG_EVENT_RECEIVED;
if (waitqueue_active(&hw->wait_aliveness_resp))
@ -1008,7 +1093,7 @@ irqreturn_t mei_txe_irq_thread_handler(int irq, void *dev_id)
/* Read from TXE */
rets = mei_irq_read_handler(dev, &complete_list, &slots);
if (rets && dev->dev_state != MEI_DEV_RESETTING) {
dev_err(&dev->pdev->dev,
dev_err(dev->dev,
"mei_irq_read_handler ret = %d.\n", rets);
schedule_work(&dev->reset_work);
@ -1026,7 +1111,7 @@ irqreturn_t mei_txe_irq_thread_handler(int irq, void *dev_id)
dev->hbuf_is_ready = mei_hbuf_is_ready(dev);
rets = mei_irq_write_handler(dev, &complete_list);
if (rets && rets != -EMSGSIZE)
dev_err(&dev->pdev->dev, "mei_irq_write_handler ret = %d.\n",
dev_err(dev->dev, "mei_irq_write_handler ret = %d.\n",
rets);
dev->hbuf_is_ready = mei_hbuf_is_ready(dev);
}
@ -1034,7 +1119,7 @@ irqreturn_t mei_txe_irq_thread_handler(int irq, void *dev_id)
mei_irq_compl_handler(dev, &complete_list);
end:
dev_dbg(&dev->pdev->dev, "interrupt thread end ret = %d\n", rets);
dev_dbg(dev->dev, "interrupt thread end ret = %d\n", rets);
mutex_unlock(&dev->device_lock);
@ -1046,6 +1131,7 @@ static const struct mei_hw_ops mei_txe_hw_ops = {
.host_is_ready = mei_txe_host_is_ready,
.fw_status = mei_txe_fw_status,
.pg_state = mei_txe_pg_state,
.hw_is_ready = mei_txe_hw_is_ready,
@ -1072,27 +1158,14 @@ static const struct mei_hw_ops mei_txe_hw_ops = {
};
#define MEI_CFG_TXE_FW_STS \
.fw_status.count = 2, \
.fw_status.status[0] = PCI_CFG_TXE_FW_STS0, \
.fw_status.status[1] = PCI_CFG_TXE_FW_STS1
const struct mei_cfg mei_txe_cfg = {
MEI_CFG_TXE_FW_STS,
};
/**
* mei_txe_dev_init - allocates and initializes txe hardware specific structure
*
* @pdev - pci device
* @cfg - per device generation config
*
* returns struct mei_device * on success or NULL;
* @pdev: pci device
*
* Return: struct mei_device * on success or NULL
*/
struct mei_device *mei_txe_dev_init(struct pci_dev *pdev,
const struct mei_cfg *cfg)
struct mei_device *mei_txe_dev_init(struct pci_dev *pdev)
{
struct mei_device *dev;
struct mei_txe_hw *hw;
@ -1102,15 +1175,12 @@ struct mei_device *mei_txe_dev_init(struct pci_dev *pdev,
if (!dev)
return NULL;
mei_device_init(dev, cfg);
mei_device_init(dev, &pdev->dev, &mei_txe_hw_ops);
hw = to_txe_hw(dev);
init_waitqueue_head(&hw->wait_aliveness_resp);
dev->ops = &mei_txe_hw_ops;
dev->pdev = pdev;
return dev;
}
@ -1120,6 +1190,8 @@ struct mei_device *mei_txe_dev_init(struct pci_dev *pdev,
* @dev: the device structure
* @addr: physical address start of the range
* @range: physical range size
*
* Return: 0 on success an error code otherwise
*/
int mei_txe_setup_satt2(struct mei_device *dev, phys_addr_t addr, u32 range)
{
@ -1151,7 +1223,7 @@ int mei_txe_setup_satt2(struct mei_device *dev, phys_addr_t addr, u32 range)
mei_txe_br_reg_write(hw, SATT2_SAP_SIZE_REG, range);
mei_txe_br_reg_write(hw, SATT2_BRG_BA_LSB_REG, lo32);
mei_txe_br_reg_write(hw, SATT2_CTRL_REG, ctrl);
dev_dbg(&dev->pdev->dev, "SATT2: SAP_SIZE_OFFSET=0x%08X, BRG_BA_LSB_OFFSET=0x%08X, CTRL_OFFSET=0x%08X\n",
dev_dbg(dev->dev, "SATT2: SAP_SIZE_OFFSET=0x%08X, BRG_BA_LSB_OFFSET=0x%08X, CTRL_OFFSET=0x%08X\n",
range, lo32, ctrl);
return 0;

View file

@ -40,6 +40,7 @@
* @mem_addr: SeC and BRIDGE bars
* @aliveness: aliveness (power gating) state of the hardware
* @readiness: readiness state of the hardware
* @slots: number of empty slots
* @wait_aliveness_resp: aliveness wait queue
* @intr_cause: translated interrupt cause
*/
@ -61,10 +62,7 @@ static inline struct mei_device *hw_txe_to_mei(struct mei_txe_hw *hw)
return container_of((void *)hw, struct mei_device, hw);
}
extern const struct mei_cfg mei_txe_cfg;
struct mei_device *mei_txe_dev_init(struct pci_dev *pdev,
const struct mei_cfg *cfg);
struct mei_device *mei_txe_dev_init(struct pci_dev *pdev);
irqreturn_t mei_txe_irq_quick_handler(int irq, void *dev_id);
irqreturn_t mei_txe_irq_thread_handler(int irq, void *dev_id);

View file

@ -97,23 +97,52 @@ enum mei_stop_reason_types {
SYSTEM_S5_ENTRY = 0x08
};
/**
* enum mei_hbm_status - mei host bus messages return values
*
* @MEI_HBMS_SUCCESS : status success
* @MEI_HBMS_CLIENT_NOT_FOUND : client not found
* @MEI_HBMS_ALREADY_EXISTS : connection already established
* @MEI_HBMS_REJECTED : connection is rejected
* @MEI_HBMS_INVALID_PARAMETER : invalid parameter
* @MEI_HBMS_NOT_ALLOWED : operation not allowed
* @MEI_HBMS_ALREADY_STARTED : system is already started
* @MEI_HBMS_NOT_STARTED : system not started
*
* @MEI_HBMS_MAX : sentinel
*/
enum mei_hbm_status {
MEI_HBMS_SUCCESS = 0,
MEI_HBMS_CLIENT_NOT_FOUND = 1,
MEI_HBMS_ALREADY_EXISTS = 2,
MEI_HBMS_REJECTED = 3,
MEI_HBMS_INVALID_PARAMETER = 4,
MEI_HBMS_NOT_ALLOWED = 5,
MEI_HBMS_ALREADY_STARTED = 6,
MEI_HBMS_NOT_STARTED = 7,
MEI_HBMS_MAX
};
/*
* Client Connect Status
* used by hbm_client_connect_response.status
*/
enum mei_cl_connect_status {
MEI_CL_CONN_SUCCESS = 0x00,
MEI_CL_CONN_NOT_FOUND = 0x01,
MEI_CL_CONN_ALREADY_STARTED = 0x02,
MEI_CL_CONN_OUT_OF_RESOURCES = 0x03,
MEI_CL_CONN_MESSAGE_SMALL = 0x04
MEI_CL_CONN_SUCCESS = MEI_HBMS_SUCCESS,
MEI_CL_CONN_NOT_FOUND = MEI_HBMS_CLIENT_NOT_FOUND,
MEI_CL_CONN_ALREADY_STARTED = MEI_HBMS_ALREADY_EXISTS,
MEI_CL_CONN_OUT_OF_RESOURCES = MEI_HBMS_REJECTED,
MEI_CL_CONN_MESSAGE_SMALL = MEI_HBMS_INVALID_PARAMETER,
};
/*
* Client Disconnect Status
*/
enum mei_cl_disconnect_status {
MEI_CL_DISCONN_SUCCESS = 0x00
MEI_CL_DISCONN_SUCCESS = MEI_HBMS_SUCCESS
};
/*
@ -138,10 +167,10 @@ struct mei_bus_message {
* struct hbm_cl_cmd - client specific host bus command
* CONNECT, DISCONNECT, and FlOW CONTROL
*
* @hbm_cmd - bus message command header
* @me_addr - address of the client in ME
* @host_addr - address of the client in the driver
* @data
* @hbm_cmd: bus message command header
* @me_addr: address of the client in ME
* @host_addr: address of the client in the driver
* @data: generic data
*/
struct mei_hbm_cl_cmd {
u8 hbm_cmd;
@ -206,14 +235,13 @@ struct mei_client_properties {
struct hbm_props_request {
u8 hbm_cmd;
u8 address;
u8 me_addr;
u8 reserved[2];
} __packed;
struct hbm_props_response {
u8 hbm_cmd;
u8 address;
u8 me_addr;
u8 status;
u8 reserved[1];
struct mei_client_properties client_properties;
@ -222,8 +250,8 @@ struct hbm_props_response {
/**
* struct hbm_power_gate - power gate request/response
*
* @hbm_cmd - bus message command header
* @reserved[3]
* @hbm_cmd: bus message command header
* @reserved: reserved
*/
struct hbm_power_gate {
u8 hbm_cmd;
@ -233,10 +261,10 @@ struct hbm_power_gate {
/**
* struct hbm_client_connect_request - connect/disconnect request
*
* @hbm_cmd - bus message command header
* @me_addr - address of the client in ME
* @host_addr - address of the client in the driver
* @reserved
* @hbm_cmd: bus message command header
* @me_addr: address of the client in ME
* @host_addr: address of the client in the driver
* @reserved: reserved
*/
struct hbm_client_connect_request {
u8 hbm_cmd;
@ -248,10 +276,10 @@ struct hbm_client_connect_request {
/**
* struct hbm_client_connect_response - connect/disconnect response
*
* @hbm_cmd - bus message command header
* @me_addr - address of the client in ME
* @host_addr - address of the client in the driver
* @status - status of the request
* @hbm_cmd: bus message command header
* @me_addr: address of the client in ME
* @host_addr: address of the client in the driver
* @status: status of the request
*/
struct hbm_client_connect_response {
u8 hbm_cmd;

View file

@ -15,7 +15,6 @@
*/
#include <linux/export.h>
#include <linux/pci.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/delay.h>
@ -43,13 +42,23 @@ const char *mei_dev_state_str(int state)
#undef MEI_DEV_STATE
}
const char *mei_pg_state_str(enum mei_pg_state state)
{
#define MEI_PG_STATE(state) case MEI_PG_##state: return #state
switch (state) {
MEI_PG_STATE(OFF);
MEI_PG_STATE(ON);
default:
return "unknown";
}
#undef MEI_PG_STATE
}
/**
* mei_cancel_work. Cancel mei background jobs
* mei_cancel_work - Cancel mei background jobs
*
* @dev: the device structure
*
* returns 0 on success or < 0 if the reset hasn't succeeded
*/
void mei_cancel_work(struct mei_device *dev)
{
@ -64,6 +73,8 @@ EXPORT_SYMBOL_GPL(mei_cancel_work);
* mei_reset - resets host and fw.
*
* @dev: the device structure
*
* Return: 0 on success or < 0 if the reset hasn't succeeded
*/
int mei_reset(struct mei_device *dev)
{
@ -76,8 +87,9 @@ int mei_reset(struct mei_device *dev)
state != MEI_DEV_POWER_DOWN &&
state != MEI_DEV_POWER_UP) {
struct mei_fw_status fw_status;
mei_fw_status(dev, &fw_status);
dev_warn(&dev->pdev->dev,
dev_warn(dev->dev,
"unexpected reset: dev_state = %s " FW_STS_FMT "\n",
mei_dev_state_str(state), FW_STS_PRM(fw_status));
}
@ -95,7 +107,7 @@ int mei_reset(struct mei_device *dev)
dev->reset_count++;
if (dev->reset_count > MEI_MAX_CONSEC_RESET) {
dev_err(&dev->pdev->dev, "reset: reached maximal consecutive resets: disabling the device\n");
dev_err(dev->dev, "reset: reached maximal consecutive resets: disabling the device\n");
dev->dev_state = MEI_DEV_DISABLED;
return -ENODEV;
}
@ -116,7 +128,7 @@ int mei_reset(struct mei_device *dev)
mei_cl_all_wakeup(dev);
/* remove entry if already in list */
dev_dbg(&dev->pdev->dev, "remove iamthif and wd from the file list.\n");
dev_dbg(dev->dev, "remove iamthif and wd from the file list.\n");
mei_cl_unlink(&dev->wd_cl);
mei_cl_unlink(&dev->iamthif_cl);
mei_amthif_reset_params(dev);
@ -128,28 +140,28 @@ int mei_reset(struct mei_device *dev)
dev->wd_pending = false;
if (ret) {
dev_err(&dev->pdev->dev, "hw_reset failed ret = %d\n", ret);
dev_err(dev->dev, "hw_reset failed ret = %d\n", ret);
return ret;
}
if (state == MEI_DEV_POWER_DOWN) {
dev_dbg(&dev->pdev->dev, "powering down: end of reset\n");
dev_dbg(dev->dev, "powering down: end of reset\n");
dev->dev_state = MEI_DEV_DISABLED;
return 0;
}
ret = mei_hw_start(dev);
if (ret) {
dev_err(&dev->pdev->dev, "hw_start failed ret = %d\n", ret);
dev_err(dev->dev, "hw_start failed ret = %d\n", ret);
return ret;
}
dev_dbg(&dev->pdev->dev, "link is established start sending messages.\n");
dev_dbg(dev->dev, "link is established start sending messages.\n");
dev->dev_state = MEI_DEV_INIT_CLIENTS;
ret = mei_hbm_start_req(dev);
if (ret) {
dev_err(&dev->pdev->dev, "hbm_start failed ret = %d\n", ret);
dev_err(dev->dev, "hbm_start failed ret = %d\n", ret);
dev->dev_state = MEI_DEV_RESETTING;
return ret;
}
@ -163,11 +175,12 @@ EXPORT_SYMBOL_GPL(mei_reset);
*
* @dev: the device structure
*
* returns 0 on success, <0 on failure.
* Return: 0 on success, <0 on failure.
*/
int mei_start(struct mei_device *dev)
{
int ret;
mutex_lock(&dev->device_lock);
/* acknowledge interrupt and stop interrupts */
@ -175,7 +188,7 @@ int mei_start(struct mei_device *dev)
mei_hw_config(dev);
dev_dbg(&dev->pdev->dev, "reset in start the mei device.\n");
dev_dbg(dev->dev, "reset in start the mei device.\n");
dev->reset_count = 0;
do {
@ -183,43 +196,43 @@ int mei_start(struct mei_device *dev)
ret = mei_reset(dev);
if (ret == -ENODEV || dev->dev_state == MEI_DEV_DISABLED) {
dev_err(&dev->pdev->dev, "reset failed ret = %d", ret);
dev_err(dev->dev, "reset failed ret = %d", ret);
goto err;
}
} while (ret);
/* we cannot start the device w/o hbm start message completed */
if (dev->dev_state == MEI_DEV_DISABLED) {
dev_err(&dev->pdev->dev, "reset failed");
dev_err(dev->dev, "reset failed");
goto err;
}
if (mei_hbm_start_wait(dev)) {
dev_err(&dev->pdev->dev, "HBM haven't started");
dev_err(dev->dev, "HBM haven't started");
goto err;
}
if (!mei_host_is_ready(dev)) {
dev_err(&dev->pdev->dev, "host is not ready.\n");
dev_err(dev->dev, "host is not ready.\n");
goto err;
}
if (!mei_hw_is_ready(dev)) {
dev_err(&dev->pdev->dev, "ME is not ready.\n");
dev_err(dev->dev, "ME is not ready.\n");
goto err;
}
if (!mei_hbm_version_is_supported(dev)) {
dev_dbg(&dev->pdev->dev, "MEI start failed.\n");
dev_dbg(dev->dev, "MEI start failed.\n");
goto err;
}
dev_dbg(&dev->pdev->dev, "link layer has been established.\n");
dev_dbg(dev->dev, "link layer has been established.\n");
mutex_unlock(&dev->device_lock);
return 0;
err:
dev_err(&dev->pdev->dev, "link layer initialization failed.\n");
dev_err(dev->dev, "link layer initialization failed.\n");
dev->dev_state = MEI_DEV_DISABLED;
mutex_unlock(&dev->device_lock);
return -ENODEV;
@ -231,7 +244,7 @@ EXPORT_SYMBOL_GPL(mei_start);
*
* @dev: the device structure
*
* returns 0 on success or -ENODEV if the restart hasn't succeeded
* Return: 0 on success or -ENODEV if the restart hasn't succeeded
*/
int mei_restart(struct mei_device *dev)
{
@ -249,7 +262,7 @@ int mei_restart(struct mei_device *dev)
mutex_unlock(&dev->device_lock);
if (err == -ENODEV || dev->dev_state == MEI_DEV_DISABLED) {
dev_err(&dev->pdev->dev, "device disabled = %d\n", err);
dev_err(dev->dev, "device disabled = %d\n", err);
return -ENODEV;
}
@ -275,7 +288,7 @@ static void mei_reset_work(struct work_struct *work)
mutex_unlock(&dev->device_lock);
if (dev->dev_state == MEI_DEV_DISABLED) {
dev_err(&dev->pdev->dev, "device disabled = %d\n", ret);
dev_err(dev->dev, "device disabled = %d\n", ret);
return;
}
@ -286,7 +299,7 @@ static void mei_reset_work(struct work_struct *work)
void mei_stop(struct mei_device *dev)
{
dev_dbg(&dev->pdev->dev, "stopping the device.\n");
dev_dbg(dev->dev, "stopping the device.\n");
mei_cancel_work(dev);
@ -312,7 +325,7 @@ EXPORT_SYMBOL_GPL(mei_stop);
*
* @dev: the device structure
*
* returns true of there is no pending write
* Return: true of there is no pending write
*/
bool mei_write_is_idle(struct mei_device *dev)
{
@ -320,7 +333,7 @@ bool mei_write_is_idle(struct mei_device *dev)
list_empty(&dev->ctrl_wr_list.list) &&
list_empty(&dev->write_list.list));
dev_dbg(&dev->pdev->dev, "write pg: is idle[%d] state=%s ctrl=%d write=%d\n",
dev_dbg(dev->dev, "write pg: is idle[%d] state=%s ctrl=%d write=%d\n",
idle,
mei_dev_state_str(dev->dev_state),
list_empty(&dev->ctrl_wr_list.list),
@ -330,36 +343,25 @@ bool mei_write_is_idle(struct mei_device *dev)
}
EXPORT_SYMBOL_GPL(mei_write_is_idle);
int mei_fw_status(struct mei_device *dev, struct mei_fw_status *fw_status)
{
int i;
const struct mei_fw_status *fw_src = &dev->cfg->fw_status;
if (!fw_status)
return -EINVAL;
fw_status->count = fw_src->count;
for (i = 0; i < fw_src->count && i < MEI_FW_STATUS_MAX; i++) {
int ret;
ret = pci_read_config_dword(dev->pdev,
fw_src->status[i], &fw_status->status[i]);
if (ret)
return ret;
}
return 0;
}
EXPORT_SYMBOL_GPL(mei_fw_status);
void mei_device_init(struct mei_device *dev, const struct mei_cfg *cfg)
/**
* mei_device_init -- initialize mei_device structure
*
* @dev: the mei device
* @device: the device structure
* @hw_ops: hw operations
*/
void mei_device_init(struct mei_device *dev,
struct device *device,
const struct mei_hw_ops *hw_ops)
{
/* setup our list array */
INIT_LIST_HEAD(&dev->file_list);
INIT_LIST_HEAD(&dev->device_list);
INIT_LIST_HEAD(&dev->me_clients);
mutex_init(&dev->device_lock);
init_waitqueue_head(&dev->wait_hw_ready);
init_waitqueue_head(&dev->wait_pg);
init_waitqueue_head(&dev->wait_recvd_msg);
init_waitqueue_head(&dev->wait_hbm_start);
init_waitqueue_head(&dev->wait_stop_wd);
dev->dev_state = MEI_DEV_INITIALIZING;
dev->reset_count = 0;
@ -389,7 +391,8 @@ void mei_device_init(struct mei_device *dev, const struct mei_cfg *cfg)
bitmap_set(dev->host_clients_map, 0, 1);
dev->pg_event = MEI_PG_EVENT_IDLE;
dev->cfg = cfg;
dev->ops = hw_ops;
dev->dev = device;
}
EXPORT_SYMBOL_GPL(mei_device_init);

View file

@ -16,11 +16,11 @@
#include <linux/export.h>
#include <linux/pci.h>
#include <linux/kthread.h>
#include <linux/interrupt.h>
#include <linux/fs.h>
#include <linux/jiffies.h>
#include <linux/slab.h>
#include <linux/mei.h>
@ -33,8 +33,8 @@
* mei_irq_compl_handler - dispatch complete handlers
* for the completed callbacks
*
* @dev - mei device
* @compl_list - list of completed cbs
* @dev: mei device
* @compl_list: list of completed cbs
*/
void mei_irq_compl_handler(struct mei_device *dev, struct mei_cl_cb *compl_list)
{
@ -47,7 +47,7 @@ void mei_irq_compl_handler(struct mei_device *dev, struct mei_cl_cb *compl_list)
if (!cl)
continue;
dev_dbg(&dev->pdev->dev, "completing call back.\n");
dev_dbg(dev->dev, "completing call back.\n");
if (cl == &dev->iamthif_cl)
mei_amthif_complete(dev, cb);
else
@ -62,7 +62,7 @@ EXPORT_SYMBOL_GPL(mei_irq_compl_handler);
* @cl: host client
* @mei_hdr: header of mei client message
*
* returns true if matches, false otherwise
* Return: true if matches, false otherwise
*/
static inline int mei_cl_hbm_equal(struct mei_cl *cl,
struct mei_msg_hdr *mei_hdr)
@ -72,12 +72,12 @@ static inline int mei_cl_hbm_equal(struct mei_cl *cl,
}
/**
* mei_cl_is_reading - checks if the client
is the one to read this message
* is the one to read this message
*
* @cl: mei client
* @mei_hdr: header of mei message
*
* returns true on match and false otherwise
* Return: true on match and false otherwise
*/
static bool mei_cl_is_reading(struct mei_cl *cl, struct mei_msg_hdr *mei_hdr)
{
@ -87,13 +87,13 @@ static bool mei_cl_is_reading(struct mei_cl *cl, struct mei_msg_hdr *mei_hdr)
}
/**
* mei_irq_read_client_message - process client message
* mei_cl_irq_read_msg - process client message
*
* @dev: the device structure
* @mei_hdr: header of mei client message
* @complete_list: An instance of our list structure
*
* returns 0 on success, <0 on failure.
* Return: 0 on success, <0 on failure.
*/
static int mei_cl_irq_read_msg(struct mei_device *dev,
struct mei_msg_hdr *mei_hdr,
@ -126,7 +126,6 @@ static int mei_cl_irq_read_msg(struct mei_device *dev,
GFP_KERNEL);
if (!buffer) {
cl_err(dev, cl, "allocation failed.\n");
list_del(&cb->list);
return -ENOMEM;
}
@ -149,10 +148,10 @@ static int mei_cl_irq_read_msg(struct mei_device *dev,
break;
}
dev_dbg(&dev->pdev->dev, "message read\n");
dev_dbg(dev->dev, "message read\n");
if (!buffer) {
mei_read_slots(dev, dev->rd_msg_buf, mei_hdr->length);
dev_dbg(&dev->pdev->dev, "discarding message " MEI_HDR_FMT "\n",
dev_dbg(dev->dev, "discarding message " MEI_HDR_FMT "\n",
MEI_HDR_PRM(mei_hdr));
}
@ -166,7 +165,7 @@ static int mei_cl_irq_read_msg(struct mei_device *dev,
* @cb: callback block.
* @cmpl_list: complete list.
*
* returns 0, OK; otherwise, error.
* Return: 0, OK; otherwise, error.
*/
static int mei_cl_irq_disconnect_rsp(struct mei_cl *cl, struct mei_cl_cb *cb,
struct mei_cl_cb *cmpl_list)
@ -195,16 +194,16 @@ static int mei_cl_irq_disconnect_rsp(struct mei_cl *cl, struct mei_cl_cb *cb,
/**
* mei_cl_irq_close - processes close related operation from
* mei_cl_irq_disconnect - processes close related operation from
* interrupt thread context - send disconnect request
*
* @cl: client
* @cb: callback block.
* @cmpl_list: complete list.
*
* returns 0, OK; otherwise, error.
* Return: 0, OK; otherwise, error.
*/
static int mei_cl_irq_close(struct mei_cl *cl, struct mei_cl_cb *cb,
static int mei_cl_irq_disconnect(struct mei_cl *cl, struct mei_cl_cb *cb,
struct mei_cl_cb *cmpl_list)
{
struct mei_device *dev = cl->dev;
@ -235,14 +234,14 @@ static int mei_cl_irq_close(struct mei_cl *cl, struct mei_cl_cb *cb,
/**
* mei_cl_irq_close - processes client read related operation from the
* mei_cl_irq_read - processes client read related operation from the
* interrupt thread context - request for flow control credits
*
* @cl: client
* @cb: callback block.
* @cmpl_list: complete list.
*
* returns 0, OK; otherwise, error.
* Return: 0, OK; otherwise, error.
*/
static int mei_cl_irq_read(struct mei_cl *cl, struct mei_cl_cb *cb,
struct mei_cl_cb *cmpl_list)
@ -279,7 +278,7 @@ static int mei_cl_irq_read(struct mei_cl *cl, struct mei_cl_cb *cb,
* @cb: callback block.
* @cmpl_list: complete list.
*
* returns 0, OK; otherwise, error.
* Return: 0, OK; otherwise, error.
*/
static int mei_cl_irq_connect(struct mei_cl *cl, struct mei_cl_cb *cb,
struct mei_cl_cb *cmpl_list)
@ -322,7 +321,7 @@ static int mei_cl_irq_connect(struct mei_cl *cl, struct mei_cl_cb *cb,
* @cmpl_list: An instance of our list structure
* @slots: slots to read.
*
* returns 0 on success, <0 on failure.
* Return: 0 on success, <0 on failure.
*/
int mei_irq_read_handler(struct mei_device *dev,
struct mei_cl_cb *cmpl_list, s32 *slots)
@ -334,20 +333,20 @@ int mei_irq_read_handler(struct mei_device *dev,
if (!dev->rd_msg_hdr) {
dev->rd_msg_hdr = mei_read_hdr(dev);
(*slots)--;
dev_dbg(&dev->pdev->dev, "slots =%08x.\n", *slots);
dev_dbg(dev->dev, "slots =%08x.\n", *slots);
}
mei_hdr = (struct mei_msg_hdr *) &dev->rd_msg_hdr;
dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(mei_hdr));
dev_dbg(dev->dev, MEI_HDR_FMT, MEI_HDR_PRM(mei_hdr));
if (mei_hdr->reserved || !dev->rd_msg_hdr) {
dev_err(&dev->pdev->dev, "corrupted message header 0x%08X\n",
dev_err(dev->dev, "corrupted message header 0x%08X\n",
dev->rd_msg_hdr);
ret = -EBADMSG;
goto end;
}
if (mei_slots2data(*slots) < mei_hdr->length) {
dev_err(&dev->pdev->dev, "less data available than length=%08x.\n",
dev_err(dev->dev, "less data available than length=%08x.\n",
*slots);
/* we can't read the message */
ret = -ENODATA;
@ -358,7 +357,7 @@ int mei_irq_read_handler(struct mei_device *dev,
if (mei_hdr->host_addr == 0 && mei_hdr->me_addr == 0) {
ret = mei_hbm_dispatch(dev, mei_hdr);
if (ret) {
dev_dbg(&dev->pdev->dev, "mei_hbm_dispatch failed ret = %d\n",
dev_dbg(dev->dev, "mei_hbm_dispatch failed ret = %d\n",
ret);
goto end;
}
@ -375,7 +374,7 @@ int mei_irq_read_handler(struct mei_device *dev,
/* if no recipient cl was found we assume corrupted header */
if (&cl->link == &dev->file_list) {
dev_err(&dev->pdev->dev, "no destination client found 0x%08X\n",
dev_err(dev->dev, "no destination client found 0x%08X\n",
dev->rd_msg_hdr);
ret = -EBADMSG;
goto end;
@ -387,14 +386,14 @@ int mei_irq_read_handler(struct mei_device *dev,
ret = mei_amthif_irq_read_msg(dev, mei_hdr, cmpl_list);
if (ret) {
dev_err(&dev->pdev->dev, "mei_amthif_irq_read_msg failed = %d\n",
dev_err(dev->dev, "mei_amthif_irq_read_msg failed = %d\n",
ret);
goto end;
}
} else {
ret = mei_cl_irq_read_msg(dev, mei_hdr, cmpl_list);
if (ret) {
dev_err(&dev->pdev->dev, "mei_cl_irq_read_msg failed = %d\n",
dev_err(dev->dev, "mei_cl_irq_read_msg failed = %d\n",
ret);
goto end;
}
@ -407,7 +406,7 @@ reset_slots:
if (*slots == -EOVERFLOW) {
/* overflow - reset */
dev_err(&dev->pdev->dev, "resetting due to slots overflow.\n");
dev_err(dev->dev, "resetting due to slots overflow.\n");
/* set the event since message has been read */
ret = -ERANGE;
goto end;
@ -425,7 +424,7 @@ EXPORT_SYMBOL_GPL(mei_irq_read_handler);
* @dev: the device structure
* @cmpl_list: An instance of our list structure
*
* returns 0 on success, <0 on failure.
* Return: 0 on success, <0 on failure.
*/
int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list)
{
@ -445,7 +444,7 @@ int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list)
return -EMSGSIZE;
/* complete all waiting for write CB */
dev_dbg(&dev->pdev->dev, "complete all waiting for write cb.\n");
dev_dbg(dev->dev, "complete all waiting for write cb.\n");
list = &dev->write_waiting_list;
list_for_each_entry_safe(cb, next, &list->list, list) {
@ -487,7 +486,7 @@ int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list)
}
/* complete control write list CB */
dev_dbg(&dev->pdev->dev, "complete control write list cb.\n");
dev_dbg(dev->dev, "complete control write list cb.\n");
list_for_each_entry_safe(cb, next, &dev->ctrl_wr_list.list, list) {
cl = cb->cl;
if (!cl) {
@ -495,9 +494,9 @@ int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list)
return -ENODEV;
}
switch (cb->fop_type) {
case MEI_FOP_CLOSE:
case MEI_FOP_DISCONNECT:
/* send disconnect message */
ret = mei_cl_irq_close(cl, cb, cmpl_list);
ret = mei_cl_irq_disconnect(cl, cb, cmpl_list);
if (ret)
return ret;
@ -528,7 +527,7 @@ int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list)
}
/* complete write list CB */
dev_dbg(&dev->pdev->dev, "complete write list cb.\n");
dev_dbg(dev->dev, "complete write list cb.\n");
list_for_each_entry_safe(cb, next, &dev->write_list.list, list) {
cl = cb->cl;
if (cl == NULL)
@ -556,8 +555,6 @@ void mei_timer(struct work_struct *work)
{
unsigned long timeout;
struct mei_cl *cl;
struct mei_cl_cb *cb_pos = NULL;
struct mei_cl_cb *cb_next = NULL;
struct mei_device *dev = container_of(work,
struct mei_device, timer_work.work);
@ -571,7 +568,7 @@ void mei_timer(struct work_struct *work)
if (dev->init_clients_timer) {
if (--dev->init_clients_timer == 0) {
dev_err(&dev->pdev->dev, "timer: init clients timeout hbm_state = %d.\n",
dev_err(dev->dev, "timer: init clients timeout hbm_state = %d.\n",
dev->hbm_state);
mei_reset(dev);
goto out;
@ -586,7 +583,7 @@ void mei_timer(struct work_struct *work)
list_for_each_entry(cl, &dev->file_list, link) {
if (cl->timer_count) {
if (--cl->timer_count == 0) {
dev_err(&dev->pdev->dev, "timer: connect/disconnect timeout.\n");
dev_err(dev->dev, "timer: connect/disconnect timeout.\n");
mei_reset(dev);
goto out;
}
@ -598,7 +595,7 @@ void mei_timer(struct work_struct *work)
if (dev->iamthif_stall_timer) {
if (--dev->iamthif_stall_timer == 0) {
dev_err(&dev->pdev->dev, "timer: amthif hanged.\n");
dev_err(dev->dev, "timer: amthif hanged.\n");
mei_reset(dev);
dev->iamthif_msg_buf_size = 0;
dev->iamthif_msg_buf_index = 0;
@ -620,27 +617,20 @@ void mei_timer(struct work_struct *work)
timeout = dev->iamthif_timer +
mei_secs_to_jiffies(MEI_IAMTHIF_READ_TIMER);
dev_dbg(&dev->pdev->dev, "dev->iamthif_timer = %ld\n",
dev_dbg(dev->dev, "dev->iamthif_timer = %ld\n",
dev->iamthif_timer);
dev_dbg(&dev->pdev->dev, "timeout = %ld\n", timeout);
dev_dbg(&dev->pdev->dev, "jiffies = %ld\n", jiffies);
dev_dbg(dev->dev, "timeout = %ld\n", timeout);
dev_dbg(dev->dev, "jiffies = %ld\n", jiffies);
if (time_after(jiffies, timeout)) {
/*
* User didn't read the AMTHI data on time (15sec)
* freeing AMTHI for other requests
*/
dev_dbg(&dev->pdev->dev, "freeing AMTHI for other requests\n");
dev_dbg(dev->dev, "freeing AMTHI for other requests\n");
list_for_each_entry_safe(cb_pos, cb_next,
&dev->amthif_rd_complete_list.list, list) {
cl = cb_pos->file_object->private_data;
/* Finding the AMTHI entry. */
if (cl == &dev->iamthif_cl)
list_del(&cb_pos->list);
}
mei_io_list_flush(&dev->amthif_rd_complete_list,
&dev->iamthif_cl);
mei_io_cb_free(dev->iamthif_current_cb);
dev->iamthif_current_cb = NULL;

View file

@ -17,12 +17,12 @@
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/aio.h>
#include <linux/pci.h>
#include <linux/poll.h>
#include <linux/init.h>
#include <linux/ioctl.h>
@ -44,7 +44,7 @@
* @inode: pointer to inode structure
* @file: pointer to file structure
*
* returns 0 on success, <0 on error
* Return: 0 on success, <0 on error
*/
static int mei_open(struct inode *inode, struct file *file)
{
@ -63,7 +63,7 @@ static int mei_open(struct inode *inode, struct file *file)
err = -ENODEV;
if (dev->dev_state != MEI_DEV_ENABLED) {
dev_dbg(&dev->pdev->dev, "dev_state != MEI_ENABLED dev_state = %s\n",
dev_dbg(dev->dev, "dev_state != MEI_ENABLED dev_state = %s\n",
mei_dev_state_str(dev->dev_state));
goto err_unlock;
}
@ -96,7 +96,7 @@ err_unlock:
* @inode: pointer to inode structure
* @file: pointer to file structure
*
* returns 0 on success, <0 on error
* Return: 0 on success, <0 on error
*/
static int mei_release(struct inode *inode, struct file *file)
{
@ -157,7 +157,7 @@ out:
* @length: buffer length
* @offset: data offset in buffer
*
* returns >=0 data length on success , <0 on error
* Return: >=0 data length on success , <0 on error
*/
static ssize_t mei_read(struct file *file, char __user *ubuf,
size_t length, loff_t *offset)
@ -211,7 +211,7 @@ static ssize_t mei_read(struct file *file, char __user *ubuf,
err = mei_cl_read_start(cl, length);
if (err && err != -EBUSY) {
dev_dbg(&dev->pdev->dev,
dev_dbg(dev->dev,
"mei start read failure with status = %d\n", err);
rets = err;
goto out;
@ -254,7 +254,7 @@ static ssize_t mei_read(struct file *file, char __user *ubuf,
}
/* now copy the data to user space */
copy_buffer:
dev_dbg(&dev->pdev->dev, "buf.size = %d buf.idx= %ld\n",
dev_dbg(dev->dev, "buf.size = %d buf.idx= %ld\n",
cb->response_buffer.size, cb->buf_idx);
if (length == 0 || ubuf == NULL || *offset > cb->buf_idx) {
rets = -EMSGSIZE;
@ -266,7 +266,7 @@ copy_buffer:
length = min_t(size_t, length, cb->buf_idx - *offset);
if (copy_to_user(ubuf, cb->response_buffer.data + *offset, length)) {
dev_dbg(&dev->pdev->dev, "failed to copy data to userland\n");
dev_dbg(dev->dev, "failed to copy data to userland\n");
rets = -EFAULT;
goto free;
}
@ -285,7 +285,7 @@ free:
cl->reading_state = MEI_IDLE;
cl->read_cb = NULL;
out:
dev_dbg(&dev->pdev->dev, "end mei read rets= %d\n", rets);
dev_dbg(dev->dev, "end mei read rets= %d\n", rets);
mutex_unlock(&dev->device_lock);
return rets;
}
@ -297,17 +297,17 @@ out:
* @length: buffer length
* @offset: data offset in buffer
*
* returns >=0 data length on success , <0 on error
* Return: >=0 data length on success , <0 on error
*/
static ssize_t mei_write(struct file *file, const char __user *ubuf,
size_t length, loff_t *offset)
{
struct mei_cl *cl = file->private_data;
struct mei_me_client *me_cl;
struct mei_cl_cb *write_cb = NULL;
struct mei_device *dev;
unsigned long timeout = 0;
int rets;
int id;
if (WARN_ON(!cl || !cl->dev))
return -ENODEV;
@ -321,8 +321,8 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
goto out;
}
id = mei_me_cl_by_id(dev, cl->me_client_id);
if (id < 0) {
me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id);
if (!me_cl) {
rets = -ENOTTY;
goto out;
}
@ -332,13 +332,13 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
goto out;
}
if (length > dev->me_clients[id].props.max_msg_length) {
if (length > me_cl->props.max_msg_length) {
rets = -EFBIG;
goto out;
}
if (cl->state != MEI_FILE_CONNECTED) {
dev_err(&dev->pdev->dev, "host client = %d, is not connected to ME client = %d",
dev_err(dev->dev, "host client = %d, is not connected to ME client = %d",
cl->host_client_id, cl->me_client_id);
rets = -ENODEV;
goto out;
@ -377,7 +377,6 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
write_cb = mei_io_cb_init(cl, file);
if (!write_cb) {
dev_err(&dev->pdev->dev, "write cb allocation failed\n");
rets = -ENOMEM;
goto out;
}
@ -387,7 +386,7 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
rets = copy_from_user(write_cb->request_buffer.data, ubuf, length);
if (rets) {
dev_dbg(&dev->pdev->dev, "failed to copy data from userland\n");
dev_dbg(dev->dev, "failed to copy data from userland\n");
rets = -EFAULT;
goto out;
}
@ -396,7 +395,7 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
rets = mei_amthif_write(dev, write_cb);
if (rets) {
dev_err(&dev->pdev->dev,
dev_err(dev->dev,
"amthif write failed with status = %d\n", rets);
goto out;
}
@ -415,27 +414,23 @@ out:
/**
* mei_ioctl_connect_client - the connect to fw client IOCTL function
*
* @dev: the device structure
* @data: IOCTL connect data, input and output parameters
* @file: private data of the file object
* @data: IOCTL connect data, input and output parameters
*
* Locking: called under "dev->device_lock" lock
*
* returns 0 on success, <0 on failure.
* Return: 0 on success, <0 on failure.
*/
static int mei_ioctl_connect_client(struct file *file,
struct mei_connect_client_data *data)
{
struct mei_device *dev;
struct mei_client *client;
struct mei_me_client *me_cl;
struct mei_cl *cl;
int i;
int rets;
cl = file->private_data;
if (WARN_ON(!cl || !cl->dev))
return -ENODEV;
dev = cl->dev;
if (dev->dev_state != MEI_DEV_ENABLED) {
@ -450,28 +445,29 @@ static int mei_ioctl_connect_client(struct file *file,
}
/* find ME client we're trying to connect to */
i = mei_me_cl_by_uuid(dev, &data->in_client_uuid);
if (i < 0 || dev->me_clients[i].props.fixed_address) {
dev_dbg(&dev->pdev->dev, "Cannot connect to FW Client UUID = %pUl\n",
me_cl = mei_me_cl_by_uuid(dev, &data->in_client_uuid);
if (!me_cl || me_cl->props.fixed_address) {
dev_dbg(dev->dev, "Cannot connect to FW Client UUID = %pUl\n",
&data->in_client_uuid);
rets = -ENOTTY;
goto end;
}
cl->me_client_id = dev->me_clients[i].client_id;
cl->me_client_id = me_cl->client_id;
cl->cl_uuid = me_cl->props.protocol_name;
dev_dbg(&dev->pdev->dev, "Connect to FW Client ID = %d\n",
dev_dbg(dev->dev, "Connect to FW Client ID = %d\n",
cl->me_client_id);
dev_dbg(&dev->pdev->dev, "FW Client - Protocol Version = %d\n",
dev->me_clients[i].props.protocol_version);
dev_dbg(&dev->pdev->dev, "FW Client - Max Msg Len = %d\n",
dev->me_clients[i].props.max_msg_length);
dev_dbg(dev->dev, "FW Client - Protocol Version = %d\n",
me_cl->props.protocol_version);
dev_dbg(dev->dev, "FW Client - Max Msg Len = %d\n",
me_cl->props.max_msg_length);
/* if we're connecting to amthif client then we will use the
* existing connection
*/
if (uuid_le_cmp(data->in_client_uuid, mei_amthif_guid) == 0) {
dev_dbg(&dev->pdev->dev, "FW Client is amthi\n");
dev_dbg(dev->dev, "FW Client is amthi\n");
if (dev->iamthif_cl.state != MEI_FILE_CONNECTED) {
rets = -ENODEV;
goto end;
@ -484,10 +480,8 @@ static int mei_ioctl_connect_client(struct file *file,
file->private_data = &dev->iamthif_cl;
client = &data->out_client_properties;
client->max_msg_length =
dev->me_clients[i].props.max_msg_length;
client->protocol_version =
dev->me_clients[i].props.protocol_version;
client->max_msg_length = me_cl->props.max_msg_length;
client->protocol_version = me_cl->props.protocol_version;
rets = dev->iamthif_cl.status;
goto end;
@ -496,9 +490,9 @@ static int mei_ioctl_connect_client(struct file *file,
/* prepare the output buffer */
client = &data->out_client_properties;
client->max_msg_length = dev->me_clients[i].props.max_msg_length;
client->protocol_version = dev->me_clients[i].props.protocol_version;
dev_dbg(&dev->pdev->dev, "Can connect?\n");
client->max_msg_length = me_cl->props.max_msg_length;
client->protocol_version = me_cl->props.protocol_version;
dev_dbg(dev->dev, "Can connect?\n");
rets = mei_cl_connect(cl, file);
@ -507,7 +501,6 @@ end:
return rets;
}
/**
* mei_ioctl - the IOCTL function
*
@ -515,24 +508,22 @@ end:
* @cmd: ioctl command
* @data: pointer to mei message structure
*
* returns 0 on success , <0 on error
* Return: 0 on success , <0 on error
*/
static long mei_ioctl(struct file *file, unsigned int cmd, unsigned long data)
{
struct mei_device *dev;
struct mei_cl *cl = file->private_data;
struct mei_connect_client_data *connect_data = NULL;
struct mei_connect_client_data connect_data;
int rets;
if (cmd != IOCTL_MEI_CONNECT_CLIENT)
return -EINVAL;
if (WARN_ON(!cl || !cl->dev))
return -ENODEV;
dev = cl->dev;
dev_dbg(&dev->pdev->dev, "IOCTL cmd = 0x%x", cmd);
dev_dbg(dev->dev, "IOCTL cmd = 0x%x", cmd);
mutex_lock(&dev->device_lock);
if (dev->dev_state != MEI_DEV_ENABLED) {
@ -540,38 +531,36 @@ static long mei_ioctl(struct file *file, unsigned int cmd, unsigned long data)
goto out;
}
dev_dbg(&dev->pdev->dev, ": IOCTL_MEI_CONNECT_CLIENT.\n");
connect_data = kzalloc(sizeof(struct mei_connect_client_data),
GFP_KERNEL);
if (!connect_data) {
rets = -ENOMEM;
goto out;
}
dev_dbg(&dev->pdev->dev, "copy connect data from user\n");
if (copy_from_user(connect_data, (char __user *)data,
switch (cmd) {
case IOCTL_MEI_CONNECT_CLIENT:
dev_dbg(dev->dev, ": IOCTL_MEI_CONNECT_CLIENT.\n");
if (copy_from_user(&connect_data, (char __user *)data,
sizeof(struct mei_connect_client_data))) {
dev_dbg(&dev->pdev->dev, "failed to copy data from userland\n");
rets = -EFAULT;
goto out;
}
dev_dbg(dev->dev, "failed to copy data from userland\n");
rets = -EFAULT;
goto out;
}
rets = mei_ioctl_connect_client(file, connect_data);
rets = mei_ioctl_connect_client(file, &connect_data);
if (rets)
goto out;
/* if all is ok, copying the data back to user. */
if (rets)
goto out;
dev_dbg(&dev->pdev->dev, "copy connect data to user\n");
if (copy_to_user((char __user *)data, connect_data,
/* if all is ok, copying the data back to user. */
if (copy_to_user((char __user *)data, &connect_data,
sizeof(struct mei_connect_client_data))) {
dev_dbg(&dev->pdev->dev, "failed to copy data to userland\n");
rets = -EFAULT;
goto out;
dev_dbg(dev->dev, "failed to copy data to userland\n");
rets = -EFAULT;
goto out;
}
break;
default:
dev_err(dev->dev, ": unsupported ioctl %d.\n", cmd);
rets = -ENOIOCTLCMD;
}
out:
kfree(connect_data);
mutex_unlock(&dev->device_lock);
return rets;
}
@ -583,7 +572,7 @@ out:
* @cmd: ioctl command
* @data: pointer to mei message structure
*
* returns 0 on success , <0 on error
* Return: 0 on success , <0 on error
*/
#ifdef CONFIG_COMPAT
static long mei_compat_ioctl(struct file *file,
@ -600,7 +589,7 @@ static long mei_compat_ioctl(struct file *file,
* @file: pointer to file structure
* @wait: pointer to poll_table structure
*
* returns poll mask
* Return: poll mask
*/
static unsigned int mei_poll(struct file *file, poll_table *wait)
{
@ -670,7 +659,7 @@ static DEFINE_IDR(mei_idr);
*
* @dev: device pointer
*
* returns allocated minor, or -ENOSPC if no free minor left
* Return: allocated minor, or -ENOSPC if no free minor left
*/
static int mei_minor_get(struct mei_device *dev)
{
@ -681,7 +670,7 @@ static int mei_minor_get(struct mei_device *dev)
if (ret >= 0)
dev->minor = ret;
else if (ret == -ENOSPC)
dev_err(&dev->pdev->dev, "too many mei devices\n");
dev_err(dev->dev, "too many mei devices\n");
mutex_unlock(&mei_minor_lock);
return ret;

View file

@ -129,20 +129,18 @@ enum mei_wd_states {
/**
* enum mei_cb_file_ops - file operation associated with the callback
* @MEI_FOP_READ - read
* @MEI_FOP_WRITE - write
* @MEI_FOP_CONNECT - connect
* @MEI_FOP_DISCONNECT_RSP - disconnect response
* @MEI_FOP_OPEN - open
* @MEI_FOP_CLOSE - close
* @MEI_FOP_READ: read
* @MEI_FOP_WRITE: write
* @MEI_FOP_CONNECT: connect
* @MEI_FOP_DISCONNECT: disconnect
* @MEI_FOP_DISCONNECT_RSP: disconnect response
*/
enum mei_cb_file_ops {
MEI_FOP_READ = 0,
MEI_FOP_WRITE,
MEI_FOP_CONNECT,
MEI_FOP_DISCONNECT,
MEI_FOP_DISCONNECT_RSP,
MEI_FOP_OPEN,
MEI_FOP_CLOSE
};
/*
@ -159,8 +157,8 @@ struct mei_msg_data {
/*
* struct mei_fw_status - storage of FW status data
*
* @count - number of actually available elements in array
* @status - FW status registers
* @count: number of actually available elements in array
* @status: FW status registers
*/
struct mei_fw_status {
int count;
@ -170,11 +168,13 @@ struct mei_fw_status {
/**
* struct mei_me_client - representation of me (fw) client
*
* @props - client properties
* @client_id - me client id
* @mei_flow_ctrl_creds - flow control credits
* @list: link in me client list
* @props: client properties
* @client_id: me client id
* @mei_flow_ctrl_creds: flow control credits
*/
struct mei_me_client {
struct list_head list;
struct mei_client_properties props;
u8 client_id;
u8 mei_flow_ctrl_creds;
@ -186,8 +186,15 @@ struct mei_cl;
/**
* struct mei_cl_cb - file operation callback structure
*
* @cl - file client who is running this operation
* @fop_type - file operation type
* @list: link in callback queue
* @cl: file client who is running this operation
* @fop_type: file operation type
* @request_buffer: buffer to store request data
* @response_buffer: buffer to store response data
* @buf_idx: last read index
* @read_time: last read operation time stamp (iamthif)
* @file_object: pointer to file structure
* @internal: communication between driver and FW flag
*/
struct mei_cl_cb {
struct list_head list;
@ -201,7 +208,29 @@ struct mei_cl_cb {
u32 internal:1;
};
/* MEI client instance carried as file->private_data*/
/**
* struct mei_cl - me client host representation
* carried in file->private_data
*
* @link: link in the clients list
* @dev: mei parent device
* @state: file operation state
* @tx_wait: wait queue for tx completion
* @rx_wait: wait queue for rx completion
* @wait: wait queue for management operation
* @status: connection status
* @cl_uuid: client uuid name
* @host_client_id: host id
* @me_client_id: me/fw id
* @mei_flow_ctrl_creds: transmit flow credentials
* @timer_count: watchdog timer for operation completion
* @reading_state: state of the rx
* @writing_state: state of the tx
* @read_cb: current pending reading callback
*
* @device: device on the mei client bus
* @device_link: link to bus clients
*/
struct mei_cl {
struct list_head link;
struct mei_device *dev;
@ -210,7 +239,7 @@ struct mei_cl {
wait_queue_head_t rx_wait;
wait_queue_head_t wait;
int status;
/* ID of client connected */
uuid_le cl_uuid;
u8 host_client_id;
u8 me_client_id;
u8 mei_flow_ctrl_creds;
@ -222,35 +251,35 @@ struct mei_cl {
/* MEI CL bus data */
struct mei_cl_device *device;
struct list_head device_link;
uuid_le device_uuid;
};
/** struct mei_hw_ops
*
* @host_is_ready - query for host readiness
* @host_is_ready : query for host readiness
* @hw_is_ready - query if hw is ready
* @hw_reset - reset hw
* @hw_start - start hw after reset
* @hw_config - configure hw
* @hw_is_ready : query if hw is ready
* @hw_reset : reset hw
* @hw_start : start hw after reset
* @hw_config : configure hw
* @pg_state - power gating state of the device
* @pg_is_enabled - is power gating enabled
* @fw_status : get fw status registers
* @pg_state : power gating state of the device
* @pg_is_enabled : is power gating enabled
* @intr_clear - clear pending interrupts
* @intr_enable - enable interrupts
* @intr_disable - disable interrupts
* @intr_clear : clear pending interrupts
* @intr_enable : enable interrupts
* @intr_disable : disable interrupts
* @hbuf_free_slots - query for write buffer empty slots
* @hbuf_is_ready - query if write buffer is empty
* @hbuf_max_len - query for write buffer max len
* @hbuf_free_slots : query for write buffer empty slots
* @hbuf_is_ready : query if write buffer is empty
* @hbuf_max_len : query for write buffer max len
* @write - write a message to FW
* @write : write a message to FW
* @rdbuf_full_slots - query how many slots are filled
* @rdbuf_full_slots : query how many slots are filled
* @read_hdr - get first 4 bytes (header)
* @read - read a buffer from the FW
* @read_hdr : get first 4 bytes (header)
* @read : read a buffer from the FW
*/
struct mei_hw_ops {
@ -261,6 +290,8 @@ struct mei_hw_ops {
int (*hw_start)(struct mei_device *dev);
void (*hw_config)(struct mei_device *dev);
int (*fw_status)(struct mei_device *dev, struct mei_fw_status *fw_sts);
enum mei_pg_state (*pg_state)(struct mei_device *dev);
bool (*pg_is_enabled)(struct mei_device *dev);
@ -328,11 +359,12 @@ void mei_cl_bus_exit(void);
* when being probed and shall use it for doing ME bus I/O.
*
* @dev: linux driver model device pointer
* @uuid: me client uuid
* @cl: mei client
* @ops: ME transport ops
* @event_work: async work to execute event callback
* @event_cb: Drivers register this callback to get asynchronous ME
* events (e.g. Rx buffer pending) notifications.
* @event_context: event callback run context
* @events: Events bitmask sent to the driver.
* @priv_data: client private data
*/
@ -352,7 +384,7 @@ struct mei_cl_device {
};
/**
/**
* enum mei_pg_event - power gating transition events
*
* @MEI_PG_EVENT_IDLE: the driver is not in power gating transition
@ -376,67 +408,106 @@ enum mei_pg_state {
MEI_PG_ON = 1,
};
/*
* mei_cfg
*
* @fw_status - FW status
* @quirk_probe - device exclusion quirk
*/
struct mei_cfg {
const struct mei_fw_status fw_status;
bool (*quirk_probe)(struct pci_dev *pdev);
};
#define MEI_PCI_DEVICE(dev, cfg) \
.vendor = PCI_VENDOR_ID_INTEL, .device = (dev), \
.subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, \
.driver_data = (kernel_ulong_t)&(cfg)
const char *mei_pg_state_str(enum mei_pg_state state);
/**
* struct mei_device - MEI private device struct
* @pdev - pointer to pci device struct
* @cdev - character device
* @minor - minor number allocated for device
*
* @reset_count - limits the number of consecutive resets
* @hbm_state - state of host bus message protocol
* @pg_event - power gating event
* @mem_addr - mem mapped base register address
* @hbuf_depth - depth of hardware host/write buffer is slots
* @hbuf_is_ready - query if the host host/write buffer is ready
* @wr_msg - the buffer for hbm control messages
* @cfg - per device generation config and ops
* @dev : device on a bus
* @cdev : character device
* @minor : minor number allocated for device
*
* @read_list : read completion list
* @write_list : write pending list
* @write_waiting_list : write completion list
* @ctrl_wr_list : pending control write list
* @ctrl_rd_list : pending control read list
*
* @file_list : list of opened handles
* @open_handle_count: number of opened handles
*
* @device_lock : big device lock
* @timer_work : MEI timer delayed work (timeouts)
*
* @recvd_hw_ready : hw ready message received flag
*
* @wait_hw_ready : wait queue for receive HW ready message form FW
* @wait_pg : wait queue for receive PG message from FW
* @wait_hbm_start : wait queue for receive HBM start message from FW
* @wait_stop_wd : wait queue for receive WD stop message from FW
*
* @reset_count : number of consecutive resets
* @dev_state : device state
* @hbm_state : state of host bus message protocol
* @init_clients_timer : HBM init handshake timeout
*
* @pg_event : power gating event
* @pg_domain : runtime PM domain
*
* @rd_msg_buf : control messages buffer
* @rd_msg_hdr : read message header storage
*
* @hbuf_depth : depth of hardware host/write buffer is slots
* @hbuf_is_ready : query if the host host/write buffer is ready
* @wr_msg : the buffer for hbm control messages
*
* @version : HBM protocol version in use
* @hbm_f_pg_supported : hbm feature pgi protocol
*
* @me_clients : list of FW clients
* @me_clients_map : FW clients bit map
* @host_clients_map : host clients id pool
* @me_client_index : last FW client index in enumeration
*
* @wd_cl : watchdog client
* @wd_state : watchdog client state
* @wd_pending : watchdog command is pending
* @wd_timeout : watchdog expiration timeout
* @wd_data : watchdog message buffer
*
* @amthif_cmd_list : amthif list for cmd waiting
* @amthif_rd_complete_list : amthif list for reading completed cmd data
* @iamthif_file_object : file for current amthif operation
* @iamthif_cl : amthif host client
* @iamthif_current_cb : amthif current operation callback
* @iamthif_open_count : number of opened amthif connections
* @iamthif_mtu : amthif client max message length
* @iamthif_timer : time stamp of current amthif command completion
* @iamthif_stall_timer : timer to detect amthif hang
* @iamthif_msg_buf : amthif current message buffer
* @iamthif_msg_buf_size : size of current amthif message request buffer
* @iamthif_msg_buf_index : current index in amthif message request buffer
* @iamthif_state : amthif processor state
* @iamthif_flow_control_pending: amthif waits for flow control
* @iamthif_ioctl : wait for completion if amthif control message
* @iamthif_canceled : current amthif command is canceled
*
* @init_work : work item for the device init
* @reset_work : work item for the device reset
*
* @device_list : mei client bus list
*
* @dbgfs_dir : debugfs mei root directory
*
* @ops: : hw specific operations
* @hw : hw specific data
*/
struct mei_device {
struct pci_dev *pdev; /* pointer to pci device struct */
struct device *dev;
struct cdev cdev;
int minor;
/*
* lists of queues
*/
/* array of pointers to aio lists */
struct mei_cl_cb read_list; /* driver read queue */
struct mei_cl_cb write_list; /* driver write queue */
struct mei_cl_cb write_waiting_list; /* write waiting queue */
struct mei_cl_cb ctrl_wr_list; /* managed write IOCTL list */
struct mei_cl_cb ctrl_rd_list; /* managed read IOCTL list */
struct mei_cl_cb read_list;
struct mei_cl_cb write_list;
struct mei_cl_cb write_waiting_list;
struct mei_cl_cb ctrl_wr_list;
struct mei_cl_cb ctrl_rd_list;
/*
* list of files
*/
struct list_head file_list;
long open_handle_count;
/*
* lock for the device
*/
struct mutex device_lock; /* device lock */
struct delayed_work timer_work; /* MEI timer delayed work (timeouts) */
struct mutex device_lock;
struct delayed_work timer_work;
bool recvd_hw_ready;
/*
@ -444,7 +515,7 @@ struct mei_device {
*/
wait_queue_head_t wait_hw_ready;
wait_queue_head_t wait_pg;
wait_queue_head_t wait_recvd_msg;
wait_queue_head_t wait_hbm_start;
wait_queue_head_t wait_stop_wd;
/*
@ -463,7 +534,7 @@ struct mei_device {
struct dev_pm_domain pg_domain;
#endif /* CONFIG_PM_RUNTIME */
unsigned char rd_msg_buf[MEI_RD_MSG_BUF_SIZE]; /* control messages */
unsigned char rd_msg_buf[MEI_RD_MSG_BUF_SIZE];
u32 rd_msg_hdr;
/* write buffer */
@ -477,12 +548,11 @@ struct mei_device {
} wr_msg;
struct hbm_version version;
unsigned int hbm_f_pg_supported:1;
struct mei_me_client *me_clients; /* Note: memory has to be allocated */
struct list_head me_clients;
DECLARE_BITMAP(me_clients_map, MEI_CLIENTS_MAX);
DECLARE_BITMAP(host_clients_map, MEI_CLIENTS_MAX);
unsigned long me_clients_num;
unsigned long me_client_presentation_num;
unsigned long me_client_index;
struct mei_cl wd_cl;
@ -523,7 +593,6 @@ struct mei_device {
const struct mei_hw_ops *ops;
const struct mei_cfg *cfg;
char hw[0] __aligned(sizeof(void *));
};
@ -535,8 +604,10 @@ static inline unsigned long mei_secs_to_jiffies(unsigned long sec)
/**
* mei_data2slots - get slots - number of (dwords) from a message length
* + size of the mei header
* @length - size of the messages in bytes
* returns - number of slots
*
* @length: size of the messages in bytes
*
* Return: number of slots
*/
static inline u32 mei_data2slots(size_t length)
{
@ -544,9 +615,11 @@ static inline u32 mei_data2slots(size_t length)
}
/**
* mei_slots2data- get data in slots - bytes from slots
* @slots - number of available slots
* returns - number of bytes in slots
* mei_slots2data - get data in slots - bytes from slots
*
* @slots: number of available slots
*
* Return: number of bytes in slots
*/
static inline u32 mei_slots2data(int slots)
{
@ -556,7 +629,9 @@ static inline u32 mei_slots2data(int slots)
/*
* mei init function prototypes
*/
void mei_device_init(struct mei_device *dev, const struct mei_cfg *cfg);
void mei_device_init(struct mei_device *dev,
struct device *device,
const struct mei_hw_ops *hw_ops);
int mei_reset(struct mei_device *dev);
int mei_start(struct mei_device *dev);
int mei_restart(struct mei_device *dev);
@ -622,12 +697,12 @@ int mei_wd_host_init(struct mei_device *dev);
/*
* mei_watchdog_register - Registering watchdog interface
* once we got connection to the WD Client
* @dev - mei device
* @dev: mei device
*/
int mei_watchdog_register(struct mei_device *dev);
/*
* mei_watchdog_unregister - Unregistering watchdog interface
* @dev - mei device
* @dev: mei device
*/
void mei_watchdog_unregister(struct mei_device *dev);
@ -723,7 +798,11 @@ static inline int mei_count_full_read_slots(struct mei_device *dev)
return dev->ops->rdbuf_full_slots(dev);
}
int mei_fw_status(struct mei_device *dev, struct mei_fw_status *fw_status);
static inline int mei_fw_status(struct mei_device *dev,
struct mei_fw_status *fw_status)
{
return dev->ops->fw_status(dev, fw_status);
}
#define FW_STS_FMT "%08X %08X"
#define FW_STS_PRM(fw_status) \

View file

@ -19,7 +19,8 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/device.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/mei_cl_bus.h>
#include "mei_dev.h"
@ -87,14 +88,20 @@ struct mei_nfc_hci_hdr {
#define MEI_NFC_HEADER_SIZE 10
/** mei_nfc_dev - NFC mei device
/**
* struct mei_nfc_dev - NFC mei device
*
* @cl: NFC host client
* @cl_info: NFC info host client
* @init_work: perform connection to the info client
* @send_wq: send completion wait queue
* @fw_ivn: NFC Interface Version Number
* @vendor_id: NFC manufacturer ID
* @radio_type: NFC radio type
* @bus_name: bus name
*
* @req_id: message counter
* @recv_req_id: reception message counter
*/
struct mei_nfc_dev {
struct mei_cl *cl;
@ -163,7 +170,7 @@ static int mei_nfc_build_bus_name(struct mei_nfc_dev *ndev)
return 0;
default:
dev_err(&dev->pdev->dev, "Unknown radio type 0x%x\n",
dev_err(dev->dev, "Unknown radio type 0x%x\n",
ndev->radio_type);
return -EINVAL;
@ -175,14 +182,14 @@ static int mei_nfc_build_bus_name(struct mei_nfc_dev *ndev)
ndev->bus_name = "pn544";
return 0;
default:
dev_err(&dev->pdev->dev, "Unknown radio type 0x%x\n",
dev_err(dev->dev, "Unknown radio type 0x%x\n",
ndev->radio_type);
return -EINVAL;
}
default:
dev_err(&dev->pdev->dev, "Unknown vendor ID 0x%x\n",
dev_err(dev->dev, "Unknown vendor ID 0x%x\n",
ndev->vendor_id);
return -EINVAL;
@ -231,21 +238,21 @@ static int mei_nfc_connect(struct mei_nfc_dev *ndev)
ret = __mei_cl_send(cl, (u8 *)cmd, connect_length);
if (ret < 0) {
dev_err(&dev->pdev->dev, "Could not send connect cmd\n");
dev_err(dev->dev, "Could not send connect cmd\n");
goto err;
}
bytes_recv = __mei_cl_recv(cl, (u8 *)reply, connect_resp_length);
if (bytes_recv < 0) {
dev_err(&dev->pdev->dev, "Could not read connect response\n");
dev_err(dev->dev, "Could not read connect response\n");
ret = bytes_recv;
goto err;
}
dev_info(&dev->pdev->dev, "IVN 0x%x Vendor ID 0x%x\n",
dev_info(dev->dev, "IVN 0x%x Vendor ID 0x%x\n",
connect_resp->fw_ivn, connect_resp->vendor_id);
dev_info(&dev->pdev->dev, "ME FW %d.%d.%d.%d\n",
dev_info(dev->dev, "ME FW %d.%d.%d.%d\n",
connect_resp->me_major, connect_resp->me_minor,
connect_resp->me_hotfix, connect_resp->me_build);
@ -279,7 +286,7 @@ static int mei_nfc_if_version(struct mei_nfc_dev *ndev)
ret = __mei_cl_send(cl, (u8 *)&cmd, sizeof(struct mei_nfc_cmd));
if (ret < 0) {
dev_err(&dev->pdev->dev, "Could not send IF version cmd\n");
dev_err(dev->dev, "Could not send IF version cmd\n");
return ret;
}
@ -293,7 +300,7 @@ static int mei_nfc_if_version(struct mei_nfc_dev *ndev)
bytes_recv = __mei_cl_recv(cl, (u8 *)reply, if_version_length);
if (bytes_recv < 0 || bytes_recv < sizeof(struct mei_nfc_reply)) {
dev_err(&dev->pdev->dev, "Could not read IF version\n");
dev_err(dev->dev, "Could not read IF version\n");
ret = -EIO;
goto err;
}
@ -319,7 +326,7 @@ static int mei_nfc_enable(struct mei_cl_device *cldev)
ret = mei_nfc_connect(ndev);
if (ret < 0) {
dev_err(&dev->pdev->dev, "Could not connect to NFC");
dev_err(dev->dev, "Could not connect to NFC");
return ret;
}
@ -361,7 +368,7 @@ static int mei_nfc_send(struct mei_cl_device *cldev, u8 *buf, size_t length)
if (!wait_event_interruptible_timeout(ndev->send_wq,
ndev->recv_req_id == ndev->req_id, HZ)) {
dev_err(&dev->pdev->dev, "NFC MEI command timeout\n");
dev_err(dev->dev, "NFC MEI command timeout\n");
err = -ETIME;
} else {
ndev->req_id++;
@ -418,8 +425,7 @@ static void mei_nfc_init(struct work_struct *work)
if (mei_cl_connect(cl_info, NULL) < 0) {
mutex_unlock(&dev->device_lock);
dev_err(&dev->pdev->dev,
"Could not connect to the NFC INFO ME client");
dev_err(dev->dev, "Could not connect to the NFC INFO ME client");
goto err;
}
@ -427,21 +433,19 @@ static void mei_nfc_init(struct work_struct *work)
mutex_unlock(&dev->device_lock);
if (mei_nfc_if_version(ndev) < 0) {
dev_err(&dev->pdev->dev, "Could not get the NFC interface version");
dev_err(dev->dev, "Could not get the NFC interface version");
goto err;
}
dev_info(&dev->pdev->dev,
"NFC MEI VERSION: IVN 0x%x Vendor ID 0x%x Type 0x%x\n",
dev_info(dev->dev, "NFC MEI VERSION: IVN 0x%x Vendor ID 0x%x Type 0x%x\n",
ndev->fw_ivn, ndev->vendor_id, ndev->radio_type);
mutex_lock(&dev->device_lock);
if (mei_cl_disconnect(cl_info) < 0) {
mutex_unlock(&dev->device_lock);
dev_err(&dev->pdev->dev,
"Could not disconnect the NFC INFO ME client");
dev_err(dev->dev, "Could not disconnect the NFC INFO ME client");
goto err;
}
@ -449,15 +453,13 @@ static void mei_nfc_init(struct work_struct *work)
mutex_unlock(&dev->device_lock);
if (mei_nfc_build_bus_name(ndev) < 0) {
dev_err(&dev->pdev->dev,
"Could not build the bus ID name\n");
dev_err(dev->dev, "Could not build the bus ID name\n");
return;
}
cldev = mei_cl_add_device(dev, mei_nfc_guid, ndev->bus_name, &nfc_ops);
if (!cldev) {
dev_err(&dev->pdev->dev,
"Could not add the NFC device to the MEI bus\n");
dev_err(dev->dev, "Could not add the NFC device to the MEI bus\n");
goto err;
}
@ -472,7 +474,6 @@ err:
mei_nfc_free(ndev);
mutex_unlock(&dev->device_lock);
return;
}
@ -480,7 +481,8 @@ int mei_nfc_host_init(struct mei_device *dev)
{
struct mei_nfc_dev *ndev = &nfc_dev;
struct mei_cl *cl_info, *cl = NULL;
int i, ret;
struct mei_me_client *me_cl;
int ret;
/* already initialized */
if (ndev->cl_info)
@ -498,40 +500,38 @@ int mei_nfc_host_init(struct mei_device *dev)
}
/* check for valid client id */
i = mei_me_cl_by_uuid(dev, &mei_nfc_info_guid);
if (i < 0) {
dev_info(&dev->pdev->dev, "nfc: failed to find the client\n");
me_cl = mei_me_cl_by_uuid(dev, &mei_nfc_info_guid);
if (!me_cl) {
dev_info(dev->dev, "nfc: failed to find the client\n");
ret = -ENOTTY;
goto err;
}
cl_info->me_client_id = dev->me_clients[i].client_id;
cl_info->me_client_id = me_cl->client_id;
cl_info->cl_uuid = me_cl->props.protocol_name;
ret = mei_cl_link(cl_info, MEI_HOST_CLIENT_ID_ANY);
if (ret)
goto err;
cl_info->device_uuid = mei_nfc_info_guid;
list_add_tail(&cl_info->device_link, &dev->device_list);
/* check for valid client id */
i = mei_me_cl_by_uuid(dev, &mei_nfc_guid);
if (i < 0) {
dev_info(&dev->pdev->dev, "nfc: failed to find the client\n");
me_cl = mei_me_cl_by_uuid(dev, &mei_nfc_guid);
if (!me_cl) {
dev_info(dev->dev, "nfc: failed to find the client\n");
ret = -ENOTTY;
goto err;
}
cl->me_client_id = dev->me_clients[i].client_id;
cl->me_client_id = me_cl->client_id;
cl->cl_uuid = me_cl->props.protocol_name;
ret = mei_cl_link(cl, MEI_HOST_CLIENT_ID_ANY);
if (ret)
goto err;
cl->device_uuid = mei_nfc_guid;
list_add_tail(&cl->device_link, &dev->device_list);
ndev->req_id = 1;
@ -551,6 +551,7 @@ err:
void mei_nfc_host_exit(struct mei_device *dev)
{
struct mei_nfc_dev *ndev = &nfc_dev;
cancel_work_sync(&ndev->init_work);
}

View file

@ -98,12 +98,12 @@ static inline void mei_me_unset_pm_domain(struct mei_device *dev) {}
#endif /* CONFIG_PM_RUNTIME */
/**
* mei_quirk_probe - probe for devices that doesn't valid ME interface
* mei_me_quirk_probe - probe for devices that doesn't valid ME interface
*
* @pdev: PCI device structure
* @cfg: per generation config
*
* returns true if ME Interface is valid, false otherwise
* Return: true if ME Interface is valid, false otherwise
*/
static bool mei_me_quirk_probe(struct pci_dev *pdev,
const struct mei_cfg *cfg)
@ -117,12 +117,12 @@ static bool mei_me_quirk_probe(struct pci_dev *pdev,
}
/**
* mei_probe - Device Initialization Routine
* mei_me_probe - Device Initialization Routine
*
* @pdev: PCI device structure
* @ent: entry in kcs_pci_tbl
*
* returns 0 on success, <0 on failure.
* Return: 0 on success, <0 on failure.
*/
static int mei_me_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
@ -249,7 +249,7 @@ end:
}
/**
* mei_remove - Device Removal Routine
* mei_me_remove - Device Removal Routine
*
* @pdev: PCI device structure
*
@ -430,7 +430,7 @@ static int mei_me_pm_runtime_resume(struct device *device)
*/
static inline void mei_me_set_pm_domain(struct mei_device *dev)
{
struct pci_dev *pdev = dev->pdev;
struct pci_dev *pdev = to_pci_dev(dev->dev);
if (pdev->dev.bus && pdev->dev.bus->pm) {
dev->pg_domain.ops = *pdev->dev.bus->pm;
@ -451,7 +451,7 @@ static inline void mei_me_set_pm_domain(struct mei_device *dev)
static inline void mei_me_unset_pm_domain(struct mei_device *dev)
{
/* stop using pm callbacks if any */
dev->pdev->dev.pm_domain = NULL;
dev->dev->pm_domain = NULL;
}
#endif /* CONFIG_PM_RUNTIME */

View file

@ -36,7 +36,8 @@
#include "hw-txe.h"
static const struct pci_device_id mei_txe_pci_tbl[] = {
{MEI_PCI_DEVICE(0x0F18, mei_txe_cfg)}, /* Baytrail */
{PCI_VDEVICE(INTEL, 0x0F18)}, /* Baytrail */
{0, }
};
MODULE_DEVICE_TABLE(pci, mei_txe_pci_tbl);
@ -52,6 +53,7 @@ static inline void mei_txe_unset_pm_domain(struct mei_device *dev) {}
static void mei_txe_pci_iounmap(struct pci_dev *pdev, struct mei_txe_hw *hw)
{
int i;
for (i = SEC_BAR; i < NUM_OF_MEM_BARS; i++) {
if (hw->mem_addr[i]) {
pci_iounmap(pdev, hw->mem_addr[i]);
@ -65,11 +67,10 @@ static void mei_txe_pci_iounmap(struct pci_dev *pdev, struct mei_txe_hw *hw)
* @pdev: PCI device structure
* @ent: entry in mei_txe_pci_tbl
*
* returns 0 on success, <0 on failure.
* Return: 0 on success, <0 on failure.
*/
static int mei_txe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
const struct mei_cfg *cfg = (struct mei_cfg *)(ent->driver_data);
struct mei_device *dev;
struct mei_txe_hw *hw;
int err;
@ -100,7 +101,7 @@ static int mei_txe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
}
/* allocates and initializes the mei dev structure */
dev = mei_txe_dev_init(pdev, cfg);
dev = mei_txe_dev_init(pdev);
if (!dev) {
err = -ENOMEM;
goto release_regions;
@ -377,7 +378,7 @@ static int mei_txe_pm_runtime_resume(struct device *device)
*/
static inline void mei_txe_set_pm_domain(struct mei_device *dev)
{
struct pci_dev *pdev = dev->pdev;
struct pci_dev *pdev = to_pci_dev(dev->dev);
if (pdev->dev.bus && pdev->dev.bus->pm) {
dev->pg_domain.ops = *pdev->dev.bus->pm;
@ -398,7 +399,7 @@ static inline void mei_txe_set_pm_domain(struct mei_device *dev)
static inline void mei_txe_unset_pm_domain(struct mei_device *dev)
{
/* stop using pm callbacks if any */
dev->pdev->dev.pm_domain = NULL;
dev->dev->pm_domain = NULL;
}
#endif /* CONFIG_PM_RUNTIME */

View file

@ -17,7 +17,6 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/device.h>
#include <linux/pci.h>
#include <linux/sched.h>
#include <linux/watchdog.h>
@ -42,7 +41,7 @@ const uuid_le mei_wd_guid = UUID_LE(0x05B79A6F, 0x4628, 0x4D7F, 0x89,
static void mei_wd_set_start_timeout(struct mei_device *dev, u16 timeout)
{
dev_dbg(&dev->pdev->dev, "wd: set timeout=%d.\n", timeout);
dev_dbg(dev->dev, "wd: set timeout=%d.\n", timeout);
memcpy(dev->wd_data, mei_start_wd_params, MEI_WD_HDR_SIZE);
memcpy(dev->wd_data + MEI_WD_HDR_SIZE, &timeout, sizeof(u16));
}
@ -52,14 +51,14 @@ static void mei_wd_set_start_timeout(struct mei_device *dev, u16 timeout)
*
* @dev: the device structure
*
* returns -ENOTTY if wd client cannot be found
* Return: -ENOTTY if wd client cannot be found
* -EIO if write has failed
* 0 on success
*/
int mei_wd_host_init(struct mei_device *dev)
{
struct mei_cl *cl = &dev->wd_cl;
int id;
struct mei_me_client *me_cl;
int ret;
mei_cl_init(cl, dev);
@ -69,25 +68,26 @@ int mei_wd_host_init(struct mei_device *dev)
/* check for valid client id */
id = mei_me_cl_by_uuid(dev, &mei_wd_guid);
if (id < 0) {
dev_info(&dev->pdev->dev, "wd: failed to find the client\n");
me_cl = mei_me_cl_by_uuid(dev, &mei_wd_guid);
if (!me_cl) {
dev_info(dev->dev, "wd: failed to find the client\n");
return -ENOTTY;
}
cl->me_client_id = dev->me_clients[id].client_id;
cl->me_client_id = me_cl->client_id;
cl->cl_uuid = me_cl->props.protocol_name;
ret = mei_cl_link(cl, MEI_WD_HOST_CLIENT_ID);
if (ret < 0) {
dev_info(&dev->pdev->dev, "wd: failed link client\n");
dev_info(dev->dev, "wd: failed link client\n");
return ret;
}
ret = mei_cl_connect(cl, NULL);
if (ret) {
dev_err(&dev->pdev->dev, "wd: failed to connect = %d\n", ret);
dev_err(dev->dev, "wd: failed to connect = %d\n", ret);
mei_cl_unlink(cl);
return ret;
}
@ -105,7 +105,7 @@ int mei_wd_host_init(struct mei_device *dev)
*
* @dev: the device structure
*
* returns 0 if success,
* Return: 0 if success,
* -EIO when message send fails
* -EINVAL when invalid message is to be sent
* -ENODEV on flow control failure
@ -127,19 +127,19 @@ int mei_wd_send(struct mei_device *dev)
else if (!memcmp(dev->wd_data, mei_stop_wd_params, MEI_WD_HDR_SIZE))
hdr.length = MEI_WD_STOP_MSG_SIZE;
else {
dev_err(&dev->pdev->dev, "wd: invalid message is to be sent, aborting\n");
dev_err(dev->dev, "wd: invalid message is to be sent, aborting\n");
return -EINVAL;
}
ret = mei_write_message(dev, &hdr, dev->wd_data);
if (ret) {
dev_err(&dev->pdev->dev, "wd: write message failed\n");
dev_err(dev->dev, "wd: write message failed\n");
return ret;
}
ret = mei_cl_flow_ctrl_reduce(cl);
if (ret) {
dev_err(&dev->pdev->dev, "wd: flow_ctrl_reduce failed.\n");
dev_err(dev->dev, "wd: flow_ctrl_reduce failed.\n");
return ret;
}
@ -150,9 +150,8 @@ int mei_wd_send(struct mei_device *dev)
* mei_wd_stop - sends watchdog stop message to fw.
*
* @dev: the device structure
* @preserve: indicate if to keep the timeout value
*
* returns 0 if success
* Return: 0 if success
* on error:
* -EIO when message send fails
* -EINVAL when invalid message is to be sent
@ -192,11 +191,10 @@ int mei_wd_stop(struct mei_device *dev)
if (dev->wd_state != MEI_WD_IDLE) {
/* timeout */
ret = -ETIME;
dev_warn(&dev->pdev->dev,
"wd: stop failed to complete ret=%d.\n", ret);
dev_warn(dev->dev, "wd: stop failed to complete ret=%d\n", ret);
goto err;
}
dev_dbg(&dev->pdev->dev, "wd: stop completed after %u msec\n",
dev_dbg(dev->dev, "wd: stop completed after %u msec\n",
MEI_WD_STOP_TIMEOUT - jiffies_to_msecs(ret));
return 0;
err:
@ -208,7 +206,7 @@ err:
*
* @wd_dev - watchdog device struct
*
* returns 0 if success, negative errno code for failure
* Return: 0 if success, negative errno code for failure
*/
static int mei_wd_ops_start(struct watchdog_device *wd_dev)
{
@ -222,15 +220,13 @@ static int mei_wd_ops_start(struct watchdog_device *wd_dev)
mutex_lock(&dev->device_lock);
if (dev->dev_state != MEI_DEV_ENABLED) {
dev_dbg(&dev->pdev->dev,
"wd: dev_state != MEI_DEV_ENABLED dev_state = %s\n",
dev_dbg(dev->dev, "wd: dev_state != MEI_DEV_ENABLED dev_state = %s\n",
mei_dev_state_str(dev->dev_state));
goto end_unlock;
}
if (dev->wd_cl.state != MEI_FILE_CONNECTED) {
dev_dbg(&dev->pdev->dev,
"MEI Driver is not connected to Watchdog Client\n");
dev_dbg(dev->dev, "MEI Driver is not connected to Watchdog Client\n");
goto end_unlock;
}
@ -247,7 +243,7 @@ end_unlock:
*
* @wd_dev - watchdog device struct
*
* returns 0 if success, negative errno code for failure
* Return: 0 if success, negative errno code for failure
*/
static int mei_wd_ops_stop(struct watchdog_device *wd_dev)
{
@ -269,7 +265,7 @@ static int mei_wd_ops_stop(struct watchdog_device *wd_dev)
*
* @wd_dev - watchdog device struct
*
* returns 0 if success, negative errno code for failure
* Return: 0 if success, negative errno code for failure
*/
static int mei_wd_ops_ping(struct watchdog_device *wd_dev)
{
@ -283,7 +279,7 @@ static int mei_wd_ops_ping(struct watchdog_device *wd_dev)
mutex_lock(&dev->device_lock);
if (dev->wd_cl.state != MEI_FILE_CONNECTED) {
dev_err(&dev->pdev->dev, "wd: not connected.\n");
dev_err(dev->dev, "wd: not connected.\n");
ret = -ENODEV;
goto end;
}
@ -296,7 +292,7 @@ static int mei_wd_ops_ping(struct watchdog_device *wd_dev)
/* Check if we can send the ping to HW*/
if (ret && mei_hbuf_acquire(dev)) {
dev_dbg(&dev->pdev->dev, "wd: sending ping\n");
dev_dbg(dev->dev, "wd: sending ping\n");
ret = mei_wd_send(dev);
if (ret)
@ -317,7 +313,7 @@ end:
* @wd_dev - watchdog device struct
* @timeout - timeout value to set
*
* returns 0 if success, negative errno code for failure
* Return: 0 if success, negative errno code for failure
*/
static int mei_wd_ops_set_timeout(struct watchdog_device *wd_dev,
unsigned int timeout)
@ -379,13 +375,12 @@ int mei_watchdog_register(struct mei_device *dev)
ret = watchdog_register_device(&amt_wd_dev);
mutex_lock(&dev->device_lock);
if (ret) {
dev_err(&dev->pdev->dev, "wd: unable to register watchdog device = %d.\n",
dev_err(dev->dev, "wd: unable to register watchdog device = %d.\n",
ret);
return ret;
}
dev_dbg(&dev->pdev->dev,
"wd: successfully register watchdog interface.\n");
dev_dbg(dev->dev, "wd: successfully register watchdog interface.\n");
watchdog_set_drvdata(&amt_wd_dev, dev);
return 0;
}

View file

@ -9,6 +9,7 @@
* warranty of any kind, whether express or implied.
*/
#include <linux/device.h>
#include <linux/clk.h>
#include <linux/slab.h>
#include <linux/delay.h>
@ -743,58 +744,33 @@ static int spear_pcie_gadget_probe(struct platform_device *pdev)
struct config_item *cg_item;
struct configfs_subsystem *subsys;
/* get resource for application registers*/
res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res0) {
dev_err(&pdev->dev, "no resource defined\n");
return -EBUSY;
}
if (!request_mem_region(res0->start, resource_size(res0),
pdev->name)) {
dev_err(&pdev->dev, "pcie gadget region already claimed\n");
return -EBUSY;
}
/* get resource for dbi registers*/
res1 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
if (!res1) {
dev_err(&pdev->dev, "no resource defined\n");
goto err_rel_res0;
}
if (!request_mem_region(res1->start, resource_size(res1),
pdev->name)) {
dev_err(&pdev->dev, "pcie gadget region already claimed\n");
goto err_rel_res0;
}
target = kzalloc(sizeof(*target), GFP_KERNEL);
target = devm_kzalloc(&pdev->dev, sizeof(*target), GFP_KERNEL);
if (!target) {
dev_err(&pdev->dev, "out of memory\n");
status = -ENOMEM;
goto err_rel_res;
return -ENOMEM;
}
cg_item = &target->subsys.su_group.cg_item;
sprintf(cg_item->ci_namebuf, "pcie_gadget.%d", pdev->id);
cg_item->ci_type = &pcie_gadget_target_type;
config = &target->config;
config->va_app_base = (void __iomem *)ioremap(res0->start,
resource_size(res0));
if (!config->va_app_base) {
/* get resource for application registers*/
res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
config->va_app_base = devm_ioremap_resource(&pdev->dev, res0);
if (IS_ERR(config->va_app_base)) {
dev_err(&pdev->dev, "ioremap fail\n");
status = -ENOMEM;
goto err_kzalloc;
return PTR_ERR(config->va_app_base);
}
/* get resource for dbi registers*/
res1 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
config->base = (void __iomem *)res1->start;
config->va_dbi_base = (void __iomem *)ioremap(res1->start,
resource_size(res1));
if (!config->va_dbi_base) {
config->va_dbi_base = devm_ioremap_resource(&pdev->dev, res1);
if (IS_ERR(config->va_dbi_base)) {
dev_err(&pdev->dev, "ioremap fail\n");
status = -ENOMEM;
goto err_iounmap_app;
return PTR_ERR(config->va_dbi_base);
}
platform_set_drvdata(pdev, target);
@ -802,15 +778,15 @@ static int spear_pcie_gadget_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "no update irq?\n");
status = irq;
goto err_iounmap;
return irq;
}
status = request_irq(irq, spear_pcie_gadget_irq, 0, pdev->name, NULL);
status = devm_request_irq(&pdev->dev, irq, spear_pcie_gadget_irq,
0, pdev->name, NULL);
if (status) {
dev_err(&pdev->dev,
"pcie gadget interrupt IRQ%d already claimed\n", irq);
goto err_iounmap;
return status;
}
/* Register configfs hooks */
@ -819,7 +795,7 @@ static int spear_pcie_gadget_probe(struct platform_device *pdev)
mutex_init(&subsys->su_mutex);
status = configfs_register_subsystem(subsys);
if (status)
goto err_irq;
return status;
/*
* init basic pcie application registers
@ -835,13 +811,12 @@ static int spear_pcie_gadget_probe(struct platform_device *pdev)
clk = clk_get_sys("pcie1", NULL);
if (IS_ERR(clk)) {
pr_err("%s:couldn't get clk for pcie1\n", __func__);
status = PTR_ERR(clk);
goto err_irq;
return PTR_ERR(clk);
}
status = clk_enable(clk);
if (status) {
pr_err("%s:couldn't enable clk for pcie1\n", __func__);
goto err_irq;
return status;
}
} else if (pdev->id == 2) {
/*
@ -851,53 +826,26 @@ static int spear_pcie_gadget_probe(struct platform_device *pdev)
clk = clk_get_sys("pcie2", NULL);
if (IS_ERR(clk)) {
pr_err("%s:couldn't get clk for pcie2\n", __func__);
status = PTR_ERR(clk);
goto err_irq;
return PTR_ERR(clk);
}
status = clk_enable(clk);
if (status) {
pr_err("%s:couldn't enable clk for pcie2\n", __func__);
goto err_irq;
return status;
}
}
spear13xx_pcie_device_init(config);
return 0;
err_irq:
free_irq(irq, NULL);
err_iounmap:
iounmap(config->va_dbi_base);
err_iounmap_app:
iounmap(config->va_app_base);
err_kzalloc:
kfree(target);
err_rel_res:
release_mem_region(res1->start, resource_size(res1));
err_rel_res0:
release_mem_region(res0->start, resource_size(res0));
return status;
}
static int spear_pcie_gadget_remove(struct platform_device *pdev)
{
struct resource *res0, *res1;
static struct pcie_gadget_target *target;
struct spear_pcie_gadget_config *config;
int irq;
res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
res1 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
irq = platform_get_irq(pdev, 0);
target = platform_get_drvdata(pdev);
config = &target->config;
free_irq(irq, NULL);
iounmap(config->va_dbi_base);
iounmap(config->va_app_base);
release_mem_region(res1->start, resource_size(res1));
release_mem_region(res0->start, resource_size(res0));
configfs_unregister_subsystem(&target->subsys);
kfree(target);
return 0;
}

View file

@ -153,8 +153,9 @@ static void st_reg_complete(struct st_data_s *st_gdata, char err)
(st_gdata->list[i]->priv_data, err);
pr_info("protocol %d's cb sent %d\n", i, err);
if (err) { /* cleanup registered protocol */
st_gdata->protos_registered--;
st_gdata->is_registered[i] = false;
if (st_gdata->protos_registered)
st_gdata->protos_registered--;
}
}
}
@ -639,14 +640,12 @@ long st_unregister(struct st_proto_s *proto)
return -EPROTONOSUPPORT;
}
st_gdata->protos_registered--;
if (st_gdata->protos_registered)
st_gdata->protos_registered--;
remove_channel_from_table(st_gdata, proto);
spin_unlock_irqrestore(&st_gdata->lock, flags);
/* paranoid check */
if (st_gdata->protos_registered < ST_EMPTY)
st_gdata->protos_registered = ST_EMPTY;
if ((st_gdata->protos_registered == ST_EMPTY) &&
(!test_bit(ST_REG_PENDING, &st_gdata->st_state))) {
pr_info(" all chnl_ids unregistered ");

View file

@ -328,7 +328,8 @@ int vmci_datagram_dispatch(u32 context_id,
BUILD_BUG_ON(sizeof(struct vmci_datagram) != 24);
if (VMCI_DG_SIZE(dg) > VMCI_MAX_DG_SIZE) {
if (dg->payload_size > VMCI_MAX_DG_SIZE ||
VMCI_DG_SIZE(dg) > VMCI_MAX_DG_SIZE) {
pr_devel("Payload (size=%llu bytes) too big to send\n",
(unsigned long long)dg->payload_size);
return VMCI_ERROR_INVALID_ARGS;