Commit 7a53eea1 authored by Linus Torvalds's avatar Linus Torvalds

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

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

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

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

* tag 'char-misc-4.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (144 commits)
  drivers/misc/hpilo: Changes to support new security states in iLO5 FW
  at25: fix debug and error messaging
  misc/genwqe: ensure zero initialization
  vme: fake: remove unexpected unlock in fake_master_set()
  vme: fake: mark symbols static where possible
  spmi: pmic-arb: Return an error code if sanity check fails
  Drivers: hv: get rid of id in struct vmbus_channel
  Drivers: hv: make VMBus bus ids persistent
  mcb: Add a dma_device to mcb_device
  mcb: Enable PCI bus mastering by default
  mei: stop the stall timer worker if not needed
  clk: probe common clock drivers earlier
  vme: fake: fix build for 64-bit dma_addr_t
  ttyprintk: Neaten and simplify printing
  mei: me: add kaby point device ids
  coresight: tmc: mark symbols static where possible
  coresight: perf: deal with error condition properly
  Drivers: hv: hv_util: Avoid dynamic allocation in time synch
  fpga manager: Add hardware dependency to Zynq driver
  Drivers: hv: utils: Support TimeSync version 4.0 protocol samples.
  ...
parents 597f03f9 c9fef1cc
......@@ -1944,6 +1944,11 @@ E: kraxel@bytesex.org
E: kraxel@suse.de
D: video4linux, bttv, vesafb, some scsi, misc fixes
N: Hans J. Koch
D: USERSPACE I/O, MAX6650
D: Hans passed away in June 2016, and will be greatly missed.
W: https://lwn.net/Articles/691000/
N: Harald Koenig
E: koenig@tat.physik.uni-tuebingen.de
D: XFree86 (S3), DCF77, some kernel hacks and fixes
......
......@@ -153,7 +153,7 @@ Description:
What: /sys/class/mic/mic(x)/heartbeat_enable
Date: March 2015
KernelVersion: 3.20
KernelVersion: 4.4
Contact: Ashutosh Dixit <ashutosh.dixit@intel.com>
Description:
The MIC drivers detect and inform user space about card crashes
......
What: /sys/bus/i2c/devices/<busnum>-<devaddr>/pressure0_input
Date: June 2010
Contact: Christoph Mair <christoph.mair@gmail.com>
Description: Start a pressure measurement and read the result. Values
represent the ambient air pressure in pascal (0.01 millibar).
Reading: returns the current air pressure.
What: /sys/bus/i2c/devices/<busnum>-<devaddr>/temp0_input
Date: June 2010
Contact: Christoph Mair <christoph.mair@gmail.com>
Description: Measure the ambient temperature. The returned value represents
the ambient temperature in units of 0.1 degree celsius.
Reading: returns the current temperature.
What: /sys/bus/i2c/devices/<busnum>-<devaddr>/oversampling
Date: June 2010
Contact: Christoph Mair <christoph.mair@gmail.com>
Description: Tell the bmp085 to use more samples to calculate a pressure
value. When writing to this file the chip will use 2^x samples
to calculate the next pressure value with x being the value
written. Using this feature will decrease RMS noise and
increase the measurement time.
Reading: returns the current oversampling setting.
Writing: sets a new oversampling setting.
Accepted values: 0..3.
= Rockchip eFuse device tree bindings =
Required properties:
- compatible: Should be "rockchip,rockchip-efuse"
- compatible: Should be one of the following.
- "rockchip,rk3066a-efuse" - for RK3066a SoCs.
- "rockchip,rk3188-efuse" - for RK3188 SoCs.
- "rockchip,rk3288-efuse" - for RK3288 SoCs.
- "rockchip,rk3399-efuse" - for RK3399 SoCs.
- reg: Should contain the registers location and exact eFuse size
- clocks: Should be the clock id of eFuse
- clock-names: Should be "pclk_efuse"
Deprecated properties:
- compatible: "rockchip,rockchip-efuse"
Old efuse compatible value compatible to rk3066a, rk3188 and rk3288
efuses
= Data cells =
Are child nodes of eFuse, bindings of which as described in
bindings/nvmem/nvmem.txt
......@@ -13,7 +22,7 @@ bindings/nvmem/nvmem.txt
Example:
efuse: efuse@ffb40000 {
compatible = "rockchip,rockchip-efuse";
compatible = "rockchip,rk3288-efuse";
reg = <0xffb40000 0x20>;
#address-cells = <1>;
#size-cells = <1>;
......
......@@ -8,13 +8,14 @@ As with other subsystems within the Linux kernel, VME device drivers register
with the VME subsystem, typically called from the devices init routine. This is
achieved via a call to the following function:
int vme_register_driver (struct vme_driver *driver);
int vme_register_driver (struct vme_driver *driver, unsigned int ndevs);
If driver registration is successful this function returns zero, if an error
occurred a negative error code will be returned.
A pointer to a structure of type 'vme_driver' must be provided to the
registration function. The structure is as follows:
registration function. Along with ndevs, which is the number of devices your
driver is able to support. The structure is as follows:
struct vme_driver {
struct list_head node;
......@@ -32,8 +33,8 @@ At the minimum, the '.name', '.match' and '.probe' elements of this structure
should be correctly set. The '.name' element is a pointer to a string holding
the device driver's name.
The '.match' function allows controlling the number of devices that need to
be registered. The match function should return 1 if a device should be
The '.match' function allows control over which VME devices should be registered
with the driver. The match function should return 1 if a device should be
probed and 0 otherwise. This example match function (from vme_user.c) limits
the number of devices probed to one:
......@@ -385,13 +386,13 @@ location monitor location. Each location monitor can monitor a number of
adjacent locations:
int vme_lm_attach(struct vme_resource *res, int num,
void (*callback)(int));
void (*callback)(void *));
int vme_lm_detach(struct vme_resource *res, int num);
The callback function is declared as follows.
void callback(int num);
void callback(void *data);
Slot Detection
......
......@@ -7458,9 +7458,8 @@ F: Documentation/hwmon/max20751
F: drivers/hwmon/max20751.c
MAX6650 HARDWARE MONITOR AND FAN CONTROLLER DRIVER
M: "Hans J. Koch" <hjk@hansjkoch.de>
L: linux-hwmon@vger.kernel.org
S: Maintained
S: Orphan
F: Documentation/hwmon/max6650
F: drivers/hwmon/max6650.c
......@@ -12418,7 +12417,6 @@ F: fs/hostfs/
F: fs/hppfs/
USERSPACE I/O (UIO)
M: "Hans J. Koch" <hjk@hansjkoch.de>
M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc.git
......
......@@ -56,16 +56,4 @@ static struct miscdevice bL_switcher_device = {
"b.L_switcher",
&bL_switcher_fops
};
static int __init bL_switcher_dummy_if_init(void)
{
return misc_register(&bL_switcher_device);
}
static void __exit bL_switcher_dummy_if_exit(void)
{
misc_deregister(&bL_switcher_device);
}
module_init(bL_switcher_dummy_if_init);
module_exit(bL_switcher_dummy_if_exit);
module_misc_device(bL_switcher_device);
......@@ -59,18 +59,7 @@ static struct miscdevice coreb_dev = {
.name = "coreb",
.fops = &coreb_fops,
};
static int __init bf561_coreb_init(void)
{
return misc_register(&coreb_dev);
}
module_init(bf561_coreb_init);
static void __exit bf561_coreb_exit(void)
{
misc_deregister(&coreb_dev);
}
module_exit(bf561_coreb_exit);
module_misc_device(coreb_dev);
MODULE_AUTHOR("Bas Vermeulen <bvermeul@blackstar.xs4all.nl>");
MODULE_DESCRIPTION("BF561 Core B Support");
......
......@@ -175,27 +175,4 @@ static struct miscdevice harddog_miscdev = {
.name = "watchdog",
.fops = &harddog_fops,
};
static char banner[] __initdata = KERN_INFO "UML Watchdog Timer\n";
static int __init harddog_init(void)
{
int ret;
ret = misc_register(&harddog_miscdev);
if (ret)
return ret;
printk(banner);
return 0;
}
static void __exit harddog_exit(void)
{
misc_deregister(&harddog_miscdev);
}
module_init(harddog_init);
module_exit(harddog_exit);
module_misc_device(harddog_miscdev);
......@@ -29,6 +29,8 @@ obj-$(CONFIG_SFI) += sfi/
# was used and do nothing if so
obj-$(CONFIG_PNP) += pnp/
obj-y += amba/
obj-y += clk/
# Many drivers will want to use DMA so this has to be made available
# really early.
obj-$(CONFIG_DMADEVICES) += dma/
......@@ -142,8 +144,6 @@ obj-$(CONFIG_VHOST) += vhost/
obj-$(CONFIG_VLYNQ) += vlynq/
obj-$(CONFIG_STAGING) += staging/
obj-y += platform/
#common clk code
obj-y += clk/
obj-$(CONFIG_MAILBOX) += mailbox/
obj-$(CONFIG_HWSPINLOCK) += hwspinlock/
......
......@@ -377,21 +377,7 @@ static struct miscdevice vhci_miscdev = {
.fops = &vhci_fops,
.minor = VHCI_MINOR,
};
static int __init vhci_init(void)
{
BT_INFO("Virtual HCI driver ver %s", VERSION);
return misc_register(&vhci_miscdev);
}
static void __exit vhci_exit(void)
{
misc_deregister(&vhci_miscdev);
}
module_init(vhci_init);
module_exit(vhci_exit);
module_misc_device(vhci_miscdev);
module_param(amp, bool, 0644);
MODULE_PARM_DESC(amp, "Create AMP controller device");
......
......@@ -230,45 +230,7 @@ static struct miscdevice bfin_otp_misc_device = {
.name = DRIVER_NAME,
.fops = &bfin_otp_fops,
};
/**
* bfin_otp_init - Initialize module
*
* Registers the device and notifier handler. Actual device
* initialization is handled by bfin_otp_open().
*/
static int __init bfin_otp_init(void)
{
int ret;
stampit();
ret = misc_register(&bfin_otp_misc_device);
if (ret) {
pr_init(KERN_ERR PFX "unable to register a misc device\n");
return ret;
}
pr_init(KERN_INFO PFX "initialized\n");
return 0;
}
/**
* bfin_otp_exit - Deinitialize module
*
* Unregisters the device and notifier handler. Actual device
* deinitialization is handled by bfin_otp_close().
*/
static void __exit bfin_otp_exit(void)
{
stampit();
misc_deregister(&bfin_otp_misc_device);
}
module_init(bfin_otp_init);
module_exit(bfin_otp_exit);
module_misc_device(bfin_otp_misc_device);
MODULE_AUTHOR("Mike Frysinger <vapier@gentoo.org>");
MODULE_DESCRIPTION("Blackfin OTP Memory Interface");
......
......@@ -381,6 +381,9 @@ static ssize_t read_kmem(struct file *file, char __user *buf,
char *kbuf; /* k-addr because vread() takes vmlist_lock rwlock */
int err = 0;
if (!pfn_valid(PFN_DOWN(p)))
return -EIO;
read = 0;
if (p < (unsigned long) high_memory) {
low_count = count;
......@@ -509,6 +512,9 @@ static ssize_t write_kmem(struct file *file, const char __user *buf,
char *kbuf; /* k-addr because vwrite() takes vmlist_lock rwlock */
int err = 0;
if (!pfn_valid(PFN_DOWN(p)))
return -EIO;
if (p < (unsigned long) high_memory) {
unsigned long to_write = min_t(unsigned long, count,
(unsigned long)high_memory - p);
......
......@@ -124,7 +124,7 @@ static void dsp3780I_WriteGenCfg(unsigned short usDspBaseIO, unsigned uIndex,
MKBYTE(rSlaveControl));
rSlaveControl_Save = rSlaveControl;
rSlaveControl.ConfigMode = TRUE;
rSlaveControl.ConfigMode = true;
PRINTK_2(TRACE_3780I,
"3780i::dsp3780i_WriteGenCfg entry rSlaveControl+ConfigMode %x\n",
......@@ -155,7 +155,7 @@ unsigned char dsp3780I_ReadGenCfg(unsigned short usDspBaseIO,
MKBYTE(rSlaveControl) = InByteDsp(DSP_IsaSlaveControl);
rSlaveControl_Save = rSlaveControl;
rSlaveControl.ConfigMode = TRUE;
rSlaveControl.ConfigMode = true;
OutByteDsp(DSP_IsaSlaveControl, MKBYTE(rSlaveControl));
OutByteDsp(DSP_ConfigAddress, (unsigned char) uIndex);
ucValue = InByteDsp(DSP_ConfigData);
......@@ -230,7 +230,7 @@ int dsp3780I_EnableDSP(DSP_3780I_CONFIG_SETTINGS * pSettings,
rUartCfg1.BaseIO = 3;
break;
}
rUartCfg2.Enable = TRUE;
rUartCfg2.Enable = true;
}
rHBridgeCfg1.Reserved = rHBridgeCfg2.Reserved = 0;
......@@ -238,7 +238,7 @@ int dsp3780I_EnableDSP(DSP_3780I_CONFIG_SETTINGS * pSettings,
rHBridgeCfg1.IrqPulse = pSettings->bDspIrqPulse;
rHBridgeCfg1.Irq = (unsigned char) pIrqMap[pSettings->usDspIrq];
rHBridgeCfg1.AccessMode = 1;
rHBridgeCfg2.Enable = TRUE;
rHBridgeCfg2.Enable = true;
rBusmasterCfg2.Reserved = 0;
......@@ -278,8 +278,8 @@ int dsp3780I_EnableDSP(DSP_3780I_CONFIG_SETTINGS * pSettings,
* soft-reset active for 10ms.
*/
rSlaveControl.ClockControl = 0;
rSlaveControl.SoftReset = TRUE;
rSlaveControl.ConfigMode = FALSE;
rSlaveControl.SoftReset = true;
rSlaveControl.ConfigMode = false;
rSlaveControl.Reserved = 0;
PRINTK_4(TRACE_3780I,
......@@ -302,7 +302,7 @@ int dsp3780I_EnableDSP(DSP_3780I_CONFIG_SETTINGS * pSettings,
for (i = 0; i < 11; i++)
udelay(2000);
rSlaveControl.SoftReset = FALSE;
rSlaveControl.SoftReset = false;
OutWordDsp(DSP_IsaSlaveControl, MKWORD(rSlaveControl));
MKWORD(tval) = InWordDsp(DSP_IsaSlaveControl);
......@@ -326,10 +326,10 @@ int dsp3780I_EnableDSP(DSP_3780I_CONFIG_SETTINGS * pSettings,
}
rHBridgeControl.EnableDspInt = FALSE;
rHBridgeControl.MemAutoInc = TRUE;
rHBridgeControl.IoAutoInc = FALSE;
rHBridgeControl.DiagnosticMode = FALSE;
rHBridgeControl.EnableDspInt = false;
rHBridgeControl.MemAutoInc = true;
rHBridgeControl.IoAutoInc = false;
rHBridgeControl.DiagnosticMode = false;
PRINTK_3(TRACE_3780I,
"3780i::dsp3780i_EnableDSP DSP_HBridgeControl %x rHBridgeControl %x\n",
......@@ -345,7 +345,7 @@ int dsp3780I_EnableDSP(DSP_3780I_CONFIG_SETTINGS * pSettings,
ChipID = ReadMsaCfg(DSP_ChipID);
PRINTK_2(TRACE_3780I,
"3780i::dsp3780I_EnableDSP exiting bRC=TRUE, ChipID %x\n",
"3780i::dsp3780I_EnableDSP exiting bRC=true, ChipID %x\n",
ChipID);
return 0;
......@@ -361,8 +361,8 @@ int dsp3780I_DisableDSP(DSP_3780I_CONFIG_SETTINGS * pSettings)
PRINTK_1(TRACE_3780I, "3780i::dsp3780i_DisableDSP entry\n");
rSlaveControl.ClockControl = 0;
rSlaveControl.SoftReset = TRUE;
rSlaveControl.ConfigMode = FALSE;
rSlaveControl.SoftReset = true;
rSlaveControl.ConfigMode = false;
rSlaveControl.Reserved = 0;
spin_lock_irqsave(&dsp_lock, flags);
OutWordDsp(DSP_IsaSlaveControl, MKWORD(rSlaveControl));
......@@ -398,14 +398,14 @@ int dsp3780I_Reset(DSP_3780I_CONFIG_SETTINGS * pSettings)
PRINTK_2(TRACE_3780I, "3780i::dsp3780i_Reset rHBridgeControl %x\n",
MKWORD(rHBridgeControl));
rHBridgeControl.EnableDspInt = FALSE;
rHBridgeControl.EnableDspInt = false;
OutWordDsp(DSP_HBridgeControl, MKWORD(rHBridgeControl));
spin_unlock_irqrestore(&dsp_lock, flags);
/* Reset the core via the boot domain register */
rBootDomain.ResetCore = TRUE;
rBootDomain.Halt = TRUE;
rBootDomain.NMI = TRUE;
rBootDomain.ResetCore = true;
rBootDomain.Halt = true;
rBootDomain.NMI = true;
rBootDomain.Reserved = 0;
PRINTK_2(TRACE_3780I, "3780i::dsp3780i_Reset rBootDomain %x\n",
......@@ -438,26 +438,26 @@ int dsp3780I_Run(DSP_3780I_CONFIG_SETTINGS * pSettings)
/* Transition the core to a running state */
rBootDomain.ResetCore = TRUE;
rBootDomain.Halt = FALSE;
rBootDomain.NMI = TRUE;
rBootDomain.ResetCore = true;
rBootDomain.Halt = false;
rBootDomain.NMI = true;
rBootDomain.Reserved = 0;
WriteMsaCfg(DSP_MspBootDomain, MKWORD(rBootDomain));
udelay(5);
rBootDomain.ResetCore = FALSE;
rBootDomain.ResetCore = false;
WriteMsaCfg(DSP_MspBootDomain, MKWORD(rBootDomain));
udelay(5);
rBootDomain.NMI = FALSE;
rBootDomain.NMI = false;
WriteMsaCfg(DSP_MspBootDomain, MKWORD(rBootDomain));
udelay(5);
/* Enable DSP to PC interrupt */
spin_lock_irqsave(&dsp_lock, flags);
MKWORD(rHBridgeControl) = InWordDsp(DSP_HBridgeControl);
rHBridgeControl.EnableDspInt = TRUE;
rHBridgeControl.EnableDspInt = true;
PRINTK_2(TRACE_3780I, "3780i::dsp3780i_Run rHBridgeControl %x\n",
MKWORD(rHBridgeControl));
......@@ -466,7 +466,7 @@ int dsp3780I_Run(DSP_3780I_CONFIG_SETTINGS * pSettings)
spin_unlock_irqrestore(&dsp_lock, flags);
PRINTK_1(TRACE_3780I, "3780i::dsp3780i_Run exit bRC=TRUE\n");
PRINTK_1(TRACE_3780I, "3780i::dsp3780i_Run exit bRC=true\n");
return 0;
}
......@@ -508,7 +508,7 @@ int dsp3780I_ReadDStore(unsigned short usDspBaseIO, void __user *pvBuffer,
PRINTK_1(TRACE_3780I,
"3780I::dsp3780I_ReadDStore exit bRC=TRUE\n");
"3780I::dsp3780I_ReadDStore exit bRC=true\n");
return 0;
}
......@@ -550,7 +550,7 @@ int dsp3780I_ReadAndClearDStore(unsigned short usDspBaseIO,
PRINTK_1(TRACE_3780I,
"3780I::dsp3780I_ReadAndClearDStore exit bRC=TRUE\n");
"3780I::dsp3780I_ReadAndClearDStore exit bRC=true\n");
return 0;
}
......@@ -592,7 +592,7 @@ int dsp3780I_WriteDStore(unsigned short usDspBaseIO, void __user *pvBuffer,
PRINTK_1(TRACE_3780I,
"3780I::dsp3780D_WriteDStore exit bRC=TRUE\n");
"3780I::dsp3780D_WriteDStore exit bRC=true\n");
return 0;
}
......@@ -640,7 +640,7 @@ int dsp3780I_ReadIStore(unsigned short usDspBaseIO, void __user *pvBuffer,
}
PRINTK_1(TRACE_3780I,
"3780I::dsp3780I_ReadIStore exit bRC=TRUE\n");
"3780I::dsp3780I_ReadIStore exit bRC=true\n");
return 0;
}
......@@ -689,7 +689,7 @@ int dsp3780I_WriteIStore(unsigned short usDspBaseIO, void __user *pvBuffer,
}
PRINTK_1(TRACE_3780I,
"3780I::dsp3780I_WriteIStore exit bRC=TRUE\n");
"3780I::dsp3780I_WriteIStore exit bRC=true\n");
return 0;
}
......@@ -713,7 +713,7 @@ int dsp3780I_GetIPCSource(unsigned short usDspBaseIO,
*/
spin_lock_irqsave(&dsp_lock, flags);
MKWORD(rHBridgeControl) = InWordDsp(DSP_HBridgeControl);
rHBridgeControl.EnableDspInt = FALSE;
rHBridgeControl.EnableDspInt = false;
OutWordDsp(DSP_HBridgeControl, MKWORD(rHBridgeControl));
*pusIPCSource = InWordDsp(DSP_Interrupt);
......@@ -725,7 +725,7 @@ int dsp3780I_GetIPCSource(unsigned short usDspBaseIO,
OutWordDsp(DSP_Interrupt, (unsigned short) ~(*pusIPCSource));
rHBridgeControl.EnableDspInt = TRUE;
rHBridgeControl.EnableDspInt = true;
OutWordDsp(DSP_HBridgeControl, MKWORD(rHBridgeControl));
spin_unlock_irqrestore(&dsp_lock, flags);
......
......@@ -101,7 +101,7 @@ typedef struct {
} DSP_UART_CFG_1;
typedef struct {
unsigned char Enable:1; /* RW: Enable I/O and IRQ: 0=FALSE, 1=TRUE */
unsigned char Enable:1; /* RW: Enable I/O and IRQ: 0=false, 1=true */
unsigned char Reserved:7; /* 0: Reserved */
} DSP_UART_CFG_2;
......@@ -114,7 +114,7 @@ typedef struct {
} DSP_HBRIDGE_CFG_1;
typedef struct {
unsigned char Enable:1; /* RW: enable I/O and IRQ: 0=FALSE, 1=TRUE */
unsigned char Enable:1; /* RW: enable I/O and IRQ: 0=false, 1=true */
unsigned char Reserved:7; /* 0: Reserved */
} DSP_HBRIDGE_CFG_2;
......@@ -133,12 +133,12 @@ typedef struct {
typedef struct {
unsigned char GateIOCHRDY:1; /* RW: Enable IOCHRDY gating: 0=FALSE, 1=TRUE */
unsigned char GateIOCHRDY:1; /* RW: Enable IOCHRDY gating: 0=false, 1=true */
unsigned char Reserved:7; /* 0: Reserved */
} DSP_ISA_PROT_CFG;
typedef struct {
unsigned char Enable:1; /* RW: Enable low power suspend/resume 0=FALSE, 1=TRUE */
unsigned char Enable:1; /* RW: Enable low power suspend/resume 0=false, 1=true */
unsigned char Reserved:7; /* 0: Reserved */
} DSP_POWER_MGMT_CFG;
......
......@@ -296,8 +296,8 @@ static long mwave_ioctl(struct file *file, unsigned int iocmd,
pDrvData->IPCs[ipcnum].usIntCount);
mutex_lock(&mwave_mutex);
pDrvData->IPCs[ipcnum].bIsHere = FALSE;
pDrvData->IPCs[ipcnum].bIsEnabled = TRUE;
pDrvData->IPCs[ipcnum].bIsHere = false;
pDrvData->IPCs[ipcnum].bIsEnabled = true;
mutex_unlock(&mwave_mutex);
PRINTK_2(TRACE_MWAVE,
......@@ -324,7 +324,7 @@ static long mwave_ioctl(struct file *file, unsigned int iocmd,
pDrvData->IPCs[ipcnum].usIntCount);
mutex_lock(&mwave_mutex);
if (pDrvData->IPCs[ipcnum].bIsEnabled == TRUE) {
if (pDrvData->IPCs[ipcnum].bIsEnabled == true) {
DECLARE_WAITQUEUE(wait, current);
PRINTK_2(TRACE_MWAVE,
......@@ -332,7 +332,7 @@ static long mwave_ioctl(struct file *file, unsigned int iocmd,
" ipc %x going to sleep\n",
ipcnum);
add_wait_queue(&pDrvData->IPCs[ipcnum].ipc_wait_queue, &wait);
pDrvData->IPCs[ipcnum].bIsHere = TRUE;
pDrvData->IPCs[ipcnum].bIsHere = true;
set_current_state(TASK_INTERRUPTIBLE);
/* check whether an event was signalled by */
/* the interrupt handler while we were gone */
......@@ -355,7 +355,7 @@ static long mwave_ioctl(struct file *file, unsigned int iocmd,
" application\n",
ipcnum);
}
pDrvData->IPCs[ipcnum].bIsHere = FALSE;
pDrvData->IPCs[ipcnum].bIsHere = false;
remove_wait_queue(&pDrvData->IPCs[ipcnum].ipc_wait_queue, &wait);
set_current_state(TASK_RUNNING);
PRINTK_2(TRACE_MWAVE,
......@@ -384,9 +384,9 @@ static long mwave_ioctl(struct file *file, unsigned int iocmd,
return -EINVAL;
}
mutex_lock(&mwave_mutex);
if (pDrvData->IPCs[ipcnum].bIsEnabled == TRUE) {
pDrvData->IPCs[ipcnum].bIsEnabled = FALSE;
if (pDrvData->IPCs[ipcnum].bIsHere == TRUE) {
if (pDrvData->IPCs[ipcnum].bIsEnabled == true) {
pDrvData->IPCs[ipcnum].bIsEnabled = false;
if (pDrvData->IPCs[ipcnum].bIsHere == true) {
wake_up_interruptible(&pDrvData->IPCs[ipcnum].ipc_wait_queue);
}
}
......@@ -541,7 +541,7 @@ static void mwave_exit(void)
if (pDrvData->device_registered) {
device_unregister(&mwave_device);
pDrvData->device_registered = FALSE;
pDrvData->device_registered = false;
}
#endif
......@@ -576,16 +576,16 @@ static int __init mwave_init(void)
memset(&mwave_s_mdd, 0, sizeof(MWAVE_DEVICE_DATA));
pDrvData->bBDInitialized = FALSE;
pDrvData->bResourcesClaimed = FALSE;
pDrvData->bDSPEnabled = FALSE;
pDrvData->bDSPReset = FALSE;
pDrvData->bMwaveDevRegistered = FALSE;
pDrvData->bBDInitialized = false;
pDrvData->bResourcesClaimed = false;
pDrvData->bDSPEnabled = false;
pDrvData->bDSPReset = false;
pDrvData->bMwaveDevRegistered = false;
pDrvData->sLine = -1;
for (i = 0; i < ARRAY_SIZE(pDrvData->IPCs); i++) {
pDrvData->IPCs[i].bIsEnabled = FALSE;
pDrvData->IPCs[i].bIsHere = FALSE;
pDrvData->IPCs[i].bIsEnabled = false;
pDrvData->IPCs[i].bIsHere = false;
pDrvData->IPCs[i].usIntCount = 0; /* no ints received yet */
init_waitqueue_head(&pDrvData->IPCs[i].ipc_wait_queue);
}
......@@ -601,7 +601,7 @@ static int __init mwave_init(void)
" Failed to initialize board data\n");
goto cleanup_error;
}
pDrvData->bBDInitialized = TRUE;
pDrvData->bBDInitialized = true;
retval = tp3780I_CalcResources(&pDrvData->rBDData);
PRINTK_2(TRACE_MWAVE,
......@@ -626,7 +626,7 @@ static int __init mwave_init(void)
" Failed to claim resources\n");
goto cleanup_error;
}
pDrvData->bResourcesClaimed = TRUE;
pDrvData->bResourcesClaimed = true;
retval = tp3780I_EnableDSP(&pDrvData->rBDData);
PRINTK_2(TRACE_MWAVE,
......@@ -639,7 +639,7 @@ static int __init mwave_init(void)
" Failed to enable DSP\n");
goto cleanup_error;
}
pDrvData->bDSPEnabled = TRUE;
pDrvData->bDSPEnabled = true;
if (misc_register(&mwave_misc_dev) < 0) {
PRINTK_ERROR(KERN_ERR_MWAVE
......@@ -647,7 +647,7 @@ static int __init mwave_init(void)
" Failed to register misc device\n");
goto cleanup_error;
}
pDrvData->bMwaveDevRegistered = TRUE;
pDrvData->bMwaveDevRegistered = true;
pDrvData->sLine = register_serial_portandirq(
pDrvData->rBDData.rDspSettings.usUartBaseIO,
......@@ -668,7 +668,7 @@ static int __init mwave_init(void)
if (device_register(&mwave_device))
goto cleanup_error;
pDrvData->device_registered = TRUE;
pDrvData->device_registered = true;
for (i = 0; i < ARRAY_SIZE(mwave_dev_attrs); i++) {
if(device_create_file(&mwave_device, mwave_dev_attrs[i])) {
PRINTK_ERROR(KERN_ERR_MWAVE
......
......@@ -125,8 +125,8 @@ extern int mwave_uart_io;
typedef struct _MWAVE_IPC {
unsigned short usIntCount; /* 0=none, 1=first, 2=greater than 1st */
BOOLEAN bIsEnabled;
BOOLEAN bIsHere;
bool bIsEnabled;
bool bIsHere;
/* entry spin lock */
wait_queue_head_t ipc_wait_queue;
} MWAVE_IPC;
......@@ -135,12 +135,12 @@ typedef struct _MWAVE_DEVICE_DATA {
THINKPAD_BD_DATA rBDData; /* board driver's data area */
unsigned long ulIPCSource_ISR; /* IPC source bits for recently processed intr, set during ISR processing */
unsigned long ulIPCSource_DPC; /* IPC source bits for recently processed intr, set during DPC processing */
BOOLEAN bBDInitialized;
BOOLEAN bResourcesClaimed;
BOOLEAN bDSPEnabled;
BOOLEAN bDSPReset;
bool bBDInitialized;
bool bResourcesClaimed;
bool bDSPEnabled;
bool bDSPReset;
MWAVE_IPC IPCs[16];
BOOLEAN bMwaveDevRegistered;
bool bMwaveDevRegistered;
short sLine;
int nr_registered_attrs;
int device_registered;
......
......@@ -493,7 +493,7 @@ int smapi_set_DSP_cfg(void)
}
int smapi_set_DSP_power_state(BOOLEAN bOn)
int smapi_set_DSP_power_state(bool bOn)
{
int bRC = -EIO;
unsigned short usAX, usBX, usCX, usDX, usDI, usSI;
......@@ -556,7 +556,7 @@ int smapi_init(void)
PRINTK_ERROR("smapi::smapi_init, ERROR unable to read from SMAPI port\n");
} else {
PRINTK_2(TRACE_SMAPI,
"smapi::smapi_init, exit TRUE g_usSmapiPort %x\n",
"smapi::smapi_init, exit true g_usSmapiPort %x\n",
g_usSmapiPort);
retval = 0;
//SmapiQuerySystemID();
......
......@@ -49,10 +49,6 @@
#ifndef _LINUX_SMAPI_H
#define _LINUX_SMAPI_H
#define TRUE 1
#define FALSE 0
#define BOOLEAN int
typedef struct {
int bDSPPresent;
int bDSPEnabled;
......@@ -74,7 +70,7 @@ typedef struct {
int smapi_init(void);
int smapi_query_DSP_cfg(SMAPI_DSP_SETTINGS * pSettings);
int smapi_set_DSP_cfg(void);
int smapi_set_DSP_power_state(BOOLEAN bOn);
int smapi_set_DSP_power_state(bool bOn);
#endif
......@@ -80,13 +80,13 @@ static void EnableSRAM(THINKPAD_BD_DATA * pBDData)
WriteMsaCfg(DSP_GpioModeControl_15_8, MKWORD(rGpioMode));
MKWORD(rGpioDriverEnable) = 0;
rGpioDriverEnable.Enable10 = TRUE;
rGpioDriverEnable.Mask10 = TRUE;
rGpioDriverEnable.Enable10 = true;
rGpioDriverEnable.Mask10 = true;
WriteMsaCfg(DSP_GpioDriverEnable_15_8, MKWORD(rGpioDriverEnable));
MKWORD(rGpioOutputData) = 0;
rGpioOutputData.Latch10 = 0;
rGpioOutputData.Mask10 = TRUE;
rGpioOutputData.Mask10 = true;
WriteMsaCfg(DSP_GpioOutputData_15_8, MKWORD(rGpioOutputData));
PRINTK_1(TRACE_TP3780I, "tp3780i::EnableSRAM exit\n");
......@@ -127,7 +127,7 @@ static irqreturn_t DspInterrupt(int irq, void *dev_id)
PRINTK_2(TRACE_TP3780I,
"tp3780i::DspInterrupt usIntCount %x\n",
pDrvData->IPCs[usPCNum - 1].usIntCount);
if (pDrvData->IPCs[usPCNum - 1].bIsEnabled == TRUE) {
if (pDrvData->IPCs[usPCNum - 1].bIsEnabled == true) {
PRINTK_2(TRACE_TP3780I,
"tp3780i::DspInterrupt, waking up usPCNum %x\n",
usPCNum - 1);
......@@ -160,8 +160,8 @@ int tp3780I_InitializeBoardData(THINKPAD_BD_DATA * pBDData)
PRINTK_2(TRACE_TP3780I, "tp3780i::tp3780I_InitializeBoardData entry pBDData %p\n", pBDData);
pBDData->bDSPEnabled = FALSE;
pSettings->bInterruptClaimed = FALSE;
pBDData->bDSPEnabled = false;
pSettings->bInterruptClaimed = false;
retval = smapi_init();
if (retval) {
......@@ -269,7 +269,7 @@ int tp3780I_ReleaseResources(THINKPAD_BD_DATA * pBDData)
if (pSettings->bInterruptClaimed) {
free_irq(pSettings->usDspIrq, NULL);
pSettings->bInterruptClaimed = FALSE;
pSettings->bInterruptClaimed = false;
}
PRINTK_2(TRACE_TP3780I,
......@@ -283,7 +283,7 @@ int tp3780I_ReleaseResources(THINKPAD_BD_DATA * pBDData)
int tp3780I_EnableDSP(THINKPAD_BD_DATA * pBDData)
{
DSP_3780I_CONFIG_SETTINGS *pSettings = &pBDData->rDspSettings;
BOOLEAN bDSPPoweredUp = FALSE, bInterruptAllocated = FALSE;
bool bDSPPoweredUp = false, bInterruptAllocated = false;
PRINTK_2(TRACE_TP3780I, "tp3780i::tp3780I_EnableDSP entry pBDData %p\n", pBDData);
......@@ -336,14 +336,14 @@ int tp3780I_EnableDSP(THINKPAD_BD_DATA * pBDData)
}
}
pSettings->bDspIrqActiveLow = pSettings->bDspIrqPulse = TRUE;
pSettings->bUartIrqActiveLow = pSettings->bUartIrqPulse = TRUE;
pSettings->bDspIrqActiveLow = pSettings->bDspIrqPulse = true;
pSettings->bUartIrqActiveLow = pSettings->bUartIrqPulse = true;
if (pBDData->bShareDspIrq) {
pSettings->bDspIrqActiveLow = FALSE;
pSettings->bDspIrqActiveLow = false;
}
if (pBDData->bShareUartIrq) {
pSettings->bUartIrqActiveLow = FALSE;
pSettings->bUartIrqActiveLow = false;
}
pSettings->usNumTransfers = TP_CFG_NumTransfers;
......@@ -373,16 +373,16 @@ int tp3780I_EnableDSP(THINKPAD_BD_DATA * pBDData)
PRINTK_3(TRACE_TP3780I,
"tp3780i::tp3780I_EnableDSP, got interrupt %x bShareDspIrq %x\n",
pSettings->usDspIrq, pBDData->bShareDspIrq);
bInterruptAllocated = TRUE;
pSettings->bInterruptClaimed = TRUE;
bInterruptAllocated = true;
pSettings->bInterruptClaimed = true;
}
smapi_set_DSP_power_state(FALSE);
if (smapi_set_DSP_power_state(TRUE)) {
PRINTK_ERROR(KERN_ERR_MWAVE "tp3780i::tp3780I_EnableDSP: Error: smapi_set_DSP_power_state(TRUE) failed\n");
smapi_set_DSP_power_state(false);
if (smapi_set_DSP_power_state(true)) {
PRINTK_ERROR(KERN_ERR_MWAVE "tp3780i::tp3780I_EnableDSP: Error: smapi_set_DSP_power_state(true) failed\n");
goto exit_cleanup;
} else {
bDSPPoweredUp = TRUE;
bDSPPoweredUp = true;
}
if (dsp3780I_EnableDSP(pSettings, s_ausThinkpadIrqToField, s_ausThinkpadDmaToField)) {
......@@ -392,7 +392,7 @@ int tp3780I_EnableDSP(THINKPAD_BD_DATA * pBDData)
EnableSRAM(pBDData);
pBDData->bDSPEnabled = TRUE;
pBDData->bDSPEnabled = true;
PRINTK_1(TRACE_TP3780I, "tp3780i::tp3780I_EnableDSP exit\n");
......@@ -401,10 +401,10 @@ int tp3780I_EnableDSP(THINKPAD_BD_DATA * pBDData)
exit_cleanup:
PRINTK_ERROR("tp3780i::tp3780I_EnableDSP: Cleaning up\n");
if (bDSPPoweredUp)
smapi_set_DSP_power_state(FALSE);
smapi_set_DSP_power_state(false);
if (bInterruptAllocated) {
free_irq(pSettings->usDspIrq, NULL);
pSettings->bInterruptClaimed = FALSE;
pSettings->bInterruptClaimed = false;
}
return -EIO;
}
......@@ -421,10 +421,10 @@ int tp3780I_DisableDSP(THINKPAD_BD_DATA * pBDData)
dsp3780I_DisableDSP(&pBDData->rDspSettings);
if (pSettings->bInterruptClaimed) {
free_irq(pSettings->usDspIrq, NULL);
pSettings->bInterruptClaimed = FALSE;
pSettings->bInterruptClaimed = false;
}
smapi_set_DSP_power_state(FALSE);
pBDData->bDSPEnabled = FALSE;
smapi_set_DSP_power_state(false);
pBDData->bDSPEnabled = false;
}
PRINTK_2(TRACE_TP3780I, "tp3780i::tp3780I_DisableDSP exit retval %x\n", retval);
......@@ -516,7 +516,7 @@ int tp3780I_ReadWriteDspDStore(THINKPAD_BD_DATA * pBDData, unsigned int uOpcode,
int retval = 0;
DSP_3780I_CONFIG_SETTINGS *pSettings = &pBDData->rDspSettings;
unsigned short usDspBaseIO = pSettings->usDspBaseIO;
BOOLEAN bRC = 0;
bool bRC = 0;
PRINTK_6(TRACE_TP3780I,
"tp3780i::tp3780I_ReadWriteDspDStore entry pBDData %p, uOpcode %x, pvBuffer %p, uCount %x, ulDSPAddr %lx\n",
......@@ -552,7 +552,7 @@ int tp3780I_ReadWriteDspIStore(THINKPAD_BD_DATA * pBDData, unsigned int uOpcode,
int retval = 0;
DSP_3780I_CONFIG_SETTINGS *pSettings = &pBDData->rDspSettings;
unsigned short usDspBaseIO = pSettings->usDspBaseIO;
BOOLEAN bRC = 0;
bool bRC = 0;
PRINTK_6(TRACE_TP3780I,
"tp3780i::tp3780I_ReadWriteDspIStore entry pBDData %p, uOpcode %x, pvBuffer %p, uCount %x, ulDSPAddr %lx\n",
......
......@@ -286,7 +286,7 @@ static int register_device(int minor, struct pp_struct *pp)
struct parport *port;
struct pardevice *pdev = NULL;
char *name;
int fl;
struct pardev_cb ppdev_cb;
name = kasprintf(GFP_KERNEL, CHRDEV "%x", minor);
if (name == NULL)
......@@ -299,9 +299,11 @@ static int register_device(int minor, struct pp_struct *pp)
return -ENXIO;
}
fl = (pp->flags & PP_EXCL) ? PARPORT_FLAG_EXCL : 0;
pdev = parport_register_device(port, name, NULL,
NULL, pp_irq, fl, pp);
memset(&ppdev_cb, 0, sizeof(ppdev_cb));
ppdev_cb.irq_func = pp_irq;
ppdev_cb.flags = (pp->flags & PP_EXCL) ? PARPORT_FLAG_EXCL : 0;
ppdev_cb.private = pp;
pdev = parport_register_dev_model(port, name, &ppdev_cb, minor);
parport_put_port(port);
if (!pdev) {
......@@ -799,10 +801,23 @@ static void pp_detach(struct parport *port)
device_destroy(ppdev_class, MKDEV(PP_MAJOR, port->number));
}
static int pp_probe(struct pardevice *par_dev)
{
struct device_driver *drv = par_dev->dev.driver;
int len = strlen(drv->name);
if (strncmp(par_dev->name, drv->name, len))
return -ENODEV;
return 0;
}
static struct parport_driver pp_driver = {
.name = CHRDEV,
.attach = pp_attach,
.probe = pp_probe,
.match_port = pp_attach,
.detach = pp_detach,
.devmodel = true,
};
static int __init ppdev_init(void)
......
......@@ -385,13 +385,18 @@ scdrv_init(void)
event_nasid = ia64_sn_get_console_nasid();
snsc_class = class_create(THIS_MODULE, SYSCTL_BASENAME);
if (IS_ERR(snsc_class)) {
printk("%s: failed to allocate class\n", __func__);
return PTR_ERR(snsc_class);
}
if (alloc_chrdev_region(&first_dev, 0, num_cnodes,
SYSCTL_BASENAME) < 0) {
printk("%s: failed to register SN system controller device\n",
__func__);
return -ENODEV;
}
snsc_class = class_create(THIS_MODULE, SYSCTL_BASENAME);
for (cnode = 0; cnode < num_cnodes; cnode++) {
geoid = cnodeid_get_geoid(cnode);
......
......@@ -331,13 +331,11 @@ static const struct file_operations srom_fops = {
/**
* srom_setup_minor() - Initialize per-minor information.
* @srom: Per-device SROM state.
* @index: Device to set up.
* @devhdl: Partition device handle.
*/
static int srom_setup_minor(struct srom_dev *srom, int index)
static int srom_setup_minor(struct srom_dev *srom, int devhdl)
{
struct device *dev;
int devhdl = srom->hv_devhdl;
srom->hv_devhdl = devhdl;
mutex_init(&srom->lock);
if (_srom_read(devhdl, &srom->total_size,
......@@ -350,9 +348,7 @@ static int srom_setup_minor(struct srom_dev *srom, int index)
SROM_PAGE_SIZE_OFF, sizeof(srom->page_size)) < 0)
return -EIO;
dev = device_create(srom_class, &srom_parent->dev,
MKDEV(srom_major, index), srom, "%d", index);
return PTR_ERR_OR_ZERO(dev);
return 0;
}
/** srom_init() - Initialize the driver's module. */
......@@ -365,7 +361,7 @@ static int srom_init(void)
* Start with a plausible number of partitions; the krealloc() call
* below will yield about log(srom_devs) additional allocations.
*/
srom_devices = kzalloc(4 * sizeof(struct srom_dev), GFP_KERNEL);
srom_devices = kmalloc(4 * sizeof(struct srom_dev), GFP_KERNEL);
/* Discover the number of srom partitions. */
for (i = 0; ; i++) {
......@@ -373,7 +369,7 @@ static int srom_init(void)
char buf[20];
struct srom_dev *new_srom_devices =
krealloc(srom_devices, (i+1) * sizeof(struct srom_dev),
GFP_KERNEL | __GFP_ZERO);
GFP_KERNEL);
if (!new_srom_devices) {
result = -ENOMEM;
goto fail_mem;
......@@ -387,7 +383,9 @@ static int srom_init(void)
i, devhdl);
break;
}
srom_devices[i].hv_devhdl = devhdl;
result = srom_setup_minor(&srom_devices[i], devhdl);
if (result != 0)
goto fail_mem;
}
srom_devs = i;
......@@ -431,9 +429,13 @@ static int srom_init(void)
srom_class->dev_groups = srom_dev_groups;
srom_class->devnode = srom_devnode;
/* Do per-partition initialization */
/* Create per-partition devices */
for (i = 0; i < srom_devs; i++) {
result = srom_setup_minor(srom_devices + i, i);
struct device *dev =
device_create(srom_class, &srom_parent->dev,
MKDEV(srom_major, i), srom_devices + i,
"%d", i);
result = PTR_ERR_OR_ZERO(dev);
if (result < 0)
goto fail_class;
}
......
......@@ -31,60 +31,53 @@ static struct ttyprintk_port tpk_port;
* printk messages (also suitable for logging service):
* - any cr is replaced by nl
* - adds a ttyprintk source tag in front of each line
* - too long message is fragmeted, with '\'nl between fragments
* - TPK_STR_SIZE isn't really the write_room limiting factor, bcause
* - too long message is fragmented, with '\'nl between fragments
* - TPK_STR_SIZE isn't really the write_room limiting factor, because
* it is emptied on the fly during preformatting.
*/
#define TPK_STR_SIZE 508 /* should be bigger then max expected line length */
#define TPK_MAX_ROOM 4096 /* we could assume 4K for instance */
static const char *tpk_tag = "[U] "; /* U for User */
static int tpk_curr;
static char tpk_buffer[TPK_STR_SIZE + 4];
static void tpk_flush(void)
{
if (tpk_curr > 0) {
tpk_buffer[tpk_curr] = '\0';
pr_info("[U] %s\n", tpk_buffer);
tpk_curr = 0;
}
}
static int tpk_printk(const unsigned char *buf, int count)
{
static char tmp[TPK_STR_SIZE + 4];
int i = tpk_curr;
if (buf == NULL) {
/* flush tmp[] */
if (tpk_curr > 0) {
/* non nl or cr terminated message - add nl */
tmp[tpk_curr + 0] = '\n';
tmp[tpk_curr + 1] = '\0';
printk(KERN_INFO "%s%s", tpk_tag, tmp);
tpk_curr = 0;
}
tpk_flush();
return i;
}
for (i = 0; i < count; i++) {
tmp[tpk_curr] = buf[i];
if (tpk_curr < TPK_STR_SIZE) {
switch (buf[i]) {
case '\r':
/* replace cr with nl */
tmp[tpk_curr + 0] = '\n';
tmp[tpk_curr + 1] = '\0';
printk(KERN_INFO "%s%s", tpk_tag, tmp);
tpk_curr = 0;
if ((i + 1) < count && buf[i + 1] == '\n')
i++;
break;
case '\n':
tmp[tpk_curr + 1] = '\0';
printk(KERN_INFO "%s%s", tpk_tag, tmp);
tpk_curr = 0;
break;
default:
tpk_curr++;
}
} else {
if (tpk_curr >= TPK_STR_SIZE) {
/* end of tmp buffer reached: cut the message in two */
tmp[tpk_curr + 1] = '\\';
tmp[tpk_curr + 2] = '\n';
tmp[tpk_curr + 3] = '\0';
printk(KERN_INFO "%s%s", tpk_tag, tmp);
tpk_curr = 0;
tpk_buffer[tpk_curr++] = '\\';
tpk_flush();
}
switch (buf[i]) {
case '\r':
tpk_flush();
if ((i + 1) < count && buf[i + 1] == '\n')
i++;
break;
case '\n':
tpk_flush();
break;
default:
tpk_buffer[tpk_curr++] = buf[i];
break;
}
}
......
......@@ -655,10 +655,10 @@ static int xilly_obtain_idt(struct xilly_endpoint *endpoint)
version = channel->wr_buffers[0]->addr;
/* Check version number. Accept anything below 0x82 for now. */
/* Check version number. Reject anything above 0x82. */
if (*version > 0x82) {
dev_err(endpoint->dev,
"No support for IDT version 0x%02x. Maybe the xillybus driver needs an upgarde. Aborting.\n",
"No support for IDT version 0x%02x. Maybe the xillybus driver needs an upgrade. Aborting.\n",
*version);
return -ENODEV;
}
......
......@@ -21,6 +21,7 @@ config FPGA_MGR_SOCFPGA
config FPGA_MGR_ZYNQ_FPGA
tristate "Xilinx Zynq FPGA"
depends on ARCH_ZYNQ || COMPILE_TEST
depends on HAS_DMA
help
FPGA manager driver support for Xilinx Zynq FPGAs.
......
......@@ -779,19 +779,8 @@ static struct miscdevice uhid_misc = {
.minor = UHID_MINOR,
.name = UHID_NAME,
};
module_misc_device(uhid_misc);
static int __init uhid_init(void)
{
return misc_register(&uhid_misc);
}
static void __exit uhid_exit(void)
{
misc_deregister(&uhid_misc);
}
module_init(uhid_init);
module_exit(uhid_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("David Herrmann <dh.herrmann@gmail.com>");
MODULE_DESCRIPTION("User-space I/O driver support for HID subsystem");
......
This diff is collapsed.
......@@ -21,6 +21,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/mm.h>
......@@ -138,10 +139,32 @@ static const struct vmbus_device vmbus_devs[] = {
},
};
static u16 hv_get_dev_type(const uuid_le *guid)
static const struct {
uuid_le guid;
} vmbus_unsupported_devs[] = {
{ HV_AVMA1_GUID },
{ HV_AVMA2_GUID },
{ HV_RDV_GUID },
};
static bool is_unsupported_vmbus_devs(const uuid_le *guid)
{
int i;
for (i = 0; i < ARRAY_SIZE(vmbus_unsupported_devs); i++)
if (!uuid_le_cmp(*guid, vmbus_unsupported_devs[i].guid))
return true;
return false;
}
static u16 hv_get_dev_type(const struct vmbus_channel *channel)
{
const uuid_le *guid = &channel->offermsg.offer.if_type;
u16 i;
if (is_hvsock_channel(channel) || is_unsupported_vmbus_devs(guid))
return HV_UNKOWN;
for (i = HV_IDE; i < HV_UNKOWN; i++) {
if (!uuid_le_cmp(*guid, vmbus_devs[i].guid))
return i;
......@@ -251,14 +274,12 @@ EXPORT_SYMBOL_GPL(vmbus_prep_negotiate_resp);
*/
static struct vmbus_channel *alloc_channel(void)
{
static atomic_t chan_num = ATOMIC_INIT(0);
struct vmbus_channel *channel;
channel = kzalloc(sizeof(*channel), GFP_ATOMIC);
if (!channel)
return NULL;
channel->id = atomic_inc_return(&chan_num);
channel->acquire_ring_lock = true;
spin_lock_init(&channel->inbound_lock);
spin_lock_init(&channel->lock);
......@@ -303,16 +324,32 @@ static void vmbus_release_relid(u32 relid)
vmbus_post_msg(&msg, sizeof(struct vmbus_channel_relid_released));
}
void hv_event_tasklet_disable(struct vmbus_channel *channel)
{
struct tasklet_struct *tasklet;
tasklet = hv_context.event_dpc[channel->target_cpu];
tasklet_disable(tasklet);
}
void hv_event_tasklet_enable(struct vmbus_channel *channel)
{
struct tasklet_struct *tasklet;
tasklet = hv_context.event_dpc[channel->target_cpu];
tasklet_enable(tasklet);
/* In case there is any pending event */
tasklet_schedule(tasklet);
}
void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid)
{
unsigned long flags;
struct vmbus_channel *primary_channel;
vmbus_release_relid(relid);
BUG_ON(!channel->rescind);
BUG_ON(!mutex_is_locked(&vmbus_connection.channel_mutex));
hv_event_tasklet_disable(channel);
if (channel->target_cpu != get_cpu()) {
put_cpu();
smp_call_function_single(channel->target_cpu,
......@@ -321,6 +358,7 @@ void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid)
percpu_channel_deq(channel);
put_cpu();
}
hv_event_tasklet_enable(channel);
if (channel->primary_channel == NULL) {
list_del(&channel->listentry);
......@@ -338,8 +376,11 @@ void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid)
* We need to free the bit for init_vp_index() to work in the case
* of sub-channel, when we reload drivers like hv_netvsc.
*/
cpumask_clear_cpu(channel->target_cpu,
&primary_channel->alloced_cpus_in_node);
if (channel->affinity_policy == HV_LOCALIZED)
cpumask_clear_cpu(channel->target_cpu,
&primary_channel->alloced_cpus_in_node);
vmbus_release_relid(relid);
free_channel(channel);
}
......@@ -405,10 +446,13 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel)
goto err_free_chan;
}
dev_type = hv_get_dev_type(&newchannel->offermsg.offer.if_type);
dev_type = hv_get_dev_type(newchannel);
if (dev_type == HV_NIC)
set_channel_signal_state(newchannel, HV_SIGNAL_POLICY_EXPLICIT);
init_vp_index(newchannel, dev_type);
hv_event_tasklet_disable(newchannel);
if (newchannel->target_cpu != get_cpu()) {
put_cpu();
smp_call_function_single(newchannel->target_cpu,
......@@ -418,6 +462,7 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel)
percpu_channel_enq(newchannel);
put_cpu();
}
hv_event_tasklet_enable(newchannel);
/*
* This state is used to indicate a successful open
......@@ -463,12 +508,11 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel)
return;
err_deq_chan:
vmbus_release_relid(newchannel->offermsg.child_relid);
mutex_lock(&vmbus_connection.channel_mutex);
list_del(&newchannel->listentry);
mutex_unlock(&vmbus_connection.channel_mutex);
hv_event_tasklet_disable(newchannel);
if (newchannel->target_cpu != get_cpu()) {
put_cpu();
smp_call_function_single(newchannel->target_cpu,
......@@ -477,6 +521,9 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel)
percpu_channel_deq(newchannel);
put_cpu();
}
hv_event_tasklet_enable(newchannel);
vmbus_release_relid(newchannel->offermsg.child_relid);
err_free_chan:
free_channel(newchannel);
......@@ -522,17 +569,17 @@ static void init_vp_index(struct vmbus_channel *channel, u16 dev_type)
}
/*
* We distribute primary channels evenly across all the available
* NUMA nodes and within the assigned NUMA node we will assign the
* first available CPU to the primary channel.
* The sub-channels will be assigned to the CPUs available in the
* NUMA node evenly.
* Based on the channel affinity policy, we will assign the NUMA
* nodes.
*/
if (!primary) {
if ((channel->affinity_policy == HV_BALANCED) || (!primary)) {
while (true) {
next_node = next_numa_node_id++;
if (next_node == nr_node_ids)
if (next_node == nr_node_ids) {
next_node = next_numa_node_id = 0;
continue;
}
if (cpumask_empty(cpumask_of_node(next_node)))
continue;
break;
......@@ -556,15 +603,17 @@ static void init_vp_index(struct vmbus_channel *channel, u16 dev_type)
cur_cpu = -1;
/*
* Normally Hyper-V host doesn't create more subchannels than there
* are VCPUs on the node but it is possible when not all present VCPUs
* on the node are initialized by guest. Clear the alloced_cpus_in_node
* to start over.
*/
if (cpumask_equal(&primary->alloced_cpus_in_node,
cpumask_of_node(primary->numa_node)))
cpumask_clear(&primary->alloced_cpus_in_node);
if (primary->affinity_policy == HV_LOCALIZED) {
/*
* Normally Hyper-V host doesn't create more subchannels
* than there are VCPUs on the node but it is possible when not
* all present VCPUs on the node are initialized by guest.
* Clear the alloced_cpus_in_node to start over.
*/
if (cpumask_equal(&primary->alloced_cpus_in_node,
cpumask_of_node(primary->numa_node)))
cpumask_clear(&primary->alloced_cpus_in_node);
}
while (true) {
cur_cpu = cpumask_next(cur_cpu, &available_mask);
......@@ -575,17 +624,24 @@ static void init_vp_index(struct vmbus_channel *channel, u16 dev_type)
continue;
}
/*
* NOTE: in the case of sub-channel, we clear the sub-channel
* related bit(s) in primary->alloced_cpus_in_node in
* hv_process_channel_removal(), so when we reload drivers
* like hv_netvsc in SMP guest, here we're able to re-allocate
* bit from primary->alloced_cpus_in_node.
*/
if (!cpumask_test_cpu(cur_cpu,
&primary->alloced_cpus_in_node)) {
cpumask_set_cpu(cur_cpu,
&primary->alloced_cpus_in_node);
if (primary->affinity_policy == HV_LOCALIZED) {
/*
* NOTE: in the case of sub-channel, we clear the
* sub-channel related bit(s) in
* primary->alloced_cpus_in_node in
* hv_process_channel_removal(), so when we
* reload drivers like hv_netvsc in SMP guest, here
* we're able to re-allocate
* bit from primary->alloced_cpus_in_node.
*/
if (!cpumask_test_cpu(cur_cpu,
&primary->alloced_cpus_in_node)) {
cpumask_set_cpu(cur_cpu,
&primary->alloced_cpus_in_node);
cpumask_set_cpu(cur_cpu, alloced_mask);
break;
}
} else {
cpumask_set_cpu(cur_cpu, alloced_mask);
break;
}
......
......@@ -439,7 +439,7 @@ int vmbus_post_msg(void *buffer, size_t buflen)
union hv_connection_id conn_id;
int ret = 0;
int retries = 0;
u32 msec = 1;
u32 usec = 1;
conn_id.asu32 = 0;
conn_id.u.id = VMBUS_MESSAGE_CONNECTION_ID;
......@@ -472,9 +472,9 @@ int vmbus_post_msg(void *buffer, size_t buflen)
}
retries++;
msleep(msec);
if (msec < 2048)
msec *= 2;
udelay(usec);
if (usec < 2048)
usec *= 2;
}
return ret;
}
......
......@@ -278,7 +278,7 @@ int hv_init(void)
*
* This routine is called normally during driver unloading or exiting.
*/
void hv_cleanup(void)
void hv_cleanup(bool crash)
{
union hv_x64_msr_hypercall_contents hypercall_msr;
......@@ -288,7 +288,8 @@ void hv_cleanup(void)
if (hv_context.hypercall_page) {
hypercall_msr.as_uint64 = 0;
wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
vfree(hv_context.hypercall_page);
if (!crash)
vfree(hv_context.hypercall_page);
hv_context.hypercall_page = NULL;
}
......@@ -308,7 +309,8 @@ void hv_cleanup(void)
hypercall_msr.as_uint64 = 0;
wrmsrl(HV_X64_MSR_REFERENCE_TSC, hypercall_msr.as_uint64);
vfree(hv_context.tsc_page);
if (!crash)
vfree(hv_context.tsc_page);
hv_context.tsc_page = NULL;
}
#endif
......
This diff is collapsed.
......@@ -83,6 +83,12 @@ static void fcopy_timeout_func(struct work_struct *dummy)
hv_poll_channel(fcopy_transaction.recv_channel, fcopy_poll_wrapper);
}
static void fcopy_register_done(void)
{
pr_debug("FCP: userspace daemon registered\n");
hv_poll_channel(fcopy_transaction.recv_channel, fcopy_poll_wrapper);
}
static int fcopy_handle_handshake(u32 version)
{
u32 our_ver = FCOPY_CURRENT_VERSION;
......@@ -94,7 +100,8 @@ static int fcopy_handle_handshake(u32 version)
break;
case FCOPY_VERSION_1:
/* Daemon expects us to reply with our own version */
if (hvutil_transport_send(hvt, &our_ver, sizeof(our_ver)))
if (hvutil_transport_send(hvt, &our_ver, sizeof(our_ver),
fcopy_register_done))
return -EFAULT;
dm_reg_value = version;
break;
......@@ -107,8 +114,7 @@ static int fcopy_handle_handshake(u32 version)
*/
return -EINVAL;
}
pr_debug("FCP: userspace daemon ver. %d registered\n", version);
hv_poll_channel(fcopy_transaction.recv_channel, fcopy_poll_wrapper);
pr_debug("FCP: userspace daemon ver. %d connected\n", version);
return 0;
}
......@@ -161,7 +167,7 @@ static void fcopy_send_data(struct work_struct *dummy)
}
fcopy_transaction.state = HVUTIL_USERSPACE_REQ;
rc = hvutil_transport_send(hvt, out_src, out_len);
rc = hvutil_transport_send(hvt, out_src, out_len, NULL);
if (rc) {
pr_debug("FCP: failed to communicate to the daemon: %d\n", rc);
if (cancel_delayed_work_sync(&fcopy_timeout_work)) {
......
......@@ -102,6 +102,17 @@ static void kvp_poll_wrapper(void *channel)
hv_kvp_onchannelcallback(channel);
}
static void kvp_register_done(void)
{
/*
* If we're still negotiating with the host cancel the timeout
* work to not poll the channel twice.
*/
pr_debug("KVP: userspace daemon registered\n");
cancel_delayed_work_sync(&kvp_host_handshake_work);
hv_poll_channel(kvp_transaction.recv_channel, kvp_poll_wrapper);
}
static void
kvp_register(int reg_value)
{
......@@ -116,7 +127,8 @@ kvp_register(int reg_value)
kvp_msg->kvp_hdr.operation = reg_value;
strcpy(version, HV_DRV_VERSION);
hvutil_transport_send(hvt, kvp_msg, sizeof(*kvp_msg));
hvutil_transport_send(hvt, kvp_msg, sizeof(*kvp_msg),
kvp_register_done);
kfree(kvp_msg);
}
}
......@@ -158,17 +170,10 @@ static int kvp_handle_handshake(struct hv_kvp_msg *msg)
/*
* We have a compatible daemon; complete the handshake.
*/
pr_debug("KVP: userspace daemon ver. %d registered\n",
KVP_OP_REGISTER);
pr_debug("KVP: userspace daemon ver. %d connected\n",
msg->kvp_hdr.operation);
kvp_register(dm_reg_value);
/*
* If we're still negotiating with the host cancel the timeout
* work to not poll the channel twice.
*/
cancel_delayed_work_sync(&kvp_host_handshake_work);
hv_poll_channel(kvp_transaction.recv_channel, kvp_poll_wrapper);
return 0;
}
......@@ -455,7 +460,7 @@ kvp_send_key(struct work_struct *dummy)
}
kvp_transaction.state = HVUTIL_USERSPACE_REQ;
rc = hvutil_transport_send(hvt, message, sizeof(*message));
rc = hvutil_transport_send(hvt, message, sizeof(*message), NULL);
if (rc) {
pr_debug("KVP: failed to communicate to the daemon: %d\n", rc);
if (cancel_delayed_work_sync(&kvp_timeout_work)) {
......
......@@ -67,11 +67,11 @@ static const char vss_devname[] = "vmbus/hv_vss";
static __u8 *recv_buffer;
static struct hvutil_transport *hvt;
static void vss_send_op(struct work_struct *dummy);
static void vss_timeout_func(struct work_struct *dummy);
static void vss_handle_request(struct work_struct *dummy);
static DECLARE_DELAYED_WORK(vss_timeout_work, vss_timeout_func);
static DECLARE_WORK(vss_send_op_work, vss_send_op);
static DECLARE_WORK(vss_handle_request_work, vss_handle_request);
static void vss_poll_wrapper(void *channel)
{
......@@ -95,6 +95,12 @@ static void vss_timeout_func(struct work_struct *dummy)
hv_poll_channel(vss_transaction.recv_channel, vss_poll_wrapper);
}
static void vss_register_done(void)
{
hv_poll_channel(vss_transaction.recv_channel, vss_poll_wrapper);
pr_debug("VSS: userspace daemon registered\n");
}
static int vss_handle_handshake(struct hv_vss_msg *vss_msg)
{
u32 our_ver = VSS_OP_REGISTER1;
......@@ -105,16 +111,16 @@ static int vss_handle_handshake(struct hv_vss_msg *vss_msg)
dm_reg_value = VSS_OP_REGISTER;
break;
case VSS_OP_REGISTER1:
/* Daemon expects us to reply with our own version*/
if (hvutil_transport_send(hvt, &our_ver, sizeof(our_ver)))
/* Daemon expects us to reply with our own version */
if (hvutil_transport_send(hvt, &our_ver, sizeof(our_ver),
vss_register_done))
return -EFAULT;
dm_reg_value = VSS_OP_REGISTER1;
break;
default:
return -EINVAL;
}
hv_poll_channel(vss_transaction.recv_channel, vss_poll_wrapper);
pr_debug("VSS: userspace daemon ver. %d registered\n", dm_reg_value);
pr_debug("VSS: userspace daemon ver. %d connected\n", dm_reg_value);
return 0;
}
......@@ -136,6 +142,11 @@ static int vss_on_msg(void *msg, int len)
return vss_handle_handshake(vss_msg);
} else if (vss_transaction.state == HVUTIL_USERSPACE_REQ) {
vss_transaction.state = HVUTIL_USERSPACE_RECV;
if (vss_msg->vss_hdr.operation == VSS_OP_HOT_BACKUP)
vss_transaction.msg->vss_cf.flags =
VSS_HBU_NO_AUTO_RECOVERY;
if (cancel_delayed_work_sync(&vss_timeout_work)) {
vss_respond_to_host(vss_msg->error);
/* Transaction is finished, reset the state. */
......@@ -150,8 +161,7 @@ static int vss_on_msg(void *msg, int len)
return 0;
}
static void vss_send_op(struct work_struct *dummy)
static void vss_send_op(void)
{
int op = vss_transaction.msg->vss_hdr.operation;
int rc;
......@@ -168,7 +178,10 @@ static void vss_send_op(struct work_struct *dummy)
vss_msg->vss_hdr.operation = op;
vss_transaction.state = HVUTIL_USERSPACE_REQ;
rc = hvutil_transport_send(hvt, vss_msg, sizeof(*vss_msg));
schedule_delayed_work(&vss_timeout_work, VSS_USERSPACE_TIMEOUT);
rc = hvutil_transport_send(hvt, vss_msg, sizeof(*vss_msg), NULL);
if (rc) {
pr_warn("VSS: failed to communicate to the daemon: %d\n", rc);
if (cancel_delayed_work_sync(&vss_timeout_work)) {
......@@ -182,6 +195,38 @@ static void vss_send_op(struct work_struct *dummy)
return;
}
static void vss_handle_request(struct work_struct *dummy)
{
switch (vss_transaction.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_THAW:
case VSS_OP_FREEZE:
case VSS_OP_HOT_BACKUP:
if (vss_transaction.state < HVUTIL_READY) {
/* Userspace is not registered yet */
vss_respond_to_host(HV_E_FAIL);
return;
}
vss_transaction.state = HVUTIL_HOSTMSG_RECEIVED;
vss_send_op();
return;
case VSS_OP_GET_DM_INFO:
vss_transaction.msg->dm_info.flags = 0;
break;
default:
break;
}
vss_respond_to_host(0);
hv_poll_channel(vss_transaction.recv_channel, vss_poll_wrapper);
}
/*
* Send a response back to the host.
*/
......@@ -266,48 +311,8 @@ void hv_vss_onchannelcallback(void *context)
vss_transaction.recv_req_id = requestid;
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:
if (vss_transaction.state < HVUTIL_READY) {
/* Userspace is not registered yet */
vss_respond_to_host(HV_E_FAIL);
return;
}
vss_transaction.state = HVUTIL_HOSTMSG_RECEIVED;
schedule_work(&vss_send_op_work);
schedule_delayed_work(&vss_timeout_work,
VSS_USERSPACE_TIMEOUT);
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;
}
schedule_work(&vss_handle_request_work);
return;
}
icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
......@@ -358,6 +363,6 @@ void hv_vss_deinit(void)
{
vss_transaction.state = HVUTIL_DEVICE_DYING;
cancel_delayed_work_sync(&vss_timeout_work);
cancel_work_sync(&vss_send_op_work);
cancel_work_sync(&vss_handle_request_work);
hvutil_transport_destroy(hvt);
}
......@@ -34,22 +34,25 @@
#define SD_MINOR 0
#define SD_VERSION (SD_MAJOR << 16 | SD_MINOR)
#define SD_WS2008_MAJOR 1
#define SD_WS2008_VERSION (SD_WS2008_MAJOR << 16 | SD_MINOR)
#define SD_MAJOR_1 1
#define SD_VERSION_1 (SD_MAJOR_1 << 16 | SD_MINOR)
#define TS_MAJOR 3
#define TS_MAJOR 4
#define TS_MINOR 0
#define TS_VERSION (TS_MAJOR << 16 | TS_MINOR)
#define TS_WS2008_MAJOR 1
#define TS_WS2008_VERSION (TS_WS2008_MAJOR << 16 | TS_MINOR)
#define TS_MAJOR_1 1
#define TS_VERSION_1 (TS_MAJOR_1 << 16 | TS_MINOR)
#define TS_MAJOR_3 3
#define TS_VERSION_3 (TS_MAJOR_3 << 16 | TS_MINOR)
#define HB_MAJOR 3
#define HB_MINOR 0
#define HB_MINOR 0
#define HB_VERSION (HB_MAJOR << 16 | HB_MINOR)
#define HB_WS2008_MAJOR 1
#define HB_WS2008_VERSION (HB_WS2008_MAJOR << 16 | HB_MINOR)
#define HB_MAJOR_1 1
#define HB_VERSION_1 (HB_MAJOR_1 << 16 | HB_MINOR)
static int sd_srv_version;
static int ts_srv_version;
......@@ -61,9 +64,14 @@ static struct hv_util_service util_shutdown = {
.util_cb = shutdown_onchannelcallback,
};
static int hv_timesync_init(struct hv_util_service *srv);
static void hv_timesync_deinit(void);
static void timesync_onchannelcallback(void *context);
static struct hv_util_service util_timesynch = {
.util_cb = timesync_onchannelcallback,
.util_init = hv_timesync_init,
.util_deinit = hv_timesync_deinit,
};
static void heartbeat_onchannelcallback(void *context);
......@@ -160,20 +168,6 @@ static void shutdown_onchannelcallback(void *context)
schedule_work(&shutdown_work);
}
/*
* Set guest time to host UTC time.
*/
static inline void do_adj_guesttime(u64 hosttime)
{
s64 host_tns;
struct timespec host_ts;
host_tns = (hosttime - WLTIMEDELTA) * 100;
host_ts = ns_to_timespec(host_tns);
do_settimeofday(&host_ts);
}
/*
* Set the host time in a process context.
*/
......@@ -181,15 +175,37 @@ static inline void do_adj_guesttime(u64 hosttime)
struct adj_time_work {
struct work_struct work;
u64 host_time;
u64 ref_time;
u8 flags;
};
static void hv_set_host_time(struct work_struct *work)
{
struct adj_time_work *wrk;
s64 host_tns;
u64 newtime;
struct timespec host_ts;
wrk = container_of(work, struct adj_time_work, work);
do_adj_guesttime(wrk->host_time);
kfree(wrk);
newtime = wrk->host_time;
if (ts_srv_version > TS_VERSION_3) {
/*
* Some latency has been introduced since Hyper-V generated
* its time sample. Take that latency into account before
* using TSC reference time sample from Hyper-V.
*
* This sample is given by TimeSync v4 and above hosts.
*/
u64 current_tick;
rdmsrl(HV_X64_MSR_TIME_REF_COUNT, current_tick);
newtime += (current_tick - wrk->ref_time);
}
host_tns = (newtime - WLTIMEDELTA) * 100;
host_ts = ns_to_timespec(host_tns);
do_settimeofday(&host_ts);
}
/*
......@@ -198,33 +214,31 @@ static void hv_set_host_time(struct work_struct *work)
* ICTIMESYNCFLAG_SYNC flag bit indicates reboot, restore events of the VM.
* After reboot the flag ICTIMESYNCFLAG_SYNC is included in the first time
* message after the timesync channel is opened. Since the hv_utils module is
* loaded after hv_vmbus, the first message is usually missed. The other
* thing is, systime is automatically set to emulated hardware clock which may
* not be UTC time or in the same time zone. So, to override these effects, we
* use the first 50 time samples for initial system time setting.
* loaded after hv_vmbus, the first message is usually missed. This bit is
* considered a hard request to discipline the clock.
*
* ICTIMESYNCFLAG_SAMPLE bit indicates a time sample from host. This is
* typically used as a hint to the guest. The guest is under no obligation
* to discipline the clock.
*/
static inline void adj_guesttime(u64 hosttime, u8 flags)
static struct adj_time_work wrk;
static inline void adj_guesttime(u64 hosttime, u64 reftime, u8 flags)
{
struct adj_time_work *wrk;
static s32 scnt = 50;
wrk = kmalloc(sizeof(struct adj_time_work), GFP_ATOMIC);
if (wrk == NULL)
/*
* This check is safe since we are executing in the
* interrupt context and time synch messages arre always
* delivered on the same CPU.
*/
if (work_pending(&wrk.work))
return;
wrk->host_time = hosttime;
if ((flags & ICTIMESYNCFLAG_SYNC) != 0) {
INIT_WORK(&wrk->work, hv_set_host_time);
schedule_work(&wrk->work);
return;
wrk.host_time = hosttime;
wrk.ref_time = reftime;
wrk.flags = flags;
if ((flags & (ICTIMESYNCFLAG_SYNC | ICTIMESYNCFLAG_SAMPLE)) != 0) {
schedule_work(&wrk.work);
}
if ((flags & ICTIMESYNCFLAG_SAMPLE) != 0 && scnt > 0) {
scnt--;
INIT_WORK(&wrk->work, hv_set_host_time);
schedule_work(&wrk->work);
} else
kfree(wrk);
}
/*
......@@ -237,6 +251,7 @@ static void timesync_onchannelcallback(void *context)
u64 requestid;
struct icmsg_hdr *icmsghdrp;
struct ictimesync_data *timedatap;
struct ictimesync_ref_data *refdata;
u8 *time_txf_buf = util_timesynch.recv_buffer;
struct icmsg_negotiate *negop = NULL;
......@@ -252,11 +267,27 @@ static void timesync_onchannelcallback(void *context)
time_txf_buf,
util_fw_version,
ts_srv_version);
pr_info("Using TimeSync version %d.%d\n",
ts_srv_version >> 16, ts_srv_version & 0xFFFF);
} else {
timedatap = (struct ictimesync_data *)&time_txf_buf[
sizeof(struct vmbuspipe_hdr) +
sizeof(struct icmsg_hdr)];
adj_guesttime(timedatap->parenttime, timedatap->flags);
if (ts_srv_version > TS_VERSION_3) {
refdata = (struct ictimesync_ref_data *)
&time_txf_buf[
sizeof(struct vmbuspipe_hdr) +
sizeof(struct icmsg_hdr)];
adj_guesttime(refdata->parenttime,
refdata->vmreferencetime,
refdata->flags);
} else {
timedatap = (struct ictimesync_data *)
&time_txf_buf[
sizeof(struct vmbuspipe_hdr) +
sizeof(struct icmsg_hdr)];
adj_guesttime(timedatap->parenttime,
0,
timedatap->flags);
}
}
icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
......@@ -350,16 +381,21 @@ static int util_probe(struct hv_device *dev,
switch (vmbus_proto_version) {
case (VERSION_WS2008):
util_fw_version = UTIL_WS2K8_FW_VERSION;
sd_srv_version = SD_WS2008_VERSION;
ts_srv_version = TS_WS2008_VERSION;
hb_srv_version = HB_WS2008_VERSION;
sd_srv_version = SD_VERSION_1;
ts_srv_version = TS_VERSION_1;
hb_srv_version = HB_VERSION_1;
break;
default:
case(VERSION_WIN10):
util_fw_version = UTIL_FW_VERSION;
sd_srv_version = SD_VERSION;
ts_srv_version = TS_VERSION;
hb_srv_version = HB_VERSION;
break;
default:
util_fw_version = UTIL_FW_VERSION;
sd_srv_version = SD_VERSION;
ts_srv_version = TS_VERSION_3;
hb_srv_version = HB_VERSION;
}
ret = vmbus_open(dev->channel, 4 * PAGE_SIZE, 4 * PAGE_SIZE, NULL, 0,
......@@ -427,6 +463,17 @@ static struct hv_driver util_drv = {
.remove = util_remove,
};
static int hv_timesync_init(struct hv_util_service *srv)
{
INIT_WORK(&wrk.work, hv_set_host_time);
return 0;
}
static void hv_timesync_deinit(void)
{
cancel_work_sync(&wrk.work);
}
static int __init init_hyperv_utils(void)
{
pr_info("Registering HyperV Utility Driver\n");
......
......@@ -72,6 +72,10 @@ static ssize_t hvt_op_read(struct file *file, char __user *buf,
hvt->outmsg = NULL;
hvt->outmsg_len = 0;
if (hvt->on_read)
hvt->on_read();
hvt->on_read = NULL;
out_unlock:
mutex_unlock(&hvt->lock);
return ret;
......@@ -219,7 +223,8 @@ static void hvt_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp)
mutex_unlock(&hvt->lock);
}
int hvutil_transport_send(struct hvutil_transport *hvt, void *msg, int len)
int hvutil_transport_send(struct hvutil_transport *hvt, void *msg, int len,
void (*on_read_cb)(void))
{
struct cn_msg *cn_msg;
int ret = 0;
......@@ -237,6 +242,13 @@ int hvutil_transport_send(struct hvutil_transport *hvt, void *msg, int len)
memcpy(cn_msg->data, msg, len);
ret = cn_netlink_send(cn_msg, 0, 0, GFP_ATOMIC);
kfree(cn_msg);
/*
* We don't know when netlink messages are delivered but unlike
* in CHARDEV mode we're not blocked and we can send next
* messages right away.
*/
if (on_read_cb)
on_read_cb();
return ret;
}
/* HVUTIL_TRANSPORT_CHARDEV */
......@@ -255,6 +267,7 @@ int hvutil_transport_send(struct hvutil_transport *hvt, void *msg, int len)
if (hvt->outmsg) {
memcpy(hvt->outmsg, msg, len);
hvt->outmsg_len = len;
hvt->on_read = on_read_cb;
wake_up_interruptible(&hvt->outmsg_q);
} else
ret = -ENOMEM;
......
......@@ -36,6 +36,7 @@ struct hvutil_transport {
struct list_head list; /* hvt_list */
int (*on_msg)(void *, int); /* callback on new user message */
void (*on_reset)(void); /* callback when userspace drops */
void (*on_read)(void); /* callback on message read */
u8 *outmsg; /* message to the userspace */
int outmsg_len; /* its length */
wait_queue_head_t outmsg_q; /* poll/read wait queue */
......@@ -46,7 +47,8 @@ struct hvutil_transport *hvutil_transport_init(const char *name,
u32 cn_idx, u32 cn_val,
int (*on_msg)(void *, int),
void (*on_reset)(void));
int hvutil_transport_send(struct hvutil_transport *hvt, void *msg, int len);
int hvutil_transport_send(struct hvutil_transport *hvt, void *msg, int len,
void (*on_read_cb)(void));
void hvutil_transport_destroy(struct hvutil_transport *hvt);
#endif /* _HV_UTILS_TRANSPORT_H */
......@@ -495,7 +495,7 @@ struct hv_ring_buffer_debug_info {
extern int hv_init(void);
extern void hv_cleanup(void);
extern void hv_cleanup(bool crash);
extern int hv_post_message(union hv_connection_id connection_id,
enum hv_message_type message_type,
......@@ -522,14 +522,15 @@ extern unsigned int host_info_edx;
/* Interface */
int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info, void *buffer,
u32 buflen);
int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info,
struct page *pages, u32 pagecnt);
void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info);
int hv_ringbuffer_write(struct hv_ring_buffer_info *ring_info,
struct kvec *kv_list,
u32 kv_count, bool *signal, bool lock);
u32 kv_count, bool *signal, bool lock,
enum hv_signal_policy policy);
int hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info,
void *buffer, u32 buflen, u32 *buffer_actual_len,
......
......@@ -27,6 +27,8 @@
#include <linux/mm.h>
#include <linux/hyperv.h>
#include <linux/uio.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>
#include "hyperv_vmbus.h"
......@@ -66,12 +68,20 @@ u32 hv_end_read(struct hv_ring_buffer_info *rbi)
* arrived.
*/
static bool hv_need_to_signal(u32 old_write, struct hv_ring_buffer_info *rbi)
static bool hv_need_to_signal(u32 old_write, struct hv_ring_buffer_info *rbi,
enum hv_signal_policy policy)
{
virt_mb();
if (READ_ONCE(rbi->ring_buffer->interrupt_mask))
return false;
/*
* When the client wants to control signaling,
* we only honour the host interrupt mask.
*/
if (policy == HV_SIGNAL_POLICY_EXPLICIT)
return true;
/* check interrupt_mask before read_index */
virt_rmb();
/*
......@@ -162,18 +172,7 @@ static u32 hv_copyfrom_ringbuffer(
void *ring_buffer = hv_get_ring_buffer(ring_info);
u32 ring_buffer_size = hv_get_ring_buffersize(ring_info);
u32 frag_len;
/* wrap-around detected at the src */
if (destlen > ring_buffer_size - start_read_offset) {
frag_len = ring_buffer_size - start_read_offset;
memcpy(dest, ring_buffer + start_read_offset, frag_len);
memcpy(dest + frag_len, ring_buffer, destlen - frag_len);
} else
memcpy(dest, ring_buffer + start_read_offset, destlen);
memcpy(dest, ring_buffer + start_read_offset, destlen);
start_read_offset += destlen;
start_read_offset %= ring_buffer_size;
......@@ -194,15 +193,8 @@ static u32 hv_copyto_ringbuffer(
{
void *ring_buffer = hv_get_ring_buffer(ring_info);
u32 ring_buffer_size = hv_get_ring_buffersize(ring_info);
u32 frag_len;
/* wrap-around detected! */
if (srclen > ring_buffer_size - start_write_offset) {
frag_len = ring_buffer_size - start_write_offset;
memcpy(ring_buffer + start_write_offset, src, frag_len);
memcpy(ring_buffer, src + frag_len, srclen - frag_len);
} else
memcpy(ring_buffer + start_write_offset, src, srclen);
memcpy(ring_buffer + start_write_offset, src, srclen);
start_write_offset += srclen;
start_write_offset %= ring_buffer_size;
......@@ -235,22 +227,46 @@ void hv_ringbuffer_get_debuginfo(struct hv_ring_buffer_info *ring_info,
/* Initialize the ring buffer. */
int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info,
void *buffer, u32 buflen)
struct page *pages, u32 page_cnt)
{
if (sizeof(struct hv_ring_buffer) != PAGE_SIZE)
return -EINVAL;
int i;
struct page **pages_wraparound;
BUILD_BUG_ON((sizeof(struct hv_ring_buffer) != PAGE_SIZE));
memset(ring_info, 0, sizeof(struct hv_ring_buffer_info));
ring_info->ring_buffer = (struct hv_ring_buffer *)buffer;
/*
* First page holds struct hv_ring_buffer, do wraparound mapping for
* the rest.
*/
pages_wraparound = kzalloc(sizeof(struct page *) * (page_cnt * 2 - 1),
GFP_KERNEL);
if (!pages_wraparound)
return -ENOMEM;
pages_wraparound[0] = pages;
for (i = 0; i < 2 * (page_cnt - 1); i++)
pages_wraparound[i + 1] = &pages[i % (page_cnt - 1) + 1];
ring_info->ring_buffer = (struct hv_ring_buffer *)
vmap(pages_wraparound, page_cnt * 2 - 1, VM_MAP, PAGE_KERNEL);
kfree(pages_wraparound);
if (!ring_info->ring_buffer)
return -ENOMEM;
ring_info->ring_buffer->read_index =
ring_info->ring_buffer->write_index = 0;
/* Set the feature bit for enabling flow control. */
ring_info->ring_buffer->feature_bits.value = 1;
ring_info->ring_size = buflen;
ring_info->ring_datasize = buflen - sizeof(struct hv_ring_buffer);
ring_info->ring_size = page_cnt << PAGE_SHIFT;
ring_info->ring_datasize = ring_info->ring_size -
sizeof(struct hv_ring_buffer);
spin_lock_init(&ring_info->ring_lock);
......@@ -260,11 +276,13 @@ int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info,
/* Cleanup the ring buffer. */
void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info)
{
vunmap(ring_info->ring_buffer);
}
/* Write to the ring buffer. */
int hv_ringbuffer_write(struct hv_ring_buffer_info *outring_info,
struct kvec *kv_list, u32 kv_count, bool *signal, bool lock)
struct kvec *kv_list, u32 kv_count, bool *signal, bool lock,
enum hv_signal_policy policy)
{
int i = 0;
u32 bytes_avail_towrite;
......@@ -326,7 +344,7 @@ int hv_ringbuffer_write(struct hv_ring_buffer_info *outring_info,
if (lock)
spin_unlock_irqrestore(&outring_info->ring_lock, flags);
*signal = hv_need_to_signal(old_write, outring_info);
*signal = hv_need_to_signal(old_write, outring_info, policy);
return 0;
}
......
......@@ -105,8 +105,8 @@ static struct notifier_block hyperv_panic_block = {
static const char *fb_mmio_name = "fb_range";
static struct resource *fb_mmio;
struct resource *hyperv_mmio;
DEFINE_SEMAPHORE(hyperv_mmio_lock);
static struct resource *hyperv_mmio;
static DEFINE_SEMAPHORE(hyperv_mmio_lock);
static int vmbus_exists(void)
{
......@@ -874,7 +874,7 @@ static int vmbus_bus_init(void)
bus_unregister(&hv_bus);
err_cleanup:
hv_cleanup();
hv_cleanup(false);
return ret;
}
......@@ -961,8 +961,8 @@ int vmbus_device_register(struct hv_device *child_device_obj)
{
int ret = 0;
dev_set_name(&child_device_obj->device, "vmbus_%d",
child_device_obj->channel->id);
dev_set_name(&child_device_obj->device, "vmbus-%pUl",
child_device_obj->channel->offermsg.offer.if_instance.b);
child_device_obj->device.bus = &hv_bus;
child_device_obj->device.parent = &hv_acpi_dev->dev;
......@@ -1326,7 +1326,7 @@ static void hv_kexec_handler(void)
vmbus_initiate_unload(false);
for_each_online_cpu(cpu)
smp_call_function_single(cpu, hv_synic_cleanup, NULL, 1);
hv_cleanup();
hv_cleanup(false);
};
static void hv_crash_handler(struct pt_regs *regs)
......@@ -1338,7 +1338,7 @@ static void hv_crash_handler(struct pt_regs *regs)
* for kdump.
*/
hv_synic_cleanup(NULL);
hv_cleanup();
hv_cleanup(true);
};
static int __init hv_acpi_init(void)
......@@ -1398,7 +1398,7 @@ static void __exit vmbus_exit(void)
&hyperv_panic_block);
}
bus_unregister(&hv_bus);
hv_cleanup();
hv_cleanup(false);
for_each_online_cpu(cpu) {
tasklet_kill(hv_context.event_dpc[cpu]);
smp_call_function_single(cpu, hv_synic_cleanup, NULL, 1);
......
......@@ -184,8 +184,7 @@ static void etb_disable_hw(struct etb_drvdata *drvdata)
if (coresight_timeout(drvdata->base, ETB_FFCR, ETB_FFCR_BIT, 0)) {
dev_err(drvdata->dev,
"timeout observed when probing at offset %#x\n",
ETB_FFCR);
"timeout while waiting for completion of Manual Flush\n");
}
/* disable trace capture */
......@@ -193,8 +192,7 @@ static void etb_disable_hw(struct etb_drvdata *drvdata)
if (coresight_timeout(drvdata->base, ETB_FFSR, ETB_FFSR_BIT, 1)) {
dev_err(drvdata->dev,
"timeout observed when probing at offset %#x\n",
ETB_FFCR);
"timeout while waiting for Formatter to Stop\n");
}
CS_LOCK(drvdata->base);
......@@ -561,7 +559,7 @@ static const struct file_operations etb_fops = {
};
#define coresight_etb10_simple_func(name, offset) \
coresight_simple_func(struct etb_drvdata, name, offset)
coresight_simple_func(struct etb_drvdata, NULL, name, offset)
coresight_etb10_simple_func(rdp, ETB_RAM_DEPTH_REG);
coresight_etb10_simple_func(sts, ETB_STATUS_REG);
......@@ -638,7 +636,7 @@ static int etb_probe(struct amba_device *adev, const struct amba_id *id)
struct coresight_platform_data *pdata = NULL;
struct etb_drvdata *drvdata;
struct resource *res = &adev->res;
struct coresight_desc *desc;
struct coresight_desc desc = { 0 };
struct device_node *np = adev->dev.of_node;
if (np) {
......@@ -684,17 +682,13 @@ static int etb_probe(struct amba_device *adev, const struct amba_id *id)
return -ENOMEM;
}
desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
if (!desc)
return -ENOMEM;
desc->type = CORESIGHT_DEV_TYPE_SINK;
desc->subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER;
desc->ops = &etb_cs_ops;
desc->pdata = pdata;
desc->dev = dev;
desc->groups = coresight_etb_groups;
drvdata->csdev = coresight_register(desc);
desc.type = CORESIGHT_DEV_TYPE_SINK;
desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER;
desc.ops = &etb_cs_ops;
desc.pdata = pdata;
desc.dev = dev;
desc.groups = coresight_etb_groups;
drvdata->csdev = coresight_register(&desc);
if (IS_ERR(drvdata->csdev))
return PTR_ERR(drvdata->csdev);
......
......@@ -27,6 +27,7 @@
#include <linux/types.h>
#include <linux/workqueue.h>
#include "coresight-etm-perf.h"
#include "coresight-priv.h"
static struct pmu etm_pmu;
......@@ -71,14 +72,48 @@ static const struct attribute_group *etm_pmu_attr_groups[] = {
static void etm_event_read(struct perf_event *event) {}
static int etm_event_init(struct perf_event *event)
static int etm_addr_filters_alloc(struct perf_event *event)
{
if (event->attr.type != etm_pmu.type)
return -ENOENT;
struct etm_filters *filters;
int node = event->cpu == -1 ? -1 : cpu_to_node(event->cpu);
filters = kzalloc_node(sizeof(struct etm_filters), GFP_KERNEL, node);
if (!filters)
return -ENOMEM;
if (event->parent)
memcpy(filters, event->parent->hw.addr_filters,
sizeof(*filters));
event->hw.addr_filters = filters;
return 0;
}
static void etm_event_destroy(struct perf_event *event)
{
kfree(event->hw.addr_filters);
event->hw.addr_filters = NULL;
}
static int etm_event_init(struct perf_event *event)
{
int ret = 0;
if (event->attr.type != etm_pmu.type) {
ret = -ENOENT;
goto out;
}
ret = etm_addr_filters_alloc(event);
if (ret)
goto out;
event->destroy = etm_event_destroy;
out:
return ret;
}
static void free_event_data(struct work_struct *work)
{
int cpu;
......@@ -100,7 +135,7 @@ static void free_event_data(struct work_struct *work)
}
for_each_cpu(cpu, mask) {
if (event_data->path[cpu])
if (!(IS_ERR_OR_NULL(event_data->path[cpu])))
coresight_release_path(event_data->path[cpu]);
}
......@@ -185,7 +220,7 @@ static void *etm_setup_aux(int event_cpu, void **pages,
* referenced later when the path is actually needed.
*/
event_data->path[cpu] = coresight_build_path(csdev);
if (!event_data->path[cpu])
if (IS_ERR(event_data->path[cpu]))
goto err;
}
......@@ -258,7 +293,7 @@ static void etm_event_start(struct perf_event *event, int flags)
event->hw.state = 0;
/* Finally enable the tracer */
if (source_ops(csdev)->enable(csdev, &event->attr, CS_MODE_PERF))
if (source_ops(csdev)->enable(csdev, event, CS_MODE_PERF))
goto fail_end_stop;
out:
......@@ -291,7 +326,7 @@ static void etm_event_stop(struct perf_event *event, int mode)
return;
/* stop tracer */
source_ops(csdev)->disable(csdev);
source_ops(csdev)->disable(csdev, event);
/* tell the core */
event->hw.state = PERF_HES_STOPPED;
......@@ -342,6 +377,87 @@ static void etm_event_del(struct perf_event *event, int mode)
etm_event_stop(event, PERF_EF_UPDATE);
}
static int etm_addr_filters_validate(struct list_head *filters)
{
bool range = false, address = false;
int index = 0;
struct perf_addr_filter *filter;
list_for_each_entry(filter, filters, entry) {
/*
* No need to go further if there's no more
* room for filters.
*/
if (++index > ETM_ADDR_CMP_MAX)
return -EOPNOTSUPP;
/*
* As taken from the struct perf_addr_filter documentation:
* @range: 1: range, 0: address
*
* At this time we don't allow range and start/stop filtering
* to cohabitate, they have to be mutually exclusive.
*/
if ((filter->range == 1) && address)
return -EOPNOTSUPP;
if ((filter->range == 0) && range)
return -EOPNOTSUPP;
/*
* For range filtering, the second address in the address
* range comparator needs to be higher than the first.
* Invalid otherwise.
*/
if (filter->range && filter->size == 0)
return -EINVAL;
/*
* Everything checks out with this filter, record what we've
* received before moving on to the next one.
*/
if (filter->range)
range = true;
else
address = true;
}
return 0;
}
static void etm_addr_filters_sync(struct perf_event *event)
{
struct perf_addr_filters_head *head = perf_event_addr_filters(event);
unsigned long start, stop, *offs = event->addr_filters_offs;
struct etm_filters *filters = event->hw.addr_filters;
struct etm_filter *etm_filter;
struct perf_addr_filter *filter;
int i = 0;
list_for_each_entry(filter, &head->list, entry) {
start = filter->offset + offs[i];
stop = start + filter->size;
etm_filter = &filters->etm_filter[i];
if (filter->range == 1) {
etm_filter->start_addr = start;
etm_filter->stop_addr = stop;
etm_filter->type = ETM_ADDR_TYPE_RANGE;
} else {
if (filter->filter == 1) {
etm_filter->start_addr = start;
etm_filter->type = ETM_ADDR_TYPE_START;
} else {
etm_filter->stop_addr = stop;
etm_filter->type = ETM_ADDR_TYPE_STOP;
}
}
i++;
}
filters->nr_filters = i;
}
int etm_perf_symlink(struct coresight_device *csdev, bool link)
{
char entry[sizeof("cpu9999999")];
......@@ -371,18 +487,21 @@ static int __init etm_perf_init(void)
{
int ret;
etm_pmu.capabilities = PERF_PMU_CAP_EXCLUSIVE;
etm_pmu.attr_groups = etm_pmu_attr_groups;
etm_pmu.task_ctx_nr = perf_sw_context;
etm_pmu.read = etm_event_read;
etm_pmu.event_init = etm_event_init;
etm_pmu.setup_aux = etm_setup_aux;
etm_pmu.free_aux = etm_free_aux;
etm_pmu.start = etm_event_start;
etm_pmu.stop = etm_event_stop;
etm_pmu.add = etm_event_add;
etm_pmu.del = etm_event_del;
etm_pmu.capabilities = PERF_PMU_CAP_EXCLUSIVE;
etm_pmu.attr_groups = etm_pmu_attr_groups;
etm_pmu.task_ctx_nr = perf_sw_context;
etm_pmu.read = etm_event_read;
etm_pmu.event_init = etm_event_init;
etm_pmu.setup_aux = etm_setup_aux;
etm_pmu.free_aux = etm_free_aux;
etm_pmu.start = etm_event_start;
etm_pmu.stop = etm_event_stop;
etm_pmu.add = etm_event_add;
etm_pmu.del = etm_event_del;
etm_pmu.addr_filters_sync = etm_addr_filters_sync;
etm_pmu.addr_filters_validate = etm_addr_filters_validate;
etm_pmu.nr_addr_filters = ETM_ADDR_CMP_MAX;
ret = perf_pmu_register(&etm_pmu, CORESIGHT_ETM_PMU_NAME, -1);
if (ret == 0)
......
......@@ -18,8 +18,42 @@
#ifndef _CORESIGHT_ETM_PERF_H
#define _CORESIGHT_ETM_PERF_H
#include "coresight-priv.h"
struct coresight_device;
/*
* In both ETMv3 and v4 the maximum number of address comparator implentable
* is 8. The actual number is implementation specific and will be checked
* when filters are applied.
*/
#define ETM_ADDR_CMP_MAX 8
/**
* struct etm_filter - single instruction range or start/stop configuration.
* @start_addr: The address to start tracing on.
* @stop_addr: The address to stop tracing on.
* @type: Is this a range or start/stop filter.
*/
struct etm_filter {
unsigned long start_addr;
unsigned long stop_addr;
enum etm_addr_type type;
};
/**
* struct etm_filters - set of filters for a session
* @etm_filter: All the filters for this session.
* @nr_filters: Number of filters
* @ssstatus: Status of the start/stop logic.
*/
struct etm_filters {
struct etm_filter etm_filter[ETM_ADDR_CMP_MAX];
unsigned int nr_filters;
bool ssstatus;
};
#ifdef CONFIG_CORESIGHT
int etm_perf_symlink(struct coresight_device *csdev, bool link);
......
......@@ -259,14 +259,6 @@ struct etm_drvdata {
struct etm_config config;
};
enum etm_addr_type {
ETM_ADDR_TYPE_NONE,
ETM_ADDR_TYPE_SINGLE,
ETM_ADDR_TYPE_RANGE,
ETM_ADDR_TYPE_START,
ETM_ADDR_TYPE_STOP,
};
static inline void etm_writel(struct etm_drvdata *drvdata,
u32 val, u32 off)
{
......
......@@ -18,6 +18,7 @@
#include <linux/pm_runtime.h>
#include <linux/sysfs.h>
#include "coresight-etm.h"
#include "coresight-priv.h"
static ssize_t nr_addr_cmp_show(struct device *dev,
struct device_attribute *attr, char *buf)
......@@ -1222,7 +1223,7 @@ static struct attribute *coresight_etm_attrs[] = {
};
#define coresight_etm3x_simple_func(name, offset) \
coresight_simple_func(struct etm_drvdata, name, offset)
coresight_simple_func(struct etm_drvdata, NULL, name, offset)
coresight_etm3x_simple_func(etmccr, ETMCCR);
coresight_etm3x_simple_func(etmccer, ETMCCER);
......
......@@ -311,9 +311,10 @@ void etm_config_trace_mode(struct etm_config *config)
#define ETM3X_SUPPORTED_OPTIONS (ETMCR_CYC_ACC | ETMCR_TIMESTAMP_EN)
static int etm_parse_event_config(struct etm_drvdata *drvdata,
struct perf_event_attr *attr)
struct perf_event *event)
{
struct etm_config *config = &drvdata->config;
struct perf_event_attr *attr = &event->attr;
if (!attr)
return -EINVAL;
......@@ -459,7 +460,7 @@ static int etm_trace_id(struct coresight_device *csdev)
}
static int etm_enable_perf(struct coresight_device *csdev,
struct perf_event_attr *attr)
struct perf_event *event)
{
struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
......@@ -467,7 +468,7 @@ static int etm_enable_perf(struct coresight_device *csdev,
return -EINVAL;
/* Configure the tracer based on the session's specifics */
etm_parse_event_config(drvdata, attr);
etm_parse_event_config(drvdata, event);
/* And enable it */
etm_enable_hw(drvdata);
......@@ -504,7 +505,7 @@ static int etm_enable_sysfs(struct coresight_device *csdev)
}
static int etm_enable(struct coresight_device *csdev,
struct perf_event_attr *attr, u32 mode)
struct perf_event *event, u32 mode)
{
int ret;
u32 val;
......@@ -521,7 +522,7 @@ static int etm_enable(struct coresight_device *csdev,
ret = etm_enable_sysfs(csdev);
break;
case CS_MODE_PERF:
ret = etm_enable_perf(csdev, attr);
ret = etm_enable_perf(csdev, event);
break;
default:
ret = -EINVAL;
......@@ -601,7 +602,8 @@ static void etm_disable_sysfs(struct coresight_device *csdev)
dev_info(drvdata->dev, "ETM tracing disabled\n");
}
static void etm_disable(struct coresight_device *csdev)
static void etm_disable(struct coresight_device *csdev,
struct perf_event *event)
{
u32 mode;
struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
......@@ -756,13 +758,9 @@ static int etm_probe(struct amba_device *adev, const struct amba_id *id)
struct coresight_platform_data *pdata = NULL;
struct etm_drvdata *drvdata;
struct resource *res = &adev->res;
struct coresight_desc *desc;
struct coresight_desc desc = { 0 };
struct device_node *np = adev->dev.of_node;
desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
if (!desc)
return -ENOMEM;
drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
if (!drvdata)
return -ENOMEM;
......@@ -825,13 +823,13 @@ static int etm_probe(struct amba_device *adev, const struct amba_id *id)
etm_init_trace_id(drvdata);
etm_set_default(&drvdata->config);
desc->type = CORESIGHT_DEV_TYPE_SOURCE;
desc->subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_PROC;
desc->ops = &etm_cs_ops;
desc->pdata = pdata;
desc->dev = dev;
desc->groups = coresight_etm_groups;
drvdata->csdev = coresight_register(desc);
desc.type = CORESIGHT_DEV_TYPE_SOURCE;
desc.subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_PROC;
desc.ops = &etm_cs_ops;
desc.pdata = pdata;
desc.dev = dev;
desc.groups = coresight_etm_groups;
drvdata->csdev = coresight_register(&desc);
if (IS_ERR(drvdata->csdev)) {
ret = PTR_ERR(drvdata->csdev);
goto err_arch_supported;
......@@ -893,6 +891,11 @@ static struct amba_id etm_ids[] = {
.mask = 0x0003ffff,
.data = "ETM 3.3",
},
{ /* ETM 3.5 - Cortex-A5 */
.id = 0x0003b955,
.mask = 0x0003ffff,
.data = "ETM 3.5",
},
{ /* ETM 3.5 */
.id = 0x0003b956,
.mask = 0x0003ffff,
......
......@@ -18,6 +18,7 @@
#include <linux/pm_runtime.h>
#include <linux/sysfs.h>
#include "coresight-etm4x.h"
#include "coresight-priv.h"
static int etm4_set_mode_exclude(struct etmv4_drvdata *drvdata, bool exclude)
{
......@@ -2039,15 +2040,42 @@ static struct attribute *coresight_etmv4_attrs[] = {
NULL,
};
struct etmv4_reg {
void __iomem *addr;
u32 data;
};
static void do_smp_cross_read(void *data)
{
struct etmv4_reg *reg = data;
reg->data = readl_relaxed(reg->addr);
}
static u32 etmv4_cross_read(const struct device *dev, u32 offset)
{
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev);
struct etmv4_reg reg;
reg.addr = drvdata->base + offset;
/*
* smp cross call ensures the CPU will be powered up before
* accessing the ETMv4 trace core registers
*/
smp_call_function_single(drvdata->cpu, do_smp_cross_read, &reg, 1);
return reg.data;
}
#define coresight_etm4x_simple_func(name, offset) \
coresight_simple_func(struct etmv4_drvdata, name, offset)
coresight_simple_func(struct etmv4_drvdata, NULL, name, offset)
#define coresight_etm4x_cross_read(name, offset) \
coresight_simple_func(struct etmv4_drvdata, etmv4_cross_read, \
name, offset)
coresight_etm4x_simple_func(trcoslsr, TRCOSLSR);
coresight_etm4x_simple_func(trcpdcr, TRCPDCR);
coresight_etm4x_simple_func(trcpdsr, TRCPDSR);
coresight_etm4x_simple_func(trclsr, TRCLSR);
coresight_etm4x_simple_func(trcconfig, TRCCONFIGR);
coresight_etm4x_simple_func(trctraceid, TRCTRACEIDR);
coresight_etm4x_simple_func(trcauthstatus, TRCAUTHSTATUS);
coresight_etm4x_simple_func(trcdevid, TRCDEVID);
coresight_etm4x_simple_func(trcdevtype, TRCDEVTYPE);
......@@ -2055,6 +2083,9 @@ coresight_etm4x_simple_func(trcpidr0, TRCPIDR0);
coresight_etm4x_simple_func(trcpidr1, TRCPIDR1);
coresight_etm4x_simple_func(trcpidr2, TRCPIDR2);
coresight_etm4x_simple_func(trcpidr3, TRCPIDR3);
coresight_etm4x_cross_read(trcoslsr, TRCOSLSR);
coresight_etm4x_cross_read(trcconfig, TRCCONFIGR);
coresight_etm4x_cross_read(trctraceid, TRCTRACEIDR);
static struct attribute *coresight_etmv4_mgmt_attrs[] = {
&dev_attr_trcoslsr.attr,
......@@ -2073,19 +2104,19 @@ static struct attribute *coresight_etmv4_mgmt_attrs[] = {
NULL,
};
coresight_etm4x_simple_func(trcidr0, TRCIDR0);
coresight_etm4x_simple_func(trcidr1, TRCIDR1);
coresight_etm4x_simple_func(trcidr2, TRCIDR2);
coresight_etm4x_simple_func(trcidr3, TRCIDR3);
coresight_etm4x_simple_func(trcidr4, TRCIDR4);
coresight_etm4x_simple_func(trcidr5, TRCIDR5);
coresight_etm4x_cross_read(trcidr0, TRCIDR0);
coresight_etm4x_cross_read(trcidr1, TRCIDR1);
coresight_etm4x_cross_read(trcidr2, TRCIDR2);
coresight_etm4x_cross_read(trcidr3, TRCIDR3);
coresight_etm4x_cross_read(trcidr4, TRCIDR4);
coresight_etm4x_cross_read(trcidr5, TRCIDR5);
/* trcidr[6,7] are reserved */
coresight_etm4x_simple_func(trcidr8, TRCIDR8);
coresight_etm4x_simple_func(trcidr9, TRCIDR9);
coresight_etm4x_simple_func(trcidr10, TRCIDR10);
coresight_etm4x_simple_func(trcidr11, TRCIDR11);
coresight_etm4x_simple_func(trcidr12, TRCIDR12);
coresight_etm4x_simple_func(trcidr13, TRCIDR13);
coresight_etm4x_cross_read(trcidr8, TRCIDR8);
coresight_etm4x_cross_read(trcidr9, TRCIDR9);
coresight_etm4x_cross_read(trcidr10, TRCIDR10);
coresight_etm4x_cross_read(trcidr11, TRCIDR11);
coresight_etm4x_cross_read(trcidr12, TRCIDR12);
coresight_etm4x_cross_read(trcidr13, TRCIDR13);
static struct attribute *coresight_etmv4_trcidr_attrs[] = {
&dev_attr_trcidr0.attr,
......
......@@ -183,6 +183,9 @@
#define TRCSTATR_IDLE_BIT 0
#define ETM_DEFAULT_ADDR_COMP 0
/* PowerDown Control Register bits */
#define TRCPDCR_PU BIT(3)
/* secure state access levels */
#define ETM_EXLEVEL_S_APP BIT(8)
#define ETM_EXLEVEL_S_OS BIT(9)
......@@ -407,14 +410,6 @@ enum etm_addr_ctxtype {
ETM_CTX_CTXID_VMID,
};
enum etm_addr_type {
ETM_ADDR_TYPE_NONE,
ETM_ADDR_TYPE_SINGLE,
ETM_ADDR_TYPE_RANGE,
ETM_ADDR_TYPE_START,
ETM_ADDR_TYPE_STOP,
};
extern const struct attribute_group *coresight_etmv4_groups[];
void etm4_config_trace_mode(struct etmv4_config *config);
#endif
......@@ -176,7 +176,7 @@ static int funnel_probe(struct amba_device *adev, const struct amba_id *id)
struct coresight_platform_data *pdata = NULL;
struct funnel_drvdata *drvdata;
struct resource *res = &adev->res;
struct coresight_desc *desc;
struct coresight_desc desc = { 0 };
struct device_node *np = adev->dev.of_node;
if (np) {
......@@ -207,17 +207,13 @@ static int funnel_probe(struct amba_device *adev, const struct amba_id *id)
drvdata->base = base;
pm_runtime_put(&adev->dev);
desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
if (!desc)
return -ENOMEM;
desc->type = CORESIGHT_DEV_TYPE_LINK;
desc->subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_MERG;
desc->ops = &funnel_cs_ops;
desc->pdata = pdata;
desc->dev = dev;
desc->groups = coresight_funnel_groups;
drvdata->csdev = coresight_register(desc);
desc.type = CORESIGHT_DEV_TYPE_LINK;
desc.subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_MERG;
desc.ops = &funnel_cs_ops;
desc.pdata = pdata;
desc.dev = dev;
desc.groups = coresight_funnel_groups;
drvdata->csdev = coresight_register(&desc);
if (IS_ERR(drvdata->csdev))
return PTR_ERR(drvdata->csdev);
......
......@@ -16,6 +16,7 @@
#include <linux/bitops.h>
#include <linux/io.h>
#include <linux/coresight.h>
#include <linux/pm_runtime.h>
/*
* Coresight management registers (0xf00-0xfcc)
......@@ -37,16 +38,32 @@
#define ETM_MODE_EXCL_KERN BIT(30)
#define ETM_MODE_EXCL_USER BIT(31)
#define coresight_simple_func(type, name, offset) \
typedef u32 (*coresight_read_fn)(const struct device *, u32 offset);
#define coresight_simple_func(type, func, name, offset) \
static ssize_t name##_show(struct device *_dev, \
struct device_attribute *attr, char *buf) \
{ \
type *drvdata = dev_get_drvdata(_dev->parent); \
return scnprintf(buf, PAGE_SIZE, "0x%x\n", \
readl_relaxed(drvdata->base + offset)); \
coresight_read_fn fn = func; \
u32 val; \
pm_runtime_get_sync(_dev->parent); \
if (fn) \
val = fn(_dev->parent, offset); \
else \
val = readl_relaxed(drvdata->base + offset); \
pm_runtime_put_sync(_dev->parent); \
return scnprintf(buf, PAGE_SIZE, "0x%x\n", val); \
} \
static DEVICE_ATTR_RO(name)
enum etm_addr_type {
ETM_ADDR_TYPE_NONE,
ETM_ADDR_TYPE_SINGLE,
ETM_ADDR_TYPE_RANGE,
ETM_ADDR_TYPE_START,
ETM_ADDR_TYPE_STOP,
};
enum cs_mode {
CS_MODE_DISABLED,
CS_MODE_SYSFS,
......
......@@ -102,7 +102,7 @@ static int replicator_probe(struct amba_device *adev, const struct amba_id *id)
struct resource *res = &adev->res;
struct coresight_platform_data *pdata = NULL;
struct replicator_state *drvdata;
struct coresight_desc *desc;
struct coresight_desc desc = { 0 };
struct device_node *np = adev->dev.of_node;
void __iomem *base;
......@@ -134,16 +134,12 @@ static int replicator_probe(struct amba_device *adev, const struct amba_id *id)
dev_set_drvdata(dev, drvdata);
pm_runtime_put(&adev->dev);
desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
if (!desc)
return -ENOMEM;
desc->type = CORESIGHT_DEV_TYPE_LINK;
desc->subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_SPLIT;
desc->ops = &replicator_cs_ops;
desc->pdata = adev->dev.platform_data;
desc->dev = &adev->dev;
drvdata->csdev = coresight_register(desc);
desc.type = CORESIGHT_DEV_TYPE_LINK;
desc.subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_SPLIT;
desc.ops = &replicator_cs_ops;
desc.pdata = adev->dev.platform_data;
desc.dev = &adev->dev;
drvdata->csdev = coresight_register(&desc);
if (IS_ERR(drvdata->csdev))
return PTR_ERR(drvdata->csdev);
......
......@@ -69,7 +69,7 @@ static int replicator_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct coresight_platform_data *pdata = NULL;
struct replicator_drvdata *drvdata;
struct coresight_desc *desc;
struct coresight_desc desc = { 0 };
struct device_node *np = pdev->dev.of_node;
if (np) {
......@@ -95,18 +95,12 @@ static int replicator_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
platform_set_drvdata(pdev, drvdata);
desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
if (!desc) {
ret = -ENOMEM;
goto out_disable_pm;
}
desc->type = CORESIGHT_DEV_TYPE_LINK;
desc->subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_SPLIT;
desc->ops = &replicator_cs_ops;
desc->pdata = pdev->dev.platform_data;
desc->dev = &pdev->dev;
drvdata->csdev = coresight_register(desc);
desc.type = CORESIGHT_DEV_TYPE_LINK;
desc.subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_SPLIT;
desc.ops = &replicator_cs_ops;
desc.pdata = pdev->dev.platform_data;
desc.dev = &pdev->dev;
drvdata->csdev = coresight_register(&desc);
if (IS_ERR(drvdata->csdev)) {
ret = PTR_ERR(drvdata->csdev);
goto out_disable_pm;
......
......@@ -105,10 +105,12 @@ module_param_named(
/**
* struct channel_space - central management entity for extended ports
* @base: memory mapped base address where channels start.
* @phys: physical base address of channel region.
* @guaraneed: is the channel delivery guaranteed.
*/
struct channel_space {
void __iomem *base;
phys_addr_t phys;
unsigned long *guaranteed;
};
......@@ -196,7 +198,7 @@ static void stm_enable_hw(struct stm_drvdata *drvdata)
}
static int stm_enable(struct coresight_device *csdev,
struct perf_event_attr *attr, u32 mode)
struct perf_event *event, u32 mode)
{
u32 val;
struct stm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
......@@ -258,7 +260,8 @@ static void stm_disable_hw(struct stm_drvdata *drvdata)
stm_hwevent_disable_hw(drvdata);
}
static void stm_disable(struct coresight_device *csdev)
static void stm_disable(struct coresight_device *csdev,
struct perf_event *event)
{
struct stm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
......@@ -353,7 +356,24 @@ static void stm_generic_unlink(struct stm_data *stm_data,
if (!drvdata || !drvdata->csdev)
return;
stm_disable(drvdata->csdev);
stm_disable(drvdata->csdev, NULL);
}
static phys_addr_t
stm_mmio_addr(struct stm_data *stm_data, unsigned int master,
unsigned int channel, unsigned int nr_chans)
{
struct stm_drvdata *drvdata = container_of(stm_data,
struct stm_drvdata, stm);
phys_addr_t addr;
addr = drvdata->chs.phys + channel * BYTES_PER_CHANNEL;
if (offset_in_page(addr) ||
offset_in_page(nr_chans * BYTES_PER_CHANNEL))
return 0;
return addr;
}
static long stm_generic_set_options(struct stm_data *stm_data,
......@@ -616,7 +636,7 @@ static ssize_t traceid_store(struct device *dev,
static DEVICE_ATTR_RW(traceid);
#define coresight_stm_simple_func(name, offset) \
coresight_simple_func(struct stm_drvdata, name, offset)
coresight_simple_func(struct stm_drvdata, NULL, name, offset)
coresight_stm_simple_func(tcsr, STMTCSR);
coresight_stm_simple_func(tsfreqr, STMTSFREQR);
......@@ -761,7 +781,9 @@ static void stm_init_generic_data(struct stm_drvdata *drvdata)
drvdata->stm.sw_end = 1;
drvdata->stm.hw_override = true;
drvdata->stm.sw_nchannels = drvdata->numsp;
drvdata->stm.sw_mmiosz = BYTES_PER_CHANNEL;
drvdata->stm.packet = stm_generic_packet;
drvdata->stm.mmio_addr = stm_mmio_addr;
drvdata->stm.link = stm_generic_link;
drvdata->stm.unlink = stm_generic_unlink;
drvdata->stm.set_options = stm_generic_set_options;
......@@ -778,7 +800,7 @@ static int stm_probe(struct amba_device *adev, const struct amba_id *id)
struct resource *res = &adev->res;
struct resource ch_res;
size_t res_size, bitmap_size;
struct coresight_desc *desc;
struct coresight_desc desc = { 0 };
struct device_node *np = adev->dev.of_node;
if (np) {
......@@ -808,6 +830,7 @@ static int stm_probe(struct amba_device *adev, const struct amba_id *id)
ret = stm_get_resource_byname(np, "stm-stimulus-base", &ch_res);
if (ret)
return ret;
drvdata->chs.phys = ch_res.start;
base = devm_ioremap_resource(dev, &ch_res);
if (IS_ERR(base))
......@@ -843,19 +866,13 @@ static int stm_probe(struct amba_device *adev, const struct amba_id *id)
return -EPROBE_DEFER;
}
desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
if (!desc) {
ret = -ENOMEM;
goto stm_unregister;
}
desc->type = CORESIGHT_DEV_TYPE_SOURCE;
desc->subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE;
desc->ops = &stm_cs_ops;
desc->pdata = pdata;
desc->dev = dev;
desc->groups = coresight_stm_groups;
drvdata->csdev = coresight_register(desc);
desc.type = CORESIGHT_DEV_TYPE_SOURCE;
desc.subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE;
desc.ops = &stm_cs_ops;
desc.pdata = pdata;
desc.dev = dev;
desc.groups = coresight_stm_groups;
drvdata->csdev = coresight_register(&desc);
if (IS_ERR(drvdata->csdev)) {
ret = PTR_ERR(drvdata->csdev);
goto stm_unregister;
......
......@@ -22,7 +22,7 @@
#include "coresight-priv.h"
#include "coresight-tmc.h"
void tmc_etb_enable_hw(struct tmc_drvdata *drvdata)
static void tmc_etb_enable_hw(struct tmc_drvdata *drvdata)
{
CS_UNLOCK(drvdata->base);
......@@ -48,6 +48,7 @@ static void tmc_etb_dump_hw(struct tmc_drvdata *drvdata)
int i;
bufp = drvdata->buf;
drvdata->len = 0;
while (1) {
for (i = 0; i < drvdata->memwidth; i++) {
read_data = readl_relaxed(drvdata->base + TMC_RRD);
......@@ -55,6 +56,7 @@ static void tmc_etb_dump_hw(struct tmc_drvdata *drvdata)
return;
memcpy(bufp, &read_data, 4);
bufp += 4;
drvdata->len += 4;
}
}
}
......@@ -166,7 +168,7 @@ static int tmc_enable_etf_sink_sysfs(struct coresight_device *csdev, u32 mode)
spin_unlock_irqrestore(&drvdata->spinlock, flags);
/* Free memory outside the spinlock if need be */
if (!used && buf)
if (!used)
kfree(buf);
if (!ret)
......
......@@ -20,7 +20,7 @@
#include "coresight-priv.h"
#include "coresight-tmc.h"
void tmc_etr_enable_hw(struct tmc_drvdata *drvdata)
static void tmc_etr_enable_hw(struct tmc_drvdata *drvdata)
{
u32 axictl;
......@@ -64,11 +64,17 @@ static void tmc_etr_dump_hw(struct tmc_drvdata *drvdata)
rwp = readl_relaxed(drvdata->base + TMC_RWP);
val = readl_relaxed(drvdata->base + TMC_STS);
/* How much memory do we still have */
if (val & BIT(0))
/*
* Adjust the buffer to point to the beginning of the trace data
* and update the available trace data.
*/
if (val & TMC_STS_FULL) {
drvdata->buf = drvdata->vaddr + rwp - drvdata->paddr;
else
drvdata->len = drvdata->size;
} else {
drvdata->buf = drvdata->vaddr;
drvdata->len = rwp - drvdata->paddr;
}
}
static void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
......
......@@ -38,8 +38,7 @@ void tmc_wait_for_tmcready(struct tmc_drvdata *drvdata)
if (coresight_timeout(drvdata->base,
TMC_STS, TMC_STS_TMCREADY_BIT, 1)) {
dev_err(drvdata->dev,
"timeout observed when probing at offset %#x\n",
TMC_STS);
"timeout while waiting for TMC to be Ready\n");
}
}
......@@ -56,8 +55,7 @@ void tmc_flush_and_stop(struct tmc_drvdata *drvdata)
if (coresight_timeout(drvdata->base,
TMC_FFCR, TMC_FFCR_FLUSHMAN_BIT, 0)) {
dev_err(drvdata->dev,
"timeout observed when probing at offset %#x\n",
TMC_FFCR);
"timeout while waiting for completion of Manual Flush\n");
}
tmc_wait_for_tmcready(drvdata);
......@@ -140,8 +138,8 @@ static ssize_t tmc_read(struct file *file, char __user *data, size_t len,
struct tmc_drvdata, miscdev);
char *bufp = drvdata->buf + *ppos;
if (*ppos + len > drvdata->size)
len = drvdata->size - *ppos;
if (*ppos + len > drvdata->len)
len = drvdata->len - *ppos;
if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
if (bufp == (char *)(drvdata->vaddr + drvdata->size))
......@@ -160,7 +158,7 @@ static ssize_t tmc_read(struct file *file, char __user *data, size_t len,
*ppos += len;
dev_dbg(drvdata->dev, "%s: %zu bytes copied, %d bytes left\n",
__func__, len, (int)(drvdata->size - *ppos));
__func__, len, (int)(drvdata->len - *ppos));
return len;
}
......@@ -220,7 +218,7 @@ static enum tmc_mem_intf_width tmc_get_memwidth(u32 devid)
}
#define coresight_tmc_simple_func(name, offset) \
coresight_simple_func(struct tmc_drvdata, name, offset)
coresight_simple_func(struct tmc_drvdata, NULL, name, offset)
coresight_tmc_simple_func(rsz, TMC_RSZ);
coresight_tmc_simple_func(sts, TMC_STS);
......@@ -249,8 +247,8 @@ static struct attribute *coresight_tmc_mgmt_attrs[] = {
NULL,
};
ssize_t trigger_cntr_show(struct device *dev,
struct device_attribute *attr, char *buf)
static ssize_t trigger_cntr_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent);
unsigned long val = drvdata->trigger_cntr;
......@@ -304,27 +302,32 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id)
struct coresight_platform_data *pdata = NULL;
struct tmc_drvdata *drvdata;
struct resource *res = &adev->res;
struct coresight_desc *desc;
struct coresight_desc desc = { 0 };
struct device_node *np = adev->dev.of_node;
if (np) {
pdata = of_get_coresight_platform_data(dev, np);
if (IS_ERR(pdata))
return PTR_ERR(pdata);
if (IS_ERR(pdata)) {
ret = PTR_ERR(pdata);
goto out;
}
adev->dev.platform_data = pdata;
}
ret = -ENOMEM;
drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
if (!drvdata)
return -ENOMEM;
goto out;
drvdata->dev = &adev->dev;
dev_set_drvdata(dev, drvdata);
/* Validity for the resource is already checked by the AMBA core */
base = devm_ioremap_resource(dev, res);
if (IS_ERR(base))
return PTR_ERR(base);
if (IS_ERR(base)) {
ret = PTR_ERR(base);
goto out;
}
drvdata->base = base;
......@@ -347,33 +350,28 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id)
pm_runtime_put(&adev->dev);
desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
if (!desc) {
ret = -ENOMEM;
goto err_devm_kzalloc;
}
desc->pdata = pdata;
desc->dev = dev;
desc->subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER;
desc->groups = coresight_tmc_groups;
desc.pdata = pdata;
desc.dev = dev;
desc.groups = coresight_tmc_groups;
if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
desc->type = CORESIGHT_DEV_TYPE_SINK;
desc->ops = &tmc_etb_cs_ops;
desc.type = CORESIGHT_DEV_TYPE_SINK;
desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER;
desc.ops = &tmc_etb_cs_ops;
} else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
desc->type = CORESIGHT_DEV_TYPE_SINK;
desc->ops = &tmc_etr_cs_ops;
desc.type = CORESIGHT_DEV_TYPE_SINK;
desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER;
desc.ops = &tmc_etr_cs_ops;
} else {
desc->type = CORESIGHT_DEV_TYPE_LINKSINK;
desc->subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_FIFO;
desc->ops = &tmc_etf_cs_ops;
desc.type = CORESIGHT_DEV_TYPE_LINKSINK;
desc.subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_FIFO;
desc.ops = &tmc_etf_cs_ops;
}
drvdata->csdev = coresight_register(desc);
drvdata->csdev = coresight_register(&desc);
if (IS_ERR(drvdata->csdev)) {
ret = PTR_ERR(drvdata->csdev);
goto err_devm_kzalloc;
goto out;
}
drvdata->miscdev.name = pdata->name;
......@@ -381,16 +379,8 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id)
drvdata->miscdev.fops = &tmc_fops;
ret = misc_register(&drvdata->miscdev);
if (ret)
goto err_misc_register;
return 0;
err_misc_register:
coresight_unregister(drvdata->csdev);
err_devm_kzalloc:
if (drvdata->config_type == TMC_CONFIG_TYPE_ETR)
dma_free_coherent(dev, drvdata->size,
drvdata->vaddr, drvdata->paddr);
coresight_unregister(drvdata->csdev);
out:
return ret;
}
......
......@@ -98,7 +98,8 @@ enum tmc_mem_intf_width {
* @buf: area of memory where trace data get sent.
* @paddr: DMA start location in RAM.
* @vaddr: virtual representation of @paddr.
* @size: @buf size.
* @size: trace buffer size.
* @len: size of the available trace.
* @mode: how this TMC is being used.
* @config_type: TMC variant, must be of type @tmc_config_type.
* @memwidth: width of the memory interface databus, in bytes.
......@@ -115,6 +116,7 @@ struct tmc_drvdata {
dma_addr_t paddr;
void __iomem *vaddr;
u32 size;
u32 len;
local_t mode;
enum tmc_config_type config_type;
enum tmc_mem_intf_width memwidth;
......
......@@ -119,7 +119,7 @@ static int tpiu_probe(struct amba_device *adev, const struct amba_id *id)
struct coresight_platform_data *pdata = NULL;
struct tpiu_drvdata *drvdata;
struct resource *res = &adev->res;
struct coresight_desc *desc;
struct coresight_desc desc = { 0 };
struct device_node *np = adev->dev.of_node;
if (np) {
......@@ -154,16 +154,12 @@ static int tpiu_probe(struct amba_device *adev, const struct amba_id *id)
pm_runtime_put(&adev->dev);
desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
if (!desc)
return -ENOMEM;
desc->type = CORESIGHT_DEV_TYPE_SINK;
desc->subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_PORT;
desc->ops = &tpiu_cs_ops;
desc->pdata = pdata;
desc->dev = dev;
drvdata->csdev = coresight_register(desc);
desc.type = CORESIGHT_DEV_TYPE_SINK;
desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_PORT;
desc.ops = &tpiu_cs_ops;
desc.pdata = pdata;
desc.dev = dev;
drvdata->csdev = coresight_register(&desc);
if (IS_ERR(drvdata->csdev))
return PTR_ERR(drvdata->csdev);
......
......@@ -257,7 +257,7 @@ static void coresight_disable_source(struct coresight_device *csdev)
{
if (atomic_dec_return(csdev->refcnt) == 0) {
if (source_ops(csdev)->disable) {
source_ops(csdev)->disable(csdev);
source_ops(csdev)->disable(csdev, NULL);
csdev->enable = false;
}
}
......@@ -429,7 +429,7 @@ struct list_head *coresight_build_path(struct coresight_device *csdev)
path = kzalloc(sizeof(struct list_head), GFP_KERNEL);
if (!path)
return NULL;
return ERR_PTR(-ENOMEM);
INIT_LIST_HEAD(path);
......@@ -725,7 +725,8 @@ static int coresight_orphan_match(struct device *dev, void *data)
/* We have found at least one orphan connection */
if (conn->child_dev == NULL) {
/* Does it match this newly added device? */
if (!strcmp(dev_name(&csdev->dev), conn->child_name)) {
if (conn->child_name &&
!strcmp(dev_name(&csdev->dev), conn->child_name)) {
conn->child_dev = csdev;
} else {
/* This component still has an orphan */
......@@ -893,7 +894,7 @@ struct coresight_device *coresight_register(struct coresight_desc *desc)
int nr_refcnts = 1;
atomic_t *refcnts = NULL;
struct coresight_device *csdev;
struct coresight_connection *conns;
struct coresight_connection *conns = NULL;
csdev = kzalloc(sizeof(*csdev), GFP_KERNEL);
if (!csdev) {
......@@ -921,16 +922,20 @@ struct coresight_device *coresight_register(struct coresight_desc *desc)
csdev->nr_inport = desc->pdata->nr_inport;
csdev->nr_outport = desc->pdata->nr_outport;
conns = kcalloc(csdev->nr_outport, sizeof(*conns), GFP_KERNEL);
if (!conns) {
ret = -ENOMEM;
goto err_kzalloc_conns;
}
for (i = 0; i < csdev->nr_outport; i++) {
conns[i].outport = desc->pdata->outports[i];
conns[i].child_name = desc->pdata->child_names[i];
conns[i].child_port = desc->pdata->child_ports[i];
/* Initialise connections if there is at least one outport */
if (csdev->nr_outport) {
conns = kcalloc(csdev->nr_outport, sizeof(*conns), GFP_KERNEL);
if (!conns) {
ret = -ENOMEM;
goto err_kzalloc_conns;
}
for (i = 0; i < csdev->nr_outport; i++) {
conns[i].outport = desc->pdata->outports[i];
conns[i].child_name = desc->pdata->child_names[i];
conns[i].child_port = desc->pdata->child_ports[i];
}
}
csdev->conns = conns;
......
......@@ -166,7 +166,7 @@ struct coresight_platform_data *of_get_coresight_platform_data(
rdev = of_coresight_get_endpoint_device(rparent);
if (!rdev)
continue;
return ERR_PTR(-EPROBE_DEFER);
pdata->child_names[i] = dev_name(rdev);
pdata->child_ports[i] = rendpoint.id;
......@@ -184,6 +184,7 @@ struct coresight_platform_data *of_get_coresight_platform_data(
break;
}
}
of_node_put(dn);
return pdata;
}
......
......@@ -8,8 +8,6 @@ menu "Pressure sensors"
config BMP280
tristate "Bosch Sensortec BMP180/BMP280 pressure sensor I2C driver"
depends on (I2C || SPI_MASTER)
depends on !(BMP085_I2C=y || BMP085_I2C=m)
depends on !(BMP085_SPI=y || BMP085_SPI=m)
select REGMAP
select BMP280_I2C if (I2C)
select BMP280_SPI if (SPI_MASTER)
......
......@@ -1013,23 +1013,12 @@ static struct miscdevice uinput_misc = {
.minor = UINPUT_MINOR,
.name = UINPUT_NAME,
};
module_misc_device(uinput_misc);
MODULE_ALIAS_MISCDEV(UINPUT_MINOR);
MODULE_ALIAS("devname:" UINPUT_NAME);
static int __init uinput_init(void)
{
return misc_register(&uinput_misc);
}
static void __exit uinput_exit(void)
{
misc_deregister(&uinput_misc);
}
MODULE_AUTHOR("Aristeu Sergio Rozanski Filho");
MODULE_DESCRIPTION("User level driver support for input subsystem");
MODULE_LICENSE("GPL");
MODULE_VERSION("0.3");
module_init(uinput_init);
module_exit(uinput_exit);
......@@ -1171,27 +1171,10 @@ static struct miscdevice _nvm_misc = {
.nodename = "lightnvm/control",
.fops = &_ctl_fops,
};
module_misc_device(_nvm_misc);
MODULE_ALIAS_MISCDEV(MISC_DYNAMIC_MINOR);
static int __init nvm_mod_init(void)
{
int ret;
ret = misc_register(&_nvm_misc);
if (ret)
pr_err("nvm: misc_register failed for control device");
return ret;
}
static void __exit nvm_mod_exit(void)
{
misc_deregister(&_nvm_misc);
}
MODULE_AUTHOR("Matias Bjorling <m@bjorling.me>");
MODULE_LICENSE("GPL v2");
MODULE_VERSION("0.1");
module_init(nvm_mod_init);
module_exit(nvm_mod_exit);
......@@ -28,4 +28,13 @@ config MCB_PCI
If build as a module, the module is called mcb-pci.ko
config MCB_LPC
tristate "LPC (non PCI) based MCB carrier"
default n
help
This is a MCB carrier on a LPC or non PCI device.
If build as a module, the module is called mcb-lpc.ko
endif # MCB
......@@ -5,3 +5,4 @@ mcb-y += mcb-core.o
mcb-y += mcb-parse.o
obj-$(CONFIG_MCB_PCI) += mcb-pci.o
obj-$(CONFIG_MCB_LPC) += mcb-lpc.o
......@@ -233,6 +233,7 @@ int mcb_device_register(struct mcb_bus *bus, struct mcb_device *dev)
dev->dev.bus = &mcb_bus_type;
dev->dev.parent = bus->dev.parent;
dev->dev.release = mcb_release_dev;
dev->dma_dev = bus->carrier;
device_id = dev->id;
dev_set_name(&dev->dev, "mcb%d-16z%03d-%d:%d:%d",
......@@ -369,7 +370,6 @@ struct mcb_device *mcb_alloc_dev(struct mcb_bus *bus)
if (!dev)
return NULL;
INIT_LIST_HEAD(&dev->bus_list);
dev->bus = bus;
return dev;
......@@ -405,20 +405,6 @@ static int __mcb_bus_add_devices(struct device *dev, void *data)
return 0;
}
static int __mcb_bus_add_child(struct device *dev, void *data)
{
struct mcb_device *mdev = to_mcb_device(dev);
struct mcb_bus *child;
BUG_ON(!mdev->is_added);
child = mdev->subordinate;
if (child)
mcb_bus_add_devices(child);
return 0;
}
/**
* mcb_bus_add_devices() - Add devices in the bus' internal device list
* @bus: The @mcb_bus we add the devices
......@@ -428,8 +414,6 @@ static int __mcb_bus_add_child(struct device *dev, void *data)
void mcb_bus_add_devices(const struct mcb_bus *bus)
{
bus_for_each_dev(&mcb_bus_type, NULL, NULL, __mcb_bus_add_devices);
bus_for_each_dev(&mcb_bus_type, NULL, NULL, __mcb_bus_add_child);
}
EXPORT_SYMBOL_GPL(mcb_bus_add_devices);
......
......@@ -112,6 +112,15 @@ struct chameleon_bdd {
u32 size;
} __packed;
struct chameleon_bar {
u32 addr;
u32 size;
};
#define BAR_CNT(x) ((x) & 0x07)
#define CHAMELEON_BAR_MAX 6
#define BAR_DESC_SIZE(x) ((x) * sizeof(struct chameleon_bar) + sizeof(__le32))
int chameleon_parse_cells(struct mcb_bus *bus, phys_addr_t mapbase,
void __iomem *base);
......
This diff is collapsed.
This diff is collapsed.
......@@ -46,6 +46,7 @@ static int mcb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
dev_err(&pdev->dev, "Failed to enable PCI device\n");
return -ENODEV;
}
pci_set_master(pdev);
priv->mapbase = pci_resource_start(pdev, 0);
if (!priv->mapbase) {
......
......@@ -16,6 +16,7 @@
#include <linux/gfp.h>
#include <memory/jedec_ddr.h>
#include <linux/export.h>
#include "of_memory.h"
/**
* of_get_min_tck() - extract min timing values for ddr
......
......@@ -429,34 +429,6 @@ config ARM_CHARLCD
line and the Linux version on the second line, but that's
still useful.
config BMP085
tristate
depends on SYSFS
config BMP085_I2C
tristate "BMP085 digital pressure sensor on I2C"
select BMP085
select REGMAP_I2C
depends on I2C && SYSFS
help
Say Y here if you want to support Bosch Sensortec's digital pressure
sensor hooked to an I2C bus.
To compile this driver as a module, choose M here: the
module will be called bmp085-i2c.
config BMP085_SPI
tristate "BMP085 digital pressure sensor on SPI"
select BMP085
select REGMAP_SPI
depends on SPI_MASTER && SYSFS
help
Say Y here if you want to support Bosch Sensortec's digital pressure
sensor hooked to an SPI bus.
To compile this driver as a module, choose M here: the
module will be called bmp085-spi.
config PCH_PHUB
tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) PHUB"
select GENERIC_NET_UTILS
......
......@@ -9,9 +9,6 @@ obj-$(CONFIG_AD525X_DPOT_SPI) += ad525x_dpot-spi.o
obj-$(CONFIG_INTEL_MID_PTI) += pti.o
obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o
obj-$(CONFIG_ATMEL_TCLIB) += atmel_tclib.o
obj-$(CONFIG_BMP085) += bmp085.o
obj-$(CONFIG_BMP085_I2C) += bmp085-i2c.o
obj-$(CONFIG_BMP085_SPI) += bmp085-spi.o
obj-$(CONFIG_DUMMY_IRQ) += dummy-irq.o
obj-$(CONFIG_ICS932S401) += ics932s401.o
obj-$(CONFIG_LKDTM) += lkdtm.o
......
/*
* Copyright (c) 2012 Bosch Sensortec GmbH
* Copyright (c) 2012 Unixphere AB
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/err.h>
#include "bmp085.h"
#define BMP085_I2C_ADDRESS 0x77
static const unsigned short normal_i2c[] = { BMP085_I2C_ADDRESS,
I2C_CLIENT_END };
static int bmp085_i2c_detect(struct i2c_client *client,
struct i2c_board_info *info)
{
if (client->addr != BMP085_I2C_ADDRESS)
return -ENODEV;
return bmp085_detect(&client->dev);
}
static int bmp085_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int err;
struct regmap *regmap = devm_regmap_init_i2c(client,
&bmp085_regmap_config);
if (IS_ERR(regmap)) {
err = PTR_ERR(regmap);
dev_err(&client->dev, "Failed to init regmap: %d\n", err);
return err;
}
return bmp085_probe(&client->dev, regmap, client->irq);
}
static int bmp085_i2c_remove(struct i2c_client *client)
{
return bmp085_remove(&client->dev);
}
static const struct i2c_device_id bmp085_id[] = {
{ BMP085_NAME, 0 },
{ "bmp180", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, bmp085_id);
static struct i2c_driver bmp085_i2c_driver = {
.driver = {
.name = BMP085_NAME,
},
.id_table = bmp085_id,
.probe = bmp085_i2c_probe,
.remove = bmp085_i2c_remove,
.detect = bmp085_i2c_detect,
.address_list = normal_i2c
};
module_i2c_driver(bmp085_i2c_driver);
MODULE_AUTHOR("Eric Andersson <eric.andersson@unixphere.com>");
MODULE_DESCRIPTION("BMP085 I2C bus driver");
MODULE_LICENSE("GPL");
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.
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