Commit 5af23440 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'char-misc-4.7-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.7-rc1.

  Lots of different tiny driver subsystems have updates here with new
  drivers and functionality.  Details in the shortlog.

  All have been in linux-next with no reported issues for a while"

* tag 'char-misc-4.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (125 commits)
  mcb: Delete num_cells variable which is not required
  mcb: Fixed bar number assignment for the gdd
  mcb: Replace ioremap and request_region with the devm version
  mcb: Implement bus->dev.release callback
  mcb: export bus information via sysfs
  mcb: Correctly initialize the bus's device
  mei: bus: call mei_cl_read_start under device lock
  coresight: etb10: adjust read pointer only when needed
  coresight: configuring ETF in FIFO mode when acting as link
  coresight: tmc: implementing TMC-ETF AUX space API
  coresight: moving struct cs_buffers to header file
  coresight: tmc: keep track of memory width
  coresight: tmc: make sysFS and Perf mode mutually exclusive
  coresight: tmc: dump system memory content only when needed
  coresight: tmc: adding mode of operation for link/sinks
  coresight: tmc: getting rid of multiple read access
  coresight: tmc: allocating memory when needed
  coresight: tmc: making prepare/unprepare functions generic
  coresight: tmc: splitting driver in ETB/ETF and ETR components
  coresight: tmc: cleaning up header file
  ...
parents 19e36ad2 725d0123
...@@ -6,13 +6,6 @@ Description: (RW) Add/remove a sink from a trace path. There can be multiple ...@@ -6,13 +6,6 @@ Description: (RW) Add/remove a sink from a trace path. There can be multiple
source for a single sink. source for a single sink.
ex: echo 1 > /sys/bus/coresight/devices/20010000.etb/enable_sink ex: echo 1 > /sys/bus/coresight/devices/20010000.etb/enable_sink
What: /sys/bus/coresight/devices/<memory_map>.etb/status
Date: November 2014
KernelVersion: 3.19
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (R) List various control and status registers. The specific
layout and content is driver specific.
What: /sys/bus/coresight/devices/<memory_map>.etb/trigger_cntr What: /sys/bus/coresight/devices/<memory_map>.etb/trigger_cntr
Date: November 2014 Date: November 2014
KernelVersion: 3.19 KernelVersion: 3.19
...@@ -22,3 +15,65 @@ Description: (RW) Disables write access to the Trace RAM by stopping the ...@@ -22,3 +15,65 @@ Description: (RW) Disables write access to the Trace RAM by stopping the
following the trigger event. The number of 32-bit words written following the trigger event. The number of 32-bit words written
into the Trace RAM following the trigger event is equal to the into the Trace RAM following the trigger event is equal to the
value stored in this register+1 (from ARM ETB-TRM). value stored in this register+1 (from ARM ETB-TRM).
What: /sys/bus/coresight/devices/<memory_map>.etb/mgmt/rdp
Date: March 2016
KernelVersion: 4.7
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (R) Defines the depth, in words, of the trace RAM in powers of
2. The value is read directly from HW register RDP, 0x004.
What: /sys/bus/coresight/devices/<memory_map>.etb/mgmt/sts
Date: March 2016
KernelVersion: 4.7
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (R) Shows the value held by the ETB status register. The value
is read directly from HW register STS, 0x00C.
What: /sys/bus/coresight/devices/<memory_map>.etb/mgmt/rrp
Date: March 2016
KernelVersion: 4.7
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (R) Shows the value held by the ETB RAM Read Pointer register
that is used to read entries from the Trace RAM over the APB
interface. The value is read directly from HW register RRP,
0x014.
What: /sys/bus/coresight/devices/<memory_map>.etb/mgmt/rwp
Date: March 2016
KernelVersion: 4.7
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (R) Shows the value held by the ETB RAM Write Pointer register
that is used to sets the write pointer to write entries from
the CoreSight bus into the Trace RAM. The value is read directly
from HW register RWP, 0x018.
What: /sys/bus/coresight/devices/<memory_map>.etb/mgmt/trg
Date: March 2016
KernelVersion: 4.7
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (R) Similar to "trigger_cntr" above except that this value is
read directly from HW register TRG, 0x01C.
What: /sys/bus/coresight/devices/<memory_map>.etb/mgmt/ctl
Date: March 2016
KernelVersion: 4.7
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (R) Shows the value held by the ETB Control register. The value
is read directly from HW register CTL, 0x020.
What: /sys/bus/coresight/devices/<memory_map>.etb/mgmt/ffsr
Date: March 2016
KernelVersion: 4.7
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (R) Shows the value held by the ETB Formatter and Flush Status
register. The value is read directly from HW register FFSR,
0x300.
What: /sys/bus/coresight/devices/<memory_map>.etb/mgmt/ffcr
Date: March 2016
KernelVersion: 4.7
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (R) Shows the value held by the ETB Formatter and Flush Control
register. The value is read directly from HW register FFCR,
0x304.
...@@ -359,6 +359,19 @@ Contact: Mathieu Poirier <mathieu.poirier@linaro.org> ...@@ -359,6 +359,19 @@ Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (R) Print the content of the Peripheral ID3 Register Description: (R) Print the content of the Peripheral ID3 Register
(0xFEC). The value is taken directly from the HW. (0xFEC). The value is taken directly from the HW.
What: /sys/bus/coresight/devices/<memory_map>.etm/mgmt/trcconfig
Date: February 2016
KernelVersion: 4.07
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (R) Print the content of the trace configuration register
(0x010) as currently set by SW.
What: /sys/bus/coresight/devices/<memory_map>.etm/mgmt/trctraceid
Date: February 2016
KernelVersion: 4.07
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (R) Print the content of the trace ID register (0x040).
What: /sys/bus/coresight/devices/<memory_map>.etm/trcidr/trcidr0 What: /sys/bus/coresight/devices/<memory_map>.etm/trcidr/trcidr0
Date: April 2015 Date: April 2015
KernelVersion: 4.01 KernelVersion: 4.01
......
What: /sys/bus/coresight/devices/<memory_map>.stm/enable_source
Date: April 2016
KernelVersion: 4.7
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (RW) Enable/disable tracing on this specific trace macrocell.
Enabling the trace macrocell implies it has been configured
properly and a sink has been identified for it. The path
of coresight components linking the source to the sink is
configured and managed automatically by the coresight framework.
What: /sys/bus/coresight/devices/<memory_map>.stm/hwevent_enable
Date: April 2016
KernelVersion: 4.7
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (RW) Provides access to the HW event enable register, used in
conjunction with HW event bank select register.
What: /sys/bus/coresight/devices/<memory_map>.stm/hwevent_select
Date: April 2016
KernelVersion: 4.7
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (RW) Gives access to the HW event block select register
(STMHEBSR) in order to configure up to 256 channels. Used in
conjunction with "hwevent_enable" register as described above.
What: /sys/bus/coresight/devices/<memory_map>.stm/port_enable
Date: April 2016
KernelVersion: 4.7
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (RW) Provides access to the stimulus port enable register
(STMSPER). Used in conjunction with "port_select" described
below.
What: /sys/bus/coresight/devices/<memory_map>.stm/port_select
Date: April 2016
KernelVersion: 4.7
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (RW) Used to determine which bank of stimulus port bit in
register STMSPER (see above) apply to.
What: /sys/bus/coresight/devices/<memory_map>.stm/status
Date: April 2016
KernelVersion: 4.7
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (R) List various control and status registers. The specific
layout and content is driver specific.
What: /sys/bus/coresight/devices/<memory_map>.stm/traceid
Date: April 2016
KernelVersion: 4.7
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (RW) Holds the trace ID that will appear in the trace stream
coming from this trace entity.
...@@ -6,3 +6,80 @@ Description: (RW) Disables write access to the Trace RAM by stopping the ...@@ -6,3 +6,80 @@ Description: (RW) Disables write access to the Trace RAM by stopping the
formatter after a defined number of words have been stored formatter after a defined number of words have been stored
following the trigger event. Additional interface for this following the trigger event. Additional interface for this
driver are expected to be added as it matures. driver are expected to be added as it matures.
What: /sys/bus/coresight/devices/<memory_map>.tmc/mgmt/rsz
Date: March 2016
KernelVersion: 4.7
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (R) Defines the size, in 32-bit words, of the local RAM buffer.
The value is read directly from HW register RSZ, 0x004.
What: /sys/bus/coresight/devices/<memory_map>.tmc/mgmt/sts
Date: March 2016
KernelVersion: 4.7
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (R) Shows the value held by the TMC status register. The value
is read directly from HW register STS, 0x00C.
What: /sys/bus/coresight/devices/<memory_map>.tmc/mgmt/rrp
Date: March 2016
KernelVersion: 4.7
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (R) Shows the value held by the TMC RAM Read Pointer register
that is used to read entries from the Trace RAM over the APB
interface. The value is read directly from HW register RRP,
0x014.
What: /sys/bus/coresight/devices/<memory_map>.tmc/mgmt/rwp
Date: March 2016
KernelVersion: 4.7
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (R) Shows the value held by the TMC RAM Write Pointer register
that is used to sets the write pointer to write entries from
the CoreSight bus into the Trace RAM. The value is read directly
from HW register RWP, 0x018.
What: /sys/bus/coresight/devices/<memory_map>.tmc/mgmt/trg
Date: March 2016
KernelVersion: 4.7
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (R) Similar to "trigger_cntr" above except that this value is
read directly from HW register TRG, 0x01C.
What: /sys/bus/coresight/devices/<memory_map>.tmc/mgmt/ctl
Date: March 2016
KernelVersion: 4.7
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (R) Shows the value held by the TMC Control register. The value
is read directly from HW register CTL, 0x020.
What: /sys/bus/coresight/devices/<memory_map>.tmc/mgmt/ffsr
Date: March 2016
KernelVersion: 4.7
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (R) Shows the value held by the TMC Formatter and Flush Status
register. The value is read directly from HW register FFSR,
0x300.
What: /sys/bus/coresight/devices/<memory_map>.tmc/mgmt/ffcr
Date: March 2016
KernelVersion: 4.7
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (R) Shows the value held by the TMC Formatter and Flush Control
register. The value is read directly from HW register FFCR,
0x304.
What: /sys/bus/coresight/devices/<memory_map>.tmc/mgmt/mode
Date: March 2016
KernelVersion: 4.7
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (R) Shows the value held by the TMC Mode register, which
indicate the mode the device has been configured to enact. The
The value is read directly from the MODE register, 0x028.
What: /sys/bus/coresight/devices/<memory_map>.tmc/mgmt/devid
Date: March 2016
KernelVersion: 4.7
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (R) Indicates the capabilities of the Coresight TMC.
The value is read directly from the DEVID register, 0xFC8,
What: /sys/bus/mcb/devices/mcb:X
Date: March 2016
KernelVersion: 4.7
Contact: Johannes Thumshirn <jth@kernel.org>
Description: Hardware chip or device hosting the MEN chameleon bus
What: /sys/bus/mcb/devices/mcb:X/revision
Date: March 2016
KernelVersion: 4.7
Contact: Johannes Thumshirn <jth@kernel.org>
Description: The FPGA's revision number
What: /sys/bus/mcb/devices/mcb:X/minor
Date: March 2016
KernelVersion: 4.7
Contact: Johannes Thumshirn <jth@kernel.org>
Description: The FPGA's minor number
What: /sys/bus/mcb/devices/mcb:X/model
Date: March 2016
KernelVersion: 4.7
Contact: Johannes Thumshirn <jth@kernel.org>
Description: The FPGA's model number
What: /sys/bus/mcb/devices/mcb:X/name
Date: March 2016
KernelVersion: 4.7
Contact: Johannes Thumshirn <jth@kernel.org>
Description: The FPGA's name
...@@ -12,3 +12,13 @@ KernelVersion: 4.3 ...@@ -12,3 +12,13 @@ KernelVersion: 4.3
Contact: Alexander Shishkin <alexander.shishkin@linux.intel.com> Contact: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Description: Description:
Shows the number of channels per master on this STM device. Shows the number of channels per master on this STM device.
What: /sys/class/stm/<stm>/hw_override
Date: March 2016
KernelVersion: 4.7
Contact: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Description:
Reads as 0 if master numbers in the STP stream produced by
this stm device will match the master numbers assigned by
the software or 1 if the stm hardware overrides software
assigned masters.
...@@ -19,6 +19,7 @@ its hardware characteristcs. ...@@ -19,6 +19,7 @@ its hardware characteristcs.
- "arm,coresight-etm3x", "arm,primecell"; - "arm,coresight-etm3x", "arm,primecell";
- "arm,coresight-etm4x", "arm,primecell"; - "arm,coresight-etm4x", "arm,primecell";
- "qcom,coresight-replicator1x", "arm,primecell"; - "qcom,coresight-replicator1x", "arm,primecell";
- "arm,coresight-stm", "arm,primecell"; [1]
* reg: physical base address and length of the register * reg: physical base address and length of the register
set(s) of the component. set(s) of the component.
...@@ -36,6 +37,14 @@ its hardware characteristcs. ...@@ -36,6 +37,14 @@ its hardware characteristcs.
layout using the generic DT graph presentation found in layout using the generic DT graph presentation found in
"bindings/graph.txt". "bindings/graph.txt".
* Additional required properties for System Trace Macrocells (STM):
* reg: along with the physical base address and length of the register
set as described above, another entry is required to describe the
mapping of the extended stimulus port area.
* reg-names: the only acceptable values are "stm-base" and
"stm-stimulus-base", each corresponding to the areas defined in "reg".
* Required properties for devices that don't show up on the AMBA bus, such as * Required properties for devices that don't show up on the AMBA bus, such as
non-configurable replicators: non-configurable replicators:
...@@ -202,3 +211,22 @@ Example: ...@@ -202,3 +211,22 @@ Example:
}; };
}; };
}; };
4. STM
stm@20100000 {
compatible = "arm,coresight-stm", "arm,primecell";
reg = <0 0x20100000 0 0x1000>,
<0 0x28000000 0 0x180000>;
reg-names = "stm-base", "stm-stimulus-base";
clocks = <&soc_smc50mhz>;
clock-names = "apb_pclk";
port {
stm_out_port: endpoint {
remote-endpoint = <&main_funnel_in_port2>;
};
};
};
[1]. There is currently two version of STM: STM32 and STM500. Both
have the same HW interface and as such don't need an explicit binding name.
...@@ -190,8 +190,8 @@ expected to be accessed and controlled using those entries. ...@@ -190,8 +190,8 @@ expected to be accessed and controlled using those entries.
Last but not least, "struct module *owner" is expected to be set to reflect Last but not least, "struct module *owner" is expected to be set to reflect
the information carried in "THIS_MODULE". the information carried in "THIS_MODULE".
How to use How to use the tracer modules
---------- -----------------------------
Before trace collection can start, a coresight sink needs to be identify. Before trace collection can start, a coresight sink needs to be identify.
There is no limit on the amount of sinks (nor sources) that can be enabled at There is no limit on the amount of sinks (nor sources) that can be enabled at
...@@ -297,3 +297,36 @@ Info Tracing enabled ...@@ -297,3 +297,36 @@ Info Tracing enabled
Instruction 13570831 0x8026B584 E28DD00C false ADD sp,sp,#0xc Instruction 13570831 0x8026B584 E28DD00C false ADD sp,sp,#0xc
Instruction 0 0x8026B588 E8BD8000 true LDM sp!,{pc} Instruction 0 0x8026B588 E8BD8000 true LDM sp!,{pc}
Timestamp Timestamp: 17107041535 Timestamp Timestamp: 17107041535
How to use the STM module
-------------------------
Using the System Trace Macrocell module is the same as the tracers - the only
difference is that clients are driving the trace capture rather
than the program flow through the code.
As with any other CoreSight component, specifics about the STM tracer can be
found in sysfs with more information on each entry being found in [1]:
root@genericarmv8:~# ls /sys/bus/coresight/devices/20100000.stm
enable_source hwevent_select port_enable subsystem uevent
hwevent_enable mgmt port_select traceid
root@genericarmv8:~#
Like any other source a sink needs to be identified and the STM enabled before
being used:
root@genericarmv8:~# echo 1 > /sys/bus/coresight/devices/20010000.etf/enable_sink
root@genericarmv8:~# echo 1 > /sys/bus/coresight/devices/20100000.stm/enable_source
From there user space applications can request and use channels using the devfs
interface provided for that purpose by the generic STM API:
root@genericarmv8:~# ls -l /dev/20100000.stm
crw------- 1 root root 10, 61 Jan 3 18:11 /dev/20100000.stm
root@genericarmv8:~#
Details on how to use the generic STM API can be found here [2].
[1]. Documentation/ABI/testing/sysfs-bus-coresight-devices-stm
[2]. Documentation/trace/stm.txt
...@@ -33,7 +33,15 @@ temperature conversion at a time. If none of the devices are parasite ...@@ -33,7 +33,15 @@ temperature conversion at a time. If none of the devices are parasite
powered it would be possible to convert all the devices at the same powered it would be possible to convert all the devices at the same
time and then go back to read individual sensors. That isn't time and then go back to read individual sensors. That isn't
currently supported. The driver also doesn't support reduced currently supported. The driver also doesn't support reduced
precision (which would also reduce the conversion time). precision (which would also reduce the conversion time) when reading values.
Writing a value between 9 and 12 to the sysfs w1_slave file will change the
precision of the sensor for the next readings. This value is in (volatile)
SRAM, so it is reset when the sensor gets power-cycled.
To store the current precision configuration into EEPROM, the value 0
has to be written to the sysfs w1_slave file. Since the EEPROM has a limited
amount of writes (>50k), this command should be used wisely.
The module parameter strong_pullup can be set to 0 to disable the The module parameter strong_pullup can be set to 0 to disable the
strong pullup, 1 to enable autodetection or 2 to force strong pullup. strong pullup, 1 to enable autodetection or 2 to force strong pullup.
......
...@@ -9843,6 +9843,7 @@ F: drivers/mmc/host/dw_mmc* ...@@ -9843,6 +9843,7 @@ F: drivers/mmc/host/dw_mmc*
SYSTEM TRACE MODULE CLASS SYSTEM TRACE MODULE CLASS
M: Alexander Shishkin <alexander.shishkin@linux.intel.com> M: Alexander Shishkin <alexander.shishkin@linux.intel.com>
S: Maintained S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/ash/stm.git
F: Documentation/trace/stm.txt F: Documentation/trace/stm.txt
F: drivers/hwtracing/stm/ F: drivers/hwtracing/stm/
F: include/linux/stm.h F: include/linux/stm.h
......
...@@ -279,8 +279,7 @@ if RTC_LIB=n ...@@ -279,8 +279,7 @@ if RTC_LIB=n
config RTC config RTC
tristate "Enhanced Real Time Clock Support (legacy PC RTC driver)" tristate "Enhanced Real Time Clock Support (legacy PC RTC driver)"
depends on !PPC && !PARISC && !IA64 && !M68K && !SPARC && !FRV \ depends on ALPHA || (MIPS && MACH_LOONGSON64) || MN10300
&& !ARM && !SUPERH && !S390 && !AVR32 && !BLACKFIN && !UML
---help--- ---help---
If you say Y here and create a character special file /dev/rtc with If you say Y here and create a character special file /dev/rtc with
major number 10 and minor number 135 using mknod ("man mknod"), you major number 10 and minor number 135 using mknod ("man mknod"), you
...@@ -585,7 +584,6 @@ config TELCLOCK ...@@ -585,7 +584,6 @@ config TELCLOCK
config DEVPORT config DEVPORT
bool bool
depends on !M68K
depends on ISA || PCI depends on ISA || PCI
default y default y
......
...@@ -81,7 +81,6 @@ static int xilly_map_single_of(struct xilly_endpoint *ep, ...@@ -81,7 +81,6 @@ static int xilly_map_single_of(struct xilly_endpoint *ep,
{ {
dma_addr_t addr; dma_addr_t addr;
struct xilly_mapping *this; struct xilly_mapping *this;
int rc;
this = kzalloc(sizeof(*this), GFP_KERNEL); this = kzalloc(sizeof(*this), GFP_KERNEL);
if (!this) if (!this)
...@@ -101,15 +100,7 @@ static int xilly_map_single_of(struct xilly_endpoint *ep, ...@@ -101,15 +100,7 @@ static int xilly_map_single_of(struct xilly_endpoint *ep,
*ret_dma_handle = addr; *ret_dma_handle = addr;
rc = devm_add_action(ep->dev, xilly_of_unmap, this); return devm_add_action_or_reset(ep->dev, xilly_of_unmap, this);
if (rc) {
dma_unmap_single(ep->dev, addr, size, direction);
kfree(this);
return rc;
}
return 0;
} }
static struct xilly_endpoint_hardware of_hw = { static struct xilly_endpoint_hardware of_hw = {
......
...@@ -98,7 +98,6 @@ static int xilly_map_single_pci(struct xilly_endpoint *ep, ...@@ -98,7 +98,6 @@ static int xilly_map_single_pci(struct xilly_endpoint *ep,
int pci_direction; int pci_direction;
dma_addr_t addr; dma_addr_t addr;
struct xilly_mapping *this; struct xilly_mapping *this;
int rc;
this = kzalloc(sizeof(*this), GFP_KERNEL); this = kzalloc(sizeof(*this), GFP_KERNEL);
if (!this) if (!this)
...@@ -120,14 +119,7 @@ static int xilly_map_single_pci(struct xilly_endpoint *ep, ...@@ -120,14 +119,7 @@ static int xilly_map_single_pci(struct xilly_endpoint *ep,
*ret_dma_handle = addr; *ret_dma_handle = addr;
rc = devm_add_action(ep->dev, xilly_pci_unmap, this); return devm_add_action_or_reset(ep->dev, xilly_pci_unmap, this);
if (rc) {
pci_unmap_single(ep->pdev, addr, size, pci_direction);
kfree(this);
return rc;
}
return 0;
} }
static struct xilly_endpoint_hardware pci_hw = { static struct xilly_endpoint_hardware pci_hw = {
......
...@@ -597,27 +597,55 @@ static void init_vp_index(struct vmbus_channel *channel, u16 dev_type) ...@@ -597,27 +597,55 @@ static void init_vp_index(struct vmbus_channel *channel, u16 dev_type)
static void vmbus_wait_for_unload(void) static void vmbus_wait_for_unload(void)
{ {
int cpu = smp_processor_id(); int cpu;
void *page_addr = hv_context.synic_message_page[cpu]; void *page_addr;
struct hv_message *msg = (struct hv_message *)page_addr + struct hv_message *msg;
VMBUS_MESSAGE_SINT;
struct vmbus_channel_message_header *hdr; struct vmbus_channel_message_header *hdr;
bool unloaded = false; u32 message_type;
/*
* CHANNELMSG_UNLOAD_RESPONSE is always delivered to the CPU which was
* used for initial contact or to CPU0 depending on host version. When
* we're crashing on a different CPU let's hope that IRQ handler on
* the cpu which receives CHANNELMSG_UNLOAD_RESPONSE is still
* functional and vmbus_unload_response() will complete
* vmbus_connection.unload_event. If not, the last thing we can do is
* read message pages for all CPUs directly.
*/
while (1) { while (1) {
if (READ_ONCE(msg->header.message_type) == HVMSG_NONE) { if (completion_done(&vmbus_connection.unload_event))
mdelay(10); break;
continue;
}
hdr = (struct vmbus_channel_message_header *)msg->u.payload; for_each_online_cpu(cpu) {
if (hdr->msgtype == CHANNELMSG_UNLOAD_RESPONSE) page_addr = hv_context.synic_message_page[cpu];
unloaded = true; msg = (struct hv_message *)page_addr +
VMBUS_MESSAGE_SINT;
vmbus_signal_eom(msg); message_type = READ_ONCE(msg->header.message_type);
if (message_type == HVMSG_NONE)
continue;
if (unloaded) hdr = (struct vmbus_channel_message_header *)
break; msg->u.payload;
if (hdr->msgtype == CHANNELMSG_UNLOAD_RESPONSE)
complete(&vmbus_connection.unload_event);
vmbus_signal_eom(msg, message_type);
}
mdelay(10);
}
/*
* We're crashing and already got the UNLOAD_RESPONSE, cleanup all
* maybe-pending messages on all CPUs to be able to receive new
* messages after we reconnect.
*/
for_each_online_cpu(cpu) {
page_addr = hv_context.synic_message_page[cpu];
msg = (struct hv_message *)page_addr + VMBUS_MESSAGE_SINT;
msg->header.message_type = HVMSG_NONE;
} }
} }
......
...@@ -495,3 +495,4 @@ void vmbus_set_event(struct vmbus_channel *channel) ...@@ -495,3 +495,4 @@ void vmbus_set_event(struct vmbus_channel *channel)
hv_do_hypercall(HVCALL_SIGNAL_EVENT, channel->sig_event, NULL); hv_do_hypercall(HVCALL_SIGNAL_EVENT, channel->sig_event, NULL);
} }
EXPORT_SYMBOL_GPL(vmbus_set_event);
...@@ -714,7 +714,7 @@ static bool pfn_covered(unsigned long start_pfn, unsigned long pfn_cnt) ...@@ -714,7 +714,7 @@ static bool pfn_covered(unsigned long start_pfn, unsigned long pfn_cnt)
* If the pfn range we are dealing with is not in the current * If the pfn range we are dealing with is not in the current
* "hot add block", move on. * "hot add block", move on.
*/ */
if ((start_pfn >= has->end_pfn)) if (start_pfn < has->start_pfn || start_pfn >= has->end_pfn)
continue; continue;
/* /*
* If the current hot add-request extends beyond * If the current hot add-request extends beyond
...@@ -768,7 +768,7 @@ static unsigned long handle_pg_range(unsigned long pg_start, ...@@ -768,7 +768,7 @@ static unsigned long handle_pg_range(unsigned long pg_start,
* If the pfn range we are dealing with is not in the current * If the pfn range we are dealing with is not in the current
* "hot add block", move on. * "hot add block", move on.
*/ */
if ((start_pfn >= has->end_pfn)) if (start_pfn < has->start_pfn || start_pfn >= has->end_pfn)
continue; continue;
old_covered_state = has->covered_end_pfn; old_covered_state = has->covered_end_pfn;
...@@ -1400,6 +1400,7 @@ static void balloon_onchannelcallback(void *context) ...@@ -1400,6 +1400,7 @@ static void balloon_onchannelcallback(void *context)
* This is a normal hot-add request specifying * This is a normal hot-add request specifying
* hot-add memory. * hot-add memory.
*/ */
dm->host_specified_ha_region = false;
ha_pg_range = &ha_msg->range; ha_pg_range = &ha_msg->range;
dm->ha_wrk.ha_page_range = *ha_pg_range; dm->ha_wrk.ha_page_range = *ha_pg_range;
dm->ha_wrk.ha_region_range.page_range = 0; dm->ha_wrk.ha_region_range.page_range = 0;
......
...@@ -78,9 +78,11 @@ static void kvp_send_key(struct work_struct *dummy); ...@@ -78,9 +78,11 @@ static void kvp_send_key(struct work_struct *dummy);
static void kvp_respond_to_host(struct hv_kvp_msg *msg, int error); static void kvp_respond_to_host(struct hv_kvp_msg *msg, int error);
static void kvp_timeout_func(struct work_struct *dummy); static void kvp_timeout_func(struct work_struct *dummy);
static void kvp_host_handshake_func(struct work_struct *dummy);
static void kvp_register(int); static void kvp_register(int);
static DECLARE_DELAYED_WORK(kvp_timeout_work, kvp_timeout_func); static DECLARE_DELAYED_WORK(kvp_timeout_work, kvp_timeout_func);
static DECLARE_DELAYED_WORK(kvp_host_handshake_work, kvp_host_handshake_func);
static DECLARE_WORK(kvp_sendkey_work, kvp_send_key); static DECLARE_WORK(kvp_sendkey_work, kvp_send_key);
static const char kvp_devname[] = "vmbus/hv_kvp"; static const char kvp_devname[] = "vmbus/hv_kvp";
...@@ -130,6 +132,11 @@ static void kvp_timeout_func(struct work_struct *dummy) ...@@ -130,6 +132,11 @@ static void kvp_timeout_func(struct work_struct *dummy)
hv_poll_channel(kvp_transaction.recv_channel, kvp_poll_wrapper); hv_poll_channel(kvp_transaction.recv_channel, kvp_poll_wrapper);
} }
static void kvp_host_handshake_func(struct work_struct *dummy)
{
hv_poll_channel(kvp_transaction.recv_channel, hv_kvp_onchannelcallback);
}
static int kvp_handle_handshake(struct hv_kvp_msg *msg) static int kvp_handle_handshake(struct hv_kvp_msg *msg)
{ {
switch (msg->kvp_hdr.operation) { switch (msg->kvp_hdr.operation) {
...@@ -154,6 +161,12 @@ static int kvp_handle_handshake(struct hv_kvp_msg *msg) ...@@ -154,6 +161,12 @@ static int kvp_handle_handshake(struct hv_kvp_msg *msg)
pr_debug("KVP: userspace daemon ver. %d registered\n", pr_debug("KVP: userspace daemon ver. %d registered\n",
KVP_OP_REGISTER); KVP_OP_REGISTER);
kvp_register(dm_reg_value); 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); hv_poll_channel(kvp_transaction.recv_channel, kvp_poll_wrapper);
return 0; return 0;
...@@ -594,7 +607,22 @@ void hv_kvp_onchannelcallback(void *context) ...@@ -594,7 +607,22 @@ void hv_kvp_onchannelcallback(void *context)
struct icmsg_negotiate *negop = NULL; struct icmsg_negotiate *negop = NULL;
int util_fw_version; int util_fw_version;
int kvp_srv_version; int kvp_srv_version;
static enum {NEGO_NOT_STARTED,
NEGO_IN_PROGRESS,
NEGO_FINISHED} host_negotiatied = NEGO_NOT_STARTED;
if (host_negotiatied == NEGO_NOT_STARTED &&
kvp_transaction.state < HVUTIL_READY) {
/*
* If userspace daemon is not connected and host is asking
* us to negotiate we need to delay to not lose messages.
* This is important for Failover IP setting.
*/
host_negotiatied = NEGO_IN_PROGRESS;
schedule_delayed_work(&kvp_host_handshake_work,
HV_UTIL_NEGO_TIMEOUT * HZ);
return;
}
if (kvp_transaction.state > HVUTIL_READY) if (kvp_transaction.state > HVUTIL_READY)
return; return;
...@@ -672,6 +700,8 @@ void hv_kvp_onchannelcallback(void *context) ...@@ -672,6 +700,8 @@ void hv_kvp_onchannelcallback(void *context)
vmbus_sendpacket(channel, recv_buffer, vmbus_sendpacket(channel, recv_buffer,
recvlen, requestid, recvlen, requestid,
VM_PKT_DATA_INBAND, 0); VM_PKT_DATA_INBAND, 0);
host_negotiatied = NEGO_FINISHED;
} }
} }
...@@ -708,6 +738,7 @@ hv_kvp_init(struct hv_util_service *srv) ...@@ -708,6 +738,7 @@ hv_kvp_init(struct hv_util_service *srv)
void hv_kvp_deinit(void) void hv_kvp_deinit(void)
{ {
kvp_transaction.state = HVUTIL_DEVICE_DYING; kvp_transaction.state = HVUTIL_DEVICE_DYING;
cancel_delayed_work_sync(&kvp_host_handshake_work);
cancel_delayed_work_sync(&kvp_timeout_work); cancel_delayed_work_sync(&kvp_timeout_work);
cancel_work_sync(&kvp_sendkey_work); cancel_work_sync(&kvp_sendkey_work);
hvutil_transport_destroy(hvt); hvutil_transport_destroy(hvt);
......
...@@ -35,6 +35,11 @@ ...@@ -35,6 +35,11 @@
*/ */
#define HV_UTIL_TIMEOUT 30 #define HV_UTIL_TIMEOUT 30
/*
* Timeout for guest-host handshake for services.
*/
#define HV_UTIL_NEGO_TIMEOUT 60
/* /*
* The below CPUID leaves are present if VersionAndFeatures.HypervisorPresent * The below CPUID leaves are present if VersionAndFeatures.HypervisorPresent
* is set by CPUID(HVCPUID_VERSION_FEATURES). * is set by CPUID(HVCPUID_VERSION_FEATURES).
...@@ -620,9 +625,21 @@ extern struct vmbus_channel_message_table_entry ...@@ -620,9 +625,21 @@ extern struct vmbus_channel_message_table_entry
channel_message_table[CHANNELMSG_COUNT]; channel_message_table[CHANNELMSG_COUNT];
/* Free the message slot and signal end-of-message if required */ /* Free the message slot and signal end-of-message if required */
static inline void vmbus_signal_eom(struct hv_message *msg) static inline void vmbus_signal_eom(struct hv_message *msg, u32 old_msg_type)
{ {
msg->header.message_type = HVMSG_NONE; /*
* On crash we're reading some other CPU's message page and we need
* to be careful: this other CPU may already had cleared the header
* and the host may already had delivered some other message there.
* In case we blindly write msg->header.message_type we're going
* to lose it. We can still lose a message of the same type but
* we count on the fact that there can only be one
* CHANNELMSG_UNLOAD_RESPONSE and we don't care about other messages
* on crash.
*/
if (cmpxchg(&msg->header.message_type, old_msg_type,
HVMSG_NONE) != old_msg_type)
return;
/* /*
* Make sure the write to MessageType (ie set to * Make sure the write to MessageType (ie set to
...@@ -667,8 +684,6 @@ void vmbus_disconnect(void); ...@@ -667,8 +684,6 @@ void vmbus_disconnect(void);
int vmbus_post_msg(void *buffer, size_t buflen); int vmbus_post_msg(void *buffer, size_t buflen);
void vmbus_set_event(struct vmbus_channel *channel);
void vmbus_on_event(unsigned long data); void vmbus_on_event(unsigned long data);
void vmbus_on_msg_dpc(unsigned long data); void vmbus_on_msg_dpc(unsigned long data);
......
...@@ -33,25 +33,21 @@ ...@@ -33,25 +33,21 @@
void hv_begin_read(struct hv_ring_buffer_info *rbi) void hv_begin_read(struct hv_ring_buffer_info *rbi)
{ {
rbi->ring_buffer->interrupt_mask = 1; rbi->ring_buffer->interrupt_mask = 1;
mb(); virt_mb();
} }
u32 hv_end_read(struct hv_ring_buffer_info *rbi) u32 hv_end_read(struct hv_ring_buffer_info *rbi)
{ {
u32 read;
u32 write;
rbi->ring_buffer->interrupt_mask = 0; rbi->ring_buffer->interrupt_mask = 0;
mb(); virt_mb();
/* /*
* Now check to see if the ring buffer is still empty. * Now check to see if the ring buffer is still empty.
* If it is not, we raced and we need to process new * If it is not, we raced and we need to process new
* incoming messages. * incoming messages.
*/ */
hv_get_ringbuffer_availbytes(rbi, &read, &write); return hv_get_bytes_to_read(rbi);
return read;
} }
/* /*
...@@ -72,69 +68,17 @@ u32 hv_end_read(struct hv_ring_buffer_info *rbi) ...@@ -72,69 +68,17 @@ u32 hv_end_read(struct hv_ring_buffer_info *rbi)
static bool hv_need_to_signal(u32 old_write, struct hv_ring_buffer_info *rbi) static bool hv_need_to_signal(u32 old_write, struct hv_ring_buffer_info *rbi)
{ {
mb(); virt_mb();
if (rbi->ring_buffer->interrupt_mask) if (READ_ONCE(rbi->ring_buffer->interrupt_mask))
return false; return false;
/* check interrupt_mask before read_index */ /* check interrupt_mask before read_index */
rmb(); virt_rmb();
/* /*
* This is the only case we need to signal when the * This is the only case we need to signal when the
* ring transitions from being empty to non-empty. * ring transitions from being empty to non-empty.
*/ */
if (old_write == rbi->ring_buffer->read_index) if (old_write == READ_ONCE(rbi->ring_buffer->read_index))
return true;
return false;
}
/*
* To optimize the flow management on the send-side,
* when the sender is blocked because of lack of
* sufficient space in the ring buffer, potential the
* consumer of the ring buffer can signal the producer.
* This is controlled by the following parameters:
*
* 1. pending_send_sz: This is the size in bytes that the
* producer is trying to send.
* 2. The feature bit feat_pending_send_sz set to indicate if
* the consumer of the ring will signal when the ring
* state transitions from being full to a state where
* there is room for the producer to send the pending packet.
*/
static bool hv_need_to_signal_on_read(struct hv_ring_buffer_info *rbi)
{
u32 cur_write_sz;
u32 r_size;
u32 write_loc;
u32 read_loc = rbi->ring_buffer->read_index;
u32 pending_sz;
/*
* Issue a full memory barrier before making the signaling decision.
* Here is the reason for having this barrier:
* If the reading of the pend_sz (in this function)
* were to be reordered and read before we commit the new read
* index (in the calling function) we could
* have a problem. If the host were to set the pending_sz after we
* have sampled pending_sz and go to sleep before we commit the
* read index, we could miss sending the interrupt. Issue a full
* memory barrier to address this.
*/
mb();
pending_sz = rbi->ring_buffer->pending_send_sz;
write_loc = rbi->ring_buffer->write_index;
/* If the other end is not blocked on write don't bother. */
if (pending_sz == 0)
return false;
r_size = rbi->ring_datasize;
cur_write_sz = write_loc >= read_loc ? r_size - (write_loc - read_loc) :
read_loc - write_loc;
if (cur_write_sz >= pending_sz)
return true; return true;
return false; return false;
...@@ -188,17 +132,9 @@ hv_set_next_read_location(struct hv_ring_buffer_info *ring_info, ...@@ -188,17 +132,9 @@ hv_set_next_read_location(struct hv_ring_buffer_info *ring_info,
u32 next_read_location) u32 next_read_location)
{ {
ring_info->ring_buffer->read_index = next_read_location; ring_info->ring_buffer->read_index = next_read_location;
ring_info->priv_read_index = next_read_location;
} }
/* Get the start of the ring buffer. */
static inline void *
hv_get_ring_buffer(struct hv_ring_buffer_info *ring_info)
{
return (void *)ring_info->ring_buffer->buffer;
}
/* Get the size of the ring buffer. */ /* Get the size of the ring buffer. */
static inline u32 static inline u32
hv_get_ring_buffersize(struct hv_ring_buffer_info *ring_info) hv_get_ring_buffersize(struct hv_ring_buffer_info *ring_info)
...@@ -332,7 +268,6 @@ int hv_ringbuffer_write(struct hv_ring_buffer_info *outring_info, ...@@ -332,7 +268,6 @@ int hv_ringbuffer_write(struct hv_ring_buffer_info *outring_info,
{ {
int i = 0; int i = 0;
u32 bytes_avail_towrite; u32 bytes_avail_towrite;
u32 bytes_avail_toread;
u32 totalbytes_towrite = 0; u32 totalbytes_towrite = 0;
u32 next_write_location; u32 next_write_location;
...@@ -348,9 +283,7 @@ int hv_ringbuffer_write(struct hv_ring_buffer_info *outring_info, ...@@ -348,9 +283,7 @@ int hv_ringbuffer_write(struct hv_ring_buffer_info *outring_info,
if (lock) if (lock)
spin_lock_irqsave(&outring_info->ring_lock, flags); spin_lock_irqsave(&outring_info->ring_lock, flags);
hv_get_ringbuffer_availbytes(outring_info, bytes_avail_towrite = hv_get_bytes_to_write(outring_info);
&bytes_avail_toread,
&bytes_avail_towrite);
/* /*
* If there is only room for the packet, assume it is full. * If there is only room for the packet, assume it is full.
...@@ -384,7 +317,7 @@ int hv_ringbuffer_write(struct hv_ring_buffer_info *outring_info, ...@@ -384,7 +317,7 @@ int hv_ringbuffer_write(struct hv_ring_buffer_info *outring_info,
sizeof(u64)); sizeof(u64));
/* Issue a full memory barrier before updating the write index */ /* Issue a full memory barrier before updating the write index */
mb(); virt_mb();
/* Now, update the write location */ /* Now, update the write location */
hv_set_next_write_location(outring_info, next_write_location); hv_set_next_write_location(outring_info, next_write_location);
...@@ -401,7 +334,6 @@ int hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info, ...@@ -401,7 +334,6 @@ int hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info,
void *buffer, u32 buflen, u32 *buffer_actual_len, void *buffer, u32 buflen, u32 *buffer_actual_len,
u64 *requestid, bool *signal, bool raw) u64 *requestid, bool *signal, bool raw)
{ {
u32 bytes_avail_towrite;
u32 bytes_avail_toread; u32 bytes_avail_toread;
u32 next_read_location = 0; u32 next_read_location = 0;
u64 prev_indices = 0; u64 prev_indices = 0;
...@@ -417,10 +349,7 @@ int hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info, ...@@ -417,10 +349,7 @@ int hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info,
*buffer_actual_len = 0; *buffer_actual_len = 0;
*requestid = 0; *requestid = 0;
hv_get_ringbuffer_availbytes(inring_info, bytes_avail_toread = hv_get_bytes_to_read(inring_info);
&bytes_avail_toread,
&bytes_avail_towrite);
/* Make sure there is something to read */ /* Make sure there is something to read */
if (bytes_avail_toread < sizeof(desc)) { if (bytes_avail_toread < sizeof(desc)) {
/* /*
...@@ -464,7 +393,7 @@ int hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info, ...@@ -464,7 +393,7 @@ int hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info,
* the writer may start writing to the read area once the read index * the writer may start writing to the read area once the read index
* is updated. * is updated.
*/ */
mb(); virt_mb();
/* Update the read index */ /* Update the read index */
hv_set_next_read_location(inring_info, next_read_location); hv_set_next_read_location(inring_info, next_read_location);
......
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
#include <linux/ptrace.h> #include <linux/ptrace.h>
#include <linux/screen_info.h> #include <linux/screen_info.h>
#include <linux/kdebug.h> #include <linux/kdebug.h>
#include <linux/efi.h>
#include "hyperv_vmbus.h" #include "hyperv_vmbus.h"
static struct acpi_device *hv_acpi_dev; static struct acpi_device *hv_acpi_dev;
...@@ -101,7 +102,10 @@ static struct notifier_block hyperv_panic_block = { ...@@ -101,7 +102,10 @@ static struct notifier_block hyperv_panic_block = {
.notifier_call = hyperv_panic_event, .notifier_call = hyperv_panic_event,
}; };
static const char *fb_mmio_name = "fb_range";
static struct resource *fb_mmio;
struct resource *hyperv_mmio; struct resource *hyperv_mmio;
DEFINE_SEMAPHORE(hyperv_mmio_lock);
static int vmbus_exists(void) static int vmbus_exists(void)
{ {
...@@ -708,7 +712,7 @@ static void hv_process_timer_expiration(struct hv_message *msg, int cpu) ...@@ -708,7 +712,7 @@ static void hv_process_timer_expiration(struct hv_message *msg, int cpu)
if (dev->event_handler) if (dev->event_handler)
dev->event_handler(dev); dev->event_handler(dev);
vmbus_signal_eom(msg); vmbus_signal_eom(msg, HVMSG_TIMER_EXPIRED);
} }
void vmbus_on_msg_dpc(unsigned long data) void vmbus_on_msg_dpc(unsigned long data)
...@@ -720,8 +724,9 @@ void vmbus_on_msg_dpc(unsigned long data) ...@@ -720,8 +724,9 @@ void vmbus_on_msg_dpc(unsigned long data)
struct vmbus_channel_message_header *hdr; struct vmbus_channel_message_header *hdr;
struct vmbus_channel_message_table_entry *entry; struct vmbus_channel_message_table_entry *entry;
struct onmessage_work_context *ctx; struct onmessage_work_context *ctx;
u32 message_type = msg->header.message_type;
if (msg->header.message_type == HVMSG_NONE) if (message_type == HVMSG_NONE)
/* no msg */ /* no msg */
return; return;
...@@ -746,7 +751,7 @@ void vmbus_on_msg_dpc(unsigned long data) ...@@ -746,7 +751,7 @@ void vmbus_on_msg_dpc(unsigned long data)
entry->message_handler(hdr); entry->message_handler(hdr);
msg_handled: msg_handled:
vmbus_signal_eom(msg); vmbus_signal_eom(msg, message_type);
} }
static void vmbus_isr(void) static void vmbus_isr(void)
...@@ -1048,7 +1053,6 @@ static acpi_status vmbus_walk_resources(struct acpi_resource *res, void *ctx) ...@@ -1048,7 +1053,6 @@ static acpi_status vmbus_walk_resources(struct acpi_resource *res, void *ctx)
new_res->end = end; new_res->end = end;
/* /*
* Stick ranges from higher in address space at the front of the list.
* If two ranges are adjacent, merge them. * If two ranges are adjacent, merge them.
*/ */
do { do {
...@@ -1069,7 +1073,7 @@ static acpi_status vmbus_walk_resources(struct acpi_resource *res, void *ctx) ...@@ -1069,7 +1073,7 @@ static acpi_status vmbus_walk_resources(struct acpi_resource *res, void *ctx)
break; break;
} }
if ((*old_res)->end < new_res->start) { if ((*old_res)->start > new_res->end) {
new_res->sibling = *old_res; new_res->sibling = *old_res;
if (prev_res) if (prev_res)
(*prev_res)->sibling = new_res; (*prev_res)->sibling = new_res;
...@@ -1091,6 +1095,12 @@ static int vmbus_acpi_remove(struct acpi_device *device) ...@@ -1091,6 +1095,12 @@ static int vmbus_acpi_remove(struct acpi_device *device)
struct resource *next_res; struct resource *next_res;
if (hyperv_mmio) { if (hyperv_mmio) {
if (fb_mmio) {
__release_region(hyperv_mmio, fb_mmio->start,
resource_size(fb_mmio));
fb_mmio = NULL;
}
for (cur_res = hyperv_mmio; cur_res; cur_res = next_res) { for (cur_res = hyperv_mmio; cur_res; cur_res = next_res) {
next_res = cur_res->sibling; next_res = cur_res->sibling;
kfree(cur_res); kfree(cur_res);
...@@ -1100,6 +1110,30 @@ static int vmbus_acpi_remove(struct acpi_device *device) ...@@ -1100,6 +1110,30 @@ static int vmbus_acpi_remove(struct acpi_device *device)
return 0; return 0;
} }
static void vmbus_reserve_fb(void)
{
int size;
/*
* Make a claim for the frame buffer in the resource tree under the
* first node, which will be the one below 4GB. The length seems to
* be underreported, particularly in a Generation 1 VM. So start out
* reserving a larger area and make it smaller until it succeeds.
*/
if (screen_info.lfb_base) {
if (efi_enabled(EFI_BOOT))
size = max_t(__u32, screen_info.lfb_size, 0x800000);
else
size = max_t(__u32, screen_info.lfb_size, 0x4000000);
for (; !fb_mmio && (size >= 0x100000); size >>= 1) {
fb_mmio = __request_region(hyperv_mmio,
screen_info.lfb_base, size,
fb_mmio_name, 0);
}
}
}
/** /**
* vmbus_allocate_mmio() - Pick a memory-mapped I/O range. * vmbus_allocate_mmio() - Pick a memory-mapped I/O range.
* @new: If successful, supplied a pointer to the * @new: If successful, supplied a pointer to the
...@@ -1128,11 +1162,33 @@ int vmbus_allocate_mmio(struct resource **new, struct hv_device *device_obj, ...@@ -1128,11 +1162,33 @@ int vmbus_allocate_mmio(struct resource **new, struct hv_device *device_obj,
resource_size_t size, resource_size_t align, resource_size_t size, resource_size_t align,
bool fb_overlap_ok) bool fb_overlap_ok)
{ {
struct resource *iter; struct resource *iter, *shadow;
resource_size_t range_min, range_max, start, local_min, local_max; resource_size_t range_min, range_max, start;
const char *dev_n = dev_name(&device_obj->device); const char *dev_n = dev_name(&device_obj->device);
u32 fb_end = screen_info.lfb_base + (screen_info.lfb_size << 1); int retval;
int i;
retval = -ENXIO;
down(&hyperv_mmio_lock);
/*
* If overlaps with frame buffers are allowed, then first attempt to
* make the allocation from within the reserved region. Because it
* is already reserved, no shadow allocation is necessary.
*/
if (fb_overlap_ok && fb_mmio && !(min > fb_mmio->end) &&
!(max < fb_mmio->start)) {
range_min = fb_mmio->start;
range_max = fb_mmio->end;
start = (range_min + align - 1) & ~(align - 1);
for (; start + size - 1 <= range_max; start += align) {
*new = request_mem_region_exclusive(start, size, dev_n);
if (*new) {
retval = 0;
goto exit;
}
}
}
for (iter = hyperv_mmio; iter; iter = iter->sibling) { for (iter = hyperv_mmio; iter; iter = iter->sibling) {
if ((iter->start >= max) || (iter->end <= min)) if ((iter->start >= max) || (iter->end <= min))
...@@ -1140,45 +1196,55 @@ int vmbus_allocate_mmio(struct resource **new, struct hv_device *device_obj, ...@@ -1140,45 +1196,55 @@ int vmbus_allocate_mmio(struct resource **new, struct hv_device *device_obj,
range_min = iter->start; range_min = iter->start;
range_max = iter->end; range_max = iter->end;
start = (range_min + align - 1) & ~(align - 1);
/* If this range overlaps the frame buffer, split it into for (; start + size - 1 <= range_max; start += align) {
two tries. */ shadow = __request_region(iter, start, size, NULL,
for (i = 0; i < 2; i++) { IORESOURCE_BUSY);
local_min = range_min; if (!shadow)
local_max = range_max; continue;
if (fb_overlap_ok || (range_min >= fb_end) ||
(range_max <= screen_info.lfb_base)) { *new = request_mem_region_exclusive(start, size, dev_n);
i++; if (*new) {
} else { shadow->name = (char *)*new;
if ((range_min <= screen_info.lfb_base) && retval = 0;
(range_max >= screen_info.lfb_base)) { goto exit;
/*
* The frame buffer is in this window,
* so trim this into the part that
* preceeds the frame buffer.
*/
local_max = screen_info.lfb_base - 1;
range_min = fb_end;
} else {
range_min = fb_end;
continue;
}
} }
start = (local_min + align - 1) & ~(align - 1); __release_region(iter, start, size);
for (; start + size - 1 <= local_max; start += align) {
*new = request_mem_region_exclusive(start, size,
dev_n);
if (*new)
return 0;
}
} }
} }
return -ENXIO; exit:
up(&hyperv_mmio_lock);
return retval;
} }
EXPORT_SYMBOL_GPL(vmbus_allocate_mmio); EXPORT_SYMBOL_GPL(vmbus_allocate_mmio);
/**
* vmbus_free_mmio() - Free a memory-mapped I/O range.
* @start: Base address of region to release.
* @size: Size of the range to be allocated
*
* This function releases anything requested by
* vmbus_mmio_allocate().
*/
void vmbus_free_mmio(resource_size_t start, resource_size_t size)
{
struct resource *iter;
down(&hyperv_mmio_lock);
for (iter = hyperv_mmio; iter; iter = iter->sibling) {
if ((iter->start >= start + size) || (iter->end <= start))
continue;
__release_region(iter, start, size);
}
release_mem_region(start, size);
up(&hyperv_mmio_lock);
}
EXPORT_SYMBOL_GPL(vmbus_free_mmio);
/** /**
* vmbus_cpu_number_to_vp_number() - Map CPU to VP. * vmbus_cpu_number_to_vp_number() - Map CPU to VP.
* @cpu_number: CPU number in Linux terms * @cpu_number: CPU number in Linux terms
...@@ -1219,8 +1285,10 @@ static int vmbus_acpi_add(struct acpi_device *device) ...@@ -1219,8 +1285,10 @@ static int vmbus_acpi_add(struct acpi_device *device)
if (ACPI_FAILURE(result)) if (ACPI_FAILURE(result))
continue; continue;
if (hyperv_mmio) if (hyperv_mmio) {
vmbus_reserve_fb();
break; break;
}
} }
ret_val = 0; ret_val = 0;
......
...@@ -78,4 +78,15 @@ config CORESIGHT_QCOM_REPLICATOR ...@@ -78,4 +78,15 @@ config CORESIGHT_QCOM_REPLICATOR
programmable ATB replicator sends the ATB trace stream from the programmable ATB replicator sends the ATB trace stream from the
ETB/ETF to the TPIUi and ETR. ETB/ETF to the TPIUi and ETR.
config CORESIGHT_STM
bool "CoreSight System Trace Macrocell driver"
depends on (ARM && !(CPU_32v3 || CPU_32v4 || CPU_32v4T)) || ARM64
select CORESIGHT_LINKS_AND_SINKS
select STM
help
This driver provides support for hardware assisted software
instrumentation based tracing. This is primarily used for
logging useful software events or data coming from various entities
in the system, possibly running different OSs
endif endif
# #
# Makefile for CoreSight drivers. # Makefile for CoreSight drivers.
# #
obj-$(CONFIG_CORESIGHT) += coresight.o obj-$(CONFIG_CORESIGHT) += coresight.o coresight-etm-perf.o
obj-$(CONFIG_OF) += of_coresight.o obj-$(CONFIG_OF) += of_coresight.o
obj-$(CONFIG_CORESIGHT_LINK_AND_SINK_TMC) += coresight-tmc.o obj-$(CONFIG_CORESIGHT_LINK_AND_SINK_TMC) += coresight-tmc.o \
coresight-tmc-etf.o \
coresight-tmc-etr.o
obj-$(CONFIG_CORESIGHT_SINK_TPIU) += coresight-tpiu.o obj-$(CONFIG_CORESIGHT_SINK_TPIU) += coresight-tpiu.o
obj-$(CONFIG_CORESIGHT_SINK_ETBV10) += coresight-etb10.o obj-$(CONFIG_CORESIGHT_SINK_ETBV10) += coresight-etb10.o
obj-$(CONFIG_CORESIGHT_LINKS_AND_SINKS) += coresight-funnel.o \ obj-$(CONFIG_CORESIGHT_LINKS_AND_SINKS) += coresight-funnel.o \
coresight-replicator.o coresight-replicator.o
obj-$(CONFIG_CORESIGHT_SOURCE_ETM3X) += coresight-etm3x.o coresight-etm-cp14.o \ obj-$(CONFIG_CORESIGHT_SOURCE_ETM3X) += coresight-etm3x.o coresight-etm-cp14.o \
coresight-etm3x-sysfs.o \ coresight-etm3x-sysfs.o
coresight-etm-perf.o obj-$(CONFIG_CORESIGHT_SOURCE_ETM4X) += coresight-etm4x.o \
obj-$(CONFIG_CORESIGHT_SOURCE_ETM4X) += coresight-etm4x.o coresight-etm4x-sysfs.o
obj-$(CONFIG_CORESIGHT_QCOM_REPLICATOR) += coresight-replicator-qcom.o obj-$(CONFIG_CORESIGHT_QCOM_REPLICATOR) += coresight-replicator-qcom.o
obj-$(CONFIG_CORESIGHT_STM) += coresight-stm.o
...@@ -70,26 +70,6 @@ ...@@ -70,26 +70,6 @@
#define ETB_FFSR_BIT 1 #define ETB_FFSR_BIT 1
#define ETB_FRAME_SIZE_WORDS 4 #define ETB_FRAME_SIZE_WORDS 4
/**
* struct cs_buffer - keep track of a recording session' specifics
* @cur: index of the current buffer
* @nr_pages: max number of pages granted to us
* @offset: offset within the current buffer
* @data_size: how much we collected in this run
* @lost: other than zero if we had a HW buffer wrap around
* @snapshot: is this run in snapshot mode
* @data_pages: a handle the ring buffer
*/
struct cs_buffers {
unsigned int cur;
unsigned int nr_pages;
unsigned long offset;
local_t data_size;
local_t lost;
bool snapshot;
void **data_pages;
};
/** /**
* struct etb_drvdata - specifics associated to an ETB component * struct etb_drvdata - specifics associated to an ETB component
* @base: memory mapped base address for this component. * @base: memory mapped base address for this component.
...@@ -440,7 +420,7 @@ static void etb_update_buffer(struct coresight_device *csdev, ...@@ -440,7 +420,7 @@ static void etb_update_buffer(struct coresight_device *csdev,
u32 mask = ~(ETB_FRAME_SIZE_WORDS - 1); u32 mask = ~(ETB_FRAME_SIZE_WORDS - 1);
/* The new read pointer must be frame size aligned */ /* The new read pointer must be frame size aligned */
to_read -= handle->size & mask; to_read = handle->size & mask;
/* /*
* Move the RAM read pointer up, keeping in mind that * Move the RAM read pointer up, keeping in mind that
* everything is in frame size units. * everything is in frame size units.
...@@ -448,7 +428,8 @@ static void etb_update_buffer(struct coresight_device *csdev, ...@@ -448,7 +428,8 @@ static void etb_update_buffer(struct coresight_device *csdev,
read_ptr = (write_ptr + drvdata->buffer_depth) - read_ptr = (write_ptr + drvdata->buffer_depth) -
to_read / ETB_FRAME_SIZE_WORDS; to_read / ETB_FRAME_SIZE_WORDS;
/* Wrap around if need be*/ /* Wrap around if need be*/
read_ptr &= ~(drvdata->buffer_depth - 1); if (read_ptr > (drvdata->buffer_depth - 1))
read_ptr -= drvdata->buffer_depth;
/* let the decoder know we've skipped ahead */ /* let the decoder know we've skipped ahead */
local_inc(&buf->lost); local_inc(&buf->lost);
} }
...@@ -579,47 +560,29 @@ static const struct file_operations etb_fops = { ...@@ -579,47 +560,29 @@ static const struct file_operations etb_fops = {
.llseek = no_llseek, .llseek = no_llseek,
}; };
static ssize_t status_show(struct device *dev, #define coresight_etb10_simple_func(name, offset) \
struct device_attribute *attr, char *buf) coresight_simple_func(struct etb_drvdata, name, offset)
{
unsigned long flags; coresight_etb10_simple_func(rdp, ETB_RAM_DEPTH_REG);
u32 etb_rdr, etb_sr, etb_rrp, etb_rwp; coresight_etb10_simple_func(sts, ETB_STATUS_REG);
u32 etb_trg, etb_cr, etb_ffsr, etb_ffcr; coresight_etb10_simple_func(rrp, ETB_RAM_READ_POINTER);
struct etb_drvdata *drvdata = dev_get_drvdata(dev->parent); coresight_etb10_simple_func(rwp, ETB_RAM_WRITE_POINTER);
coresight_etb10_simple_func(trg, ETB_TRG);
pm_runtime_get_sync(drvdata->dev); coresight_etb10_simple_func(ctl, ETB_CTL_REG);
spin_lock_irqsave(&drvdata->spinlock, flags); coresight_etb10_simple_func(ffsr, ETB_FFSR);
CS_UNLOCK(drvdata->base); coresight_etb10_simple_func(ffcr, ETB_FFCR);
etb_rdr = readl_relaxed(drvdata->base + ETB_RAM_DEPTH_REG); static struct attribute *coresight_etb_mgmt_attrs[] = {
etb_sr = readl_relaxed(drvdata->base + ETB_STATUS_REG); &dev_attr_rdp.attr,
etb_rrp = readl_relaxed(drvdata->base + ETB_RAM_READ_POINTER); &dev_attr_sts.attr,
etb_rwp = readl_relaxed(drvdata->base + ETB_RAM_WRITE_POINTER); &dev_attr_rrp.attr,
etb_trg = readl_relaxed(drvdata->base + ETB_TRG); &dev_attr_rwp.attr,
etb_cr = readl_relaxed(drvdata->base + ETB_CTL_REG); &dev_attr_trg.attr,
etb_ffsr = readl_relaxed(drvdata->base + ETB_FFSR); &dev_attr_ctl.attr,
etb_ffcr = readl_relaxed(drvdata->base + ETB_FFCR); &dev_attr_ffsr.attr,
&dev_attr_ffcr.attr,
CS_LOCK(drvdata->base); NULL,
spin_unlock_irqrestore(&drvdata->spinlock, flags); };
pm_runtime_put(drvdata->dev);
return sprintf(buf,
"Depth:\t\t0x%x\n"
"Status:\t\t0x%x\n"
"RAM read ptr:\t0x%x\n"
"RAM wrt ptr:\t0x%x\n"
"Trigger cnt:\t0x%x\n"
"Control:\t0x%x\n"
"Flush status:\t0x%x\n"
"Flush ctrl:\t0x%x\n",
etb_rdr, etb_sr, etb_rrp, etb_rwp,
etb_trg, etb_cr, etb_ffsr, etb_ffcr);
return -EINVAL;
}
static DEVICE_ATTR_RO(status);
static ssize_t trigger_cntr_show(struct device *dev, static ssize_t trigger_cntr_show(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
...@@ -649,10 +612,23 @@ static DEVICE_ATTR_RW(trigger_cntr); ...@@ -649,10 +612,23 @@ static DEVICE_ATTR_RW(trigger_cntr);
static struct attribute *coresight_etb_attrs[] = { static struct attribute *coresight_etb_attrs[] = {
&dev_attr_trigger_cntr.attr, &dev_attr_trigger_cntr.attr,
&dev_attr_status.attr,
NULL, NULL,
}; };
ATTRIBUTE_GROUPS(coresight_etb);
static const struct attribute_group coresight_etb_group = {
.attrs = coresight_etb_attrs,
};
static const struct attribute_group coresight_etb_mgmt_group = {
.attrs = coresight_etb_mgmt_attrs,
.name = "mgmt",
};
const struct attribute_group *coresight_etb_groups[] = {
&coresight_etb_group,
&coresight_etb_mgmt_group,
NULL,
};
static int etb_probe(struct amba_device *adev, const struct amba_id *id) static int etb_probe(struct amba_device *adev, const struct amba_id *id)
{ {
...@@ -729,7 +705,6 @@ static int etb_probe(struct amba_device *adev, const struct amba_id *id) ...@@ -729,7 +705,6 @@ static int etb_probe(struct amba_device *adev, const struct amba_id *id)
if (ret) if (ret)
goto err_misc_register; goto err_misc_register;
dev_info(dev, "ETB initialized\n");
return 0; return 0;
err_misc_register: err_misc_register:
......
...@@ -1221,26 +1221,19 @@ static struct attribute *coresight_etm_attrs[] = { ...@@ -1221,26 +1221,19 @@ static struct attribute *coresight_etm_attrs[] = {
NULL, NULL,
}; };
#define coresight_simple_func(name, offset) \ #define coresight_etm3x_simple_func(name, offset) \
static ssize_t name##_show(struct device *_dev, \ coresight_simple_func(struct etm_drvdata, name, offset)
struct device_attribute *attr, char *buf) \
{ \ coresight_etm3x_simple_func(etmccr, ETMCCR);
struct etm_drvdata *drvdata = dev_get_drvdata(_dev->parent); \ coresight_etm3x_simple_func(etmccer, ETMCCER);
return scnprintf(buf, PAGE_SIZE, "0x%x\n", \ coresight_etm3x_simple_func(etmscr, ETMSCR);
readl_relaxed(drvdata->base + offset)); \ coresight_etm3x_simple_func(etmidr, ETMIDR);
} \ coresight_etm3x_simple_func(etmcr, ETMCR);
DEVICE_ATTR_RO(name) coresight_etm3x_simple_func(etmtraceidr, ETMTRACEIDR);
coresight_etm3x_simple_func(etmteevr, ETMTEEVR);
coresight_simple_func(etmccr, ETMCCR); coresight_etm3x_simple_func(etmtssvr, ETMTSSCR);
coresight_simple_func(etmccer, ETMCCER); coresight_etm3x_simple_func(etmtecr1, ETMTECR1);
coresight_simple_func(etmscr, ETMSCR); coresight_etm3x_simple_func(etmtecr2, ETMTECR2);
coresight_simple_func(etmidr, ETMIDR);
coresight_simple_func(etmcr, ETMCR);
coresight_simple_func(etmtraceidr, ETMTRACEIDR);
coresight_simple_func(etmteevr, ETMTEEVR);
coresight_simple_func(etmtssvr, ETMTSSCR);
coresight_simple_func(etmtecr1, ETMTECR1);
coresight_simple_func(etmtecr2, ETMTECR2);
static struct attribute *coresight_etm_mgmt_attrs[] = { static struct attribute *coresight_etm_mgmt_attrs[] = {
&dev_attr_etmccr.attr, &dev_attr_etmccr.attr,
......
This diff is collapsed.
...@@ -221,7 +221,6 @@ static int funnel_probe(struct amba_device *adev, const struct amba_id *id) ...@@ -221,7 +221,6 @@ static int funnel_probe(struct amba_device *adev, const struct amba_id *id)
if (IS_ERR(drvdata->csdev)) if (IS_ERR(drvdata->csdev))
return PTR_ERR(drvdata->csdev); return PTR_ERR(drvdata->csdev);
dev_info(dev, "FUNNEL initialized\n");
return 0; return 0;
} }
......
...@@ -37,12 +37,42 @@ ...@@ -37,12 +37,42 @@
#define ETM_MODE_EXCL_KERN BIT(30) #define ETM_MODE_EXCL_KERN BIT(30)
#define ETM_MODE_EXCL_USER BIT(31) #define ETM_MODE_EXCL_USER BIT(31)
#define coresight_simple_func(type, 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)); \
} \
static DEVICE_ATTR_RO(name)
enum cs_mode { enum cs_mode {
CS_MODE_DISABLED, CS_MODE_DISABLED,
CS_MODE_SYSFS, CS_MODE_SYSFS,
CS_MODE_PERF, CS_MODE_PERF,
}; };
/**
* struct cs_buffer - keep track of a recording session' specifics
* @cur: index of the current buffer
* @nr_pages: max number of pages granted to us
* @offset: offset within the current buffer
* @data_size: how much we collected in this run
* @lost: other than zero if we had a HW buffer wrap around
* @snapshot: is this run in snapshot mode
* @data_pages: a handle the ring buffer
*/
struct cs_buffers {
unsigned int cur;
unsigned int nr_pages;
unsigned long offset;
local_t data_size;
local_t lost;
bool snapshot;
void **data_pages;
};
static inline void CS_LOCK(void __iomem *addr) static inline void CS_LOCK(void __iomem *addr)
{ {
do { do {
......
...@@ -114,7 +114,6 @@ static int replicator_probe(struct platform_device *pdev) ...@@ -114,7 +114,6 @@ static int replicator_probe(struct platform_device *pdev)
pm_runtime_put(&pdev->dev); pm_runtime_put(&pdev->dev);
dev_info(dev, "REPLICATOR initialized\n");
return 0; return 0;
out_disable_pm: out_disable_pm:
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/*
* Copyright(C) 2015 Linaro Limited. All rights reserved.
* Author: Mathieu Poirier <mathieu.poirier@linaro.org>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef _CORESIGHT_TMC_H
#define _CORESIGHT_TMC_H
#include <linux/miscdevice.h>
#define TMC_RSZ 0x004
#define TMC_STS 0x00c
#define TMC_RRD 0x010
#define TMC_RRP 0x014
#define TMC_RWP 0x018
#define TMC_TRG 0x01c
#define TMC_CTL 0x020
#define TMC_RWD 0x024
#define TMC_MODE 0x028
#define TMC_LBUFLEVEL 0x02c
#define TMC_CBUFLEVEL 0x030
#define TMC_BUFWM 0x034
#define TMC_RRPHI 0x038
#define TMC_RWPHI 0x03c
#define TMC_AXICTL 0x110
#define TMC_DBALO 0x118
#define TMC_DBAHI 0x11c
#define TMC_FFSR 0x300
#define TMC_FFCR 0x304
#define TMC_PSCR 0x308
#define TMC_ITMISCOP0 0xee0
#define TMC_ITTRFLIN 0xee8
#define TMC_ITATBDATA0 0xeec
#define TMC_ITATBCTR2 0xef0
#define TMC_ITATBCTR1 0xef4
#define TMC_ITATBCTR0 0xef8
/* register description */
/* TMC_CTL - 0x020 */
#define TMC_CTL_CAPT_EN BIT(0)
/* TMC_STS - 0x00C */
#define TMC_STS_TMCREADY_BIT 2
#define TMC_STS_FULL BIT(0)
#define TMC_STS_TRIGGERED BIT(1)
/* TMC_AXICTL - 0x110 */
#define TMC_AXICTL_PROT_CTL_B0 BIT(0)
#define TMC_AXICTL_PROT_CTL_B1 BIT(1)
#define TMC_AXICTL_SCT_GAT_MODE BIT(7)
#define TMC_AXICTL_WR_BURST_16 0xF00
/* TMC_FFCR - 0x304 */
#define TMC_FFCR_FLUSHMAN_BIT 6
#define TMC_FFCR_EN_FMT BIT(0)
#define TMC_FFCR_EN_TI BIT(1)
#define TMC_FFCR_FON_FLIN BIT(4)
#define TMC_FFCR_FON_TRIG_EVT BIT(5)
#define TMC_FFCR_TRIGON_TRIGIN BIT(8)
#define TMC_FFCR_STOP_ON_FLUSH BIT(12)
enum tmc_config_type {
TMC_CONFIG_TYPE_ETB,
TMC_CONFIG_TYPE_ETR,
TMC_CONFIG_TYPE_ETF,
};
enum tmc_mode {
TMC_MODE_CIRCULAR_BUFFER,
TMC_MODE_SOFTWARE_FIFO,
TMC_MODE_HARDWARE_FIFO,
};
enum tmc_mem_intf_width {
TMC_MEM_INTF_WIDTH_32BITS = 1,
TMC_MEM_INTF_WIDTH_64BITS = 2,
TMC_MEM_INTF_WIDTH_128BITS = 4,
TMC_MEM_INTF_WIDTH_256BITS = 8,
};
/**
* struct tmc_drvdata - specifics associated to an TMC component
* @base: memory mapped base address for this component.
* @dev: the device entity associated to this component.
* @csdev: component vitals needed by the framework.
* @miscdev: specifics to handle "/dev/xyz.tmc" entry.
* @spinlock: only one at a time pls.
* @buf: area of memory where trace data get sent.
* @paddr: DMA start location in RAM.
* @vaddr: virtual representation of @paddr.
* @size: @buf size.
* @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.
* @trigger_cntr: amount of words to store after a trigger.
*/
struct tmc_drvdata {
void __iomem *base;
struct device *dev;
struct coresight_device *csdev;
struct miscdevice miscdev;
spinlock_t spinlock;
bool reading;
char *buf;
dma_addr_t paddr;
void __iomem *vaddr;
u32 size;
local_t mode;
enum tmc_config_type config_type;
enum tmc_mem_intf_width memwidth;
u32 trigger_cntr;
};
/* Generic functions */
void tmc_wait_for_tmcready(struct tmc_drvdata *drvdata);
void tmc_flush_and_stop(struct tmc_drvdata *drvdata);
void tmc_enable_hw(struct tmc_drvdata *drvdata);
void tmc_disable_hw(struct tmc_drvdata *drvdata);
/* ETB/ETF functions */
int tmc_read_prepare_etb(struct tmc_drvdata *drvdata);
int tmc_read_unprepare_etb(struct tmc_drvdata *drvdata);
extern const struct coresight_ops tmc_etb_cs_ops;
extern const struct coresight_ops tmc_etf_cs_ops;
/* ETR functions */
int tmc_read_prepare_etr(struct tmc_drvdata *drvdata);
int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata);
extern const struct coresight_ops tmc_etr_cs_ops;
#endif
...@@ -167,7 +167,6 @@ static int tpiu_probe(struct amba_device *adev, const struct amba_id *id) ...@@ -167,7 +167,6 @@ static int tpiu_probe(struct amba_device *adev, const struct amba_id *id)
if (IS_ERR(drvdata->csdev)) if (IS_ERR(drvdata->csdev))
return PTR_ERR(drvdata->csdev); return PTR_ERR(drvdata->csdev);
dev_info(dev, "TPIU initialized\n");
return 0; return 0;
} }
......
This diff is collapsed.
...@@ -71,6 +71,15 @@ static int intel_th_probe(struct device *dev) ...@@ -71,6 +71,15 @@ static int intel_th_probe(struct device *dev)
if (ret) if (ret)
return ret; return ret;
if (thdrv->attr_group) {
ret = sysfs_create_group(&thdev->dev.kobj, thdrv->attr_group);
if (ret) {
thdrv->remove(thdev);
return ret;
}
}
if (thdev->type == INTEL_TH_OUTPUT && if (thdev->type == INTEL_TH_OUTPUT &&
!intel_th_output_assigned(thdev)) !intel_th_output_assigned(thdev))
ret = hubdrv->assign(hub, thdev); ret = hubdrv->assign(hub, thdev);
...@@ -91,6 +100,9 @@ static int intel_th_remove(struct device *dev) ...@@ -91,6 +100,9 @@ static int intel_th_remove(struct device *dev)
return err; return err;
} }
if (thdrv->attr_group)
sysfs_remove_group(&thdev->dev.kobj, thdrv->attr_group);
thdrv->remove(thdev); thdrv->remove(thdev);
if (intel_th_output_assigned(thdev)) { if (intel_th_output_assigned(thdev)) {
...@@ -171,7 +183,14 @@ static DEVICE_ATTR_RO(port); ...@@ -171,7 +183,14 @@ static DEVICE_ATTR_RO(port);
static int intel_th_output_activate(struct intel_th_device *thdev) static int intel_th_output_activate(struct intel_th_device *thdev)
{ {
struct intel_th_driver *thdrv = to_intel_th_driver(thdev->dev.driver); struct intel_th_driver *thdrv =
to_intel_th_driver_or_null(thdev->dev.driver);
if (!thdrv)
return -ENODEV;
if (!try_module_get(thdrv->driver.owner))
return -ENODEV;
if (thdrv->activate) if (thdrv->activate)
return thdrv->activate(thdev); return thdrv->activate(thdev);
...@@ -183,12 +202,18 @@ static int intel_th_output_activate(struct intel_th_device *thdev) ...@@ -183,12 +202,18 @@ static int intel_th_output_activate(struct intel_th_device *thdev)
static void intel_th_output_deactivate(struct intel_th_device *thdev) static void intel_th_output_deactivate(struct intel_th_device *thdev)
{ {
struct intel_th_driver *thdrv = to_intel_th_driver(thdev->dev.driver); struct intel_th_driver *thdrv =
to_intel_th_driver_or_null(thdev->dev.driver);
if (!thdrv)
return;
if (thdrv->deactivate) if (thdrv->deactivate)
thdrv->deactivate(thdev); thdrv->deactivate(thdev);
else else
intel_th_trace_disable(thdev); intel_th_trace_disable(thdev);
module_put(thdrv->driver.owner);
} }
static ssize_t active_show(struct device *dev, struct device_attribute *attr, static ssize_t active_show(struct device *dev, struct device_attribute *attr,
......
...@@ -115,6 +115,7 @@ intel_th_output_assigned(struct intel_th_device *thdev) ...@@ -115,6 +115,7 @@ intel_th_output_assigned(struct intel_th_device *thdev)
* @enable: enable tracing for a given output device * @enable: enable tracing for a given output device
* @disable: disable tracing for a given output device * @disable: disable tracing for a given output device
* @fops: file operations for device nodes * @fops: file operations for device nodes
* @attr_group: attributes provided by the driver
* *
* Callbacks @probe and @remove are required for all device types. * Callbacks @probe and @remove are required for all device types.
* Switch device driver needs to fill in @assign, @enable and @disable * Switch device driver needs to fill in @assign, @enable and @disable
...@@ -139,6 +140,8 @@ struct intel_th_driver { ...@@ -139,6 +140,8 @@ struct intel_th_driver {
void (*deactivate)(struct intel_th_device *thdev); void (*deactivate)(struct intel_th_device *thdev);
/* file_operations for those who want a device node */ /* file_operations for those who want a device node */
const struct file_operations *fops; const struct file_operations *fops;
/* optional attributes */
struct attribute_group *attr_group;
/* source ops */ /* source ops */
int (*set_output)(struct intel_th_device *thdev, int (*set_output)(struct intel_th_device *thdev,
...@@ -148,6 +151,9 @@ struct intel_th_driver { ...@@ -148,6 +151,9 @@ struct intel_th_driver {
#define to_intel_th_driver(_d) \ #define to_intel_th_driver(_d) \
container_of((_d), struct intel_th_driver, driver) container_of((_d), struct intel_th_driver, driver)
#define to_intel_th_driver_or_null(_d) \
((_d) ? to_intel_th_driver(_d) : NULL)
static inline struct intel_th_device * static inline struct intel_th_device *
to_intel_th_hub(struct intel_th_device *thdev) to_intel_th_hub(struct intel_th_device *thdev)
{ {
......
This diff is collapsed.
...@@ -75,6 +75,11 @@ static const struct pci_device_id intel_th_pci_id_table[] = { ...@@ -75,6 +75,11 @@ static const struct pci_device_id intel_th_pci_id_table[] = {
PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0a80), PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0a80),
.driver_data = (kernel_ulong_t)0, .driver_data = (kernel_ulong_t)0,
}, },
{
/* Broxton B-step */
PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x1a8e),
.driver_data = (kernel_ulong_t)0,
},
{ 0 }, { 0 },
}; };
......
...@@ -200,7 +200,6 @@ static int intel_th_pti_probe(struct intel_th_device *thdev) ...@@ -200,7 +200,6 @@ static int intel_th_pti_probe(struct intel_th_device *thdev)
struct resource *res; struct resource *res;
struct pti_device *pti; struct pti_device *pti;
void __iomem *base; void __iomem *base;
int ret;
res = intel_th_device_get_resource(thdev, IORESOURCE_MEM, 0); res = intel_th_device_get_resource(thdev, IORESOURCE_MEM, 0);
if (!res) if (!res)
...@@ -219,10 +218,6 @@ static int intel_th_pti_probe(struct intel_th_device *thdev) ...@@ -219,10 +218,6 @@ static int intel_th_pti_probe(struct intel_th_device *thdev)
read_hw_config(pti); read_hw_config(pti);
ret = sysfs_create_group(&dev->kobj, &pti_output_group);
if (ret)
return ret;
dev_set_drvdata(dev, pti); dev_set_drvdata(dev, pti);
return 0; return 0;
...@@ -237,6 +232,7 @@ static struct intel_th_driver intel_th_pti_driver = { ...@@ -237,6 +232,7 @@ static struct intel_th_driver intel_th_pti_driver = {
.remove = intel_th_pti_remove, .remove = intel_th_pti_remove,
.activate = intel_th_pti_activate, .activate = intel_th_pti_activate,
.deactivate = intel_th_pti_deactivate, .deactivate = intel_th_pti_deactivate,
.attr_group = &pti_output_group,
.driver = { .driver = {
.name = "pti", .name = "pti",
.owner = THIS_MODULE, .owner = THIS_MODULE,
......
This diff is collapsed.
...@@ -46,9 +46,7 @@ static struct stm_data dummy_stm[DUMMY_STM_MAX]; ...@@ -46,9 +46,7 @@ static struct stm_data dummy_stm[DUMMY_STM_MAX];
static int nr_dummies = 4; static int nr_dummies = 4;
module_param(nr_dummies, int, 0600); module_param(nr_dummies, int, 0400);
static unsigned int dummy_stm_nr;
static unsigned int fail_mode; static unsigned int fail_mode;
...@@ -65,12 +63,12 @@ static int dummy_stm_link(struct stm_data *data, unsigned int master, ...@@ -65,12 +63,12 @@ static int dummy_stm_link(struct stm_data *data, unsigned int master,
static int dummy_stm_init(void) static int dummy_stm_init(void)
{ {
int i, ret = -ENOMEM, __nr_dummies = ACCESS_ONCE(nr_dummies); int i, ret = -ENOMEM;
if (__nr_dummies < 0 || __nr_dummies > DUMMY_STM_MAX) if (nr_dummies < 0 || nr_dummies > DUMMY_STM_MAX)
return -EINVAL; return -EINVAL;
for (i = 0; i < __nr_dummies; i++) { for (i = 0; i < nr_dummies; i++) {
dummy_stm[i].name = kasprintf(GFP_KERNEL, "dummy_stm.%d", i); dummy_stm[i].name = kasprintf(GFP_KERNEL, "dummy_stm.%d", i);
if (!dummy_stm[i].name) if (!dummy_stm[i].name)
goto fail_unregister; goto fail_unregister;
...@@ -86,8 +84,6 @@ static int dummy_stm_init(void) ...@@ -86,8 +84,6 @@ static int dummy_stm_init(void)
goto fail_free; goto fail_free;
} }
dummy_stm_nr = __nr_dummies;
return 0; return 0;
fail_unregister: fail_unregister:
...@@ -105,7 +101,7 @@ static void dummy_stm_exit(void) ...@@ -105,7 +101,7 @@ static void dummy_stm_exit(void)
{ {
int i; int i;
for (i = 0; i < dummy_stm_nr; i++) { for (i = 0; i < nr_dummies; i++) {
stm_unregister_device(&dummy_stm[i]); stm_unregister_device(&dummy_stm[i]);
kfree(dummy_stm[i].name); kfree(dummy_stm[i].name);
} }
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
#define PCI_VENDOR_ID_MEN 0x1a88 #define PCI_VENDOR_ID_MEN 0x1a88
#define PCI_DEVICE_ID_MEN_CHAMELEON 0x4d45 #define PCI_DEVICE_ID_MEN_CHAMELEON 0x4d45
#define CHAMELEON_FILENAME_LEN 12
#define CHAMELEONV2_MAGIC 0xabce #define CHAMELEONV2_MAGIC 0xabce
#define CHAM_HEADER_SIZE 0x200 #define CHAM_HEADER_SIZE 0x200
......
This diff is collapsed.
This diff is collapsed.
...@@ -109,7 +109,7 @@ const struct lpddr2_timings *of_get_ddr_timings(struct device_node *np_ddr, ...@@ -109,7 +109,7 @@ const struct lpddr2_timings *of_get_ddr_timings(struct device_node *np_ddr,
struct lpddr2_timings *timings = NULL; struct lpddr2_timings *timings = NULL;
u32 arr_sz = 0, i = 0; u32 arr_sz = 0, i = 0;
struct device_node *np_tim; struct device_node *np_tim;
char *tim_compat; char *tim_compat = NULL;
switch (device_type) { switch (device_type) {
case DDR_TYPE_LPDDR2_S2: case DDR_TYPE_LPDDR2_S2:
......
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