You've already forked linux-rockchip
mirror of
https://github.com/armbian/linux-rockchip.git
synced 2026-01-06 11:08:10 -08:00
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 ...
This commit is contained in:
@@ -6,13 +6,6 @@ Description: (RW) Add/remove a sink from a trace path. There can be multiple
|
||||
source for a single 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
|
||||
Date: November 2014
|
||||
KernelVersion: 3.19
|
||||
@@ -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
|
||||
into the Trace RAM following the trigger event is equal to the
|
||||
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>
|
||||
Description: (R) Print the content of the Peripheral ID3 Register
|
||||
(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
|
||||
Date: April 2015
|
||||
KernelVersion: 4.01
|
||||
|
||||
53
Documentation/ABI/testing/sysfs-bus-coresight-devices-stm
Normal file
53
Documentation/ABI/testing/sysfs-bus-coresight-devices-stm
Normal file
@@ -0,0 +1,53 @@
|
||||
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
|
||||
formatter after a defined number of words have been stored
|
||||
following the trigger event. Additional interface for this
|
||||
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,
|
||||
|
||||
29
Documentation/ABI/testing/sysfs-bus-mcb
Normal file
29
Documentation/ABI/testing/sysfs-bus-mcb
Normal file
@@ -0,0 +1,29 @@
|
||||
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
|
||||
Contact: Alexander Shishkin <alexander.shishkin@linux.intel.com>
|
||||
Description:
|
||||
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.
|
||||
- "arm,coresight-etm3x", "arm,primecell";
|
||||
- "arm,coresight-etm4x", "arm,primecell";
|
||||
- "qcom,coresight-replicator1x", "arm,primecell";
|
||||
- "arm,coresight-stm", "arm,primecell"; [1]
|
||||
|
||||
* reg: physical base address and length of the register
|
||||
set(s) of the component.
|
||||
@@ -36,6 +37,14 @@ its hardware characteristcs.
|
||||
layout using the generic DT graph presentation found in
|
||||
"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
|
||||
non-configurable replicators:
|
||||
|
||||
@@ -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.
|
||||
Last but not least, "struct module *owner" is expected to be set to reflect
|
||||
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.
|
||||
There is no limit on the amount of sinks (nor sources) that can be enabled at
|
||||
@@ -297,3 +297,36 @@ Info Tracing enabled
|
||||
Instruction 13570831 0x8026B584 E28DD00C false ADD sp,sp,#0xc
|
||||
Instruction 0 0x8026B588 E8BD8000 true LDM sp!,{pc}
|
||||
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
|
||||
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
|
||||
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
|
||||
strong pullup, 1 to enable autodetection or 2 to force strong pullup.
|
||||
|
||||
@@ -9843,6 +9843,7 @@ F: drivers/mmc/host/dw_mmc*
|
||||
SYSTEM TRACE MODULE CLASS
|
||||
M: Alexander Shishkin <alexander.shishkin@linux.intel.com>
|
||||
S: Maintained
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/ash/stm.git
|
||||
F: Documentation/trace/stm.txt
|
||||
F: drivers/hwtracing/stm/
|
||||
F: include/linux/stm.h
|
||||
|
||||
@@ -279,8 +279,7 @@ if RTC_LIB=n
|
||||
|
||||
config RTC
|
||||
tristate "Enhanced Real Time Clock Support (legacy PC RTC driver)"
|
||||
depends on !PPC && !PARISC && !IA64 && !M68K && !SPARC && !FRV \
|
||||
&& !ARM && !SUPERH && !S390 && !AVR32 && !BLACKFIN && !UML
|
||||
depends on ALPHA || (MIPS && MACH_LOONGSON64) || MN10300
|
||||
---help---
|
||||
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
|
||||
@@ -585,7 +584,6 @@ config TELCLOCK
|
||||
|
||||
config DEVPORT
|
||||
bool
|
||||
depends on !M68K
|
||||
depends on ISA || PCI
|
||||
default y
|
||||
|
||||
|
||||
@@ -81,7 +81,6 @@ static int xilly_map_single_of(struct xilly_endpoint *ep,
|
||||
{
|
||||
dma_addr_t addr;
|
||||
struct xilly_mapping *this;
|
||||
int rc;
|
||||
|
||||
this = kzalloc(sizeof(*this), GFP_KERNEL);
|
||||
if (!this)
|
||||
@@ -101,15 +100,7 @@ static int xilly_map_single_of(struct xilly_endpoint *ep,
|
||||
|
||||
*ret_dma_handle = addr;
|
||||
|
||||
rc = devm_add_action(ep->dev, xilly_of_unmap, this);
|
||||
|
||||
if (rc) {
|
||||
dma_unmap_single(ep->dev, addr, size, direction);
|
||||
kfree(this);
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return devm_add_action_or_reset(ep->dev, xilly_of_unmap, this);
|
||||
}
|
||||
|
||||
static struct xilly_endpoint_hardware of_hw = {
|
||||
|
||||
@@ -98,7 +98,6 @@ static int xilly_map_single_pci(struct xilly_endpoint *ep,
|
||||
int pci_direction;
|
||||
dma_addr_t addr;
|
||||
struct xilly_mapping *this;
|
||||
int rc;
|
||||
|
||||
this = kzalloc(sizeof(*this), GFP_KERNEL);
|
||||
if (!this)
|
||||
@@ -120,14 +119,7 @@ static int xilly_map_single_pci(struct xilly_endpoint *ep,
|
||||
|
||||
*ret_dma_handle = addr;
|
||||
|
||||
rc = devm_add_action(ep->dev, xilly_pci_unmap, this);
|
||||
if (rc) {
|
||||
pci_unmap_single(ep->pdev, addr, size, pci_direction);
|
||||
kfree(this);
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return devm_add_action_or_reset(ep->dev, xilly_pci_unmap, this);
|
||||
}
|
||||
|
||||
static struct xilly_endpoint_hardware pci_hw = {
|
||||
|
||||
@@ -597,27 +597,55 @@ static void init_vp_index(struct vmbus_channel *channel, u16 dev_type)
|
||||
|
||||
static void vmbus_wait_for_unload(void)
|
||||
{
|
||||
int cpu = smp_processor_id();
|
||||
void *page_addr = hv_context.synic_message_page[cpu];
|
||||
struct hv_message *msg = (struct hv_message *)page_addr +
|
||||
VMBUS_MESSAGE_SINT;
|
||||
int cpu;
|
||||
void *page_addr;
|
||||
struct hv_message *msg;
|
||||
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) {
|
||||
if (READ_ONCE(msg->header.message_type) == HVMSG_NONE) {
|
||||
mdelay(10);
|
||||
continue;
|
||||
if (completion_done(&vmbus_connection.unload_event))
|
||||
break;
|
||||
|
||||
for_each_online_cpu(cpu) {
|
||||
page_addr = hv_context.synic_message_page[cpu];
|
||||
msg = (struct hv_message *)page_addr +
|
||||
VMBUS_MESSAGE_SINT;
|
||||
|
||||
message_type = READ_ONCE(msg->header.message_type);
|
||||
if (message_type == HVMSG_NONE)
|
||||
continue;
|
||||
|
||||
hdr = (struct vmbus_channel_message_header *)
|
||||
msg->u.payload;
|
||||
|
||||
if (hdr->msgtype == CHANNELMSG_UNLOAD_RESPONSE)
|
||||
complete(&vmbus_connection.unload_event);
|
||||
|
||||
vmbus_signal_eom(msg, message_type);
|
||||
}
|
||||
|
||||
hdr = (struct vmbus_channel_message_header *)msg->u.payload;
|
||||
if (hdr->msgtype == CHANNELMSG_UNLOAD_RESPONSE)
|
||||
unloaded = true;
|
||||
mdelay(10);
|
||||
}
|
||||
|
||||
vmbus_signal_eom(msg);
|
||||
|
||||
if (unloaded)
|
||||
break;
|
||||
/*
|
||||
* 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)
|
||||
|
||||
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)
|
||||
* If the pfn range we are dealing with is not in the current
|
||||
* "hot add block", move on.
|
||||
*/
|
||||
if ((start_pfn >= has->end_pfn))
|
||||
if (start_pfn < has->start_pfn || start_pfn >= has->end_pfn)
|
||||
continue;
|
||||
/*
|
||||
* If the current hot add-request extends beyond
|
||||
@@ -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
|
||||
* "hot add block", move on.
|
||||
*/
|
||||
if ((start_pfn >= has->end_pfn))
|
||||
if (start_pfn < has->start_pfn || start_pfn >= has->end_pfn)
|
||||
continue;
|
||||
|
||||
old_covered_state = has->covered_end_pfn;
|
||||
@@ -1400,6 +1400,7 @@ static void balloon_onchannelcallback(void *context)
|
||||
* This is a normal hot-add request specifying
|
||||
* hot-add memory.
|
||||
*/
|
||||
dm->host_specified_ha_region = false;
|
||||
ha_pg_range = &ha_msg->range;
|
||||
dm->ha_wrk.ha_page_range = *ha_pg_range;
|
||||
dm->ha_wrk.ha_region_range.page_range = 0;
|
||||
|
||||
@@ -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_timeout_func(struct work_struct *dummy);
|
||||
static void kvp_host_handshake_func(struct work_struct *dummy);
|
||||
static void kvp_register(int);
|
||||
|
||||
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 const char kvp_devname[] = "vmbus/hv_kvp";
|
||||
@@ -130,6 +132,11 @@ static void kvp_timeout_func(struct work_struct *dummy)
|
||||
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)
|
||||
{
|
||||
switch (msg->kvp_hdr.operation) {
|
||||
@@ -154,6 +161,12 @@ static int kvp_handle_handshake(struct hv_kvp_msg *msg)
|
||||
pr_debug("KVP: userspace daemon ver. %d registered\n",
|
||||
KVP_OP_REGISTER);
|
||||
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;
|
||||
@@ -594,7 +607,22 @@ void hv_kvp_onchannelcallback(void *context)
|
||||
struct icmsg_negotiate *negop = NULL;
|
||||
int util_fw_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)
|
||||
return;
|
||||
|
||||
@@ -672,6 +700,8 @@ void hv_kvp_onchannelcallback(void *context)
|
||||
vmbus_sendpacket(channel, recv_buffer,
|
||||
recvlen, requestid,
|
||||
VM_PKT_DATA_INBAND, 0);
|
||||
|
||||
host_negotiatied = NEGO_FINISHED;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -708,6 +738,7 @@ hv_kvp_init(struct hv_util_service *srv)
|
||||
void hv_kvp_deinit(void)
|
||||
{
|
||||
kvp_transaction.state = HVUTIL_DEVICE_DYING;
|
||||
cancel_delayed_work_sync(&kvp_host_handshake_work);
|
||||
cancel_delayed_work_sync(&kvp_timeout_work);
|
||||
cancel_work_sync(&kvp_sendkey_work);
|
||||
hvutil_transport_destroy(hvt);
|
||||
|
||||
@@ -35,6 +35,11 @@
|
||||
*/
|
||||
#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
|
||||
* is set by CPUID(HVCPUID_VERSION_FEATURES).
|
||||
@@ -620,9 +625,21 @@ extern struct vmbus_channel_message_table_entry
|
||||
channel_message_table[CHANNELMSG_COUNT];
|
||||
|
||||
/* 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
|
||||
@@ -667,8 +684,6 @@ void vmbus_disconnect(void);
|
||||
|
||||
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_msg_dpc(unsigned long data);
|
||||
|
||||
|
||||
@@ -33,25 +33,21 @@
|
||||
void hv_begin_read(struct hv_ring_buffer_info *rbi)
|
||||
{
|
||||
rbi->ring_buffer->interrupt_mask = 1;
|
||||
mb();
|
||||
virt_mb();
|
||||
}
|
||||
|
||||
u32 hv_end_read(struct hv_ring_buffer_info *rbi)
|
||||
{
|
||||
u32 read;
|
||||
u32 write;
|
||||
|
||||
rbi->ring_buffer->interrupt_mask = 0;
|
||||
mb();
|
||||
virt_mb();
|
||||
|
||||
/*
|
||||
* Now check to see if the ring buffer is still empty.
|
||||
* If it is not, we raced and we need to process new
|
||||
* incoming messages.
|
||||
*/
|
||||
hv_get_ringbuffer_availbytes(rbi, &read, &write);
|
||||
|
||||
return read;
|
||||
return hv_get_bytes_to_read(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)
|
||||
{
|
||||
mb();
|
||||
if (rbi->ring_buffer->interrupt_mask)
|
||||
virt_mb();
|
||||
if (READ_ONCE(rbi->ring_buffer->interrupt_mask))
|
||||
return false;
|
||||
|
||||
/* check interrupt_mask before read_index */
|
||||
rmb();
|
||||
virt_rmb();
|
||||
/*
|
||||
* This is the only case we need to signal when the
|
||||
* ring transitions from being empty to non-empty.
|
||||
*/
|
||||
if (old_write == 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)
|
||||
if (old_write == READ_ONCE(rbi->ring_buffer->read_index))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
@@ -188,17 +132,9 @@ hv_set_next_read_location(struct hv_ring_buffer_info *ring_info,
|
||||
u32 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. */
|
||||
static inline u32
|
||||
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,
|
||||
{
|
||||
int i = 0;
|
||||
u32 bytes_avail_towrite;
|
||||
u32 bytes_avail_toread;
|
||||
u32 totalbytes_towrite = 0;
|
||||
|
||||
u32 next_write_location;
|
||||
@@ -348,9 +283,7 @@ int hv_ringbuffer_write(struct hv_ring_buffer_info *outring_info,
|
||||
if (lock)
|
||||
spin_lock_irqsave(&outring_info->ring_lock, flags);
|
||||
|
||||
hv_get_ringbuffer_availbytes(outring_info,
|
||||
&bytes_avail_toread,
|
||||
&bytes_avail_towrite);
|
||||
bytes_avail_towrite = hv_get_bytes_to_write(outring_info);
|
||||
|
||||
/*
|
||||
* 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,
|
||||
sizeof(u64));
|
||||
|
||||
/* Issue a full memory barrier before updating the write index */
|
||||
mb();
|
||||
virt_mb();
|
||||
|
||||
/* Now, update the 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,
|
||||
void *buffer, u32 buflen, u32 *buffer_actual_len,
|
||||
u64 *requestid, bool *signal, bool raw)
|
||||
{
|
||||
u32 bytes_avail_towrite;
|
||||
u32 bytes_avail_toread;
|
||||
u32 next_read_location = 0;
|
||||
u64 prev_indices = 0;
|
||||
@@ -417,10 +349,7 @@ int hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info,
|
||||
*buffer_actual_len = 0;
|
||||
*requestid = 0;
|
||||
|
||||
hv_get_ringbuffer_availbytes(inring_info,
|
||||
&bytes_avail_toread,
|
||||
&bytes_avail_towrite);
|
||||
|
||||
bytes_avail_toread = hv_get_bytes_to_read(inring_info);
|
||||
/* Make sure there is something to read */
|
||||
if (bytes_avail_toread < sizeof(desc)) {
|
||||
/*
|
||||
@@ -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
|
||||
* is updated.
|
||||
*/
|
||||
mb();
|
||||
virt_mb();
|
||||
|
||||
/* Update the read index */
|
||||
hv_set_next_read_location(inring_info, next_read_location);
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/screen_info.h>
|
||||
#include <linux/kdebug.h>
|
||||
#include <linux/efi.h>
|
||||
#include "hyperv_vmbus.h"
|
||||
|
||||
static struct acpi_device *hv_acpi_dev;
|
||||
@@ -101,7 +102,10 @@ static struct notifier_block hyperv_panic_block = {
|
||||
.notifier_call = hyperv_panic_event,
|
||||
};
|
||||
|
||||
static const char *fb_mmio_name = "fb_range";
|
||||
static struct resource *fb_mmio;
|
||||
struct resource *hyperv_mmio;
|
||||
DEFINE_SEMAPHORE(hyperv_mmio_lock);
|
||||
|
||||
static int vmbus_exists(void)
|
||||
{
|
||||
@@ -708,7 +712,7 @@ static void hv_process_timer_expiration(struct hv_message *msg, int cpu)
|
||||
if (dev->event_handler)
|
||||
dev->event_handler(dev);
|
||||
|
||||
vmbus_signal_eom(msg);
|
||||
vmbus_signal_eom(msg, HVMSG_TIMER_EXPIRED);
|
||||
}
|
||||
|
||||
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_table_entry *entry;
|
||||
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 */
|
||||
return;
|
||||
|
||||
@@ -746,7 +751,7 @@ void vmbus_on_msg_dpc(unsigned long data)
|
||||
entry->message_handler(hdr);
|
||||
|
||||
msg_handled:
|
||||
vmbus_signal_eom(msg);
|
||||
vmbus_signal_eom(msg, message_type);
|
||||
}
|
||||
|
||||
static void vmbus_isr(void)
|
||||
@@ -1048,7 +1053,6 @@ static acpi_status vmbus_walk_resources(struct acpi_resource *res, void *ctx)
|
||||
new_res->end = end;
|
||||
|
||||
/*
|
||||
* Stick ranges from higher in address space at the front of the list.
|
||||
* If two ranges are adjacent, merge them.
|
||||
*/
|
||||
do {
|
||||
@@ -1069,7 +1073,7 @@ static acpi_status vmbus_walk_resources(struct acpi_resource *res, void *ctx)
|
||||
break;
|
||||
}
|
||||
|
||||
if ((*old_res)->end < new_res->start) {
|
||||
if ((*old_res)->start > new_res->end) {
|
||||
new_res->sibling = *old_res;
|
||||
if (prev_res)
|
||||
(*prev_res)->sibling = new_res;
|
||||
@@ -1091,6 +1095,12 @@ static int vmbus_acpi_remove(struct acpi_device *device)
|
||||
struct resource *next_res;
|
||||
|
||||
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) {
|
||||
next_res = cur_res->sibling;
|
||||
kfree(cur_res);
|
||||
@@ -1100,6 +1110,30 @@ static int vmbus_acpi_remove(struct acpi_device *device)
|
||||
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.
|
||||
* @new: If successful, supplied a pointer to the
|
||||
@@ -1128,11 +1162,33 @@ int vmbus_allocate_mmio(struct resource **new, struct hv_device *device_obj,
|
||||
resource_size_t size, resource_size_t align,
|
||||
bool fb_overlap_ok)
|
||||
{
|
||||
struct resource *iter;
|
||||
resource_size_t range_min, range_max, start, local_min, local_max;
|
||||
struct resource *iter, *shadow;
|
||||
resource_size_t range_min, range_max, start;
|
||||
const char *dev_n = dev_name(&device_obj->device);
|
||||
u32 fb_end = screen_info.lfb_base + (screen_info.lfb_size << 1);
|
||||
int i;
|
||||
int retval;
|
||||
|
||||
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) {
|
||||
if ((iter->start >= max) || (iter->end <= min))
|
||||
@@ -1140,45 +1196,55 @@ int vmbus_allocate_mmio(struct resource **new, struct hv_device *device_obj,
|
||||
|
||||
range_min = iter->start;
|
||||
range_max = iter->end;
|
||||
start = (range_min + align - 1) & ~(align - 1);
|
||||
for (; start + size - 1 <= range_max; start += align) {
|
||||
shadow = __request_region(iter, start, size, NULL,
|
||||
IORESOURCE_BUSY);
|
||||
if (!shadow)
|
||||
continue;
|
||||
|
||||
/* If this range overlaps the frame buffer, split it into
|
||||
two tries. */
|
||||
for (i = 0; i < 2; i++) {
|
||||
local_min = range_min;
|
||||
local_max = range_max;
|
||||
if (fb_overlap_ok || (range_min >= fb_end) ||
|
||||
(range_max <= screen_info.lfb_base)) {
|
||||
i++;
|
||||
} else {
|
||||
if ((range_min <= screen_info.lfb_base) &&
|
||||
(range_max >= screen_info.lfb_base)) {
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
*new = request_mem_region_exclusive(start, size, dev_n);
|
||||
if (*new) {
|
||||
shadow->name = (char *)*new;
|
||||
retval = 0;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
start = (local_min + align - 1) & ~(align - 1);
|
||||
for (; start + size - 1 <= local_max; start += align) {
|
||||
*new = request_mem_region_exclusive(start, size,
|
||||
dev_n);
|
||||
if (*new)
|
||||
return 0;
|
||||
}
|
||||
__release_region(iter, start, size);
|
||||
}
|
||||
}
|
||||
|
||||
return -ENXIO;
|
||||
exit:
|
||||
up(&hyperv_mmio_lock);
|
||||
return retval;
|
||||
}
|
||||
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.
|
||||
* @cpu_number: CPU number in Linux terms
|
||||
@@ -1219,8 +1285,10 @@ static int vmbus_acpi_add(struct acpi_device *device)
|
||||
|
||||
if (ACPI_FAILURE(result))
|
||||
continue;
|
||||
if (hyperv_mmio)
|
||||
if (hyperv_mmio) {
|
||||
vmbus_reserve_fb();
|
||||
break;
|
||||
}
|
||||
}
|
||||
ret_val = 0;
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user