Commit 4f567cbc authored by Linus Torvalds's avatar Linus Torvalds

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

Pull char/misc driver update from Greg Kroah-Hartman:
 "Here's the big char / misc driver update for 3.10-rc1

  A number of various driver updates, the majority being new
  functionality in the MEI driver subsystem (it's now a subsystem, it
  started out just a single driver), extcon updates, memory updates,
  hyper-v updates, and a bunch of other small stuff that doesn't fit in
  any other tree.

  All of these have been in linux-next for a while"

* tag 'char-misc-3.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (148 commits)
  Tools: hv: Fix a checkpatch warning
  tools: hv: skip iso9660 mounts in hv_vss_daemon
  tools: hv: use FIFREEZE/FITHAW in hv_vss_daemon
  tools: hv: use getmntent in hv_vss_daemon
  Tools: hv: Fix a checkpatch warning
  tools: hv: fix checks for origin of netlink message in hv_vss_daemon
  Tools: hv: fix warnings in hv_vss_daemon
  misc: mark spear13xx-pcie-gadget as broken
  mei: fix krealloc() misuse in in mei_cl_irq_read_msg()
  mei: reduce flow control only for completed messages
  mei: reseting -> resetting
  mei: fix reading large reposnes
  mei: revamp mei_irq_read_client_message function
  mei: revamp mei_amthif_irq_read_message
  mei: revamp hbm state machine
  Revert "drivers/scsi: use module_pcmcia_driver() in pcmcia drivers"
  Revert "scsi: pcmcia: nsp_cs: remove module init/exit function prototypes"
  scsi: pcmcia: nsp_cs: remove module init/exit function prototypes
  mei: wd: fix line over 80 characters
  misc: tsl2550: Use dev_pm_ops
  ...
parents 92ddcf4a 0e272639
What: /sys/bus/mei/devices/.../modalias
Date: March 2013
KernelVersion: 3.10
Contact: Samuel Ortiz <sameo@linux.intel.com>
linux-mei@linux.intel.com
Description: Stores the same MODALIAS value emitted by uevent
Format: mei:<mei device name>
* Qualcomm SSBI
Some Qualcomm MSM devices contain a point-to-point serial bus used to
communicate with a limited range of devices (mostly power management
chips).
These require the following properties:
- compatible: "qcom,ssbi"
- qcom,controller-type
indicates the SSBI bus variant the controller should use to talk
with the slave device. This should be one of "ssbi", "ssbi2", or
"pmic-arbiter". The type chosen is determined by the attached
slave.
The slave device should be the single child node of the ssbi device
with a compatible field.
Intel(R) Management Engine (ME) Client bus API
===============================================
Rationale
=========
MEI misc character device is useful for dedicated applications to send and receive
data to the many FW appliance found in Intel's ME from the user space.
However for some of the ME functionalities it make sense to leverage existing software
stack and expose them through existing kernel subsystems.
In order to plug seamlessly into the kernel device driver model we add kernel virtual
bus abstraction on top of the MEI driver. This allows implementing linux kernel drivers
for the various MEI features as a stand alone entities found in their respective subsystem.
Existing device drivers can even potentially be re-used by adding an MEI CL bus layer to
the existing code.
MEI CL bus API
===========
A driver implementation for an MEI Client is very similar to existing bus
based device drivers. The driver registers itself as an MEI CL bus driver through
the mei_cl_driver structure:
struct mei_cl_driver {
struct device_driver driver;
const char *name;
const struct mei_cl_device_id *id_table;
int (*probe)(struct mei_cl_device *dev, const struct mei_cl_id *id);
int (*remove)(struct mei_cl_device *dev);
};
struct mei_cl_id {
char name[MEI_NAME_SIZE];
kernel_ulong_t driver_info;
};
The mei_cl_id structure allows the driver to bind itself against a device name.
To actually register a driver on the ME Client bus one must call the mei_cl_add_driver()
API. This is typically called at module init time.
Once registered on the ME Client bus, a driver will typically try to do some I/O on
this bus and this should be done through the mei_cl_send() and mei_cl_recv()
routines. The latter is synchronous (blocks and sleeps until data shows up).
In order for drivers to be notified of pending events waiting for them (e.g.
an Rx event) they can register an event handler through the
mei_cl_register_event_cb() routine. Currently only the MEI_EVENT_RX event
will trigger an event handler call and the driver implementation is supposed
to call mei_recv() from the event handler in order to fetch the pending
received buffers.
Example
=======
As a theoretical example let's pretend the ME comes with a "contact" NFC IP.
The driver init and exit routines for this device would look like:
#define CONTACT_DRIVER_NAME "contact"
static struct mei_cl_device_id contact_mei_cl_tbl[] = {
{ CONTACT_DRIVER_NAME, },
/* required last entry */
{ }
};
MODULE_DEVICE_TABLE(mei_cl, contact_mei_cl_tbl);
static struct mei_cl_driver contact_driver = {
.id_table = contact_mei_tbl,
.name = CONTACT_DRIVER_NAME,
.probe = contact_probe,
.remove = contact_remove,
};
static int contact_init(void)
{
int r;
r = mei_cl_driver_register(&contact_driver);
if (r) {
pr_err(CONTACT_DRIVER_NAME ": driver registration failed\n");
return r;
}
return 0;
}
static void __exit contact_exit(void)
{
mei_cl_driver_unregister(&contact_driver);
}
module_init(contact_init);
module_exit(contact_exit);
And the driver's simplified probe routine would look like that:
int contact_probe(struct mei_cl_device *dev, struct mei_cl_device_id *id)
{
struct contact_driver *contact;
[...]
mei_cl_enable_device(dev);
mei_cl_register_event_cb(dev, contact_event_cb, contact);
return 0;
}
In the probe routine the driver first enable the MEI device and then registers
an ME bus event handler which is as close as it can get to registering a
threaded IRQ handler.
The handler implementation will typically call some I/O routine depending on
the pending events:
#define MAX_NFC_PAYLOAD 128
static void contact_event_cb(struct mei_cl_device *dev, u32 events,
void *context)
{
struct contact_driver *contact = context;
if (events & BIT(MEI_EVENT_RX)) {
u8 payload[MAX_NFC_PAYLOAD];
int payload_size;
payload_size = mei_recv(dev, payload, MAX_NFC_PAYLOAD);
if (payload_size <= 0)
return;
/* Hook to the NFC subsystem */
nfc_hci_recv_frame(contact->hdev, payload, payload_size);
}
}
......@@ -1031,6 +1031,7 @@ F: drivers/mmc/host/msm_sdcc.h
F: drivers/tty/serial/msm_serial.h
F: drivers/tty/serial/msm_serial.c
F: drivers/*/pm8???-*
F: drivers/ssbi/
F: include/linux/mfd/pm8xxx/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/davidb/linux-msm.git
S: Maintained
......
......@@ -38,4 +38,10 @@ serial@19c400000 {
<0x19c00000 0x1000>;
interrupts = <0 195 0x0>;
};
qcom,ssbi@500000 {
compatible = "qcom,ssbi";
reg = <0x500000 0x1000>;
qcom,controller-type = "pmic-arbiter";
};
};
......@@ -38,4 +38,10 @@ serial@19c400000 {
<0x16400000 0x1000>;
interrupts = <0 154 0x0>;
};
qcom,ssbi@500000 {
compatible = "qcom,ssbi";
reg = <0x500000 0x1000>;
qcom,controller-type = "pmic-arbiter";
};
};
......@@ -52,6 +52,8 @@ source "drivers/i2c/Kconfig"
source "drivers/spi/Kconfig"
source "drivers/ssbi/Kconfig"
source "drivers/hsi/Kconfig"
source "drivers/pps/Kconfig"
......
......@@ -114,6 +114,7 @@ obj-y += firmware/
obj-$(CONFIG_CRYPTO) += crypto/
obj-$(CONFIG_SUPERH) += sh/
obj-$(CONFIG_ARCH_SHMOBILE) += sh/
obj-$(CONFIG_SSBI) += ssbi/
ifndef CONFIG_ARCH_USES_GETTIMEOFFSET
obj-y += clocksource/
endif
......
......@@ -387,21 +387,9 @@ static struct pcmcia_driver pcmcia_driver = {
.probe = pcmcia_init_one,
.remove = pcmcia_remove_one,
};
static int __init pcmcia_init(void)
{
return pcmcia_register_driver(&pcmcia_driver);
}
static void __exit pcmcia_exit(void)
{
pcmcia_unregister_driver(&pcmcia_driver);
}
module_pcmcia_driver(pcmcia_driver);
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("low-level driver for PCMCIA ATA");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
module_init(pcmcia_init);
module_exit(pcmcia_exit);
......@@ -934,17 +934,4 @@ static struct pcmcia_driver bluecard_driver = {
.remove = bluecard_detach,
.id_table = bluecard_ids,
};
static int __init init_bluecard_cs(void)
{
return pcmcia_register_driver(&bluecard_driver);
}
static void __exit exit_bluecard_cs(void)
{
pcmcia_unregister_driver(&bluecard_driver);
}
module_init(init_bluecard_cs);
module_exit(exit_bluecard_cs);
module_pcmcia_driver(bluecard_driver);
......@@ -760,17 +760,4 @@ static struct pcmcia_driver bt3c_driver = {
.remove = bt3c_detach,
.id_table = bt3c_ids,
};
static int __init init_bt3c_cs(void)
{
return pcmcia_register_driver(&bt3c_driver);
}
static void __exit exit_bt3c_cs(void)
{
pcmcia_unregister_driver(&bt3c_driver);
}
module_init(init_bt3c_cs);
module_exit(exit_bt3c_cs);
module_pcmcia_driver(bt3c_driver);
......@@ -688,17 +688,4 @@ static struct pcmcia_driver btuart_driver = {
.remove = btuart_detach,
.id_table = btuart_ids,
};
static int __init init_btuart_cs(void)
{
return pcmcia_register_driver(&btuart_driver);
}
static void __exit exit_btuart_cs(void)
{
pcmcia_unregister_driver(&btuart_driver);
}
module_init(init_btuart_cs);
module_exit(exit_btuart_cs);
module_pcmcia_driver(btuart_driver);
......@@ -628,17 +628,4 @@ static struct pcmcia_driver dtl1_driver = {
.remove = dtl1_detach,
.id_table = dtl1_ids,
};
static int __init init_dtl1_cs(void)
{
return pcmcia_register_driver(&dtl1_driver);
}
static void __exit exit_dtl1_cs(void)
{
pcmcia_unregister_driver(&dtl1_driver);
}
module_init(init_dtl1_cs);
module_exit(exit_dtl1_cs);
module_pcmcia_driver(dtl1_driver);
......@@ -804,8 +804,8 @@ static long ac_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
printk(KERN_INFO "Prom version board %d ....... V%d.%d %s",
i+1,
(int)(readb(apbs[IndexCard].RamIO + VERS) >> 4),
(int)(readb(apbs[IndexCard].RamIO + VERS) & 0xF),
(int)(readb(apbs[i].RamIO + VERS) >> 4),
(int)(readb(apbs[i].RamIO + VERS) & 0xF),
boardname);
......
......@@ -228,18 +228,7 @@ static struct platform_driver mxc_rnga_driver = {
.remove = __exit_p(mxc_rnga_remove),
};
static int __init mod_init(void)
{
return platform_driver_probe(&mxc_rnga_driver, mxc_rnga_probe);
}
static void __exit mod_exit(void)
{
platform_driver_unregister(&mxc_rnga_driver);
}
module_init(mod_init);
module_exit(mod_exit);
module_platform_driver_probe(mxc_rnga_driver, mxc_rnga_probe);
MODULE_AUTHOR("Freescale Semiconductor, Inc.");
MODULE_DESCRIPTION("H/W RNGA driver for i.MX");
......
......@@ -166,18 +166,7 @@ static struct platform_driver tx4939_rng_driver = {
.remove = tx4939_rng_remove,
};
static int __init tx4939rng_init(void)
{
return platform_driver_probe(&tx4939_rng_driver, tx4939_rng_probe);
}
static void __exit tx4939rng_exit(void)
{
platform_driver_unregister(&tx4939_rng_driver);
}
module_init(tx4939rng_init);
module_exit(tx4939rng_exit);
module_platform_driver_probe(tx4939_rng_driver, tx4939_rng_probe);
MODULE_DESCRIPTION("H/W Random Number Generator (RNG) driver for TX4939");
MODULE_LICENSE("GPL");
......@@ -371,7 +371,7 @@ static int srom_setup_minor(struct srom_dev *srom, int index)
dev = device_create(srom_class, &platform_bus,
MKDEV(srom_major, index), srom, "%d", index);
return IS_ERR(dev) ? PTR_ERR(dev) : 0;
return PTR_RET(dev);
}
/** srom_init() - Initialize the driver's module. */
......
This diff is collapsed.
......@@ -38,7 +38,7 @@
* extcon-max77693 driver use 'default_init_data' to bring up base operation
* of MAX77693 MUIC device.
*/
struct max77693_reg_data default_init_data[] = {
static struct max77693_reg_data default_init_data[] = {
{
/* STATUS2 - [3]ChgDetRun */
.addr = MAX77693_MUIC_REG_STATUS2,
......@@ -258,7 +258,7 @@ static int max77693_muic_set_debounce_time(struct max77693_muic_info *info,
CONTROL3_ADCDBSET_MASK);
if (ret) {
dev_err(info->dev, "failed to set ADC debounce time\n");
return -EAGAIN;
return ret;
}
break;
default:
......@@ -294,7 +294,7 @@ static int max77693_muic_set_path(struct max77693_muic_info *info,
MAX77693_MUIC_REG_CTRL1, ctrl1, COMP_SW_MASK);
if (ret < 0) {
dev_err(info->dev, "failed to update MUIC register\n");
return -EAGAIN;
return ret;
}
if (attached)
......@@ -307,7 +307,7 @@ static int max77693_muic_set_path(struct max77693_muic_info *info,
CONTROL2_LOWPWR_MASK | CONTROL2_CPEN_MASK);
if (ret < 0) {
dev_err(info->dev, "failed to update MUIC register\n");
return -EAGAIN;
return ret;
}
dev_info(info->dev,
......@@ -1035,7 +1035,7 @@ static int max77693_muic_detect_accessory(struct max77693_muic_info *info)
if (ret) {
dev_err(info->dev, "failed to read MUIC register\n");
mutex_unlock(&info->mutex);
return -EINVAL;
return ret;
}
adc = max77693_muic_get_cable_type(info, MAX77693_CABLE_GROUP_ADC,
......
......@@ -196,7 +196,7 @@ static int max8997_muic_set_debounce_time(struct max8997_muic_info *info,
CONTROL3_ADCDBSET_MASK);
if (ret) {
dev_err(info->dev, "failed to set ADC debounce time\n");
return -EAGAIN;
return ret;
}
break;
default:
......@@ -232,7 +232,7 @@ static int max8997_muic_set_path(struct max8997_muic_info *info,
MAX8997_MUIC_REG_CONTROL1, ctrl1, COMP_SW_MASK);
if (ret < 0) {
dev_err(info->dev, "failed to update MUIC register\n");
return -EAGAIN;
return ret;
}
if (attached)
......@@ -245,7 +245,7 @@ static int max8997_muic_set_path(struct max8997_muic_info *info,
CONTROL2_LOWPWR_MASK | CONTROL2_CPEN_MASK);
if (ret < 0) {
dev_err(info->dev, "failed to update MUIC register\n");
return -EAGAIN;
return ret;
}
dev_info(info->dev,
......@@ -397,7 +397,7 @@ static int max8997_muic_handle_jig_uart(struct max8997_muic_info *info,
ret = max8997_muic_set_path(info, info->path_uart, attached);
if (ret) {
dev_err(info->dev, "failed to update muic register\n");
return -EINVAL;
return ret;
}
extcon_set_cable_state(info->edev, "JIG", attached);
......@@ -608,7 +608,7 @@ static int max8997_muic_detect_dev(struct max8997_muic_info *info)
if (ret) {
dev_err(info->dev, "failed to read MUIC register\n");
mutex_unlock(&info->mutex);
return -EINVAL;
return ret;
}
adc = max8997_muic_get_cable_type(info, MAX8997_CABLE_GROUP_ADC,
......@@ -646,7 +646,7 @@ static void max8997_muic_detect_cable_wq(struct work_struct *work)
ret = max8997_muic_detect_dev(info);
if (ret < 0)
pr_err("failed to detect cable type\n");
dev_err(info->dev, "failed to detect cable type\n");
}
static int max8997_muic_probe(struct platform_device *pdev)
......
......@@ -5,4 +5,4 @@ obj-$(CONFIG_HYPERV_BALLOON) += hv_balloon.o
hv_vmbus-y := vmbus_drv.o \
hv.o connection.o channel.o \
channel_mgmt.o ring_buffer.o
hv_utils-y := hv_util.o hv_kvp.o
hv_utils-y := hv_util.o hv_kvp.o hv_snapshot.o
......@@ -165,8 +165,19 @@ static void vmbus_process_rescind_offer(struct work_struct *work)
struct vmbus_channel *channel = container_of(work,
struct vmbus_channel,
work);
unsigned long flags;
struct vmbus_channel_relid_released msg;
vmbus_device_unregister(channel->device_obj);
memset(&msg, 0, sizeof(struct vmbus_channel_relid_released));
msg.child_relid = channel->offermsg.child_relid;
msg.header.msgtype = CHANNELMSG_RELID_RELEASED;
vmbus_post_msg(&msg, sizeof(struct vmbus_channel_relid_released));
spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
list_del(&channel->listentry);
spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
free_channel(channel);
}
void vmbus_free_channels(void)
......
......@@ -289,9 +289,8 @@ void hv_synic_init(void *arg)
/* Check the version */
rdmsrl(HV_X64_MSR_SVERSION, version);
hv_context.event_dpc[cpu] = (struct tasklet_struct *)
kmalloc(sizeof(struct tasklet_struct),
GFP_ATOMIC);
hv_context.event_dpc[cpu] = kmalloc(sizeof(struct tasklet_struct),
GFP_ATOMIC);
if (hv_context.event_dpc[cpu] == NULL) {
pr_err("Unable to allocate event dpc\n");
goto cleanup;
......
This diff is collapsed.
/*
* An implementation of host initiated guest snapshot.
*
*
* Copyright (C) 2013, Microsoft, Inc.
* Author : K. Y. Srinivasan <kys@microsoft.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
* NON INFRINGEMENT. See the GNU General Public License for more
* details.
*
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/net.h>
#include <linux/nls.h>
#include <linux/connector.h>
#include <linux/workqueue.h>
#include <linux/hyperv.h>
/*
* Global state maintained for transaction that is being processed.
* Note that only one transaction can be active at any point in time.
*
* This state is set when we receive a request from the host; we
* cleanup this state when the transaction is completed - when we respond
* to the host with the key value.
*/
static struct {
bool active; /* transaction status - active or not */
int recv_len; /* number of bytes received. */
struct vmbus_channel *recv_channel; /* chn we got the request */
u64 recv_req_id; /* request ID. */
struct hv_vss_msg *msg; /* current message */
} vss_transaction;
static void vss_respond_to_host(int error);
static struct cb_id vss_id = { CN_VSS_IDX, CN_VSS_VAL };
static const char vss_name[] = "vss_kernel_module";
static __u8 *recv_buffer;
static void vss_send_op(struct work_struct *dummy);
static DECLARE_WORK(vss_send_op_work, vss_send_op);
/*
* Callback when data is received from user mode.
*/
static void
vss_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp)
{
struct hv_vss_msg *vss_msg;
vss_msg = (struct hv_vss_msg *)msg->data;
if (vss_msg->vss_hdr.operation == VSS_OP_REGISTER) {
pr_info("VSS daemon registered\n");
vss_transaction.active = false;
if (vss_transaction.recv_channel != NULL)
hv_vss_onchannelcallback(vss_transaction.recv_channel);
return;
}
vss_respond_to_host(vss_msg->error);
}
static void vss_send_op(struct work_struct *dummy)
{
int op = vss_transaction.msg->vss_hdr.operation;
struct cn_msg *msg;
struct hv_vss_msg *vss_msg;
msg = kzalloc(sizeof(*msg) + sizeof(*vss_msg), GFP_ATOMIC);
if (!msg)
return;
vss_msg = (struct hv_vss_msg *)msg->data;
msg->id.idx = CN_VSS_IDX;
msg->id.val = CN_VSS_VAL;
vss_msg->vss_hdr.operation = op;
msg->len = sizeof(struct hv_vss_msg);
cn_netlink_send(msg, 0, GFP_ATOMIC);
kfree(msg);
return;
}
/*
* Send a response back to the host.
*/
static void
vss_respond_to_host(int error)
{
struct icmsg_hdr *icmsghdrp;
u32 buf_len;
struct vmbus_channel *channel;
u64 req_id;
/*
* If a transaction is not active; log and return.
*/
if (!vss_transaction.active) {
/*
* This is a spurious call!
*/
pr_warn("VSS: Transaction not active\n");
return;
}
/*
* Copy the global state for completing the transaction. Note that
* only one transaction can be active at a time.
*/
buf_len = vss_transaction.recv_len;
channel = vss_transaction.recv_channel;
req_id = vss_transaction.recv_req_id;
vss_transaction.active = false;
icmsghdrp = (struct icmsg_hdr *)
&recv_buffer[sizeof(struct vmbuspipe_hdr)];
if (channel->onchannel_callback == NULL)
/*
* We have raced with util driver being unloaded;
* silently return.
*/
return;
icmsghdrp->status = error;
icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE;
vmbus_sendpacket(channel, recv_buffer, buf_len, req_id,
VM_PKT_DATA_INBAND, 0);
}
/*
* This callback is invoked when we get a VSS message from the host.
* The host ensures that only one VSS transaction can be active at a time.
*/
void hv_vss_onchannelcallback(void *context)
{
struct vmbus_channel *channel = context;
u32 recvlen;
u64 requestid;
struct hv_vss_msg *vss_msg;
struct icmsg_hdr *icmsghdrp;
struct icmsg_negotiate *negop = NULL;
if (vss_transaction.active) {
/*
* We will defer processing this callback once
* the current transaction is complete.
*/
vss_transaction.recv_channel = channel;
return;
}
vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE * 2, &recvlen,
&requestid);
if (recvlen > 0) {
icmsghdrp = (struct icmsg_hdr *)&recv_buffer[
sizeof(struct vmbuspipe_hdr)];
if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
vmbus_prep_negotiate_resp(icmsghdrp, negop,
recv_buffer, MAX_SRV_VER, MAX_SRV_VER);
/*
* We currently negotiate the highest number the
* host has presented. If this version is not
* atleast 5.0, reject.
*/
negop = (struct icmsg_negotiate *)&recv_buffer[
sizeof(struct vmbuspipe_hdr) +
sizeof(struct icmsg_hdr)];
if (negop->icversion_data[1].major < 5)
negop->icframe_vercnt = 0;
} else {
vss_msg = (struct hv_vss_msg *)&recv_buffer[
sizeof(struct vmbuspipe_hdr) +
sizeof(struct icmsg_hdr)];
/*
* Stash away this global state for completing the
* transaction; note transactions are serialized.
*/
vss_transaction.recv_len = recvlen;
vss_transaction.recv_channel = channel;
vss_transaction.recv_req_id = requestid;
vss_transaction.active = true;
vss_transaction.msg = (struct hv_vss_msg *)vss_msg;
switch (vss_msg->vss_hdr.operation) {
/*
* Initiate a "freeze/thaw"
* operation in the guest.
* We respond to the host once
* the operation is complete.
*
* We send the message to the
* user space daemon and the
* operation is performed in
* the daemon.
*/
case VSS_OP_FREEZE:
case VSS_OP_THAW:
schedule_work(&vss_send_op_work);
return;
case VSS_OP_HOT_BACKUP:
vss_msg->vss_cf.flags =
VSS_HBU_NO_AUTO_RECOVERY;
vss_respond_to_host(0);
return;
case VSS_OP_GET_DM_INFO:
vss_msg->dm_info.flags = 0;
vss_respond_to_host(0);
return;
default:
vss_respond_to_host(0);
return;
}
}
icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
| ICMSGHDRFLAG_RESPONSE;
vmbus_sendpacket(channel, recv_buffer,
recvlen, requestid,
VM_PKT_DATA_INBAND, 0);
}
}
int
hv_vss_init(struct hv_util_service *srv)
{
int err;
err = cn_add_callback(&vss_id, vss_name, vss_cn_callback);
if (err)
return err;
recv_buffer = srv->recv_buffer;
/*
* When this driver loads, the user level daemon that
* processes the host requests may not yet be running.
* Defer processing channel callbacks until the daemon
* has registered.
*/
vss_transaction.active = true;
return 0;
}
void hv_vss_deinit(void)
{
cn_del_callback(&vss_id);
cancel_work_sync(&vss_send_op_work);
}
......@@ -49,6 +49,12 @@ static struct hv_util_service util_kvp = {
.util_deinit = hv_kvp_deinit,
};
static struct hv_util_service util_vss = {
.util_cb = hv_vss_onchannelcallback,
.util_init = hv_vss_init,
.util_deinit = hv_vss_deinit,
};
static void perform_shutdown(struct work_struct *dummy)
{
orderly_poweroff(true);
......@@ -339,6 +345,10 @@ static const struct hv_vmbus_device_id id_table[] = {
{ HV_KVP_GUID,
.driver_data = (unsigned long)&util_kvp
},
/* VSS GUID */
{ HV_VSS_GUID,
.driver_data = (unsigned long)&util_vss
},
{ },
};
......
......@@ -71,6 +71,7 @@ u32 hv_end_read(struct hv_ring_buffer_info *rbi)
static bool hv_need_to_signal(u32 old_write, struct hv_ring_buffer_info *rbi)
{
smp_mb();
if (rbi->ring_buffer->interrupt_mask)
return false;
......
......@@ -480,6 +480,7 @@ static void tpci200_release_device(struct ipack_device *dev)
static int tpci200_create_device(struct tpci200_board *tpci200, int i)
{
int ret;
enum ipack_space space;
struct ipack_device *dev =
kzalloc(sizeof(struct ipack_device), GFP_KERNEL);
......@@ -495,7 +496,18 @@ static int tpci200_create_device(struct tpci200_board *tpci200, int i)
+ tpci200_space_interval[space] * i;
dev->region[space].size = tpci200_space_size[space];
}
return ipack_device_register(dev);
ret = ipack_device_init(dev);
if (ret < 0) {
ipack_put_device(dev);
return ret;
}
ret = ipack_device_add(dev);
if (ret < 0)
ipack_put_device(dev);
return ret;
}
static int tpci200_pci_probe(struct pci_dev *pdev,
......
......@@ -227,7 +227,7 @@ static int ipack_unregister_bus_member(struct device *dev, void *data)
struct ipack_bus_device *bus = data;
if (idev->bus == bus)
ipack_device_unregister(idev);
ipack_device_del(idev);
return 1;
}
......@@ -419,7 +419,7 @@ static int ipack_device_read_id(struct ipack_device *dev)
return ret;
}
int ipack_device_register(struct ipack_device *dev)
int ipack_device_init(struct ipack_device *dev)
{
int ret;
......@@ -428,6 +428,7 @@ int ipack_device_register(struct ipack_device *dev)
dev->dev.parent = dev->bus->parent;
dev_set_name(&dev->dev,
"ipack-dev.%u.%u", dev->bus->bus_nr, dev->slot);
device_initialize(&dev->dev);
if (dev->bus->ops->set_clockrate(dev, 8))
dev_warn(&dev->dev, "failed to switch to 8 MHz operation for reading of device ID.\n");
......@@ -447,19 +448,34 @@ int ipack_device_register(struct ipack_device *dev)
dev_err(&dev->dev, "failed to switch to 32 MHz operation.\n");
}
ret = device_register(&dev->dev);
if (ret < 0)
kfree(dev->id);
return 0;
}
EXPORT_SYMBOL_GPL(ipack_device_init);
return ret;
int ipack_device_add(struct ipack_device *dev)
{
return device_add(&dev->dev);
}
EXPORT_SYMBOL_GPL(ipack_device_add);
void ipack_device_del(struct ipack_device *dev)
{
device_del(&dev->dev);
ipack_put_device(dev);
}
EXPORT_SYMBOL_GPL(ipack_device_del);
void ipack_get_device(struct ipack_device *dev)
{
get_device(&dev->dev);
}
EXPORT_SYMBOL_GPL(ipack_device_register);
EXPORT_SYMBOL_GPL(ipack_get_device);
void ipack_device_unregister(struct ipack_device *dev)
void ipack_put_device(struct ipack_device *dev)
{
device_unregister(&dev->dev);
put_device(&dev->dev);
}
EXPORT_SYMBOL_GPL(ipack_device_unregister);
EXPORT_SYMBOL_GPL(ipack_put_device);
static int __init ipack_init(void)
{
......
......@@ -163,16 +163,4 @@ static struct pcmcia_driver avmcs_driver = {
.remove = avmcs_detach,
.id_table = avmcs_ids,
};
static int __init avmcs_init(void)
{
return pcmcia_register_driver(&avmcs_driver);
}
static void __exit avmcs_exit(void)
{
pcmcia_unregister_driver(&avmcs_driver);
}
module_init(avmcs_init);
module_exit(avmcs_exit);
module_pcmcia_driver(avmcs_driver);
......@@ -159,16 +159,4 @@ static struct pcmcia_driver avma1cs_driver = {
.remove = avma1cs_detach,
.id_table = avma1cs_ids,
};
static int __init init_avma1_cs(void)
{
return pcmcia_register_driver(&avma1cs_driver);
}
static void __exit exit_avma1_cs(void)
{
pcmcia_unregister_driver(&avma1cs_driver);
}
module_init(init_avma1_cs);
module_exit(exit_avma1_cs);
module_pcmcia_driver(avma1cs_driver);
......@@ -215,16 +215,4 @@ static struct pcmcia_driver elsa_cs_driver = {
.suspend = elsa_suspend,
.resume = elsa_resume,
};
static int __init init_elsa_cs(void)
{
return pcmcia_register_driver(&elsa_cs_driver);
}
static void __exit exit_elsa_cs(void)
{
pcmcia_unregister_driver(&elsa_cs_driver);
}
module_init(init_elsa_cs);
module_exit(exit_elsa_cs);
module_pcmcia_driver(elsa_cs_driver);
......@@ -206,16 +206,4 @@ static struct pcmcia_driver sedlbauer_driver = {
.suspend = sedlbauer_suspend,
.resume = sedlbauer_resume,
};
static int __init init_sedlbauer_cs(void)
{
return pcmcia_register_driver(&sedlbauer_driver);
}
static void __exit exit_sedlbauer_cs(void)
{
pcmcia_unregister_driver(&sedlbauer_driver);
}
module_init(init_sedlbauer_cs);
module_exit(exit_sedlbauer_cs);
module_pcmcia_driver(sedlbauer_driver);
......@@ -197,16 +197,4 @@ static struct pcmcia_driver teles_cs_driver = {
.suspend = teles_suspend,
.resume = teles_resume,
};
static int __init init_teles_cs(void)
{
return pcmcia_register_driver(&teles_cs_driver);
}
static void __exit exit_teles_cs(void)
{
pcmcia_unregister_driver(&teles_cs_driver);
}
module_init(init_teles_cs);
module_exit(exit_teles_cs);
module_pcmcia_driver(teles_cs_driver);
......@@ -25,6 +25,7 @@
#include <linux/module.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/pm.h>
#include <memory/jedec_ddr.h>
#include "emif.h"
#include "of_memory.h"
......@@ -256,6 +257,41 @@ static void set_lpmode(struct emif_data *emif, u8 lpmode)
u32 temp;
void __iomem *base = emif->base;
/*
* Workaround for errata i743 - LPDDR2 Power-Down State is Not
* Efficient
*
* i743 DESCRIPTION:
* The EMIF supports power-down state for low power. The EMIF
* automatically puts the SDRAM into power-down after the memory is
* not accessed for a defined number of cycles and the
* EMIF_PWR_MGMT_CTRL[10:8] REG_LP_MODE bit field is set to 0x4.
* As the EMIF supports automatic output impedance calibration, a ZQ
* calibration long command is issued every time it exits active
* power-down and precharge power-down modes. The EMIF waits and
* blocks any other command during this calibration.
* The EMIF does not allow selective disabling of ZQ calibration upon
* exit of power-down mode. Due to very short periods of power-down
* cycles, ZQ calibration overhead creates bandwidth issues and
* increases overall system power consumption. On the other hand,
* issuing ZQ calibration long commands when exiting self-refresh is
* still required.
*
* WORKAROUND
* Because there is no power consumption benefit of the power-down due
* to the calibration and there is a performance risk, the guideline
* is to not allow power-down state and, therefore, to not have set
* the EMIF_PWR_MGMT_CTRL[10:8] REG_LP_MODE bit field to 0x4.
*/
if ((emif->plat_data->ip_rev == EMIF_4D) &&
(EMIF_LP_MODE_PWR_DN == lpmode)) {
WARN_ONCE(1,
"REG_LP_MODE = LP_MODE_PWR_DN(4) is prohibited by"
"erratum i743 switch to LP_MODE_SELF_REFRESH(2)\n");
/* rollback LP_MODE to Self-refresh mode */
lpmode = EMIF_LP_MODE_SELF_REFRESH;
}
temp = readl(base + EMIF_POWER_MANAGEMENT_CONTROL);
temp &= ~LP_MODE_MASK;
temp |= (lpmode << LP_MODE_SHIFT);
......@@ -715,6 +751,8 @@ static u32 get_pwr_mgmt_ctrl(u32 freq, struct emif_data *emif, u32 ip_rev)
u32 timeout_perf = EMIF_LP_MODE_TIMEOUT_PERFORMANCE;
u32 timeout_pwr = EMIF_LP_MODE_TIMEOUT_POWER;
u32 freq_threshold = EMIF_LP_MODE_FREQ_THRESHOLD;
u32 mask;
u8 shift;
struct emif_custom_configs *cust_cfgs = emif->plat_data->custom_configs;
......@@ -728,37 +766,59 @@ static u32 get_pwr_mgmt_ctrl(u32 freq, struct emif_data *emif, u32 ip_rev)
/* Timeout based on DDR frequency */
timeout = freq >= freq_threshold ? timeout_perf : timeout_pwr;
/* The value to be set in register is "log2(timeout) - 3" */
/*
* The value to be set in register is "log2(timeout) - 3"
* if timeout < 16 load 0 in register
* if timeout is not a power of 2, round to next highest power of 2
*/
if (timeout < 16) {
timeout = 0;
} else {
timeout = __fls(timeout) - 3;
if (timeout & (timeout - 1))
timeout++;
timeout <<= 1;
timeout = __fls(timeout) - 3;
}
switch (lpmode) {
case EMIF_LP_MODE_CLOCK_STOP:
pwr_mgmt_ctrl = (timeout << CS_TIM_SHIFT) |
SR_TIM_MASK | PD_TIM_MASK;
shift = CS_TIM_SHIFT;
mask = CS_TIM_MASK;
break;
case EMIF_LP_MODE_SELF_REFRESH:
/* Workaround for errata i735 */
if (timeout < 6)
timeout = 6;
pwr_mgmt_ctrl = (timeout << SR_TIM_SHIFT) |
CS_TIM_MASK | PD_TIM_MASK;
shift = SR_TIM_SHIFT;
mask = SR_TIM_MASK;
break;
case EMIF_LP_MODE_PWR_DN:
pwr_mgmt_ctrl = (timeout << PD_TIM_SHIFT) |
CS_TIM_MASK | SR_TIM_MASK;
shift = PD_TIM_SHIFT;
mask = PD_TIM_MASK;
break;
case EMIF_LP_MODE_DISABLE:
default:
pwr_mgmt_ctrl = CS_TIM_MASK |
PD_TIM_MASK | SR_TIM_MASK;
mask = 0;
shift = 0;
break;
}
/* Round to maximum in case of overflow, BUT warn! */
if (lpmode != EMIF_LP_MODE_DISABLE && timeout > mask >> shift) {
pr_err("TIMEOUT Overflow - lpmode=%d perf=%d pwr=%d freq=%d\n",
lpmode,
timeout_perf,
timeout_pwr,
freq_threshold);
WARN(1, "timeout=0x%02x greater than 0x%02x. Using max\n",
timeout, mask >> shift);
timeout = mask >> shift;
}
/* Setup required timing */
pwr_mgmt_ctrl = (timeout << shift) & mask;
/* setup a default mask for rest of the modes */
pwr_mgmt_ctrl |= (SR_TIM_MASK | CS_TIM_MASK | PD_TIM_MASK) &
~mask;
/* No CS_TIM in EMIF_4D5 */
if (ip_rev == EMIF_4D5)
......@@ -815,6 +875,8 @@ static void setup_registers(struct emif_data *emif, struct emif_regs *regs)
writel(regs->sdram_tim2_shdw, base + EMIF_SDRAM_TIMING_2_SHDW);
writel(regs->phy_ctrl_1_shdw, base + EMIF_DDR_PHY_CTRL_1_SHDW);
writel(regs->pwr_mgmt_ctrl_shdw,
base + EMIF_POWER_MANAGEMENT_CTRL_SHDW);
/* Settings specific for EMIF4D5 */
if (emif->plat_data->ip_rev != EMIF_4D5)
......@@ -892,6 +954,7 @@ static irqreturn_t handle_temp_alert(void __iomem *base, struct emif_data *emif)
{
u32 old_temp_level;
irqreturn_t ret = IRQ_HANDLED;
struct emif_custom_configs *custom_configs;
spin_lock_irqsave(&emif_lock, irq_state);
old_temp_level = emif->temperature_level;
......@@ -904,6 +967,29 @@ static irqreturn_t handle_temp_alert(void __iomem *base, struct emif_data *emif)
goto out;
}
custom_configs = emif->plat_data->custom_configs;
/*
* IF we detect higher than "nominal rating" from DDR sensor
* on an unsupported DDR part, shutdown system
*/
if (custom_configs && !(custom_configs->mask &
EMIF_CUSTOM_CONFIG_EXTENDED_TEMP_PART)) {
if (emif->temperature_level >= SDRAM_TEMP_HIGH_DERATE_REFRESH) {
dev_err(emif->dev,
"%s:NOT Extended temperature capable memory."
"Converting MR4=0x%02x as shutdown event\n",
__func__, emif->temperature_level);
/*
* Temperature far too high - do kernel_power_off()
* from thread context
*/
emif->temperature_level = SDRAM_TEMP_VERY_HIGH_SHUTDOWN;
ret = IRQ_WAKE_THREAD;
goto out;
}
}
if (emif->temperature_level < old_temp_level ||
emif->temperature_level == SDRAM_TEMP_VERY_HIGH_SHUTDOWN) {
/*
......@@ -965,7 +1051,14 @@ static irqreturn_t emif_threaded_isr(int irq, void *dev_id)
if (emif->temperature_level == SDRAM_TEMP_VERY_HIGH_SHUTDOWN) {
dev_emerg(emif->dev, "SDRAM temperature exceeds operating limit.. Needs shut down!!!\n");
kernel_power_off();
/* If we have Power OFF ability, use it, else try restarting */
if (pm_power_off) {
kernel_power_off();
} else {
WARN(1, "FIXME: NO pm_power_off!!! trying restart\n");
kernel_restart("SDRAM Over-temp Emergency restart");
}
return IRQ_HANDLED;
}
......@@ -1170,7 +1263,7 @@ static void __init_or_module of_get_custom_configs(struct device_node *np_emif,
{
struct emif_custom_configs *cust_cfgs = NULL;
int len;
const int *lpmode, *poll_intvl;
const __be32 *lpmode, *poll_intvl;
lpmode = of_get_property(np_emif, "low-power-mode", &len);
poll_intvl = of_get_property(np_emif, "temp-alert-poll-interval", &len);
......@@ -1184,7 +1277,7 @@ static void __init_or_module of_get_custom_configs(struct device_node *np_emif,
if (lpmode) {
cust_cfgs->mask |= EMIF_CUSTOM_CONFIG_LPMODE;
cust_cfgs->lpmode = *lpmode;
cust_cfgs->lpmode = be32_to_cpup(lpmode);
of_property_read_u32(np_emif,
"low-power-mode-timeout-performance",
&cust_cfgs->lpmode_timeout_performance);
......@@ -1199,9 +1292,13 @@ static void __init_or_module of_get_custom_configs(struct device_node *np_emif,
if (poll_intvl) {
cust_cfgs->mask |=
EMIF_CUSTOM_CONFIG_TEMP_ALERT_POLL_INTERVAL;
cust_cfgs->temp_alert_poll_interval_ms = *poll_intvl;
cust_cfgs->temp_alert_poll_interval_ms =
be32_to_cpup(poll_intvl);
}
if (of_find_property(np_emif, "extended-temp-part", &len))
cust_cfgs->mask |= EMIF_CUSTOM_CONFIG_EXTENDED_TEMP_PART;
if (!is_custom_config_valid(cust_cfgs, emif->dev)) {
devm_kfree(emif->dev, cust_cfgs);
return;
......@@ -1407,7 +1504,7 @@ static struct emif_data *__init_or_module get_device_details(
if (pd->timings) {
temp = devm_kzalloc(dev, size, GFP_KERNEL);
if (temp) {
memcpy(temp, pd->timings, sizeof(*pd->timings));
memcpy(temp, pd->timings, size);
pd->timings = temp;
} else {
dev_warn(dev, "%s:%d: allocation error\n", __func__,
......@@ -1841,18 +1938,8 @@ static struct platform_driver emif_driver = {
},
};
static int __init_or_module emif_register(void)
{
return platform_driver_probe(&emif_driver, emif_probe);
}
static void __exit emif_unregister(void)
{
platform_driver_unregister(&emif_driver);
}
module_platform_driver_probe(emif_driver, emif_probe);
module_init(emif_register);
module_exit(emif_unregister);
MODULE_DESCRIPTION("TI EMIF SDRAM Controller Driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:emif");
......
......@@ -268,6 +268,7 @@ static const u32 tegra30_mc_ctx[] = {
MC_INTMASK,
};
#ifdef CONFIG_PM
static int tegra30_mc_suspend(struct device *dev)
{
int i;
......@@ -291,6 +292,7 @@ static int tegra30_mc_resume(struct device *dev)
mc_readl(mc, MC_TIMING_CONTROL);
return 0;
}
#endif
static UNIVERSAL_DEV_PM_OPS(tegra30_mc_pm,
tegra30_mc_suspend,
......
......@@ -991,7 +991,7 @@ config MFD_PM8XXX
config MFD_PM8921_CORE
tristate "Qualcomm PM8921 PMIC chip"
depends on MSM_SSBI
depends on SSBI && BROKEN
select MFD_CORE
select MFD_PM8XXX
help
......
......@@ -17,7 +17,7 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/msm_ssbi.h>
#include <linux/ssbi.h>
#include <linux/mfd/core.h>
#include <linux/mfd/pm8xxx/pm8921.h>
#include <linux/mfd/pm8xxx/core.h>
......@@ -35,7 +35,7 @@ static int pm8921_readb(const struct device *dev, u16 addr, u8 *val)
const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev);
const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data;
return msm_ssbi_read(pmic->dev->parent, addr, val, 1);
return ssbi_read(pmic->dev->parent, addr, val, 1);
}
static int pm8921_writeb(const struct device *dev, u16 addr, u8 val)
......@@ -43,7 +43,7 @@ static int pm8921_writeb(const struct device *dev, u16 addr, u8 val)
const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev);
const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data;
return msm_ssbi_write(pmic->dev->parent, addr, &val, 1);
return ssbi_write(pmic->dev->parent, addr, &val, 1);
}
static int pm8921_read_buf(const struct device *dev, u16 addr, u8 *buf,
......@@ -52,7 +52,7 @@ static int pm8921_read_buf(const struct device *dev, u16 addr, u8 *buf,
const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev);
const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data;
return msm_ssbi_read(pmic->dev->parent, addr, buf, cnt);
return ssbi_read(pmic->dev->parent, addr, buf, cnt);
}
static int pm8921_write_buf(const struct device *dev, u16 addr, u8 *buf,
......@@ -61,7 +61,7 @@ static int pm8921_write_buf(const struct device *dev, u16 addr, u8 *buf,
const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev);
const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data;
return msm_ssbi_write(pmic->dev->parent, addr, buf, cnt);
return ssbi_write(pmic->dev->parent, addr, buf, cnt);
}
static int pm8921_read_irq_stat(const struct device *dev, int irq)
......@@ -124,7 +124,7 @@ static int pm8921_probe(struct platform_device *pdev)
}
/* Read PMIC chip revision */
rc = msm_ssbi_read(pdev->dev.parent, REG_HWREV, &val, sizeof(val));
rc = ssbi_read(pdev->dev.parent, REG_HWREV, &val, sizeof(val));
if (rc) {
pr_err("Failed to read hw rev reg %d:rc=%d\n", REG_HWREV, rc);
goto err_read_rev;
......@@ -133,7 +133,7 @@ static int pm8921_probe(struct platform_device *pdev)
rev = val;
/* Read PMIC chip revision 2 */
rc = msm_ssbi_read(pdev->dev.parent, REG_HWREV_2, &val, sizeof(val));
rc = ssbi_read(pdev->dev.parent, REG_HWREV_2, &val, sizeof(val));
if (rc) {
pr_err("Failed to read hw rev 2 reg %d:rc=%d\n",
REG_HWREV_2, rc);
......
......@@ -331,6 +331,10 @@ static const struct reg_default wm5102_reg_default[] = {
{ 0x000002A3, 0x1102 }, /* R675 - Mic Detect 1 */
{ 0x000002A4, 0x009F }, /* R676 - Mic Detect 2 */
{ 0x000002A5, 0x0000 }, /* R677 - Mic Detect 3 */
{ 0x000002A6, 0x3737 }, /* R678 - Mic Detect Level 1 */
{ 0x000002A7, 0x372C }, /* R679 - Mic Detect Level 2 */
{ 0x000002A8, 0x1422 }, /* R680 - Mic Detect Level 3 */
{ 0x000002A9, 0x030A }, /* R681 - Mic Detect Level 4 */
{ 0x000002C3, 0x0000 }, /* R707 - Mic noise mix control 1 */
{ 0x000002CB, 0x0000 }, /* R715 - Isolation control */
{ 0x000002D3, 0x0000 }, /* R723 - Jack detect analogue */
......@@ -1090,6 +1094,10 @@ static bool wm5102_readable_register(struct device *dev, unsigned int reg)
case ARIZONA_MIC_DETECT_1:
case ARIZONA_MIC_DETECT_2:
case ARIZONA_MIC_DETECT_3:
case ARIZONA_MIC_DETECT_LEVEL_1:
case ARIZONA_MIC_DETECT_LEVEL_2:
case ARIZONA_MIC_DETECT_LEVEL_3:
case ARIZONA_MIC_DETECT_LEVEL_4:
case ARIZONA_MIC_NOISE_MIX_CONTROL_1:
case ARIZONA_ISOLATION_CONTROL:
case ARIZONA_JACK_DETECT_ANALOGUE:
......
......@@ -93,6 +93,14 @@ config ATMEL_TCB_CLKSRC_BLOCK
TC can be used for other purposes, such as PWM generation and
interval timing.
config DUMMY_IRQ
tristate "Dummy IRQ handler"
default n
---help---
This module accepts a single 'irq' parameter, which it should register for.
The sole purpose of this module is to help with debugging of systems on
which spurious IRQs would happen on disabled IRQ vector.
config IBM_ASM
tristate "Device driver for IBM RSA service processor"
depends on X86 && PCI && INPUT
......@@ -398,7 +406,7 @@ config DS1682
config SPEAR13XX_PCIE_GADGET
bool "PCIe gadget support for SPEAr13XX platform"
depends on ARCH_SPEAR13XX
depends on ARCH_SPEAR13XX && BROKEN
default n
help
This option enables gadget support for PCIe controller. If
......
......@@ -13,6 +13,7 @@ obj-$(CONFIG_ATMEL_TCLIB) += atmel_tclib.o
obj-$(CONFIG_BMP085) += bmp085.o
obj-$(CONFIG_BMP085_I2C) += bmp085-i2c.o
obj-$(CONFIG_BMP085_SPI) += bmp085-spi.o
obj-$(CONFIG_DUMMY_IRQ) += dummy-irq.o
obj-$(CONFIG_ICS932S401) += ics932s401.o
obj-$(CONFIG_LKDTM) += lkdtm.o
obj-$(CONFIG_TIFM_CORE) += tifm_core.o
......@@ -49,6 +50,5 @@ obj-y += carma/
obj-$(CONFIG_USB_SWITCH_FSA9480) += fsa9480.o
obj-$(CONFIG_ALTERA_STAPL) +=altera-stapl/
obj-$(CONFIG_INTEL_MEI) += mei/
obj-$(CONFIG_MAX8997_MUIC) += max8997-muic.o
obj-$(CONFIG_VMWARE_VMCI) += vmw_vmci/
obj-$(CONFIG_LATTICE_ECP3_CONFIG) += lattice-ecp3-config.o
......@@ -272,19 +272,8 @@ static int apds9802als_remove(struct i2c_client *client)
}
#ifdef CONFIG_PM
static int apds9802als_suspend(struct i2c_client *client, pm_message_t mesg)
{
als_set_power_state(client, false);
return 0;
}
static int apds9802als_resume(struct i2c_client *client)
{
als_set_default_config(client);
return 0;
}
static int apds9802als_runtime_suspend(struct device *dev)
static int apds9802als_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
......@@ -292,7 +281,7 @@ static int apds9802als_runtime_suspend(struct device *dev)
return 0;
}
static int apds9802als_runtime_resume(struct device *dev)
static int apds9802als_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
......@@ -300,16 +289,12 @@ static int apds9802als_runtime_resume(struct device *dev)
return 0;
}
static const struct dev_pm_ops apds9802als_pm_ops = {
.runtime_suspend = apds9802als_runtime_suspend,
.runtime_resume = apds9802als_runtime_resume,
};
static UNIVERSAL_DEV_PM_OPS(apds9802als_pm_ops, apds9802als_suspend,
apds9802als_resume, NULL);
#define APDS9802ALS_PM_OPS (&apds9802als_pm_ops)
#else /* CONFIG_PM */
#define apds9802als_suspend NULL
#define apds9802als_resume NULL
#define APDS9802ALS_PM_OPS NULL
#endif /* CONFIG_PM */
......@@ -327,8 +312,6 @@ static struct i2c_driver apds9802als_driver = {
},
.probe = apds9802als_probe,
.remove = apds9802als_remove,
.suspend = apds9802als_suspend,
.resume = apds9802als_resume,
.id_table = apds9802als_id,
};
......
......@@ -700,9 +700,6 @@ static ssize_t apds990x_lux_calib_store(struct device *dev,
if (strict_strtoul(buf, 0, &value))
return -EINVAL;
if (chip->lux_calib > APDS_RANGE)
return -EINVAL;
chip->lux_calib = value;
return len;
......@@ -1204,7 +1201,7 @@ static int apds990x_remove(struct i2c_client *client)
return 0;
}
#ifdef CONFIG_PM
#ifdef CONFIG_PM_SLEEP
static int apds990x_suspend(struct device *dev)
{
struct i2c_client *client = container_of(dev, struct i2c_client, dev);
......@@ -1227,10 +1224,6 @@ static int apds990x_resume(struct device *dev)
return 0;
}
#else
#define apds990x_suspend NULL
#define apds990x_resume NULL
#define apds990x_shutdown NULL
#endif
#ifdef CONFIG_PM_RUNTIME
......
......@@ -378,18 +378,7 @@ static struct platform_driver charlcd_driver = {
.remove = __exit_p(charlcd_remove),
};
static int __init charlcd_init(void)
{
return platform_driver_probe(&charlcd_driver, charlcd_probe);
}
static void __exit charlcd_exit(void)
{
platform_driver_unregister(&charlcd_driver);
}
module_init(charlcd_init);
module_exit(charlcd_exit);
module_platform_driver_probe(charlcd_driver, charlcd_probe);
MODULE_AUTHOR("Linus Walleij <triad@df.lth.se>");
MODULE_DESCRIPTION("ARM Character LCD Driver");
......
......@@ -393,17 +393,7 @@ static struct platform_driver atmel_pwm_driver = {
*/
};
static int __init pwm_init(void)
{
return platform_driver_probe(&atmel_pwm_driver, pwm_probe);
}
module_init(pwm_init);
static void __exit pwm_exit(void)
{
platform_driver_unregister(&atmel_pwm_driver);
}
module_exit(pwm_exit);
module_platform_driver_probe(atmel_pwm_driver, pwm_probe);
MODULE_DESCRIPTION("Driver for AT32/AT91 PWM module");
MODULE_LICENSE("GPL");
......
......@@ -1310,7 +1310,7 @@ static int bh1770_remove(struct i2c_client *client)
return 0;
}
#ifdef CONFIG_PM
#ifdef CONFIG_PM_SLEEP
static int bh1770_suspend(struct device *dev)
{
struct i2c_client *client = container_of(dev, struct i2c_client, dev);
......@@ -1346,11 +1346,6 @@ static int bh1770_resume(struct device *dev)
}
return ret;
}
#else
#define bh1770_suspend NULL
#define bh1770_shutdown NULL
#define bh1770_resume NULL
#endif
#ifdef CONFIG_PM_RUNTIME
......
......@@ -196,7 +196,7 @@ static int bh1780_remove(struct i2c_client *client)
return 0;
}
#ifdef CONFIG_PM
#ifdef CONFIG_PM_SLEEP
static int bh1780_suspend(struct device *dev)
{
struct bh1780_data *ddata;
......@@ -235,11 +235,9 @@ static int bh1780_resume(struct device *dev)
return 0;
}
#endif /* CONFIG_PM_SLEEP */
static SIMPLE_DEV_PM_OPS(bh1780_pm, bh1780_suspend, bh1780_resume);
#define BH1780_PMOPS (&bh1780_pm)
#else
#define BH1780_PMOPS NULL
#endif /* CONFIG_PM */
static const struct i2c_device_id bh1780_id[] = {
{ "bh1780", 0 },
......@@ -252,7 +250,7 @@ static struct i2c_driver bh1780_driver = {
.id_table = bh1780_id,
.driver = {
.name = "bh1780",
.pm = BH1780_PMOPS,
.pm = &bh1780_pm,
},
};
......
......@@ -24,8 +24,11 @@
static int mfgpt_reset_timers;
module_param_named(mfgptfix, mfgpt_reset_timers, int, 0644);
MODULE_PARM_DESC(mfgptfix, "Reset the MFGPT timers during init; "
"required by some broken BIOSes (ie, TinyBIOS < 0.99).");
MODULE_PARM_DESC(mfgptfix, "Try to reset the MFGPT timers during init; "
"required by some broken BIOSes (ie, TinyBIOS < 0.99) or kexec "
"(1 = reset the MFGPT using an undocumented bit, "
"2 = perform a soft reset by unconfiguring all timers); "
"use what works best for you.");
struct cs5535_mfgpt_timer {
struct cs5535_mfgpt_chip *chip;
......@@ -255,6 +258,28 @@ static void reset_all_timers(void)
wrmsr(MSR_MFGPT_SETUP, val, dummy);
}
/*
* This is another sledgehammer to reset all MFGPT timers.
* Instead of using the undocumented bit method it clears
* IRQ, NMI and RESET settings.
*/
static void soft_reset(void)
{
int i;
struct cs5535_mfgpt_timer t;
for (i = 0; i < MFGPT_MAX_TIMERS; i++) {
t.nr = i;
cs5535_mfgpt_toggle_event(&t, MFGPT_CMP1, MFGPT_EVENT_RESET, 0);
cs5535_mfgpt_toggle_event(&t, MFGPT_CMP2, MFGPT_EVENT_RESET, 0);
cs5535_mfgpt_toggle_event(&t, MFGPT_CMP1, MFGPT_EVENT_NMI, 0);
cs5535_mfgpt_toggle_event(&t, MFGPT_CMP2, MFGPT_EVENT_NMI, 0);
cs5535_mfgpt_toggle_event(&t, MFGPT_CMP1, MFGPT_EVENT_IRQ, 0);
cs5535_mfgpt_toggle_event(&t, MFGPT_CMP2, MFGPT_EVENT_IRQ, 0);
}
}
/*
* Check whether any MFGPTs are available for the kernel to use. In most
* cases, firmware that uses AMD's VSA code will claim all timers during
......@@ -271,15 +296,17 @@ static int scan_timers(struct cs5535_mfgpt_chip *mfgpt)
int i;
/* bios workaround */
if (mfgpt_reset_timers)
if (mfgpt_reset_timers == 1)
reset_all_timers();
else if (mfgpt_reset_timers == 2)
soft_reset();
/* just to be safe, protect this section w/ lock */
spin_lock_irqsave(&mfgpt->lock, flags);
for (i = 0; i < MFGPT_MAX_TIMERS; i++) {
timer.nr = i;
val = cs5535_mfgpt_read(&timer, MFGPT_REG_SETUP);
if (!(val & MFGPT_SETUP_SETUP)) {
if (!(val & MFGPT_SETUP_SETUP) || mfgpt_reset_timers == 2) {
__set_bit(i, mfgpt->avail);
timers++;
}
......@@ -294,6 +321,12 @@ static int cs5535_mfgpt_probe(struct platform_device *pdev)
struct resource *res;
int err = -EIO, t;
if (mfgpt_reset_timers < 0 || mfgpt_reset_timers > 2) {
dev_err(&pdev->dev, "Bad mfgpt_reset_timers value: %i\n",
mfgpt_reset_timers);
goto done;
}
/* There are two ways to get the MFGPT base address; one is by
* fetching it from MSR_LBAR_MFGPT, the other is by reading the
* PCI BAR info. The latter method is easier (especially across
......
/*
* Dummy IRQ handler driver.
*
* This module only registers itself as a handler that is specified to it
* by the 'irq' parameter.
*
* The sole purpose of this module is to help with debugging of systems on
* which spurious IRQs would happen on disabled IRQ vector.
*
* Copyright (C) 2013 Jiri Kosina
*/
/*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
static int irq;
static irqreturn_t dummy_interrupt(int irq, void *dev_id)
{
static int count = 0;
if (count == 0) {
printk(KERN_INFO "dummy-irq: interrupt occured on IRQ %d\n",
irq);
count++;
}
return IRQ_NONE;
}
static int __init dummy_irq_init(void)
{
if (request_irq(irq, &dummy_interrupt, IRQF_SHARED, "dummy_irq", &irq)) {
printk(KERN_ERR "dummy-irq: cannot register IRQ %d\n", irq);
return -EIO;
}
printk(KERN_INFO "dummy-irq: registered for IRQ %d\n", irq);
return 0;
}
static void __exit dummy_irq_exit(void)
{
printk(KERN_INFO "dummy-irq unloaded\n");
free_irq(irq, &irq);
}
module_init(dummy_irq_init);
module_exit(dummy_irq_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jiri Kosina");
module_param(irq, uint, 0444);
MODULE_PARM_DESC(irq, "The IRQ to register for");
......@@ -412,7 +412,7 @@ static int at25_probe(struct spi_device *spi)
mutex_init(&at25->lock);
at25->chip = chip;
at25->spi = spi_dev_get(spi);
dev_set_drvdata(&spi->dev, at25);
spi_set_drvdata(spi, at25);
at25->addrlen = addrlen;
/* Export the EEPROM bytes through sysfs, since that's convenient.
......@@ -463,7 +463,7 @@ static int at25_remove(struct spi_device *spi)
{
struct at25_data *at25;
at25 = dev_get_drvdata(&spi->dev);
at25 = spi_get_drvdata(spi);
sysfs_remove_bin_file(&spi->dev.kobj, &at25->bin);
kfree(at25);
return 0;
......
......@@ -363,7 +363,7 @@ static int eeprom_93xx46_probe(struct spi_device *spi)
dev_err(&spi->dev, "can't create erase interface\n");
}
dev_set_drvdata(&spi->dev, edev);
spi_set_drvdata(spi, edev);
return 0;
fail:
kfree(edev);
......@@ -372,13 +372,13 @@ static int eeprom_93xx46_probe(struct spi_device *spi)
static int eeprom_93xx46_remove(struct spi_device *spi)
{
struct eeprom_93xx46_dev *edev = dev_get_drvdata(&spi->dev);
struct eeprom_93xx46_dev *edev = spi_get_drvdata(spi);
if (!(edev->pdata->flags & EE_READONLY))
device_remove_file(&spi->dev, &dev_attr_erase);
sysfs_remove_bin_file(&spi->dev.kobj, &edev->bin);
dev_set_drvdata(&spi->dev, NULL);
spi_set_drvdata(spi, NULL);
kfree(edev);
return 0;
}
......
......@@ -365,18 +365,7 @@ static struct platform_driver ep93xx_pwm_driver = {
.remove = __exit_p(ep93xx_pwm_remove),
};
static int __init ep93xx_pwm_init(void)
{
return platform_driver_probe(&ep93xx_pwm_driver, ep93xx_pwm_probe);
}
static void __exit ep93xx_pwm_exit(void)
{
platform_driver_unregister(&ep93xx_pwm_driver);
}
module_init(ep93xx_pwm_init);
module_exit(ep93xx_pwm_exit);
module_platform_driver_probe(ep93xx_pwm_driver, ep93xx_pwm_probe);
MODULE_AUTHOR("Matthieu Crapet <mcrapet@gmail.com>, "
"H Hartley Sweeten <hsweeten@visionengravers.com>");
......
......@@ -474,10 +474,11 @@ static int fsa9480_remove(struct i2c_client *client)
return 0;
}
#ifdef CONFIG_PM
#ifdef CONFIG_PM_SLEEP
static int fsa9480_suspend(struct i2c_client *client, pm_message_t state)
static int fsa9480_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct fsa9480_usbsw *usbsw = i2c_get_clientdata(client);
struct fsa9480_platform_data *pdata = usbsw->pdata;
......@@ -490,8 +491,9 @@ static int fsa9480_suspend(struct i2c_client *client, pm_message_t state)
return 0;
}
static int fsa9480_resume(struct i2c_client *client)
static int fsa9480_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct fsa9480_usbsw *usbsw = i2c_get_clientdata(client);
int dev1, dev2;
......@@ -515,12 +517,14 @@ static int fsa9480_resume(struct i2c_client *client)
return 0;
}
static SIMPLE_DEV_PM_OPS(fsa9480_pm_ops, fsa9480_suspend, fsa9480_resume);
#define FSA9480_PM_OPS (&fsa9480_pm_ops)
#else
#define fsa9480_suspend NULL
#define fsa9480_resume NULL
#define FSA9480_PM_OPS NULL
#endif /* CONFIG_PM */
#endif /* CONFIG_PM_SLEEP */
static const struct i2c_device_id fsa9480_id[] = {
{"fsa9480", 0},
......@@ -531,11 +535,10 @@ MODULE_DEVICE_TABLE(i2c, fsa9480_id);
static struct i2c_driver fsa9480_i2c_driver = {
.driver = {
.name = "fsa9480",
.pm = FSA9480_PM_OPS,
},
.probe = fsa9480_probe,
.remove = fsa9480_remove,
.resume = fsa9480_resume,
.suspend = fsa9480_suspend,
.id_table = fsa9480_id,
};
......
......@@ -409,18 +409,20 @@ static int isl29003_remove(struct i2c_client *client)
return 0;
}
#ifdef CONFIG_PM
static int isl29003_suspend(struct i2c_client *client, pm_message_t mesg)
#ifdef CONFIG_PM_SLEEP
static int isl29003_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct isl29003_data *data = i2c_get_clientdata(client);
data->power_state_before_suspend = isl29003_get_power_state(client);
return isl29003_set_power_state(client, 0);
}
static int isl29003_resume(struct i2c_client *client)
static int isl29003_resume(struct device *dev)
{
int i;
struct i2c_client *client = to_i2c_client(dev);
struct isl29003_data *data = i2c_get_clientdata(client);
/* restore registers from cache */
......@@ -432,10 +434,12 @@ static int isl29003_resume(struct i2c_client *client)
data->power_state_before_suspend);
}
static SIMPLE_DEV_PM_OPS(isl29003_pm_ops, isl29003_suspend, isl29003_resume);
#define ISL29003_PM_OPS (&isl29003_pm_ops)
#else
#define isl29003_suspend NULL
#define isl29003_resume NULL
#endif /* CONFIG_PM */
#define ISL29003_PM_OPS NULL
#endif /* CONFIG_PM_SLEEP */
static const struct i2c_device_id isl29003_id[] = {
{ "isl29003", 0 },
......@@ -447,9 +451,8 @@ static struct i2c_driver isl29003_driver = {
.driver = {
.name = ISL29003_DRV_NAME,
.owner = THIS_MODULE,
.pm = ISL29003_PM_OPS,
},
.suspend = isl29003_suspend,
.resume = isl29003_resume,
.probe = isl29003_probe,
.remove = isl29003_remove,
.id_table = isl29003_id,
......
......@@ -69,7 +69,7 @@ static const struct ecp3_dev ecp3_dev[] = {
static void firmware_load(const struct firmware *fw, void *context)
{
struct spi_device *spi = (struct spi_device *)context;
struct fpga_data *data = dev_get_drvdata(&spi->dev);
struct fpga_data *data = spi_get_drvdata(spi);
u8 *buffer;
int ret;
u8 txbuf[8];
......
......@@ -10,10 +10,9 @@ config INTEL_MEI
<http://software.intel.com/en-us/manageability/>
config INTEL_MEI_ME
bool "ME Enabled Intel Chipsets"
depends on INTEL_MEI
tristate "ME Enabled Intel Chipsets"
select INTEL_MEI
depends on X86 && PCI && WATCHDOG_CORE
default y
help
MEI support for ME Enabled Intel chipsets.
......
......@@ -10,5 +10,10 @@ mei-objs += client.o
mei-objs += main.o
mei-objs += amthif.o
mei-objs += wd.o
mei-$(CONFIG_INTEL_MEI_ME) += pci-me.o
mei-$(CONFIG_INTEL_MEI_ME) += hw-me.o
mei-objs += bus.o
mei-objs += nfc.o
mei-$(CONFIG_DEBUG_FS) += debugfs.o
obj-$(CONFIG_INTEL_MEI_ME) += mei-me.o
mei-me-objs := pci-me.o
mei-me-objs += hw-me.o
......@@ -449,7 +449,7 @@ int mei_amthif_irq_write_complete(struct mei_device *dev, s32 *slots,
struct mei_msg_hdr mei_hdr;
struct mei_cl *cl = cb->cl;
size_t len = dev->iamthif_msg_buf_size - dev->iamthif_msg_buf_index;
size_t msg_slots = mei_data2slots(len);
u32 msg_slots = mei_data2slots(len);
mei_hdr.host_addr = cl->host_client_id;
mei_hdr.me_addr = cl->me_client_id;
......@@ -505,14 +505,15 @@ int mei_amthif_irq_write_complete(struct mei_device *dev, s32 *slots,
* mei_amthif_irq_read_message - read routine after ISR to
* handle the read amthif message
*
* @complete_list: An instance of our list structure
* @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.
*/
int mei_amthif_irq_read_message(struct mei_cl_cb *complete_list,
struct mei_device *dev, struct mei_msg_hdr *mei_hdr)
int mei_amthif_irq_read_msg(struct mei_device *dev,
struct mei_msg_hdr *mei_hdr,
struct mei_cl_cb *complete_list)
{
struct mei_cl_cb *cb;
unsigned char *buffer;
......@@ -530,8 +531,7 @@ int mei_amthif_irq_read_message(struct mei_cl_cb *complete_list,
if (!mei_hdr->msg_complete)
return 0;
dev_dbg(&dev->pdev->dev,
"amthif_message_buffer_index =%d\n",
dev_dbg(&dev->pdev->dev, "amthif_message_buffer_index =%d\n",
mei_hdr->length);
dev_dbg(&dev->pdev->dev, "completed amthif read.\n ");
......@@ -566,12 +566,13 @@ int mei_amthif_irq_read_message(struct mei_cl_cb *complete_list,
*/
int mei_amthif_irq_read(struct mei_device *dev, s32 *slots)
{
u32 msg_slots = mei_data2slots(sizeof(struct hbm_flow_control));
if (((*slots) * sizeof(u32)) < (sizeof(struct mei_msg_hdr)
+ sizeof(struct hbm_flow_control))) {
if (*slots < msg_slots)
return -EMSGSIZE;
}
*slots -= mei_data2slots(sizeof(struct hbm_flow_control));
*slots -= msg_slots;
if (mei_hbm_cl_flow_control_req(dev, &dev->iamthif_cl)) {
dev_dbg(&dev->pdev->dev, "iamthif flow control failed\n");
return -EIO;
......
This diff is collapsed.
......@@ -216,6 +216,7 @@ void mei_cl_init(struct mei_cl *cl, struct mei_device *dev)
init_waitqueue_head(&cl->rx_wait);
init_waitqueue_head(&cl->tx_wait);
INIT_LIST_HEAD(&cl->link);
INIT_LIST_HEAD(&cl->device_link);
cl->reading_state = MEI_IDLE;
cl->writing_state = MEI_IDLE;
cl->dev = dev;
......@@ -357,6 +358,9 @@ void mei_host_client_init(struct work_struct *work)
mei_amthif_host_init(dev);
else if (!uuid_le_cmp(client_props->protocol_name, mei_wd_guid))
mei_wd_host_init(dev);
else if (!uuid_le_cmp(client_props->protocol_name, mei_nfc_guid))
mei_nfc_host_init(dev);
}
dev->dev_state = MEI_DEV_ENABLED;
......@@ -620,7 +624,7 @@ int mei_cl_flow_ctrl_reduce(struct mei_cl *cl)
*
* returns 0 on success, <0 on failure.
*/
int mei_cl_read_start(struct mei_cl *cl)
int mei_cl_read_start(struct mei_cl *cl, size_t length)
{
struct mei_device *dev;
struct mei_cl_cb *cb;
......@@ -653,8 +657,9 @@ int mei_cl_read_start(struct mei_cl *cl)
if (!cb)
return -ENOMEM;
rets = mei_io_cb_alloc_resp_buf(cb,
dev->me_clients[i].props.max_msg_length);
/* always allocate at least client max message */
length = max_t(size_t, length, dev->me_clients[i].props.max_msg_length);
rets = mei_io_cb_alloc_resp_buf(cb, length);
if (rets)
goto err;
......@@ -676,6 +681,111 @@ int mei_cl_read_start(struct mei_cl *cl)
return rets;
}
/**
* mei_cl_write - submit a write cb to mei device
assumes device_lock is locked
*
* @cl: host client
* @cl: write callback with filled data
*
* returns numbe of bytes sent on success, <0 on failure.
*/
int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking)
{
struct mei_device *dev;
struct mei_msg_data *buf;
struct mei_msg_hdr mei_hdr;
int rets;
if (WARN_ON(!cl || !cl->dev))
return -ENODEV;
if (WARN_ON(!cb))
return -EINVAL;
dev = cl->dev;
buf = &cb->request_buffer;
dev_dbg(&dev->pdev->dev, "mei_cl_write %d\n", buf->size);
cb->fop_type = MEI_FOP_WRITE;
rets = mei_cl_flow_ctrl_creds(cl);
if (rets < 0)
goto err;
/* Host buffer is not ready, we queue the request */
if (rets == 0 || !dev->hbuf_is_ready) {
cb->buf_idx = 0;
/* unseting complete will enqueue the cb for write */
mei_hdr.msg_complete = 0;
cl->writing_state = MEI_WRITING;
rets = buf->size;
goto out;
}
dev->hbuf_is_ready = false;
/* Check for a maximum length */
if (buf->size > mei_hbuf_max_len(dev)) {
mei_hdr.length = mei_hbuf_max_len(dev);
mei_hdr.msg_complete = 0;
} else {
mei_hdr.length = buf->size;
mei_hdr.msg_complete = 1;
}
mei_hdr.host_addr = cl->host_client_id;
mei_hdr.me_addr = cl->me_client_id;
mei_hdr.reserved = 0;
dev_dbg(&dev->pdev->dev, "write " MEI_HDR_FMT "\n",
MEI_HDR_PRM(&mei_hdr));
if (mei_write_message(dev, &mei_hdr, buf->data)) {
rets = -EIO;
goto err;
}
cl->writing_state = MEI_WRITING;
cb->buf_idx = mei_hdr.length;
rets = buf->size;
out:
if (mei_hdr.msg_complete) {
if (mei_cl_flow_ctrl_reduce(cl)) {
rets = -ENODEV;
goto err;
}
list_add_tail(&cb->list, &dev->write_waiting_list.list);
} else {
list_add_tail(&cb->list, &dev->write_list.list);
}
if (blocking && cl->writing_state != MEI_WRITE_COMPLETE) {
mutex_unlock(&dev->device_lock);
if (wait_event_interruptible(cl->tx_wait,
cl->writing_state == MEI_WRITE_COMPLETE)) {
if (signal_pending(current))
rets = -EINTR;
else
rets = -ERESTARTSYS;
}
mutex_lock(&dev->device_lock);
}
err:
return rets;
}
/**
* mei_cl_all_disconnect - disconnect forcefully all connected clients
*
......
......@@ -86,17 +86,16 @@ int mei_cl_flow_ctrl_reduce(struct mei_cl *cl);
*/
bool mei_cl_is_other_connecting(struct mei_cl *cl);
int mei_cl_disconnect(struct mei_cl *cl);
int mei_cl_read_start(struct mei_cl *cl);
int mei_cl_connect(struct mei_cl *cl, struct file *file);
int mei_cl_read_start(struct mei_cl *cl, size_t length);
int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking);
void mei_host_client_init(struct work_struct *work);
void mei_cl_all_disconnect(struct mei_device *dev);
void mei_cl_all_read_wakeup(struct mei_device *dev);
void mei_cl_all_write_clear(struct mei_device *dev);
#endif /* _MEI_CLIENT_H_ */
/*
*
* Intel Management Engine Interface (Intel MEI) Linux driver
* Copyright (c) 2012-2013, Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/debugfs.h>
#include <linux/pci.h>
#include <linux/mei.h>
#include "mei_dev.h"
#include "hw.h"
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;
int pos = 0;
int ret;
if (!buf)
return -ENOMEM;
pos += scnprintf(buf + pos, bufsz - pos,
" |id|addr| UUID |con|msg len|\n");
mutex_lock(&dev->device_lock);
/* if the driver is not enabled the list won't b consitent */
if (dev->dev_state != MEI_DEV_ENABLED)
goto out;
for (i = 0; i < dev->me_clients_num; i++) {
cl = &dev->me_clients[i];
/* skip me clients that cannot be connected */
if (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);
}
out:
mutex_unlock(&dev->device_lock);
ret = simple_read_from_buffer(ubuf, cnt, ppos, buf, pos);
kfree(buf);
return ret;
}
static const struct file_operations mei_dbgfs_fops_meclients = {
.open = simple_open,
.read = mei_dbgfs_read_meclients,
.llseek = generic_file_llseek,
};
static ssize_t mei_dbgfs_read_devstate(struct file *fp, char __user *ubuf,
size_t cnt, loff_t *ppos)
{
struct mei_device *dev = fp->private_data;
const size_t bufsz = 1024;
char *buf = kzalloc(bufsz, GFP_KERNEL);
int pos = 0;
int ret;
if (!buf)
return -ENOMEM;
pos += scnprintf(buf + pos, bufsz - pos, "%s\n",
mei_dev_state_str(dev->dev_state));
ret = simple_read_from_buffer(ubuf, cnt, ppos, buf, pos);
kfree(buf);
return ret;
}
static const struct file_operations mei_dbgfs_fops_devstate = {
.open = simple_open,
.read = mei_dbgfs_read_devstate,
.llseek = generic_file_llseek,
};
/**
* mei_dbgfs_deregister - Remove the debugfs files and directories
* @mei - pointer to mei device private dat
*/
void mei_dbgfs_deregister(struct mei_device *dev)
{
if (!dev->dbgfs_dir)
return;
debugfs_remove_recursive(dev->dbgfs_dir);
dev->dbgfs_dir = NULL;
}
/**
* Add the debugfs files
*
*/
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;
f = debugfs_create_file("meclients", S_IRUSR, dir,
dev, &mei_dbgfs_fops_meclients);
if (!f) {
dev_err(&dev->pdev->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");
goto err;
}
dev->dbgfs_dir = dir;
return 0;
err:
mei_dbgfs_deregister(dev);
return -ENODEV;
}
......@@ -52,7 +52,7 @@ static void mei_hbm_me_cl_allocate(struct mei_device *dev)
sizeof(struct mei_me_client), GFP_KERNEL);
if (!clients) {
dev_err(&dev->pdev->dev, "memory allocation for ME clients failed.\n");
dev->dev_state = MEI_DEV_RESETING;
dev->dev_state = MEI_DEV_RESETTING;
mei_reset(dev, 1);
return;
}
......@@ -123,12 +123,33 @@ static bool is_treat_specially_client(struct mei_cl *cl,
return false;
}
int mei_hbm_start_wait(struct mei_device *dev)
{
int ret;
if (dev->hbm_state > MEI_HBM_START)
return 0;
mutex_unlock(&dev->device_lock);
ret = wait_event_interruptible_timeout(dev->wait_recvd_msg,
dev->hbm_state == MEI_HBM_IDLE ||
dev->hbm_state > MEI_HBM_START,
mei_secs_to_jiffies(MEI_INTEROP_TIMEOUT));
mutex_lock(&dev->device_lock);
if (ret <= 0 && (dev->hbm_state <= MEI_HBM_START)) {
dev->hbm_state = MEI_HBM_IDLE;
dev_err(&dev->pdev->dev, "wating for mei start failed\n");
return -ETIMEDOUT;
}
return 0;
}
/**
* mei_hbm_start_req - sends start request message.
*
* @dev: the device structure
*/
void mei_hbm_start_req(struct mei_device *dev)
int mei_hbm_start_req(struct mei_device *dev)
{
struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
struct hbm_host_version_request *start_req;
......@@ -143,18 +164,19 @@ void mei_hbm_start_req(struct mei_device *dev)
start_req->host_version.major_version = HBM_MAJOR_VERSION;
start_req->host_version.minor_version = HBM_MINOR_VERSION;
dev->recvd_msg = false;
dev->hbm_state = MEI_HBM_IDLE;
if (mei_write_message(dev, mei_hdr, dev->wr_msg.data)) {
dev_dbg(&dev->pdev->dev, "write send version message to FW fail.\n");
dev->dev_state = MEI_DEV_RESETING;
dev_err(&dev->pdev->dev, "version message writet failed\n");
dev->dev_state = MEI_DEV_RESETTING;
mei_reset(dev, 1);
return -ENODEV;
}
dev->init_clients_state = MEI_START_MESSAGE;
dev->hbm_state = MEI_HBM_START;
dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
return ;
return 0;
}
/**
/*
* mei_hbm_enum_clients_req - sends enumeration client request message.
*
* @dev: the device structure
......@@ -174,11 +196,11 @@ static void mei_hbm_enum_clients_req(struct mei_device *dev)
enum_req->hbm_cmd = HOST_ENUM_REQ_CMD;
if (mei_write_message(dev, mei_hdr, dev->wr_msg.data)) {
dev->dev_state = MEI_DEV_RESETING;
dev_dbg(&dev->pdev->dev, "write send enumeration request message to FW fail.\n");
dev->dev_state = MEI_DEV_RESETTING;
dev_err(&dev->pdev->dev, "enumeration request write failed.\n");
mei_reset(dev, 1);
}
dev->init_clients_state = MEI_ENUM_CLIENTS_MESSAGE;
dev->hbm_state = MEI_HBM_ENUM_CLIENTS;
dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
return;
}
......@@ -208,6 +230,7 @@ static int mei_hbm_prop_req(struct mei_device *dev)
/* We got all client properties */
if (next_client_index == MEI_CLIENTS_MAX) {
dev->hbm_state = MEI_HBM_STARTED;
schedule_work(&dev->init_work);
return 0;
......@@ -226,8 +249,8 @@ static int mei_hbm_prop_req(struct mei_device *dev)
prop_req->address = next_client_index;
if (mei_write_message(dev, mei_hdr, dev->wr_msg.data)) {
dev->dev_state = MEI_DEV_RESETING;
dev_err(&dev->pdev->dev, "Properties request command failed\n");
dev->dev_state = MEI_DEV_RESETTING;
dev_err(&dev->pdev->dev, "properties request write failed\n");
mei_reset(dev, 1);
return -EIO;
......@@ -542,27 +565,28 @@ void mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
dev->version = version_res->me_max_version;
dev_dbg(&dev->pdev->dev, "version mismatch.\n");
dev->hbm_state = MEI_HBM_STOP;
mei_hbm_stop_req_prepare(dev, &dev->wr_msg.hdr,
dev->wr_msg.data);
mei_write_message(dev, &dev->wr_msg.hdr,
dev->wr_msg.data);
return;
}
dev->version.major_version = HBM_MAJOR_VERSION;
dev->version.minor_version = HBM_MINOR_VERSION;
if (dev->dev_state == MEI_DEV_INIT_CLIENTS &&
dev->init_clients_state == MEI_START_MESSAGE) {
dev->hbm_state == MEI_HBM_START) {
dev->init_clients_timer = 0;
mei_hbm_enum_clients_req(dev);
} else {
dev->recvd_msg = false;
dev_dbg(&dev->pdev->dev, "reset due to received hbm: host start\n");
dev_err(&dev->pdev->dev, "reset: wrong host start response\n");
mei_reset(dev, 1);
return;
}
dev->recvd_msg = true;
wake_up_interruptible(&dev->wait_recvd_msg);
dev_dbg(&dev->pdev->dev, "host start response message received.\n");
break;
......@@ -591,23 +615,20 @@ void mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
me_client = &dev->me_clients[dev->me_client_presentation_num];
if (props_res->status || !dev->me_clients) {
dev_dbg(&dev->pdev->dev, "reset due to received host client properties response bus message wrong status.\n");
dev_err(&dev->pdev->dev, "reset: properties response hbm wrong status.\n");
mei_reset(dev, 1);
return;
}
if (me_client->client_id != props_res->address) {
dev_err(&dev->pdev->dev,
"Host client properties reply mismatch\n");
dev_err(&dev->pdev->dev, "reset: host properties response address mismatch\n");
mei_reset(dev, 1);
return;
}
if (dev->dev_state != MEI_DEV_INIT_CLIENTS ||
dev->init_clients_state != MEI_CLIENT_PROPERTIES_MESSAGE) {
dev_err(&dev->pdev->dev,
"Unexpected client properties reply\n");
dev->hbm_state != MEI_HBM_CLIENT_PROPERTIES) {
dev_err(&dev->pdev->dev, "reset: unexpected properties response\n");
mei_reset(dev, 1);
return;
......@@ -626,26 +647,28 @@ void mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
enum_res = (struct hbm_host_enum_response *) mei_msg;
memcpy(dev->me_clients_map, enum_res->valid_addresses, 32);
if (dev->dev_state == MEI_DEV_INIT_CLIENTS &&
dev->init_clients_state == MEI_ENUM_CLIENTS_MESSAGE) {
dev->hbm_state == MEI_HBM_ENUM_CLIENTS) {
dev->init_clients_timer = 0;
dev->me_client_presentation_num = 0;
dev->me_client_index = 0;
mei_hbm_me_cl_allocate(dev);
dev->init_clients_state =
MEI_CLIENT_PROPERTIES_MESSAGE;
dev->hbm_state = MEI_HBM_CLIENT_PROPERTIES;
/* first property reqeust */
mei_hbm_prop_req(dev);
} else {
dev_dbg(&dev->pdev->dev, "reset due to received host enumeration clients response bus message.\n");
dev_err(&dev->pdev->dev, "reset: unexpected enumeration response hbm.\n");
mei_reset(dev, 1);
return;
}
break;
case HOST_STOP_RES_CMD:
if (dev->hbm_state != MEI_HBM_STOP)
dev_err(&dev->pdev->dev, "unexpected stop response hbm.\n");
dev->dev_state = MEI_DEV_DISABLED;
dev_dbg(&dev->pdev->dev, "resetting because of FW stop response.\n");
dev_info(&dev->pdev->dev, "reset: FW stop response.\n");
mei_reset(dev, 1);
break;
......@@ -657,6 +680,7 @@ void mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
case ME_STOP_REQ_CMD:
dev->hbm_state = MEI_HBM_STOP;
mei_hbm_stop_req_prepare(dev, &dev->wr_ext_msg.hdr,
dev->wr_ext_msg.data);
break;
......
......@@ -17,6 +17,27 @@
#ifndef _MEI_HBM_H_
#define _MEI_HBM_H_
struct mei_device;
struct mei_msg_hdr;
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_ENUM_CLIENTS : enumeration request was sent
* @MEI_HBM_CLIENT_PROPERTIES : acquiring clients properties
*/
enum mei_hbm_state {
MEI_HBM_IDLE = 0,
MEI_HBM_START,
MEI_HBM_ENUM_CLIENTS,
MEI_HBM_CLIENT_PROPERTIES,
MEI_HBM_STARTED,
MEI_HBM_STOP,
};
void mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr);
static inline void mei_hbm_hdr(struct mei_msg_hdr *hdr, size_t length)
......@@ -28,8 +49,8 @@ static inline void mei_hbm_hdr(struct mei_msg_hdr *hdr, size_t length)
hdr->reserved = 0;
}
void mei_hbm_start_req(struct mei_device *dev);
int mei_hbm_start_req(struct mei_device *dev);
int mei_hbm_start_wait(struct mei_device *dev);
int mei_hbm_cl_flow_control_req(struct mei_device *dev, struct mei_cl *cl);
int mei_hbm_cl_disconnect_req(struct mei_device *dev, struct mei_cl *cl);
int mei_hbm_cl_connect_req(struct mei_device *dev, struct mei_cl *cl);
......
......@@ -26,14 +26,14 @@
/**
* mei_reg_read - Reads 32bit data from the mei device
* mei_me_reg_read - Reads 32bit data from the mei device
*
* @dev: the device structure
* @offset: offset from which to read the data
*
* returns register value (u32)
*/
static inline u32 mei_reg_read(const struct mei_me_hw *hw,
static inline u32 mei_me_reg_read(const struct mei_me_hw *hw,
unsigned long offset)
{
return ioread32(hw->mem_addr + offset);
......@@ -41,20 +41,20 @@ static inline u32 mei_reg_read(const struct mei_me_hw *hw,
/**
* mei_reg_write - Writes 32bit data to the mei device
* mei_me_reg_write - Writes 32bit data to the mei device
*
* @dev: the device structure
* @offset: offset from which to write the data
* @value: register value to write (u32)
*/
static inline void mei_reg_write(const struct mei_me_hw *hw,
static inline void mei_me_reg_write(const struct mei_me_hw *hw,
unsigned long offset, u32 value)
{
iowrite32(value, hw->mem_addr + offset);
}
/**
* mei_mecbrw_read - Reads 32bit data from ME circular buffer
* mei_me_mecbrw_read - Reads 32bit data from ME circular buffer
* read window register
*
* @dev: the device structure
......@@ -63,18 +63,18 @@ static inline void mei_reg_write(const struct mei_me_hw *hw,
*/
static u32 mei_me_mecbrw_read(const struct mei_device *dev)
{
return mei_reg_read(to_me_hw(dev), ME_CB_RW);
return mei_me_reg_read(to_me_hw(dev), ME_CB_RW);
}
/**
* mei_mecsr_read - Reads 32bit data from the ME CSR
* mei_me_mecsr_read - Reads 32bit data from the ME CSR
*
* @dev: the device structure
*
* returns ME_CSR_HA register value (u32)
*/
static inline u32 mei_mecsr_read(const struct mei_me_hw *hw)
static inline u32 mei_me_mecsr_read(const struct mei_me_hw *hw)
{
return mei_reg_read(hw, ME_CSR_HA);
return mei_me_reg_read(hw, ME_CSR_HA);
}
/**
......@@ -86,7 +86,7 @@ static inline u32 mei_mecsr_read(const struct mei_me_hw *hw)
*/
static inline u32 mei_hcsr_read(const struct mei_me_hw *hw)
{
return mei_reg_read(hw, H_CSR);
return mei_me_reg_read(hw, H_CSR);
}
/**
......@@ -98,7 +98,7 @@ static inline u32 mei_hcsr_read(const struct mei_me_hw *hw)
static inline void mei_hcsr_set(struct mei_me_hw *hw, u32 hcsr)
{
hcsr &= ~H_IS;
mei_reg_write(hw, H_CSR, hcsr);
mei_me_reg_write(hw, H_CSR, hcsr);
}
......@@ -123,7 +123,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_reg_write(hw, H_CSR, hcsr);
mei_me_reg_write(hw, H_CSR, hcsr);
}
/**
* mei_me_intr_enable - enables mei device interrupts
......@@ -228,10 +228,42 @@ static bool mei_me_host_is_ready(struct mei_device *dev)
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_mecsr_read(hw);
hw->me_hw_state = mei_me_mecsr_read(hw);
return (hw->me_hw_state & ME_RDY_HRA) == ME_RDY_HRA;
}
static int mei_me_hw_ready_wait(struct mei_device *dev)
{
int err;
if (mei_me_hw_is_ready(dev))
return 0;
mutex_unlock(&dev->device_lock);
err = wait_event_interruptible_timeout(dev->wait_hw_ready,
dev->recvd_hw_ready, MEI_INTEROP_TIMEOUT);
mutex_lock(&dev->device_lock);
if (!err && !dev->recvd_hw_ready) {
dev_err(&dev->pdev->dev,
"wait hw ready failed. status = 0x%x\n", err);
return -ETIMEDOUT;
}
dev->recvd_hw_ready = false;
return 0;
}
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");
mei_me_host_set_ready(dev);
return ret;
}
/**
* mei_hbuf_filled_slots - gets number of device filled buffer slots
*
......@@ -305,10 +337,11 @@ static int mei_me_write_message(struct mei_device *dev,
unsigned char *buf)
{
struct mei_me_hw *hw = to_me_hw(dev);
unsigned long rem, dw_cnt;
unsigned long rem;
unsigned long length = header->length;
u32 *reg_buf = (u32 *)buf;
u32 hcsr;
u32 dw_cnt;
int i;
int empty_slots;
......@@ -321,16 +354,16 @@ static int mei_me_write_message(struct mei_device *dev,
if (empty_slots < 0 || dw_cnt > empty_slots)
return -EIO;
mei_reg_write(hw, H_CB_WW, *((u32 *) header));
mei_me_reg_write(hw, H_CB_WW, *((u32 *) header));
for (i = 0; i < length / 4; i++)
mei_reg_write(hw, H_CB_WW, reg_buf[i]);
mei_me_reg_write(hw, H_CB_WW, reg_buf[i]);
rem = length & 0x3;
if (rem > 0) {
u32 reg = 0;
memcpy(&reg, &buf[length - rem], rem);
mei_reg_write(hw, H_CB_WW, reg);
mei_me_reg_write(hw, H_CB_WW, reg);
}
hcsr = mei_hcsr_read(hw) | H_IG;
......@@ -354,7 +387,7 @@ static int mei_me_count_full_read_slots(struct mei_device *dev)
char read_ptr, write_ptr;
unsigned char buffer_depth, filled_slots;
hw->me_hw_state = mei_mecsr_read(hw);
hw->me_hw_state = mei_me_mecsr_read(hw);
buffer_depth = (unsigned char)((hw->me_hw_state & ME_CBD_HRA) >> 24);
read_ptr = (char) ((hw->me_hw_state & ME_CBRP_HRA) >> 8);
write_ptr = (char) ((hw->me_hw_state & ME_CBWP_HRA) >> 16);
......@@ -414,7 +447,7 @@ irqreturn_t mei_me_irq_quick_handler(int irq, void *dev_id)
return IRQ_NONE;
/* clear H_IS bit in H_CSR */
mei_reg_write(hw, H_CSR, csr_reg);
mei_me_reg_write(hw, H_CSR, csr_reg);
return IRQ_WAKE_THREAD;
}
......@@ -433,12 +466,8 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id)
{
struct mei_device *dev = (struct mei_device *) dev_id;
struct mei_cl_cb complete_list;
struct mei_cl_cb *cb_pos = NULL, *cb_next = NULL;
struct mei_cl *cl;
s32 slots;
int rets;
bool bus_message_received;
dev_dbg(&dev->pdev->dev, "function called after ISR to handle the interrupt processing.\n");
/* initialize our complete list */
......@@ -452,7 +481,7 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id)
/* check if ME wants a reset */
if (!mei_hw_is_ready(dev) &&
dev->dev_state != MEI_DEV_RESETING &&
dev->dev_state != MEI_DEV_RESETTING &&
dev->dev_state != MEI_DEV_INITIALIZING) {
dev_dbg(&dev->pdev->dev, "FW not ready.\n");
mei_reset(dev, 1);
......@@ -465,14 +494,9 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id)
if (mei_hw_is_ready(dev)) {
dev_dbg(&dev->pdev->dev, "we need to start the dev.\n");
mei_host_set_ready(dev);
dev->recvd_hw_ready = true;
wake_up_interruptible(&dev->wait_hw_ready);
dev_dbg(&dev->pdev->dev, "link is established start sending messages.\n");
/* link is established * start sending messages. */
dev->dev_state = MEI_DEV_INIT_CLIENTS;
mei_hbm_start_req(dev);
mutex_unlock(&dev->device_lock);
return IRQ_HANDLED;
} else {
......@@ -499,44 +523,20 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id)
dev_dbg(&dev->pdev->dev, "end of bottom half function.\n");
dev->hbuf_is_ready = mei_hbuf_is_ready(dev);
bus_message_received = false;
if (dev->recvd_msg && waitqueue_active(&dev->wait_recvd_msg)) {
dev_dbg(&dev->pdev->dev, "received waiting bus message\n");
bus_message_received = true;
}
mutex_unlock(&dev->device_lock);
if (bus_message_received) {
dev_dbg(&dev->pdev->dev, "wake up dev->wait_recvd_msg\n");
wake_up_interruptible(&dev->wait_recvd_msg);
bus_message_received = false;
}
if (list_empty(&complete_list.list))
return IRQ_HANDLED;
mei_irq_compl_handler(dev, &complete_list);
list_for_each_entry_safe(cb_pos, cb_next, &complete_list.list, list) {
cl = cb_pos->cl;
list_del(&cb_pos->list);
if (cl) {
if (cl != &dev->iamthif_cl) {
dev_dbg(&dev->pdev->dev, "completing call back.\n");
mei_irq_complete_handler(cl, cb_pos);
cb_pos = NULL;
} else if (cl == &dev->iamthif_cl) {
mei_amthif_complete(dev, cb_pos);
}
}
}
return IRQ_HANDLED;
}
static const struct mei_hw_ops mei_me_hw_ops = {
.host_set_ready = mei_me_host_set_ready,
.host_is_ready = mei_me_host_is_ready,
.hw_is_ready = mei_me_hw_is_ready,
.hw_reset = mei_me_hw_reset,
.hw_config = mei_me_hw_config,
.hw_config = mei_me_hw_config,
.hw_start = mei_me_hw_start,
.intr_clear = mei_me_intr_clear,
.intr_enable = mei_me_intr_enable,
......@@ -571,14 +571,6 @@ struct mei_device *mei_me_dev_init(struct pci_dev *pdev)
mei_device_init(dev);
INIT_LIST_HEAD(&dev->wd_cl.link);
INIT_LIST_HEAD(&dev->iamthif_cl.link);
mei_io_list_init(&dev->amthif_cmd_list);
mei_io_list_init(&dev->amthif_rd_complete_list);
INIT_DELAYED_WORK(&dev->timer_work, mei_timer);
INIT_WORK(&dev->init_work, mei_host_client_init);
dev->ops = &mei_me_hw_ops;
dev->pdev = pdev;
......
......@@ -36,12 +36,6 @@ struct mei_me_hw {
struct mei_device *mei_me_dev_init(struct pci_dev *pdev);
/* get slots (dwords) from a message length + header (bytes) */
static inline unsigned char mei_data2slots(size_t length)
{
return DIV_ROUND_UP(sizeof(struct mei_msg_hdr) + length, 4);
}
irqreturn_t mei_me_irq_quick_handler(int irq, void *dev_id);
irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id);
......
......@@ -14,6 +14,7 @@
*
*/
#include <linux/export.h>
#include <linux/pci.h>
#include <linux/sched.h>
#include <linux/wait.h>
......@@ -22,6 +23,7 @@
#include <linux/mei.h>
#include "mei_dev.h"
#include "hbm.h"
#include "client.h"
const char *mei_dev_state_str(int state)
......@@ -31,9 +33,8 @@ const char *mei_dev_state_str(int state)
MEI_DEV_STATE(INITIALIZING);
MEI_DEV_STATE(INIT_CLIENTS);
MEI_DEV_STATE(ENABLED);
MEI_DEV_STATE(RESETING);
MEI_DEV_STATE(RESETTING);
MEI_DEV_STATE(DISABLED);
MEI_DEV_STATE(RECOVERING_FROM_RESET);
MEI_DEV_STATE(POWER_DOWN);
MEI_DEV_STATE(POWER_UP);
default:
......@@ -46,7 +47,9 @@ void mei_device_init(struct mei_device *dev)
{
/* setup our list array */
INIT_LIST_HEAD(&dev->file_list);
INIT_LIST_HEAD(&dev->device_list);
mutex_init(&dev->device_lock);
init_waitqueue_head(&dev->wait_hw_ready);
init_waitqueue_head(&dev->wait_recvd_msg);
init_waitqueue_head(&dev->wait_stop_wd);
dev->dev_state = MEI_DEV_INITIALIZING;
......@@ -56,19 +59,27 @@ void mei_device_init(struct mei_device *dev)
mei_io_list_init(&dev->write_waiting_list);
mei_io_list_init(&dev->ctrl_wr_list);
mei_io_list_init(&dev->ctrl_rd_list);
INIT_DELAYED_WORK(&dev->timer_work, mei_timer);
INIT_WORK(&dev->init_work, mei_host_client_init);
INIT_LIST_HEAD(&dev->wd_cl.link);
INIT_LIST_HEAD(&dev->iamthif_cl.link);
mei_io_list_init(&dev->amthif_cmd_list);
mei_io_list_init(&dev->amthif_rd_complete_list);
}
EXPORT_SYMBOL_GPL(mei_device_init);
/**
* mei_hw_init - initializes host and fw to start work.
* mei_start - initializes host and fw to start work.
*
* @dev: the device structure
*
* returns 0 on success, <0 on failure.
*/
int mei_hw_init(struct mei_device *dev)
int mei_start(struct mei_device *dev)
{
int ret = 0;
mutex_lock(&dev->device_lock);
/* acknowledge interrupt and stop interupts */
......@@ -76,29 +87,15 @@ int mei_hw_init(struct mei_device *dev)
mei_hw_config(dev);
dev->recvd_msg = false;
dev_dbg(&dev->pdev->dev, "reset in start the mei device.\n");
mei_reset(dev, 1);
/* wait for ME to turn on ME_RDY */
if (!dev->recvd_msg) {
mutex_unlock(&dev->device_lock);
ret = wait_event_interruptible_timeout(dev->wait_recvd_msg,
dev->recvd_msg,
mei_secs_to_jiffies(MEI_INTEROP_TIMEOUT));
mutex_lock(&dev->device_lock);
}
if (ret <= 0 && !dev->recvd_msg) {
dev->dev_state = MEI_DEV_DISABLED;
dev_dbg(&dev->pdev->dev,
"wait_event_interruptible_timeout failed"
"on wait for ME to turn on ME_RDY.\n");
if (mei_hbm_start_wait(dev)) {
dev_err(&dev->pdev->dev, "HBM haven't started");
goto err;
}
if (!mei_host_is_ready(dev)) {
dev_err(&dev->pdev->dev, "host is not ready.\n");
goto err;
......@@ -115,7 +112,6 @@ int mei_hw_init(struct mei_device *dev)
goto err;
}
dev->recvd_msg = false;
dev_dbg(&dev->pdev->dev, "link layer has been established.\n");
mutex_unlock(&dev->device_lock);
......@@ -126,6 +122,7 @@ int mei_hw_init(struct mei_device *dev)
mutex_unlock(&dev->device_lock);
return -ENODEV;
}
EXPORT_SYMBOL_GPL(mei_start);
/**
* mei_reset - resets host and fw.
......@@ -137,9 +134,6 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled)
{
bool unexpected;
if (dev->dev_state == MEI_DEV_RECOVERING_FROM_RESET)
return;
unexpected = (dev->dev_state != MEI_DEV_INITIALIZING &&
dev->dev_state != MEI_DEV_DISABLED &&
dev->dev_state != MEI_DEV_POWER_DOWN &&
......@@ -147,11 +141,12 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled)
mei_hw_reset(dev, interrupts_enabled);
dev->hbm_state = MEI_HBM_IDLE;
if (dev->dev_state != MEI_DEV_INITIALIZING) {
if (dev->dev_state != MEI_DEV_DISABLED &&
dev->dev_state != MEI_DEV_POWER_DOWN)
dev->dev_state = MEI_DEV_RESETING;
dev->dev_state = MEI_DEV_RESETTING;
mei_cl_all_disconnect(dev);
......@@ -176,12 +171,27 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled)
dev_warn(&dev->pdev->dev, "unexpected reset: dev_state = %s\n",
mei_dev_state_str(dev->dev_state));
if (!interrupts_enabled) {
dev_dbg(&dev->pdev->dev, "intr not enabled end of reset\n");
return;
}
mei_hw_start(dev);
dev_dbg(&dev->pdev->dev, "link is established start sending messages.\n");
/* link is established * start sending messages. */
dev->dev_state = MEI_DEV_INIT_CLIENTS;
mei_hbm_start_req(dev);
/* wake up all readings so they can be interrupted */
mei_cl_all_read_wakeup(dev);
/* remove all waiting requests */
mei_cl_all_write_clear(dev);
}
EXPORT_SYMBOL_GPL(mei_reset);
void mei_stop(struct mei_device *dev)
{
......@@ -193,14 +203,18 @@ void mei_stop(struct mei_device *dev)
mei_wd_stop(dev);
mei_nfc_host_exit();
dev->dev_state = MEI_DEV_POWER_DOWN;
mei_reset(dev, 0);
mutex_unlock(&dev->device_lock);
flush_scheduled_work();
}
mei_watchdog_unregister(dev);
}
EXPORT_SYMBOL_GPL(mei_stop);
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -317,7 +317,8 @@ static int mei_wd_ops_ping(struct watchdog_device *wd_dev)
*
* returns 0 if success, negative errno code for failure
*/
static int mei_wd_ops_set_timeout(struct watchdog_device *wd_dev, unsigned int timeout)
static int mei_wd_ops_set_timeout(struct watchdog_device *wd_dev,
unsigned int timeout)
{
struct mei_device *dev;
......
......@@ -417,24 +417,26 @@ static int tsl2550_remove(struct i2c_client *client)
return 0;
}
#ifdef CONFIG_PM
#ifdef CONFIG_PM_SLEEP
static int tsl2550_suspend(struct i2c_client *client, pm_message_t mesg)
static int tsl2550_suspend(struct device *dev)
{
return tsl2550_set_power_state(client, 0);
return tsl2550_set_power_state(to_i2c_client(dev), 0);
}
static int tsl2550_resume(struct i2c_client *client)
static int tsl2550_resume(struct device *dev)
{
return tsl2550_set_power_state(client, 1);
return tsl2550_set_power_state(to_i2c_client(dev), 1);
}
static SIMPLE_DEV_PM_OPS(tsl2550_pm_ops, tsl2550_suspend, tsl2550_resume);
#define TSL2550_PM_OPS (&tsl2550_pm_ops)
#else
#define tsl2550_suspend NULL
#define tsl2550_resume NULL
#define TSL2550_PM_OPS NULL
#endif /* CONFIG_PM */
#endif /* CONFIG_PM_SLEEP */
static const struct i2c_device_id tsl2550_id[] = {
{ "tsl2550", 0 },
......@@ -446,9 +448,8 @@ static struct i2c_driver tsl2550_driver = {
.driver = {
.name = TSL2550_DRV_NAME,
.owner = THIS_MODULE,
.pm = TSL2550_PM_OPS,
},
.suspend = tsl2550_suspend,
.resume = tsl2550_resume,
.probe = tsl2550_probe,
.remove = tsl2550_remove,
.id_table = tsl2550_id,
......
......@@ -543,25 +543,7 @@ static struct pcmcia_driver sdricoh_driver = {
.suspend = sdricoh_pcmcia_suspend,
.resume = sdricoh_pcmcia_resume,
};
/*****************************************************************************\
* *
* Driver init/exit *
* *
\*****************************************************************************/
static int __init sdricoh_drv_init(void)
{
return pcmcia_register_driver(&sdricoh_driver);
}
static void __exit sdricoh_drv_exit(void)
{
pcmcia_unregister_driver(&sdricoh_driver);
}
module_init(sdricoh_drv_init);
module_exit(sdricoh_drv_exit);
module_pcmcia_driver(sdricoh_driver);
module_param(switchlocked, uint, 0444);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -130,6 +130,10 @@ static struct pcmcia_driver b43_pcmcia_driver = {
.resume = b43_pcmcia_resume,
};
/*
* These are not module init/exit functions!
* The module_pcmcia_driver() helper cannot be used here.
*/
int b43_pcmcia_init(void)
{
return pcmcia_register_driver(&b43_pcmcia_driver);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment