diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-10-03 22:57:49 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-10-03 22:57:49 -0400 |
commit | 7a53eea1f7b527fd3b6d7ca992914840981afe99 (patch) | |
tree | 35dfd7e14d5c44ae2d34e470aaaa68dbfec39324 | |
parent | 597f03f9d133e9837d00965016170271d4f87dcf (diff) | |
parent | c9fef1cc3dd3677633e6fd6ea5bd7ef3b741fab3 (diff) |
Merge tag 'char-misc-4.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc
Pull char/misc driver updates from Greg KH:
"Here's the "big" char and misc driver update for 4.9-rc1.
Lots of little things here, all over the driver tree for subsystems
that flow through me. Nothing major that I can discern, full details
are in the shortlog.
All have been in the linux-next tree with no reported issues"
* tag 'char-misc-4.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (144 commits)
drivers/misc/hpilo: Changes to support new security states in iLO5 FW
at25: fix debug and error messaging
misc/genwqe: ensure zero initialization
vme: fake: remove unexpected unlock in fake_master_set()
vme: fake: mark symbols static where possible
spmi: pmic-arb: Return an error code if sanity check fails
Drivers: hv: get rid of id in struct vmbus_channel
Drivers: hv: make VMBus bus ids persistent
mcb: Add a dma_device to mcb_device
mcb: Enable PCI bus mastering by default
mei: stop the stall timer worker if not needed
clk: probe common clock drivers earlier
vme: fake: fix build for 64-bit dma_addr_t
ttyprintk: Neaten and simplify printing
mei: me: add kaby point device ids
coresight: tmc: mark symbols static where possible
coresight: perf: deal with error condition properly
Drivers: hv: hv_util: Avoid dynamic allocation in time synch
fpga manager: Add hardware dependency to Zynq driver
Drivers: hv: utils: Support TimeSync version 4.0 protocol samples.
...
129 files changed, 4040 insertions, 2805 deletions
@@ -1944,6 +1944,11 @@ E: kraxel@bytesex.org | |||
1944 | E: kraxel@suse.de | 1944 | E: kraxel@suse.de |
1945 | D: video4linux, bttv, vesafb, some scsi, misc fixes | 1945 | D: video4linux, bttv, vesafb, some scsi, misc fixes |
1946 | 1946 | ||
1947 | N: Hans J. Koch | ||
1948 | D: USERSPACE I/O, MAX6650 | ||
1949 | D: Hans passed away in June 2016, and will be greatly missed. | ||
1950 | W: https://lwn.net/Articles/691000/ | ||
1951 | |||
1947 | N: Harald Koenig | 1952 | N: Harald Koenig |
1948 | E: koenig@tat.physik.uni-tuebingen.de | 1953 | E: koenig@tat.physik.uni-tuebingen.de |
1949 | D: XFree86 (S3), DCF77, some kernel hacks and fixes | 1954 | D: XFree86 (S3), DCF77, some kernel hacks and fixes |
diff --git a/Documentation/ABI/testing/sysfs-class-mic.txt b/Documentation/ABI/testing/sysfs-class-mic.txt index d45eed2bf128..6ef682603179 100644 --- a/Documentation/ABI/testing/sysfs-class-mic.txt +++ b/Documentation/ABI/testing/sysfs-class-mic.txt | |||
@@ -153,7 +153,7 @@ Description: | |||
153 | 153 | ||
154 | What: /sys/class/mic/mic(x)/heartbeat_enable | 154 | What: /sys/class/mic/mic(x)/heartbeat_enable |
155 | Date: March 2015 | 155 | Date: March 2015 |
156 | KernelVersion: 3.20 | 156 | KernelVersion: 4.4 |
157 | Contact: Ashutosh Dixit <ashutosh.dixit@intel.com> | 157 | Contact: Ashutosh Dixit <ashutosh.dixit@intel.com> |
158 | Description: | 158 | Description: |
159 | The MIC drivers detect and inform user space about card crashes | 159 | The MIC drivers detect and inform user space about card crashes |
diff --git a/Documentation/ABI/testing/sysfs-i2c-bmp085 b/Documentation/ABI/testing/sysfs-i2c-bmp085 deleted file mode 100644 index 585962ad0465..000000000000 --- a/Documentation/ABI/testing/sysfs-i2c-bmp085 +++ /dev/null | |||
@@ -1,31 +0,0 @@ | |||
1 | What: /sys/bus/i2c/devices/<busnum>-<devaddr>/pressure0_input | ||
2 | Date: June 2010 | ||
3 | Contact: Christoph Mair <christoph.mair@gmail.com> | ||
4 | Description: Start a pressure measurement and read the result. Values | ||
5 | represent the ambient air pressure in pascal (0.01 millibar). | ||
6 | |||
7 | Reading: returns the current air pressure. | ||
8 | |||
9 | |||
10 | What: /sys/bus/i2c/devices/<busnum>-<devaddr>/temp0_input | ||
11 | Date: June 2010 | ||
12 | Contact: Christoph Mair <christoph.mair@gmail.com> | ||
13 | Description: Measure the ambient temperature. The returned value represents | ||
14 | the ambient temperature in units of 0.1 degree celsius. | ||
15 | |||
16 | Reading: returns the current temperature. | ||
17 | |||
18 | |||
19 | What: /sys/bus/i2c/devices/<busnum>-<devaddr>/oversampling | ||
20 | Date: June 2010 | ||
21 | Contact: Christoph Mair <christoph.mair@gmail.com> | ||
22 | Description: Tell the bmp085 to use more samples to calculate a pressure | ||
23 | value. When writing to this file the chip will use 2^x samples | ||
24 | to calculate the next pressure value with x being the value | ||
25 | written. Using this feature will decrease RMS noise and | ||
26 | increase the measurement time. | ||
27 | |||
28 | Reading: returns the current oversampling setting. | ||
29 | |||
30 | Writing: sets a new oversampling setting. | ||
31 | Accepted values: 0..3. | ||
diff --git a/Documentation/devicetree/bindings/nvmem/rockchip-efuse.txt b/Documentation/devicetree/bindings/nvmem/rockchip-efuse.txt index 8f86ab3b1046..94aeeeabadd5 100644 --- a/Documentation/devicetree/bindings/nvmem/rockchip-efuse.txt +++ b/Documentation/devicetree/bindings/nvmem/rockchip-efuse.txt | |||
@@ -1,11 +1,20 @@ | |||
1 | = Rockchip eFuse device tree bindings = | 1 | = Rockchip eFuse device tree bindings = |
2 | 2 | ||
3 | Required properties: | 3 | Required properties: |
4 | - compatible: Should be "rockchip,rockchip-efuse" | 4 | - compatible: Should be one of the following. |
5 | - "rockchip,rk3066a-efuse" - for RK3066a SoCs. | ||
6 | - "rockchip,rk3188-efuse" - for RK3188 SoCs. | ||
7 | - "rockchip,rk3288-efuse" - for RK3288 SoCs. | ||
8 | - "rockchip,rk3399-efuse" - for RK3399 SoCs. | ||
5 | - reg: Should contain the registers location and exact eFuse size | 9 | - reg: Should contain the registers location and exact eFuse size |
6 | - clocks: Should be the clock id of eFuse | 10 | - clocks: Should be the clock id of eFuse |
7 | - clock-names: Should be "pclk_efuse" | 11 | - clock-names: Should be "pclk_efuse" |
8 | 12 | ||
13 | Deprecated properties: | ||
14 | - compatible: "rockchip,rockchip-efuse" | ||
15 | Old efuse compatible value compatible to rk3066a, rk3188 and rk3288 | ||
16 | efuses | ||
17 | |||
9 | = Data cells = | 18 | = Data cells = |
10 | Are child nodes of eFuse, bindings of which as described in | 19 | Are child nodes of eFuse, bindings of which as described in |
11 | bindings/nvmem/nvmem.txt | 20 | bindings/nvmem/nvmem.txt |
@@ -13,7 +22,7 @@ bindings/nvmem/nvmem.txt | |||
13 | Example: | 22 | Example: |
14 | 23 | ||
15 | efuse: efuse@ffb40000 { | 24 | efuse: efuse@ffb40000 { |
16 | compatible = "rockchip,rockchip-efuse"; | 25 | compatible = "rockchip,rk3288-efuse"; |
17 | reg = <0xffb40000 0x20>; | 26 | reg = <0xffb40000 0x20>; |
18 | #address-cells = <1>; | 27 | #address-cells = <1>; |
19 | #size-cells = <1>; | 28 | #size-cells = <1>; |
diff --git a/Documentation/vme_api.txt b/Documentation/vme_api.txt index ca5b82797f6c..90006550f485 100644 --- a/Documentation/vme_api.txt +++ b/Documentation/vme_api.txt | |||
@@ -8,13 +8,14 @@ As with other subsystems within the Linux kernel, VME device drivers register | |||
8 | with the VME subsystem, typically called from the devices init routine. This is | 8 | with the VME subsystem, typically called from the devices init routine. This is |
9 | achieved via a call to the following function: | 9 | achieved via a call to the following function: |
10 | 10 | ||
11 | int vme_register_driver (struct vme_driver *driver); | 11 | int vme_register_driver (struct vme_driver *driver, unsigned int ndevs); |
12 | 12 | ||
13 | If driver registration is successful this function returns zero, if an error | 13 | If driver registration is successful this function returns zero, if an error |
14 | occurred a negative error code will be returned. | 14 | occurred a negative error code will be returned. |
15 | 15 | ||
16 | A pointer to a structure of type 'vme_driver' must be provided to the | 16 | A pointer to a structure of type 'vme_driver' must be provided to the |
17 | registration function. The structure is as follows: | 17 | registration function. Along with ndevs, which is the number of devices your |
18 | driver is able to support. The structure is as follows: | ||
18 | 19 | ||
19 | struct vme_driver { | 20 | struct vme_driver { |
20 | struct list_head node; | 21 | struct list_head node; |
@@ -32,8 +33,8 @@ At the minimum, the '.name', '.match' and '.probe' elements of this structure | |||
32 | should be correctly set. The '.name' element is a pointer to a string holding | 33 | should be correctly set. The '.name' element is a pointer to a string holding |
33 | the device driver's name. | 34 | the device driver's name. |
34 | 35 | ||
35 | The '.match' function allows controlling the number of devices that need to | 36 | The '.match' function allows control over which VME devices should be registered |
36 | be registered. The match function should return 1 if a device should be | 37 | with the driver. The match function should return 1 if a device should be |
37 | probed and 0 otherwise. This example match function (from vme_user.c) limits | 38 | probed and 0 otherwise. This example match function (from vme_user.c) limits |
38 | the number of devices probed to one: | 39 | the number of devices probed to one: |
39 | 40 | ||
@@ -385,13 +386,13 @@ location monitor location. Each location monitor can monitor a number of | |||
385 | adjacent locations: | 386 | adjacent locations: |
386 | 387 | ||
387 | int vme_lm_attach(struct vme_resource *res, int num, | 388 | int vme_lm_attach(struct vme_resource *res, int num, |
388 | void (*callback)(int)); | 389 | void (*callback)(void *)); |
389 | 390 | ||
390 | int vme_lm_detach(struct vme_resource *res, int num); | 391 | int vme_lm_detach(struct vme_resource *res, int num); |
391 | 392 | ||
392 | The callback function is declared as follows. | 393 | The callback function is declared as follows. |
393 | 394 | ||
394 | void callback(int num); | 395 | void callback(void *data); |
395 | 396 | ||
396 | 397 | ||
397 | Slot Detection | 398 | Slot Detection |
diff --git a/MAINTAINERS b/MAINTAINERS index bbfe20ca52b3..154782568de2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -7458,9 +7458,8 @@ F: Documentation/hwmon/max20751 | |||
7458 | F: drivers/hwmon/max20751.c | 7458 | F: drivers/hwmon/max20751.c |
7459 | 7459 | ||
7460 | MAX6650 HARDWARE MONITOR AND FAN CONTROLLER DRIVER | 7460 | MAX6650 HARDWARE MONITOR AND FAN CONTROLLER DRIVER |
7461 | M: "Hans J. Koch" <hjk@hansjkoch.de> | ||
7462 | L: linux-hwmon@vger.kernel.org | 7461 | L: linux-hwmon@vger.kernel.org |
7463 | S: Maintained | 7462 | S: Orphan |
7464 | F: Documentation/hwmon/max6650 | 7463 | F: Documentation/hwmon/max6650 |
7465 | F: drivers/hwmon/max6650.c | 7464 | F: drivers/hwmon/max6650.c |
7466 | 7465 | ||
@@ -12418,7 +12417,6 @@ F: fs/hostfs/ | |||
12418 | F: fs/hppfs/ | 12417 | F: fs/hppfs/ |
12419 | 12418 | ||
12420 | USERSPACE I/O (UIO) | 12419 | USERSPACE I/O (UIO) |
12421 | M: "Hans J. Koch" <hjk@hansjkoch.de> | ||
12422 | M: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 12420 | M: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
12423 | S: Maintained | 12421 | S: Maintained |
12424 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc.git | 12422 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc.git |
diff --git a/arch/arm/common/bL_switcher_dummy_if.c b/arch/arm/common/bL_switcher_dummy_if.c index 3f47f1203c6b..6053f64c3752 100644 --- a/arch/arm/common/bL_switcher_dummy_if.c +++ b/arch/arm/common/bL_switcher_dummy_if.c | |||
@@ -56,16 +56,4 @@ static struct miscdevice bL_switcher_device = { | |||
56 | "b.L_switcher", | 56 | "b.L_switcher", |
57 | &bL_switcher_fops | 57 | &bL_switcher_fops |
58 | }; | 58 | }; |
59 | 59 | module_misc_device(bL_switcher_device); | |
60 | static int __init bL_switcher_dummy_if_init(void) | ||
61 | { | ||
62 | return misc_register(&bL_switcher_device); | ||
63 | } | ||
64 | |||
65 | static void __exit bL_switcher_dummy_if_exit(void) | ||
66 | { | ||
67 | misc_deregister(&bL_switcher_device); | ||
68 | } | ||
69 | |||
70 | module_init(bL_switcher_dummy_if_init); | ||
71 | module_exit(bL_switcher_dummy_if_exit); | ||
diff --git a/arch/blackfin/mach-bf561/coreb.c b/arch/blackfin/mach-bf561/coreb.c index 78ecb50bafc8..8a2543c654b3 100644 --- a/arch/blackfin/mach-bf561/coreb.c +++ b/arch/blackfin/mach-bf561/coreb.c | |||
@@ -59,18 +59,7 @@ static struct miscdevice coreb_dev = { | |||
59 | .name = "coreb", | 59 | .name = "coreb", |
60 | .fops = &coreb_fops, | 60 | .fops = &coreb_fops, |
61 | }; | 61 | }; |
62 | 62 | module_misc_device(coreb_dev); | |
63 | static int __init bf561_coreb_init(void) | ||
64 | { | ||
65 | return misc_register(&coreb_dev); | ||
66 | } | ||
67 | module_init(bf561_coreb_init); | ||
68 | |||
69 | static void __exit bf561_coreb_exit(void) | ||
70 | { | ||
71 | misc_deregister(&coreb_dev); | ||
72 | } | ||
73 | module_exit(bf561_coreb_exit); | ||
74 | 63 | ||
75 | MODULE_AUTHOR("Bas Vermeulen <bvermeul@blackstar.xs4all.nl>"); | 64 | MODULE_AUTHOR("Bas Vermeulen <bvermeul@blackstar.xs4all.nl>"); |
76 | MODULE_DESCRIPTION("BF561 Core B Support"); | 65 | MODULE_DESCRIPTION("BF561 Core B Support"); |
diff --git a/arch/um/drivers/harddog_kern.c b/arch/um/drivers/harddog_kern.c index 2d0266d0254d..3282787bbcfb 100644 --- a/arch/um/drivers/harddog_kern.c +++ b/arch/um/drivers/harddog_kern.c | |||
@@ -175,27 +175,4 @@ static struct miscdevice harddog_miscdev = { | |||
175 | .name = "watchdog", | 175 | .name = "watchdog", |
176 | .fops = &harddog_fops, | 176 | .fops = &harddog_fops, |
177 | }; | 177 | }; |
178 | 178 | module_misc_device(harddog_miscdev); | |
179 | static char banner[] __initdata = KERN_INFO "UML Watchdog Timer\n"; | ||
180 | |||
181 | static int __init harddog_init(void) | ||
182 | { | ||
183 | int ret; | ||
184 | |||
185 | ret = misc_register(&harddog_miscdev); | ||
186 | |||
187 | if (ret) | ||
188 | return ret; | ||
189 | |||
190 | printk(banner); | ||
191 | |||
192 | return 0; | ||
193 | } | ||
194 | |||
195 | static void __exit harddog_exit(void) | ||
196 | { | ||
197 | misc_deregister(&harddog_miscdev); | ||
198 | } | ||
199 | |||
200 | module_init(harddog_init); | ||
201 | module_exit(harddog_exit); | ||
diff --git a/drivers/Makefile b/drivers/Makefile index 53abb4a5f736..f0afdfb3c7df 100644 --- a/drivers/Makefile +++ b/drivers/Makefile | |||
@@ -29,6 +29,8 @@ obj-$(CONFIG_SFI) += sfi/ | |||
29 | # was used and do nothing if so | 29 | # was used and do nothing if so |
30 | obj-$(CONFIG_PNP) += pnp/ | 30 | obj-$(CONFIG_PNP) += pnp/ |
31 | obj-y += amba/ | 31 | obj-y += amba/ |
32 | |||
33 | obj-y += clk/ | ||
32 | # Many drivers will want to use DMA so this has to be made available | 34 | # Many drivers will want to use DMA so this has to be made available |
33 | # really early. | 35 | # really early. |
34 | obj-$(CONFIG_DMADEVICES) += dma/ | 36 | obj-$(CONFIG_DMADEVICES) += dma/ |
@@ -142,8 +144,6 @@ obj-$(CONFIG_VHOST) += vhost/ | |||
142 | obj-$(CONFIG_VLYNQ) += vlynq/ | 144 | obj-$(CONFIG_VLYNQ) += vlynq/ |
143 | obj-$(CONFIG_STAGING) += staging/ | 145 | obj-$(CONFIG_STAGING) += staging/ |
144 | obj-y += platform/ | 146 | obj-y += platform/ |
145 | #common clk code | ||
146 | obj-y += clk/ | ||
147 | 147 | ||
148 | obj-$(CONFIG_MAILBOX) += mailbox/ | 148 | obj-$(CONFIG_MAILBOX) += mailbox/ |
149 | obj-$(CONFIG_HWSPINLOCK) += hwspinlock/ | 149 | obj-$(CONFIG_HWSPINLOCK) += hwspinlock/ |
diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c index 3ff229b2e7f3..c4a75a18dcae 100644 --- a/drivers/bluetooth/hci_vhci.c +++ b/drivers/bluetooth/hci_vhci.c | |||
@@ -377,21 +377,7 @@ static struct miscdevice vhci_miscdev = { | |||
377 | .fops = &vhci_fops, | 377 | .fops = &vhci_fops, |
378 | .minor = VHCI_MINOR, | 378 | .minor = VHCI_MINOR, |
379 | }; | 379 | }; |
380 | 380 | module_misc_device(vhci_miscdev); | |
381 | static int __init vhci_init(void) | ||
382 | { | ||
383 | BT_INFO("Virtual HCI driver ver %s", VERSION); | ||
384 | |||
385 | return misc_register(&vhci_miscdev); | ||
386 | } | ||
387 | |||
388 | static void __exit vhci_exit(void) | ||
389 | { | ||
390 | misc_deregister(&vhci_miscdev); | ||
391 | } | ||
392 | |||
393 | module_init(vhci_init); | ||
394 | module_exit(vhci_exit); | ||
395 | 381 | ||
396 | module_param(amp, bool, 0644); | 382 | module_param(amp, bool, 0644); |
397 | MODULE_PARM_DESC(amp, "Create AMP controller device"); | 383 | MODULE_PARM_DESC(amp, "Create AMP controller device"); |
diff --git a/drivers/char/bfin-otp.c b/drivers/char/bfin-otp.c index 44660f1c4849..35d46da754d7 100644 --- a/drivers/char/bfin-otp.c +++ b/drivers/char/bfin-otp.c | |||
@@ -230,45 +230,7 @@ static struct miscdevice bfin_otp_misc_device = { | |||
230 | .name = DRIVER_NAME, | 230 | .name = DRIVER_NAME, |
231 | .fops = &bfin_otp_fops, | 231 | .fops = &bfin_otp_fops, |
232 | }; | 232 | }; |
233 | 233 | module_misc_device(bfin_otp_misc_device); | |
234 | /** | ||
235 | * bfin_otp_init - Initialize module | ||
236 | * | ||
237 | * Registers the device and notifier handler. Actual device | ||
238 | * initialization is handled by bfin_otp_open(). | ||
239 | */ | ||
240 | static int __init bfin_otp_init(void) | ||
241 | { | ||
242 | int ret; | ||
243 | |||
244 | stampit(); | ||
245 | |||
246 | ret = misc_register(&bfin_otp_misc_device); | ||
247 | if (ret) { | ||
248 | pr_init(KERN_ERR PFX "unable to register a misc device\n"); | ||
249 | return ret; | ||
250 | } | ||
251 | |||
252 | pr_init(KERN_INFO PFX "initialized\n"); | ||
253 | |||
254 | return 0; | ||
255 | } | ||
256 | |||
257 | /** | ||
258 | * bfin_otp_exit - Deinitialize module | ||
259 | * | ||
260 | * Unregisters the device and notifier handler. Actual device | ||
261 | * deinitialization is handled by bfin_otp_close(). | ||
262 | */ | ||
263 | static void __exit bfin_otp_exit(void) | ||
264 | { | ||
265 | stampit(); | ||
266 | |||
267 | misc_deregister(&bfin_otp_misc_device); | ||
268 | } | ||
269 | |||
270 | module_init(bfin_otp_init); | ||
271 | module_exit(bfin_otp_exit); | ||
272 | 234 | ||
273 | MODULE_AUTHOR("Mike Frysinger <vapier@gentoo.org>"); | 235 | MODULE_AUTHOR("Mike Frysinger <vapier@gentoo.org>"); |
274 | MODULE_DESCRIPTION("Blackfin OTP Memory Interface"); | 236 | MODULE_DESCRIPTION("Blackfin OTP Memory Interface"); |
diff --git a/drivers/char/mem.c b/drivers/char/mem.c index a33163dbb913..5bb1985ec484 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c | |||
@@ -381,6 +381,9 @@ static ssize_t read_kmem(struct file *file, char __user *buf, | |||
381 | char *kbuf; /* k-addr because vread() takes vmlist_lock rwlock */ | 381 | char *kbuf; /* k-addr because vread() takes vmlist_lock rwlock */ |
382 | int err = 0; | 382 | int err = 0; |
383 | 383 | ||
384 | if (!pfn_valid(PFN_DOWN(p))) | ||
385 | return -EIO; | ||
386 | |||
384 | read = 0; | 387 | read = 0; |
385 | if (p < (unsigned long) high_memory) { | 388 | if (p < (unsigned long) high_memory) { |
386 | low_count = count; | 389 | low_count = count; |
@@ -509,6 +512,9 @@ static ssize_t write_kmem(struct file *file, const char __user *buf, | |||
509 | char *kbuf; /* k-addr because vwrite() takes vmlist_lock rwlock */ | 512 | char *kbuf; /* k-addr because vwrite() takes vmlist_lock rwlock */ |
510 | int err = 0; | 513 | int err = 0; |
511 | 514 | ||
515 | if (!pfn_valid(PFN_DOWN(p))) | ||
516 | return -EIO; | ||
517 | |||
512 | if (p < (unsigned long) high_memory) { | 518 | if (p < (unsigned long) high_memory) { |
513 | unsigned long to_write = min_t(unsigned long, count, | 519 | unsigned long to_write = min_t(unsigned long, count, |
514 | (unsigned long)high_memory - p); | 520 | (unsigned long)high_memory - p); |
diff --git a/drivers/char/mwave/3780i.c b/drivers/char/mwave/3780i.c index 28740046bc83..972c40a19629 100644 --- a/drivers/char/mwave/3780i.c +++ b/drivers/char/mwave/3780i.c | |||
@@ -124,7 +124,7 @@ static void dsp3780I_WriteGenCfg(unsigned short usDspBaseIO, unsigned uIndex, | |||
124 | MKBYTE(rSlaveControl)); | 124 | MKBYTE(rSlaveControl)); |
125 | 125 | ||
126 | rSlaveControl_Save = rSlaveControl; | 126 | rSlaveControl_Save = rSlaveControl; |
127 | rSlaveControl.ConfigMode = TRUE; | 127 | rSlaveControl.ConfigMode = true; |
128 | 128 | ||
129 | PRINTK_2(TRACE_3780I, | 129 | PRINTK_2(TRACE_3780I, |
130 | "3780i::dsp3780i_WriteGenCfg entry rSlaveControl+ConfigMode %x\n", | 130 | "3780i::dsp3780i_WriteGenCfg entry rSlaveControl+ConfigMode %x\n", |
@@ -155,7 +155,7 @@ unsigned char dsp3780I_ReadGenCfg(unsigned short usDspBaseIO, | |||
155 | 155 | ||
156 | MKBYTE(rSlaveControl) = InByteDsp(DSP_IsaSlaveControl); | 156 | MKBYTE(rSlaveControl) = InByteDsp(DSP_IsaSlaveControl); |
157 | rSlaveControl_Save = rSlaveControl; | 157 | rSlaveControl_Save = rSlaveControl; |
158 | rSlaveControl.ConfigMode = TRUE; | 158 | rSlaveControl.ConfigMode = true; |
159 | OutByteDsp(DSP_IsaSlaveControl, MKBYTE(rSlaveControl)); | 159 | OutByteDsp(DSP_IsaSlaveControl, MKBYTE(rSlaveControl)); |
160 | OutByteDsp(DSP_ConfigAddress, (unsigned char) uIndex); | 160 | OutByteDsp(DSP_ConfigAddress, (unsigned char) uIndex); |
161 | ucValue = InByteDsp(DSP_ConfigData); | 161 | ucValue = InByteDsp(DSP_ConfigData); |
@@ -230,7 +230,7 @@ int dsp3780I_EnableDSP(DSP_3780I_CONFIG_SETTINGS * pSettings, | |||
230 | rUartCfg1.BaseIO = 3; | 230 | rUartCfg1.BaseIO = 3; |
231 | break; | 231 | break; |
232 | } | 232 | } |
233 | rUartCfg2.Enable = TRUE; | 233 | rUartCfg2.Enable = true; |
234 | } | 234 | } |
235 | 235 | ||
236 | rHBridgeCfg1.Reserved = rHBridgeCfg2.Reserved = 0; | 236 | rHBridgeCfg1.Reserved = rHBridgeCfg2.Reserved = 0; |
@@ -238,7 +238,7 @@ int dsp3780I_EnableDSP(DSP_3780I_CONFIG_SETTINGS * pSettings, | |||
238 | rHBridgeCfg1.IrqPulse = pSettings->bDspIrqPulse; | 238 | rHBridgeCfg1.IrqPulse = pSettings->bDspIrqPulse; |
239 | rHBridgeCfg1.Irq = (unsigned char) pIrqMap[pSettings->usDspIrq]; | 239 | rHBridgeCfg1.Irq = (unsigned char) pIrqMap[pSettings->usDspIrq]; |
240 | rHBridgeCfg1.AccessMode = 1; | 240 | rHBridgeCfg1.AccessMode = 1; |
241 | rHBridgeCfg2.Enable = TRUE; | 241 | rHBridgeCfg2.Enable = true; |
242 | 242 | ||
243 | 243 | ||
244 | rBusmasterCfg2.Reserved = 0; | 244 | rBusmasterCfg2.Reserved = 0; |
@@ -278,8 +278,8 @@ int dsp3780I_EnableDSP(DSP_3780I_CONFIG_SETTINGS * pSettings, | |||
278 | * soft-reset active for 10ms. | 278 | * soft-reset active for 10ms. |
279 | */ | 279 | */ |
280 | rSlaveControl.ClockControl = 0; | 280 | rSlaveControl.ClockControl = 0; |
281 | rSlaveControl.SoftReset = TRUE; | 281 | rSlaveControl.SoftReset = true; |
282 | rSlaveControl.ConfigMode = FALSE; | 282 | rSlaveControl.ConfigMode = false; |
283 | rSlaveControl.Reserved = 0; | 283 | rSlaveControl.Reserved = 0; |
284 | 284 | ||
285 | PRINTK_4(TRACE_3780I, | 285 | PRINTK_4(TRACE_3780I, |
@@ -302,7 +302,7 @@ int dsp3780I_EnableDSP(DSP_3780I_CONFIG_SETTINGS * pSettings, | |||
302 | for (i = 0; i < 11; i++) | 302 | for (i = 0; i < 11; i++) |
303 | udelay(2000); | 303 | udelay(2000); |
304 | 304 | ||
305 | rSlaveControl.SoftReset = FALSE; | 305 | rSlaveControl.SoftReset = false; |
306 | OutWordDsp(DSP_IsaSlaveControl, MKWORD(rSlaveControl)); | 306 | OutWordDsp(DSP_IsaSlaveControl, MKWORD(rSlaveControl)); |
307 | 307 | ||
308 | MKWORD(tval) = InWordDsp(DSP_IsaSlaveControl); | 308 | MKWORD(tval) = InWordDsp(DSP_IsaSlaveControl); |
@@ -326,10 +326,10 @@ int dsp3780I_EnableDSP(DSP_3780I_CONFIG_SETTINGS * pSettings, | |||
326 | } | 326 | } |
327 | 327 | ||
328 | 328 | ||
329 | rHBridgeControl.EnableDspInt = FALSE; | 329 | rHBridgeControl.EnableDspInt = false; |
330 | rHBridgeControl.MemAutoInc = TRUE; | 330 | rHBridgeControl.MemAutoInc = true; |
331 | rHBridgeControl.IoAutoInc = FALSE; | 331 | rHBridgeControl.IoAutoInc = false; |
332 | rHBridgeControl.DiagnosticMode = FALSE; | 332 | rHBridgeControl.DiagnosticMode = false; |
333 | 333 | ||
334 | PRINTK_3(TRACE_3780I, | 334 | PRINTK_3(TRACE_3780I, |
335 | "3780i::dsp3780i_EnableDSP DSP_HBridgeControl %x rHBridgeControl %x\n", | 335 | "3780i::dsp3780i_EnableDSP DSP_HBridgeControl %x rHBridgeControl %x\n", |
@@ -345,7 +345,7 @@ int dsp3780I_EnableDSP(DSP_3780I_CONFIG_SETTINGS * pSettings, | |||
345 | ChipID = ReadMsaCfg(DSP_ChipID); | 345 | ChipID = ReadMsaCfg(DSP_ChipID); |
346 | 346 | ||
347 | PRINTK_2(TRACE_3780I, | 347 | PRINTK_2(TRACE_3780I, |
348 | "3780i::dsp3780I_EnableDSP exiting bRC=TRUE, ChipID %x\n", | 348 | "3780i::dsp3780I_EnableDSP exiting bRC=true, ChipID %x\n", |
349 | ChipID); | 349 | ChipID); |
350 | 350 | ||
351 | return 0; | 351 | return 0; |
@@ -361,8 +361,8 @@ int dsp3780I_DisableDSP(DSP_3780I_CONFIG_SETTINGS * pSettings) | |||
361 | PRINTK_1(TRACE_3780I, "3780i::dsp3780i_DisableDSP entry\n"); | 361 | PRINTK_1(TRACE_3780I, "3780i::dsp3780i_DisableDSP entry\n"); |
362 | 362 | ||
363 | rSlaveControl.ClockControl = 0; | 363 | rSlaveControl.ClockControl = 0; |
364 | rSlaveControl.SoftReset = TRUE; | 364 | rSlaveControl.SoftReset = true; |
365 | rSlaveControl.ConfigMode = FALSE; | 365 | rSlaveControl.ConfigMode = false; |
366 | rSlaveControl.Reserved = 0; | 366 | rSlaveControl.Reserved = 0; |
367 | spin_lock_irqsave(&dsp_lock, flags); | 367 | spin_lock_irqsave(&dsp_lock, flags); |
368 | OutWordDsp(DSP_IsaSlaveControl, MKWORD(rSlaveControl)); | 368 | OutWordDsp(DSP_IsaSlaveControl, MKWORD(rSlaveControl)); |
@@ -398,14 +398,14 @@ int dsp3780I_Reset(DSP_3780I_CONFIG_SETTINGS * pSettings) | |||
398 | PRINTK_2(TRACE_3780I, "3780i::dsp3780i_Reset rHBridgeControl %x\n", | 398 | PRINTK_2(TRACE_3780I, "3780i::dsp3780i_Reset rHBridgeControl %x\n", |
399 | MKWORD(rHBridgeControl)); | 399 | MKWORD(rHBridgeControl)); |
400 | 400 | ||
401 | rHBridgeControl.EnableDspInt = FALSE; | 401 | rHBridgeControl.EnableDspInt = false; |
402 | OutWordDsp(DSP_HBridgeControl, MKWORD(rHBridgeControl)); | 402 | OutWordDsp(DSP_HBridgeControl, MKWORD(rHBridgeControl)); |
403 | spin_unlock_irqrestore(&dsp_lock, flags); | 403 | spin_unlock_irqrestore(&dsp_lock, flags); |
404 | 404 | ||
405 | /* Reset the core via the boot domain register */ | 405 | /* Reset the core via the boot domain register */ |
406 | rBootDomain.ResetCore = TRUE; | 406 | rBootDomain.ResetCore = true; |
407 | rBootDomain.Halt = TRUE; | 407 | rBootDomain.Halt = true; |
408 | rBootDomain.NMI = TRUE; | 408 | rBootDomain.NMI = true; |
409 | rBootDomain.Reserved = 0; | 409 | rBootDomain.Reserved = 0; |
410 | 410 | ||
411 | PRINTK_2(TRACE_3780I, "3780i::dsp3780i_Reset rBootDomain %x\n", | 411 | PRINTK_2(TRACE_3780I, "3780i::dsp3780i_Reset rBootDomain %x\n", |
@@ -438,26 +438,26 @@ int dsp3780I_Run(DSP_3780I_CONFIG_SETTINGS * pSettings) | |||
438 | 438 | ||
439 | 439 | ||
440 | /* Transition the core to a running state */ | 440 | /* Transition the core to a running state */ |
441 | rBootDomain.ResetCore = TRUE; | 441 | rBootDomain.ResetCore = true; |
442 | rBootDomain.Halt = FALSE; | 442 | rBootDomain.Halt = false; |
443 | rBootDomain.NMI = TRUE; | 443 | rBootDomain.NMI = true; |
444 | rBootDomain.Reserved = 0; | 444 | rBootDomain.Reserved = 0; |
445 | WriteMsaCfg(DSP_MspBootDomain, MKWORD(rBootDomain)); | 445 | WriteMsaCfg(DSP_MspBootDomain, MKWORD(rBootDomain)); |
446 | 446 | ||
447 | udelay(5); | 447 | udelay(5); |
448 | 448 | ||
449 | rBootDomain.ResetCore = FALSE; | 449 | rBootDomain.ResetCore = false; |
450 | WriteMsaCfg(DSP_MspBootDomain, MKWORD(rBootDomain)); | 450 | WriteMsaCfg(DSP_MspBootDomain, MKWORD(rBootDomain)); |
451 | udelay(5); | 451 | udelay(5); |
452 | 452 | ||
453 | rBootDomain.NMI = FALSE; | 453 | rBootDomain.NMI = false; |
454 | WriteMsaCfg(DSP_MspBootDomain, MKWORD(rBootDomain)); | 454 | WriteMsaCfg(DSP_MspBootDomain, MKWORD(rBootDomain)); |
455 | udelay(5); | 455 | udelay(5); |
456 | 456 | ||
457 | /* Enable DSP to PC interrupt */ | 457 | /* Enable DSP to PC interrupt */ |
458 | spin_lock_irqsave(&dsp_lock, flags); | 458 | spin_lock_irqsave(&dsp_lock, flags); |
459 | MKWORD(rHBridgeControl) = InWordDsp(DSP_HBridgeControl); | 459 | MKWORD(rHBridgeControl) = InWordDsp(DSP_HBridgeControl); |
460 | rHBridgeControl.EnableDspInt = TRUE; | 460 | rHBridgeControl.EnableDspInt = true; |
461 | 461 | ||
462 | PRINTK_2(TRACE_3780I, "3780i::dsp3780i_Run rHBridgeControl %x\n", | 462 | PRINTK_2(TRACE_3780I, "3780i::dsp3780i_Run rHBridgeControl %x\n", |
463 | MKWORD(rHBridgeControl)); | 463 | MKWORD(rHBridgeControl)); |
@@ -466,7 +466,7 @@ int dsp3780I_Run(DSP_3780I_CONFIG_SETTINGS * pSettings) | |||
466 | spin_unlock_irqrestore(&dsp_lock, flags); | 466 | spin_unlock_irqrestore(&dsp_lock, flags); |
467 | 467 | ||
468 | 468 | ||
469 | PRINTK_1(TRACE_3780I, "3780i::dsp3780i_Run exit bRC=TRUE\n"); | 469 | PRINTK_1(TRACE_3780I, "3780i::dsp3780i_Run exit bRC=true\n"); |
470 | 470 | ||
471 | return 0; | 471 | return 0; |
472 | } | 472 | } |
@@ -508,7 +508,7 @@ int dsp3780I_ReadDStore(unsigned short usDspBaseIO, void __user *pvBuffer, | |||
508 | 508 | ||
509 | 509 | ||
510 | PRINTK_1(TRACE_3780I, | 510 | PRINTK_1(TRACE_3780I, |
511 | "3780I::dsp3780I_ReadDStore exit bRC=TRUE\n"); | 511 | "3780I::dsp3780I_ReadDStore exit bRC=true\n"); |
512 | 512 | ||
513 | return 0; | 513 | return 0; |
514 | } | 514 | } |
@@ -550,7 +550,7 @@ int dsp3780I_ReadAndClearDStore(unsigned short usDspBaseIO, | |||
550 | 550 | ||
551 | 551 | ||
552 | PRINTK_1(TRACE_3780I, | 552 | PRINTK_1(TRACE_3780I, |
553 | "3780I::dsp3780I_ReadAndClearDStore exit bRC=TRUE\n"); | 553 | "3780I::dsp3780I_ReadAndClearDStore exit bRC=true\n"); |
554 | 554 | ||
555 | return 0; | 555 | return 0; |
556 | } | 556 | } |
@@ -592,7 +592,7 @@ int dsp3780I_WriteDStore(unsigned short usDspBaseIO, void __user *pvBuffer, | |||
592 | 592 | ||
593 | 593 | ||
594 | PRINTK_1(TRACE_3780I, | 594 | PRINTK_1(TRACE_3780I, |
595 | "3780I::dsp3780D_WriteDStore exit bRC=TRUE\n"); | 595 | "3780I::dsp3780D_WriteDStore exit bRC=true\n"); |
596 | 596 | ||
597 | return 0; | 597 | return 0; |
598 | } | 598 | } |
@@ -640,7 +640,7 @@ int dsp3780I_ReadIStore(unsigned short usDspBaseIO, void __user *pvBuffer, | |||
640 | } | 640 | } |
641 | 641 | ||
642 | PRINTK_1(TRACE_3780I, | 642 | PRINTK_1(TRACE_3780I, |
643 | "3780I::dsp3780I_ReadIStore exit bRC=TRUE\n"); | 643 | "3780I::dsp3780I_ReadIStore exit bRC=true\n"); |
644 | 644 | ||
645 | return 0; | 645 | return 0; |
646 | } | 646 | } |
@@ -689,7 +689,7 @@ int dsp3780I_WriteIStore(unsigned short usDspBaseIO, void __user *pvBuffer, | |||
689 | } | 689 | } |
690 | 690 | ||
691 | PRINTK_1(TRACE_3780I, | 691 | PRINTK_1(TRACE_3780I, |
692 | "3780I::dsp3780I_WriteIStore exit bRC=TRUE\n"); | 692 | "3780I::dsp3780I_WriteIStore exit bRC=true\n"); |
693 | 693 | ||
694 | return 0; | 694 | return 0; |
695 | } | 695 | } |
@@ -713,7 +713,7 @@ int dsp3780I_GetIPCSource(unsigned short usDspBaseIO, | |||
713 | */ | 713 | */ |
714 | spin_lock_irqsave(&dsp_lock, flags); | 714 | spin_lock_irqsave(&dsp_lock, flags); |
715 | MKWORD(rHBridgeControl) = InWordDsp(DSP_HBridgeControl); | 715 | MKWORD(rHBridgeControl) = InWordDsp(DSP_HBridgeControl); |
716 | rHBridgeControl.EnableDspInt = FALSE; | 716 | rHBridgeControl.EnableDspInt = false; |
717 | OutWordDsp(DSP_HBridgeControl, MKWORD(rHBridgeControl)); | 717 | OutWordDsp(DSP_HBridgeControl, MKWORD(rHBridgeControl)); |
718 | 718 | ||
719 | *pusIPCSource = InWordDsp(DSP_Interrupt); | 719 | *pusIPCSource = InWordDsp(DSP_Interrupt); |
@@ -725,7 +725,7 @@ int dsp3780I_GetIPCSource(unsigned short usDspBaseIO, | |||
725 | 725 | ||
726 | OutWordDsp(DSP_Interrupt, (unsigned short) ~(*pusIPCSource)); | 726 | OutWordDsp(DSP_Interrupt, (unsigned short) ~(*pusIPCSource)); |
727 | 727 | ||
728 | rHBridgeControl.EnableDspInt = TRUE; | 728 | rHBridgeControl.EnableDspInt = true; |
729 | OutWordDsp(DSP_HBridgeControl, MKWORD(rHBridgeControl)); | 729 | OutWordDsp(DSP_HBridgeControl, MKWORD(rHBridgeControl)); |
730 | spin_unlock_irqrestore(&dsp_lock, flags); | 730 | spin_unlock_irqrestore(&dsp_lock, flags); |
731 | 731 | ||
diff --git a/drivers/char/mwave/3780i.h b/drivers/char/mwave/3780i.h index fba6ab1160ce..9ccb6b270b07 100644 --- a/drivers/char/mwave/3780i.h +++ b/drivers/char/mwave/3780i.h | |||
@@ -101,7 +101,7 @@ typedef struct { | |||
101 | } DSP_UART_CFG_1; | 101 | } DSP_UART_CFG_1; |
102 | 102 | ||
103 | typedef struct { | 103 | typedef struct { |
104 | unsigned char Enable:1; /* RW: Enable I/O and IRQ: 0=FALSE, 1=TRUE */ | 104 | unsigned char Enable:1; /* RW: Enable I/O and IRQ: 0=false, 1=true */ |
105 | unsigned char Reserved:7; /* 0: Reserved */ | 105 | unsigned char Reserved:7; /* 0: Reserved */ |
106 | } DSP_UART_CFG_2; | 106 | } DSP_UART_CFG_2; |
107 | 107 | ||
@@ -114,7 +114,7 @@ typedef struct { | |||
114 | } DSP_HBRIDGE_CFG_1; | 114 | } DSP_HBRIDGE_CFG_1; |
115 | 115 | ||
116 | typedef struct { | 116 | typedef struct { |
117 | unsigned char Enable:1; /* RW: enable I/O and IRQ: 0=FALSE, 1=TRUE */ | 117 | unsigned char Enable:1; /* RW: enable I/O and IRQ: 0=false, 1=true */ |
118 | unsigned char Reserved:7; /* 0: Reserved */ | 118 | unsigned char Reserved:7; /* 0: Reserved */ |
119 | } DSP_HBRIDGE_CFG_2; | 119 | } DSP_HBRIDGE_CFG_2; |
120 | 120 | ||
@@ -133,12 +133,12 @@ typedef struct { | |||
133 | 133 | ||
134 | 134 | ||
135 | typedef struct { | 135 | typedef struct { |
136 | unsigned char GateIOCHRDY:1; /* RW: Enable IOCHRDY gating: 0=FALSE, 1=TRUE */ | 136 | unsigned char GateIOCHRDY:1; /* RW: Enable IOCHRDY gating: 0=false, 1=true */ |
137 | unsigned char Reserved:7; /* 0: Reserved */ | 137 | unsigned char Reserved:7; /* 0: Reserved */ |
138 | } DSP_ISA_PROT_CFG; | 138 | } DSP_ISA_PROT_CFG; |
139 | 139 | ||
140 | typedef struct { | 140 | typedef struct { |
141 | unsigned char Enable:1; /* RW: Enable low power suspend/resume 0=FALSE, 1=TRUE */ | 141 | unsigned char Enable:1; /* RW: Enable low power suspend/resume 0=false, 1=true */ |
142 | unsigned char Reserved:7; /* 0: Reserved */ | 142 | unsigned char Reserved:7; /* 0: Reserved */ |
143 | } DSP_POWER_MGMT_CFG; | 143 | } DSP_POWER_MGMT_CFG; |
144 | 144 | ||
diff --git a/drivers/char/mwave/mwavedd.c b/drivers/char/mwave/mwavedd.c index 164544afd680..3a3ff2eb6cba 100644 --- a/drivers/char/mwave/mwavedd.c +++ b/drivers/char/mwave/mwavedd.c | |||
@@ -296,8 +296,8 @@ static long mwave_ioctl(struct file *file, unsigned int iocmd, | |||
296 | pDrvData->IPCs[ipcnum].usIntCount); | 296 | pDrvData->IPCs[ipcnum].usIntCount); |
297 | 297 | ||
298 | mutex_lock(&mwave_mutex); | 298 | mutex_lock(&mwave_mutex); |
299 | pDrvData->IPCs[ipcnum].bIsHere = FALSE; | 299 | pDrvData->IPCs[ipcnum].bIsHere = false; |
300 | pDrvData->IPCs[ipcnum].bIsEnabled = TRUE; | 300 | pDrvData->IPCs[ipcnum].bIsEnabled = true; |
301 | mutex_unlock(&mwave_mutex); | 301 | mutex_unlock(&mwave_mutex); |
302 | 302 | ||
303 | PRINTK_2(TRACE_MWAVE, | 303 | PRINTK_2(TRACE_MWAVE, |
@@ -324,7 +324,7 @@ static long mwave_ioctl(struct file *file, unsigned int iocmd, | |||
324 | pDrvData->IPCs[ipcnum].usIntCount); | 324 | pDrvData->IPCs[ipcnum].usIntCount); |
325 | 325 | ||
326 | mutex_lock(&mwave_mutex); | 326 | mutex_lock(&mwave_mutex); |
327 | if (pDrvData->IPCs[ipcnum].bIsEnabled == TRUE) { | 327 | if (pDrvData->IPCs[ipcnum].bIsEnabled == true) { |
328 | DECLARE_WAITQUEUE(wait, current); | 328 | DECLARE_WAITQUEUE(wait, current); |
329 | 329 | ||
330 | PRINTK_2(TRACE_MWAVE, | 330 | PRINTK_2(TRACE_MWAVE, |
@@ -332,7 +332,7 @@ static long mwave_ioctl(struct file *file, unsigned int iocmd, | |||
332 | " ipc %x going to sleep\n", | 332 | " ipc %x going to sleep\n", |
333 | ipcnum); | 333 | ipcnum); |
334 | add_wait_queue(&pDrvData->IPCs[ipcnum].ipc_wait_queue, &wait); | 334 | add_wait_queue(&pDrvData->IPCs[ipcnum].ipc_wait_queue, &wait); |
335 | pDrvData->IPCs[ipcnum].bIsHere = TRUE; | 335 | pDrvData->IPCs[ipcnum].bIsHere = true; |
336 | set_current_state(TASK_INTERRUPTIBLE); | 336 | set_current_state(TASK_INTERRUPTIBLE); |
337 | /* check whether an event was signalled by */ | 337 | /* check whether an event was signalled by */ |
338 | /* the interrupt handler while we were gone */ | 338 | /* the interrupt handler while we were gone */ |
@@ -355,7 +355,7 @@ static long mwave_ioctl(struct file *file, unsigned int iocmd, | |||
355 | " application\n", | 355 | " application\n", |
356 | ipcnum); | 356 | ipcnum); |
357 | } | 357 | } |
358 | pDrvData->IPCs[ipcnum].bIsHere = FALSE; | 358 | pDrvData->IPCs[ipcnum].bIsHere = false; |
359 | remove_wait_queue(&pDrvData->IPCs[ipcnum].ipc_wait_queue, &wait); | 359 | remove_wait_queue(&pDrvData->IPCs[ipcnum].ipc_wait_queue, &wait); |
360 | set_current_state(TASK_RUNNING); | 360 | set_current_state(TASK_RUNNING); |
361 | PRINTK_2(TRACE_MWAVE, | 361 | PRINTK_2(TRACE_MWAVE, |
@@ -384,9 +384,9 @@ static long mwave_ioctl(struct file *file, unsigned int iocmd, | |||
384 | return -EINVAL; | 384 | return -EINVAL; |
385 | } | 385 | } |
386 | mutex_lock(&mwave_mutex); | 386 | mutex_lock(&mwave_mutex); |
387 | if (pDrvData->IPCs[ipcnum].bIsEnabled == TRUE) { | 387 | if (pDrvData->IPCs[ipcnum].bIsEnabled == true) { |
388 | pDrvData->IPCs[ipcnum].bIsEnabled = FALSE; | 388 | pDrvData->IPCs[ipcnum].bIsEnabled = false; |
389 | if (pDrvData->IPCs[ipcnum].bIsHere == TRUE) { | 389 | if (pDrvData->IPCs[ipcnum].bIsHere == true) { |
390 | wake_up_interruptible(&pDrvData->IPCs[ipcnum].ipc_wait_queue); | 390 | wake_up_interruptible(&pDrvData->IPCs[ipcnum].ipc_wait_queue); |
391 | } | 391 | } |
392 | } | 392 | } |
@@ -541,7 +541,7 @@ static void mwave_exit(void) | |||
541 | 541 | ||
542 | if (pDrvData->device_registered) { | 542 | if (pDrvData->device_registered) { |
543 | device_unregister(&mwave_device); | 543 | device_unregister(&mwave_device); |
544 | pDrvData->device_registered = FALSE; | 544 | pDrvData->device_registered = false; |
545 | } | 545 | } |
546 | #endif | 546 | #endif |
547 | 547 | ||
@@ -576,16 +576,16 @@ static int __init mwave_init(void) | |||
576 | 576 | ||
577 | memset(&mwave_s_mdd, 0, sizeof(MWAVE_DEVICE_DATA)); | 577 | memset(&mwave_s_mdd, 0, sizeof(MWAVE_DEVICE_DATA)); |
578 | 578 | ||
579 | pDrvData->bBDInitialized = FALSE; | 579 | pDrvData->bBDInitialized = false; |
580 | pDrvData->bResourcesClaimed = FALSE; | 580 | pDrvData->bResourcesClaimed = false; |
581 | pDrvData->bDSPEnabled = FALSE; | 581 | pDrvData->bDSPEnabled = false; |
582 | pDrvData->bDSPReset = FALSE; | 582 | pDrvData->bDSPReset = false; |
583 | pDrvData->bMwaveDevRegistered = FALSE; | 583 | pDrvData->bMwaveDevRegistered = false; |
584 | pDrvData->sLine = -1; | 584 | pDrvData->sLine = -1; |
585 | 585 | ||
586 | for (i = 0; i < ARRAY_SIZE(pDrvData->IPCs); i++) { | 586 | for (i = 0; i < ARRAY_SIZE(pDrvData->IPCs); i++) { |
587 | pDrvData->IPCs[i].bIsEnabled = FALSE; | 587 | pDrvData->IPCs[i].bIsEnabled = false; |
588 | pDrvData->IPCs[i].bIsHere = FALSE; | 588 | pDrvData->IPCs[i].bIsHere = false; |
589 | pDrvData->IPCs[i].usIntCount = 0; /* no ints received yet */ | 589 | pDrvData->IPCs[i].usIntCount = 0; /* no ints received yet */ |
590 | init_waitqueue_head(&pDrvData->IPCs[i].ipc_wait_queue); | 590 | init_waitqueue_head(&pDrvData->IPCs[i].ipc_wait_queue); |
591 | } | 591 | } |
@@ -601,7 +601,7 @@ static int __init mwave_init(void) | |||
601 | " Failed to initialize board data\n"); | 601 | " Failed to initialize board data\n"); |
602 | goto cleanup_error; | 602 | goto cleanup_error; |
603 | } | 603 | } |
604 | pDrvData->bBDInitialized = TRUE; | 604 | pDrvData->bBDInitialized = true; |
605 | 605 | ||
606 | retval = tp3780I_CalcResources(&pDrvData->rBDData); | 606 | retval = tp3780I_CalcResources(&pDrvData->rBDData); |
607 | PRINTK_2(TRACE_MWAVE, | 607 | PRINTK_2(TRACE_MWAVE, |
@@ -626,7 +626,7 @@ static int __init mwave_init(void) | |||
626 | " Failed to claim resources\n"); | 626 | " Failed to claim resources\n"); |
627 | goto cleanup_error; | 627 | goto cleanup_error; |
628 | } | 628 | } |
629 | pDrvData->bResourcesClaimed = TRUE; | 629 | pDrvData->bResourcesClaimed = true; |
630 | 630 | ||
631 | retval = tp3780I_EnableDSP(&pDrvData->rBDData); | 631 | retval = tp3780I_EnableDSP(&pDrvData->rBDData); |
632 | PRINTK_2(TRACE_MWAVE, | 632 | PRINTK_2(TRACE_MWAVE, |
@@ -639,7 +639,7 @@ static int __init mwave_init(void) | |||
639 | " Failed to enable DSP\n"); | 639 | " Failed to enable DSP\n"); |
640 | goto cleanup_error; | 640 | goto cleanup_error; |
641 | } | 641 | } |
642 | pDrvData->bDSPEnabled = TRUE; | 642 | pDrvData->bDSPEnabled = true; |
643 | 643 | ||
644 | if (misc_register(&mwave_misc_dev) < 0) { | 644 | if (misc_register(&mwave_misc_dev) < 0) { |
645 | PRINTK_ERROR(KERN_ERR_MWAVE | 645 | PRINTK_ERROR(KERN_ERR_MWAVE |
@@ -647,7 +647,7 @@ static int __init mwave_init(void) | |||
647 | " Failed to register misc device\n"); | 647 | " Failed to register misc device\n"); |
648 | goto cleanup_error; | 648 | goto cleanup_error; |
649 | } | 649 | } |
650 | pDrvData->bMwaveDevRegistered = TRUE; | 650 | pDrvData->bMwaveDevRegistered = true; |
651 | 651 | ||
652 | pDrvData->sLine = register_serial_portandirq( | 652 | pDrvData->sLine = register_serial_portandirq( |
653 | pDrvData->rBDData.rDspSettings.usUartBaseIO, | 653 | pDrvData->rBDData.rDspSettings.usUartBaseIO, |
@@ -668,7 +668,7 @@ static int __init mwave_init(void) | |||
668 | 668 | ||
669 | if (device_register(&mwave_device)) | 669 | if (device_register(&mwave_device)) |
670 | goto cleanup_error; | 670 | goto cleanup_error; |
671 | pDrvData->device_registered = TRUE; | 671 | pDrvData->device_registered = true; |
672 | for (i = 0; i < ARRAY_SIZE(mwave_dev_attrs); i++) { | 672 | for (i = 0; i < ARRAY_SIZE(mwave_dev_attrs); i++) { |
673 | if(device_create_file(&mwave_device, mwave_dev_attrs[i])) { | 673 | if(device_create_file(&mwave_device, mwave_dev_attrs[i])) { |
674 | PRINTK_ERROR(KERN_ERR_MWAVE | 674 | PRINTK_ERROR(KERN_ERR_MWAVE |
diff --git a/drivers/char/mwave/mwavedd.h b/drivers/char/mwave/mwavedd.h index 7e0d530e2e07..37e0a4926080 100644 --- a/drivers/char/mwave/mwavedd.h +++ b/drivers/char/mwave/mwavedd.h | |||
@@ -125,8 +125,8 @@ extern int mwave_uart_io; | |||
125 | 125 | ||
126 | typedef struct _MWAVE_IPC { | 126 | typedef struct _MWAVE_IPC { |
127 | unsigned short usIntCount; /* 0=none, 1=first, 2=greater than 1st */ | 127 | unsigned short usIntCount; /* 0=none, 1=first, 2=greater than 1st */ |
128 | BOOLEAN bIsEnabled; | 128 | bool bIsEnabled; |
129 | BOOLEAN bIsHere; | 129 | bool bIsHere; |
130 | /* entry spin lock */ | 130 | /* entry spin lock */ |
131 | wait_queue_head_t ipc_wait_queue; | 131 | wait_queue_head_t ipc_wait_queue; |
132 | } MWAVE_IPC; | 132 | } MWAVE_IPC; |
@@ -135,12 +135,12 @@ typedef struct _MWAVE_DEVICE_DATA { | |||
135 | THINKPAD_BD_DATA rBDData; /* board driver's data area */ | 135 | THINKPAD_BD_DATA rBDData; /* board driver's data area */ |
136 | unsigned long ulIPCSource_ISR; /* IPC source bits for recently processed intr, set during ISR processing */ | 136 | unsigned long ulIPCSource_ISR; /* IPC source bits for recently processed intr, set during ISR processing */ |
137 | unsigned long ulIPCSource_DPC; /* IPC source bits for recently processed intr, set during DPC processing */ | 137 | unsigned long ulIPCSource_DPC; /* IPC source bits for recently processed intr, set during DPC processing */ |
138 | BOOLEAN bBDInitialized; | 138 | bool bBDInitialized; |
139 | BOOLEAN bResourcesClaimed; | 139 | bool bResourcesClaimed; |
140 | BOOLEAN bDSPEnabled; | 140 | bool bDSPEnabled; |
141 | BOOLEAN bDSPReset; | 141 | bool bDSPReset; |
142 | MWAVE_IPC IPCs[16]; | 142 | MWAVE_IPC IPCs[16]; |
143 | BOOLEAN bMwaveDevRegistered; | 143 | bool bMwaveDevRegistered; |
144 | short sLine; | 144 | short sLine; |
145 | int nr_registered_attrs; | 145 | int nr_registered_attrs; |
146 | int device_registered; | 146 | int device_registered; |
diff --git a/drivers/char/mwave/smapi.c b/drivers/char/mwave/smapi.c index 6187fd14b3fe..8c5411a8f33f 100644 --- a/drivers/char/mwave/smapi.c +++ b/drivers/char/mwave/smapi.c | |||
@@ -493,7 +493,7 @@ exit_smapi_request_error: | |||
493 | } | 493 | } |
494 | 494 | ||
495 | 495 | ||
496 | int smapi_set_DSP_power_state(BOOLEAN bOn) | 496 | int smapi_set_DSP_power_state(bool bOn) |
497 | { | 497 | { |
498 | int bRC = -EIO; | 498 | int bRC = -EIO; |
499 | unsigned short usAX, usBX, usCX, usDX, usDI, usSI; | 499 | unsigned short usAX, usBX, usCX, usDX, usDI, usSI; |
@@ -556,7 +556,7 @@ int smapi_init(void) | |||
556 | PRINTK_ERROR("smapi::smapi_init, ERROR unable to read from SMAPI port\n"); | 556 | PRINTK_ERROR("smapi::smapi_init, ERROR unable to read from SMAPI port\n"); |
557 | } else { | 557 | } else { |
558 | PRINTK_2(TRACE_SMAPI, | 558 | PRINTK_2(TRACE_SMAPI, |
559 | "smapi::smapi_init, exit TRUE g_usSmapiPort %x\n", | 559 | "smapi::smapi_init, exit true g_usSmapiPort %x\n", |
560 | g_usSmapiPort); | 560 | g_usSmapiPort); |
561 | retval = 0; | 561 | retval = 0; |
562 | //SmapiQuerySystemID(); | 562 | //SmapiQuerySystemID(); |
diff --git a/drivers/char/mwave/smapi.h b/drivers/char/mwave/smapi.h index 64b2ec1420e3..ebc206b000b9 100644 --- a/drivers/char/mwave/smapi.h +++ b/drivers/char/mwave/smapi.h | |||
@@ -49,10 +49,6 @@ | |||
49 | #ifndef _LINUX_SMAPI_H | 49 | #ifndef _LINUX_SMAPI_H |
50 | #define _LINUX_SMAPI_H | 50 | #define _LINUX_SMAPI_H |
51 | 51 | ||
52 | #define TRUE 1 | ||
53 | #define FALSE 0 | ||
54 | #define BOOLEAN int | ||
55 | |||
56 | typedef struct { | 52 | typedef struct { |
57 | int bDSPPresent; | 53 | int bDSPPresent; |
58 | int bDSPEnabled; | 54 | int bDSPEnabled; |
@@ -74,7 +70,7 @@ typedef struct { | |||
74 | int smapi_init(void); | 70 | int smapi_init(void); |
75 | int smapi_query_DSP_cfg(SMAPI_DSP_SETTINGS * pSettings); | 71 | int smapi_query_DSP_cfg(SMAPI_DSP_SETTINGS * pSettings); |
76 | int smapi_set_DSP_cfg(void); | 72 | int smapi_set_DSP_cfg(void); |
77 | int smapi_set_DSP_power_state(BOOLEAN bOn); | 73 | int smapi_set_DSP_power_state(bool bOn); |
78 | 74 | ||
79 | 75 | ||
80 | #endif | 76 | #endif |
diff --git a/drivers/char/mwave/tp3780i.c b/drivers/char/mwave/tp3780i.c index 04e6d6a27994..5e1618a76b2a 100644 --- a/drivers/char/mwave/tp3780i.c +++ b/drivers/char/mwave/tp3780i.c | |||
@@ -80,13 +80,13 @@ static void EnableSRAM(THINKPAD_BD_DATA * pBDData) | |||
80 | WriteMsaCfg(DSP_GpioModeControl_15_8, MKWORD(rGpioMode)); | 80 | WriteMsaCfg(DSP_GpioModeControl_15_8, MKWORD(rGpioMode)); |
81 | 81 | ||
82 | MKWORD(rGpioDriverEnable) = 0; | 82 | MKWORD(rGpioDriverEnable) = 0; |
83 | rGpioDriverEnable.Enable10 = TRUE; | 83 | rGpioDriverEnable.Enable10 = true; |
84 | rGpioDriverEnable.Mask10 = TRUE; | 84 | rGpioDriverEnable.Mask10 = true; |
85 | WriteMsaCfg(DSP_GpioDriverEnable_15_8, MKWORD(rGpioDriverEnable)); | 85 | WriteMsaCfg(DSP_GpioDriverEnable_15_8, MKWORD(rGpioDriverEnable)); |
86 | 86 | ||
87 | MKWORD(rGpioOutputData) = 0; | 87 | MKWORD(rGpioOutputData) = 0; |
88 | rGpioOutputData.Latch10 = 0; | 88 | rGpioOutputData.Latch10 = 0; |
89 | rGpioOutputData.Mask10 = TRUE; | 89 | rGpioOutputData.Mask10 = true; |
90 | WriteMsaCfg(DSP_GpioOutputData_15_8, MKWORD(rGpioOutputData)); | 90 | WriteMsaCfg(DSP_GpioOutputData_15_8, MKWORD(rGpioOutputData)); |
91 | 91 | ||
92 | PRINTK_1(TRACE_TP3780I, "tp3780i::EnableSRAM exit\n"); | 92 | PRINTK_1(TRACE_TP3780I, "tp3780i::EnableSRAM exit\n"); |
@@ -127,7 +127,7 @@ static irqreturn_t DspInterrupt(int irq, void *dev_id) | |||
127 | PRINTK_2(TRACE_TP3780I, | 127 | PRINTK_2(TRACE_TP3780I, |
128 | "tp3780i::DspInterrupt usIntCount %x\n", | 128 | "tp3780i::DspInterrupt usIntCount %x\n", |
129 | pDrvData->IPCs[usPCNum - 1].usIntCount); | 129 | pDrvData->IPCs[usPCNum - 1].usIntCount); |
130 | if (pDrvData->IPCs[usPCNum - 1].bIsEnabled == TRUE) { | 130 | if (pDrvData->IPCs[usPCNum - 1].bIsEnabled == true) { |
131 | PRINTK_2(TRACE_TP3780I, | 131 | PRINTK_2(TRACE_TP3780I, |
132 | "tp3780i::DspInterrupt, waking up usPCNum %x\n", | 132 | "tp3780i::DspInterrupt, waking up usPCNum %x\n", |
133 | usPCNum - 1); | 133 | usPCNum - 1); |
@@ -160,8 +160,8 @@ int tp3780I_InitializeBoardData(THINKPAD_BD_DATA * pBDData) | |||
160 | 160 | ||
161 | PRINTK_2(TRACE_TP3780I, "tp3780i::tp3780I_InitializeBoardData entry pBDData %p\n", pBDData); | 161 | PRINTK_2(TRACE_TP3780I, "tp3780i::tp3780I_InitializeBoardData entry pBDData %p\n", pBDData); |
162 | 162 | ||
163 | pBDData->bDSPEnabled = FALSE; | 163 | pBDData->bDSPEnabled = false; |
164 | pSettings->bInterruptClaimed = FALSE; | 164 | pSettings->bInterruptClaimed = false; |
165 | 165 | ||
166 | retval = smapi_init(); | 166 | retval = smapi_init(); |
167 | if (retval) { | 167 | if (retval) { |
@@ -269,7 +269,7 @@ int tp3780I_ReleaseResources(THINKPAD_BD_DATA * pBDData) | |||
269 | 269 | ||
270 | if (pSettings->bInterruptClaimed) { | 270 | if (pSettings->bInterruptClaimed) { |
271 | free_irq(pSettings->usDspIrq, NULL); | 271 | free_irq(pSettings->usDspIrq, NULL); |
272 | pSettings->bInterruptClaimed = FALSE; | 272 | pSettings->bInterruptClaimed = false; |
273 | } | 273 | } |
274 | 274 | ||
275 | PRINTK_2(TRACE_TP3780I, | 275 | PRINTK_2(TRACE_TP3780I, |
@@ -283,7 +283,7 @@ int tp3780I_ReleaseResources(THINKPAD_BD_DATA * pBDData) | |||
283 | int tp3780I_EnableDSP(THINKPAD_BD_DATA * pBDData) | 283 | int tp3780I_EnableDSP(THINKPAD_BD_DATA * pBDData) |
284 | { | 284 | { |
285 | DSP_3780I_CONFIG_SETTINGS *pSettings = &pBDData->rDspSettings; | 285 | DSP_3780I_CONFIG_SETTINGS *pSettings = &pBDData->rDspSettings; |
286 | BOOLEAN bDSPPoweredUp = FALSE, bInterruptAllocated = FALSE; | 286 | bool bDSPPoweredUp = false, bInterruptAllocated = false; |
287 | 287 | ||
288 | PRINTK_2(TRACE_TP3780I, "tp3780i::tp3780I_EnableDSP entry pBDData %p\n", pBDData); | 288 | PRINTK_2(TRACE_TP3780I, "tp3780i::tp3780I_EnableDSP entry pBDData %p\n", pBDData); |
289 | 289 | ||
@@ -336,14 +336,14 @@ int tp3780I_EnableDSP(THINKPAD_BD_DATA * pBDData) | |||
336 | } | 336 | } |
337 | } | 337 | } |
338 | 338 | ||
339 | pSettings->bDspIrqActiveLow = pSettings->bDspIrqPulse = TRUE; | 339 | pSettings->bDspIrqActiveLow = pSettings->bDspIrqPulse = true; |
340 | pSettings->bUartIrqActiveLow = pSettings->bUartIrqPulse = TRUE; | 340 | pSettings->bUartIrqActiveLow = pSettings->bUartIrqPulse = true; |
341 | 341 | ||
342 | if (pBDData->bShareDspIrq) { | 342 | if (pBDData->bShareDspIrq) { |
343 | pSettings->bDspIrqActiveLow = FALSE; | 343 | pSettings->bDspIrqActiveLow = false; |
344 | } | 344 | } |
345 | if (pBDData->bShareUartIrq) { | 345 | if (pBDData->bShareUartIrq) { |
346 | pSettings->bUartIrqActiveLow = FALSE; | 346 | pSettings->bUartIrqActiveLow = false; |
347 | } | 347 | } |
348 | 348 | ||
349 | pSettings->usNumTransfers = TP_CFG_NumTransfers; | 349 | pSettings->usNumTransfers = TP_CFG_NumTransfers; |
@@ -373,16 +373,16 @@ int tp3780I_EnableDSP(THINKPAD_BD_DATA * pBDData) | |||
373 | PRINTK_3(TRACE_TP3780I, | 373 | PRINTK_3(TRACE_TP3780I, |
374 | "tp3780i::tp3780I_EnableDSP, got interrupt %x bShareDspIrq %x\n", | 374 | "tp3780i::tp3780I_EnableDSP, got interrupt %x bShareDspIrq %x\n", |
375 | pSettings->usDspIrq, pBDData->bShareDspIrq); | 375 | pSettings->usDspIrq, pBDData->bShareDspIrq); |
376 | bInterruptAllocated = TRUE; | 376 | bInterruptAllocated = true; |
377 | pSettings->bInterruptClaimed = TRUE; | 377 | pSettings->bInterruptClaimed = true; |
378 | } | 378 | } |
379 | 379 | ||
380 | smapi_set_DSP_power_state(FALSE); | 380 | smapi_set_DSP_power_state(false); |
381 | if (smapi_set_DSP_power_state(TRUE)) { | 381 | if (smapi_set_DSP_power_state(true)) { |
382 | PRINTK_ERROR(KERN_ERR_MWAVE "tp3780i::tp3780I_EnableDSP: Error: smapi_set_DSP_power_state(TRUE) failed\n"); | 382 | PRINTK_ERROR(KERN_ERR_MWAVE "tp3780i::tp3780I_EnableDSP: Error: smapi_set_DSP_power_state(true) failed\n"); |
383 | goto exit_cleanup; | 383 | goto exit_cleanup; |
384 | } else { | 384 | } else { |
385 | bDSPPoweredUp = TRUE; | 385 | bDSPPoweredUp = true; |
386 | } | 386 | } |
387 | 387 | ||
388 | if (dsp3780I_EnableDSP(pSettings, s_ausThinkpadIrqToField, s_ausThinkpadDmaToField)) { | 388 | if (dsp3780I_EnableDSP(pSettings, s_ausThinkpadIrqToField, s_ausThinkpadDmaToField)) { |
@@ -392,7 +392,7 @@ int tp3780I_EnableDSP(THINKPAD_BD_DATA * pBDData) | |||
392 | 392 | ||
393 | EnableSRAM(pBDData); | 393 | EnableSRAM(pBDData); |
394 | 394 | ||
395 | pBDData->bDSPEnabled = TRUE; | 395 | pBDData->bDSPEnabled = true; |
396 | 396 | ||
397 | PRINTK_1(TRACE_TP3780I, "tp3780i::tp3780I_EnableDSP exit\n"); | 397 | PRINTK_1(TRACE_TP3780I, "tp3780i::tp3780I_EnableDSP exit\n"); |
398 | 398 | ||
@@ -401,10 +401,10 @@ int tp3780I_EnableDSP(THINKPAD_BD_DATA * pBDData) | |||
401 | exit_cleanup: | 401 | exit_cleanup: |
402 | PRINTK_ERROR("tp3780i::tp3780I_EnableDSP: Cleaning up\n"); | 402 | PRINTK_ERROR("tp3780i::tp3780I_EnableDSP: Cleaning up\n"); |
403 | if (bDSPPoweredUp) | 403 | if (bDSPPoweredUp) |
404 | smapi_set_DSP_power_state(FALSE); | 404 | smapi_set_DSP_power_state(false); |
405 | if (bInterruptAllocated) { | 405 | if (bInterruptAllocated) { |
406 | free_irq(pSettings->usDspIrq, NULL); | 406 | free_irq(pSettings->usDspIrq, NULL); |
407 | pSettings->bInterruptClaimed = FALSE; | 407 | pSettings->bInterruptClaimed = false; |
408 | } | 408 | } |
409 | return -EIO; | 409 | return -EIO; |
410 | } | 410 | } |
@@ -421,10 +421,10 @@ int tp3780I_DisableDSP(THINKPAD_BD_DATA * pBDData) | |||
421 | dsp3780I_DisableDSP(&pBDData->rDspSettings); | 421 | dsp3780I_DisableDSP(&pBDData->rDspSettings); |
422 | if (pSettings->bInterruptClaimed) { | 422 | if (pSettings->bInterruptClaimed) { |
423 | free_irq(pSettings->usDspIrq, NULL); | 423 | free_irq(pSettings->usDspIrq, NULL); |
424 | pSettings->bInterruptClaimed = FALSE; | 424 | pSettings->bInterruptClaimed = false; |
425 | } | 425 | } |
426 | smapi_set_DSP_power_state(FALSE); | 426 | smapi_set_DSP_power_state(false); |
427 | pBDData->bDSPEnabled = FALSE; | 427 | pBDData->bDSPEnabled = false; |
428 | } | 428 | } |
429 | 429 | ||
430 | PRINTK_2(TRACE_TP3780I, "tp3780i::tp3780I_DisableDSP exit retval %x\n", retval); | 430 | PRINTK_2(TRACE_TP3780I, "tp3780i::tp3780I_DisableDSP exit retval %x\n", retval); |
@@ -516,7 +516,7 @@ int tp3780I_ReadWriteDspDStore(THINKPAD_BD_DATA * pBDData, unsigned int uOpcode, | |||
516 | int retval = 0; | 516 | int retval = 0; |
517 | DSP_3780I_CONFIG_SETTINGS *pSettings = &pBDData->rDspSettings; | 517 | DSP_3780I_CONFIG_SETTINGS *pSettings = &pBDData->rDspSettings; |
518 | unsigned short usDspBaseIO = pSettings->usDspBaseIO; | 518 | unsigned short usDspBaseIO = pSettings->usDspBaseIO; |
519 | BOOLEAN bRC = 0; | 519 | bool bRC = 0; |
520 | 520 | ||
521 | PRINTK_6(TRACE_TP3780I, | 521 | PRINTK_6(TRACE_TP3780I, |
522 | "tp3780i::tp3780I_ReadWriteDspDStore entry pBDData %p, uOpcode %x, pvBuffer %p, uCount %x, ulDSPAddr %lx\n", | 522 | "tp3780i::tp3780I_ReadWriteDspDStore entry pBDData %p, uOpcode %x, pvBuffer %p, uCount %x, ulDSPAddr %lx\n", |
@@ -552,7 +552,7 @@ int tp3780I_ReadWriteDspIStore(THINKPAD_BD_DATA * pBDData, unsigned int uOpcode, | |||
552 | int retval = 0; | 552 | int retval = 0; |
553 | DSP_3780I_CONFIG_SETTINGS *pSettings = &pBDData->rDspSettings; | 553 | DSP_3780I_CONFIG_SETTINGS *pSettings = &pBDData->rDspSettings; |
554 | unsigned short usDspBaseIO = pSettings->usDspBaseIO; | 554 | unsigned short usDspBaseIO = pSettings->usDspBaseIO; |
555 | BOOLEAN bRC = 0; | 555 | bool bRC = 0; |
556 | 556 | ||
557 | PRINTK_6(TRACE_TP3780I, | 557 | PRINTK_6(TRACE_TP3780I, |
558 | "tp3780i::tp3780I_ReadWriteDspIStore entry pBDData %p, uOpcode %x, pvBuffer %p, uCount %x, ulDSPAddr %lx\n", | 558 | "tp3780i::tp3780I_ReadWriteDspIStore entry pBDData %p, uOpcode %x, pvBuffer %p, uCount %x, ulDSPAddr %lx\n", |
diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c index f8a483c67b07..d23368874710 100644 --- a/drivers/char/ppdev.c +++ b/drivers/char/ppdev.c | |||
@@ -286,7 +286,7 @@ static int register_device(int minor, struct pp_struct *pp) | |||
286 | struct parport *port; | 286 | struct parport *port; |
287 | struct pardevice *pdev = NULL; | 287 | struct pardevice *pdev = NULL; |
288 | char *name; | 288 | char *name; |
289 | int fl; | 289 | struct pardev_cb ppdev_cb; |
290 | 290 | ||
291 | name = kasprintf(GFP_KERNEL, CHRDEV "%x", minor); | 291 | name = kasprintf(GFP_KERNEL, CHRDEV "%x", minor); |
292 | if (name == NULL) | 292 | if (name == NULL) |
@@ -299,9 +299,11 @@ static int register_device(int minor, struct pp_struct *pp) | |||
299 | return -ENXIO; | 299 | return -ENXIO; |
300 | } | 300 | } |
301 | 301 | ||
302 | fl = (pp->flags & PP_EXCL) ? PARPORT_FLAG_EXCL : 0; | 302 | memset(&ppdev_cb, 0, sizeof(ppdev_cb)); |
303 | pdev = parport_register_device(port, name, NULL, | 303 | ppdev_cb.irq_func = pp_irq; |
304 | NULL, pp_irq, fl, pp); | 304 | ppdev_cb.flags = (pp->flags & PP_EXCL) ? PARPORT_FLAG_EXCL : 0; |
305 | ppdev_cb.private = pp; | ||
306 | pdev = parport_register_dev_model(port, name, &ppdev_cb, minor); | ||
305 | parport_put_port(port); | 307 | parport_put_port(port); |
306 | 308 | ||
307 | if (!pdev) { | 309 | if (!pdev) { |
@@ -799,10 +801,23 @@ static void pp_detach(struct parport *port) | |||
799 | device_destroy(ppdev_class, MKDEV(PP_MAJOR, port->number)); | 801 | device_destroy(ppdev_class, MKDEV(PP_MAJOR, port->number)); |
800 | } | 802 | } |
801 | 803 | ||
804 | static int pp_probe(struct pardevice *par_dev) | ||
805 | { | ||
806 | struct device_driver *drv = par_dev->dev.driver; | ||
807 | int len = strlen(drv->name); | ||
808 | |||
809 | if (strncmp(par_dev->name, drv->name, len)) | ||
810 | return -ENODEV; | ||
811 | |||
812 | return 0; | ||
813 | } | ||
814 | |||
802 | static struct parport_driver pp_driver = { | 815 | static struct parport_driver pp_driver = { |
803 | .name = CHRDEV, | 816 | .name = CHRDEV, |
804 | .attach = pp_attach, | 817 | .probe = pp_probe, |
818 | .match_port = pp_attach, | ||
805 | .detach = pp_detach, | 819 | .detach = pp_detach, |
820 | .devmodel = true, | ||
806 | }; | 821 | }; |
807 | 822 | ||
808 | static int __init ppdev_init(void) | 823 | static int __init ppdev_init(void) |
diff --git a/drivers/char/snsc.c b/drivers/char/snsc.c index 94006f9c2e43..10e56323f390 100644 --- a/drivers/char/snsc.c +++ b/drivers/char/snsc.c | |||
@@ -385,13 +385,18 @@ scdrv_init(void) | |||
385 | 385 | ||
386 | event_nasid = ia64_sn_get_console_nasid(); | 386 | event_nasid = ia64_sn_get_console_nasid(); |
387 | 387 | ||
388 | snsc_class = class_create(THIS_MODULE, SYSCTL_BASENAME); | ||
389 | if (IS_ERR(snsc_class)) { | ||
390 | printk("%s: failed to allocate class\n", __func__); | ||
391 | return PTR_ERR(snsc_class); | ||
392 | } | ||
393 | |||
388 | if (alloc_chrdev_region(&first_dev, 0, num_cnodes, | 394 | if (alloc_chrdev_region(&first_dev, 0, num_cnodes, |
389 | SYSCTL_BASENAME) < 0) { | 395 | SYSCTL_BASENAME) < 0) { |
390 | printk("%s: failed to register SN system controller device\n", | 396 | printk("%s: failed to register SN system controller device\n", |
391 | __func__); | 397 | __func__); |
392 | return -ENODEV; | 398 | return -ENODEV; |
393 | } | 399 | } |
394 | snsc_class = class_create(THIS_MODULE, SYSCTL_BASENAME); | ||
395 | 400 | ||
396 | for (cnode = 0; cnode < num_cnodes; cnode++) { | 401 | for (cnode = 0; cnode < num_cnodes; cnode++) { |
397 | geoid = cnodeid_get_geoid(cnode); | 402 | geoid = cnodeid_get_geoid(cnode); |
diff --git a/drivers/char/tile-srom.c b/drivers/char/tile-srom.c index 69f6b4acc377..398800edb2cc 100644 --- a/drivers/char/tile-srom.c +++ b/drivers/char/tile-srom.c | |||
@@ -331,13 +331,11 @@ static const struct file_operations srom_fops = { | |||
331 | /** | 331 | /** |
332 | * srom_setup_minor() - Initialize per-minor information. | 332 | * srom_setup_minor() - Initialize per-minor information. |
333 | * @srom: Per-device SROM state. | 333 | * @srom: Per-device SROM state. |
334 | * @index: Device to set up. | 334 | * @devhdl: Partition device handle. |
335 | */ | 335 | */ |
336 | static int srom_setup_minor(struct srom_dev *srom, int index) | 336 | static int srom_setup_minor(struct srom_dev *srom, int devhdl) |
337 | { | 337 | { |
338 | struct device *dev; | 338 | srom->hv_devhdl = devhdl; |
339 | int devhdl = srom->hv_devhdl; | ||
340 | |||
341 | mutex_init(&srom->lock); | 339 | mutex_init(&srom->lock); |
342 | 340 | ||
343 | if (_srom_read(devhdl, &srom->total_size, | 341 | if (_srom_read(devhdl, &srom->total_size, |
@@ -350,9 +348,7 @@ static int srom_setup_minor(struct srom_dev *srom, int index) | |||
350 | SROM_PAGE_SIZE_OFF, sizeof(srom->page_size)) < 0) | 348 | SROM_PAGE_SIZE_OFF, sizeof(srom->page_size)) < 0) |
351 | return -EIO; | 349 | return -EIO; |
352 | 350 | ||
353 | dev = device_create(srom_class, &srom_parent->dev, | 351 | return 0; |
354 | MKDEV(srom_major, index), srom, "%d", index); | ||
355 | return PTR_ERR_OR_ZERO(dev); | ||
356 | } | 352 | } |
357 | 353 | ||
358 | /** srom_init() - Initialize the driver's module. */ | 354 | /** srom_init() - Initialize the driver's module. */ |
@@ -365,7 +361,7 @@ static int srom_init(void) | |||
365 | * Start with a plausible number of partitions; the krealloc() call | 361 | * Start with a plausible number of partitions; the krealloc() call |
366 | * below will yield about log(srom_devs) additional allocations. | 362 | * below will yield about log(srom_devs) additional allocations. |
367 | */ | 363 | */ |
368 | srom_devices = kzalloc(4 * sizeof(struct srom_dev), GFP_KERNEL); | 364 | srom_devices = kmalloc(4 * sizeof(struct srom_dev), GFP_KERNEL); |
369 | 365 | ||
370 | /* Discover the number of srom partitions. */ | 366 | /* Discover the number of srom partitions. */ |
371 | for (i = 0; ; i++) { | 367 | for (i = 0; ; i++) { |
@@ -373,7 +369,7 @@ static int srom_init(void) | |||
373 | char buf[20]; | 369 | char buf[20]; |
374 | struct srom_dev *new_srom_devices = | 370 | struct srom_dev *new_srom_devices = |
375 | krealloc(srom_devices, (i+1) * sizeof(struct srom_dev), | 371 | krealloc(srom_devices, (i+1) * sizeof(struct srom_dev), |
376 | GFP_KERNEL | __GFP_ZERO); | 372 | GFP_KERNEL); |
377 | if (!new_srom_devices) { | 373 | if (!new_srom_devices) { |
378 | result = -ENOMEM; | 374 | result = -ENOMEM; |
379 | goto fail_mem; | 375 | goto fail_mem; |
@@ -387,7 +383,9 @@ static int srom_init(void) | |||
387 | i, devhdl); | 383 | i, devhdl); |
388 | break; | 384 | break; |
389 | } | 385 | } |
390 | srom_devices[i].hv_devhdl = devhdl; | 386 | result = srom_setup_minor(&srom_devices[i], devhdl); |
387 | if (result != 0) | ||
388 | goto fail_mem; | ||
391 | } | 389 | } |
392 | srom_devs = i; | 390 | srom_devs = i; |
393 | 391 | ||
@@ -431,9 +429,13 @@ static int srom_init(void) | |||
431 | srom_class->dev_groups = srom_dev_groups; | 429 | srom_class->dev_groups = srom_dev_groups; |
432 | srom_class->devnode = srom_devnode; | 430 | srom_class->devnode = srom_devnode; |
433 | 431 | ||
434 | /* Do per-partition initialization */ | 432 | /* Create per-partition devices */ |
435 | for (i = 0; i < srom_devs; i++) { | 433 | for (i = 0; i < srom_devs; i++) { |
436 | result = srom_setup_minor(srom_devices + i, i); | 434 | struct device *dev = |
435 | device_create(srom_class, &srom_parent->dev, | ||
436 | MKDEV(srom_major, i), srom_devices + i, | ||
437 | "%d", i); | ||
438 | result = PTR_ERR_OR_ZERO(dev); | ||
437 | if (result < 0) | 439 | if (result < 0) |
438 | goto fail_class; | 440 | goto fail_class; |
439 | } | 441 | } |
diff --git a/drivers/char/ttyprintk.c b/drivers/char/ttyprintk.c index b098d2d0b7c4..67549ce88cc9 100644 --- a/drivers/char/ttyprintk.c +++ b/drivers/char/ttyprintk.c | |||
@@ -31,60 +31,53 @@ static struct ttyprintk_port tpk_port; | |||
31 | * printk messages (also suitable for logging service): | 31 | * printk messages (also suitable for logging service): |
32 | * - any cr is replaced by nl | 32 | * - any cr is replaced by nl |
33 | * - adds a ttyprintk source tag in front of each line | 33 | * - adds a ttyprintk source tag in front of each line |
34 | * - too long message is fragmeted, with '\'nl between fragments | 34 | * - too long message is fragmented, with '\'nl between fragments |
35 | * - TPK_STR_SIZE isn't really the write_room limiting factor, bcause | 35 | * - TPK_STR_SIZE isn't really the write_room limiting factor, because |
36 | * it is emptied on the fly during preformatting. | 36 | * it is emptied on the fly during preformatting. |
37 | */ | 37 | */ |
38 | #define TPK_STR_SIZE 508 /* should be bigger then max expected line length */ | 38 | #define TPK_STR_SIZE 508 /* should be bigger then max expected line length */ |
39 | #define TPK_MAX_ROOM 4096 /* we could assume 4K for instance */ | 39 | #define TPK_MAX_ROOM 4096 /* we could assume 4K for instance */ |
40 | static const char *tpk_tag = "[U] "; /* U for User */ | ||
41 | static int tpk_curr; | 40 | static int tpk_curr; |
42 | 41 | ||
42 | static char tpk_buffer[TPK_STR_SIZE + 4]; | ||
43 | |||
44 | static void tpk_flush(void) | ||
45 | { | ||
46 | if (tpk_curr > 0) { | ||
47 | tpk_buffer[tpk_curr] = '\0'; | ||
48 | pr_info("[U] %s\n", tpk_buffer); | ||
49 | tpk_curr = 0; | ||
50 | } | ||
51 | } | ||
52 | |||
43 | static int tpk_printk(const unsigned char *buf, int count) | 53 | static int tpk_printk(const unsigned char *buf, int count) |
44 | { | 54 | { |
45 | static char tmp[TPK_STR_SIZE + 4]; | ||
46 | int i = tpk_curr; | 55 | int i = tpk_curr; |
47 | 56 | ||
48 | if (buf == NULL) { | 57 | if (buf == NULL) { |
49 | /* flush tmp[] */ | 58 | tpk_flush(); |
50 | if (tpk_curr > 0) { | ||
51 | /* non nl or cr terminated message - add nl */ | ||
52 | tmp[tpk_curr + 0] = '\n'; | ||
53 | tmp[tpk_curr + 1] = '\0'; | ||
54 | printk(KERN_INFO "%s%s", tpk_tag, tmp); | ||
55 | tpk_curr = 0; | ||
56 | } | ||
57 | return i; | 59 | return i; |
58 | } | 60 | } |
59 | 61 | ||
60 | for (i = 0; i < count; i++) { | 62 | for (i = 0; i < count; i++) { |
61 | tmp[tpk_curr] = buf[i]; | 63 | if (tpk_curr >= TPK_STR_SIZE) { |
62 | if (tpk_curr < TPK_STR_SIZE) { | ||
63 | switch (buf[i]) { | ||
64 | case '\r': | ||
65 | /* replace cr with nl */ | ||
66 | tmp[tpk_curr + 0] = '\n'; | ||
67 | tmp[tpk_curr + 1] = '\0'; | ||
68 | printk(KERN_INFO "%s%s", tpk_tag, tmp); | ||
69 | tpk_curr = 0; | ||
70 | if ((i + 1) < count && buf[i + 1] == '\n') | ||
71 | i++; | ||
72 | break; | ||
73 | case '\n': | ||
74 | tmp[tpk_curr + 1] = '\0'; | ||
75 | printk(KERN_INFO "%s%s", tpk_tag, tmp); | ||
76 | tpk_curr = 0; | ||
77 | break; | ||
78 | default: | ||
79 | tpk_curr++; | ||
80 | } | ||
81 | } else { | ||
82 | /* end of tmp buffer reached: cut the message in two */ | 64 | /* end of tmp buffer reached: cut the message in two */ |
83 | tmp[tpk_curr + 1] = '\\'; | 65 | tpk_buffer[tpk_curr++] = '\\'; |
84 | tmp[tpk_curr + 2] = '\n'; | 66 | tpk_flush(); |
85 | tmp[tpk_curr + 3] = '\0'; | 67 | } |
86 | printk(KERN_INFO "%s%s", tpk_tag, tmp); | 68 | |
87 | tpk_curr = 0; | 69 | switch (buf[i]) { |
70 | case '\r': | ||
71 | tpk_flush(); | ||
72 | if ((i + 1) < count && buf[i + 1] == '\n') | ||
73 | i++; | ||
74 | break; | ||
75 | case '\n': | ||
76 | tpk_flush(); | ||
77 | break; | ||
78 | default: | ||
79 | tpk_buffer[tpk_curr++] = buf[i]; | ||
80 | break; | ||
88 | } | 81 | } |
89 | } | 82 | } |
90 | 83 | ||
diff --git a/drivers/char/xillybus/xillybus_core.c b/drivers/char/xillybus/xillybus_core.c index dcd19f3f182e..b6c9cdead7f3 100644 --- a/drivers/char/xillybus/xillybus_core.c +++ b/drivers/char/xillybus/xillybus_core.c | |||
@@ -655,10 +655,10 @@ static int xilly_obtain_idt(struct xilly_endpoint *endpoint) | |||
655 | 655 | ||
656 | version = channel->wr_buffers[0]->addr; | 656 | version = channel->wr_buffers[0]->addr; |
657 | 657 | ||
658 | /* Check version number. Accept anything below 0x82 for now. */ | 658 | /* Check version number. Reject anything above 0x82. */ |
659 | if (*version > 0x82) { | 659 | if (*version > 0x82) { |
660 | dev_err(endpoint->dev, | 660 | dev_err(endpoint->dev, |
661 | "No support for IDT version 0x%02x. Maybe the xillybus driver needs an upgarde. Aborting.\n", | 661 | "No support for IDT version 0x%02x. Maybe the xillybus driver needs an upgrade. Aborting.\n", |
662 | *version); | 662 | *version); |
663 | return -ENODEV; | 663 | return -ENODEV; |
664 | } | 664 | } |
diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig index d61410299ec0..cd84934774cc 100644 --- a/drivers/fpga/Kconfig +++ b/drivers/fpga/Kconfig | |||
@@ -21,6 +21,7 @@ config FPGA_MGR_SOCFPGA | |||
21 | 21 | ||
22 | config FPGA_MGR_ZYNQ_FPGA | 22 | config FPGA_MGR_ZYNQ_FPGA |
23 | tristate "Xilinx Zynq FPGA" | 23 | tristate "Xilinx Zynq FPGA" |
24 | depends on ARCH_ZYNQ || COMPILE_TEST | ||
24 | depends on HAS_DMA | 25 | depends on HAS_DMA |
25 | help | 26 | help |
26 | FPGA manager driver support for Xilinx Zynq FPGAs. | 27 | FPGA manager driver support for Xilinx Zynq FPGAs. |
diff --git a/drivers/hid/uhid.c b/drivers/hid/uhid.c index 99ec3ff7563b..7f8ff39ed44b 100644 --- a/drivers/hid/uhid.c +++ b/drivers/hid/uhid.c | |||
@@ -779,19 +779,8 @@ static struct miscdevice uhid_misc = { | |||
779 | .minor = UHID_MINOR, | 779 | .minor = UHID_MINOR, |
780 | .name = UHID_NAME, | 780 | .name = UHID_NAME, |
781 | }; | 781 | }; |
782 | module_misc_device(uhid_misc); | ||
782 | 783 | ||
783 | static int __init uhid_init(void) | ||
784 | { | ||
785 | return misc_register(&uhid_misc); | ||
786 | } | ||
787 | |||
788 | static void __exit uhid_exit(void) | ||
789 | { | ||
790 | misc_deregister(&uhid_misc); | ||
791 | } | ||
792 | |||
793 | module_init(uhid_init); | ||
794 | module_exit(uhid_exit); | ||
795 | MODULE_LICENSE("GPL"); | 784 | MODULE_LICENSE("GPL"); |
796 | MODULE_AUTHOR("David Herrmann <dh.herrmann@gmail.com>"); | 785 | MODULE_AUTHOR("David Herrmann <dh.herrmann@gmail.com>"); |
797 | MODULE_DESCRIPTION("User-space I/O driver support for HID subsystem"); | 786 | MODULE_DESCRIPTION("User-space I/O driver support for HID subsystem"); |
diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c index 56dd261f7142..16f91c8490fe 100644 --- a/drivers/hv/channel.c +++ b/drivers/hv/channel.c | |||
@@ -43,7 +43,12 @@ static void vmbus_setevent(struct vmbus_channel *channel) | |||
43 | { | 43 | { |
44 | struct hv_monitor_page *monitorpage; | 44 | struct hv_monitor_page *monitorpage; |
45 | 45 | ||
46 | if (channel->offermsg.monitor_allocated) { | 46 | /* |
47 | * For channels marked as in "low latency" mode | ||
48 | * bypass the monitor page mechanism. | ||
49 | */ | ||
50 | if ((channel->offermsg.monitor_allocated) && | ||
51 | (!channel->low_latency)) { | ||
47 | /* Each u32 represents 32 channels */ | 52 | /* Each u32 represents 32 channels */ |
48 | sync_set_bit(channel->offermsg.child_relid & 31, | 53 | sync_set_bit(channel->offermsg.child_relid & 31, |
49 | (unsigned long *) vmbus_connection.send_int_page + | 54 | (unsigned long *) vmbus_connection.send_int_page + |
@@ -70,12 +75,14 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size, | |||
70 | { | 75 | { |
71 | struct vmbus_channel_open_channel *open_msg; | 76 | struct vmbus_channel_open_channel *open_msg; |
72 | struct vmbus_channel_msginfo *open_info = NULL; | 77 | struct vmbus_channel_msginfo *open_info = NULL; |
73 | void *in, *out; | ||
74 | unsigned long flags; | 78 | unsigned long flags; |
75 | int ret, err = 0; | 79 | int ret, err = 0; |
76 | unsigned long t; | ||
77 | struct page *page; | 80 | struct page *page; |
78 | 81 | ||
82 | if (send_ringbuffer_size % PAGE_SIZE || | ||
83 | recv_ringbuffer_size % PAGE_SIZE) | ||
84 | return -EINVAL; | ||
85 | |||
79 | spin_lock_irqsave(&newchannel->lock, flags); | 86 | spin_lock_irqsave(&newchannel->lock, flags); |
80 | if (newchannel->state == CHANNEL_OPEN_STATE) { | 87 | if (newchannel->state == CHANNEL_OPEN_STATE) { |
81 | newchannel->state = CHANNEL_OPENING_STATE; | 88 | newchannel->state = CHANNEL_OPENING_STATE; |
@@ -95,36 +102,33 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size, | |||
95 | recv_ringbuffer_size)); | 102 | recv_ringbuffer_size)); |
96 | 103 | ||
97 | if (!page) | 104 | if (!page) |
98 | out = (void *)__get_free_pages(GFP_KERNEL|__GFP_ZERO, | 105 | page = alloc_pages(GFP_KERNEL|__GFP_ZERO, |
99 | get_order(send_ringbuffer_size + | 106 | get_order(send_ringbuffer_size + |
100 | recv_ringbuffer_size)); | 107 | recv_ringbuffer_size)); |
101 | else | ||
102 | out = (void *)page_address(page); | ||
103 | 108 | ||
104 | if (!out) { | 109 | if (!page) { |
105 | err = -ENOMEM; | 110 | err = -ENOMEM; |
106 | goto error0; | 111 | goto error_set_chnstate; |
107 | } | 112 | } |
108 | 113 | ||
109 | in = (void *)((unsigned long)out + send_ringbuffer_size); | 114 | newchannel->ringbuffer_pages = page_address(page); |
110 | |||
111 | newchannel->ringbuffer_pages = out; | ||
112 | newchannel->ringbuffer_pagecount = (send_ringbuffer_size + | 115 | newchannel->ringbuffer_pagecount = (send_ringbuffer_size + |
113 | recv_ringbuffer_size) >> PAGE_SHIFT; | 116 | recv_ringbuffer_size) >> PAGE_SHIFT; |
114 | 117 | ||
115 | ret = hv_ringbuffer_init( | 118 | ret = hv_ringbuffer_init(&newchannel->outbound, page, |
116 | &newchannel->outbound, out, send_ringbuffer_size); | 119 | send_ringbuffer_size >> PAGE_SHIFT); |
117 | 120 | ||
118 | if (ret != 0) { | 121 | if (ret != 0) { |
119 | err = ret; | 122 | err = ret; |
120 | goto error0; | 123 | goto error_free_pages; |
121 | } | 124 | } |
122 | 125 | ||
123 | ret = hv_ringbuffer_init( | 126 | ret = hv_ringbuffer_init(&newchannel->inbound, |
124 | &newchannel->inbound, in, recv_ringbuffer_size); | 127 | &page[send_ringbuffer_size >> PAGE_SHIFT], |
128 | recv_ringbuffer_size >> PAGE_SHIFT); | ||
125 | if (ret != 0) { | 129 | if (ret != 0) { |
126 | err = ret; | 130 | err = ret; |
127 | goto error0; | 131 | goto error_free_pages; |
128 | } | 132 | } |
129 | 133 | ||
130 | 134 | ||
@@ -132,14 +136,14 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size, | |||
132 | newchannel->ringbuffer_gpadlhandle = 0; | 136 | newchannel->ringbuffer_gpadlhandle = 0; |
133 | 137 | ||
134 | ret = vmbus_establish_gpadl(newchannel, | 138 | ret = vmbus_establish_gpadl(newchannel, |
135 | newchannel->outbound.ring_buffer, | 139 | page_address(page), |
136 | send_ringbuffer_size + | 140 | send_ringbuffer_size + |
137 | recv_ringbuffer_size, | 141 | recv_ringbuffer_size, |
138 | &newchannel->ringbuffer_gpadlhandle); | 142 | &newchannel->ringbuffer_gpadlhandle); |
139 | 143 | ||
140 | if (ret != 0) { | 144 | if (ret != 0) { |
141 | err = ret; | 145 | err = ret; |
142 | goto error0; | 146 | goto error_free_pages; |
143 | } | 147 | } |
144 | 148 | ||
145 | /* Create and init the channel open message */ | 149 | /* Create and init the channel open message */ |
@@ -148,7 +152,7 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size, | |||
148 | GFP_KERNEL); | 152 | GFP_KERNEL); |
149 | if (!open_info) { | 153 | if (!open_info) { |
150 | err = -ENOMEM; | 154 | err = -ENOMEM; |
151 | goto error_gpadl; | 155 | goto error_free_gpadl; |
152 | } | 156 | } |
153 | 157 | ||
154 | init_completion(&open_info->waitevent); | 158 | init_completion(&open_info->waitevent); |
@@ -164,7 +168,7 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size, | |||
164 | 168 | ||
165 | if (userdatalen > MAX_USER_DEFINED_BYTES) { | 169 | if (userdatalen > MAX_USER_DEFINED_BYTES) { |
166 | err = -EINVAL; | 170 | err = -EINVAL; |
167 | goto error_gpadl; | 171 | goto error_free_gpadl; |
168 | } | 172 | } |
169 | 173 | ||
170 | if (userdatalen) | 174 | if (userdatalen) |
@@ -180,14 +184,10 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size, | |||
180 | 184 | ||
181 | if (ret != 0) { | 185 | if (ret != 0) { |
182 | err = ret; | 186 | err = ret; |
183 | goto error1; | 187 | goto error_clean_msglist; |
184 | } | 188 | } |
185 | 189 | ||
186 | t = wait_for_completion_timeout(&open_info->waitevent, 5*HZ); | 190 | wait_for_completion(&open_info->waitevent); |
187 | if (t == 0) { | ||
188 | err = -ETIMEDOUT; | ||
189 | goto error1; | ||
190 | } | ||
191 | 191 | ||
192 | spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags); | 192 | spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags); |
193 | list_del(&open_info->msglistentry); | 193 | list_del(&open_info->msglistentry); |
@@ -195,25 +195,27 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size, | |||
195 | 195 | ||
196 | if (open_info->response.open_result.status) { | 196 | if (open_info->response.open_result.status) { |
197 | err = -EAGAIN; | 197 | err = -EAGAIN; |
198 | goto error_gpadl; | 198 | goto error_free_gpadl; |
199 | } | 199 | } |
200 | 200 | ||
201 | newchannel->state = CHANNEL_OPENED_STATE; | 201 | newchannel->state = CHANNEL_OPENED_STATE; |
202 | kfree(open_info); | 202 | kfree(open_info); |
203 | return 0; | 203 | return 0; |
204 | 204 | ||
205 | error1: | 205 | error_clean_msglist: |
206 | spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags); | 206 | spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags); |
207 | list_del(&open_info->msglistentry); | 207 | list_del(&open_info->msglistentry); |
208 | spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags); | 208 | spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags); |
209 | 209 | ||
210 | error_gpadl: | 210 | error_free_gpadl: |
211 | vmbus_teardown_gpadl(newchannel, newchannel->ringbuffer_gpadlhandle); | 211 | vmbus_teardown_gpadl(newchannel, newchannel->ringbuffer_gpadlhandle); |
212 | |||
213 | error0: | ||
214 | free_pages((unsigned long)out, | ||
215 | get_order(send_ringbuffer_size + recv_ringbuffer_size)); | ||
216 | kfree(open_info); | 212 | kfree(open_info); |
213 | error_free_pages: | ||
214 | hv_ringbuffer_cleanup(&newchannel->outbound); | ||
215 | hv_ringbuffer_cleanup(&newchannel->inbound); | ||
216 | __free_pages(page, | ||
217 | get_order(send_ringbuffer_size + recv_ringbuffer_size)); | ||
218 | error_set_chnstate: | ||
217 | newchannel->state = CHANNEL_OPEN_STATE; | 219 | newchannel->state = CHANNEL_OPEN_STATE; |
218 | return err; | 220 | return err; |
219 | } | 221 | } |
@@ -238,8 +240,7 @@ EXPORT_SYMBOL_GPL(vmbus_send_tl_connect_request); | |||
238 | * create_gpadl_header - Creates a gpadl for the specified buffer | 240 | * create_gpadl_header - Creates a gpadl for the specified buffer |
239 | */ | 241 | */ |
240 | static int create_gpadl_header(void *kbuffer, u32 size, | 242 | static int create_gpadl_header(void *kbuffer, u32 size, |
241 | struct vmbus_channel_msginfo **msginfo, | 243 | struct vmbus_channel_msginfo **msginfo) |
242 | u32 *messagecount) | ||
243 | { | 244 | { |
244 | int i; | 245 | int i; |
245 | int pagecount; | 246 | int pagecount; |
@@ -283,7 +284,6 @@ static int create_gpadl_header(void *kbuffer, u32 size, | |||
283 | gpadl_header->range[0].pfn_array[i] = slow_virt_to_phys( | 284 | gpadl_header->range[0].pfn_array[i] = slow_virt_to_phys( |
284 | kbuffer + PAGE_SIZE * i) >> PAGE_SHIFT; | 285 | kbuffer + PAGE_SIZE * i) >> PAGE_SHIFT; |
285 | *msginfo = msgheader; | 286 | *msginfo = msgheader; |
286 | *messagecount = 1; | ||
287 | 287 | ||
288 | pfnsum = pfncount; | 288 | pfnsum = pfncount; |
289 | pfnleft = pagecount - pfncount; | 289 | pfnleft = pagecount - pfncount; |
@@ -323,7 +323,6 @@ static int create_gpadl_header(void *kbuffer, u32 size, | |||
323 | } | 323 | } |
324 | 324 | ||
325 | msgbody->msgsize = msgsize; | 325 | msgbody->msgsize = msgsize; |
326 | (*messagecount)++; | ||
327 | gpadl_body = | 326 | gpadl_body = |
328 | (struct vmbus_channel_gpadl_body *)msgbody->msg; | 327 | (struct vmbus_channel_gpadl_body *)msgbody->msg; |
329 | 328 | ||
@@ -352,6 +351,8 @@ static int create_gpadl_header(void *kbuffer, u32 size, | |||
352 | msgheader = kzalloc(msgsize, GFP_KERNEL); | 351 | msgheader = kzalloc(msgsize, GFP_KERNEL); |
353 | if (msgheader == NULL) | 352 | if (msgheader == NULL) |
354 | goto nomem; | 353 | goto nomem; |
354 | |||
355 | INIT_LIST_HEAD(&msgheader->submsglist); | ||
355 | msgheader->msgsize = msgsize; | 356 | msgheader->msgsize = msgsize; |
356 | 357 | ||
357 | gpadl_header = (struct vmbus_channel_gpadl_header *) | 358 | gpadl_header = (struct vmbus_channel_gpadl_header *) |
@@ -366,7 +367,6 @@ static int create_gpadl_header(void *kbuffer, u32 size, | |||
366 | kbuffer + PAGE_SIZE * i) >> PAGE_SHIFT; | 367 | kbuffer + PAGE_SIZE * i) >> PAGE_SHIFT; |
367 | 368 | ||
368 | *msginfo = msgheader; | 369 | *msginfo = msgheader; |
369 | *messagecount = 1; | ||
370 | } | 370 | } |
371 | 371 | ||
372 | return 0; | 372 | return 0; |
@@ -390,8 +390,7 @@ int vmbus_establish_gpadl(struct vmbus_channel *channel, void *kbuffer, | |||
390 | struct vmbus_channel_gpadl_header *gpadlmsg; | 390 | struct vmbus_channel_gpadl_header *gpadlmsg; |
391 | struct vmbus_channel_gpadl_body *gpadl_body; | 391 | struct vmbus_channel_gpadl_body *gpadl_body; |
392 | struct vmbus_channel_msginfo *msginfo = NULL; | 392 | struct vmbus_channel_msginfo *msginfo = NULL; |
393 | struct vmbus_channel_msginfo *submsginfo; | 393 | struct vmbus_channel_msginfo *submsginfo, *tmp; |
394 | u32 msgcount; | ||
395 | struct list_head *curr; | 394 | struct list_head *curr; |
396 | u32 next_gpadl_handle; | 395 | u32 next_gpadl_handle; |
397 | unsigned long flags; | 396 | unsigned long flags; |
@@ -400,7 +399,7 @@ int vmbus_establish_gpadl(struct vmbus_channel *channel, void *kbuffer, | |||
400 | next_gpadl_handle = | 399 | next_gpadl_handle = |
401 | (atomic_inc_return(&vmbus_connection.next_gpadl_handle) - 1); | 400 | (atomic_inc_return(&vmbus_connection.next_gpadl_handle) - 1); |
402 | 401 | ||
403 | ret = create_gpadl_header(kbuffer, size, &msginfo, &msgcount); | 402 | ret = create_gpadl_header(kbuffer, size, &msginfo); |
404 | if (ret) | 403 | if (ret) |
405 | return ret; | 404 | return ret; |
406 | 405 | ||
@@ -423,24 +422,21 @@ int vmbus_establish_gpadl(struct vmbus_channel *channel, void *kbuffer, | |||
423 | if (ret != 0) | 422 | if (ret != 0) |
424 | goto cleanup; | 423 | goto cleanup; |
425 | 424 | ||
426 | if (msgcount > 1) { | 425 | list_for_each(curr, &msginfo->submsglist) { |
427 | list_for_each(curr, &msginfo->submsglist) { | 426 | submsginfo = (struct vmbus_channel_msginfo *)curr; |
428 | 427 | gpadl_body = | |
429 | submsginfo = (struct vmbus_channel_msginfo *)curr; | 428 | (struct vmbus_channel_gpadl_body *)submsginfo->msg; |
430 | gpadl_body = | ||
431 | (struct vmbus_channel_gpadl_body *)submsginfo->msg; | ||
432 | 429 | ||
433 | gpadl_body->header.msgtype = | 430 | gpadl_body->header.msgtype = |
434 | CHANNELMSG_GPADL_BODY; | 431 | CHANNELMSG_GPADL_BODY; |
435 | gpadl_body->gpadl = next_gpadl_handle; | 432 | gpadl_body->gpadl = next_gpadl_handle; |
436 | 433 | ||
437 | ret = vmbus_post_msg(gpadl_body, | 434 | ret = vmbus_post_msg(gpadl_body, |
438 | submsginfo->msgsize - | 435 | submsginfo->msgsize - |
439 | sizeof(*submsginfo)); | 436 | sizeof(*submsginfo)); |
440 | if (ret != 0) | 437 | if (ret != 0) |
441 | goto cleanup; | 438 | goto cleanup; |
442 | 439 | ||
443 | } | ||
444 | } | 440 | } |
445 | wait_for_completion(&msginfo->waitevent); | 441 | wait_for_completion(&msginfo->waitevent); |
446 | 442 | ||
@@ -451,6 +447,10 @@ cleanup: | |||
451 | spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags); | 447 | spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags); |
452 | list_del(&msginfo->msglistentry); | 448 | list_del(&msginfo->msglistentry); |
453 | spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags); | 449 | spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags); |
450 | list_for_each_entry_safe(submsginfo, tmp, &msginfo->submsglist, | ||
451 | msglistentry) { | ||
452 | kfree(submsginfo); | ||
453 | } | ||
454 | 454 | ||
455 | kfree(msginfo); | 455 | kfree(msginfo); |
456 | return ret; | 456 | return ret; |
@@ -512,7 +512,6 @@ static void reset_channel_cb(void *arg) | |||
512 | static int vmbus_close_internal(struct vmbus_channel *channel) | 512 | static int vmbus_close_internal(struct vmbus_channel *channel) |
513 | { | 513 | { |
514 | struct vmbus_channel_close_channel *msg; | 514 | struct vmbus_channel_close_channel *msg; |
515 | struct tasklet_struct *tasklet; | ||
516 | int ret; | 515 | int ret; |
517 | 516 | ||
518 | /* | 517 | /* |
@@ -524,8 +523,7 @@ static int vmbus_close_internal(struct vmbus_channel *channel) | |||
524 | * To resolve the race, we can serialize them by disabling the | 523 | * To resolve the race, we can serialize them by disabling the |
525 | * tasklet when the latter is running here. | 524 | * tasklet when the latter is running here. |
526 | */ | 525 | */ |
527 | tasklet = hv_context.event_dpc[channel->target_cpu]; | 526 | hv_event_tasklet_disable(channel); |
528 | tasklet_disable(tasklet); | ||
529 | 527 | ||
530 | /* | 528 | /* |
531 | * In case a device driver's probe() fails (e.g., | 529 | * In case a device driver's probe() fails (e.g., |
@@ -591,7 +589,7 @@ static int vmbus_close_internal(struct vmbus_channel *channel) | |||
591 | get_order(channel->ringbuffer_pagecount * PAGE_SIZE)); | 589 | get_order(channel->ringbuffer_pagecount * PAGE_SIZE)); |
592 | 590 | ||
593 | out: | 591 | out: |
594 | tasklet_enable(tasklet); | 592 | hv_event_tasklet_enable(channel); |
595 | 593 | ||
596 | return ret; | 594 | return ret; |
597 | } | 595 | } |
@@ -659,7 +657,7 @@ int vmbus_sendpacket_ctl(struct vmbus_channel *channel, void *buffer, | |||
659 | bufferlist[2].iov_len = (packetlen_aligned - packetlen); | 657 | bufferlist[2].iov_len = (packetlen_aligned - packetlen); |
660 | 658 | ||
661 | ret = hv_ringbuffer_write(&channel->outbound, bufferlist, num_vecs, | 659 | ret = hv_ringbuffer_write(&channel->outbound, bufferlist, num_vecs, |
662 | &signal, lock); | 660 | &signal, lock, channel->signal_policy); |
663 | 661 | ||
664 | /* | 662 | /* |
665 | * Signalling the host is conditional on many factors: | 663 | * Signalling the host is conditional on many factors: |
@@ -680,11 +678,6 @@ int vmbus_sendpacket_ctl(struct vmbus_channel *channel, void *buffer, | |||
680 | * mechanism which can hurt the performance otherwise. | 678 | * mechanism which can hurt the performance otherwise. |
681 | */ | 679 | */ |
682 | 680 | ||
683 | if (channel->signal_policy) | ||
684 | signal = true; | ||
685 | else | ||
686 | kick_q = true; | ||
687 | |||
688 | if (((ret == 0) && kick_q && signal) || | 681 | if (((ret == 0) && kick_q && signal) || |
689 | (ret && !is_hvsock_channel(channel))) | 682 | (ret && !is_hvsock_channel(channel))) |
690 | vmbus_setevent(channel); | 683 | vmbus_setevent(channel); |
@@ -777,7 +770,7 @@ int vmbus_sendpacket_pagebuffer_ctl(struct vmbus_channel *channel, | |||
777 | bufferlist[2].iov_len = (packetlen_aligned - packetlen); | 770 | bufferlist[2].iov_len = (packetlen_aligned - packetlen); |
778 | 771 | ||
779 | ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3, | 772 | ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3, |
780 | &signal, lock); | 773 | &signal, lock, channel->signal_policy); |
781 | 774 | ||
782 | /* | 775 | /* |
783 | * Signalling the host is conditional on many factors: | 776 | * Signalling the host is conditional on many factors: |
@@ -795,11 +788,6 @@ int vmbus_sendpacket_pagebuffer_ctl(struct vmbus_channel *channel, | |||
795 | * enough condition that it should not matter. | 788 | * enough condition that it should not matter. |
796 | */ | 789 | */ |
797 | 790 | ||
798 | if (channel->signal_policy) | ||
799 | signal = true; | ||
800 | else | ||
801 | kick_q = true; | ||
802 | |||
803 | if (((ret == 0) && kick_q && signal) || (ret)) | 791 | if (((ret == 0) && kick_q && signal) || (ret)) |
804 | vmbus_setevent(channel); | 792 | vmbus_setevent(channel); |
805 | 793 | ||
@@ -861,7 +849,7 @@ int vmbus_sendpacket_mpb_desc(struct vmbus_channel *channel, | |||
861 | bufferlist[2].iov_len = (packetlen_aligned - packetlen); | 849 | bufferlist[2].iov_len = (packetlen_aligned - packetlen); |
862 | 850 | ||
863 | ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3, | 851 | ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3, |
864 | &signal, lock); | 852 | &signal, lock, channel->signal_policy); |
865 | 853 | ||
866 | if (ret == 0 && signal) | 854 | if (ret == 0 && signal) |
867 | vmbus_setevent(channel); | 855 | vmbus_setevent(channel); |
@@ -926,7 +914,7 @@ int vmbus_sendpacket_multipagebuffer(struct vmbus_channel *channel, | |||
926 | bufferlist[2].iov_len = (packetlen_aligned - packetlen); | 914 | bufferlist[2].iov_len = (packetlen_aligned - packetlen); |
927 | 915 | ||
928 | ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3, | 916 | ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3, |
929 | &signal, lock); | 917 | &signal, lock, channel->signal_policy); |
930 | 918 | ||
931 | if (ret == 0 && signal) | 919 | if (ret == 0 && signal) |
932 | vmbus_setevent(channel); | 920 | vmbus_setevent(channel); |
diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c index b6c1211b4df7..96a85cd39580 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | 21 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
22 | 22 | ||
23 | #include <linux/kernel.h> | 23 | #include <linux/kernel.h> |
24 | #include <linux/interrupt.h> | ||
24 | #include <linux/sched.h> | 25 | #include <linux/sched.h> |
25 | #include <linux/wait.h> | 26 | #include <linux/wait.h> |
26 | #include <linux/mm.h> | 27 | #include <linux/mm.h> |
@@ -138,10 +139,32 @@ static const struct vmbus_device vmbus_devs[] = { | |||
138 | }, | 139 | }, |
139 | }; | 140 | }; |
140 | 141 | ||
141 | static u16 hv_get_dev_type(const uuid_le *guid) | 142 | static const struct { |
143 | uuid_le guid; | ||
144 | } vmbus_unsupported_devs[] = { | ||
145 | { HV_AVMA1_GUID }, | ||
146 | { HV_AVMA2_GUID }, | ||
147 | { HV_RDV_GUID }, | ||
148 | }; | ||
149 | |||
150 | static bool is_unsupported_vmbus_devs(const uuid_le *guid) | ||
151 | { | ||
152 | int i; | ||
153 | |||
154 | for (i = 0; i < ARRAY_SIZE(vmbus_unsupported_devs); i++) | ||
155 | if (!uuid_le_cmp(*guid, vmbus_unsupported_devs[i].guid)) | ||
156 | return true; | ||
157 | return false; | ||
158 | } | ||
159 | |||
160 | static u16 hv_get_dev_type(const struct vmbus_channel *channel) | ||
142 | { | 161 | { |
162 | const uuid_le *guid = &channel->offermsg.offer.if_type; | ||
143 | u16 i; | 163 | u16 i; |
144 | 164 | ||
165 | if (is_hvsock_channel(channel) || is_unsupported_vmbus_devs(guid)) | ||
166 | return HV_UNKOWN; | ||
167 | |||
145 | for (i = HV_IDE; i < HV_UNKOWN; i++) { | 168 | for (i = HV_IDE; i < HV_UNKOWN; i++) { |
146 | if (!uuid_le_cmp(*guid, vmbus_devs[i].guid)) | 169 | if (!uuid_le_cmp(*guid, vmbus_devs[i].guid)) |
147 | return i; | 170 | return i; |
@@ -251,14 +274,12 @@ EXPORT_SYMBOL_GPL(vmbus_prep_negotiate_resp); | |||
251 | */ | 274 | */ |
252 | static struct vmbus_channel *alloc_channel(void) | 275 | static struct vmbus_channel *alloc_channel(void) |
253 | { | 276 | { |
254 | static atomic_t chan_num = ATOMIC_INIT(0); | ||
255 | struct vmbus_channel *channel; | 277 | struct vmbus_channel *channel; |
256 | 278 | ||
257 | channel = kzalloc(sizeof(*channel), GFP_ATOMIC); | 279 | channel = kzalloc(sizeof(*channel), GFP_ATOMIC); |
258 | if (!channel) | 280 | if (!channel) |
259 | return NULL; | 281 | return NULL; |
260 | 282 | ||
261 | channel->id = atomic_inc_return(&chan_num); | ||
262 | channel->acquire_ring_lock = true; | 283 | channel->acquire_ring_lock = true; |
263 | spin_lock_init(&channel->inbound_lock); | 284 | spin_lock_init(&channel->inbound_lock); |
264 | spin_lock_init(&channel->lock); | 285 | spin_lock_init(&channel->lock); |
@@ -303,16 +324,32 @@ static void vmbus_release_relid(u32 relid) | |||
303 | vmbus_post_msg(&msg, sizeof(struct vmbus_channel_relid_released)); | 324 | vmbus_post_msg(&msg, sizeof(struct vmbus_channel_relid_released)); |
304 | } | 325 | } |
305 | 326 | ||
327 | void hv_event_tasklet_disable(struct vmbus_channel *channel) | ||
328 | { | ||
329 | struct tasklet_struct *tasklet; | ||
330 | tasklet = hv_context.event_dpc[channel->target_cpu]; | ||
331 | tasklet_disable(tasklet); | ||
332 | } | ||
333 | |||
334 | void hv_event_tasklet_enable(struct vmbus_channel *channel) | ||
335 | { | ||
336 | struct tasklet_struct *tasklet; | ||
337 | tasklet = hv_context.event_dpc[channel->target_cpu]; | ||
338 | tasklet_enable(tasklet); | ||
339 | |||
340 | /* In case there is any pending event */ | ||
341 | tasklet_schedule(tasklet); | ||
342 | } | ||
343 | |||
306 | void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid) | 344 | void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid) |
307 | { | 345 | { |
308 | unsigned long flags; | 346 | unsigned long flags; |
309 | struct vmbus_channel *primary_channel; | 347 | struct vmbus_channel *primary_channel; |
310 | 348 | ||
311 | vmbus_release_relid(relid); | ||
312 | |||
313 | BUG_ON(!channel->rescind); | 349 | BUG_ON(!channel->rescind); |
314 | BUG_ON(!mutex_is_locked(&vmbus_connection.channel_mutex)); | 350 | BUG_ON(!mutex_is_locked(&vmbus_connection.channel_mutex)); |
315 | 351 | ||
352 | hv_event_tasklet_disable(channel); | ||
316 | if (channel->target_cpu != get_cpu()) { | 353 | if (channel->target_cpu != get_cpu()) { |
317 | put_cpu(); | 354 | put_cpu(); |
318 | smp_call_function_single(channel->target_cpu, | 355 | smp_call_function_single(channel->target_cpu, |
@@ -321,6 +358,7 @@ void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid) | |||
321 | percpu_channel_deq(channel); | 358 | percpu_channel_deq(channel); |
322 | put_cpu(); | 359 | put_cpu(); |
323 | } | 360 | } |
361 | hv_event_tasklet_enable(channel); | ||
324 | 362 | ||
325 | if (channel->primary_channel == NULL) { | 363 | if (channel->primary_channel == NULL) { |
326 | list_del(&channel->listentry); | 364 | list_del(&channel->listentry); |
@@ -338,8 +376,11 @@ void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid) | |||
338 | * We need to free the bit for init_vp_index() to work in the case | 376 | * We need to free the bit for init_vp_index() to work in the case |
339 | * of sub-channel, when we reload drivers like hv_netvsc. | 377 | * of sub-channel, when we reload drivers like hv_netvsc. |
340 | */ | 378 | */ |
341 | cpumask_clear_cpu(channel->target_cpu, | 379 | if (channel->affinity_policy == HV_LOCALIZED) |
342 | &primary_channel->alloced_cpus_in_node); | 380 | cpumask_clear_cpu(channel->target_cpu, |
381 | &primary_channel->alloced_cpus_in_node); | ||
382 | |||
383 | vmbus_release_relid(relid); | ||
343 | 384 | ||
344 | free_channel(channel); | 385 | free_channel(channel); |
345 | } | 386 | } |
@@ -405,10 +446,13 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel) | |||
405 | goto err_free_chan; | 446 | goto err_free_chan; |
406 | } | 447 | } |
407 | 448 | ||
408 | dev_type = hv_get_dev_type(&newchannel->offermsg.offer.if_type); | 449 | dev_type = hv_get_dev_type(newchannel); |
450 | if (dev_type == HV_NIC) | ||
451 | set_channel_signal_state(newchannel, HV_SIGNAL_POLICY_EXPLICIT); | ||
409 | 452 | ||
410 | init_vp_index(newchannel, dev_type); | 453 | init_vp_index(newchannel, dev_type); |
411 | 454 | ||
455 | hv_event_tasklet_disable(newchannel); | ||
412 | if (newchannel->target_cpu != get_cpu()) { | 456 | if (newchannel->target_cpu != get_cpu()) { |
413 | put_cpu(); | 457 | put_cpu(); |
414 | smp_call_function_single(newchannel->target_cpu, | 458 | smp_call_function_single(newchannel->target_cpu, |
@@ -418,6 +462,7 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel) | |||
418 | percpu_channel_enq(newchannel); | 462 | percpu_channel_enq(newchannel); |
419 | put_cpu(); | 463 | put_cpu(); |
420 | } | 464 | } |
465 | hv_event_tasklet_enable(newchannel); | ||
421 | 466 | ||
422 | /* | 467 | /* |
423 | * This state is used to indicate a successful open | 468 | * This state is used to indicate a successful open |
@@ -463,12 +508,11 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel) | |||
463 | return; | 508 | return; |
464 | 509 | ||
465 | err_deq_chan: | 510 | err_deq_chan: |
466 | vmbus_release_relid(newchannel->offermsg.child_relid); | ||
467 | |||
468 | mutex_lock(&vmbus_connection.channel_mutex); | 511 | mutex_lock(&vmbus_connection.channel_mutex); |
469 | list_del(&newchannel->listentry); | 512 | list_del(&newchannel->listentry); |
470 | mutex_unlock(&vmbus_connection.channel_mutex); | 513 | mutex_unlock(&vmbus_connection.channel_mutex); |
471 | 514 | ||
515 | hv_event_tasklet_disable(newchannel); | ||
472 | if (newchannel->target_cpu != get_cpu()) { | 516 | if (newchannel->target_cpu != get_cpu()) { |
473 | put_cpu(); | 517 | put_cpu(); |
474 | smp_call_function_single(newchannel->target_cpu, | 518 | smp_call_function_single(newchannel->target_cpu, |
@@ -477,6 +521,9 @@ err_deq_chan: | |||
477 | percpu_channel_deq(newchannel); | 521 | percpu_channel_deq(newchannel); |
478 | put_cpu(); | 522 | put_cpu(); |
479 | } | 523 | } |
524 | hv_event_tasklet_enable(newchannel); | ||
525 | |||
526 | vmbus_release_relid(newchannel->offermsg.child_relid); | ||
480 | 527 | ||
481 | err_free_chan: | 528 | err_free_chan: |
482 | free_channel(newchannel); | 529 | free_channel(newchannel); |
@@ -522,17 +569,17 @@ static void init_vp_index(struct vmbus_channel *channel, u16 dev_type) | |||
522 | } | 569 | } |
523 | 570 | ||
524 | /* | 571 | /* |
525 | * We distribute primary channels evenly across all the available | 572 | * Based on the channel affinity policy, we will assign the NUMA |
526 | * NUMA nodes and within the assigned NUMA node we will assign the | 573 | * nodes. |
527 | * first available CPU to the primary channel. | ||
528 | * The sub-channels will be assigned to the CPUs available in the | ||
529 | * NUMA node evenly. | ||
530 | */ | 574 | */ |
531 | if (!primary) { | 575 | |
576 | if ((channel->affinity_policy == HV_BALANCED) || (!primary)) { | ||
532 | while (true) { | 577 | while (true) { |
533 | next_node = next_numa_node_id++; | 578 | next_node = next_numa_node_id++; |
534 | if (next_node == nr_node_ids) | 579 | if (next_node == nr_node_ids) { |
535 | next_node = next_numa_node_id = 0; | 580 | next_node = next_numa_node_id = 0; |
581 | continue; | ||
582 | } | ||
536 | if (cpumask_empty(cpumask_of_node(next_node))) | 583 | if (cpumask_empty(cpumask_of_node(next_node))) |
537 | continue; | 584 | continue; |
538 | break; | 585 | break; |
@@ -556,15 +603,17 @@ static void init_vp_index(struct vmbus_channel *channel, u16 dev_type) | |||
556 | 603 | ||
557 | cur_cpu = -1; | 604 | cur_cpu = -1; |
558 | 605 | ||
559 | /* | 606 | if (primary->affinity_policy == HV_LOCALIZED) { |
560 | * Normally Hyper-V host doesn't create more subchannels than there | 607 | /* |
561 | * are VCPUs on the node but it is possible when not all present VCPUs | 608 | * Normally Hyper-V host doesn't create more subchannels |
562 | * on the node are initialized by guest. Clear the alloced_cpus_in_node | 609 | * than there are VCPUs on the node but it is possible when not |
563 | * to start over. | 610 | * all present VCPUs on the node are initialized by guest. |
564 | */ | 611 | * Clear the alloced_cpus_in_node to start over. |
565 | if (cpumask_equal(&primary->alloced_cpus_in_node, | 612 | */ |
566 | cpumask_of_node(primary->numa_node))) | 613 | if (cpumask_equal(&primary->alloced_cpus_in_node, |
567 | cpumask_clear(&primary->alloced_cpus_in_node); | 614 | cpumask_of_node(primary->numa_node))) |
615 | cpumask_clear(&primary->alloced_cpus_in_node); | ||
616 | } | ||
568 | 617 | ||
569 | while (true) { | 618 | while (true) { |
570 | cur_cpu = cpumask_next(cur_cpu, &available_mask); | 619 | cur_cpu = cpumask_next(cur_cpu, &available_mask); |
@@ -575,17 +624,24 @@ static void init_vp_index(struct vmbus_channel *channel, u16 dev_type) | |||
575 | continue; | 624 | continue; |
576 | } | 625 | } |
577 | 626 | ||
578 | /* | 627 | if (primary->affinity_policy == HV_LOCALIZED) { |
579 | * NOTE: in the case of sub-channel, we clear the sub-channel | 628 | /* |
580 | * related bit(s) in primary->alloced_cpus_in_node in | 629 | * NOTE: in the case of sub-channel, we clear the |
581 | * hv_process_channel_removal(), so when we reload drivers | 630 | * sub-channel related bit(s) in |
582 | * like hv_netvsc in SMP guest, here we're able to re-allocate | 631 | * primary->alloced_cpus_in_node in |
583 | * bit from primary->alloced_cpus_in_node. | 632 | * hv_process_channel_removal(), so when we |
584 | */ | 633 | * reload drivers like hv_netvsc in SMP guest, here |
585 | if (!cpumask_test_cpu(cur_cpu, | 634 | * we're able to re-allocate |
586 | &primary->alloced_cpus_in_node)) { | 635 | * bit from primary->alloced_cpus_in_node. |
587 | cpumask_set_cpu(cur_cpu, | 636 | */ |
588 | &primary->alloced_cpus_in_node); | 637 | if (!cpumask_test_cpu(cur_cpu, |
638 | &primary->alloced_cpus_in_node)) { | ||
639 | cpumask_set_cpu(cur_cpu, | ||
640 | &primary->alloced_cpus_in_node); | ||
641 | cpumask_set_cpu(cur_cpu, alloced_mask); | ||
642 | break; | ||
643 | } | ||
644 | } else { | ||
589 | cpumask_set_cpu(cur_cpu, alloced_mask); | 645 | cpumask_set_cpu(cur_cpu, alloced_mask); |
590 | break; | 646 | break; |
591 | } | 647 | } |
diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c index fcf8a02dc0ea..78e6368a4423 100644 --- a/drivers/hv/connection.c +++ b/drivers/hv/connection.c | |||
@@ -439,7 +439,7 @@ int vmbus_post_msg(void *buffer, size_t buflen) | |||
439 | union hv_connection_id conn_id; | 439 | union hv_connection_id conn_id; |
440 | int ret = 0; | 440 | int ret = 0; |
441 | int retries = 0; | 441 | int retries = 0; |
442 | u32 msec = 1; | 442 | u32 usec = 1; |
443 | 443 | ||
444 | conn_id.asu32 = 0; | 444 | conn_id.asu32 = 0; |
445 | conn_id.u.id = VMBUS_MESSAGE_CONNECTION_ID; | 445 | conn_id.u.id = VMBUS_MESSAGE_CONNECTION_ID; |
@@ -472,9 +472,9 @@ int vmbus_post_msg(void *buffer, size_t buflen) | |||
472 | } | 472 | } |
473 | 473 | ||
474 | retries++; | 474 | retries++; |
475 | msleep(msec); | 475 | udelay(usec); |
476 | if (msec < 2048) | 476 | if (usec < 2048) |
477 | msec *= 2; | 477 | usec *= 2; |
478 | } | 478 | } |
479 | return ret; | 479 | return ret; |
480 | } | 480 | } |
diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c index a1c086ba3b9a..60dbd6cb4640 100644 --- a/drivers/hv/hv.c +++ b/drivers/hv/hv.c | |||
@@ -278,7 +278,7 @@ cleanup: | |||
278 | * | 278 | * |
279 | * This routine is called normally during driver unloading or exiting. | 279 | * This routine is called normally during driver unloading or exiting. |
280 | */ | 280 | */ |
281 | void hv_cleanup(void) | 281 | void hv_cleanup(bool crash) |
282 | { | 282 | { |
283 | union hv_x64_msr_hypercall_contents hypercall_msr; | 283 | union hv_x64_msr_hypercall_contents hypercall_msr; |
284 | 284 | ||
@@ -288,7 +288,8 @@ void hv_cleanup(void) | |||
288 | if (hv_context.hypercall_page) { | 288 | if (hv_context.hypercall_page) { |
289 | hypercall_msr.as_uint64 = 0; | 289 | hypercall_msr.as_uint64 = 0; |
290 | wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64); | 290 | wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64); |
291 | vfree(hv_context.hypercall_page); | 291 | if (!crash) |
292 | vfree(hv_context.hypercall_page); | ||
292 | hv_context.hypercall_page = NULL; | 293 | hv_context.hypercall_page = NULL; |
293 | } | 294 | } |
294 | 295 | ||
@@ -308,7 +309,8 @@ void hv_cleanup(void) | |||
308 | 309 | ||
309 | hypercall_msr.as_uint64 = 0; | 310 | hypercall_msr.as_uint64 = 0; |
310 | wrmsrl(HV_X64_MSR_REFERENCE_TSC, hypercall_msr.as_uint64); | 311 | wrmsrl(HV_X64_MSR_REFERENCE_TSC, hypercall_msr.as_uint64); |
311 | vfree(hv_context.tsc_page); | 312 | if (!crash) |
313 | vfree(hv_context.tsc_page); | ||
312 | hv_context.tsc_page = NULL; | 314 | hv_context.tsc_page = NULL; |
313 | } | 315 | } |
314 | #endif | 316 | #endif |
diff --git a/drivers/hv/hv_balloon.c b/drivers/hv/hv_balloon.c index df35fb7ed5df..fdf8da929cbe 100644 --- a/drivers/hv/hv_balloon.c +++ b/drivers/hv/hv_balloon.c | |||
@@ -430,16 +430,27 @@ struct dm_info_msg { | |||
430 | * currently hot added. We hot add in multiples of 128M | 430 | * currently hot added. We hot add in multiples of 128M |
431 | * chunks; it is possible that we may not be able to bring | 431 | * chunks; it is possible that we may not be able to bring |
432 | * online all the pages in the region. The range | 432 | * online all the pages in the region. The range |
433 | * covered_end_pfn defines the pages that can | 433 | * covered_start_pfn:covered_end_pfn defines the pages that can |
434 | * be brough online. | 434 | * be brough online. |
435 | */ | 435 | */ |
436 | 436 | ||
437 | struct hv_hotadd_state { | 437 | struct hv_hotadd_state { |
438 | struct list_head list; | 438 | struct list_head list; |
439 | unsigned long start_pfn; | 439 | unsigned long start_pfn; |
440 | unsigned long covered_start_pfn; | ||
440 | unsigned long covered_end_pfn; | 441 | unsigned long covered_end_pfn; |
441 | unsigned long ha_end_pfn; | 442 | unsigned long ha_end_pfn; |
442 | unsigned long end_pfn; | 443 | unsigned long end_pfn; |
444 | /* | ||
445 | * A list of gaps. | ||
446 | */ | ||
447 | struct list_head gap_list; | ||
448 | }; | ||
449 | |||
450 | struct hv_hotadd_gap { | ||
451 | struct list_head list; | ||
452 | unsigned long start_pfn; | ||
453 | unsigned long end_pfn; | ||
443 | }; | 454 | }; |
444 | 455 | ||
445 | struct balloon_state { | 456 | struct balloon_state { |
@@ -536,7 +547,11 @@ struct hv_dynmem_device { | |||
536 | */ | 547 | */ |
537 | struct task_struct *thread; | 548 | struct task_struct *thread; |
538 | 549 | ||
539 | struct mutex ha_region_mutex; | 550 | /* |
551 | * Protects ha_region_list, num_pages_onlined counter and individual | ||
552 | * regions from ha_region_list. | ||
553 | */ | ||
554 | spinlock_t ha_lock; | ||
540 | 555 | ||
541 | /* | 556 | /* |
542 | * A list of hot-add regions. | 557 | * A list of hot-add regions. |
@@ -560,18 +575,14 @@ static int hv_memory_notifier(struct notifier_block *nb, unsigned long val, | |||
560 | void *v) | 575 | void *v) |
561 | { | 576 | { |
562 | struct memory_notify *mem = (struct memory_notify *)v; | 577 | struct memory_notify *mem = (struct memory_notify *)v; |
578 | unsigned long flags; | ||
563 | 579 | ||
564 | switch (val) { | 580 | switch (val) { |
565 | case MEM_GOING_ONLINE: | ||
566 | mutex_lock(&dm_device.ha_region_mutex); | ||
567 | break; | ||
568 | |||
569 | case MEM_ONLINE: | 581 | case MEM_ONLINE: |
582 | spin_lock_irqsave(&dm_device.ha_lock, flags); | ||
570 | dm_device.num_pages_onlined += mem->nr_pages; | 583 | dm_device.num_pages_onlined += mem->nr_pages; |
584 | spin_unlock_irqrestore(&dm_device.ha_lock, flags); | ||
571 | case MEM_CANCEL_ONLINE: | 585 | case MEM_CANCEL_ONLINE: |
572 | if (val == MEM_ONLINE || | ||
573 | mutex_is_locked(&dm_device.ha_region_mutex)) | ||
574 | mutex_unlock(&dm_device.ha_region_mutex); | ||
575 | if (dm_device.ha_waiting) { | 586 | if (dm_device.ha_waiting) { |
576 | dm_device.ha_waiting = false; | 587 | dm_device.ha_waiting = false; |
577 | complete(&dm_device.ol_waitevent); | 588 | complete(&dm_device.ol_waitevent); |
@@ -579,10 +590,11 @@ static int hv_memory_notifier(struct notifier_block *nb, unsigned long val, | |||
579 | break; | 590 | break; |
580 | 591 | ||
581 | case MEM_OFFLINE: | 592 | case MEM_OFFLINE: |
582 | mutex_lock(&dm_device.ha_region_mutex); | 593 | spin_lock_irqsave(&dm_device.ha_lock, flags); |
583 | dm_device.num_pages_onlined -= mem->nr_pages; | 594 | dm_device.num_pages_onlined -= mem->nr_pages; |
584 | mutex_unlock(&dm_device.ha_region_mutex); | 595 | spin_unlock_irqrestore(&dm_device.ha_lock, flags); |
585 | break; | 596 | break; |
597 | case MEM_GOING_ONLINE: | ||
586 | case MEM_GOING_OFFLINE: | 598 | case MEM_GOING_OFFLINE: |
587 | case MEM_CANCEL_OFFLINE: | 599 | case MEM_CANCEL_OFFLINE: |
588 | break; | 600 | break; |
@@ -595,18 +607,46 @@ static struct notifier_block hv_memory_nb = { | |||
595 | .priority = 0 | 607 | .priority = 0 |
596 | }; | 608 | }; |
597 | 609 | ||
610 | /* Check if the particular page is backed and can be onlined and online it. */ | ||
611 | static void hv_page_online_one(struct hv_hotadd_state *has, struct page *pg) | ||
612 | { | ||
613 | unsigned long cur_start_pgp; | ||
614 | unsigned long cur_end_pgp; | ||
615 | struct hv_hotadd_gap *gap; | ||
616 | |||
617 | cur_start_pgp = (unsigned long)pfn_to_page(has->covered_start_pfn); | ||
618 | cur_end_pgp = (unsigned long)pfn_to_page(has->covered_end_pfn); | ||
619 | |||
620 | /* The page is not backed. */ | ||
621 | if (((unsigned long)pg < cur_start_pgp) || | ||
622 | ((unsigned long)pg >= cur_end_pgp)) | ||
623 | return; | ||
624 | |||
625 | /* Check for gaps. */ | ||
626 | list_for_each_entry(gap, &has->gap_list, list) { | ||
627 | cur_start_pgp = (unsigned long) | ||
628 | pfn_to_page(gap->start_pfn); | ||
629 | cur_end_pgp = (unsigned long) | ||
630 | pfn_to_page(gap->end_pfn); | ||
631 | if (((unsigned long)pg >= cur_start_pgp) && | ||
632 | ((unsigned long)pg < cur_end_pgp)) { | ||
633 | return; | ||
634 | } | ||
635 | } | ||
636 | |||
637 | /* This frame is currently backed; online the page. */ | ||
638 | __online_page_set_limits(pg); | ||
639 | __online_page_increment_counters(pg); | ||
640 | __online_page_free(pg); | ||
641 | } | ||
598 | 642 | ||
599 | static void hv_bring_pgs_online(unsigned long start_pfn, unsigned long size) | 643 | static void hv_bring_pgs_online(struct hv_hotadd_state *has, |
644 | unsigned long start_pfn, unsigned long size) | ||
600 | { | 645 | { |
601 | int i; | 646 | int i; |
602 | 647 | ||
603 | for (i = 0; i < size; i++) { | 648 | for (i = 0; i < size; i++) |
604 | struct page *pg; | 649 | hv_page_online_one(has, pfn_to_page(start_pfn + i)); |
605 | pg = pfn_to_page(start_pfn + i); | ||
606 | __online_page_set_limits(pg); | ||
607 | __online_page_increment_counters(pg); | ||
608 | __online_page_free(pg); | ||
609 | } | ||
610 | } | 650 | } |
611 | 651 | ||
612 | static void hv_mem_hot_add(unsigned long start, unsigned long size, | 652 | static void hv_mem_hot_add(unsigned long start, unsigned long size, |
@@ -618,9 +658,12 @@ static void hv_mem_hot_add(unsigned long start, unsigned long size, | |||
618 | unsigned long start_pfn; | 658 | unsigned long start_pfn; |
619 | unsigned long processed_pfn; | 659 | unsigned long processed_pfn; |
620 | unsigned long total_pfn = pfn_count; | 660 | unsigned long total_pfn = pfn_count; |
661 | unsigned long flags; | ||
621 | 662 | ||
622 | for (i = 0; i < (size/HA_CHUNK); i++) { | 663 | for (i = 0; i < (size/HA_CHUNK); i++) { |
623 | start_pfn = start + (i * HA_CHUNK); | 664 | start_pfn = start + (i * HA_CHUNK); |
665 | |||
666 | spin_lock_irqsave(&dm_device.ha_lock, flags); | ||
624 | has->ha_end_pfn += HA_CHUNK; | 667 | has->ha_end_pfn += HA_CHUNK; |
625 | 668 | ||
626 | if (total_pfn > HA_CHUNK) { | 669 | if (total_pfn > HA_CHUNK) { |
@@ -632,11 +675,11 @@ static void hv_mem_hot_add(unsigned long start, unsigned long size, | |||
632 | } | 675 | } |
633 | 676 | ||
634 | has->covered_end_pfn += processed_pfn; | 677 | has->covered_end_pfn += processed_pfn; |
678 | spin_unlock_irqrestore(&dm_device.ha_lock, flags); | ||
635 | 679 | ||
636 | init_completion(&dm_device.ol_waitevent); | 680 | init_completion(&dm_device.ol_waitevent); |
637 | dm_device.ha_waiting = true; | 681 | dm_device.ha_waiting = !memhp_auto_online; |
638 | 682 | ||
639 | mutex_unlock(&dm_device.ha_region_mutex); | ||
640 | nid = memory_add_physaddr_to_nid(PFN_PHYS(start_pfn)); | 683 | nid = memory_add_physaddr_to_nid(PFN_PHYS(start_pfn)); |
641 | ret = add_memory(nid, PFN_PHYS((start_pfn)), | 684 | ret = add_memory(nid, PFN_PHYS((start_pfn)), |
642 | (HA_CHUNK << PAGE_SHIFT)); | 685 | (HA_CHUNK << PAGE_SHIFT)); |
@@ -653,20 +696,23 @@ static void hv_mem_hot_add(unsigned long start, unsigned long size, | |||
653 | */ | 696 | */ |
654 | do_hot_add = false; | 697 | do_hot_add = false; |
655 | } | 698 | } |
699 | spin_lock_irqsave(&dm_device.ha_lock, flags); | ||
656 | has->ha_end_pfn -= HA_CHUNK; | 700 | has->ha_end_pfn -= HA_CHUNK; |
657 | has->covered_end_pfn -= processed_pfn; | 701 | has->covered_end_pfn -= processed_pfn; |
658 | mutex_lock(&dm_device.ha_region_mutex); | 702 | spin_unlock_irqrestore(&dm_device.ha_lock, flags); |
659 | break; | 703 | break; |
660 | } | 704 | } |
661 | 705 | ||
662 | /* | 706 | /* |
663 | * Wait for the memory block to be onlined. | 707 | * Wait for the memory block to be onlined when memory onlining |
664 | * Since the hot add has succeeded, it is ok to | 708 | * is done outside of kernel (memhp_auto_online). Since the hot |
665 | * proceed even if the pages in the hot added region | 709 | * add has succeeded, it is ok to proceed even if the pages in |
666 | * have not been "onlined" within the allowed time. | 710 | * the hot added region have not been "onlined" within the |
711 | * allowed time. | ||
667 | */ | 712 | */ |
668 | wait_for_completion_timeout(&dm_device.ol_waitevent, 5*HZ); | 713 | if (dm_device.ha_waiting) |
669 | mutex_lock(&dm_device.ha_region_mutex); | 714 | wait_for_completion_timeout(&dm_device.ol_waitevent, |
715 | 5*HZ); | ||
670 | post_status(&dm_device); | 716 | post_status(&dm_device); |
671 | } | 717 | } |
672 | 718 | ||
@@ -675,47 +721,64 @@ static void hv_mem_hot_add(unsigned long start, unsigned long size, | |||
675 | 721 | ||
676 | static void hv_online_page(struct page *pg) | 722 | static void hv_online_page(struct page *pg) |
677 | { | 723 | { |
678 | struct list_head *cur; | ||
679 | struct hv_hotadd_state *has; | 724 | struct hv_hotadd_state *has; |
680 | unsigned long cur_start_pgp; | 725 | unsigned long cur_start_pgp; |
681 | unsigned long cur_end_pgp; | 726 | unsigned long cur_end_pgp; |
727 | unsigned long flags; | ||
682 | 728 | ||
683 | list_for_each(cur, &dm_device.ha_region_list) { | 729 | spin_lock_irqsave(&dm_device.ha_lock, flags); |
684 | has = list_entry(cur, struct hv_hotadd_state, list); | 730 | list_for_each_entry(has, &dm_device.ha_region_list, list) { |
685 | cur_start_pgp = (unsigned long)pfn_to_page(has->start_pfn); | 731 | cur_start_pgp = (unsigned long) |
686 | cur_end_pgp = (unsigned long)pfn_to_page(has->covered_end_pfn); | 732 | pfn_to_page(has->start_pfn); |
733 | cur_end_pgp = (unsigned long)pfn_to_page(has->end_pfn); | ||
687 | 734 | ||
688 | if (((unsigned long)pg >= cur_start_pgp) && | 735 | /* The page belongs to a different HAS. */ |
689 | ((unsigned long)pg < cur_end_pgp)) { | 736 | if (((unsigned long)pg < cur_start_pgp) || |
690 | /* | 737 | ((unsigned long)pg >= cur_end_pgp)) |
691 | * This frame is currently backed; online the | 738 | continue; |
692 | * page. | 739 | |
693 | */ | 740 | hv_page_online_one(has, pg); |
694 | __online_page_set_limits(pg); | 741 | break; |
695 | __online_page_increment_counters(pg); | ||
696 | __online_page_free(pg); | ||
697 | } | ||
698 | } | 742 | } |
743 | spin_unlock_irqrestore(&dm_device.ha_lock, flags); | ||
699 | } | 744 | } |
700 | 745 | ||
701 | static bool pfn_covered(unsigned long start_pfn, unsigned long pfn_cnt) | 746 | static int pfn_covered(unsigned long start_pfn, unsigned long pfn_cnt) |
702 | { | 747 | { |
703 | struct list_head *cur; | ||
704 | struct hv_hotadd_state *has; | 748 | struct hv_hotadd_state *has; |
749 | struct hv_hotadd_gap *gap; | ||
705 | unsigned long residual, new_inc; | 750 | unsigned long residual, new_inc; |
751 | int ret = 0; | ||
752 | unsigned long flags; | ||
706 | 753 | ||
707 | if (list_empty(&dm_device.ha_region_list)) | 754 | spin_lock_irqsave(&dm_device.ha_lock, flags); |
708 | return false; | 755 | list_for_each_entry(has, &dm_device.ha_region_list, list) { |
709 | |||
710 | list_for_each(cur, &dm_device.ha_region_list) { | ||
711 | has = list_entry(cur, struct hv_hotadd_state, list); | ||
712 | |||
713 | /* | 756 | /* |
714 | * If the pfn range we are dealing with is not in the current | 757 | * If the pfn range we are dealing with is not in the current |
715 | * "hot add block", move on. | 758 | * "hot add block", move on. |
716 | */ | 759 | */ |
717 | if (start_pfn < has->start_pfn || start_pfn >= has->end_pfn) | 760 | if (start_pfn < has->start_pfn || start_pfn >= has->end_pfn) |
718 | continue; | 761 | continue; |
762 | |||
763 | /* | ||
764 | * If the current start pfn is not where the covered_end | ||
765 | * is, create a gap and update covered_end_pfn. | ||
766 | */ | ||
767 | if (has->covered_end_pfn != start_pfn) { | ||
768 | gap = kzalloc(sizeof(struct hv_hotadd_gap), GFP_ATOMIC); | ||
769 | if (!gap) { | ||
770 | ret = -ENOMEM; | ||
771 | break; | ||
772 | } | ||
773 | |||
774 | INIT_LIST_HEAD(&gap->list); | ||
775 | gap->start_pfn = has->covered_end_pfn; | ||
776 | gap->end_pfn = start_pfn; | ||
777 | list_add_tail(&gap->list, &has->gap_list); | ||
778 | |||
779 | has->covered_end_pfn = start_pfn; | ||
780 | } | ||
781 | |||
719 | /* | 782 | /* |
720 | * If the current hot add-request extends beyond | 783 | * If the current hot add-request extends beyond |
721 | * our current limit; extend it. | 784 | * our current limit; extend it. |
@@ -732,19 +795,12 @@ static bool pfn_covered(unsigned long start_pfn, unsigned long pfn_cnt) | |||
732 | has->end_pfn += new_inc; | 795 | has->end_pfn += new_inc; |
733 | } | 796 | } |
734 | 797 | ||
735 | /* | 798 | ret = 1; |
736 | * If the current start pfn is not where the covered_end | 799 | break; |
737 | * is, update it. | ||
738 | */ | ||
739 | |||
740 | if (has->covered_end_pfn != start_pfn) | ||
741 | has->covered_end_pfn = start_pfn; | ||
742 | |||
743 | return true; | ||
744 | |||
745 | } | 800 | } |
801 | spin_unlock_irqrestore(&dm_device.ha_lock, flags); | ||
746 | 802 | ||
747 | return false; | 803 | return ret; |
748 | } | 804 | } |
749 | 805 | ||
750 | static unsigned long handle_pg_range(unsigned long pg_start, | 806 | static unsigned long handle_pg_range(unsigned long pg_start, |
@@ -753,17 +809,13 @@ static unsigned long handle_pg_range(unsigned long pg_start, | |||
753 | unsigned long start_pfn = pg_start; | 809 | unsigned long start_pfn = pg_start; |
754 | unsigned long pfn_cnt = pg_count; | 810 | unsigned long pfn_cnt = pg_count; |
755 | unsigned long size; | 811 | unsigned long size; |
756 | struct list_head *cur; | ||
757 | struct hv_hotadd_state *has; | 812 | struct hv_hotadd_state *has; |
758 | unsigned long pgs_ol = 0; | 813 | unsigned long pgs_ol = 0; |
759 | unsigned long old_covered_state; | 814 | unsigned long old_covered_state; |
815 | unsigned long res = 0, flags; | ||
760 | 816 | ||
761 | if (list_empty(&dm_device.ha_region_list)) | 817 | spin_lock_irqsave(&dm_device.ha_lock, flags); |
762 | return 0; | 818 | list_for_each_entry(has, &dm_device.ha_region_list, list) { |
763 | |||
764 | list_for_each(cur, &dm_device.ha_region_list) { | ||
765 | has = list_entry(cur, struct hv_hotadd_state, list); | ||
766 | |||
767 | /* | 819 | /* |
768 | * If the pfn range we are dealing with is not in the current | 820 | * If the pfn range we are dealing with is not in the current |
769 | * "hot add block", move on. | 821 | * "hot add block", move on. |
@@ -783,6 +835,8 @@ static unsigned long handle_pg_range(unsigned long pg_start, | |||
783 | if (pgs_ol > pfn_cnt) | 835 | if (pgs_ol > pfn_cnt) |
784 | pgs_ol = pfn_cnt; | 836 | pgs_ol = pfn_cnt; |
785 | 837 | ||
838 | has->covered_end_pfn += pgs_ol; | ||
839 | pfn_cnt -= pgs_ol; | ||
786 | /* | 840 | /* |
787 | * Check if the corresponding memory block is already | 841 | * Check if the corresponding memory block is already |
788 | * online by checking its last previously backed page. | 842 | * online by checking its last previously backed page. |
@@ -791,10 +845,8 @@ static unsigned long handle_pg_range(unsigned long pg_start, | |||
791 | */ | 845 | */ |
792 | if (start_pfn > has->start_pfn && | 846 | if (start_pfn > has->start_pfn && |
793 | !PageReserved(pfn_to_page(start_pfn - 1))) | 847 | !PageReserved(pfn_to_page(start_pfn - 1))) |
794 | hv_bring_pgs_online(start_pfn, pgs_ol); | 848 | hv_bring_pgs_online(has, start_pfn, pgs_ol); |
795 | 849 | ||
796 | has->covered_end_pfn += pgs_ol; | ||
797 | pfn_cnt -= pgs_ol; | ||
798 | } | 850 | } |
799 | 851 | ||
800 | if ((has->ha_end_pfn < has->end_pfn) && (pfn_cnt > 0)) { | 852 | if ((has->ha_end_pfn < has->end_pfn) && (pfn_cnt > 0)) { |
@@ -813,17 +865,20 @@ static unsigned long handle_pg_range(unsigned long pg_start, | |||
813 | } else { | 865 | } else { |
814 | pfn_cnt = size; | 866 | pfn_cnt = size; |
815 | } | 867 | } |
868 | spin_unlock_irqrestore(&dm_device.ha_lock, flags); | ||
816 | hv_mem_hot_add(has->ha_end_pfn, size, pfn_cnt, has); | 869 | hv_mem_hot_add(has->ha_end_pfn, size, pfn_cnt, has); |
870 | spin_lock_irqsave(&dm_device.ha_lock, flags); | ||
817 | } | 871 | } |
818 | /* | 872 | /* |
819 | * If we managed to online any pages that were given to us, | 873 | * If we managed to online any pages that were given to us, |
820 | * we declare success. | 874 | * we declare success. |
821 | */ | 875 | */ |
822 | return has->covered_end_pfn - old_covered_state; | 876 | res = has->covered_end_pfn - old_covered_state; |
823 | 877 | break; | |
824 | } | 878 | } |
879 | spin_unlock_irqrestore(&dm_device.ha_lock, flags); | ||
825 | 880 | ||
826 | return 0; | 881 | return res; |
827 | } | 882 | } |
828 | 883 | ||
829 | static unsigned long process_hot_add(unsigned long pg_start, | 884 | static unsigned long process_hot_add(unsigned long pg_start, |
@@ -832,13 +887,20 @@ static unsigned long process_hot_add(unsigned long pg_start, | |||
832 | unsigned long rg_size) | 887 | unsigned long rg_size) |
833 | { | 888 | { |
834 | struct hv_hotadd_state *ha_region = NULL; | 889 | struct hv_hotadd_state *ha_region = NULL; |
890 | int covered; | ||
891 | unsigned long flags; | ||
835 | 892 | ||
836 | if (pfn_cnt == 0) | 893 | if (pfn_cnt == 0) |
837 | return 0; | 894 | return 0; |
838 | 895 | ||
839 | if (!dm_device.host_specified_ha_region) | 896 | if (!dm_device.host_specified_ha_region) { |
840 | if (pfn_covered(pg_start, pfn_cnt)) | 897 | covered = pfn_covered(pg_start, pfn_cnt); |
898 | if (covered < 0) | ||
899 | return 0; | ||
900 | |||
901 | if (covered) | ||
841 | goto do_pg_range; | 902 | goto do_pg_range; |
903 | } | ||
842 | 904 | ||
843 | /* | 905 | /* |
844 | * If the host has specified a hot-add range; deal with it first. | 906 | * If the host has specified a hot-add range; deal with it first. |
@@ -850,12 +912,17 @@ static unsigned long process_hot_add(unsigned long pg_start, | |||
850 | return 0; | 912 | return 0; |
851 | 913 | ||
852 | INIT_LIST_HEAD(&ha_region->list); | 914 | INIT_LIST_HEAD(&ha_region->list); |
915 | INIT_LIST_HEAD(&ha_region->gap_list); | ||
853 | 916 | ||
854 | list_add_tail(&ha_region->list, &dm_device.ha_region_list); | ||
855 | ha_region->start_pfn = rg_start; | 917 | ha_region->start_pfn = rg_start; |
856 | ha_region->ha_end_pfn = rg_start; | 918 | ha_region->ha_end_pfn = rg_start; |
919 | ha_region->covered_start_pfn = pg_start; | ||
857 | ha_region->covered_end_pfn = pg_start; | 920 | ha_region->covered_end_pfn = pg_start; |
858 | ha_region->end_pfn = rg_start + rg_size; | 921 | ha_region->end_pfn = rg_start + rg_size; |
922 | |||
923 | spin_lock_irqsave(&dm_device.ha_lock, flags); | ||
924 | list_add_tail(&ha_region->list, &dm_device.ha_region_list); | ||
925 | spin_unlock_irqrestore(&dm_device.ha_lock, flags); | ||
859 | } | 926 | } |
860 | 927 | ||
861 | do_pg_range: | 928 | do_pg_range: |
@@ -882,7 +949,6 @@ static void hot_add_req(struct work_struct *dummy) | |||
882 | resp.hdr.size = sizeof(struct dm_hot_add_response); | 949 | resp.hdr.size = sizeof(struct dm_hot_add_response); |
883 | 950 | ||
884 | #ifdef CONFIG_MEMORY_HOTPLUG | 951 | #ifdef CONFIG_MEMORY_HOTPLUG |
885 | mutex_lock(&dm_device.ha_region_mutex); | ||
886 | pg_start = dm->ha_wrk.ha_page_range.finfo.start_page; | 952 | pg_start = dm->ha_wrk.ha_page_range.finfo.start_page; |
887 | pfn_cnt = dm->ha_wrk.ha_page_range.finfo.page_cnt; | 953 | pfn_cnt = dm->ha_wrk.ha_page_range.finfo.page_cnt; |
888 | 954 | ||
@@ -916,7 +982,6 @@ static void hot_add_req(struct work_struct *dummy) | |||
916 | rg_start, rg_sz); | 982 | rg_start, rg_sz); |
917 | 983 | ||
918 | dm->num_pages_added += resp.page_count; | 984 | dm->num_pages_added += resp.page_count; |
919 | mutex_unlock(&dm_device.ha_region_mutex); | ||
920 | #endif | 985 | #endif |
921 | /* | 986 | /* |
922 | * The result field of the response structure has the | 987 | * The result field of the response structure has the |
@@ -1010,7 +1075,6 @@ static unsigned long compute_balloon_floor(void) | |||
1010 | static void post_status(struct hv_dynmem_device *dm) | 1075 | static void post_status(struct hv_dynmem_device *dm) |
1011 | { | 1076 | { |
1012 | struct dm_status status; | 1077 | struct dm_status status; |
1013 | struct sysinfo val; | ||
1014 | unsigned long now = jiffies; | 1078 | unsigned long now = jiffies; |
1015 | unsigned long last_post = last_post_time; | 1079 | unsigned long last_post = last_post_time; |
1016 | 1080 | ||
@@ -1022,7 +1086,6 @@ static void post_status(struct hv_dynmem_device *dm) | |||
1022 | if (!time_after(now, (last_post_time + HZ))) | 1086 | if (!time_after(now, (last_post_time + HZ))) |
1023 | return; | 1087 | return; |
1024 | 1088 | ||
1025 | si_meminfo(&val); | ||
1026 | memset(&status, 0, sizeof(struct dm_status)); | 1089 | memset(&status, 0, sizeof(struct dm_status)); |
1027 | status.hdr.type = DM_STATUS_REPORT; | 1090 | status.hdr.type = DM_STATUS_REPORT; |
1028 | status.hdr.size = sizeof(struct dm_status); | 1091 | status.hdr.size = sizeof(struct dm_status); |
@@ -1038,7 +1101,7 @@ static void post_status(struct hv_dynmem_device *dm) | |||
1038 | * num_pages_onlined) as committed to the host, otherwise it can try | 1101 | * num_pages_onlined) as committed to the host, otherwise it can try |
1039 | * asking us to balloon them out. | 1102 | * asking us to balloon them out. |
1040 | */ | 1103 | */ |
1041 | status.num_avail = val.freeram; | 1104 | status.num_avail = si_mem_available(); |
1042 | status.num_committed = vm_memory_committed() + | 1105 | status.num_committed = vm_memory_committed() + |
1043 | dm->num_pages_ballooned + | 1106 | dm->num_pages_ballooned + |
1044 | (dm->num_pages_added > dm->num_pages_onlined ? | 1107 | (dm->num_pages_added > dm->num_pages_onlined ? |
@@ -1144,7 +1207,7 @@ static void balloon_up(struct work_struct *dummy) | |||
1144 | int ret; | 1207 | int ret; |
1145 | bool done = false; | 1208 | bool done = false; |
1146 | int i; | 1209 | int i; |
1147 | struct sysinfo val; | 1210 | long avail_pages; |
1148 | unsigned long floor; | 1211 | unsigned long floor; |
1149 | 1212 | ||
1150 | /* The host balloons pages in 2M granularity. */ | 1213 | /* The host balloons pages in 2M granularity. */ |
@@ -1156,12 +1219,12 @@ static void balloon_up(struct work_struct *dummy) | |||
1156 | */ | 1219 | */ |
1157 | alloc_unit = 512; | 1220 | alloc_unit = 512; |
1158 | 1221 | ||
1159 | si_meminfo(&val); | 1222 | avail_pages = si_mem_available(); |
1160 | floor = compute_balloon_floor(); | 1223 | floor = compute_balloon_floor(); |
1161 | 1224 | ||
1162 | /* Refuse to balloon below the floor, keep the 2M granularity. */ | 1225 | /* Refuse to balloon below the floor, keep the 2M granularity. */ |
1163 | if (val.freeram < num_pages || val.freeram - num_pages < floor) { | 1226 | if (avail_pages < num_pages || avail_pages - num_pages < floor) { |
1164 | num_pages = val.freeram > floor ? (val.freeram - floor) : 0; | 1227 | num_pages = avail_pages > floor ? (avail_pages - floor) : 0; |
1165 | num_pages -= num_pages % PAGES_IN_2M; | 1228 | num_pages -= num_pages % PAGES_IN_2M; |
1166 | } | 1229 | } |
1167 | 1230 | ||
@@ -1172,7 +1235,6 @@ static void balloon_up(struct work_struct *dummy) | |||
1172 | bl_resp->hdr.size = sizeof(struct dm_balloon_response); | 1235 | bl_resp->hdr.size = sizeof(struct dm_balloon_response); |
1173 | bl_resp->more_pages = 1; | 1236 | bl_resp->more_pages = 1; |
1174 | 1237 | ||
1175 | |||
1176 | num_pages -= num_ballooned; | 1238 | num_pages -= num_ballooned; |
1177 | num_ballooned = alloc_balloon_pages(&dm_device, num_pages, | 1239 | num_ballooned = alloc_balloon_pages(&dm_device, num_pages, |
1178 | bl_resp, alloc_unit); | 1240 | bl_resp, alloc_unit); |
@@ -1461,7 +1523,7 @@ static int balloon_probe(struct hv_device *dev, | |||
1461 | init_completion(&dm_device.host_event); | 1523 | init_completion(&dm_device.host_event); |
1462 | init_completion(&dm_device.config_event); | 1524 | init_completion(&dm_device.config_event); |
1463 | INIT_LIST_HEAD(&dm_device.ha_region_list); | 1525 | INIT_LIST_HEAD(&dm_device.ha_region_list); |
1464 | mutex_init(&dm_device.ha_region_mutex); | 1526 | spin_lock_init(&dm_device.ha_lock); |
1465 | INIT_WORK(&dm_device.balloon_wrk.wrk, balloon_up); | 1527 | INIT_WORK(&dm_device.balloon_wrk.wrk, balloon_up); |
1466 | INIT_WORK(&dm_device.ha_wrk.wrk, hot_add_req); | 1528 | INIT_WORK(&dm_device.ha_wrk.wrk, hot_add_req); |
1467 | dm_device.host_specified_ha_region = false; | 1529 | dm_device.host_specified_ha_region = false; |
@@ -1580,8 +1642,9 @@ probe_error0: | |||
1580 | static int balloon_remove(struct hv_device *dev) | 1642 | static int balloon_remove(struct hv_device *dev) |
1581 | { | 1643 | { |
1582 | struct hv_dynmem_device *dm = hv_get_drvdata(dev); | 1644 | struct hv_dynmem_device *dm = hv_get_drvdata(dev); |
1583 | struct list_head *cur, *tmp; | 1645 | struct hv_hotadd_state *has, *tmp; |
1584 | struct hv_hotadd_state *has; | 1646 | struct hv_hotadd_gap *gap, *tmp_gap; |
1647 | unsigned long flags; | ||
1585 | 1648 | ||
1586 | if (dm->num_pages_ballooned != 0) | 1649 | if (dm->num_pages_ballooned != 0) |
1587 | pr_warn("Ballooned pages: %d\n", dm->num_pages_ballooned); | 1650 | pr_warn("Ballooned pages: %d\n", dm->num_pages_ballooned); |
@@ -1596,11 +1659,16 @@ static int balloon_remove(struct hv_device *dev) | |||
1596 | restore_online_page_callback(&hv_online_page); | 1659 | restore_online_page_callback(&hv_online_page); |
1597 | unregister_memory_notifier(&hv_memory_nb); | 1660 | unregister_memory_notifier(&hv_memory_nb); |
1598 | #endif | 1661 | #endif |
1599 | list_for_each_safe(cur, tmp, &dm->ha_region_list) { | 1662 | spin_lock_irqsave(&dm_device.ha_lock, flags); |
1600 | has = list_entry(cur, struct hv_hotadd_state, list); | 1663 | list_for_each_entry_safe(has, tmp, &dm->ha_region_list, list) { |
1664 | list_for_each_entry_safe(gap, tmp_gap, &has->gap_list, list) { | ||
1665 | list_del(&gap->list); | ||
1666 | kfree(gap); | ||
1667 | } | ||
1601 | list_del(&has->list); | 1668 | list_del(&has->list); |
1602 | kfree(has); | 1669 | kfree(has); |
1603 | } | 1670 | } |
1671 | spin_unlock_irqrestore(&dm_device.ha_lock, flags); | ||
1604 | 1672 | ||
1605 | return 0; | 1673 | return 0; |
1606 | } | 1674 | } |
diff --git a/drivers/hv/hv_fcopy.c b/drivers/hv/hv_fcopy.c index 23c70799ad8a..8b2ba98831ec 100644 --- a/drivers/hv/hv_fcopy.c +++ b/drivers/hv/hv_fcopy.c | |||
@@ -83,6 +83,12 @@ static void fcopy_timeout_func(struct work_struct *dummy) | |||
83 | hv_poll_channel(fcopy_transaction.recv_channel, fcopy_poll_wrapper); | 83 | hv_poll_channel(fcopy_transaction.recv_channel, fcopy_poll_wrapper); |
84 | } | 84 | } |
85 | 85 | ||
86 | static void fcopy_register_done(void) | ||
87 | { | ||
88 | pr_debug("FCP: userspace daemon registered\n"); | ||
89 | hv_poll_channel(fcopy_transaction.recv_channel, fcopy_poll_wrapper); | ||
90 | } | ||
91 | |||
86 | static int fcopy_handle_handshake(u32 version) | 92 | static int fcopy_handle_handshake(u32 version) |
87 | { | 93 | { |
88 | u32 our_ver = FCOPY_CURRENT_VERSION; | 94 | u32 our_ver = FCOPY_CURRENT_VERSION; |
@@ -94,7 +100,8 @@ static int fcopy_handle_handshake(u32 version) | |||
94 | break; | 100 | break; |
95 | case FCOPY_VERSION_1: | 101 | case FCOPY_VERSION_1: |
96 | /* Daemon expects us to reply with our own version */ | 102 | /* Daemon expects us to reply with our own version */ |
97 | if (hvutil_transport_send(hvt, &our_ver, sizeof(our_ver))) | 103 | if (hvutil_transport_send(hvt, &our_ver, sizeof(our_ver), |
104 | fcopy_register_done)) | ||
98 | return -EFAULT; | 105 | return -EFAULT; |
99 | dm_reg_value = version; | 106 | dm_reg_value = version; |
100 | break; | 107 | break; |
@@ -107,8 +114,7 @@ static int fcopy_handle_handshake(u32 version) | |||
107 | */ | 114 | */ |
108 | return -EINVAL; | 115 | return -EINVAL; |
109 | } | 116 | } |
110 | pr_debug("FCP: userspace daemon ver. %d registered\n", version); | 117 | pr_debug("FCP: userspace daemon ver. %d connected\n", version); |
111 | hv_poll_channel(fcopy_transaction.recv_channel, fcopy_poll_wrapper); | ||
112 | return 0; | 118 | return 0; |
113 | } | 119 | } |
114 | 120 | ||
@@ -161,7 +167,7 @@ static void fcopy_send_data(struct work_struct *dummy) | |||
161 | } | 167 | } |
162 | 168 | ||
163 | fcopy_transaction.state = HVUTIL_USERSPACE_REQ; | 169 | fcopy_transaction.state = HVUTIL_USERSPACE_REQ; |
164 | rc = hvutil_transport_send(hvt, out_src, out_len); | 170 | rc = hvutil_transport_send(hvt, out_src, out_len, NULL); |
165 | if (rc) { | 171 | if (rc) { |
166 | pr_debug("FCP: failed to communicate to the daemon: %d\n", rc); | 172 | pr_debug("FCP: failed to communicate to the daemon: %d\n", rc); |
167 | if (cancel_delayed_work_sync(&fcopy_timeout_work)) { | 173 | if (cancel_delayed_work_sync(&fcopy_timeout_work)) { |
diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c index cb1a9160aab1..5e1fdc8d32ab 100644 --- a/drivers/hv/hv_kvp.c +++ b/drivers/hv/hv_kvp.c | |||
@@ -102,6 +102,17 @@ static void kvp_poll_wrapper(void *channel) | |||
102 | hv_kvp_onchannelcallback(channel); | 102 | hv_kvp_onchannelcallback(channel); |
103 | } | 103 | } |
104 | 104 | ||
105 | static void kvp_register_done(void) | ||
106 | { | ||
107 | /* | ||
108 | * If we're still negotiating with the host cancel the timeout | ||
109 | * work to not poll the channel twice. | ||
110 | */ | ||
111 | pr_debug("KVP: userspace daemon registered\n"); | ||
112 | cancel_delayed_work_sync(&kvp_host_handshake_work); | ||
113 | hv_poll_channel(kvp_transaction.recv_channel, kvp_poll_wrapper); | ||
114 | } | ||
115 | |||
105 | static void | 116 | static void |
106 | kvp_register(int reg_value) | 117 | kvp_register(int reg_value) |
107 | { | 118 | { |
@@ -116,7 +127,8 @@ kvp_register(int reg_value) | |||
116 | kvp_msg->kvp_hdr.operation = reg_value; | 127 | kvp_msg->kvp_hdr.operation = reg_value; |
117 | strcpy(version, HV_DRV_VERSION); | 128 | strcpy(version, HV_DRV_VERSION); |
118 | 129 | ||
119 | hvutil_transport_send(hvt, kvp_msg, sizeof(*kvp_msg)); | 130 | hvutil_transport_send(hvt, kvp_msg, sizeof(*kvp_msg), |
131 | kvp_register_done); | ||
120 | kfree(kvp_msg); | 132 | kfree(kvp_msg); |
121 | } | 133 | } |
122 | } | 134 | } |
@@ -158,17 +170,10 @@ static int kvp_handle_handshake(struct hv_kvp_msg *msg) | |||
158 | /* | 170 | /* |
159 | * We have a compatible daemon; complete the handshake. | 171 | * We have a compatible daemon; complete the handshake. |
160 | */ | 172 | */ |
161 | pr_debug("KVP: userspace daemon ver. %d registered\n", | 173 | pr_debug("KVP: userspace daemon ver. %d connected\n", |
162 | KVP_OP_REGISTER); | 174 | msg->kvp_hdr.operation); |
163 | kvp_register(dm_reg_value); | 175 | kvp_register(dm_reg_value); |
164 | 176 | ||
165 | /* | ||
166 | * If we're still negotiating with the host cancel the timeout | ||
167 | * work to not poll the channel twice. | ||
168 | */ | ||
169 | cancel_delayed_work_sync(&kvp_host_handshake_work); | ||
170 | hv_poll_channel(kvp_transaction.recv_channel, kvp_poll_wrapper); | ||
171 | |||
172 | return 0; | 177 | return 0; |
173 | } | 178 | } |
174 | 179 | ||
@@ -455,7 +460,7 @@ kvp_send_key(struct work_struct *dummy) | |||
455 | } | 460 | } |
456 | 461 | ||
457 | kvp_transaction.state = HVUTIL_USERSPACE_REQ; | 462 | kvp_transaction.state = HVUTIL_USERSPACE_REQ; |
458 | rc = hvutil_transport_send(hvt, message, sizeof(*message)); | 463 | rc = hvutil_transport_send(hvt, message, sizeof(*message), NULL); |
459 | if (rc) { | 464 | if (rc) { |
460 | pr_debug("KVP: failed to communicate to the daemon: %d\n", rc); | 465 | pr_debug("KVP: failed to communicate to the daemon: %d\n", rc); |
461 | if (cancel_delayed_work_sync(&kvp_timeout_work)) { | 466 | if (cancel_delayed_work_sync(&kvp_timeout_work)) { |
diff --git a/drivers/hv/hv_snapshot.c b/drivers/hv/hv_snapshot.c index 3fba14e88f03..a6707133c297 100644 --- a/drivers/hv/hv_snapshot.c +++ b/drivers/hv/hv_snapshot.c | |||
@@ -67,11 +67,11 @@ static const char vss_devname[] = "vmbus/hv_vss"; | |||
67 | static __u8 *recv_buffer; | 67 | static __u8 *recv_buffer; |
68 | static struct hvutil_transport *hvt; | 68 | static struct hvutil_transport *hvt; |
69 | 69 | ||
70 | static void vss_send_op(struct work_struct *dummy); | ||
71 | static void vss_timeout_func(struct work_struct *dummy); | 70 | static void vss_timeout_func(struct work_struct *dummy); |
71 | static void vss_handle_request(struct work_struct *dummy); | ||
72 | 72 | ||
73 | static DECLARE_DELAYED_WORK(vss_timeout_work, vss_timeout_func); | 73 | static DECLARE_DELAYED_WORK(vss_timeout_work, vss_timeout_func); |
74 | static DECLARE_WORK(vss_send_op_work, vss_send_op); | 74 | static DECLARE_WORK(vss_handle_request_work, vss_handle_request); |
75 | 75 | ||
76 | static void vss_poll_wrapper(void *channel) | 76 | static void vss_poll_wrapper(void *channel) |
77 | { | 77 | { |
@@ -95,6 +95,12 @@ static void vss_timeout_func(struct work_struct *dummy) | |||
95 | hv_poll_channel(vss_transaction.recv_channel, vss_poll_wrapper); | 95 | hv_poll_channel(vss_transaction.recv_channel, vss_poll_wrapper); |
96 | } | 96 | } |
97 | 97 | ||
98 | static void vss_register_done(void) | ||
99 | { | ||
100 | hv_poll_channel(vss_transaction.recv_channel, vss_poll_wrapper); | ||
101 | pr_debug("VSS: userspace daemon registered\n"); | ||
102 | } | ||
103 | |||
98 | static int vss_handle_handshake(struct hv_vss_msg *vss_msg) | 104 | static int vss_handle_handshake(struct hv_vss_msg *vss_msg) |
99 | { | 105 | { |
100 | u32 our_ver = VSS_OP_REGISTER1; | 106 | u32 our_ver = VSS_OP_REGISTER1; |
@@ -105,16 +111,16 @@ static int vss_handle_handshake(struct hv_vss_msg *vss_msg) | |||
105 | dm_reg_value = VSS_OP_REGISTER; | 111 | dm_reg_value = VSS_OP_REGISTER; |
106 | break; | 112 | break; |
107 | case VSS_OP_REGISTER1: | 113 | case VSS_OP_REGISTER1: |
108 | /* Daemon expects us to reply with our own version*/ | 114 | /* Daemon expects us to reply with our own version */ |
109 | if (hvutil_transport_send(hvt, &our_ver, sizeof(our_ver))) | 115 | if (hvutil_transport_send(hvt, &our_ver, sizeof(our_ver), |
116 | vss_register_done)) | ||
110 | return -EFAULT; | 117 | return -EFAULT; |
111 | dm_reg_value = VSS_OP_REGISTER1; | 118 | dm_reg_value = VSS_OP_REGISTER1; |
112 | break; | 119 | break; |
113 | default: | 120 | default: |
114 | return -EINVAL; | 121 | return -EINVAL; |
115 | } | 122 | } |
116 | hv_poll_channel(vss_transaction.recv_channel, vss_poll_wrapper); | 123 | pr_debug("VSS: userspace daemon ver. %d connected\n", dm_reg_value); |
117 | pr_debug("VSS: userspace daemon ver. %d registered\n", dm_reg_value); | ||
118 | return 0; | 124 | return 0; |
119 | } | 125 | } |
120 | 126 | ||
@@ -136,6 +142,11 @@ static int vss_on_msg(void *msg, int len) | |||
136 | return vss_handle_handshake(vss_msg); | 142 | return vss_handle_handshake(vss_msg); |
137 | } else if (vss_transaction.state == HVUTIL_USERSPACE_REQ) { | 143 | } else if (vss_transaction.state == HVUTIL_USERSPACE_REQ) { |
138 | vss_transaction.state = HVUTIL_USERSPACE_RECV; | 144 | vss_transaction.state = HVUTIL_USERSPACE_RECV; |
145 | |||
146 | if (vss_msg->vss_hdr.operation == VSS_OP_HOT_BACKUP) | ||
147 | vss_transaction.msg->vss_cf.flags = | ||
148 | VSS_HBU_NO_AUTO_RECOVERY; | ||
149 | |||
139 | if (cancel_delayed_work_sync(&vss_timeout_work)) { | 150 | if (cancel_delayed_work_sync(&vss_timeout_work)) { |
140 | vss_respond_to_host(vss_msg->error); | 151 | vss_respond_to_host(vss_msg->error); |
141 | /* Transaction is finished, reset the state. */ | 152 | /* Transaction is finished, reset the state. */ |
@@ -150,8 +161,7 @@ static int vss_on_msg(void *msg, int len) | |||
150 | return 0; | 161 | return 0; |
151 | } | 162 | } |
152 | 163 | ||
153 | 164 | static void vss_send_op(void) | |
154 | static void vss_send_op(struct work_struct *dummy) | ||
155 | { | 165 | { |
156 | int op = vss_transaction.msg->vss_hdr.operation; | 166 | int op = vss_transaction.msg->vss_hdr.operation; |
157 | int rc; | 167 | int rc; |
@@ -168,7 +178,10 @@ static void vss_send_op(struct work_struct *dummy) | |||
168 | vss_msg->vss_hdr.operation = op; | 178 | vss_msg->vss_hdr.operation = op; |
169 | 179 | ||
170 | vss_transaction.state = HVUTIL_USERSPACE_REQ; | 180 | vss_transaction.state = HVUTIL_USERSPACE_REQ; |
171 | rc = hvutil_transport_send(hvt, vss_msg, sizeof(*vss_msg)); | 181 | |
182 | schedule_delayed_work(&vss_timeout_work, VSS_USERSPACE_TIMEOUT); | ||
183 | |||
184 | rc = hvutil_transport_send(hvt, vss_msg, sizeof(*vss_msg), NULL); | ||
172 | if (rc) { | 185 | if (rc) { |
173 | pr_warn("VSS: failed to communicate to the daemon: %d\n", rc); | 186 | pr_warn("VSS: failed to communicate to the daemon: %d\n", rc); |
174 | if (cancel_delayed_work_sync(&vss_timeout_work)) { | 187 | if (cancel_delayed_work_sync(&vss_timeout_work)) { |
@@ -182,6 +195,38 @@ static void vss_send_op(struct work_struct *dummy) | |||
182 | return; | 195 | return; |
183 | } | 196 | } |
184 | 197 | ||
198 | static void vss_handle_request(struct work_struct *dummy) | ||
199 | { | ||
200 | switch (vss_transaction.msg->vss_hdr.operation) { | ||
201 | /* | ||
202 | * Initiate a "freeze/thaw" operation in the guest. | ||
203 | * We respond to the host once the operation is complete. | ||
204 | * | ||
205 | * We send the message to the user space daemon and the operation is | ||
206 | * performed in the daemon. | ||
207 | */ | ||
208 | case VSS_OP_THAW: | ||
209 | case VSS_OP_FREEZE: | ||
210 | case VSS_OP_HOT_BACKUP: | ||
211 | if (vss_transaction.state < HVUTIL_READY) { | ||
212 | /* Userspace is not registered yet */ | ||
213 | vss_respond_to_host(HV_E_FAIL); | ||
214 | return; | ||
215 | } | ||
216 | vss_transaction.state = HVUTIL_HOSTMSG_RECEIVED; | ||
217 | vss_send_op(); | ||
218 | return; | ||
219 | case VSS_OP_GET_DM_INFO: | ||
220 | vss_transaction.msg->dm_info.flags = 0; | ||
221 | break; | ||
222 | default: | ||
223 | break; | ||
224 | } | ||
225 | |||
226 | vss_respond_to_host(0); | ||
227 | hv_poll_channel(vss_transaction.recv_channel, vss_poll_wrapper); | ||
228 | } | ||
229 | |||
185 | /* | 230 | /* |
186 | * Send a response back to the host. | 231 | * Send a response back to the host. |
187 | */ | 232 | */ |
@@ -266,48 +311,8 @@ void hv_vss_onchannelcallback(void *context) | |||
266 | vss_transaction.recv_req_id = requestid; | 311 | vss_transaction.recv_req_id = requestid; |
267 | vss_transaction.msg = (struct hv_vss_msg *)vss_msg; | 312 | vss_transaction.msg = (struct hv_vss_msg *)vss_msg; |
268 | 313 | ||
269 | switch (vss_msg->vss_hdr.operation) { | 314 | schedule_work(&vss_handle_request_work); |
270 | /* | 315 | return; |
271 | * Initiate a "freeze/thaw" | ||
272 | * operation in the guest. | ||
273 | * We respond to the host once | ||
274 | * the operation is complete. | ||
275 | * | ||
276 | * We send the message to the | ||
277 | * user space daemon and the | ||
278 | * operation is performed in | ||
279 | * the daemon. | ||
280 | */ | ||
281 | case VSS_OP_FREEZE: | ||
282 | case VSS_OP_THAW: | ||
283 | if (vss_transaction.state < HVUTIL_READY) { | ||
284 | /* Userspace is not registered yet */ | ||
285 | vss_respond_to_host(HV_E_FAIL); | ||
286 | return; | ||
287 | } | ||
288 | vss_transaction.state = HVUTIL_HOSTMSG_RECEIVED; | ||
289 | schedule_work(&vss_send_op_work); | ||
290 | schedule_delayed_work(&vss_timeout_work, | ||
291 | VSS_USERSPACE_TIMEOUT); | ||
292 | return; | ||
293 | |||
294 | case VSS_OP_HOT_BACKUP: | ||
295 | vss_msg->vss_cf.flags = | ||
296 | VSS_HBU_NO_AUTO_RECOVERY; | ||
297 | vss_respond_to_host(0); | ||
298 | return; | ||
299 | |||
300 | case VSS_OP_GET_DM_INFO: | ||
301 | vss_msg->dm_info.flags = 0; | ||
302 | vss_respond_to_host(0); | ||
303 | return; | ||
304 | |||
305 | default: | ||
306 | vss_respond_to_host(0); | ||
307 | return; | ||
308 | |||
309 | } | ||
310 | |||
311 | } | 316 | } |
312 | 317 | ||
313 | icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION | 318 | icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION |
@@ -358,6 +363,6 @@ void hv_vss_deinit(void) | |||
358 | { | 363 | { |
359 | vss_transaction.state = HVUTIL_DEVICE_DYING; | 364 | vss_transaction.state = HVUTIL_DEVICE_DYING; |
360 | cancel_delayed_work_sync(&vss_timeout_work); | 365 | cancel_delayed_work_sync(&vss_timeout_work); |
361 | cancel_work_sync(&vss_send_op_work); | 366 | cancel_work_sync(&vss_handle_request_work); |
362 | hvutil_transport_destroy(hvt); | 367 | hvutil_transport_destroy(hvt); |
363 | } | 368 | } |
diff --git a/drivers/hv/hv_util.c b/drivers/hv/hv_util.c index d5acaa2d8e61..4aa3cb63fd41 100644 --- a/drivers/hv/hv_util.c +++ b/drivers/hv/hv_util.c | |||
@@ -34,22 +34,25 @@ | |||
34 | #define SD_MINOR 0 | 34 | #define SD_MINOR 0 |
35 | #define SD_VERSION (SD_MAJOR << 16 | SD_MINOR) | 35 | #define SD_VERSION (SD_MAJOR << 16 | SD_MINOR) |
36 | 36 | ||
37 | #define SD_WS2008_MAJOR 1 | 37 | #define SD_MAJOR_1 1 |
38 | #define SD_WS2008_VERSION (SD_WS2008_MAJOR << 16 | SD_MINOR) | 38 | #define SD_VERSION_1 (SD_MAJOR_1 << 16 | SD_MINOR) |
39 | 39 | ||
40 | #define TS_MAJOR 3 | 40 | #define TS_MAJOR 4 |
41 | #define TS_MINOR 0 | 41 | #define TS_MINOR 0 |
42 | #define TS_VERSION (TS_MAJOR << 16 | TS_MINOR) | 42 | #define TS_VERSION (TS_MAJOR << 16 | TS_MINOR) |
43 | 43 | ||
44 | #define TS_WS2008_MAJOR 1 | 44 | #define TS_MAJOR_1 1 |
45 | #define TS_WS2008_VERSION (TS_WS2008_MAJOR << 16 | TS_MINOR) | 45 | #define TS_VERSION_1 (TS_MAJOR_1 << 16 | TS_MINOR) |
46 | |||
47 | #define TS_MAJOR_3 3 | ||
48 | #define TS_VERSION_3 (TS_MAJOR_3 << 16 | TS_MINOR) | ||
46 | 49 | ||
47 | #define HB_MAJOR 3 | 50 | #define HB_MAJOR 3 |
48 | #define HB_MINOR 0 | 51 | #define HB_MINOR 0 |
49 | #define HB_VERSION (HB_MAJOR << 16 | HB_MINOR) | 52 | #define HB_VERSION (HB_MAJOR << 16 | HB_MINOR) |
50 | 53 | ||
51 | #define HB_WS2008_MAJOR 1 | 54 | #define HB_MAJOR_1 1 |
52 | #define HB_WS2008_VERSION (HB_WS2008_MAJOR << 16 | HB_MINOR) | 55 | #define HB_VERSION_1 (HB_MAJOR_1 << 16 | HB_MINOR) |
53 | 56 | ||
54 | static int sd_srv_version; | 57 | static int sd_srv_version; |
55 | static int ts_srv_version; | 58 | static int ts_srv_version; |
@@ -61,9 +64,14 @@ static struct hv_util_service util_shutdown = { | |||
61 | .util_cb = shutdown_onchannelcallback, | 64 | .util_cb = shutdown_onchannelcallback, |
62 | }; | 65 | }; |
63 | 66 | ||
67 | static int hv_timesync_init(struct hv_util_service *srv); | ||
68 | static void hv_timesync_deinit(void); | ||
69 | |||
64 | static void timesync_onchannelcallback(void *context); | 70 | static void timesync_onchannelcallback(void *context); |
65 | static struct hv_util_service util_timesynch = { | 71 | static struct hv_util_service util_timesynch = { |
66 | .util_cb = timesync_onchannelcallback, | 72 | .util_cb = timesync_onchannelcallback, |
73 | .util_init = hv_timesync_init, | ||
74 | .util_deinit = hv_timesync_deinit, | ||
67 | }; | 75 | }; |
68 | 76 | ||
69 | static void heartbeat_onchannelcallback(void *context); | 77 | static void heartbeat_onchannelcallback(void *context); |
@@ -161,35 +169,43 @@ static void shutdown_onchannelcallback(void *context) | |||
161 | } | 169 | } |
162 | 170 | ||
163 | /* | 171 | /* |
164 | * Set guest time to host UTC time. | ||
165 | */ | ||
166 | static inline void do_adj_guesttime(u64 hosttime) | ||
167 | { | ||
168 | s64 host_tns; | ||
169 | struct timespec host_ts; | ||
170 | |||
171 | host_tns = (hosttime - WLTIMEDELTA) * 100; | ||
172 | host_ts = ns_to_timespec(host_tns); | ||
173 | |||
174 | do_settimeofday(&host_ts); | ||
175 | } | ||
176 | |||
177 | /* | ||
178 | * Set the host time in a process context. | 172 | * Set the host time in a process context. |
179 | */ | 173 | */ |
180 | 174 | ||
181 | struct adj_time_work { | 175 | struct adj_time_work { |
182 | struct work_struct work; | 176 | struct work_struct work; |
183 | u64 host_time; | 177 | u64 host_time; |
178 | u64 ref_time; | ||
179 | u8 flags; | ||
184 | }; | 180 | }; |
185 | 181 | ||
186 | static void hv_set_host_time(struct work_struct *work) | 182 | static void hv_set_host_time(struct work_struct *work) |
187 | { | 183 | { |
188 | struct adj_time_work *wrk; | 184 | struct adj_time_work *wrk; |
185 | s64 host_tns; | ||
186 | u64 newtime; | ||
187 | struct timespec host_ts; | ||
189 | 188 | ||
190 | wrk = container_of(work, struct adj_time_work, work); | 189 | wrk = container_of(work, struct adj_time_work, work); |
191 | do_adj_guesttime(wrk->host_time); | 190 | |
192 | kfree(wrk); | 191 | newtime = wrk->host_time; |
192 | if (ts_srv_version > TS_VERSION_3) { | ||
193 | /* | ||
194 | * Some latency has been introduced since Hyper-V generated | ||
195 | * its time sample. Take that latency into account before | ||
196 | * using TSC reference time sample from Hyper-V. | ||
197 | * | ||
198 | * This sample is given by TimeSync v4 and above hosts. | ||
199 | */ | ||
200 | u64 current_tick; | ||
201 | |||
202 | rdmsrl(HV_X64_MSR_TIME_REF_COUNT, current_tick); | ||
203 | newtime += (current_tick - wrk->ref_time); | ||
204 | } | ||
205 | host_tns = (newtime - WLTIMEDELTA) * 100; | ||
206 | host_ts = ns_to_timespec(host_tns); | ||
207 | |||
208 | do_settimeofday(&host_ts); | ||
193 | } | 209 | } |
194 | 210 | ||
195 | /* | 211 | /* |
@@ -198,33 +214,31 @@ static void hv_set_host_time(struct work_struct *work) | |||
198 | * ICTIMESYNCFLAG_SYNC flag bit indicates reboot, restore events of the VM. | 214 | * ICTIMESYNCFLAG_SYNC flag bit indicates reboot, restore events of the VM. |
199 | * After reboot the flag ICTIMESYNCFLAG_SYNC is included in the first time | 215 | * After reboot the flag ICTIMESYNCFLAG_SYNC is included in the first time |
200 | * message after the timesync channel is opened. Since the hv_utils module is | 216 | * message after the timesync channel is opened. Since the hv_utils module is |
201 | * loaded after hv_vmbus, the first message is usually missed. The other | 217 | * loaded after hv_vmbus, the first message is usually missed. This bit is |
202 | * thing is, systime is automatically set to emulated hardware clock which may | 218 | * considered a hard request to discipline the clock. |
203 | * not be UTC time or in the same time zone. So, to override these effects, we | 219 | * |
204 | * use the first 50 time samples for initial system time setting. | 220 | * ICTIMESYNCFLAG_SAMPLE bit indicates a time sample from host. This is |
221 | * typically used as a hint to the guest. The guest is under no obligation | ||
222 | * to discipline the clock. | ||
205 | */ | 223 | */ |
206 | static inline void adj_guesttime(u64 hosttime, u8 flags) | 224 | static struct adj_time_work wrk; |
225 | static inline void adj_guesttime(u64 hosttime, u64 reftime, u8 flags) | ||
207 | { | 226 | { |
208 | struct adj_time_work *wrk; | ||
209 | static s32 scnt = 50; | ||
210 | 227 | ||
211 | wrk = kmalloc(sizeof(struct adj_time_work), GFP_ATOMIC); | 228 | /* |
212 | if (wrk == NULL) | 229 | * This check is safe since we are executing in the |
230 | * interrupt context and time synch messages arre always | ||
231 | * delivered on the same CPU. | ||
232 | */ | ||
233 | if (work_pending(&wrk.work)) | ||
213 | return; | 234 | return; |
214 | 235 | ||
215 | wrk->host_time = hosttime; | 236 | wrk.host_time = hosttime; |
216 | if ((flags & ICTIMESYNCFLAG_SYNC) != 0) { | 237 | wrk.ref_time = reftime; |
217 | INIT_WORK(&wrk->work, hv_set_host_time); | 238 | wrk.flags = flags; |
218 | schedule_work(&wrk->work); | 239 | if ((flags & (ICTIMESYNCFLAG_SYNC | ICTIMESYNCFLAG_SAMPLE)) != 0) { |
219 | return; | 240 | schedule_work(&wrk.work); |
220 | } | 241 | } |
221 | |||
222 | if ((flags & ICTIMESYNCFLAG_SAMPLE) != 0 && scnt > 0) { | ||
223 | scnt--; | ||
224 | INIT_WORK(&wrk->work, hv_set_host_time); | ||
225 | schedule_work(&wrk->work); | ||
226 | } else | ||
227 | kfree(wrk); | ||
228 | } | 242 | } |
229 | 243 | ||
230 | /* | 244 | /* |
@@ -237,6 +251,7 @@ static void timesync_onchannelcallback(void *context) | |||
237 | u64 requestid; | 251 | u64 requestid; |
238 | struct icmsg_hdr *icmsghdrp; | 252 | struct icmsg_hdr *icmsghdrp; |
239 | struct ictimesync_data *timedatap; | 253 | struct ictimesync_data *timedatap; |
254 | struct ictimesync_ref_data *refdata; | ||
240 | u8 *time_txf_buf = util_timesynch.recv_buffer; | 255 | u8 *time_txf_buf = util_timesynch.recv_buffer; |
241 | struct icmsg_negotiate *negop = NULL; | 256 | struct icmsg_negotiate *negop = NULL; |
242 | 257 | ||
@@ -252,11 +267,27 @@ static void timesync_onchannelcallback(void *context) | |||
252 | time_txf_buf, | 267 | time_txf_buf, |
253 | util_fw_version, | 268 | util_fw_version, |
254 | ts_srv_version); | 269 | ts_srv_version); |
270 | pr_info("Using TimeSync version %d.%d\n", | ||
271 | ts_srv_version >> 16, ts_srv_version & 0xFFFF); | ||
255 | } else { | 272 | } else { |
256 | timedatap = (struct ictimesync_data *)&time_txf_buf[ | 273 | if (ts_srv_version > TS_VERSION_3) { |
257 | sizeof(struct vmbuspipe_hdr) + | 274 | refdata = (struct ictimesync_ref_data *) |
258 | sizeof(struct icmsg_hdr)]; | 275 | &time_txf_buf[ |
259 | adj_guesttime(timedatap->parenttime, timedatap->flags); | 276 | sizeof(struct vmbuspipe_hdr) + |
277 | sizeof(struct icmsg_hdr)]; | ||
278 | |||
279 | adj_guesttime(refdata->parenttime, | ||
280 | refdata->vmreferencetime, | ||
281 | refdata->flags); | ||
282 | } else { | ||
283 | timedatap = (struct ictimesync_data *) | ||
284 | &time_txf_buf[ | ||
285 | sizeof(struct vmbuspipe_hdr) + | ||
286 | sizeof(struct icmsg_hdr)]; | ||
287 | adj_guesttime(timedatap->parenttime, | ||
288 | 0, | ||
289 | timedatap->flags); | ||
290 | } | ||
260 | } | 291 | } |
261 | 292 | ||
262 | icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION | 293 | icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION |
@@ -350,16 +381,21 @@ static int util_probe(struct hv_device *dev, | |||
350 | switch (vmbus_proto_version) { | 381 | switch (vmbus_proto_version) { |
351 | case (VERSION_WS2008): | 382 | case (VERSION_WS2008): |
352 | util_fw_version = UTIL_WS2K8_FW_VERSION; | 383 | util_fw_version = UTIL_WS2K8_FW_VERSION; |
353 | sd_srv_version = SD_WS2008_VERSION; | 384 | sd_srv_version = SD_VERSION_1; |
354 | ts_srv_version = TS_WS2008_VERSION; | 385 | ts_srv_version = TS_VERSION_1; |
355 | hb_srv_version = HB_WS2008_VERSION; | 386 | hb_srv_version = HB_VERSION_1; |
356 | break; | 387 | break; |
357 | 388 | case(VERSION_WIN10): | |
358 | default: | ||
359 | util_fw_version = UTIL_FW_VERSION; | 389 | util_fw_version = UTIL_FW_VERSION; |
360 | sd_srv_version = SD_VERSION; | 390 | sd_srv_version = SD_VERSION; |
361 | ts_srv_version = TS_VERSION; | 391 | ts_srv_version = TS_VERSION; |
362 | hb_srv_version = HB_VERSION; | 392 | hb_srv_version = HB_VERSION; |
393 | break; | ||
394 | default: | ||
395 | util_fw_version = UTIL_FW_VERSION; | ||
396 | sd_srv_version = SD_VERSION; | ||
397 | ts_srv_version = TS_VERSION_3; | ||
398 | hb_srv_version = HB_VERSION; | ||
363 | } | 399 | } |
364 | 400 | ||
365 | ret = vmbus_open(dev->channel, 4 * PAGE_SIZE, 4 * PAGE_SIZE, NULL, 0, | 401 | ret = vmbus_open(dev->channel, 4 * PAGE_SIZE, 4 * PAGE_SIZE, NULL, 0, |
@@ -427,6 +463,17 @@ static struct hv_driver util_drv = { | |||
427 | .remove = util_remove, | 463 | .remove = util_remove, |
428 | }; | 464 | }; |
429 | 465 | ||
466 | static int hv_timesync_init(struct hv_util_service *srv) | ||
467 | { | ||
468 | INIT_WORK(&wrk.work, hv_set_host_time); | ||
469 | return 0; | ||
470 | } | ||
471 | |||
472 | static void hv_timesync_deinit(void) | ||
473 | { | ||
474 | cancel_work_sync(&wrk.work); | ||
475 | } | ||
476 | |||
430 | static int __init init_hyperv_utils(void) | 477 | static int __init init_hyperv_utils(void) |
431 | { | 478 | { |
432 | pr_info("Registering HyperV Utility Driver\n"); | 479 | pr_info("Registering HyperV Utility Driver\n"); |
diff --git a/drivers/hv/hv_utils_transport.c b/drivers/hv/hv_utils_transport.c index 9a9983fa4531..c235a9515267 100644 --- a/drivers/hv/hv_utils_transport.c +++ b/drivers/hv/hv_utils_transport.c | |||
@@ -72,6 +72,10 @@ static ssize_t hvt_op_read(struct file *file, char __user *buf, | |||
72 | hvt->outmsg = NULL; | 72 | hvt->outmsg = NULL; |
73 | hvt->outmsg_len = 0; | 73 | hvt->outmsg_len = 0; |
74 | 74 | ||
75 | if (hvt->on_read) | ||
76 | hvt->on_read(); | ||
77 | hvt->on_read = NULL; | ||
78 | |||
75 | out_unlock: | 79 | out_unlock: |
76 | mutex_unlock(&hvt->lock); | 80 | mutex_unlock(&hvt->lock); |
77 | return ret; | 81 | return ret; |
@@ -219,7 +223,8 @@ static void hvt_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp) | |||
219 | mutex_unlock(&hvt->lock); | 223 | mutex_unlock(&hvt->lock); |
220 | } | 224 | } |
221 | 225 | ||
222 | int hvutil_transport_send(struct hvutil_transport *hvt, void *msg, int len) | 226 | int hvutil_transport_send(struct hvutil_transport *hvt, void *msg, int len, |
227 | void (*on_read_cb)(void)) | ||
223 | { | 228 | { |
224 | struct cn_msg *cn_msg; | 229 | struct cn_msg *cn_msg; |
225 | int ret = 0; | 230 | int ret = 0; |
@@ -237,6 +242,13 @@ int hvutil_transport_send(struct hvutil_transport *hvt, void *msg, int len) | |||
237 | memcpy(cn_msg->data, msg, len); | 242 | memcpy(cn_msg->data, msg, len); |
238 | ret = cn_netlink_send(cn_msg, 0, 0, GFP_ATOMIC); | 243 | ret = cn_netlink_send(cn_msg, 0, 0, GFP_ATOMIC); |
239 | kfree(cn_msg); | 244 | kfree(cn_msg); |
245 | /* | ||
246 | * We don't know when netlink messages are delivered but unlike | ||
247 | * in CHARDEV mode we're not blocked and we can send next | ||
248 | * messages right away. | ||
249 | */ | ||
250 | if (on_read_cb) | ||
251 | on_read_cb(); | ||
240 | return ret; | 252 | return ret; |
241 | } | 253 | } |
242 | /* HVUTIL_TRANSPORT_CHARDEV */ | 254 | /* HVUTIL_TRANSPORT_CHARDEV */ |
@@ -255,6 +267,7 @@ int hvutil_transport_send(struct hvutil_transport *hvt, void *msg, int len) | |||
255 | if (hvt->outmsg) { | 267 | if (hvt->outmsg) { |
256 | memcpy(hvt->outmsg, msg, len); | 268 | memcpy(hvt->outmsg, msg, len); |
257 | hvt->outmsg_len = len; | 269 | hvt->outmsg_len = len; |
270 | hvt->on_read = on_read_cb; | ||
258 | wake_up_interruptible(&hvt->outmsg_q); | 271 | wake_up_interruptible(&hvt->outmsg_q); |
259 | } else | 272 | } else |
260 | ret = -ENOMEM; | 273 | ret = -ENOMEM; |
diff --git a/drivers/hv/hv_utils_transport.h b/drivers/hv/hv_utils_transport.h index 06254a165a18..d98f5225c3e6 100644 --- a/drivers/hv/hv_utils_transport.h +++ b/drivers/hv/hv_utils_transport.h | |||
@@ -36,6 +36,7 @@ struct hvutil_transport { | |||
36 | struct list_head list; /* hvt_list */ | 36 | struct list_head list; /* hvt_list */ |
37 | int (*on_msg)(void *, int); /* callback on new user message */ | 37 | int (*on_msg)(void *, int); /* callback on new user message */ |
38 | void (*on_reset)(void); /* callback when userspace drops */ | 38 | void (*on_reset)(void); /* callback when userspace drops */ |
39 | void (*on_read)(void); /* callback on message read */ | ||
39 | u8 *outmsg; /* message to the userspace */ | 40 | u8 *outmsg; /* message to the userspace */ |
40 | int outmsg_len; /* its length */ | 41 | int outmsg_len; /* its length */ |
41 | wait_queue_head_t outmsg_q; /* poll/read wait queue */ | 42 | wait_queue_head_t outmsg_q; /* poll/read wait queue */ |
@@ -46,7 +47,8 @@ struct hvutil_transport *hvutil_transport_init(const char *name, | |||
46 | u32 cn_idx, u32 cn_val, | 47 | u32 cn_idx, u32 cn_val, |
47 | int (*on_msg)(void *, int), | 48 | int (*on_msg)(void *, int), |
48 | void (*on_reset)(void)); | 49 | void (*on_reset)(void)); |
49 | int hvutil_transport_send(struct hvutil_transport *hvt, void *msg, int len); | 50 | int hvutil_transport_send(struct hvutil_transport *hvt, void *msg, int len, |
51 | void (*on_read_cb)(void)); | ||
50 | void hvutil_transport_destroy(struct hvutil_transport *hvt); | 52 | void hvutil_transport_destroy(struct hvutil_transport *hvt); |
51 | 53 | ||
52 | #endif /* _HV_UTILS_TRANSPORT_H */ | 54 | #endif /* _HV_UTILS_TRANSPORT_H */ |
diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h index 718b5c72f0c8..a5b4442433c8 100644 --- a/drivers/hv/hyperv_vmbus.h +++ b/drivers/hv/hyperv_vmbus.h | |||
@@ -495,7 +495,7 @@ struct hv_ring_buffer_debug_info { | |||
495 | 495 | ||
496 | extern int hv_init(void); | 496 | extern int hv_init(void); |
497 | 497 | ||
498 | extern void hv_cleanup(void); | 498 | extern void hv_cleanup(bool crash); |
499 | 499 | ||
500 | extern int hv_post_message(union hv_connection_id connection_id, | 500 | extern int hv_post_message(union hv_connection_id connection_id, |
501 | enum hv_message_type message_type, | 501 | enum hv_message_type message_type, |
@@ -522,14 +522,15 @@ extern unsigned int host_info_edx; | |||
522 | /* Interface */ | 522 | /* Interface */ |
523 | 523 | ||
524 | 524 | ||
525 | int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info, void *buffer, | 525 | int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info, |
526 | u32 buflen); | 526 | struct page *pages, u32 pagecnt); |
527 | 527 | ||
528 | void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info); | 528 | void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info); |
529 | 529 | ||
530 | int hv_ringbuffer_write(struct hv_ring_buffer_info *ring_info, | 530 | int hv_ringbuffer_write(struct hv_ring_buffer_info *ring_info, |
531 | struct kvec *kv_list, | 531 | struct kvec *kv_list, |
532 | u32 kv_count, bool *signal, bool lock); | 532 | u32 kv_count, bool *signal, bool lock, |
533 | enum hv_signal_policy policy); | ||
533 | 534 | ||
534 | int hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info, | 535 | int hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info, |
535 | void *buffer, u32 buflen, u32 *buffer_actual_len, | 536 | void *buffer, u32 buflen, u32 *buffer_actual_len, |
diff --git a/drivers/hv/ring_buffer.c b/drivers/hv/ring_buffer.c index fe586bf74e17..08043da1a61c 100644 --- a/drivers/hv/ring_buffer.c +++ b/drivers/hv/ring_buffer.c | |||
@@ -27,6 +27,8 @@ | |||
27 | #include <linux/mm.h> | 27 | #include <linux/mm.h> |
28 | #include <linux/hyperv.h> | 28 | #include <linux/hyperv.h> |
29 | #include <linux/uio.h> | 29 | #include <linux/uio.h> |
30 | #include <linux/vmalloc.h> | ||
31 | #include <linux/slab.h> | ||
30 | 32 | ||
31 | #include "hyperv_vmbus.h" | 33 | #include "hyperv_vmbus.h" |
32 | 34 | ||
@@ -66,12 +68,20 @@ u32 hv_end_read(struct hv_ring_buffer_info *rbi) | |||
66 | * arrived. | 68 | * arrived. |
67 | */ | 69 | */ |
68 | 70 | ||
69 | static bool hv_need_to_signal(u32 old_write, struct hv_ring_buffer_info *rbi) | 71 | static bool hv_need_to_signal(u32 old_write, struct hv_ring_buffer_info *rbi, |
72 | enum hv_signal_policy policy) | ||
70 | { | 73 | { |
71 | virt_mb(); | 74 | virt_mb(); |
72 | if (READ_ONCE(rbi->ring_buffer->interrupt_mask)) | 75 | if (READ_ONCE(rbi->ring_buffer->interrupt_mask)) |
73 | return false; | 76 | return false; |
74 | 77 | ||
78 | /* | ||
79 | * When the client wants to control signaling, | ||
80 | * we only honour the host interrupt mask. | ||
81 | */ | ||
82 | if (policy == HV_SIGNAL_POLICY_EXPLICIT) | ||
83 | return true; | ||
84 | |||
75 | /* check interrupt_mask before read_index */ | 85 | /* check interrupt_mask before read_index */ |
76 | virt_rmb(); | 86 | virt_rmb(); |
77 | /* | 87 | /* |
@@ -162,18 +172,7 @@ static u32 hv_copyfrom_ringbuffer( | |||
162 | void *ring_buffer = hv_get_ring_buffer(ring_info); | 172 | void *ring_buffer = hv_get_ring_buffer(ring_info); |
163 | u32 ring_buffer_size = hv_get_ring_buffersize(ring_info); | 173 | u32 ring_buffer_size = hv_get_ring_buffersize(ring_info); |
164 | 174 | ||
165 | u32 frag_len; | 175 | memcpy(dest, ring_buffer + start_read_offset, destlen); |
166 | |||
167 | /* wrap-around detected at the src */ | ||
168 | if (destlen > ring_buffer_size - start_read_offset) { | ||
169 | frag_len = ring_buffer_size - start_read_offset; | ||
170 | |||
171 | memcpy(dest, ring_buffer + start_read_offset, frag_len); | ||
172 | memcpy(dest + frag_len, ring_buffer, destlen - frag_len); | ||
173 | } else | ||
174 | |||
175 | memcpy(dest, ring_buffer + start_read_offset, destlen); | ||
176 | |||
177 | 176 | ||
178 | start_read_offset += destlen; | 177 | start_read_offset += destlen; |
179 | start_read_offset %= ring_buffer_size; | 178 | start_read_offset %= ring_buffer_size; |
@@ -194,15 +193,8 @@ static u32 hv_copyto_ringbuffer( | |||
194 | { | 193 | { |
195 | void *ring_buffer = hv_get_ring_buffer(ring_info); | 194 | void *ring_buffer = hv_get_ring_buffer(ring_info); |
196 | u32 ring_buffer_size = hv_get_ring_buffersize(ring_info); | 195 | u32 ring_buffer_size = hv_get_ring_buffersize(ring_info); |
197 | u32 frag_len; | ||
198 | 196 | ||
199 | /* wrap-around detected! */ | 197 | memcpy(ring_buffer + start_write_offset, src, srclen); |
200 | if (srclen > ring_buffer_size - start_write_offset) { | ||
201 | frag_len = ring_buffer_size - start_write_offset; | ||
202 | memcpy(ring_buffer + start_write_offset, src, frag_len); | ||
203 | memcpy(ring_buffer, src + frag_len, srclen - frag_len); | ||
204 | } else | ||
205 | memcpy(ring_buffer + start_write_offset, src, srclen); | ||
206 | 198 | ||
207 | start_write_offset += srclen; | 199 | start_write_offset += srclen; |
208 | start_write_offset %= ring_buffer_size; | 200 | start_write_offset %= ring_buffer_size; |
@@ -235,22 +227,46 @@ void hv_ringbuffer_get_debuginfo(struct hv_ring_buffer_info *ring_info, | |||
235 | 227 | ||
236 | /* Initialize the ring buffer. */ | 228 | /* Initialize the ring buffer. */ |
237 | int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info, | 229 | int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info, |
238 | void *buffer, u32 buflen) | 230 | struct page *pages, u32 page_cnt) |
239 | { | 231 | { |
240 | if (sizeof(struct hv_ring_buffer) != PAGE_SIZE) | 232 | int i; |
241 | return -EINVAL; | 233 | struct page **pages_wraparound; |
234 | |||
235 | BUILD_BUG_ON((sizeof(struct hv_ring_buffer) != PAGE_SIZE)); | ||
242 | 236 | ||
243 | memset(ring_info, 0, sizeof(struct hv_ring_buffer_info)); | 237 | memset(ring_info, 0, sizeof(struct hv_ring_buffer_info)); |
244 | 238 | ||
245 | ring_info->ring_buffer = (struct hv_ring_buffer *)buffer; | 239 | /* |
240 | * First page holds struct hv_ring_buffer, do wraparound mapping for | ||
241 | * the rest. | ||
242 | */ | ||
243 | pages_wraparound = kzalloc(sizeof(struct page *) * (page_cnt * 2 - 1), | ||
244 | GFP_KERNEL); | ||
245 | if (!pages_wraparound) | ||
246 | return -ENOMEM; | ||
247 | |||
248 | pages_wraparound[0] = pages; | ||
249 | for (i = 0; i < 2 * (page_cnt - 1); i++) | ||
250 | pages_wraparound[i + 1] = &pages[i % (page_cnt - 1) + 1]; | ||
251 | |||
252 | ring_info->ring_buffer = (struct hv_ring_buffer *) | ||
253 | vmap(pages_wraparound, page_cnt * 2 - 1, VM_MAP, PAGE_KERNEL); | ||
254 | |||
255 | kfree(pages_wraparound); | ||
256 | |||
257 | |||
258 | if (!ring_info->ring_buffer) | ||
259 | return -ENOMEM; | ||
260 | |||
246 | ring_info->ring_buffer->read_index = | 261 | ring_info->ring_buffer->read_index = |
247 | ring_info->ring_buffer->write_index = 0; | 262 | ring_info->ring_buffer->write_index = 0; |
248 | 263 | ||
249 | /* Set the feature bit for enabling flow control. */ | 264 | /* Set the feature bit for enabling flow control. */ |
250 | ring_info->ring_buffer->feature_bits.value = 1; | 265 | ring_info->ring_buffer->feature_bits.value = 1; |
251 | 266 | ||
252 | ring_info->ring_size = buflen; | 267 | ring_info->ring_size = page_cnt << PAGE_SHIFT; |
253 | ring_info->ring_datasize = buflen - sizeof(struct hv_ring_buffer); | 268 | ring_info->ring_datasize = ring_info->ring_size - |
269 | sizeof(struct hv_ring_buffer); | ||
254 | 270 | ||
255 | spin_lock_init(&ring_info->ring_lock); | 271 | spin_lock_init(&ring_info->ring_lock); |
256 | 272 | ||
@@ -260,11 +276,13 @@ int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info, | |||
260 | /* Cleanup the ring buffer. */ | 276 | /* Cleanup the ring buffer. */ |
261 | void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info) | 277 | void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info) |
262 | { | 278 | { |
279 | vunmap(ring_info->ring_buffer); | ||
263 | } | 280 | } |
264 | 281 | ||
265 | /* Write to the ring buffer. */ | 282 | /* Write to the ring buffer. */ |
266 | int hv_ringbuffer_write(struct hv_ring_buffer_info *outring_info, | 283 | int hv_ringbuffer_write(struct hv_ring_buffer_info *outring_info, |
267 | struct kvec *kv_list, u32 kv_count, bool *signal, bool lock) | 284 | struct kvec *kv_list, u32 kv_count, bool *signal, bool lock, |
285 | enum hv_signal_policy policy) | ||
268 | { | 286 | { |
269 | int i = 0; | 287 | int i = 0; |
270 | u32 bytes_avail_towrite; | 288 | u32 bytes_avail_towrite; |
@@ -326,7 +344,7 @@ int hv_ringbuffer_write(struct hv_ring_buffer_info *outring_info, | |||
326 | if (lock) | 344 | if (lock) |
327 | spin_unlock_irqrestore(&outring_info->ring_lock, flags); | 345 | spin_unlock_irqrestore(&outring_info->ring_lock, flags); |
328 | 346 | ||
329 | *signal = hv_need_to_signal(old_write, outring_info); | 347 | *signal = hv_need_to_signal(old_write, outring_info, policy); |
330 | return 0; | 348 | return 0; |
331 | } | 349 | } |
332 | 350 | ||
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index e82f7e1c217c..a259e18d22d5 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c | |||
@@ -105,8 +105,8 @@ static struct notifier_block hyperv_panic_block = { | |||
105 | 105 | ||
106 | static const char *fb_mmio_name = "fb_range"; | 106 | static const char *fb_mmio_name = "fb_range"; |
107 | static struct resource *fb_mmio; | 107 | static struct resource *fb_mmio; |
108 | struct resource *hyperv_mmio; | 108 | static struct resource *hyperv_mmio; |
109 | DEFINE_SEMAPHORE(hyperv_mmio_lock); | 109 | static DEFINE_SEMAPHORE(hyperv_mmio_lock); |
110 | 110 | ||
111 | static int vmbus_exists(void) | 111 | static int vmbus_exists(void) |
112 | { | 112 | { |
@@ -874,7 +874,7 @@ err_alloc: | |||
874 | bus_unregister(&hv_bus); | 874 | bus_unregister(&hv_bus); |
875 | 875 | ||
876 | err_cleanup: | 876 | err_cleanup: |
877 | hv_cleanup(); | 877 | hv_cleanup(false); |
878 | 878 | ||
879 | return ret; | 879 | return ret; |
880 | } | 880 | } |
@@ -961,8 +961,8 @@ int vmbus_device_register(struct hv_device *child_device_obj) | |||
961 | { | 961 | { |
962 | int ret = 0; | 962 | int ret = 0; |
963 | 963 | ||
964 | dev_set_name(&child_device_obj->device, "vmbus_%d", | 964 | dev_set_name(&child_device_obj->device, "vmbus-%pUl", |
965 | child_device_obj->channel->id); | 965 | child_device_obj->channel->offermsg.offer.if_instance.b); |
966 | 966 | ||
967 | child_device_obj->device.bus = &hv_bus; | 967 | child_device_obj->device.bus = &hv_bus; |
968 | child_device_obj->device.parent = &hv_acpi_dev->dev; | 968 | child_device_obj->device.parent = &hv_acpi_dev->dev; |
@@ -1326,7 +1326,7 @@ static void hv_kexec_handler(void) | |||
1326 | vmbus_initiate_unload(false); | 1326 | vmbus_initiate_unload(false); |
1327 | for_each_online_cpu(cpu) | 1327 | for_each_online_cpu(cpu) |
1328 | smp_call_function_single(cpu, hv_synic_cleanup, NULL, 1); | 1328 | smp_call_function_single(cpu, hv_synic_cleanup, NULL, 1); |
1329 | hv_cleanup(); | 1329 | hv_cleanup(false); |
1330 | }; | 1330 | }; |
1331 | 1331 | ||
1332 | static void hv_crash_handler(struct pt_regs *regs) | 1332 | static void hv_crash_handler(struct pt_regs *regs) |
@@ -1338,7 +1338,7 @@ static void hv_crash_handler(struct pt_regs *regs) | |||
1338 | * for kdump. | 1338 | * for kdump. |
1339 | */ | 1339 | */ |
1340 | hv_synic_cleanup(NULL); | 1340 | hv_synic_cleanup(NULL); |
1341 | hv_cleanup(); | 1341 | hv_cleanup(true); |
1342 | }; | 1342 | }; |
1343 | 1343 | ||
1344 | static int __init hv_acpi_init(void) | 1344 | static int __init hv_acpi_init(void) |
@@ -1398,7 +1398,7 @@ static void __exit vmbus_exit(void) | |||
1398 | &hyperv_panic_block); | 1398 | &hyperv_panic_block); |
1399 | } | 1399 | } |
1400 | bus_unregister(&hv_bus); | 1400 | bus_unregister(&hv_bus); |
1401 | hv_cleanup(); | 1401 | hv_cleanup(false); |
1402 | for_each_online_cpu(cpu) { | 1402 | for_each_online_cpu(cpu) { |
1403 | tasklet_kill(hv_context.event_dpc[cpu]); | 1403 | tasklet_kill(hv_context.event_dpc[cpu]); |
1404 | smp_call_function_single(cpu, hv_synic_cleanup, NULL, 1); | 1404 | smp_call_function_single(cpu, hv_synic_cleanup, NULL, 1); |
diff --git a/drivers/hwtracing/coresight/coresight-etb10.c b/drivers/hwtracing/coresight/coresight-etb10.c index 4d20b0be0c0b..d7325c6534ad 100644 --- a/drivers/hwtracing/coresight/coresight-etb10.c +++ b/drivers/hwtracing/coresight/coresight-etb10.c | |||
@@ -184,8 +184,7 @@ static void etb_disable_hw(struct etb_drvdata *drvdata) | |||
184 | 184 | ||
185 | if (coresight_timeout(drvdata->base, ETB_FFCR, ETB_FFCR_BIT, 0)) { | 185 | if (coresight_timeout(drvdata->base, ETB_FFCR, ETB_FFCR_BIT, 0)) { |
186 | dev_err(drvdata->dev, | 186 | dev_err(drvdata->dev, |
187 | "timeout observed when probing at offset %#x\n", | 187 | "timeout while waiting for completion of Manual Flush\n"); |
188 | ETB_FFCR); | ||
189 | } | 188 | } |
190 | 189 | ||
191 | /* disable trace capture */ | 190 | /* disable trace capture */ |
@@ -193,8 +192,7 @@ static void etb_disable_hw(struct etb_drvdata *drvdata) | |||
193 | 192 | ||
194 | if (coresight_timeout(drvdata->base, ETB_FFSR, ETB_FFSR_BIT, 1)) { | 193 | if (coresight_timeout(drvdata->base, ETB_FFSR, ETB_FFSR_BIT, 1)) { |
195 | dev_err(drvdata->dev, | 194 | dev_err(drvdata->dev, |
196 | "timeout observed when probing at offset %#x\n", | 195 | "timeout while waiting for Formatter to Stop\n"); |
197 | ETB_FFCR); | ||
198 | } | 196 | } |
199 | 197 | ||
200 | CS_LOCK(drvdata->base); | 198 | CS_LOCK(drvdata->base); |
@@ -561,7 +559,7 @@ static const struct file_operations etb_fops = { | |||
561 | }; | 559 | }; |
562 | 560 | ||
563 | #define coresight_etb10_simple_func(name, offset) \ | 561 | #define coresight_etb10_simple_func(name, offset) \ |
564 | coresight_simple_func(struct etb_drvdata, name, offset) | 562 | coresight_simple_func(struct etb_drvdata, NULL, name, offset) |
565 | 563 | ||
566 | coresight_etb10_simple_func(rdp, ETB_RAM_DEPTH_REG); | 564 | coresight_etb10_simple_func(rdp, ETB_RAM_DEPTH_REG); |
567 | coresight_etb10_simple_func(sts, ETB_STATUS_REG); | 565 | coresight_etb10_simple_func(sts, ETB_STATUS_REG); |
@@ -638,7 +636,7 @@ static int etb_probe(struct amba_device *adev, const struct amba_id *id) | |||
638 | struct coresight_platform_data *pdata = NULL; | 636 | struct coresight_platform_data *pdata = NULL; |
639 | struct etb_drvdata *drvdata; | 637 | struct etb_drvdata *drvdata; |
640 | struct resource *res = &adev->res; | 638 | struct resource *res = &adev->res; |
641 | struct coresight_desc *desc; | 639 | struct coresight_desc desc = { 0 }; |
642 | struct device_node *np = adev->dev.of_node; | 640 | struct device_node *np = adev->dev.of_node; |
643 | 641 | ||
644 | if (np) { | 642 | if (np) { |
@@ -684,17 +682,13 @@ static int etb_probe(struct amba_device *adev, const struct amba_id *id) | |||
684 | return -ENOMEM; | 682 | return -ENOMEM; |
685 | } | 683 | } |
686 | 684 | ||
687 | desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL); | 685 | desc.type = CORESIGHT_DEV_TYPE_SINK; |
688 | if (!desc) | 686 | desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER; |
689 | return -ENOMEM; | 687 | desc.ops = &etb_cs_ops; |
690 | 688 | desc.pdata = pdata; | |
691 | desc->type = CORESIGHT_DEV_TYPE_SINK; | 689 | desc.dev = dev; |
692 | desc->subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER; | 690 | desc.groups = coresight_etb_groups; |
693 | desc->ops = &etb_cs_ops; | 691 | drvdata->csdev = coresight_register(&desc); |
694 | desc->pdata = pdata; | ||
695 | desc->dev = dev; | ||
696 | desc->groups = coresight_etb_groups; | ||
697 | drvdata->csdev = coresight_register(desc); | ||
698 | if (IS_ERR(drvdata->csdev)) | 692 | if (IS_ERR(drvdata->csdev)) |
699 | return PTR_ERR(drvdata->csdev); | 693 | return PTR_ERR(drvdata->csdev); |
700 | 694 | ||
diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c index 755125f7917f..2cd7c718198a 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.c +++ b/drivers/hwtracing/coresight/coresight-etm-perf.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/types.h> | 27 | #include <linux/types.h> |
28 | #include <linux/workqueue.h> | 28 | #include <linux/workqueue.h> |
29 | 29 | ||
30 | #include "coresight-etm-perf.h" | ||
30 | #include "coresight-priv.h" | 31 | #include "coresight-priv.h" |
31 | 32 | ||
32 | static struct pmu etm_pmu; | 33 | static struct pmu etm_pmu; |
@@ -71,14 +72,48 @@ static const struct attribute_group *etm_pmu_attr_groups[] = { | |||
71 | 72 | ||
72 | static void etm_event_read(struct perf_event *event) {} | 73 | static void etm_event_read(struct perf_event *event) {} |
73 | 74 | ||
74 | static int etm_event_init(struct perf_event *event) | 75 | static int etm_addr_filters_alloc(struct perf_event *event) |
75 | { | 76 | { |
76 | if (event->attr.type != etm_pmu.type) | 77 | struct etm_filters *filters; |
77 | return -ENOENT; | 78 | int node = event->cpu == -1 ? -1 : cpu_to_node(event->cpu); |
79 | |||
80 | filters = kzalloc_node(sizeof(struct etm_filters), GFP_KERNEL, node); | ||
81 | if (!filters) | ||
82 | return -ENOMEM; | ||
83 | |||
84 | if (event->parent) | ||
85 | memcpy(filters, event->parent->hw.addr_filters, | ||
86 | sizeof(*filters)); | ||
87 | |||
88 | event->hw.addr_filters = filters; | ||
78 | 89 | ||
79 | return 0; | 90 | return 0; |
80 | } | 91 | } |
81 | 92 | ||
93 | static void etm_event_destroy(struct perf_event *event) | ||
94 | { | ||
95 | kfree(event->hw.addr_filters); | ||
96 | event->hw.addr_filters = NULL; | ||
97 | } | ||
98 | |||
99 | static int etm_event_init(struct perf_event *event) | ||
100 | { | ||
101 | int ret = 0; | ||
102 | |||
103 | if (event->attr.type != etm_pmu.type) { | ||
104 | ret = -ENOENT; | ||
105 | goto out; | ||
106 | } | ||
107 | |||
108 | ret = etm_addr_filters_alloc(event); | ||
109 | if (ret) | ||
110 | goto out; | ||
111 | |||
112 | event->destroy = etm_event_destroy; | ||
113 | out: | ||
114 | return ret; | ||
115 | } | ||
116 | |||
82 | static void free_event_data(struct work_struct *work) | 117 | static void free_event_data(struct work_struct *work) |
83 | { | 118 | { |
84 | int cpu; | 119 | int cpu; |
@@ -100,7 +135,7 @@ static void free_event_data(struct work_struct *work) | |||
100 | } | 135 | } |
101 | 136 | ||
102 | for_each_cpu(cpu, mask) { | 137 | for_each_cpu(cpu, mask) { |
103 | if (event_data->path[cpu]) | 138 | if (!(IS_ERR_OR_NULL(event_data->path[cpu]))) |
104 | coresight_release_path(event_data->path[cpu]); | 139 | coresight_release_path(event_data->path[cpu]); |
105 | } | 140 | } |
106 | 141 | ||
@@ -185,7 +220,7 @@ static void *etm_setup_aux(int event_cpu, void **pages, | |||
185 | * referenced later when the path is actually needed. | 220 | * referenced later when the path is actually needed. |
186 | */ | 221 | */ |
187 | event_data->path[cpu] = coresight_build_path(csdev); | 222 | event_data->path[cpu] = coresight_build_path(csdev); |
188 | if (!event_data->path[cpu]) | 223 | if (IS_ERR(event_data->path[cpu])) |
189 | goto err; | 224 | goto err; |
190 | } | 225 | } |
191 | 226 | ||
@@ -258,7 +293,7 @@ static void etm_event_start(struct perf_event *event, int flags) | |||
258 | event->hw.state = 0; | 293 | event->hw.state = 0; |
259 | 294 | ||
260 | /* Finally enable the tracer */ | 295 | /* Finally enable the tracer */ |
261 | if (source_ops(csdev)->enable(csdev, &event->attr, CS_MODE_PERF)) | 296 | if (source_ops(csdev)->enable(csdev, event, CS_MODE_PERF)) |
262 | goto fail_end_stop; | 297 | goto fail_end_stop; |
263 | 298 | ||
264 | out: | 299 | out: |
@@ -291,7 +326,7 @@ static void etm_event_stop(struct perf_event *event, int mode) | |||
291 | return; | 326 | return; |
292 | 327 | ||
293 | /* stop tracer */ | 328 | /* stop tracer */ |
294 | source_ops(csdev)->disable(csdev); | 329 | source_ops(csdev)->disable(csdev, event); |
295 | 330 | ||
296 | /* tell the core */ | 331 | /* tell the core */ |
297 | event->hw.state = PERF_HES_STOPPED; | 332 | event->hw.state = PERF_HES_STOPPED; |
@@ -342,6 +377,87 @@ static void etm_event_del(struct perf_event *event, int mode) | |||
342 | etm_event_stop(event, PERF_EF_UPDATE); | 377 | etm_event_stop(event, PERF_EF_UPDATE); |
343 | } | 378 | } |
344 | 379 | ||
380 | static int etm_addr_filters_validate(struct list_head *filters) | ||
381 | { | ||
382 | bool range = false, address = false; | ||
383 | int index = 0; | ||
384 | struct perf_addr_filter *filter; | ||
385 | |||
386 | list_for_each_entry(filter, filters, entry) { | ||
387 | /* | ||
388 | * No need to go further if there's no more | ||
389 | * room for filters. | ||
390 | */ | ||
391 | if (++index > ETM_ADDR_CMP_MAX) | ||
392 | return -EOPNOTSUPP; | ||
393 | |||
394 | /* | ||
395 | * As taken from the struct perf_addr_filter documentation: | ||
396 | * @range: 1: range, 0: address | ||
397 | * | ||
398 | * At this time we don't allow range and start/stop filtering | ||
399 | * to cohabitate, they have to be mutually exclusive. | ||
400 | */ | ||
401 | if ((filter->range == 1) && address) | ||
402 | return -EOPNOTSUPP; | ||
403 | |||
404 | if ((filter->range == 0) && range) | ||
405 | return -EOPNOTSUPP; | ||
406 | |||
407 | /* | ||
408 | * For range filtering, the second address in the address | ||
409 | * range comparator needs to be higher than the first. | ||
410 | * Invalid otherwise. | ||
411 | */ | ||
412 | if (filter->range && filter->size == 0) | ||
413 | return -EINVAL; | ||
414 | |||
415 | /* | ||
416 | * Everything checks out with this filter, record what we've | ||
417 | * received before moving on to the next one. | ||
418 | */ | ||
419 | if (filter->range) | ||
420 | range = true; | ||
421 | else | ||
422 | address = true; | ||
423 | } | ||
424 | |||
425 | return 0; | ||
426 | } | ||
427 | |||
428 | static void etm_addr_filters_sync(struct perf_event *event) | ||
429 | { | ||
430 | struct perf_addr_filters_head *head = perf_event_addr_filters(event); | ||
431 | unsigned long start, stop, *offs = event->addr_filters_offs; | ||
432 | struct etm_filters *filters = event->hw.addr_filters; | ||
433 | struct etm_filter *etm_filter; | ||
434 | struct perf_addr_filter *filter; | ||
435 | int i = 0; | ||
436 | |||
437 | list_for_each_entry(filter, &head->list, entry) { | ||
438 | start = filter->offset + offs[i]; | ||
439 | stop = start + filter->size; | ||
440 | etm_filter = &filters->etm_filter[i]; | ||
441 | |||
442 | if (filter->range == 1) { | ||
443 | etm_filter->start_addr = start; | ||
444 | etm_filter->stop_addr = stop; | ||
445 | etm_filter->type = ETM_ADDR_TYPE_RANGE; | ||
446 | } else { | ||
447 | if (filter->filter == 1) { | ||
448 | etm_filter->start_addr = start; | ||
449 | etm_filter->type = ETM_ADDR_TYPE_START; | ||
450 | } else { | ||
451 | etm_filter->stop_addr = stop; | ||
452 | etm_filter->type = ETM_ADDR_TYPE_STOP; | ||
453 | } | ||
454 | } | ||
455 | i++; | ||
456 | } | ||
457 | |||
458 | filters->nr_filters = i; | ||
459 | } | ||
460 | |||
345 | int etm_perf_symlink(struct coresight_device *csdev, bool link) | 461 | int etm_perf_symlink(struct coresight_device *csdev, bool link) |
346 | { | 462 | { |
347 | char entry[sizeof("cpu9999999")]; | 463 | char entry[sizeof("cpu9999999")]; |
@@ -371,18 +487,21 @@ static int __init etm_perf_init(void) | |||
371 | { | 487 | { |
372 | int ret; | 488 | int ret; |
373 | 489 | ||
374 | etm_pmu.capabilities = PERF_PMU_CAP_EXCLUSIVE; | 490 | etm_pmu.capabilities = PERF_PMU_CAP_EXCLUSIVE; |
375 | 491 | ||
376 | etm_pmu.attr_groups = etm_pmu_attr_groups; | 492 | etm_pmu.attr_groups = etm_pmu_attr_groups; |
377 | etm_pmu.task_ctx_nr = perf_sw_context; | 493 | etm_pmu.task_ctx_nr = perf_sw_context; |
378 | etm_pmu.read = etm_event_read; | 494 | etm_pmu.read = etm_event_read; |
379 | etm_pmu.event_init = etm_event_init; | 495 | etm_pmu.event_init = etm_event_init; |
380 | etm_pmu.setup_aux = etm_setup_aux; | 496 | etm_pmu.setup_aux = etm_setup_aux; |
381 | etm_pmu.free_aux = etm_free_aux; | 497 | etm_pmu.free_aux = etm_free_aux; |
382 | etm_pmu.start = etm_event_start; | 498 | etm_pmu.start = etm_event_start; |
383 | etm_pmu.stop = etm_event_stop; | 499 | etm_pmu.stop = etm_event_stop; |
384 | etm_pmu.add = etm_event_add; | 500 | etm_pmu.add = etm_event_add; |
385 | etm_pmu.del = etm_event_del; | 501 | etm_pmu.del = etm_event_del; |
502 | etm_pmu.addr_filters_sync = etm_addr_filters_sync; | ||
503 | etm_pmu.addr_filters_validate = etm_addr_filters_validate; | ||
504 | etm_pmu.nr_addr_filters = ETM_ADDR_CMP_MAX; | ||
386 | 505 | ||
387 | ret = perf_pmu_register(&etm_pmu, CORESIGHT_ETM_PMU_NAME, -1); | 506 | ret = perf_pmu_register(&etm_pmu, CORESIGHT_ETM_PMU_NAME, -1); |
388 | if (ret == 0) | 507 | if (ret == 0) |
diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.h b/drivers/hwtracing/coresight/coresight-etm-perf.h index 87f5a134eb6f..3ffc9feb2d64 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.h +++ b/drivers/hwtracing/coresight/coresight-etm-perf.h | |||
@@ -18,8 +18,42 @@ | |||
18 | #ifndef _CORESIGHT_ETM_PERF_H | 18 | #ifndef _CORESIGHT_ETM_PERF_H |
19 | #define _CORESIGHT_ETM_PERF_H | 19 | #define _CORESIGHT_ETM_PERF_H |
20 | 20 | ||
21 | #include "coresight-priv.h" | ||
22 | |||
21 | struct coresight_device; | 23 | struct coresight_device; |
22 | 24 | ||
25 | /* | ||
26 | * In both ETMv3 and v4 the maximum number of address comparator implentable | ||
27 | * is 8. The actual number is implementation specific and will be checked | ||
28 | * when filters are applied. | ||
29 | */ | ||
30 | #define ETM_ADDR_CMP_MAX 8 | ||
31 | |||
32 | /** | ||
33 | * struct etm_filter - single instruction range or start/stop configuration. | ||
34 | * @start_addr: The address to start tracing on. | ||
35 | * @stop_addr: The address to stop tracing on. | ||
36 | * @type: Is this a range or start/stop filter. | ||
37 | */ | ||
38 | struct etm_filter { | ||
39 | unsigned long start_addr; | ||
40 | unsigned long stop_addr; | ||
41 | enum etm_addr_type type; | ||
42 | }; | ||
43 | |||
44 | /** | ||
45 | * struct etm_filters - set of filters for a session | ||
46 | * @etm_filter: All the filters for this session. | ||
47 | * @nr_filters: Number of filters | ||
48 | * @ssstatus: Status of the start/stop logic. | ||
49 | */ | ||
50 | struct etm_filters { | ||
51 | struct etm_filter etm_filter[ETM_ADDR_CMP_MAX]; | ||
52 | unsigned int nr_filters; | ||
53 | bool ssstatus; | ||
54 | }; | ||
55 | |||
56 | |||
23 | #ifdef CONFIG_CORESIGHT | 57 | #ifdef CONFIG_CORESIGHT |
24 | int etm_perf_symlink(struct coresight_device *csdev, bool link); | 58 | int etm_perf_symlink(struct coresight_device *csdev, bool link); |
25 | 59 | ||
diff --git a/drivers/hwtracing/coresight/coresight-etm.h b/drivers/hwtracing/coresight/coresight-etm.h index 51597cb2c08a..4a18ee499965 100644 --- a/drivers/hwtracing/coresight/coresight-etm.h +++ b/drivers/hwtracing/coresight/coresight-etm.h | |||
@@ -259,14 +259,6 @@ struct etm_drvdata { | |||
259 | struct etm_config config; | 259 | struct etm_config config; |
260 | }; | 260 | }; |
261 | 261 | ||
262 | enum etm_addr_type { | ||
263 | ETM_ADDR_TYPE_NONE, | ||
264 | ETM_ADDR_TYPE_SINGLE, | ||
265 | ETM_ADDR_TYPE_RANGE, | ||
266 | ETM_ADDR_TYPE_START, | ||
267 | ETM_ADDR_TYPE_STOP, | ||
268 | }; | ||
269 | |||
270 | static inline void etm_writel(struct etm_drvdata *drvdata, | 262 | static inline void etm_writel(struct etm_drvdata *drvdata, |
271 | u32 val, u32 off) | 263 | u32 val, u32 off) |
272 | { | 264 | { |
diff --git a/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c index 02d4b629891f..e9b071953f80 100644 --- a/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/pm_runtime.h> | 18 | #include <linux/pm_runtime.h> |
19 | #include <linux/sysfs.h> | 19 | #include <linux/sysfs.h> |
20 | #include "coresight-etm.h" | 20 | #include "coresight-etm.h" |
21 | #include "coresight-priv.h" | ||
21 | 22 | ||
22 | static ssize_t nr_addr_cmp_show(struct device *dev, | 23 | static ssize_t nr_addr_cmp_show(struct device *dev, |
23 | struct device_attribute *attr, char *buf) | 24 | struct device_attribute *attr, char *buf) |
@@ -1222,7 +1223,7 @@ static struct attribute *coresight_etm_attrs[] = { | |||
1222 | }; | 1223 | }; |
1223 | 1224 | ||
1224 | #define coresight_etm3x_simple_func(name, offset) \ | 1225 | #define coresight_etm3x_simple_func(name, offset) \ |
1225 | coresight_simple_func(struct etm_drvdata, name, offset) | 1226 | coresight_simple_func(struct etm_drvdata, NULL, name, offset) |
1226 | 1227 | ||
1227 | coresight_etm3x_simple_func(etmccr, ETMCCR); | 1228 | coresight_etm3x_simple_func(etmccr, ETMCCR); |
1228 | coresight_etm3x_simple_func(etmccer, ETMCCER); | 1229 | coresight_etm3x_simple_func(etmccer, ETMCCER); |
diff --git a/drivers/hwtracing/coresight/coresight-etm3x.c b/drivers/hwtracing/coresight/coresight-etm3x.c index 2de4cad9c5ed..3fe368b23d15 100644 --- a/drivers/hwtracing/coresight/coresight-etm3x.c +++ b/drivers/hwtracing/coresight/coresight-etm3x.c | |||
@@ -311,9 +311,10 @@ void etm_config_trace_mode(struct etm_config *config) | |||
311 | #define ETM3X_SUPPORTED_OPTIONS (ETMCR_CYC_ACC | ETMCR_TIMESTAMP_EN) | 311 | #define ETM3X_SUPPORTED_OPTIONS (ETMCR_CYC_ACC | ETMCR_TIMESTAMP_EN) |
312 | 312 | ||
313 | static int etm_parse_event_config(struct etm_drvdata *drvdata, | 313 | static int etm_parse_event_config(struct etm_drvdata *drvdata, |
314 | struct perf_event_attr *attr) | 314 | struct perf_event *event) |
315 | { | 315 | { |
316 | struct etm_config *config = &drvdata->config; | 316 | struct etm_config *config = &drvdata->config; |
317 | struct perf_event_attr *attr = &event->attr; | ||
317 | 318 | ||
318 | if (!attr) | 319 | if (!attr) |
319 | return -EINVAL; | 320 | return -EINVAL; |
@@ -459,7 +460,7 @@ static int etm_trace_id(struct coresight_device *csdev) | |||
459 | } | 460 | } |
460 | 461 | ||
461 | static int etm_enable_perf(struct coresight_device *csdev, | 462 | static int etm_enable_perf(struct coresight_device *csdev, |
462 | struct perf_event_attr *attr) | 463 | struct perf_event *event) |
463 | { | 464 | { |
464 | struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); | 465 | struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); |
465 | 466 | ||
@@ -467,7 +468,7 @@ static int etm_enable_perf(struct coresight_device *csdev, | |||
467 | return -EINVAL; | 468 | return -EINVAL; |
468 | 469 | ||
469 | /* Configure the tracer based on the session's specifics */ | 470 | /* Configure the tracer based on the session's specifics */ |
470 | etm_parse_event_config(drvdata, attr); | 471 | etm_parse_event_config(drvdata, event); |
471 | /* And enable it */ | 472 | /* And enable it */ |
472 | etm_enable_hw(drvdata); | 473 | etm_enable_hw(drvdata); |
473 | 474 | ||
@@ -504,7 +505,7 @@ err: | |||
504 | } | 505 | } |
505 | 506 | ||
506 | static int etm_enable(struct coresight_device *csdev, | 507 | static int etm_enable(struct coresight_device *csdev, |
507 | struct perf_event_attr *attr, u32 mode) | 508 | struct perf_event *event, u32 mode) |
508 | { | 509 | { |
509 | int ret; | 510 | int ret; |
510 | u32 val; | 511 | u32 val; |
@@ -521,7 +522,7 @@ static int etm_enable(struct coresight_device *csdev, | |||
521 | ret = etm_enable_sysfs(csdev); | 522 | ret = etm_enable_sysfs(csdev); |
522 | break; | 523 | break; |
523 | case CS_MODE_PERF: | 524 | case CS_MODE_PERF: |
524 | ret = etm_enable_perf(csdev, attr); | 525 | ret = etm_enable_perf(csdev, event); |
525 | break; | 526 | break; |
526 | default: | 527 | default: |
527 | ret = -EINVAL; | 528 | ret = -EINVAL; |
@@ -601,7 +602,8 @@ static void etm_disable_sysfs(struct coresight_device *csdev) | |||
601 | dev_info(drvdata->dev, "ETM tracing disabled\n"); | 602 | dev_info(drvdata->dev, "ETM tracing disabled\n"); |
602 | } | 603 | } |
603 | 604 | ||
604 | static void etm_disable(struct coresight_device *csdev) | 605 | static void etm_disable(struct coresight_device *csdev, |
606 | struct perf_event *event) | ||
605 | { | 607 | { |
606 | u32 mode; | 608 | u32 mode; |
607 | struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); | 609 | struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); |
@@ -756,13 +758,9 @@ static int etm_probe(struct amba_device *adev, const struct amba_id *id) | |||
756 | struct coresight_platform_data *pdata = NULL; | 758 | struct coresight_platform_data *pdata = NULL; |
757 | struct etm_drvdata *drvdata; | 759 | struct etm_drvdata *drvdata; |
758 | struct resource *res = &adev->res; | 760 | struct resource *res = &adev->res; |
759 | struct coresight_desc *desc; | 761 | struct coresight_desc desc = { 0 }; |
760 | struct device_node *np = adev->dev.of_node; | 762 | struct device_node *np = adev->dev.of_node; |
761 | 763 | ||
762 | desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL); | ||
763 | if (!desc) | ||
764 | return -ENOMEM; | ||
765 | |||
766 | drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); | 764 | drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); |
767 | if (!drvdata) | 765 | if (!drvdata) |
768 | return -ENOMEM; | 766 | return -ENOMEM; |
@@ -825,13 +823,13 @@ static int etm_probe(struct amba_device *adev, const struct amba_id *id) | |||
825 | etm_init_trace_id(drvdata); | 823 | etm_init_trace_id(drvdata); |
826 | etm_set_default(&drvdata->config); | 824 | etm_set_default(&drvdata->config); |
827 | 825 | ||
828 | desc->type = CORESIGHT_DEV_TYPE_SOURCE; | 826 | desc.type = CORESIGHT_DEV_TYPE_SOURCE; |
829 | desc->subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_PROC; | 827 | desc.subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_PROC; |
830 | desc->ops = &etm_cs_ops; | 828 | desc.ops = &etm_cs_ops; |
831 | desc->pdata = pdata; | 829 | desc.pdata = pdata; |
832 | desc->dev = dev; | 830 | desc.dev = dev; |
833 | desc->groups = coresight_etm_groups; | 831 | desc.groups = coresight_etm_groups; |
834 | drvdata->csdev = coresight_register(desc); | 832 | drvdata->csdev = coresight_register(&desc); |
835 | if (IS_ERR(drvdata->csdev)) { | 833 | if (IS_ERR(drvdata->csdev)) { |
836 | ret = PTR_ERR(drvdata->csdev); | 834 | ret = PTR_ERR(drvdata->csdev); |
837 | goto err_arch_supported; | 835 | goto err_arch_supported; |
@@ -893,6 +891,11 @@ static struct amba_id etm_ids[] = { | |||
893 | .mask = 0x0003ffff, | 891 | .mask = 0x0003ffff, |
894 | .data = "ETM 3.3", | 892 | .data = "ETM 3.3", |
895 | }, | 893 | }, |
894 | { /* ETM 3.5 - Cortex-A5 */ | ||
895 | .id = 0x0003b955, | ||
896 | .mask = 0x0003ffff, | ||
897 | .data = "ETM 3.5", | ||
898 | }, | ||
896 | { /* ETM 3.5 */ | 899 | { /* ETM 3.5 */ |
897 | .id = 0x0003b956, | 900 | .id = 0x0003b956, |
898 | .mask = 0x0003ffff, | 901 | .mask = 0x0003ffff, |
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c index 7c84308c5564..b9b1e9c8f4c4 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/pm_runtime.h> | 18 | #include <linux/pm_runtime.h> |
19 | #include <linux/sysfs.h> | 19 | #include <linux/sysfs.h> |
20 | #include "coresight-etm4x.h" | 20 | #include "coresight-etm4x.h" |
21 | #include "coresight-priv.h" | ||
21 | 22 | ||
22 | static int etm4_set_mode_exclude(struct etmv4_drvdata *drvdata, bool exclude) | 23 | static int etm4_set_mode_exclude(struct etmv4_drvdata *drvdata, bool exclude) |
23 | { | 24 | { |
@@ -2039,15 +2040,42 @@ static struct attribute *coresight_etmv4_attrs[] = { | |||
2039 | NULL, | 2040 | NULL, |
2040 | }; | 2041 | }; |
2041 | 2042 | ||
2043 | struct etmv4_reg { | ||
2044 | void __iomem *addr; | ||
2045 | u32 data; | ||
2046 | }; | ||
2047 | |||
2048 | static void do_smp_cross_read(void *data) | ||
2049 | { | ||
2050 | struct etmv4_reg *reg = data; | ||
2051 | |||
2052 | reg->data = readl_relaxed(reg->addr); | ||
2053 | } | ||
2054 | |||
2055 | static u32 etmv4_cross_read(const struct device *dev, u32 offset) | ||
2056 | { | ||
2057 | struct etmv4_drvdata *drvdata = dev_get_drvdata(dev); | ||
2058 | struct etmv4_reg reg; | ||
2059 | |||
2060 | reg.addr = drvdata->base + offset; | ||
2061 | /* | ||
2062 | * smp cross call ensures the CPU will be powered up before | ||
2063 | * accessing the ETMv4 trace core registers | ||
2064 | */ | ||
2065 | smp_call_function_single(drvdata->cpu, do_smp_cross_read, ®, 1); | ||
2066 | return reg.data; | ||
2067 | } | ||
2068 | |||
2042 | #define coresight_etm4x_simple_func(name, offset) \ | 2069 | #define coresight_etm4x_simple_func(name, offset) \ |
2043 | coresight_simple_func(struct etmv4_drvdata, name, offset) | 2070 | coresight_simple_func(struct etmv4_drvdata, NULL, name, offset) |
2071 | |||
2072 | #define coresight_etm4x_cross_read(name, offset) \ | ||
2073 | coresight_simple_func(struct etmv4_drvdata, etmv4_cross_read, \ | ||
2074 | name, offset) | ||
2044 | 2075 | ||
2045 | coresight_etm4x_simple_func(trcoslsr, TRCOSLSR); | ||
2046 | coresight_etm4x_simple_func(trcpdcr, TRCPDCR); | 2076 | coresight_etm4x_simple_func(trcpdcr, TRCPDCR); |
2047 | coresight_etm4x_simple_func(trcpdsr, TRCPDSR); | 2077 | coresight_etm4x_simple_func(trcpdsr, TRCPDSR); |
2048 | coresight_etm4x_simple_func(trclsr, TRCLSR); | 2078 | coresight_etm4x_simple_func(trclsr, TRCLSR); |
2049 | coresight_etm4x_simple_func(trcconfig, TRCCONFIGR); | ||
2050 | coresight_etm4x_simple_func(trctraceid, TRCTRACEIDR); | ||
2051 | coresight_etm4x_simple_func(trcauthstatus, TRCAUTHSTATUS); | 2079 | coresight_etm4x_simple_func(trcauthstatus, TRCAUTHSTATUS); |
2052 | coresight_etm4x_simple_func(trcdevid, TRCDEVID); | 2080 | coresight_etm4x_simple_func(trcdevid, TRCDEVID); |
2053 | coresight_etm4x_simple_func(trcdevtype, TRCDEVTYPE); | 2081 | coresight_etm4x_simple_func(trcdevtype, TRCDEVTYPE); |
@@ -2055,6 +2083,9 @@ coresight_etm4x_simple_func(trcpidr0, TRCPIDR0); | |||
2055 | coresight_etm4x_simple_func(trcpidr1, TRCPIDR1); | 2083 | coresight_etm4x_simple_func(trcpidr1, TRCPIDR1); |
2056 | coresight_etm4x_simple_func(trcpidr2, TRCPIDR2); | 2084 | coresight_etm4x_simple_func(trcpidr2, TRCPIDR2); |
2057 | coresight_etm4x_simple_func(trcpidr3, TRCPIDR3); | 2085 | coresight_etm4x_simple_func(trcpidr3, TRCPIDR3); |
2086 | coresight_etm4x_cross_read(trcoslsr, TRCOSLSR); | ||
2087 | coresight_etm4x_cross_read(trcconfig, TRCCONFIGR); | ||
2088 | coresight_etm4x_cross_read(trctraceid, TRCTRACEIDR); | ||
2058 | 2089 | ||
2059 | static struct attribute *coresight_etmv4_mgmt_attrs[] = { | 2090 | static struct attribute *coresight_etmv4_mgmt_attrs[] = { |
2060 | &dev_attr_trcoslsr.attr, | 2091 | &dev_attr_trcoslsr.attr, |
@@ -2073,19 +2104,19 @@ static struct attribute *coresight_etmv4_mgmt_attrs[] = { | |||
2073 | NULL, | 2104 | NULL, |
2074 | }; | 2105 | }; |
2075 | 2106 | ||
2076 | coresight_etm4x_simple_func(trcidr0, TRCIDR0); | 2107 | coresight_etm4x_cross_read(trcidr0, TRCIDR0); |
2077 | coresight_etm4x_simple_func(trcidr1, TRCIDR1); | 2108 | coresight_etm4x_cross_read(trcidr1, TRCIDR1); |
2078 | coresight_etm4x_simple_func(trcidr2, TRCIDR2); | 2109 | coresight_etm4x_cross_read(trcidr2, TRCIDR2); |
2079 | coresight_etm4x_simple_func(trcidr3, TRCIDR3); | 2110 | coresight_etm4x_cross_read(trcidr3, TRCIDR3); |
2080 | coresight_etm4x_simple_func(trcidr4, TRCIDR4); | 2111 | coresight_etm4x_cross_read(trcidr4, TRCIDR4); |
2081 | coresight_etm4x_simple_func(trcidr5, TRCIDR5); | 2112 | coresight_etm4x_cross_read(trcidr5, TRCIDR5); |
2082 | /* trcidr[6,7] are reserved */ | 2113 | /* trcidr[6,7] are reserved */ |
2083 | coresight_etm4x_simple_func(trcidr8, TRCIDR8); | 2114 | coresight_etm4x_cross_read(trcidr8, TRCIDR8); |
2084 | coresight_etm4x_simple_func(trcidr9, TRCIDR9); | 2115 | coresight_etm4x_cross_read(trcidr9, TRCIDR9); |
2085 | coresight_etm4x_simple_func(trcidr10, TRCIDR10); | 2116 | coresight_etm4x_cross_read(trcidr10, TRCIDR10); |
2086 | coresight_etm4x_simple_func(trcidr11, TRCIDR11); | 2117 | coresight_etm4x_cross_read(trcidr11, TRCIDR11); |
2087 | coresight_etm4x_simple_func(trcidr12, TRCIDR12); | 2118 | coresight_etm4x_cross_read(trcidr12, TRCIDR12); |
2088 | coresight_etm4x_simple_func(trcidr13, TRCIDR13); | 2119 | coresight_etm4x_cross_read(trcidr13, TRCIDR13); |
2089 | 2120 | ||
2090 | static struct attribute *coresight_etmv4_trcidr_attrs[] = { | 2121 | static struct attribute *coresight_etmv4_trcidr_attrs[] = { |
2091 | &dev_attr_trcidr0.attr, | 2122 | &dev_attr_trcidr0.attr, |
diff --git a/drivers/hwtracing/coresight/coresight-etm4x.c b/drivers/hwtracing/coresight/coresight-etm4x.c index 1a5e0d14c1dd..4db8d6a4d0cb 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x.c +++ b/drivers/hwtracing/coresight/coresight-etm4x.c | |||
@@ -33,7 +33,6 @@ | |||
33 | #include <linux/uaccess.h> | 33 | #include <linux/uaccess.h> |
34 | #include <linux/perf_event.h> | 34 | #include <linux/perf_event.h> |
35 | #include <linux/pm_runtime.h> | 35 | #include <linux/pm_runtime.h> |
36 | #include <linux/perf_event.h> | ||
37 | #include <asm/sections.h> | 36 | #include <asm/sections.h> |
38 | #include <asm/local.h> | 37 | #include <asm/local.h> |
39 | 38 | ||
@@ -46,7 +45,9 @@ module_param_named(boot_enable, boot_enable, int, S_IRUGO); | |||
46 | /* The number of ETMv4 currently registered */ | 45 | /* The number of ETMv4 currently registered */ |
47 | static int etm4_count; | 46 | static int etm4_count; |
48 | static struct etmv4_drvdata *etmdrvdata[NR_CPUS]; | 47 | static struct etmv4_drvdata *etmdrvdata[NR_CPUS]; |
49 | static void etm4_set_default(struct etmv4_config *config); | 48 | static void etm4_set_default_config(struct etmv4_config *config); |
49 | static int etm4_set_event_filters(struct etmv4_drvdata *drvdata, | ||
50 | struct perf_event *event); | ||
50 | 51 | ||
51 | static enum cpuhp_state hp_online; | 52 | static enum cpuhp_state hp_online; |
52 | 53 | ||
@@ -79,22 +80,8 @@ static int etm4_cpu_id(struct coresight_device *csdev) | |||
79 | static int etm4_trace_id(struct coresight_device *csdev) | 80 | static int etm4_trace_id(struct coresight_device *csdev) |
80 | { | 81 | { |
81 | struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); | 82 | struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); |
82 | unsigned long flags; | ||
83 | int trace_id = -1; | ||
84 | |||
85 | if (!local_read(&drvdata->mode)) | ||
86 | return drvdata->trcid; | ||
87 | |||
88 | spin_lock_irqsave(&drvdata->spinlock, flags); | ||
89 | |||
90 | CS_UNLOCK(drvdata->base); | ||
91 | trace_id = readl_relaxed(drvdata->base + TRCTRACEIDR); | ||
92 | trace_id &= ETM_TRACEID_MASK; | ||
93 | CS_LOCK(drvdata->base); | ||
94 | 83 | ||
95 | spin_unlock_irqrestore(&drvdata->spinlock, flags); | 84 | return drvdata->trcid; |
96 | |||
97 | return trace_id; | ||
98 | } | 85 | } |
99 | 86 | ||
100 | static void etm4_enable_hw(void *info) | 87 | static void etm4_enable_hw(void *info) |
@@ -113,8 +100,7 @@ static void etm4_enable_hw(void *info) | |||
113 | /* wait for TRCSTATR.IDLE to go up */ | 100 | /* wait for TRCSTATR.IDLE to go up */ |
114 | if (coresight_timeout(drvdata->base, TRCSTATR, TRCSTATR_IDLE_BIT, 1)) | 101 | if (coresight_timeout(drvdata->base, TRCSTATR, TRCSTATR_IDLE_BIT, 1)) |
115 | dev_err(drvdata->dev, | 102 | dev_err(drvdata->dev, |
116 | "timeout observed when probing at offset %#x\n", | 103 | "timeout while waiting for Idle Trace Status\n"); |
117 | TRCSTATR); | ||
118 | 104 | ||
119 | writel_relaxed(config->pe_sel, drvdata->base + TRCPROCSELR); | 105 | writel_relaxed(config->pe_sel, drvdata->base + TRCPROCSELR); |
120 | writel_relaxed(config->cfg, drvdata->base + TRCCONFIGR); | 106 | writel_relaxed(config->cfg, drvdata->base + TRCCONFIGR); |
@@ -180,14 +166,20 @@ static void etm4_enable_hw(void *info) | |||
180 | writel_relaxed(config->vmid_mask0, drvdata->base + TRCVMIDCCTLR0); | 166 | writel_relaxed(config->vmid_mask0, drvdata->base + TRCVMIDCCTLR0); |
181 | writel_relaxed(config->vmid_mask1, drvdata->base + TRCVMIDCCTLR1); | 167 | writel_relaxed(config->vmid_mask1, drvdata->base + TRCVMIDCCTLR1); |
182 | 168 | ||
169 | /* | ||
170 | * Request to keep the trace unit powered and also | ||
171 | * emulation of powerdown | ||
172 | */ | ||
173 | writel_relaxed(readl_relaxed(drvdata->base + TRCPDCR) | TRCPDCR_PU, | ||
174 | drvdata->base + TRCPDCR); | ||
175 | |||
183 | /* Enable the trace unit */ | 176 | /* Enable the trace unit */ |
184 | writel_relaxed(1, drvdata->base + TRCPRGCTLR); | 177 | writel_relaxed(1, drvdata->base + TRCPRGCTLR); |
185 | 178 | ||
186 | /* wait for TRCSTATR.IDLE to go back down to '0' */ | 179 | /* wait for TRCSTATR.IDLE to go back down to '0' */ |
187 | if (coresight_timeout(drvdata->base, TRCSTATR, TRCSTATR_IDLE_BIT, 0)) | 180 | if (coresight_timeout(drvdata->base, TRCSTATR, TRCSTATR_IDLE_BIT, 0)) |
188 | dev_err(drvdata->dev, | 181 | dev_err(drvdata->dev, |
189 | "timeout observed when probing at offset %#x\n", | 182 | "timeout while waiting for Idle Trace Status\n"); |
190 | TRCSTATR); | ||
191 | 183 | ||
192 | CS_LOCK(drvdata->base); | 184 | CS_LOCK(drvdata->base); |
193 | 185 | ||
@@ -195,12 +187,16 @@ static void etm4_enable_hw(void *info) | |||
195 | } | 187 | } |
196 | 188 | ||
197 | static int etm4_parse_event_config(struct etmv4_drvdata *drvdata, | 189 | static int etm4_parse_event_config(struct etmv4_drvdata *drvdata, |
198 | struct perf_event_attr *attr) | 190 | struct perf_event *event) |
199 | { | 191 | { |
192 | int ret = 0; | ||
200 | struct etmv4_config *config = &drvdata->config; | 193 | struct etmv4_config *config = &drvdata->config; |
194 | struct perf_event_attr *attr = &event->attr; | ||
201 | 195 | ||
202 | if (!attr) | 196 | if (!attr) { |
203 | return -EINVAL; | 197 | ret = -EINVAL; |
198 | goto out; | ||
199 | } | ||
204 | 200 | ||
205 | /* Clear configuration from previous run */ | 201 | /* Clear configuration from previous run */ |
206 | memset(config, 0, sizeof(struct etmv4_config)); | 202 | memset(config, 0, sizeof(struct etmv4_config)); |
@@ -212,14 +208,12 @@ static int etm4_parse_event_config(struct etmv4_drvdata *drvdata, | |||
212 | config->mode = ETM_MODE_EXCL_USER; | 208 | config->mode = ETM_MODE_EXCL_USER; |
213 | 209 | ||
214 | /* Always start from the default config */ | 210 | /* Always start from the default config */ |
215 | etm4_set_default(config); | 211 | etm4_set_default_config(config); |
216 | 212 | ||
217 | /* | 213 | /* Configure filters specified on the perf cmd line, if any. */ |
218 | * By default the tracers are configured to trace the whole address | 214 | ret = etm4_set_event_filters(drvdata, event); |
219 | * range. Narrow the field only if requested by user space. | 215 | if (ret) |
220 | */ | 216 | goto out; |
221 | if (config->mode) | ||
222 | etm4_config_trace_mode(config); | ||
223 | 217 | ||
224 | /* Go from generic option to ETMv4 specifics */ | 218 | /* Go from generic option to ETMv4 specifics */ |
225 | if (attr->config & BIT(ETM_OPT_CYCACC)) | 219 | if (attr->config & BIT(ETM_OPT_CYCACC)) |
@@ -227,23 +221,30 @@ static int etm4_parse_event_config(struct etmv4_drvdata *drvdata, | |||
227 | if (attr->config & BIT(ETM_OPT_TS)) | 221 | if (attr->config & BIT(ETM_OPT_TS)) |
228 | config->cfg |= ETMv4_MODE_TIMESTAMP; | 222 | config->cfg |= ETMv4_MODE_TIMESTAMP; |
229 | 223 | ||
230 | return 0; | 224 | out: |
225 | return ret; | ||
231 | } | 226 | } |
232 | 227 | ||
233 | static int etm4_enable_perf(struct coresight_device *csdev, | 228 | static int etm4_enable_perf(struct coresight_device *csdev, |
234 | struct perf_event_attr *attr) | 229 | struct perf_event *event) |
235 | { | 230 | { |
231 | int ret = 0; | ||
236 | struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); | 232 | struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); |
237 | 233 | ||
238 | if (WARN_ON_ONCE(drvdata->cpu != smp_processor_id())) | 234 | if (WARN_ON_ONCE(drvdata->cpu != smp_processor_id())) { |
239 | return -EINVAL; | 235 | ret = -EINVAL; |
236 | goto out; | ||
237 | } | ||
240 | 238 | ||
241 | /* Configure the tracer based on the session's specifics */ | 239 | /* Configure the tracer based on the session's specifics */ |
242 | etm4_parse_event_config(drvdata, attr); | 240 | ret = etm4_parse_event_config(drvdata, event); |
241 | if (ret) | ||
242 | goto out; | ||
243 | /* And enable it */ | 243 | /* And enable it */ |
244 | etm4_enable_hw(drvdata); | 244 | etm4_enable_hw(drvdata); |
245 | 245 | ||
246 | return 0; | 246 | out: |
247 | return ret; | ||
247 | } | 248 | } |
248 | 249 | ||
249 | static int etm4_enable_sysfs(struct coresight_device *csdev) | 250 | static int etm4_enable_sysfs(struct coresight_device *csdev) |
@@ -274,7 +275,7 @@ err: | |||
274 | } | 275 | } |
275 | 276 | ||
276 | static int etm4_enable(struct coresight_device *csdev, | 277 | static int etm4_enable(struct coresight_device *csdev, |
277 | struct perf_event_attr *attr, u32 mode) | 278 | struct perf_event *event, u32 mode) |
278 | { | 279 | { |
279 | int ret; | 280 | int ret; |
280 | u32 val; | 281 | u32 val; |
@@ -291,7 +292,7 @@ static int etm4_enable(struct coresight_device *csdev, | |||
291 | ret = etm4_enable_sysfs(csdev); | 292 | ret = etm4_enable_sysfs(csdev); |
292 | break; | 293 | break; |
293 | case CS_MODE_PERF: | 294 | case CS_MODE_PERF: |
294 | ret = etm4_enable_perf(csdev, attr); | 295 | ret = etm4_enable_perf(csdev, event); |
295 | break; | 296 | break; |
296 | default: | 297 | default: |
297 | ret = -EINVAL; | 298 | ret = -EINVAL; |
@@ -311,6 +312,11 @@ static void etm4_disable_hw(void *info) | |||
311 | 312 | ||
312 | CS_UNLOCK(drvdata->base); | 313 | CS_UNLOCK(drvdata->base); |
313 | 314 | ||
315 | /* power can be removed from the trace unit now */ | ||
316 | control = readl_relaxed(drvdata->base + TRCPDCR); | ||
317 | control &= ~TRCPDCR_PU; | ||
318 | writel_relaxed(control, drvdata->base + TRCPDCR); | ||
319 | |||
314 | control = readl_relaxed(drvdata->base + TRCPRGCTLR); | 320 | control = readl_relaxed(drvdata->base + TRCPRGCTLR); |
315 | 321 | ||
316 | /* EN, bit[0] Trace unit enable bit */ | 322 | /* EN, bit[0] Trace unit enable bit */ |
@@ -326,14 +332,28 @@ static void etm4_disable_hw(void *info) | |||
326 | dev_dbg(drvdata->dev, "cpu: %d disable smp call done\n", drvdata->cpu); | 332 | dev_dbg(drvdata->dev, "cpu: %d disable smp call done\n", drvdata->cpu); |
327 | } | 333 | } |
328 | 334 | ||
329 | static int etm4_disable_perf(struct coresight_device *csdev) | 335 | static int etm4_disable_perf(struct coresight_device *csdev, |
336 | struct perf_event *event) | ||
330 | { | 337 | { |
338 | u32 control; | ||
339 | struct etm_filters *filters = event->hw.addr_filters; | ||
331 | struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); | 340 | struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); |
332 | 341 | ||
333 | if (WARN_ON_ONCE(drvdata->cpu != smp_processor_id())) | 342 | if (WARN_ON_ONCE(drvdata->cpu != smp_processor_id())) |
334 | return -EINVAL; | 343 | return -EINVAL; |
335 | 344 | ||
336 | etm4_disable_hw(drvdata); | 345 | etm4_disable_hw(drvdata); |
346 | |||
347 | /* | ||
348 | * Check if the start/stop logic was active when the unit was stopped. | ||
349 | * That way we can re-enable the start/stop logic when the process is | ||
350 | * scheduled again. Configuration of the start/stop logic happens in | ||
351 | * function etm4_set_event_filters(). | ||
352 | */ | ||
353 | control = readl_relaxed(drvdata->base + TRCVICTLR); | ||
354 | /* TRCVICTLR::SSSTATUS, bit[9] */ | ||
355 | filters->ssstatus = (control & BIT(9)); | ||
356 | |||
337 | return 0; | 357 | return 0; |
338 | } | 358 | } |
339 | 359 | ||
@@ -362,7 +382,8 @@ static void etm4_disable_sysfs(struct coresight_device *csdev) | |||
362 | dev_info(drvdata->dev, "ETM tracing disabled\n"); | 382 | dev_info(drvdata->dev, "ETM tracing disabled\n"); |
363 | } | 383 | } |
364 | 384 | ||
365 | static void etm4_disable(struct coresight_device *csdev) | 385 | static void etm4_disable(struct coresight_device *csdev, |
386 | struct perf_event *event) | ||
366 | { | 387 | { |
367 | u32 mode; | 388 | u32 mode; |
368 | struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); | 389 | struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); |
@@ -381,7 +402,7 @@ static void etm4_disable(struct coresight_device *csdev) | |||
381 | etm4_disable_sysfs(csdev); | 402 | etm4_disable_sysfs(csdev); |
382 | break; | 403 | break; |
383 | case CS_MODE_PERF: | 404 | case CS_MODE_PERF: |
384 | etm4_disable_perf(csdev); | 405 | etm4_disable_perf(csdev, event); |
385 | break; | 406 | break; |
386 | } | 407 | } |
387 | 408 | ||
@@ -564,21 +585,8 @@ static void etm4_init_arch_data(void *info) | |||
564 | CS_LOCK(drvdata->base); | 585 | CS_LOCK(drvdata->base); |
565 | } | 586 | } |
566 | 587 | ||
567 | static void etm4_set_default(struct etmv4_config *config) | 588 | static void etm4_set_default_config(struct etmv4_config *config) |
568 | { | 589 | { |
569 | if (WARN_ON_ONCE(!config)) | ||
570 | return; | ||
571 | |||
572 | /* | ||
573 | * Make default initialisation trace everything | ||
574 | * | ||
575 | * Select the "always true" resource selector on the | ||
576 | * "Enablign Event" line and configure address range comparator | ||
577 | * '0' to trace all the possible address range. From there | ||
578 | * configure the "include/exclude" engine to include address | ||
579 | * range comparator '0'. | ||
580 | */ | ||
581 | |||
582 | /* disable all events tracing */ | 590 | /* disable all events tracing */ |
583 | config->eventctrl0 = 0x0; | 591 | config->eventctrl0 = 0x0; |
584 | config->eventctrl1 = 0x0; | 592 | config->eventctrl1 = 0x0; |
@@ -594,6 +602,108 @@ static void etm4_set_default(struct etmv4_config *config) | |||
594 | 602 | ||
595 | /* TRCVICTLR::EVENT = 0x01, select the always on logic */ | 603 | /* TRCVICTLR::EVENT = 0x01, select the always on logic */ |
596 | config->vinst_ctrl |= BIT(0); | 604 | config->vinst_ctrl |= BIT(0); |
605 | } | ||
606 | |||
607 | static u64 etm4_get_access_type(struct etmv4_config *config) | ||
608 | { | ||
609 | u64 access_type = 0; | ||
610 | |||
611 | /* | ||
612 | * EXLEVEL_NS, bits[15:12] | ||
613 | * The Exception levels are: | ||
614 | * Bit[12] Exception level 0 - Application | ||
615 | * Bit[13] Exception level 1 - OS | ||
616 | * Bit[14] Exception level 2 - Hypervisor | ||
617 | * Bit[15] Never implemented | ||
618 | * | ||
619 | * Always stay away from hypervisor mode. | ||
620 | */ | ||
621 | access_type = ETM_EXLEVEL_NS_HYP; | ||
622 | |||
623 | if (config->mode & ETM_MODE_EXCL_KERN) | ||
624 | access_type |= ETM_EXLEVEL_NS_OS; | ||
625 | |||
626 | if (config->mode & ETM_MODE_EXCL_USER) | ||
627 | access_type |= ETM_EXLEVEL_NS_APP; | ||
628 | |||
629 | /* | ||
630 | * EXLEVEL_S, bits[11:8], don't trace anything happening | ||
631 | * in secure state. | ||
632 | */ | ||
633 | access_type |= (ETM_EXLEVEL_S_APP | | ||
634 | ETM_EXLEVEL_S_OS | | ||
635 | ETM_EXLEVEL_S_HYP); | ||
636 | |||
637 | return access_type; | ||
638 | } | ||
639 | |||
640 | static void etm4_set_comparator_filter(struct etmv4_config *config, | ||
641 | u64 start, u64 stop, int comparator) | ||
642 | { | ||
643 | u64 access_type = etm4_get_access_type(config); | ||
644 | |||
645 | /* First half of default address comparator */ | ||
646 | config->addr_val[comparator] = start; | ||
647 | config->addr_acc[comparator] = access_type; | ||
648 | config->addr_type[comparator] = ETM_ADDR_TYPE_RANGE; | ||
649 | |||
650 | /* Second half of default address comparator */ | ||
651 | config->addr_val[comparator + 1] = stop; | ||
652 | config->addr_acc[comparator + 1] = access_type; | ||
653 | config->addr_type[comparator + 1] = ETM_ADDR_TYPE_RANGE; | ||
654 | |||
655 | /* | ||
656 | * Configure the ViewInst function to include this address range | ||
657 | * comparator. | ||
658 | * | ||
659 | * @comparator is divided by two since it is the index in the | ||
660 | * etmv4_config::addr_val array but register TRCVIIECTLR deals with | ||
661 | * address range comparator _pairs_. | ||
662 | * | ||
663 | * Therefore: | ||
664 | * index 0 -> compatator pair 0 | ||
665 | * index 2 -> comparator pair 1 | ||
666 | * index 4 -> comparator pair 2 | ||
667 | * ... | ||
668 | * index 14 -> comparator pair 7 | ||
669 | */ | ||
670 | config->viiectlr |= BIT(comparator / 2); | ||
671 | } | ||
672 | |||
673 | static void etm4_set_start_stop_filter(struct etmv4_config *config, | ||
674 | u64 address, int comparator, | ||
675 | enum etm_addr_type type) | ||
676 | { | ||
677 | int shift; | ||
678 | u64 access_type = etm4_get_access_type(config); | ||
679 | |||
680 | /* Configure the comparator */ | ||
681 | config->addr_val[comparator] = address; | ||
682 | config->addr_acc[comparator] = access_type; | ||
683 | config->addr_type[comparator] = type; | ||
684 | |||
685 | /* | ||
686 | * Configure ViewInst Start-Stop control register. | ||
687 | * Addresses configured to start tracing go from bit 0 to n-1, | ||
688 | * while those configured to stop tracing from 16 to 16 + n-1. | ||
689 | */ | ||
690 | shift = (type == ETM_ADDR_TYPE_START ? 0 : 16); | ||
691 | config->vissctlr |= BIT(shift + comparator); | ||
692 | } | ||
693 | |||
694 | static void etm4_set_default_filter(struct etmv4_config *config) | ||
695 | { | ||
696 | u64 start, stop; | ||
697 | |||
698 | /* | ||
699 | * Configure address range comparator '0' to encompass all | ||
700 | * possible addresses. | ||
701 | */ | ||
702 | start = 0x0; | ||
703 | stop = ~0x0; | ||
704 | |||
705 | etm4_set_comparator_filter(config, start, stop, | ||
706 | ETM_DEFAULT_ADDR_COMP); | ||
597 | 707 | ||
598 | /* | 708 | /* |
599 | * TRCVICTLR::SSSTATUS == 1, the start-stop logic is | 709 | * TRCVICTLR::SSSTATUS == 1, the start-stop logic is |
@@ -601,43 +711,156 @@ static void etm4_set_default(struct etmv4_config *config) | |||
601 | */ | 711 | */ |
602 | config->vinst_ctrl |= BIT(9); | 712 | config->vinst_ctrl |= BIT(9); |
603 | 713 | ||
714 | /* No start-stop filtering for ViewInst */ | ||
715 | config->vissctlr = 0x0; | ||
716 | } | ||
717 | |||
718 | static void etm4_set_default(struct etmv4_config *config) | ||
719 | { | ||
720 | if (WARN_ON_ONCE(!config)) | ||
721 | return; | ||
722 | |||
604 | /* | 723 | /* |
605 | * Configure address range comparator '0' to encompass all | 724 | * Make default initialisation trace everything |
606 | * possible addresses. | 725 | * |
726 | * Select the "always true" resource selector on the | ||
727 | * "Enablign Event" line and configure address range comparator | ||
728 | * '0' to trace all the possible address range. From there | ||
729 | * configure the "include/exclude" engine to include address | ||
730 | * range comparator '0'. | ||
607 | */ | 731 | */ |
732 | etm4_set_default_config(config); | ||
733 | etm4_set_default_filter(config); | ||
734 | } | ||
608 | 735 | ||
609 | /* First half of default address comparator: start at address 0 */ | 736 | static int etm4_get_next_comparator(struct etmv4_drvdata *drvdata, u32 type) |
610 | config->addr_val[ETM_DEFAULT_ADDR_COMP] = 0x0; | 737 | { |
611 | /* trace instruction addresses */ | 738 | int nr_comparator, index = 0; |
612 | config->addr_acc[ETM_DEFAULT_ADDR_COMP] &= ~(BIT(0) | BIT(1)); | 739 | struct etmv4_config *config = &drvdata->config; |
613 | /* EXLEVEL_NS, bits[12:15], only trace application and kernel space */ | ||
614 | config->addr_acc[ETM_DEFAULT_ADDR_COMP] |= ETM_EXLEVEL_NS_HYP; | ||
615 | /* EXLEVEL_S, bits[11:8], don't trace anything in secure state */ | ||
616 | config->addr_acc[ETM_DEFAULT_ADDR_COMP] |= (ETM_EXLEVEL_S_APP | | ||
617 | ETM_EXLEVEL_S_OS | | ||
618 | ETM_EXLEVEL_S_HYP); | ||
619 | config->addr_type[ETM_DEFAULT_ADDR_COMP] = ETM_ADDR_TYPE_RANGE; | ||
620 | 740 | ||
621 | /* | 741 | /* |
622 | * Second half of default address comparator: go all | 742 | * nr_addr_cmp holds the number of comparator _pair_, so time 2 |
623 | * the way to the top. | 743 | * for the total number of comparators. |
624 | */ | 744 | */ |
625 | config->addr_val[ETM_DEFAULT_ADDR_COMP + 1] = ~0x0; | 745 | nr_comparator = drvdata->nr_addr_cmp * 2; |
626 | /* trace instruction addresses */ | 746 | |
627 | config->addr_acc[ETM_DEFAULT_ADDR_COMP + 1] &= ~(BIT(0) | BIT(1)); | 747 | /* Go through the tally of comparators looking for a free one. */ |
628 | /* Address comparator type must be equal for both halves */ | 748 | while (index < nr_comparator) { |
629 | config->addr_acc[ETM_DEFAULT_ADDR_COMP + 1] = | 749 | switch (type) { |
630 | config->addr_acc[ETM_DEFAULT_ADDR_COMP]; | 750 | case ETM_ADDR_TYPE_RANGE: |
631 | config->addr_type[ETM_DEFAULT_ADDR_COMP + 1] = ETM_ADDR_TYPE_RANGE; | 751 | if (config->addr_type[index] == ETM_ADDR_TYPE_NONE && |
752 | config->addr_type[index + 1] == ETM_ADDR_TYPE_NONE) | ||
753 | return index; | ||
754 | |||
755 | /* Address range comparators go in pairs */ | ||
756 | index += 2; | ||
757 | break; | ||
758 | case ETM_ADDR_TYPE_START: | ||
759 | case ETM_ADDR_TYPE_STOP: | ||
760 | if (config->addr_type[index] == ETM_ADDR_TYPE_NONE) | ||
761 | return index; | ||
762 | |||
763 | /* Start/stop address can have odd indexes */ | ||
764 | index += 1; | ||
765 | break; | ||
766 | default: | ||
767 | return -EINVAL; | ||
768 | } | ||
769 | } | ||
770 | |||
771 | /* If we are here all the comparators have been used. */ | ||
772 | return -ENOSPC; | ||
773 | } | ||
774 | |||
775 | static int etm4_set_event_filters(struct etmv4_drvdata *drvdata, | ||
776 | struct perf_event *event) | ||
777 | { | ||
778 | int i, comparator, ret = 0; | ||
779 | u64 address; | ||
780 | struct etmv4_config *config = &drvdata->config; | ||
781 | struct etm_filters *filters = event->hw.addr_filters; | ||
782 | |||
783 | if (!filters) | ||
784 | goto default_filter; | ||
785 | |||
786 | /* Sync events with what Perf got */ | ||
787 | perf_event_addr_filters_sync(event); | ||
632 | 788 | ||
633 | /* | 789 | /* |
634 | * Configure the ViewInst function to filter on address range | 790 | * If there are no filters to deal with simply go ahead with |
635 | * comparator '0'. | 791 | * the default filter, i.e the entire address range. |
636 | */ | 792 | */ |
637 | config->viiectlr = BIT(0); | 793 | if (!filters->nr_filters) |
794 | goto default_filter; | ||
795 | |||
796 | for (i = 0; i < filters->nr_filters; i++) { | ||
797 | struct etm_filter *filter = &filters->etm_filter[i]; | ||
798 | enum etm_addr_type type = filter->type; | ||
799 | |||
800 | /* See if a comparator is free. */ | ||
801 | comparator = etm4_get_next_comparator(drvdata, type); | ||
802 | if (comparator < 0) { | ||
803 | ret = comparator; | ||
804 | goto out; | ||
805 | } | ||
806 | |||
807 | switch (type) { | ||
808 | case ETM_ADDR_TYPE_RANGE: | ||
809 | etm4_set_comparator_filter(config, | ||
810 | filter->start_addr, | ||
811 | filter->stop_addr, | ||
812 | comparator); | ||
813 | /* | ||
814 | * TRCVICTLR::SSSTATUS == 1, the start-stop logic is | ||
815 | * in the started state | ||
816 | */ | ||
817 | config->vinst_ctrl |= BIT(9); | ||
818 | |||
819 | /* No start-stop filtering for ViewInst */ | ||
820 | config->vissctlr = 0x0; | ||
821 | break; | ||
822 | case ETM_ADDR_TYPE_START: | ||
823 | case ETM_ADDR_TYPE_STOP: | ||
824 | /* Get the right start or stop address */ | ||
825 | address = (type == ETM_ADDR_TYPE_START ? | ||
826 | filter->start_addr : | ||
827 | filter->stop_addr); | ||
828 | |||
829 | /* Configure comparator */ | ||
830 | etm4_set_start_stop_filter(config, address, | ||
831 | comparator, type); | ||
832 | |||
833 | /* | ||
834 | * If filters::ssstatus == 1, trace acquisition was | ||
835 | * started but the process was yanked away before the | ||
836 | * the stop address was hit. As such the start/stop | ||
837 | * logic needs to be re-started so that tracing can | ||
838 | * resume where it left. | ||
839 | * | ||
840 | * The start/stop logic status when a process is | ||
841 | * scheduled out is checked in function | ||
842 | * etm4_disable_perf(). | ||
843 | */ | ||
844 | if (filters->ssstatus) | ||
845 | config->vinst_ctrl |= BIT(9); | ||
846 | |||
847 | /* No include/exclude filtering for ViewInst */ | ||
848 | config->viiectlr = 0x0; | ||
849 | break; | ||
850 | default: | ||
851 | ret = -EINVAL; | ||
852 | goto out; | ||
853 | } | ||
854 | } | ||
638 | 855 | ||
639 | /* no start-stop filtering for ViewInst */ | 856 | goto out; |
640 | config->vissctlr = 0x0; | 857 | |
858 | |||
859 | default_filter: | ||
860 | etm4_set_default_filter(config); | ||
861 | |||
862 | out: | ||
863 | return ret; | ||
641 | } | 864 | } |
642 | 865 | ||
643 | void etm4_config_trace_mode(struct etmv4_config *config) | 866 | void etm4_config_trace_mode(struct etmv4_config *config) |
@@ -727,13 +950,9 @@ static int etm4_probe(struct amba_device *adev, const struct amba_id *id) | |||
727 | struct coresight_platform_data *pdata = NULL; | 950 | struct coresight_platform_data *pdata = NULL; |
728 | struct etmv4_drvdata *drvdata; | 951 | struct etmv4_drvdata *drvdata; |
729 | struct resource *res = &adev->res; | 952 | struct resource *res = &adev->res; |
730 | struct coresight_desc *desc; | 953 | struct coresight_desc desc = { 0 }; |
731 | struct device_node *np = adev->dev.of_node; | 954 | struct device_node *np = adev->dev.of_node; |
732 | 955 | ||
733 | desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL); | ||
734 | if (!desc) | ||
735 | return -ENOMEM; | ||
736 | |||
737 | drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); | 956 | drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); |
738 | if (!drvdata) | 957 | if (!drvdata) |
739 | return -ENOMEM; | 958 | return -ENOMEM; |
@@ -788,13 +1007,13 @@ static int etm4_probe(struct amba_device *adev, const struct amba_id *id) | |||
788 | etm4_init_trace_id(drvdata); | 1007 | etm4_init_trace_id(drvdata); |
789 | etm4_set_default(&drvdata->config); | 1008 | etm4_set_default(&drvdata->config); |
790 | 1009 | ||
791 | desc->type = CORESIGHT_DEV_TYPE_SOURCE; | 1010 | desc.type = CORESIGHT_DEV_TYPE_SOURCE; |
792 | desc->subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_PROC; | 1011 | desc.subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_PROC; |
793 | desc->ops = &etm4_cs_ops; | 1012 | desc.ops = &etm4_cs_ops; |
794 | desc->pdata = pdata; | 1013 | desc.pdata = pdata; |
795 | desc->dev = dev; | 1014 | desc.dev = dev; |
796 | desc->groups = coresight_etmv4_groups; | 1015 | desc.groups = coresight_etmv4_groups; |
797 | drvdata->csdev = coresight_register(desc); | 1016 | drvdata->csdev = coresight_register(&desc); |
798 | if (IS_ERR(drvdata->csdev)) { | 1017 | if (IS_ERR(drvdata->csdev)) { |
799 | ret = PTR_ERR(drvdata->csdev); | 1018 | ret = PTR_ERR(drvdata->csdev); |
800 | goto err_arch_supported; | 1019 | goto err_arch_supported; |
@@ -826,12 +1045,12 @@ err_arch_supported: | |||
826 | } | 1045 | } |
827 | 1046 | ||
828 | static struct amba_id etm4_ids[] = { | 1047 | static struct amba_id etm4_ids[] = { |
829 | { /* ETM 4.0 - Qualcomm */ | 1048 | { /* ETM 4.0 - Cortex-A53 */ |
830 | .id = 0x0003b95d, | 1049 | .id = 0x000bb95d, |
831 | .mask = 0x0003ffff, | 1050 | .mask = 0x000fffff, |
832 | .data = "ETM 4.0", | 1051 | .data = "ETM 4.0", |
833 | }, | 1052 | }, |
834 | { /* ETM 4.0 - Juno board */ | 1053 | { /* ETM 4.0 - Cortex-A57 */ |
835 | .id = 0x000bb95e, | 1054 | .id = 0x000bb95e, |
836 | .mask = 0x000fffff, | 1055 | .mask = 0x000fffff, |
837 | .data = "ETM 4.0", | 1056 | .data = "ETM 4.0", |
diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h index 5359c5197c1d..ba8d3f86de21 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x.h +++ b/drivers/hwtracing/coresight/coresight-etm4x.h | |||
@@ -183,6 +183,9 @@ | |||
183 | #define TRCSTATR_IDLE_BIT 0 | 183 | #define TRCSTATR_IDLE_BIT 0 |
184 | #define ETM_DEFAULT_ADDR_COMP 0 | 184 | #define ETM_DEFAULT_ADDR_COMP 0 |
185 | 185 | ||
186 | /* PowerDown Control Register bits */ | ||
187 | #define TRCPDCR_PU BIT(3) | ||
188 | |||
186 | /* secure state access levels */ | 189 | /* secure state access levels */ |
187 | #define ETM_EXLEVEL_S_APP BIT(8) | 190 | #define ETM_EXLEVEL_S_APP BIT(8) |
188 | #define ETM_EXLEVEL_S_OS BIT(9) | 191 | #define ETM_EXLEVEL_S_OS BIT(9) |
@@ -407,14 +410,6 @@ enum etm_addr_ctxtype { | |||
407 | ETM_CTX_CTXID_VMID, | 410 | ETM_CTX_CTXID_VMID, |
408 | }; | 411 | }; |
409 | 412 | ||
410 | enum etm_addr_type { | ||
411 | ETM_ADDR_TYPE_NONE, | ||
412 | ETM_ADDR_TYPE_SINGLE, | ||
413 | ETM_ADDR_TYPE_RANGE, | ||
414 | ETM_ADDR_TYPE_START, | ||
415 | ETM_ADDR_TYPE_STOP, | ||
416 | }; | ||
417 | |||
418 | extern const struct attribute_group *coresight_etmv4_groups[]; | 413 | extern const struct attribute_group *coresight_etmv4_groups[]; |
419 | void etm4_config_trace_mode(struct etmv4_config *config); | 414 | void etm4_config_trace_mode(struct etmv4_config *config); |
420 | #endif | 415 | #endif |
diff --git a/drivers/hwtracing/coresight/coresight-funnel.c b/drivers/hwtracing/coresight/coresight-funnel.c index 05df789056cc..860fe6ef5632 100644 --- a/drivers/hwtracing/coresight/coresight-funnel.c +++ b/drivers/hwtracing/coresight/coresight-funnel.c | |||
@@ -176,7 +176,7 @@ static int funnel_probe(struct amba_device *adev, const struct amba_id *id) | |||
176 | struct coresight_platform_data *pdata = NULL; | 176 | struct coresight_platform_data *pdata = NULL; |
177 | struct funnel_drvdata *drvdata; | 177 | struct funnel_drvdata *drvdata; |
178 | struct resource *res = &adev->res; | 178 | struct resource *res = &adev->res; |
179 | struct coresight_desc *desc; | 179 | struct coresight_desc desc = { 0 }; |
180 | struct device_node *np = adev->dev.of_node; | 180 | struct device_node *np = adev->dev.of_node; |
181 | 181 | ||
182 | if (np) { | 182 | if (np) { |
@@ -207,17 +207,13 @@ static int funnel_probe(struct amba_device *adev, const struct amba_id *id) | |||
207 | drvdata->base = base; | 207 | drvdata->base = base; |
208 | pm_runtime_put(&adev->dev); | 208 | pm_runtime_put(&adev->dev); |
209 | 209 | ||
210 | desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL); | 210 | desc.type = CORESIGHT_DEV_TYPE_LINK; |
211 | if (!desc) | 211 | desc.subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_MERG; |
212 | return -ENOMEM; | 212 | desc.ops = &funnel_cs_ops; |
213 | 213 | desc.pdata = pdata; | |
214 | desc->type = CORESIGHT_DEV_TYPE_LINK; | 214 | desc.dev = dev; |
215 | desc->subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_MERG; | 215 | desc.groups = coresight_funnel_groups; |
216 | desc->ops = &funnel_cs_ops; | 216 | drvdata->csdev = coresight_register(&desc); |
217 | desc->pdata = pdata; | ||
218 | desc->dev = dev; | ||
219 | desc->groups = coresight_funnel_groups; | ||
220 | drvdata->csdev = coresight_register(desc); | ||
221 | if (IS_ERR(drvdata->csdev)) | 217 | if (IS_ERR(drvdata->csdev)) |
222 | return PTR_ERR(drvdata->csdev); | 218 | return PTR_ERR(drvdata->csdev); |
223 | 219 | ||
diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h index ad975c58080d..196a14be4b3d 100644 --- a/drivers/hwtracing/coresight/coresight-priv.h +++ b/drivers/hwtracing/coresight/coresight-priv.h | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/bitops.h> | 16 | #include <linux/bitops.h> |
17 | #include <linux/io.h> | 17 | #include <linux/io.h> |
18 | #include <linux/coresight.h> | 18 | #include <linux/coresight.h> |
19 | #include <linux/pm_runtime.h> | ||
19 | 20 | ||
20 | /* | 21 | /* |
21 | * Coresight management registers (0xf00-0xfcc) | 22 | * Coresight management registers (0xf00-0xfcc) |
@@ -37,16 +38,32 @@ | |||
37 | #define ETM_MODE_EXCL_KERN BIT(30) | 38 | #define ETM_MODE_EXCL_KERN BIT(30) |
38 | #define ETM_MODE_EXCL_USER BIT(31) | 39 | #define ETM_MODE_EXCL_USER BIT(31) |
39 | 40 | ||
40 | #define coresight_simple_func(type, name, offset) \ | 41 | typedef u32 (*coresight_read_fn)(const struct device *, u32 offset); |
42 | #define coresight_simple_func(type, func, name, offset) \ | ||
41 | static ssize_t name##_show(struct device *_dev, \ | 43 | static ssize_t name##_show(struct device *_dev, \ |
42 | struct device_attribute *attr, char *buf) \ | 44 | struct device_attribute *attr, char *buf) \ |
43 | { \ | 45 | { \ |
44 | type *drvdata = dev_get_drvdata(_dev->parent); \ | 46 | type *drvdata = dev_get_drvdata(_dev->parent); \ |
45 | return scnprintf(buf, PAGE_SIZE, "0x%x\n", \ | 47 | coresight_read_fn fn = func; \ |
46 | readl_relaxed(drvdata->base + offset)); \ | 48 | u32 val; \ |
49 | pm_runtime_get_sync(_dev->parent); \ | ||
50 | if (fn) \ | ||
51 | val = fn(_dev->parent, offset); \ | ||
52 | else \ | ||
53 | val = readl_relaxed(drvdata->base + offset); \ | ||
54 | pm_runtime_put_sync(_dev->parent); \ | ||
55 | return scnprintf(buf, PAGE_SIZE, "0x%x\n", val); \ | ||
47 | } \ | 56 | } \ |
48 | static DEVICE_ATTR_RO(name) | 57 | static DEVICE_ATTR_RO(name) |
49 | 58 | ||
59 | enum etm_addr_type { | ||
60 | ETM_ADDR_TYPE_NONE, | ||
61 | ETM_ADDR_TYPE_SINGLE, | ||
62 | ETM_ADDR_TYPE_RANGE, | ||
63 | ETM_ADDR_TYPE_START, | ||
64 | ETM_ADDR_TYPE_STOP, | ||
65 | }; | ||
66 | |||
50 | enum cs_mode { | 67 | enum cs_mode { |
51 | CS_MODE_DISABLED, | 68 | CS_MODE_DISABLED, |
52 | CS_MODE_SYSFS, | 69 | CS_MODE_SYSFS, |
diff --git a/drivers/hwtracing/coresight/coresight-replicator-qcom.c b/drivers/hwtracing/coresight/coresight-replicator-qcom.c index 700f710e4bfa..0a3d15f0b009 100644 --- a/drivers/hwtracing/coresight/coresight-replicator-qcom.c +++ b/drivers/hwtracing/coresight/coresight-replicator-qcom.c | |||
@@ -102,7 +102,7 @@ static int replicator_probe(struct amba_device *adev, const struct amba_id *id) | |||
102 | struct resource *res = &adev->res; | 102 | struct resource *res = &adev->res; |
103 | struct coresight_platform_data *pdata = NULL; | 103 | struct coresight_platform_data *pdata = NULL; |
104 | struct replicator_state *drvdata; | 104 | struct replicator_state *drvdata; |
105 | struct coresight_desc *desc; | 105 | struct coresight_desc desc = { 0 }; |
106 | struct device_node *np = adev->dev.of_node; | 106 | struct device_node *np = adev->dev.of_node; |
107 | void __iomem *base; | 107 | void __iomem *base; |
108 | 108 | ||
@@ -134,16 +134,12 @@ static int replicator_probe(struct amba_device *adev, const struct amba_id *id) | |||
134 | dev_set_drvdata(dev, drvdata); | 134 | dev_set_drvdata(dev, drvdata); |
135 | pm_runtime_put(&adev->dev); | 135 | pm_runtime_put(&adev->dev); |
136 | 136 | ||
137 | desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL); | 137 | desc.type = CORESIGHT_DEV_TYPE_LINK; |
138 | if (!desc) | 138 | desc.subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_SPLIT; |
139 | return -ENOMEM; | 139 | desc.ops = &replicator_cs_ops; |
140 | 140 | desc.pdata = adev->dev.platform_data; | |
141 | desc->type = CORESIGHT_DEV_TYPE_LINK; | 141 | desc.dev = &adev->dev; |
142 | desc->subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_SPLIT; | 142 | drvdata->csdev = coresight_register(&desc); |
143 | desc->ops = &replicator_cs_ops; | ||
144 | desc->pdata = adev->dev.platform_data; | ||
145 | desc->dev = &adev->dev; | ||
146 | drvdata->csdev = coresight_register(desc); | ||
147 | if (IS_ERR(drvdata->csdev)) | 143 | if (IS_ERR(drvdata->csdev)) |
148 | return PTR_ERR(drvdata->csdev); | 144 | return PTR_ERR(drvdata->csdev); |
149 | 145 | ||
diff --git a/drivers/hwtracing/coresight/coresight-replicator.c b/drivers/hwtracing/coresight/coresight-replicator.c index c6982e312e15..3756e71cb8f5 100644 --- a/drivers/hwtracing/coresight/coresight-replicator.c +++ b/drivers/hwtracing/coresight/coresight-replicator.c | |||
@@ -69,7 +69,7 @@ static int replicator_probe(struct platform_device *pdev) | |||
69 | struct device *dev = &pdev->dev; | 69 | struct device *dev = &pdev->dev; |
70 | struct coresight_platform_data *pdata = NULL; | 70 | struct coresight_platform_data *pdata = NULL; |
71 | struct replicator_drvdata *drvdata; | 71 | struct replicator_drvdata *drvdata; |
72 | struct coresight_desc *desc; | 72 | struct coresight_desc desc = { 0 }; |
73 | struct device_node *np = pdev->dev.of_node; | 73 | struct device_node *np = pdev->dev.of_node; |
74 | 74 | ||
75 | if (np) { | 75 | if (np) { |
@@ -95,18 +95,12 @@ static int replicator_probe(struct platform_device *pdev) | |||
95 | pm_runtime_enable(&pdev->dev); | 95 | pm_runtime_enable(&pdev->dev); |
96 | platform_set_drvdata(pdev, drvdata); | 96 | platform_set_drvdata(pdev, drvdata); |
97 | 97 | ||
98 | desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL); | 98 | desc.type = CORESIGHT_DEV_TYPE_LINK; |
99 | if (!desc) { | 99 | desc.subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_SPLIT; |
100 | ret = -ENOMEM; | 100 | desc.ops = &replicator_cs_ops; |
101 | goto out_disable_pm; | 101 | desc.pdata = pdev->dev.platform_data; |
102 | } | 102 | desc.dev = &pdev->dev; |
103 | 103 | drvdata->csdev = coresight_register(&desc); | |
104 | desc->type = CORESIGHT_DEV_TYPE_LINK; | ||
105 | desc->subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_SPLIT; | ||
106 | desc->ops = &replicator_cs_ops; | ||
107 | desc->pdata = pdev->dev.platform_data; | ||
108 | desc->dev = &pdev->dev; | ||
109 | drvdata->csdev = coresight_register(desc); | ||
110 | if (IS_ERR(drvdata->csdev)) { | 104 | if (IS_ERR(drvdata->csdev)) { |
111 | ret = PTR_ERR(drvdata->csdev); | 105 | ret = PTR_ERR(drvdata->csdev); |
112 | goto out_disable_pm; | 106 | goto out_disable_pm; |
diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/hwtracing/coresight/coresight-stm.c index 73be58a11e4f..49e0f1b925a5 100644 --- a/drivers/hwtracing/coresight/coresight-stm.c +++ b/drivers/hwtracing/coresight/coresight-stm.c | |||
@@ -105,10 +105,12 @@ module_param_named( | |||
105 | /** | 105 | /** |
106 | * struct channel_space - central management entity for extended ports | 106 | * struct channel_space - central management entity for extended ports |
107 | * @base: memory mapped base address where channels start. | 107 | * @base: memory mapped base address where channels start. |
108 | * @phys: physical base address of channel region. | ||
108 | * @guaraneed: is the channel delivery guaranteed. | 109 | * @guaraneed: is the channel delivery guaranteed. |
109 | */ | 110 | */ |
110 | struct channel_space { | 111 | struct channel_space { |
111 | void __iomem *base; | 112 | void __iomem *base; |
113 | phys_addr_t phys; | ||
112 | unsigned long *guaranteed; | 114 | unsigned long *guaranteed; |
113 | }; | 115 | }; |
114 | 116 | ||
@@ -196,7 +198,7 @@ static void stm_enable_hw(struct stm_drvdata *drvdata) | |||
196 | } | 198 | } |
197 | 199 | ||
198 | static int stm_enable(struct coresight_device *csdev, | 200 | static int stm_enable(struct coresight_device *csdev, |
199 | struct perf_event_attr *attr, u32 mode) | 201 | struct perf_event *event, u32 mode) |
200 | { | 202 | { |
201 | u32 val; | 203 | u32 val; |
202 | struct stm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); | 204 | struct stm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); |
@@ -258,7 +260,8 @@ static void stm_disable_hw(struct stm_drvdata *drvdata) | |||
258 | stm_hwevent_disable_hw(drvdata); | 260 | stm_hwevent_disable_hw(drvdata); |
259 | } | 261 | } |
260 | 262 | ||
261 | static void stm_disable(struct coresight_device *csdev) | 263 | static void stm_disable(struct coresight_device *csdev, |
264 | struct perf_event *event) | ||
262 | { | 265 | { |
263 | struct stm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); | 266 | struct stm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); |
264 | 267 | ||
@@ -353,7 +356,24 @@ static void stm_generic_unlink(struct stm_data *stm_data, | |||
353 | if (!drvdata || !drvdata->csdev) | 356 | if (!drvdata || !drvdata->csdev) |
354 | return; | 357 | return; |
355 | 358 | ||
356 | stm_disable(drvdata->csdev); | 359 | stm_disable(drvdata->csdev, NULL); |
360 | } | ||
361 | |||
362 | static phys_addr_t | ||
363 | stm_mmio_addr(struct stm_data *stm_data, unsigned int master, | ||
364 | unsigned int channel, unsigned int nr_chans) | ||
365 | { | ||
366 | struct stm_drvdata *drvdata = container_of(stm_data, | ||
367 | struct stm_drvdata, stm); | ||
368 | phys_addr_t addr; | ||
369 | |||
370 | addr = drvdata->chs.phys + channel * BYTES_PER_CHANNEL; | ||
371 | |||
372 | if (offset_in_page(addr) || | ||
373 | offset_in_page(nr_chans * BYTES_PER_CHANNEL)) | ||
374 | return 0; | ||
375 | |||
376 | return addr; | ||
357 | } | 377 | } |
358 | 378 | ||
359 | static long stm_generic_set_options(struct stm_data *stm_data, | 379 | static long stm_generic_set_options(struct stm_data *stm_data, |
@@ -616,7 +636,7 @@ static ssize_t traceid_store(struct device *dev, | |||
616 | static DEVICE_ATTR_RW(traceid); | 636 | static DEVICE_ATTR_RW(traceid); |
617 | 637 | ||
618 | #define coresight_stm_simple_func(name, offset) \ | 638 | #define coresight_stm_simple_func(name, offset) \ |
619 | coresight_simple_func(struct stm_drvdata, name, offset) | 639 | coresight_simple_func(struct stm_drvdata, NULL, name, offset) |
620 | 640 | ||
621 | coresight_stm_simple_func(tcsr, STMTCSR); | 641 | coresight_stm_simple_func(tcsr, STMTCSR); |
622 | coresight_stm_simple_func(tsfreqr, STMTSFREQR); | 642 | coresight_stm_simple_func(tsfreqr, STMTSFREQR); |
@@ -761,7 +781,9 @@ static void stm_init_generic_data(struct stm_drvdata *drvdata) | |||
761 | drvdata->stm.sw_end = 1; | 781 | drvdata->stm.sw_end = 1; |
762 | drvdata->stm.hw_override = true; | 782 | drvdata->stm.hw_override = true; |
763 | drvdata->stm.sw_nchannels = drvdata->numsp; | 783 | drvdata->stm.sw_nchannels = drvdata->numsp; |
784 | drvdata->stm.sw_mmiosz = BYTES_PER_CHANNEL; | ||
764 | drvdata->stm.packet = stm_generic_packet; | 785 | drvdata->stm.packet = stm_generic_packet; |
786 | drvdata->stm.mmio_addr = stm_mmio_addr; | ||
765 | drvdata->stm.link = stm_generic_link; | 787 | drvdata->stm.link = stm_generic_link; |
766 | drvdata->stm.unlink = stm_generic_unlink; | 788 | drvdata->stm.unlink = stm_generic_unlink; |
767 | drvdata->stm.set_options = stm_generic_set_options; | 789 | drvdata->stm.set_options = stm_generic_set_options; |
@@ -778,7 +800,7 @@ static int stm_probe(struct amba_device *adev, const struct amba_id *id) | |||
778 | struct resource *res = &adev->res; | 800 | struct resource *res = &adev->res; |
779 | struct resource ch_res; | 801 | struct resource ch_res; |
780 | size_t res_size, bitmap_size; | 802 | size_t res_size, bitmap_size; |
781 | struct coresight_desc *desc; | 803 | struct coresight_desc desc = { 0 }; |
782 | struct device_node *np = adev->dev.of_node; | 804 | struct device_node *np = adev->dev.of_node; |
783 | 805 | ||
784 | if (np) { | 806 | if (np) { |
@@ -808,6 +830,7 @@ static int stm_probe(struct amba_device *adev, const struct amba_id *id) | |||
808 | ret = stm_get_resource_byname(np, "stm-stimulus-base", &ch_res); | 830 | ret = stm_get_resource_byname(np, "stm-stimulus-base", &ch_res); |
809 | if (ret) | 831 | if (ret) |
810 | return ret; | 832 | return ret; |
833 | drvdata->chs.phys = ch_res.start; | ||
811 | 834 | ||
812 | base = devm_ioremap_resource(dev, &ch_res); | 835 | base = devm_ioremap_resource(dev, &ch_res); |
813 | if (IS_ERR(base)) | 836 | if (IS_ERR(base)) |
@@ -843,19 +866,13 @@ static int stm_probe(struct amba_device *adev, const struct amba_id *id) | |||
843 | return -EPROBE_DEFER; | 866 | return -EPROBE_DEFER; |
844 | } | 867 | } |
845 | 868 | ||
846 | desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL); | 869 | desc.type = CORESIGHT_DEV_TYPE_SOURCE; |
847 | if (!desc) { | 870 | desc.subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE; |
848 | ret = -ENOMEM; | 871 | desc.ops = &stm_cs_ops; |
849 | goto stm_unregister; | 872 | desc.pdata = pdata; |
850 | } | 873 | desc.dev = dev; |
851 | 874 | desc.groups = coresight_stm_groups; | |
852 | desc->type = CORESIGHT_DEV_TYPE_SOURCE; | 875 | drvdata->csdev = coresight_register(&desc); |
853 | desc->subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE; | ||
854 | desc->ops = &stm_cs_ops; | ||
855 | desc->pdata = pdata; | ||
856 | desc->dev = dev; | ||
857 | desc->groups = coresight_stm_groups; | ||
858 | drvdata->csdev = coresight_register(desc); | ||
859 | if (IS_ERR(drvdata->csdev)) { | 876 | if (IS_ERR(drvdata->csdev)) { |
860 | ret = PTR_ERR(drvdata->csdev); | 877 | ret = PTR_ERR(drvdata->csdev); |
861 | goto stm_unregister; | 878 | goto stm_unregister; |
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c index 466af86fd76f..d6941ea24d8d 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etf.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c | |||
@@ -22,7 +22,7 @@ | |||
22 | #include "coresight-priv.h" | 22 | #include "coresight-priv.h" |
23 | #include "coresight-tmc.h" | 23 | #include "coresight-tmc.h" |
24 | 24 | ||
25 | void tmc_etb_enable_hw(struct tmc_drvdata *drvdata) | 25 | static void tmc_etb_enable_hw(struct tmc_drvdata *drvdata) |
26 | { | 26 | { |
27 | CS_UNLOCK(drvdata->base); | 27 | CS_UNLOCK(drvdata->base); |
28 | 28 | ||
@@ -48,6 +48,7 @@ static void tmc_etb_dump_hw(struct tmc_drvdata *drvdata) | |||
48 | int i; | 48 | int i; |
49 | 49 | ||
50 | bufp = drvdata->buf; | 50 | bufp = drvdata->buf; |
51 | drvdata->len = 0; | ||
51 | while (1) { | 52 | while (1) { |
52 | for (i = 0; i < drvdata->memwidth; i++) { | 53 | for (i = 0; i < drvdata->memwidth; i++) { |
53 | read_data = readl_relaxed(drvdata->base + TMC_RRD); | 54 | read_data = readl_relaxed(drvdata->base + TMC_RRD); |
@@ -55,6 +56,7 @@ static void tmc_etb_dump_hw(struct tmc_drvdata *drvdata) | |||
55 | return; | 56 | return; |
56 | memcpy(bufp, &read_data, 4); | 57 | memcpy(bufp, &read_data, 4); |
57 | bufp += 4; | 58 | bufp += 4; |
59 | drvdata->len += 4; | ||
58 | } | 60 | } |
59 | } | 61 | } |
60 | } | 62 | } |
@@ -166,7 +168,7 @@ out: | |||
166 | spin_unlock_irqrestore(&drvdata->spinlock, flags); | 168 | spin_unlock_irqrestore(&drvdata->spinlock, flags); |
167 | 169 | ||
168 | /* Free memory outside the spinlock if need be */ | 170 | /* Free memory outside the spinlock if need be */ |
169 | if (!used && buf) | 171 | if (!used) |
170 | kfree(buf); | 172 | kfree(buf); |
171 | 173 | ||
172 | if (!ret) | 174 | if (!ret) |
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c index 688be9e060fc..886ea83c68e0 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c | |||
@@ -20,7 +20,7 @@ | |||
20 | #include "coresight-priv.h" | 20 | #include "coresight-priv.h" |
21 | #include "coresight-tmc.h" | 21 | #include "coresight-tmc.h" |
22 | 22 | ||
23 | void tmc_etr_enable_hw(struct tmc_drvdata *drvdata) | 23 | static void tmc_etr_enable_hw(struct tmc_drvdata *drvdata) |
24 | { | 24 | { |
25 | u32 axictl; | 25 | u32 axictl; |
26 | 26 | ||
@@ -64,11 +64,17 @@ static void tmc_etr_dump_hw(struct tmc_drvdata *drvdata) | |||
64 | rwp = readl_relaxed(drvdata->base + TMC_RWP); | 64 | rwp = readl_relaxed(drvdata->base + TMC_RWP); |
65 | val = readl_relaxed(drvdata->base + TMC_STS); | 65 | val = readl_relaxed(drvdata->base + TMC_STS); |
66 | 66 | ||
67 | /* How much memory do we still have */ | 67 | /* |
68 | if (val & BIT(0)) | 68 | * Adjust the buffer to point to the beginning of the trace data |
69 | * and update the available trace data. | ||
70 | */ | ||
71 | if (val & TMC_STS_FULL) { | ||
69 | drvdata->buf = drvdata->vaddr + rwp - drvdata->paddr; | 72 | drvdata->buf = drvdata->vaddr + rwp - drvdata->paddr; |
70 | else | 73 | drvdata->len = drvdata->size; |
74 | } else { | ||
71 | drvdata->buf = drvdata->vaddr; | 75 | drvdata->buf = drvdata->vaddr; |
76 | drvdata->len = rwp - drvdata->paddr; | ||
77 | } | ||
72 | } | 78 | } |
73 | 79 | ||
74 | static void tmc_etr_disable_hw(struct tmc_drvdata *drvdata) | 80 | static void tmc_etr_disable_hw(struct tmc_drvdata *drvdata) |
diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c index 9e02ac963cd0..d8517d2a968c 100644 --- a/drivers/hwtracing/coresight/coresight-tmc.c +++ b/drivers/hwtracing/coresight/coresight-tmc.c | |||
@@ -38,8 +38,7 @@ void tmc_wait_for_tmcready(struct tmc_drvdata *drvdata) | |||
38 | if (coresight_timeout(drvdata->base, | 38 | if (coresight_timeout(drvdata->base, |
39 | TMC_STS, TMC_STS_TMCREADY_BIT, 1)) { | 39 | TMC_STS, TMC_STS_TMCREADY_BIT, 1)) { |
40 | dev_err(drvdata->dev, | 40 | dev_err(drvdata->dev, |
41 | "timeout observed when probing at offset %#x\n", | 41 | "timeout while waiting for TMC to be Ready\n"); |
42 | TMC_STS); | ||
43 | } | 42 | } |
44 | } | 43 | } |
45 | 44 | ||
@@ -56,8 +55,7 @@ void tmc_flush_and_stop(struct tmc_drvdata *drvdata) | |||
56 | if (coresight_timeout(drvdata->base, | 55 | if (coresight_timeout(drvdata->base, |
57 | TMC_FFCR, TMC_FFCR_FLUSHMAN_BIT, 0)) { | 56 | TMC_FFCR, TMC_FFCR_FLUSHMAN_BIT, 0)) { |
58 | dev_err(drvdata->dev, | 57 | dev_err(drvdata->dev, |
59 | "timeout observed when probing at offset %#x\n", | 58 | "timeout while waiting for completion of Manual Flush\n"); |
60 | TMC_FFCR); | ||
61 | } | 59 | } |
62 | 60 | ||
63 | tmc_wait_for_tmcready(drvdata); | 61 | tmc_wait_for_tmcready(drvdata); |
@@ -140,8 +138,8 @@ static ssize_t tmc_read(struct file *file, char __user *data, size_t len, | |||
140 | struct tmc_drvdata, miscdev); | 138 | struct tmc_drvdata, miscdev); |
141 | char *bufp = drvdata->buf + *ppos; | 139 | char *bufp = drvdata->buf + *ppos; |
142 | 140 | ||
143 | if (*ppos + len > drvdata->size) | 141 | if (*ppos + len > drvdata->len) |
144 | len = drvdata->size - *ppos; | 142 | len = drvdata->len - *ppos; |
145 | 143 | ||
146 | if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) { | 144 | if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) { |
147 | if (bufp == (char *)(drvdata->vaddr + drvdata->size)) | 145 | if (bufp == (char *)(drvdata->vaddr + drvdata->size)) |
@@ -160,7 +158,7 @@ static ssize_t tmc_read(struct file *file, char __user *data, size_t len, | |||
160 | *ppos += len; | 158 | *ppos += len; |
161 | 159 | ||
162 | dev_dbg(drvdata->dev, "%s: %zu bytes copied, %d bytes left\n", | 160 | dev_dbg(drvdata->dev, "%s: %zu bytes copied, %d bytes left\n", |
163 | __func__, len, (int)(drvdata->size - *ppos)); | 161 | __func__, len, (int)(drvdata->len - *ppos)); |
164 | return len; | 162 | return len; |
165 | } | 163 | } |
166 | 164 | ||
@@ -220,7 +218,7 @@ static enum tmc_mem_intf_width tmc_get_memwidth(u32 devid) | |||
220 | } | 218 | } |
221 | 219 | ||
222 | #define coresight_tmc_simple_func(name, offset) \ | 220 | #define coresight_tmc_simple_func(name, offset) \ |
223 | coresight_simple_func(struct tmc_drvdata, name, offset) | 221 | coresight_simple_func(struct tmc_drvdata, NULL, name, offset) |
224 | 222 | ||
225 | coresight_tmc_simple_func(rsz, TMC_RSZ); | 223 | coresight_tmc_simple_func(rsz, TMC_RSZ); |
226 | coresight_tmc_simple_func(sts, TMC_STS); | 224 | coresight_tmc_simple_func(sts, TMC_STS); |
@@ -249,8 +247,8 @@ static struct attribute *coresight_tmc_mgmt_attrs[] = { | |||
249 | NULL, | 247 | NULL, |
250 | }; | 248 | }; |
251 | 249 | ||
252 | ssize_t trigger_cntr_show(struct device *dev, | 250 | static ssize_t trigger_cntr_show(struct device *dev, |
253 | struct device_attribute *attr, char *buf) | 251 | struct device_attribute *attr, char *buf) |
254 | { | 252 | { |
255 | struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent); | 253 | struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent); |
256 | unsigned long val = drvdata->trigger_cntr; | 254 | unsigned long val = drvdata->trigger_cntr; |
@@ -304,27 +302,32 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id) | |||
304 | struct coresight_platform_data *pdata = NULL; | 302 | struct coresight_platform_data *pdata = NULL; |
305 | struct tmc_drvdata *drvdata; | 303 | struct tmc_drvdata *drvdata; |
306 | struct resource *res = &adev->res; | 304 | struct resource *res = &adev->res; |
307 | struct coresight_desc *desc; | 305 | struct coresight_desc desc = { 0 }; |
308 | struct device_node *np = adev->dev.of_node; | 306 | struct device_node *np = adev->dev.of_node; |
309 | 307 | ||
310 | if (np) { | 308 | if (np) { |
311 | pdata = of_get_coresight_platform_data(dev, np); | 309 | pdata = of_get_coresight_platform_data(dev, np); |
312 | if (IS_ERR(pdata)) | 310 | if (IS_ERR(pdata)) { |
313 | return PTR_ERR(pdata); | 311 | ret = PTR_ERR(pdata); |
312 | goto out; | ||
313 | } | ||
314 | adev->dev.platform_data = pdata; | 314 | adev->dev.platform_data = pdata; |
315 | } | 315 | } |
316 | 316 | ||
317 | ret = -ENOMEM; | ||
317 | drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); | 318 | drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); |
318 | if (!drvdata) | 319 | if (!drvdata) |
319 | return -ENOMEM; | 320 | goto out; |
320 | 321 | ||
321 | drvdata->dev = &adev->dev; | 322 | drvdata->dev = &adev->dev; |
322 | dev_set_drvdata(dev, drvdata); | 323 | dev_set_drvdata(dev, drvdata); |
323 | 324 | ||
324 | /* Validity for the resource is already checked by the AMBA core */ | 325 | /* Validity for the resource is already checked by the AMBA core */ |
325 | base = devm_ioremap_resource(dev, res); | 326 | base = devm_ioremap_resource(dev, res); |
326 | if (IS_ERR(base)) | 327 | if (IS_ERR(base)) { |
327 | return PTR_ERR(base); | 328 | ret = PTR_ERR(base); |
329 | goto out; | ||
330 | } | ||
328 | 331 | ||
329 | drvdata->base = base; | 332 | drvdata->base = base; |
330 | 333 | ||
@@ -347,33 +350,28 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id) | |||
347 | 350 | ||
348 | pm_runtime_put(&adev->dev); | 351 | pm_runtime_put(&adev->dev); |
349 | 352 | ||
350 | desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL); | 353 | desc.pdata = pdata; |
351 | if (!desc) { | 354 | desc.dev = dev; |
352 | ret = -ENOMEM; | 355 | desc.groups = coresight_tmc_groups; |
353 | goto err_devm_kzalloc; | ||
354 | } | ||
355 | |||
356 | desc->pdata = pdata; | ||
357 | desc->dev = dev; | ||
358 | desc->subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER; | ||
359 | desc->groups = coresight_tmc_groups; | ||
360 | 356 | ||
361 | if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) { | 357 | if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) { |
362 | desc->type = CORESIGHT_DEV_TYPE_SINK; | 358 | desc.type = CORESIGHT_DEV_TYPE_SINK; |
363 | desc->ops = &tmc_etb_cs_ops; | 359 | desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER; |
360 | desc.ops = &tmc_etb_cs_ops; | ||
364 | } else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) { | 361 | } else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) { |
365 | desc->type = CORESIGHT_DEV_TYPE_SINK; | 362 | desc.type = CORESIGHT_DEV_TYPE_SINK; |
366 | desc->ops = &tmc_etr_cs_ops; | 363 | desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER; |
364 | desc.ops = &tmc_etr_cs_ops; | ||
367 | } else { | 365 | } else { |
368 | desc->type = CORESIGHT_DEV_TYPE_LINKSINK; | 366 | desc.type = CORESIGHT_DEV_TYPE_LINKSINK; |
369 | desc->subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_FIFO; | 367 | desc.subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_FIFO; |
370 | desc->ops = &tmc_etf_cs_ops; | 368 | desc.ops = &tmc_etf_cs_ops; |
371 | } | 369 | } |
372 | 370 | ||
373 | drvdata->csdev = coresight_register(desc); | 371 | drvdata->csdev = coresight_register(&desc); |
374 | if (IS_ERR(drvdata->csdev)) { | 372 | if (IS_ERR(drvdata->csdev)) { |
375 | ret = PTR_ERR(drvdata->csdev); | 373 | ret = PTR_ERR(drvdata->csdev); |
376 | goto err_devm_kzalloc; | 374 | goto out; |
377 | } | 375 | } |
378 | 376 | ||
379 | drvdata->miscdev.name = pdata->name; | 377 | drvdata->miscdev.name = pdata->name; |
@@ -381,16 +379,8 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id) | |||
381 | drvdata->miscdev.fops = &tmc_fops; | 379 | drvdata->miscdev.fops = &tmc_fops; |
382 | ret = misc_register(&drvdata->miscdev); | 380 | ret = misc_register(&drvdata->miscdev); |
383 | if (ret) | 381 | if (ret) |
384 | goto err_misc_register; | 382 | coresight_unregister(drvdata->csdev); |
385 | 383 | out: | |
386 | return 0; | ||
387 | |||
388 | err_misc_register: | ||
389 | coresight_unregister(drvdata->csdev); | ||
390 | err_devm_kzalloc: | ||
391 | if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) | ||
392 | dma_free_coherent(dev, drvdata->size, | ||
393 | drvdata->vaddr, drvdata->paddr); | ||
394 | return ret; | 384 | return ret; |
395 | } | 385 | } |
396 | 386 | ||
diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h index 5c5fe2ad2ca7..44b3ae346118 100644 --- a/drivers/hwtracing/coresight/coresight-tmc.h +++ b/drivers/hwtracing/coresight/coresight-tmc.h | |||
@@ -98,7 +98,8 @@ enum tmc_mem_intf_width { | |||
98 | * @buf: area of memory where trace data get sent. | 98 | * @buf: area of memory where trace data get sent. |
99 | * @paddr: DMA start location in RAM. | 99 | * @paddr: DMA start location in RAM. |
100 | * @vaddr: virtual representation of @paddr. | 100 | * @vaddr: virtual representation of @paddr. |
101 | * @size: @buf size. | 101 | * @size: trace buffer size. |
102 | * @len: size of the available trace. | ||
102 | * @mode: how this TMC is being used. | 103 | * @mode: how this TMC is being used. |
103 | * @config_type: TMC variant, must be of type @tmc_config_type. | 104 | * @config_type: TMC variant, must be of type @tmc_config_type. |
104 | * @memwidth: width of the memory interface databus, in bytes. | 105 | * @memwidth: width of the memory interface databus, in bytes. |
@@ -115,6 +116,7 @@ struct tmc_drvdata { | |||
115 | dma_addr_t paddr; | 116 | dma_addr_t paddr; |
116 | void __iomem *vaddr; | 117 | void __iomem *vaddr; |
117 | u32 size; | 118 | u32 size; |
119 | u32 len; | ||
118 | local_t mode; | 120 | local_t mode; |
119 | enum tmc_config_type config_type; | 121 | enum tmc_config_type config_type; |
120 | enum tmc_mem_intf_width memwidth; | 122 | enum tmc_mem_intf_width memwidth; |
diff --git a/drivers/hwtracing/coresight/coresight-tpiu.c b/drivers/hwtracing/coresight/coresight-tpiu.c index 4e471e2e9d89..0673baf0f2f5 100644 --- a/drivers/hwtracing/coresight/coresight-tpiu.c +++ b/drivers/hwtracing/coresight/coresight-tpiu.c | |||
@@ -119,7 +119,7 @@ static int tpiu_probe(struct amba_device *adev, const struct amba_id *id) | |||
119 | struct coresight_platform_data *pdata = NULL; | 119 | struct coresight_platform_data *pdata = NULL; |
120 | struct tpiu_drvdata *drvdata; | 120 | struct tpiu_drvdata *drvdata; |
121 | struct resource *res = &adev->res; | 121 | struct resource *res = &adev->res; |
122 | struct coresight_desc *desc; | 122 | struct coresight_desc desc = { 0 }; |
123 | struct device_node *np = adev->dev.of_node; | 123 | struct device_node *np = adev->dev.of_node; |
124 | 124 | ||
125 | if (np) { | 125 | if (np) { |
@@ -154,16 +154,12 @@ static int tpiu_probe(struct amba_device *adev, const struct amba_id *id) | |||
154 | 154 | ||
155 | pm_runtime_put(&adev->dev); | 155 | pm_runtime_put(&adev->dev); |
156 | 156 | ||
157 | desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL); | 157 | desc.type = CORESIGHT_DEV_TYPE_SINK; |
158 | if (!desc) | 158 | desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_PORT; |
159 | return -ENOMEM; | 159 | desc.ops = &tpiu_cs_ops; |
160 | 160 | desc.pdata = pdata; | |
161 | desc->type = CORESIGHT_DEV_TYPE_SINK; | 161 | desc.dev = dev; |
162 | desc->subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_PORT; | 162 | drvdata->csdev = coresight_register(&desc); |
163 | desc->ops = &tpiu_cs_ops; | ||
164 | desc->pdata = pdata; | ||
165 | desc->dev = dev; | ||
166 | drvdata->csdev = coresight_register(desc); | ||
167 | if (IS_ERR(drvdata->csdev)) | 163 | if (IS_ERR(drvdata->csdev)) |
168 | return PTR_ERR(drvdata->csdev); | 164 | return PTR_ERR(drvdata->csdev); |
169 | 165 | ||
diff --git a/drivers/hwtracing/coresight/coresight.c b/drivers/hwtracing/coresight/coresight.c index d08d1ab9bba5..7bf00a0beb6f 100644 --- a/drivers/hwtracing/coresight/coresight.c +++ b/drivers/hwtracing/coresight/coresight.c | |||
@@ -257,7 +257,7 @@ static void coresight_disable_source(struct coresight_device *csdev) | |||
257 | { | 257 | { |
258 | if (atomic_dec_return(csdev->refcnt) == 0) { | 258 | if (atomic_dec_return(csdev->refcnt) == 0) { |
259 | if (source_ops(csdev)->disable) { | 259 | if (source_ops(csdev)->disable) { |
260 | source_ops(csdev)->disable(csdev); | 260 | source_ops(csdev)->disable(csdev, NULL); |
261 | csdev->enable = false; | 261 | csdev->enable = false; |
262 | } | 262 | } |
263 | } | 263 | } |
@@ -429,7 +429,7 @@ struct list_head *coresight_build_path(struct coresight_device *csdev) | |||
429 | 429 | ||
430 | path = kzalloc(sizeof(struct list_head), GFP_KERNEL); | 430 | path = kzalloc(sizeof(struct list_head), GFP_KERNEL); |
431 | if (!path) | 431 | if (!path) |
432 | return NULL; | 432 | return ERR_PTR(-ENOMEM); |
433 | 433 | ||
434 | INIT_LIST_HEAD(path); | 434 | INIT_LIST_HEAD(path); |
435 | 435 | ||
@@ -725,7 +725,8 @@ static int coresight_orphan_match(struct device *dev, void *data) | |||
725 | /* We have found at least one orphan connection */ | 725 | /* We have found at least one orphan connection */ |
726 | if (conn->child_dev == NULL) { | 726 | if (conn->child_dev == NULL) { |
727 | /* Does it match this newly added device? */ | 727 | /* Does it match this newly added device? */ |
728 | if (!strcmp(dev_name(&csdev->dev), conn->child_name)) { | 728 | if (conn->child_name && |
729 | !strcmp(dev_name(&csdev->dev), conn->child_name)) { | ||
729 | conn->child_dev = csdev; | 730 | conn->child_dev = csdev; |
730 | } else { | 731 | } else { |
731 | /* This component still has an orphan */ | 732 | /* This component still has an orphan */ |
@@ -893,7 +894,7 @@ struct coresight_device *coresight_register(struct coresight_desc *desc) | |||
893 | int nr_refcnts = 1; | 894 | int nr_refcnts = 1; |
894 | atomic_t *refcnts = NULL; | 895 | atomic_t *refcnts = NULL; |
895 | struct coresight_device *csdev; | 896 | struct coresight_device *csdev; |
896 | struct coresight_connection *conns; | 897 | struct coresight_connection *conns = NULL; |
897 | 898 | ||
898 | csdev = kzalloc(sizeof(*csdev), GFP_KERNEL); | 899 | csdev = kzalloc(sizeof(*csdev), GFP_KERNEL); |
899 | if (!csdev) { | 900 | if (!csdev) { |
@@ -921,16 +922,20 @@ struct coresight_device *coresight_register(struct coresight_desc *desc) | |||
921 | 922 | ||
922 | csdev->nr_inport = desc->pdata->nr_inport; | 923 | csdev->nr_inport = desc->pdata->nr_inport; |
923 | csdev->nr_outport = desc->pdata->nr_outport; | 924 | csdev->nr_outport = desc->pdata->nr_outport; |
924 | conns = kcalloc(csdev->nr_outport, sizeof(*conns), GFP_KERNEL); | ||
925 | if (!conns) { | ||
926 | ret = -ENOMEM; | ||
927 | goto err_kzalloc_conns; | ||
928 | } | ||
929 | 925 | ||
930 | for (i = 0; i < csdev->nr_outport; i++) { | 926 | /* Initialise connections if there is at least one outport */ |
931 | conns[i].outport = desc->pdata->outports[i]; | 927 | if (csdev->nr_outport) { |
932 | conns[i].child_name = desc->pdata->child_names[i]; | 928 | conns = kcalloc(csdev->nr_outport, sizeof(*conns), GFP_KERNEL); |
933 | conns[i].child_port = desc->pdata->child_ports[i]; | 929 | if (!conns) { |
930 | ret = -ENOMEM; | ||
931 | goto err_kzalloc_conns; | ||
932 | } | ||
933 | |||
934 | for (i = 0; i < csdev->nr_outport; i++) { | ||
935 | conns[i].outport = desc->pdata->outports[i]; | ||
936 | conns[i].child_name = desc->pdata->child_names[i]; | ||
937 | conns[i].child_port = desc->pdata->child_ports[i]; | ||
938 | } | ||
934 | } | 939 | } |
935 | 940 | ||
936 | csdev->conns = conns; | 941 | csdev->conns = conns; |
diff --git a/drivers/hwtracing/coresight/of_coresight.c b/drivers/hwtracing/coresight/of_coresight.c index b68da1888fd5..629e031b7456 100644 --- a/drivers/hwtracing/coresight/of_coresight.c +++ b/drivers/hwtracing/coresight/of_coresight.c | |||
@@ -166,7 +166,7 @@ struct coresight_platform_data *of_get_coresight_platform_data( | |||
166 | 166 | ||
167 | rdev = of_coresight_get_endpoint_device(rparent); | 167 | rdev = of_coresight_get_endpoint_device(rparent); |
168 | if (!rdev) | 168 | if (!rdev) |
169 | continue; | 169 | return ERR_PTR(-EPROBE_DEFER); |
170 | 170 | ||
171 | pdata->child_names[i] = dev_name(rdev); | 171 | pdata->child_names[i] = dev_name(rdev); |
172 | pdata->child_ports[i] = rendpoint.id; | 172 | pdata->child_ports[i] = rendpoint.id; |
@@ -184,6 +184,7 @@ struct coresight_platform_data *of_get_coresight_platform_data( | |||
184 | break; | 184 | break; |
185 | } | 185 | } |
186 | } | 186 | } |
187 | of_node_put(dn); | ||
187 | 188 | ||
188 | return pdata; | 189 | return pdata; |
189 | } | 190 | } |
diff --git a/drivers/iio/pressure/Kconfig b/drivers/iio/pressure/Kconfig index d130cdc78f43..7fa65ab664fb 100644 --- a/drivers/iio/pressure/Kconfig +++ b/drivers/iio/pressure/Kconfig | |||
@@ -8,8 +8,6 @@ menu "Pressure sensors" | |||
8 | config BMP280 | 8 | config BMP280 |
9 | tristate "Bosch Sensortec BMP180/BMP280 pressure sensor I2C driver" | 9 | tristate "Bosch Sensortec BMP180/BMP280 pressure sensor I2C driver" |
10 | depends on (I2C || SPI_MASTER) | 10 | depends on (I2C || SPI_MASTER) |
11 | depends on !(BMP085_I2C=y || BMP085_I2C=m) | ||
12 | depends on !(BMP085_SPI=y || BMP085_SPI=m) | ||
13 | select REGMAP | 11 | select REGMAP |
14 | select BMP280_I2C if (I2C) | 12 | select BMP280_I2C if (I2C) |
15 | select BMP280_SPI if (SPI_MASTER) | 13 | select BMP280_SPI if (SPI_MASTER) |
diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index 65ebbd111702..92595b98e7ed 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c | |||
@@ -1013,23 +1013,12 @@ static struct miscdevice uinput_misc = { | |||
1013 | .minor = UINPUT_MINOR, | 1013 | .minor = UINPUT_MINOR, |
1014 | .name = UINPUT_NAME, | 1014 | .name = UINPUT_NAME, |
1015 | }; | 1015 | }; |
1016 | module_misc_device(uinput_misc); | ||
1017 | |||
1016 | MODULE_ALIAS_MISCDEV(UINPUT_MINOR); | 1018 | MODULE_ALIAS_MISCDEV(UINPUT_MINOR); |
1017 | MODULE_ALIAS("devname:" UINPUT_NAME); | 1019 | MODULE_ALIAS("devname:" UINPUT_NAME); |
1018 | 1020 | ||
1019 | static int __init uinput_init(void) | ||
1020 | { | ||
1021 | return misc_register(&uinput_misc); | ||
1022 | } | ||
1023 | |||
1024 | static void __exit uinput_exit(void) | ||
1025 | { | ||
1026 | misc_deregister(&uinput_misc); | ||
1027 | } | ||
1028 | |||
1029 | MODULE_AUTHOR("Aristeu Sergio Rozanski Filho"); | 1021 | MODULE_AUTHOR("Aristeu Sergio Rozanski Filho"); |
1030 | MODULE_DESCRIPTION("User level driver support for input subsystem"); | 1022 | MODULE_DESCRIPTION("User level driver support for input subsystem"); |
1031 | MODULE_LICENSE("GPL"); | 1023 | MODULE_LICENSE("GPL"); |
1032 | MODULE_VERSION("0.3"); | 1024 | MODULE_VERSION("0.3"); |
1033 | |||
1034 | module_init(uinput_init); | ||
1035 | module_exit(uinput_exit); | ||
diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c index 9ebd2cfbd849..c784ddcd4405 100644 --- a/drivers/lightnvm/core.c +++ b/drivers/lightnvm/core.c | |||
@@ -1171,27 +1171,10 @@ static struct miscdevice _nvm_misc = { | |||
1171 | .nodename = "lightnvm/control", | 1171 | .nodename = "lightnvm/control", |
1172 | .fops = &_ctl_fops, | 1172 | .fops = &_ctl_fops, |
1173 | }; | 1173 | }; |
1174 | module_misc_device(_nvm_misc); | ||
1174 | 1175 | ||
1175 | MODULE_ALIAS_MISCDEV(MISC_DYNAMIC_MINOR); | 1176 | MODULE_ALIAS_MISCDEV(MISC_DYNAMIC_MINOR); |
1176 | 1177 | ||
1177 | static int __init nvm_mod_init(void) | ||
1178 | { | ||
1179 | int ret; | ||
1180 | |||
1181 | ret = misc_register(&_nvm_misc); | ||
1182 | if (ret) | ||
1183 | pr_err("nvm: misc_register failed for control device"); | ||
1184 | |||
1185 | return ret; | ||
1186 | } | ||
1187 | |||
1188 | static void __exit nvm_mod_exit(void) | ||
1189 | { | ||
1190 | misc_deregister(&_nvm_misc); | ||
1191 | } | ||
1192 | |||
1193 | MODULE_AUTHOR("Matias Bjorling <m@bjorling.me>"); | 1178 | MODULE_AUTHOR("Matias Bjorling <m@bjorling.me>"); |
1194 | MODULE_LICENSE("GPL v2"); | 1179 | MODULE_LICENSE("GPL v2"); |
1195 | MODULE_VERSION("0.1"); | 1180 | MODULE_VERSION("0.1"); |
1196 | module_init(nvm_mod_init); | ||
1197 | module_exit(nvm_mod_exit); | ||
diff --git a/drivers/mcb/Kconfig b/drivers/mcb/Kconfig index e9a6976e1010..76d9c51de6c9 100644 --- a/drivers/mcb/Kconfig +++ b/drivers/mcb/Kconfig | |||
@@ -28,4 +28,13 @@ config MCB_PCI | |||
28 | 28 | ||
29 | If build as a module, the module is called mcb-pci.ko | 29 | If build as a module, the module is called mcb-pci.ko |
30 | 30 | ||
31 | config MCB_LPC | ||
32 | tristate "LPC (non PCI) based MCB carrier" | ||
33 | default n | ||
34 | help | ||
35 | |||
36 | This is a MCB carrier on a LPC or non PCI device. | ||
37 | |||
38 | If build as a module, the module is called mcb-lpc.ko | ||
39 | |||
31 | endif # MCB | 40 | endif # MCB |
diff --git a/drivers/mcb/Makefile b/drivers/mcb/Makefile index 1ae141311def..bcc7745774ab 100644 --- a/drivers/mcb/Makefile +++ b/drivers/mcb/Makefile | |||
@@ -5,3 +5,4 @@ mcb-y += mcb-core.o | |||
5 | mcb-y += mcb-parse.o | 5 | mcb-y += mcb-parse.o |
6 | 6 | ||
7 | obj-$(CONFIG_MCB_PCI) += mcb-pci.o | 7 | obj-$(CONFIG_MCB_PCI) += mcb-pci.o |
8 | obj-$(CONFIG_MCB_LPC) += mcb-lpc.o | ||
diff --git a/drivers/mcb/mcb-core.c b/drivers/mcb/mcb-core.c index 6f2c8522e14a..921a5d2a802b 100644 --- a/drivers/mcb/mcb-core.c +++ b/drivers/mcb/mcb-core.c | |||
@@ -233,6 +233,7 @@ int mcb_device_register(struct mcb_bus *bus, struct mcb_device *dev) | |||
233 | dev->dev.bus = &mcb_bus_type; | 233 | dev->dev.bus = &mcb_bus_type; |
234 | dev->dev.parent = bus->dev.parent; | 234 | dev->dev.parent = bus->dev.parent; |
235 | dev->dev.release = mcb_release_dev; | 235 | dev->dev.release = mcb_release_dev; |
236 | dev->dma_dev = bus->carrier; | ||
236 | 237 | ||
237 | device_id = dev->id; | 238 | device_id = dev->id; |
238 | dev_set_name(&dev->dev, "mcb%d-16z%03d-%d:%d:%d", | 239 | dev_set_name(&dev->dev, "mcb%d-16z%03d-%d:%d:%d", |
@@ -369,7 +370,6 @@ struct mcb_device *mcb_alloc_dev(struct mcb_bus *bus) | |||
369 | if (!dev) | 370 | if (!dev) |
370 | return NULL; | 371 | return NULL; |
371 | 372 | ||
372 | INIT_LIST_HEAD(&dev->bus_list); | ||
373 | dev->bus = bus; | 373 | dev->bus = bus; |
374 | 374 | ||
375 | return dev; | 375 | return dev; |
@@ -405,20 +405,6 @@ static int __mcb_bus_add_devices(struct device *dev, void *data) | |||
405 | return 0; | 405 | return 0; |
406 | } | 406 | } |
407 | 407 | ||
408 | static int __mcb_bus_add_child(struct device *dev, void *data) | ||
409 | { | ||
410 | struct mcb_device *mdev = to_mcb_device(dev); | ||
411 | struct mcb_bus *child; | ||
412 | |||
413 | BUG_ON(!mdev->is_added); | ||
414 | child = mdev->subordinate; | ||
415 | |||
416 | if (child) | ||
417 | mcb_bus_add_devices(child); | ||
418 | |||
419 | return 0; | ||
420 | } | ||
421 | |||
422 | /** | 408 | /** |
423 | * mcb_bus_add_devices() - Add devices in the bus' internal device list | 409 | * mcb_bus_add_devices() - Add devices in the bus' internal device list |
424 | * @bus: The @mcb_bus we add the devices | 410 | * @bus: The @mcb_bus we add the devices |
@@ -428,8 +414,6 @@ static int __mcb_bus_add_child(struct device *dev, void *data) | |||
428 | void mcb_bus_add_devices(const struct mcb_bus *bus) | 414 | void mcb_bus_add_devices(const struct mcb_bus *bus) |
429 | { | 415 | { |
430 | bus_for_each_dev(&mcb_bus_type, NULL, NULL, __mcb_bus_add_devices); | 416 | bus_for_each_dev(&mcb_bus_type, NULL, NULL, __mcb_bus_add_devices); |
431 | bus_for_each_dev(&mcb_bus_type, NULL, NULL, __mcb_bus_add_child); | ||
432 | |||
433 | } | 417 | } |
434 | EXPORT_SYMBOL_GPL(mcb_bus_add_devices); | 418 | EXPORT_SYMBOL_GPL(mcb_bus_add_devices); |
435 | 419 | ||
diff --git a/drivers/mcb/mcb-internal.h b/drivers/mcb/mcb-internal.h index 5254e0285725..d6e6933b19f1 100644 --- a/drivers/mcb/mcb-internal.h +++ b/drivers/mcb/mcb-internal.h | |||
@@ -112,6 +112,15 @@ struct chameleon_bdd { | |||
112 | u32 size; | 112 | u32 size; |
113 | } __packed; | 113 | } __packed; |
114 | 114 | ||
115 | struct chameleon_bar { | ||
116 | u32 addr; | ||
117 | u32 size; | ||
118 | }; | ||
119 | |||
120 | #define BAR_CNT(x) ((x) & 0x07) | ||
121 | #define CHAMELEON_BAR_MAX 6 | ||
122 | #define BAR_DESC_SIZE(x) ((x) * sizeof(struct chameleon_bar) + sizeof(__le32)) | ||
123 | |||
115 | int chameleon_parse_cells(struct mcb_bus *bus, phys_addr_t mapbase, | 124 | int chameleon_parse_cells(struct mcb_bus *bus, phys_addr_t mapbase, |
116 | void __iomem *base); | 125 | void __iomem *base); |
117 | 126 | ||
diff --git a/drivers/mcb/mcb-lpc.c b/drivers/mcb/mcb-lpc.c new file mode 100644 index 000000000000..d072c088ce73 --- /dev/null +++ b/drivers/mcb/mcb-lpc.c | |||
@@ -0,0 +1,158 @@ | |||
1 | /* | ||
2 | * MEN Chameleon Bus. | ||
3 | * | ||
4 | * Copyright (C) 2014 MEN Mikroelektronik GmbH (www.men.de) | ||
5 | * Author: Andreas Werner <andreas.werner@men.de> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the Free | ||
9 | * Software Foundation; version 2 of the License. | ||
10 | */ | ||
11 | |||
12 | #include <linux/platform_device.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/dmi.h> | ||
15 | #include <linux/mcb.h> | ||
16 | #include <linux/io.h> | ||
17 | #include "mcb-internal.h" | ||
18 | |||
19 | struct priv { | ||
20 | struct mcb_bus *bus; | ||
21 | struct resource *mem; | ||
22 | void __iomem *base; | ||
23 | }; | ||
24 | |||
25 | static int mcb_lpc_probe(struct platform_device *pdev) | ||
26 | { | ||
27 | struct resource *res; | ||
28 | struct priv *priv; | ||
29 | int ret = 0; | ||
30 | |||
31 | priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); | ||
32 | if (!priv) | ||
33 | return -ENOMEM; | ||
34 | |||
35 | priv->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
36 | if (!priv->mem) { | ||
37 | dev_err(&pdev->dev, "No Memory resource\n"); | ||
38 | return -ENODEV; | ||
39 | } | ||
40 | |||
41 | res = devm_request_mem_region(&pdev->dev, priv->mem->start, | ||
42 | resource_size(priv->mem), | ||
43 | KBUILD_MODNAME); | ||
44 | if (!res) { | ||
45 | dev_err(&pdev->dev, "Failed to request IO memory\n"); | ||
46 | return -EBUSY; | ||
47 | } | ||
48 | |||
49 | priv->base = devm_ioremap(&pdev->dev, priv->mem->start, | ||
50 | resource_size(priv->mem)); | ||
51 | if (!priv->base) { | ||
52 | dev_err(&pdev->dev, "Cannot ioremap\n"); | ||
53 | return -ENOMEM; | ||
54 | } | ||
55 | |||
56 | platform_set_drvdata(pdev, priv); | ||
57 | |||
58 | priv->bus = mcb_alloc_bus(&pdev->dev); | ||
59 | if (IS_ERR(priv->bus)) | ||
60 | return PTR_ERR(priv->bus); | ||
61 | |||
62 | ret = chameleon_parse_cells(priv->bus, priv->mem->start, priv->base); | ||
63 | if (ret < 0) { | ||
64 | mcb_release_bus(priv->bus); | ||
65 | return ret; | ||
66 | } | ||
67 | |||
68 | dev_dbg(&pdev->dev, "Found %d cells\n", ret); | ||
69 | |||
70 | mcb_bus_add_devices(priv->bus); | ||
71 | |||
72 | return 0; | ||
73 | |||
74 | } | ||
75 | |||
76 | static int mcb_lpc_remove(struct platform_device *pdev) | ||
77 | { | ||
78 | struct priv *priv = platform_get_drvdata(pdev); | ||
79 | |||
80 | mcb_release_bus(priv->bus); | ||
81 | |||
82 | return 0; | ||
83 | } | ||
84 | |||
85 | static struct platform_device *mcb_lpc_pdev; | ||
86 | |||
87 | static int mcb_lpc_create_platform_device(const struct dmi_system_id *id) | ||
88 | { | ||
89 | struct resource *res = id->driver_data; | ||
90 | int ret; | ||
91 | |||
92 | mcb_lpc_pdev = platform_device_alloc("mcb-lpc", -1); | ||
93 | if (!mcb_lpc_pdev) | ||
94 | return -ENOMEM; | ||
95 | |||
96 | ret = platform_device_add_resources(mcb_lpc_pdev, res, 1); | ||
97 | if (ret) | ||
98 | goto out_put; | ||
99 | |||
100 | ret = platform_device_add(mcb_lpc_pdev); | ||
101 | if (ret) | ||
102 | goto out_put; | ||
103 | |||
104 | return 0; | ||
105 | |||
106 | out_put: | ||
107 | platform_device_put(mcb_lpc_pdev); | ||
108 | return ret; | ||
109 | } | ||
110 | |||
111 | static struct resource sc24_fpga_resource = { | ||
112 | .start = 0xe000e000, | ||
113 | .end = 0xe000e000 + CHAM_HEADER_SIZE, | ||
114 | .flags = IORESOURCE_MEM, | ||
115 | }; | ||
116 | |||
117 | static struct platform_driver mcb_lpc_driver = { | ||
118 | .driver = { | ||
119 | .name = "mcb-lpc", | ||
120 | }, | ||
121 | .probe = mcb_lpc_probe, | ||
122 | .remove = mcb_lpc_remove, | ||
123 | }; | ||
124 | |||
125 | static const struct dmi_system_id mcb_lpc_dmi_table[] = { | ||
126 | { | ||
127 | .ident = "SC24", | ||
128 | .matches = { | ||
129 | DMI_MATCH(DMI_SYS_VENDOR, "MEN"), | ||
130 | DMI_MATCH(DMI_PRODUCT_VERSION, "14SC24"), | ||
131 | }, | ||
132 | .driver_data = (void *)&sc24_fpga_resource, | ||
133 | .callback = mcb_lpc_create_platform_device, | ||
134 | }, | ||
135 | {} | ||
136 | }; | ||
137 | MODULE_DEVICE_TABLE(dmi, mcb_lpc_dmi_table); | ||
138 | |||
139 | static int __init mcb_lpc_init(void) | ||
140 | { | ||
141 | if (!dmi_check_system(mcb_lpc_dmi_table)) | ||
142 | return -ENODEV; | ||
143 | |||
144 | return platform_driver_register(&mcb_lpc_driver); | ||
145 | } | ||
146 | |||
147 | static void __exit mcb_lpc_exit(void) | ||
148 | { | ||
149 | platform_device_unregister(mcb_lpc_pdev); | ||
150 | platform_driver_unregister(&mcb_lpc_driver); | ||
151 | } | ||
152 | |||
153 | module_init(mcb_lpc_init); | ||
154 | module_exit(mcb_lpc_exit); | ||
155 | |||
156 | MODULE_AUTHOR("Andreas Werner <andreas.werner@men.de>"); | ||
157 | MODULE_LICENSE("GPL"); | ||
158 | MODULE_DESCRIPTION("MCB over LPC support"); | ||
diff --git a/drivers/mcb/mcb-parse.c b/drivers/mcb/mcb-parse.c index dbecbed0d258..4ca2739b4fad 100644 --- a/drivers/mcb/mcb-parse.c +++ b/drivers/mcb/mcb-parse.c | |||
@@ -26,19 +26,20 @@ static inline uint32_t get_next_dtype(void __iomem *p) | |||
26 | } | 26 | } |
27 | 27 | ||
28 | static int chameleon_parse_bdd(struct mcb_bus *bus, | 28 | static int chameleon_parse_bdd(struct mcb_bus *bus, |
29 | phys_addr_t mapbase, | 29 | struct chameleon_bar *cb, |
30 | void __iomem *base) | 30 | void __iomem *base) |
31 | { | 31 | { |
32 | return 0; | 32 | return 0; |
33 | } | 33 | } |
34 | 34 | ||
35 | static int chameleon_parse_gdd(struct mcb_bus *bus, | 35 | static int chameleon_parse_gdd(struct mcb_bus *bus, |
36 | phys_addr_t mapbase, | 36 | struct chameleon_bar *cb, |
37 | void __iomem *base) | 37 | void __iomem *base, int bar_count) |
38 | { | 38 | { |
39 | struct chameleon_gdd __iomem *gdd = | 39 | struct chameleon_gdd __iomem *gdd = |
40 | (struct chameleon_gdd __iomem *) base; | 40 | (struct chameleon_gdd __iomem *) base; |
41 | struct mcb_device *mdev; | 41 | struct mcb_device *mdev; |
42 | u32 dev_mapbase; | ||
42 | u32 offset; | 43 | u32 offset; |
43 | u32 size; | 44 | u32 size; |
44 | int ret; | 45 | int ret; |
@@ -61,13 +62,39 @@ static int chameleon_parse_gdd(struct mcb_bus *bus, | |||
61 | mdev->group = GDD_GRP(reg2); | 62 | mdev->group = GDD_GRP(reg2); |
62 | mdev->inst = GDD_INS(reg2); | 63 | mdev->inst = GDD_INS(reg2); |
63 | 64 | ||
65 | /* | ||
66 | * If the BAR is missing, dev_mapbase is zero, or if the | ||
67 | * device is IO mapped we just print a warning and go on with the | ||
68 | * next device, instead of completely stop the gdd parser | ||
69 | */ | ||
70 | if (mdev->bar > bar_count - 1) { | ||
71 | pr_info("No BAR for 16z%03d\n", mdev->id); | ||
72 | ret = 0; | ||
73 | goto err; | ||
74 | } | ||
75 | |||
76 | dev_mapbase = cb[mdev->bar].addr; | ||
77 | if (!dev_mapbase) { | ||
78 | pr_info("BAR not assigned for 16z%03d\n", mdev->id); | ||
79 | ret = 0; | ||
80 | goto err; | ||
81 | } | ||
82 | |||
83 | if (dev_mapbase & 0x01) { | ||
84 | pr_info("IO mapped Device (16z%03d) not yet supported\n", | ||
85 | mdev->id); | ||
86 | ret = 0; | ||
87 | goto err; | ||
88 | } | ||
89 | |||
64 | pr_debug("Found a 16z%03d\n", mdev->id); | 90 | pr_debug("Found a 16z%03d\n", mdev->id); |
65 | 91 | ||
66 | mdev->irq.start = GDD_IRQ(reg1); | 92 | mdev->irq.start = GDD_IRQ(reg1); |
67 | mdev->irq.end = GDD_IRQ(reg1); | 93 | mdev->irq.end = GDD_IRQ(reg1); |
68 | mdev->irq.flags = IORESOURCE_IRQ; | 94 | mdev->irq.flags = IORESOURCE_IRQ; |
69 | 95 | ||
70 | mdev->mem.start = mapbase + offset; | 96 | mdev->mem.start = dev_mapbase + offset; |
97 | |||
71 | mdev->mem.end = mdev->mem.start + size - 1; | 98 | mdev->mem.end = mdev->mem.start + size - 1; |
72 | mdev->mem.flags = IORESOURCE_MEM; | 99 | mdev->mem.flags = IORESOURCE_MEM; |
73 | 100 | ||
@@ -85,13 +112,76 @@ err: | |||
85 | return ret; | 112 | return ret; |
86 | } | 113 | } |
87 | 114 | ||
115 | static void chameleon_parse_bar(void __iomem *base, | ||
116 | struct chameleon_bar *cb, int bar_count) | ||
117 | { | ||
118 | char __iomem *p = base; | ||
119 | int i; | ||
120 | |||
121 | /* skip reg1 */ | ||
122 | p += sizeof(__le32); | ||
123 | |||
124 | for (i = 0; i < bar_count; i++) { | ||
125 | cb[i].addr = readl(p); | ||
126 | cb[i].size = readl(p + 4); | ||
127 | |||
128 | p += sizeof(struct chameleon_bar); | ||
129 | } | ||
130 | } | ||
131 | |||
132 | static int chameleon_get_bar(char __iomem **base, phys_addr_t mapbase, | ||
133 | struct chameleon_bar **cb) | ||
134 | { | ||
135 | struct chameleon_bar *c; | ||
136 | int bar_count; | ||
137 | __le32 reg; | ||
138 | u32 dtype; | ||
139 | |||
140 | /* | ||
141 | * For those devices which are not connected | ||
142 | * to the PCI Bus (e.g. LPC) there is a bar | ||
143 | * descriptor located directly after the | ||
144 | * chameleon header. This header is comparable | ||
145 | * to a PCI header. | ||
146 | */ | ||
147 | dtype = get_next_dtype(*base); | ||
148 | if (dtype == CHAMELEON_DTYPE_BAR) { | ||
149 | reg = readl(*base); | ||
150 | |||
151 | bar_count = BAR_CNT(reg); | ||
152 | if (bar_count <= 0 && bar_count > CHAMELEON_BAR_MAX) | ||
153 | return -ENODEV; | ||
154 | |||
155 | c = kcalloc(bar_count, sizeof(struct chameleon_bar), | ||
156 | GFP_KERNEL); | ||
157 | if (!c) | ||
158 | return -ENOMEM; | ||
159 | |||
160 | chameleon_parse_bar(*base, c, bar_count); | ||
161 | *base += BAR_DESC_SIZE(bar_count); | ||
162 | } else { | ||
163 | c = kzalloc(sizeof(struct chameleon_bar), GFP_KERNEL); | ||
164 | if (!c) | ||
165 | return -ENOMEM; | ||
166 | |||
167 | bar_count = 1; | ||
168 | c->addr = mapbase; | ||
169 | } | ||
170 | |||
171 | *cb = c; | ||
172 | |||
173 | return bar_count; | ||
174 | } | ||
175 | |||
88 | int chameleon_parse_cells(struct mcb_bus *bus, phys_addr_t mapbase, | 176 | int chameleon_parse_cells(struct mcb_bus *bus, phys_addr_t mapbase, |
89 | void __iomem *base) | 177 | void __iomem *base) |
90 | { | 178 | { |
91 | char __iomem *p = base; | ||
92 | struct chameleon_fpga_header *header; | 179 | struct chameleon_fpga_header *header; |
93 | uint32_t dtype; | 180 | struct chameleon_bar *cb; |
181 | char __iomem *p = base; | ||
94 | int num_cells = 0; | 182 | int num_cells = 0; |
183 | uint32_t dtype; | ||
184 | int bar_count; | ||
95 | int ret = 0; | 185 | int ret = 0; |
96 | u32 hsize; | 186 | u32 hsize; |
97 | 187 | ||
@@ -108,8 +198,8 @@ int chameleon_parse_cells(struct mcb_bus *bus, phys_addr_t mapbase, | |||
108 | if (header->magic != CHAMELEONV2_MAGIC) { | 198 | if (header->magic != CHAMELEONV2_MAGIC) { |
109 | pr_err("Unsupported chameleon version 0x%x\n", | 199 | pr_err("Unsupported chameleon version 0x%x\n", |
110 | header->magic); | 200 | header->magic); |
111 | kfree(header); | 201 | ret = -ENODEV; |
112 | return -ENODEV; | 202 | goto free_header; |
113 | } | 203 | } |
114 | p += hsize; | 204 | p += hsize; |
115 | 205 | ||
@@ -119,16 +209,20 @@ int chameleon_parse_cells(struct mcb_bus *bus, phys_addr_t mapbase, | |||
119 | snprintf(bus->name, CHAMELEON_FILENAME_LEN + 1, "%s", | 209 | snprintf(bus->name, CHAMELEON_FILENAME_LEN + 1, "%s", |
120 | header->filename); | 210 | header->filename); |
121 | 211 | ||
212 | bar_count = chameleon_get_bar(&p, mapbase, &cb); | ||
213 | if (bar_count < 0) | ||
214 | goto free_header; | ||
215 | |||
122 | for_each_chameleon_cell(dtype, p) { | 216 | for_each_chameleon_cell(dtype, p) { |
123 | switch (dtype) { | 217 | switch (dtype) { |
124 | case CHAMELEON_DTYPE_GENERAL: | 218 | case CHAMELEON_DTYPE_GENERAL: |
125 | ret = chameleon_parse_gdd(bus, mapbase, p); | 219 | ret = chameleon_parse_gdd(bus, cb, p, bar_count); |
126 | if (ret < 0) | 220 | if (ret < 0) |
127 | goto out; | 221 | goto free_bar; |
128 | p += sizeof(struct chameleon_gdd); | 222 | p += sizeof(struct chameleon_gdd); |
129 | break; | 223 | break; |
130 | case CHAMELEON_DTYPE_BRIDGE: | 224 | case CHAMELEON_DTYPE_BRIDGE: |
131 | chameleon_parse_bdd(bus, mapbase, p); | 225 | chameleon_parse_bdd(bus, cb, p); |
132 | p += sizeof(struct chameleon_bdd); | 226 | p += sizeof(struct chameleon_bdd); |
133 | break; | 227 | break; |
134 | case CHAMELEON_DTYPE_END: | 228 | case CHAMELEON_DTYPE_END: |
@@ -136,8 +230,8 @@ int chameleon_parse_cells(struct mcb_bus *bus, phys_addr_t mapbase, | |||
136 | default: | 230 | default: |
137 | pr_err("Invalid chameleon descriptor type 0x%x\n", | 231 | pr_err("Invalid chameleon descriptor type 0x%x\n", |
138 | dtype); | 232 | dtype); |
139 | kfree(header); | 233 | ret = -EINVAL; |
140 | return -EINVAL; | 234 | goto free_bar; |
141 | } | 235 | } |
142 | num_cells++; | 236 | num_cells++; |
143 | } | 237 | } |
@@ -145,11 +239,15 @@ int chameleon_parse_cells(struct mcb_bus *bus, phys_addr_t mapbase, | |||
145 | if (num_cells == 0) | 239 | if (num_cells == 0) |
146 | num_cells = -EINVAL; | 240 | num_cells = -EINVAL; |
147 | 241 | ||
242 | kfree(cb); | ||
148 | kfree(header); | 243 | kfree(header); |
149 | return num_cells; | 244 | return num_cells; |
150 | 245 | ||
151 | out: | 246 | free_bar: |
247 | kfree(cb); | ||
248 | free_header: | ||
152 | kfree(header); | 249 | kfree(header); |
250 | |||
153 | return ret; | 251 | return ret; |
154 | } | 252 | } |
155 | EXPORT_SYMBOL_GPL(chameleon_parse_cells); | 253 | EXPORT_SYMBOL_GPL(chameleon_parse_cells); |
diff --git a/drivers/mcb/mcb-pci.c b/drivers/mcb/mcb-pci.c index b15a0349cd97..af4d2f26f1c6 100644 --- a/drivers/mcb/mcb-pci.c +++ b/drivers/mcb/mcb-pci.c | |||
@@ -46,6 +46,7 @@ static int mcb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
46 | dev_err(&pdev->dev, "Failed to enable PCI device\n"); | 46 | dev_err(&pdev->dev, "Failed to enable PCI device\n"); |
47 | return -ENODEV; | 47 | return -ENODEV; |
48 | } | 48 | } |
49 | pci_set_master(pdev); | ||
49 | 50 | ||
50 | priv->mapbase = pci_resource_start(pdev, 0); | 51 | priv->mapbase = pci_resource_start(pdev, 0); |
51 | if (!priv->mapbase) { | 52 | if (!priv->mapbase) { |
diff --git a/drivers/memory/of_memory.c b/drivers/memory/of_memory.c index 9daf94bb8f27..568f05ed961a 100644 --- a/drivers/memory/of_memory.c +++ b/drivers/memory/of_memory.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/gfp.h> | 16 | #include <linux/gfp.h> |
17 | #include <memory/jedec_ddr.h> | 17 | #include <memory/jedec_ddr.h> |
18 | #include <linux/export.h> | 18 | #include <linux/export.h> |
19 | #include "of_memory.h" | ||
19 | 20 | ||
20 | /** | 21 | /** |
21 | * of_get_min_tck() - extract min timing values for ddr | 22 | * of_get_min_tck() - extract min timing values for ddr |
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index d00252828966..64971baf11fa 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig | |||
@@ -429,34 +429,6 @@ config ARM_CHARLCD | |||
429 | line and the Linux version on the second line, but that's | 429 | line and the Linux version on the second line, but that's |
430 | still useful. | 430 | still useful. |
431 | 431 | ||
432 | config BMP085 | ||
433 | tristate | ||
434 | depends on SYSFS | ||
435 | |||
436 | config BMP085_I2C | ||
437 | tristate "BMP085 digital pressure sensor on I2C" | ||
438 | select BMP085 | ||
439 | select REGMAP_I2C | ||
440 | depends on I2C && SYSFS | ||
441 | help | ||
442 | Say Y here if you want to support Bosch Sensortec's digital pressure | ||
443 | sensor hooked to an I2C bus. | ||
444 | |||
445 | To compile this driver as a module, choose M here: the | ||
446 | module will be called bmp085-i2c. | ||
447 | |||
448 | config BMP085_SPI | ||
449 | tristate "BMP085 digital pressure sensor on SPI" | ||
450 | select BMP085 | ||
451 | select REGMAP_SPI | ||
452 | depends on SPI_MASTER && SYSFS | ||
453 | help | ||
454 | Say Y here if you want to support Bosch Sensortec's digital pressure | ||
455 | sensor hooked to an SPI bus. | ||
456 | |||
457 | To compile this driver as a module, choose M here: the | ||
458 | module will be called bmp085-spi. | ||
459 | |||
460 | config PCH_PHUB | 432 | config PCH_PHUB |
461 | tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) PHUB" | 433 | tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) PHUB" |
462 | select GENERIC_NET_UTILS | 434 | select GENERIC_NET_UTILS |
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index fb32516ddfe2..31983366090a 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile | |||
@@ -9,9 +9,6 @@ obj-$(CONFIG_AD525X_DPOT_SPI) += ad525x_dpot-spi.o | |||
9 | obj-$(CONFIG_INTEL_MID_PTI) += pti.o | 9 | obj-$(CONFIG_INTEL_MID_PTI) += pti.o |
10 | obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o | 10 | obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o |
11 | obj-$(CONFIG_ATMEL_TCLIB) += atmel_tclib.o | 11 | obj-$(CONFIG_ATMEL_TCLIB) += atmel_tclib.o |
12 | obj-$(CONFIG_BMP085) += bmp085.o | ||
13 | obj-$(CONFIG_BMP085_I2C) += bmp085-i2c.o | ||
14 | obj-$(CONFIG_BMP085_SPI) += bmp085-spi.o | ||
15 | obj-$(CONFIG_DUMMY_IRQ) += dummy-irq.o | 12 | obj-$(CONFIG_DUMMY_IRQ) += dummy-irq.o |
16 | obj-$(CONFIG_ICS932S401) += ics932s401.o | 13 | obj-$(CONFIG_ICS932S401) += ics932s401.o |
17 | obj-$(CONFIG_LKDTM) += lkdtm.o | 14 | obj-$(CONFIG_LKDTM) += lkdtm.o |
diff --git a/drivers/misc/bmp085-i2c.c b/drivers/misc/bmp085-i2c.c deleted file mode 100644 index f35c218aaa1a..000000000000 --- a/drivers/misc/bmp085-i2c.c +++ /dev/null | |||
@@ -1,83 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2012 Bosch Sensortec GmbH | ||
3 | * Copyright (c) 2012 Unixphere AB | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
18 | */ | ||
19 | |||
20 | #include <linux/module.h> | ||
21 | #include <linux/i2c.h> | ||
22 | #include <linux/err.h> | ||
23 | #include "bmp085.h" | ||
24 | |||
25 | #define BMP085_I2C_ADDRESS 0x77 | ||
26 | |||
27 | static const unsigned short normal_i2c[] = { BMP085_I2C_ADDRESS, | ||
28 | I2C_CLIENT_END }; | ||
29 | |||
30 | static int bmp085_i2c_detect(struct i2c_client *client, | ||
31 | struct i2c_board_info *info) | ||
32 | { | ||
33 | if (client->addr != BMP085_I2C_ADDRESS) | ||
34 | return -ENODEV; | ||
35 | |||
36 | return bmp085_detect(&client->dev); | ||
37 | } | ||
38 | |||
39 | static int bmp085_i2c_probe(struct i2c_client *client, | ||
40 | const struct i2c_device_id *id) | ||
41 | { | ||
42 | int err; | ||
43 | struct regmap *regmap = devm_regmap_init_i2c(client, | ||
44 | &bmp085_regmap_config); | ||
45 | |||
46 | if (IS_ERR(regmap)) { | ||
47 | err = PTR_ERR(regmap); | ||
48 | dev_err(&client->dev, "Failed to init regmap: %d\n", err); | ||
49 | return err; | ||
50 | } | ||
51 | |||
52 | return bmp085_probe(&client->dev, regmap, client->irq); | ||
53 | } | ||
54 | |||
55 | static int bmp085_i2c_remove(struct i2c_client *client) | ||
56 | { | ||
57 | return bmp085_remove(&client->dev); | ||
58 | } | ||
59 | |||
60 | static const struct i2c_device_id bmp085_id[] = { | ||
61 | { BMP085_NAME, 0 }, | ||
62 | { "bmp180", 0 }, | ||
63 | { } | ||
64 | }; | ||
65 | MODULE_DEVICE_TABLE(i2c, bmp085_id); | ||
66 | |||
67 | static struct i2c_driver bmp085_i2c_driver = { | ||
68 | .driver = { | ||
69 | .name = BMP085_NAME, | ||
70 | }, | ||
71 | .id_table = bmp085_id, | ||
72 | .probe = bmp085_i2c_probe, | ||
73 | .remove = bmp085_i2c_remove, | ||
74 | |||
75 | .detect = bmp085_i2c_detect, | ||
76 | .address_list = normal_i2c | ||
77 | }; | ||
78 | |||
79 | module_i2c_driver(bmp085_i2c_driver); | ||
80 | |||
81 | MODULE_AUTHOR("Eric Andersson <eric.andersson@unixphere.com>"); | ||
82 | MODULE_DESCRIPTION("BMP085 I2C bus driver"); | ||
83 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/misc/bmp085-spi.c b/drivers/misc/bmp085-spi.c deleted file mode 100644 index 17ecbf95ff15..000000000000 --- a/drivers/misc/bmp085-spi.c +++ /dev/null | |||
@@ -1,79 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2012 Bosch Sensortec GmbH | ||
3 | * Copyright (c) 2012 Unixphere AB | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
18 | */ | ||
19 | |||
20 | #include <linux/module.h> | ||
21 | #include <linux/spi/spi.h> | ||
22 | #include <linux/err.h> | ||
23 | #include "bmp085.h" | ||
24 | |||
25 | static int bmp085_spi_probe(struct spi_device *client) | ||
26 | { | ||
27 | int err; | ||
28 | struct regmap *regmap; | ||
29 | |||
30 | client->bits_per_word = 8; | ||
31 | err = spi_setup(client); | ||
32 | if (err < 0) { | ||
33 | dev_err(&client->dev, "spi_setup failed!\n"); | ||
34 | return err; | ||
35 | } | ||
36 | |||
37 | regmap = devm_regmap_init_spi(client, &bmp085_regmap_config); | ||
38 | if (IS_ERR(regmap)) { | ||
39 | err = PTR_ERR(regmap); | ||
40 | dev_err(&client->dev, "Failed to init regmap: %d\n", err); | ||
41 | return err; | ||
42 | } | ||
43 | |||
44 | return bmp085_probe(&client->dev, regmap, client->irq); | ||
45 | } | ||
46 | |||
47 | static int bmp085_spi_remove(struct spi_device *client) | ||
48 | { | ||
49 | return bmp085_remove(&client->dev); | ||
50 | } | ||
51 | |||
52 | static const struct of_device_id bmp085_of_match[] = { | ||
53 | { .compatible = "bosch,bmp085", }, | ||
54 | { }, | ||
55 | }; | ||
56 | MODULE_DEVICE_TABLE(of, bmp085_of_match); | ||
57 | |||
58 | static const struct spi_device_id bmp085_id[] = { | ||
59 | { "bmp180", 0 }, | ||
60 | { "bmp181", 0 }, | ||
61 | { } | ||
62 | }; | ||
63 | MODULE_DEVICE_TABLE(spi, bmp085_id); | ||
64 | |||
65 | static struct spi_driver bmp085_spi_driver = { | ||
66 | .driver = { | ||
67 | .name = BMP085_NAME, | ||
68 | .of_match_table = bmp085_of_match | ||
69 | }, | ||
70 | .id_table = bmp085_id, | ||
71 | .probe = bmp085_spi_probe, | ||
72 | .remove = bmp085_spi_remove | ||
73 | }; | ||
74 | |||
75 | module_spi_driver(bmp085_spi_driver); | ||
76 | |||
77 | MODULE_AUTHOR("Eric Andersson <eric.andersson@unixphere.com>"); | ||
78 | MODULE_DESCRIPTION("BMP085 SPI bus driver"); | ||
79 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/misc/bmp085.c b/drivers/misc/bmp085.c deleted file mode 100644 index 9b313f7810f5..000000000000 --- a/drivers/misc/bmp085.c +++ /dev/null | |||
@@ -1,506 +0,0 @@ | |||
1 | /* Copyright (c) 2010 Christoph Mair <christoph.mair@gmail.com> | ||
2 | * Copyright (c) 2012 Bosch Sensortec GmbH | ||
3 | * Copyright (c) 2012 Unixphere AB | ||
4 | * | ||
5 | * This driver supports the bmp085 and bmp18x digital barometric pressure | ||
6 | * and temperature sensors from Bosch Sensortec. The datasheets | ||
7 | * are available from their website: | ||
8 | * http://www.bosch-sensortec.com/content/language1/downloads/BST-BMP085-DS000-05.pdf | ||
9 | * http://www.bosch-sensortec.com/content/language1/downloads/BST-BMP180-DS000-07.pdf | ||
10 | * | ||
11 | * A pressure measurement is issued by reading from pressure0_input. | ||
12 | * The return value ranges from 30000 to 110000 pascal with a resulution | ||
13 | * of 1 pascal (0.01 millibar) which enables measurements from 9000m above | ||
14 | * to 500m below sea level. | ||
15 | * | ||
16 | * The temperature can be read from temp0_input. Values range from | ||
17 | * -400 to 850 representing the ambient temperature in degree celsius | ||
18 | * multiplied by 10.The resolution is 0.1 celsius. | ||
19 | * | ||
20 | * Because ambient pressure is temperature dependent, a temperature | ||
21 | * measurement will be executed automatically even if the user is reading | ||
22 | * from pressure0_input. This happens if the last temperature measurement | ||
23 | * has been executed more then one second ago. | ||
24 | * | ||
25 | * To decrease RMS noise from pressure measurements, the bmp085 can | ||
26 | * autonomously calculate the average of up to eight samples. This is | ||
27 | * set up by writing to the oversampling sysfs file. Accepted values | ||
28 | * are 0, 1, 2 and 3. 2^x when x is the value written to this file | ||
29 | * specifies the number of samples used to calculate the ambient pressure. | ||
30 | * RMS noise is specified with six pascal (without averaging) and decreases | ||
31 | * down to 3 pascal when using an oversampling setting of 3. | ||
32 | * | ||
33 | * This program is free software; you can redistribute it and/or modify | ||
34 | * it under the terms of the GNU General Public License as published by | ||
35 | * the Free Software Foundation; either version 2 of the License, or | ||
36 | * (at your option) any later version. | ||
37 | * | ||
38 | * This program is distributed in the hope that it will be useful, | ||
39 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
40 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
41 | * GNU General Public License for more details. | ||
42 | * | ||
43 | * You should have received a copy of the GNU General Public License | ||
44 | * along with this program; if not, write to the Free Software | ||
45 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
46 | */ | ||
47 | |||
48 | #include <linux/module.h> | ||
49 | #include <linux/device.h> | ||
50 | #include <linux/slab.h> | ||
51 | #include <linux/of.h> | ||
52 | #include "bmp085.h" | ||
53 | #include <linux/interrupt.h> | ||
54 | #include <linux/completion.h> | ||
55 | #include <linux/gpio.h> | ||
56 | |||
57 | #define BMP085_CHIP_ID 0x55 | ||
58 | #define BMP085_CALIBRATION_DATA_START 0xAA | ||
59 | #define BMP085_CALIBRATION_DATA_LENGTH 11 /* 16 bit values */ | ||
60 | #define BMP085_CHIP_ID_REG 0xD0 | ||
61 | #define BMP085_CTRL_REG 0xF4 | ||
62 | #define BMP085_TEMP_MEASUREMENT 0x2E | ||
63 | #define BMP085_PRESSURE_MEASUREMENT 0x34 | ||
64 | #define BMP085_CONVERSION_REGISTER_MSB 0xF6 | ||
65 | #define BMP085_CONVERSION_REGISTER_LSB 0xF7 | ||
66 | #define BMP085_CONVERSION_REGISTER_XLSB 0xF8 | ||
67 | #define BMP085_TEMP_CONVERSION_TIME 5 | ||
68 | |||
69 | struct bmp085_calibration_data { | ||
70 | s16 AC1, AC2, AC3; | ||
71 | u16 AC4, AC5, AC6; | ||
72 | s16 B1, B2; | ||
73 | s16 MB, MC, MD; | ||
74 | }; | ||
75 | |||
76 | struct bmp085_data { | ||
77 | struct device *dev; | ||
78 | struct regmap *regmap; | ||
79 | struct mutex lock; | ||
80 | struct bmp085_calibration_data calibration; | ||
81 | u8 oversampling_setting; | ||
82 | u32 raw_temperature; | ||
83 | u32 raw_pressure; | ||
84 | u32 temp_measurement_period; | ||
85 | unsigned long last_temp_measurement; | ||
86 | u8 chip_id; | ||
87 | s32 b6; /* calculated temperature correction coefficient */ | ||
88 | int irq; | ||
89 | struct completion done; | ||
90 | }; | ||
91 | |||
92 | static irqreturn_t bmp085_eoc_isr(int irq, void *devid) | ||
93 | { | ||
94 | struct bmp085_data *data = devid; | ||
95 | |||
96 | complete(&data->done); | ||
97 | |||
98 | return IRQ_HANDLED; | ||
99 | } | ||
100 | |||
101 | static s32 bmp085_read_calibration_data(struct bmp085_data *data) | ||
102 | { | ||
103 | u16 tmp[BMP085_CALIBRATION_DATA_LENGTH]; | ||
104 | struct bmp085_calibration_data *cali = &(data->calibration); | ||
105 | s32 status = regmap_bulk_read(data->regmap, | ||
106 | BMP085_CALIBRATION_DATA_START, (u8 *)tmp, | ||
107 | (BMP085_CALIBRATION_DATA_LENGTH << 1)); | ||
108 | if (status < 0) | ||
109 | return status; | ||
110 | |||
111 | cali->AC1 = be16_to_cpu(tmp[0]); | ||
112 | cali->AC2 = be16_to_cpu(tmp[1]); | ||
113 | cali->AC3 = be16_to_cpu(tmp[2]); | ||
114 | cali->AC4 = be16_to_cpu(tmp[3]); | ||
115 | cali->AC5 = be16_to_cpu(tmp[4]); | ||
116 | cali->AC6 = be16_to_cpu(tmp[5]); | ||
117 | cali->B1 = be16_to_cpu(tmp[6]); | ||
118 | cali->B2 = be16_to_cpu(tmp[7]); | ||
119 | cali->MB = be16_to_cpu(tmp[8]); | ||
120 | cali->MC = be16_to_cpu(tmp[9]); | ||
121 | cali->MD = be16_to_cpu(tmp[10]); | ||
122 | return 0; | ||
123 | } | ||
124 | |||
125 | static s32 bmp085_update_raw_temperature(struct bmp085_data *data) | ||
126 | { | ||
127 | u16 tmp; | ||
128 | s32 status; | ||
129 | |||
130 | mutex_lock(&data->lock); | ||
131 | |||
132 | init_completion(&data->done); | ||
133 | |||
134 | status = regmap_write(data->regmap, BMP085_CTRL_REG, | ||
135 | BMP085_TEMP_MEASUREMENT); | ||
136 | if (status < 0) { | ||
137 | dev_err(data->dev, | ||
138 | "Error while requesting temperature measurement.\n"); | ||
139 | goto exit; | ||
140 | } | ||
141 | wait_for_completion_timeout(&data->done, 1 + msecs_to_jiffies( | ||
142 | BMP085_TEMP_CONVERSION_TIME)); | ||
143 | |||
144 | status = regmap_bulk_read(data->regmap, BMP085_CONVERSION_REGISTER_MSB, | ||
145 | &tmp, sizeof(tmp)); | ||
146 | if (status < 0) { | ||
147 | dev_err(data->dev, | ||
148 | "Error while reading temperature measurement result\n"); | ||
149 | goto exit; | ||
150 | } | ||
151 | data->raw_temperature = be16_to_cpu(tmp); | ||
152 | data->last_temp_measurement = jiffies; | ||
153 | status = 0; /* everything ok, return 0 */ | ||
154 | |||
155 | exit: | ||
156 | mutex_unlock(&data->lock); | ||
157 | return status; | ||
158 | } | ||
159 | |||
160 | static s32 bmp085_update_raw_pressure(struct bmp085_data *data) | ||
161 | { | ||
162 | u32 tmp = 0; | ||
163 | s32 status; | ||
164 | |||
165 | mutex_lock(&data->lock); | ||
166 | |||
167 | init_completion(&data->done); | ||
168 | |||
169 | status = regmap_write(data->regmap, BMP085_CTRL_REG, | ||
170 | BMP085_PRESSURE_MEASUREMENT + | ||
171 | (data->oversampling_setting << 6)); | ||
172 | if (status < 0) { | ||
173 | dev_err(data->dev, | ||
174 | "Error while requesting pressure measurement.\n"); | ||
175 | goto exit; | ||
176 | } | ||
177 | |||
178 | /* wait for the end of conversion */ | ||
179 | wait_for_completion_timeout(&data->done, 1 + msecs_to_jiffies( | ||
180 | 2+(3 << data->oversampling_setting))); | ||
181 | /* copy data into a u32 (4 bytes), but skip the first byte. */ | ||
182 | status = regmap_bulk_read(data->regmap, BMP085_CONVERSION_REGISTER_MSB, | ||
183 | ((u8 *)&tmp)+1, 3); | ||
184 | if (status < 0) { | ||
185 | dev_err(data->dev, | ||
186 | "Error while reading pressure measurement results\n"); | ||
187 | goto exit; | ||
188 | } | ||
189 | data->raw_pressure = be32_to_cpu((tmp)); | ||
190 | data->raw_pressure >>= (8-data->oversampling_setting); | ||
191 | status = 0; /* everything ok, return 0 */ | ||
192 | |||
193 | exit: | ||
194 | mutex_unlock(&data->lock); | ||
195 | return status; | ||
196 | } | ||
197 | |||
198 | /* | ||
199 | * This function starts the temperature measurement and returns the value | ||
200 | * in tenth of a degree celsius. | ||
201 | */ | ||
202 | static s32 bmp085_get_temperature(struct bmp085_data *data, int *temperature) | ||
203 | { | ||
204 | struct bmp085_calibration_data *cali = &data->calibration; | ||
205 | long x1, x2; | ||
206 | int status; | ||
207 | |||
208 | status = bmp085_update_raw_temperature(data); | ||
209 | if (status < 0) | ||
210 | goto exit; | ||
211 | |||
212 | x1 = ((data->raw_temperature - cali->AC6) * cali->AC5) >> 15; | ||
213 | x2 = (cali->MC << 11) / (x1 + cali->MD); | ||
214 | data->b6 = x1 + x2 - 4000; | ||
215 | /* if NULL just update b6. Used for pressure only measurements */ | ||
216 | if (temperature != NULL) | ||
217 | *temperature = (x1+x2+8) >> 4; | ||
218 | |||
219 | exit: | ||
220 | return status; | ||
221 | } | ||
222 | |||
223 | /* | ||
224 | * This function starts the pressure measurement and returns the value | ||
225 | * in millibar. Since the pressure depends on the ambient temperature, | ||
226 | * a temperature measurement is executed according to the given temperature | ||
227 | * measurement period (default is 1 sec boundary). This period could vary | ||
228 | * and needs to be adjusted according to the sensor environment, i.e. if big | ||
229 | * temperature variations then the temperature needs to be read out often. | ||
230 | */ | ||
231 | static s32 bmp085_get_pressure(struct bmp085_data *data, int *pressure) | ||
232 | { | ||
233 | struct bmp085_calibration_data *cali = &data->calibration; | ||
234 | s32 x1, x2, x3, b3; | ||
235 | u32 b4, b7; | ||
236 | s32 p; | ||
237 | int status; | ||
238 | |||
239 | /* alt least every second force an update of the ambient temperature */ | ||
240 | if ((data->last_temp_measurement == 0) || | ||
241 | time_is_before_jiffies(data->last_temp_measurement + 1*HZ)) { | ||
242 | status = bmp085_get_temperature(data, NULL); | ||
243 | if (status < 0) | ||
244 | return status; | ||
245 | } | ||
246 | |||
247 | status = bmp085_update_raw_pressure(data); | ||
248 | if (status < 0) | ||
249 | return status; | ||
250 | |||
251 | x1 = (data->b6 * data->b6) >> 12; | ||
252 | x1 *= cali->B2; | ||
253 | x1 >>= 11; | ||
254 | |||
255 | x2 = cali->AC2 * data->b6; | ||
256 | x2 >>= 11; | ||
257 | |||
258 | x3 = x1 + x2; | ||
259 | |||
260 | b3 = (((((s32)cali->AC1) * 4 + x3) << data->oversampling_setting) + 2); | ||
261 | b3 >>= 2; | ||
262 | |||
263 | x1 = (cali->AC3 * data->b6) >> 13; | ||
264 | x2 = (cali->B1 * ((data->b6 * data->b6) >> 12)) >> 16; | ||
265 | x3 = (x1 + x2 + 2) >> 2; | ||
266 | b4 = (cali->AC4 * (u32)(x3 + 32768)) >> 15; | ||
267 | |||
268 | b7 = ((u32)data->raw_pressure - b3) * | ||
269 | (50000 >> data->oversampling_setting); | ||
270 | p = ((b7 < 0x80000000) ? ((b7 << 1) / b4) : ((b7 / b4) * 2)); | ||
271 | |||
272 | x1 = p >> 8; | ||
273 | x1 *= x1; | ||
274 | x1 = (x1 * 3038) >> 16; | ||
275 | x2 = (-7357 * p) >> 16; | ||
276 | p += (x1 + x2 + 3791) >> 4; | ||
277 | |||
278 | *pressure = p; | ||
279 | |||
280 | return 0; | ||
281 | } | ||
282 | |||
283 | /* | ||
284 | * This function sets the chip-internal oversampling. Valid values are 0..3. | ||
285 | * The chip will use 2^oversampling samples for internal averaging. | ||
286 | * This influences the measurement time and the accuracy; larger values | ||
287 | * increase both. The datasheet gives an overview on how measurement time, | ||
288 | * accuracy and noise correlate. | ||
289 | */ | ||
290 | static void bmp085_set_oversampling(struct bmp085_data *data, | ||
291 | unsigned char oversampling) | ||
292 | { | ||
293 | if (oversampling > 3) | ||
294 | oversampling = 3; | ||
295 | data->oversampling_setting = oversampling; | ||
296 | } | ||
297 | |||
298 | /* | ||
299 | * Returns the currently selected oversampling. Range: 0..3 | ||
300 | */ | ||
301 | static unsigned char bmp085_get_oversampling(struct bmp085_data *data) | ||
302 | { | ||
303 | return data->oversampling_setting; | ||
304 | } | ||
305 | |||
306 | /* sysfs callbacks */ | ||
307 | static ssize_t set_oversampling(struct device *dev, | ||
308 | struct device_attribute *attr, | ||
309 | const char *buf, size_t count) | ||
310 | { | ||
311 | struct bmp085_data *data = dev_get_drvdata(dev); | ||
312 | unsigned long oversampling; | ||
313 | int err = kstrtoul(buf, 10, &oversampling); | ||
314 | |||
315 | if (err == 0) { | ||
316 | mutex_lock(&data->lock); | ||
317 | bmp085_set_oversampling(data, oversampling); | ||
318 | mutex_unlock(&data->lock); | ||
319 | return count; | ||
320 | } | ||
321 | |||
322 | return err; | ||
323 | } | ||
324 | |||
325 | static ssize_t show_oversampling(struct device *dev, | ||
326 | struct device_attribute *attr, char *buf) | ||
327 | { | ||
328 | struct bmp085_data *data = dev_get_drvdata(dev); | ||
329 | |||
330 | return sprintf(buf, "%u\n", bmp085_get_oversampling(data)); | ||
331 | } | ||
332 | static DEVICE_ATTR(oversampling, S_IWUSR | S_IRUGO, | ||
333 | show_oversampling, set_oversampling); | ||
334 | |||
335 | |||
336 | static ssize_t show_temperature(struct device *dev, | ||
337 | struct device_attribute *attr, char *buf) | ||
338 | { | ||
339 | int temperature; | ||
340 | int status; | ||
341 | struct bmp085_data *data = dev_get_drvdata(dev); | ||
342 | |||
343 | status = bmp085_get_temperature(data, &temperature); | ||
344 | if (status < 0) | ||
345 | return status; | ||
346 | else | ||
347 | return sprintf(buf, "%d\n", temperature); | ||
348 | } | ||
349 | static DEVICE_ATTR(temp0_input, S_IRUGO, show_temperature, NULL); | ||
350 | |||
351 | |||
352 | static ssize_t show_pressure(struct device *dev, | ||
353 | struct device_attribute *attr, char *buf) | ||
354 | { | ||
355 | int pressure; | ||
356 | int status; | ||
357 | struct bmp085_data *data = dev_get_drvdata(dev); | ||
358 | |||
359 | status = bmp085_get_pressure(data, &pressure); | ||
360 | if (status < 0) | ||
361 | return status; | ||
362 | else | ||
363 | return sprintf(buf, "%d\n", pressure); | ||
364 | } | ||
365 | static DEVICE_ATTR(pressure0_input, S_IRUGO, show_pressure, NULL); | ||
366 | |||
367 | |||
368 | static struct attribute *bmp085_attributes[] = { | ||
369 | &dev_attr_temp0_input.attr, | ||
370 | &dev_attr_pressure0_input.attr, | ||
371 | &dev_attr_oversampling.attr, | ||
372 | NULL | ||
373 | }; | ||
374 | |||
375 | static const struct attribute_group bmp085_attr_group = { | ||
376 | .attrs = bmp085_attributes, | ||
377 | }; | ||
378 | |||
379 | int bmp085_detect(struct device *dev) | ||
380 | { | ||
381 | struct bmp085_data *data = dev_get_drvdata(dev); | ||
382 | unsigned int id; | ||
383 | int ret; | ||
384 | |||
385 | ret = regmap_read(data->regmap, BMP085_CHIP_ID_REG, &id); | ||
386 | if (ret < 0) | ||
387 | return ret; | ||
388 | |||
389 | if (id != data->chip_id) | ||
390 | return -ENODEV; | ||
391 | |||
392 | return 0; | ||
393 | } | ||
394 | EXPORT_SYMBOL_GPL(bmp085_detect); | ||
395 | |||
396 | static void bmp085_get_of_properties(struct bmp085_data *data) | ||
397 | { | ||
398 | #ifdef CONFIG_OF | ||
399 | struct device_node *np = data->dev->of_node; | ||
400 | u32 prop; | ||
401 | |||
402 | if (!np) | ||
403 | return; | ||
404 | |||
405 | if (!of_property_read_u32(np, "chip-id", &prop)) | ||
406 | data->chip_id = prop & 0xff; | ||
407 | |||
408 | if (!of_property_read_u32(np, "temp-measurement-period", &prop)) | ||
409 | data->temp_measurement_period = (prop/100)*HZ; | ||
410 | |||
411 | if (!of_property_read_u32(np, "default-oversampling", &prop)) | ||
412 | data->oversampling_setting = prop & 0xff; | ||
413 | #endif | ||
414 | } | ||
415 | |||
416 | static int bmp085_init_client(struct bmp085_data *data) | ||
417 | { | ||
418 | int status = bmp085_read_calibration_data(data); | ||
419 | |||
420 | if (status < 0) | ||
421 | return status; | ||
422 | |||
423 | /* default settings */ | ||
424 | data->chip_id = BMP085_CHIP_ID; | ||
425 | data->last_temp_measurement = 0; | ||
426 | data->temp_measurement_period = 1*HZ; | ||
427 | data->oversampling_setting = 3; | ||
428 | |||
429 | bmp085_get_of_properties(data); | ||
430 | |||
431 | mutex_init(&data->lock); | ||
432 | |||
433 | return 0; | ||
434 | } | ||
435 | |||
436 | struct regmap_config bmp085_regmap_config = { | ||
437 | .reg_bits = 8, | ||
438 | .val_bits = 8 | ||
439 | }; | ||
440 | EXPORT_SYMBOL_GPL(bmp085_regmap_config); | ||
441 | |||
442 | int bmp085_probe(struct device *dev, struct regmap *regmap, int irq) | ||
443 | { | ||
444 | struct bmp085_data *data; | ||
445 | int err = 0; | ||
446 | |||
447 | data = kzalloc(sizeof(struct bmp085_data), GFP_KERNEL); | ||
448 | if (!data) { | ||
449 | err = -ENOMEM; | ||
450 | goto exit; | ||
451 | } | ||
452 | |||
453 | dev_set_drvdata(dev, data); | ||
454 | data->dev = dev; | ||
455 | data->regmap = regmap; | ||
456 | data->irq = irq; | ||
457 | |||
458 | if (data->irq > 0) { | ||
459 | err = devm_request_irq(dev, data->irq, bmp085_eoc_isr, | ||
460 | IRQF_TRIGGER_RISING, "bmp085", | ||
461 | data); | ||
462 | if (err < 0) | ||
463 | goto exit_free; | ||
464 | } | ||
465 | |||
466 | /* Initialize the BMP085 chip */ | ||
467 | err = bmp085_init_client(data); | ||
468 | if (err < 0) | ||
469 | goto exit_free; | ||
470 | |||
471 | err = bmp085_detect(dev); | ||
472 | if (err < 0) { | ||
473 | dev_err(dev, "%s: chip_id failed!\n", BMP085_NAME); | ||
474 | goto exit_free; | ||
475 | } | ||
476 | |||
477 | /* Register sysfs hooks */ | ||
478 | err = sysfs_create_group(&dev->kobj, &bmp085_attr_group); | ||
479 | if (err) | ||
480 | goto exit_free; | ||
481 | |||
482 | dev_info(dev, "Successfully initialized %s!\n", BMP085_NAME); | ||
483 | |||
484 | return 0; | ||
485 | |||
486 | exit_free: | ||
487 | kfree(data); | ||
488 | exit: | ||
489 | return err; | ||
490 | } | ||
491 | EXPORT_SYMBOL_GPL(bmp085_probe); | ||
492 | |||
493 | int bmp085_remove(struct device *dev) | ||
494 | { | ||
495 | struct bmp085_data *data = dev_get_drvdata(dev); | ||
496 | |||
497 | sysfs_remove_group(&data->dev->kobj, &bmp085_attr_group); | ||
498 | kfree(data); | ||
499 | |||
500 | return 0; | ||
501 | } | ||
502 | EXPORT_SYMBOL_GPL(bmp085_remove); | ||
503 | |||
504 | MODULE_AUTHOR("Christoph Mair <christoph.mair@gmail.com>"); | ||
505 | MODULE_DESCRIPTION("BMP085 driver"); | ||
506 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/misc/bmp085.h b/drivers/misc/bmp085.h deleted file mode 100644 index 8b8e3b1f5ca5..000000000000 --- a/drivers/misc/bmp085.h +++ /dev/null | |||
@@ -1,33 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2012 Bosch Sensortec GmbH | ||
3 | * Copyright (c) 2012 Unixphere AB | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
18 | */ | ||
19 | |||
20 | #ifndef _BMP085_H | ||
21 | #define _BMP085_H | ||
22 | |||
23 | #include <linux/regmap.h> | ||
24 | |||
25 | #define BMP085_NAME "bmp085" | ||
26 | |||
27 | extern struct regmap_config bmp085_regmap_config; | ||
28 | |||
29 | int bmp085_probe(struct device *dev, struct regmap *regmap, int irq); | ||
30 | int bmp085_remove(struct device *dev); | ||
31 | int bmp085_detect(struct device *dev); | ||
32 | |||
33 | #endif | ||
diff --git a/drivers/misc/eeprom/at25.c b/drivers/misc/eeprom/at25.c index 2c6c7c8e3ead..5afe4cd16569 100644 --- a/drivers/misc/eeprom/at25.c +++ b/drivers/misc/eeprom/at25.c | |||
@@ -121,9 +121,8 @@ static int at25_ee_read(void *priv, unsigned int offset, | |||
121 | * this chip is clocked very slowly | 121 | * this chip is clocked very slowly |
122 | */ | 122 | */ |
123 | status = spi_sync(at25->spi, &m); | 123 | status = spi_sync(at25->spi, &m); |
124 | dev_dbg(&at25->spi->dev, | 124 | dev_dbg(&at25->spi->dev, "read %zu bytes at %d --> %zd\n", |
125 | "read %Zd bytes at %d --> %d\n", | 125 | count, offset, status); |
126 | count, offset, (int) status); | ||
127 | 126 | ||
128 | mutex_unlock(&at25->lock); | 127 | mutex_unlock(&at25->lock); |
129 | return status; | 128 | return status; |
@@ -167,8 +166,7 @@ static int at25_ee_write(void *priv, unsigned int off, void *val, size_t count) | |||
167 | *cp = AT25_WREN; | 166 | *cp = AT25_WREN; |
168 | status = spi_write(at25->spi, cp, 1); | 167 | status = spi_write(at25->spi, cp, 1); |
169 | if (status < 0) { | 168 | if (status < 0) { |
170 | dev_dbg(&at25->spi->dev, "WREN --> %d\n", | 169 | dev_dbg(&at25->spi->dev, "WREN --> %d\n", status); |
171 | (int) status); | ||
172 | break; | 170 | break; |
173 | } | 171 | } |
174 | 172 | ||
@@ -196,9 +194,8 @@ static int at25_ee_write(void *priv, unsigned int off, void *val, size_t count) | |||
196 | memcpy(cp, buf, segment); | 194 | memcpy(cp, buf, segment); |
197 | status = spi_write(at25->spi, bounce, | 195 | status = spi_write(at25->spi, bounce, |
198 | segment + at25->addrlen + 1); | 196 | segment + at25->addrlen + 1); |
199 | dev_dbg(&at25->spi->dev, | 197 | dev_dbg(&at25->spi->dev, "write %u bytes at %u --> %d\n", |
200 | "write %u bytes at %u --> %d\n", | 198 | segment, offset, status); |
201 | segment, offset, (int) status); | ||
202 | if (status < 0) | 199 | if (status < 0) |
203 | break; | 200 | break; |
204 | 201 | ||
@@ -225,8 +222,7 @@ static int at25_ee_write(void *priv, unsigned int off, void *val, size_t count) | |||
225 | 222 | ||
226 | if ((sr < 0) || (sr & AT25_SR_nRDY)) { | 223 | if ((sr < 0) || (sr & AT25_SR_nRDY)) { |
227 | dev_err(&at25->spi->dev, | 224 | dev_err(&at25->spi->dev, |
228 | "write %d bytes offset %d, " | 225 | "write %u bytes offset %u, timeout after %u msecs\n", |
229 | "timeout after %u msecs\n", | ||
230 | segment, offset, | 226 | segment, offset, |
231 | jiffies_to_msecs(jiffies - | 227 | jiffies_to_msecs(jiffies - |
232 | (timeout - EE_TIMEOUT))); | 228 | (timeout - EE_TIMEOUT))); |
@@ -368,9 +364,7 @@ static int at25_probe(struct spi_device *spi) | |||
368 | return PTR_ERR(at25->nvmem); | 364 | return PTR_ERR(at25->nvmem); |
369 | 365 | ||
370 | dev_info(&spi->dev, "%d %s %s eeprom%s, pagesize %u\n", | 366 | dev_info(&spi->dev, "%d %s %s eeprom%s, pagesize %u\n", |
371 | (chip.byte_len < 1024) | 367 | (chip.byte_len < 1024) ? chip.byte_len : (chip.byte_len / 1024), |
372 | ? chip.byte_len | ||
373 | : (chip.byte_len / 1024), | ||
374 | (chip.byte_len < 1024) ? "Byte" : "KByte", | 368 | (chip.byte_len < 1024) ? "Byte" : "KByte", |
375 | at25->chip.name, | 369 | at25->chip.name, |
376 | (chip.flags & EE_READONLY) ? " (readonly)" : "", | 370 | (chip.flags & EE_READONLY) ? " (readonly)" : "", |
diff --git a/drivers/misc/genwqe/card_base.c b/drivers/misc/genwqe/card_base.c index a70b853fa2c9..6c1f49a85023 100644 --- a/drivers/misc/genwqe/card_base.c +++ b/drivers/misc/genwqe/card_base.c | |||
@@ -1351,6 +1351,19 @@ static struct pci_driver genwqe_driver = { | |||
1351 | }; | 1351 | }; |
1352 | 1352 | ||
1353 | /** | 1353 | /** |
1354 | * genwqe_devnode() - Set default access mode for genwqe devices. | ||
1355 | * | ||
1356 | * Default mode should be rw for everybody. Do not change default | ||
1357 | * device name. | ||
1358 | */ | ||
1359 | static char *genwqe_devnode(struct device *dev, umode_t *mode) | ||
1360 | { | ||
1361 | if (mode) | ||
1362 | *mode = 0666; | ||
1363 | return NULL; | ||
1364 | } | ||
1365 | |||
1366 | /** | ||
1354 | * genwqe_init_module() - Driver registration and initialization | 1367 | * genwqe_init_module() - Driver registration and initialization |
1355 | */ | 1368 | */ |
1356 | static int __init genwqe_init_module(void) | 1369 | static int __init genwqe_init_module(void) |
@@ -1363,6 +1376,8 @@ static int __init genwqe_init_module(void) | |||
1363 | return -ENOMEM; | 1376 | return -ENOMEM; |
1364 | } | 1377 | } |
1365 | 1378 | ||
1379 | class_genwqe->devnode = genwqe_devnode; | ||
1380 | |||
1366 | debugfs_genwqe = debugfs_create_dir(GENWQE_DEVNAME, NULL); | 1381 | debugfs_genwqe = debugfs_create_dir(GENWQE_DEVNAME, NULL); |
1367 | if (!debugfs_genwqe) { | 1382 | if (!debugfs_genwqe) { |
1368 | rc = -ENOMEM; | 1383 | rc = -ENOMEM; |
diff --git a/drivers/misc/genwqe/card_ddcb.c b/drivers/misc/genwqe/card_ddcb.c index 353ee0cc733d..ddfeefe39540 100644 --- a/drivers/misc/genwqe/card_ddcb.c +++ b/drivers/misc/genwqe/card_ddcb.c | |||
@@ -1048,8 +1048,6 @@ static int setup_ddcb_queue(struct genwqe_dev *cd, struct ddcb_queue *queue) | |||
1048 | "[%s] **err: could not allocate DDCB **\n", __func__); | 1048 | "[%s] **err: could not allocate DDCB **\n", __func__); |
1049 | return -ENOMEM; | 1049 | return -ENOMEM; |
1050 | } | 1050 | } |
1051 | memset(queue->ddcb_vaddr, 0, queue_size); | ||
1052 | |||
1053 | queue->ddcb_req = kzalloc(sizeof(struct ddcb_requ *) * | 1051 | queue->ddcb_req = kzalloc(sizeof(struct ddcb_requ *) * |
1054 | queue->ddcb_max, GFP_KERNEL); | 1052 | queue->ddcb_max, GFP_KERNEL); |
1055 | if (!queue->ddcb_req) { | 1053 | if (!queue->ddcb_req) { |
diff --git a/drivers/misc/genwqe/card_utils.c b/drivers/misc/genwqe/card_utils.c index 222367cc8c81..8a679ecc8fd1 100644 --- a/drivers/misc/genwqe/card_utils.c +++ b/drivers/misc/genwqe/card_utils.c | |||
@@ -220,8 +220,8 @@ void *__genwqe_alloc_consistent(struct genwqe_dev *cd, size_t size, | |||
220 | if (get_order(size) > MAX_ORDER) | 220 | if (get_order(size) > MAX_ORDER) |
221 | return NULL; | 221 | return NULL; |
222 | 222 | ||
223 | return dma_alloc_coherent(&cd->pci_dev->dev, size, dma_handle, | 223 | return dma_zalloc_coherent(&cd->pci_dev->dev, size, dma_handle, |
224 | GFP_KERNEL); | 224 | GFP_KERNEL); |
225 | } | 225 | } |
226 | 226 | ||
227 | void __genwqe_free_consistent(struct genwqe_dev *cd, size_t size, | 227 | void __genwqe_free_consistent(struct genwqe_dev *cd, size_t size, |
diff --git a/drivers/misc/hpilo.c b/drivers/misc/hpilo.c index d6a901cd4222..fea8ff40440f 100644 --- a/drivers/misc/hpilo.c +++ b/drivers/misc/hpilo.c | |||
@@ -688,7 +688,8 @@ static void ilo_unmap_device(struct pci_dev *pdev, struct ilo_hwinfo *hw) | |||
688 | 688 | ||
689 | static int ilo_map_device(struct pci_dev *pdev, struct ilo_hwinfo *hw) | 689 | static int ilo_map_device(struct pci_dev *pdev, struct ilo_hwinfo *hw) |
690 | { | 690 | { |
691 | int error = -ENOMEM; | 691 | int bar; |
692 | unsigned long off; | ||
692 | 693 | ||
693 | /* map the memory mapped i/o registers */ | 694 | /* map the memory mapped i/o registers */ |
694 | hw->mmio_vaddr = pci_iomap(pdev, 1, 0); | 695 | hw->mmio_vaddr = pci_iomap(pdev, 1, 0); |
@@ -698,7 +699,15 @@ static int ilo_map_device(struct pci_dev *pdev, struct ilo_hwinfo *hw) | |||
698 | } | 699 | } |
699 | 700 | ||
700 | /* map the adapter shared memory region */ | 701 | /* map the adapter shared memory region */ |
701 | hw->ram_vaddr = pci_iomap(pdev, 2, max_ccb * ILOHW_CCB_SZ); | 702 | if (pdev->subsystem_device == 0x00E4) { |
703 | bar = 5; | ||
704 | /* Last 8k is reserved for CCBs */ | ||
705 | off = pci_resource_len(pdev, bar) - 0x2000; | ||
706 | } else { | ||
707 | bar = 2; | ||
708 | off = 0; | ||
709 | } | ||
710 | hw->ram_vaddr = pci_iomap_range(pdev, bar, off, max_ccb * ILOHW_CCB_SZ); | ||
702 | if (hw->ram_vaddr == NULL) { | 711 | if (hw->ram_vaddr == NULL) { |
703 | dev_err(&pdev->dev, "Error mapping shared mem\n"); | 712 | dev_err(&pdev->dev, "Error mapping shared mem\n"); |
704 | goto mmio_free; | 713 | goto mmio_free; |
@@ -717,7 +726,7 @@ ram_free: | |||
717 | mmio_free: | 726 | mmio_free: |
718 | pci_iounmap(pdev, hw->mmio_vaddr); | 727 | pci_iounmap(pdev, hw->mmio_vaddr); |
719 | out: | 728 | out: |
720 | return error; | 729 | return -ENOMEM; |
721 | } | 730 | } |
722 | 731 | ||
723 | static void ilo_remove(struct pci_dev *pdev) | 732 | static void ilo_remove(struct pci_dev *pdev) |
@@ -899,7 +908,7 @@ static void __exit ilo_exit(void) | |||
899 | class_destroy(ilo_class); | 908 | class_destroy(ilo_class); |
900 | } | 909 | } |
901 | 910 | ||
902 | MODULE_VERSION("1.4.1"); | 911 | MODULE_VERSION("1.5.0"); |
903 | MODULE_ALIAS(ILO_NAME); | 912 | MODULE_ALIAS(ILO_NAME); |
904 | MODULE_DESCRIPTION(ILO_NAME); | 913 | MODULE_DESCRIPTION(ILO_NAME); |
905 | MODULE_AUTHOR("David Altobelli <david.altobelli@hpe.com>"); | 914 | MODULE_AUTHOR("David Altobelli <david.altobelli@hpe.com>"); |
diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c index a039a5df6f21..7ae89b4a21d5 100644 --- a/drivers/misc/mei/amthif.c +++ b/drivers/misc/mei/amthif.c | |||
@@ -47,7 +47,6 @@ const uuid_le mei_amthif_guid = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d, | |||
47 | void mei_amthif_reset_params(struct mei_device *dev) | 47 | void mei_amthif_reset_params(struct mei_device *dev) |
48 | { | 48 | { |
49 | /* reset iamthif parameters. */ | 49 | /* reset iamthif parameters. */ |
50 | dev->iamthif_current_cb = NULL; | ||
51 | dev->iamthif_canceled = false; | 50 | dev->iamthif_canceled = false; |
52 | dev->iamthif_state = MEI_IAMTHIF_IDLE; | 51 | dev->iamthif_state = MEI_IAMTHIF_IDLE; |
53 | dev->iamthif_stall_timer = 0; | 52 | dev->iamthif_stall_timer = 0; |
@@ -67,8 +66,12 @@ int mei_amthif_host_init(struct mei_device *dev, struct mei_me_client *me_cl) | |||
67 | struct mei_cl *cl = &dev->iamthif_cl; | 66 | struct mei_cl *cl = &dev->iamthif_cl; |
68 | int ret; | 67 | int ret; |
69 | 68 | ||
70 | if (mei_cl_is_connected(cl)) | 69 | mutex_lock(&dev->device_lock); |
71 | return 0; | 70 | |
71 | if (mei_cl_is_connected(cl)) { | ||
72 | ret = 0; | ||
73 | goto out; | ||
74 | } | ||
72 | 75 | ||
73 | dev->iamthif_state = MEI_IAMTHIF_IDLE; | 76 | dev->iamthif_state = MEI_IAMTHIF_IDLE; |
74 | 77 | ||
@@ -77,179 +80,37 @@ int mei_amthif_host_init(struct mei_device *dev, struct mei_me_client *me_cl) | |||
77 | ret = mei_cl_link(cl); | 80 | ret = mei_cl_link(cl); |
78 | if (ret < 0) { | 81 | if (ret < 0) { |
79 | dev_err(dev->dev, "amthif: failed cl_link %d\n", ret); | 82 | dev_err(dev->dev, "amthif: failed cl_link %d\n", ret); |
80 | return ret; | 83 | goto out; |
81 | } | 84 | } |
82 | 85 | ||
83 | ret = mei_cl_connect(cl, me_cl, NULL); | 86 | ret = mei_cl_connect(cl, me_cl, NULL); |
84 | 87 | ||
85 | return ret; | ||
86 | } | ||
87 | |||
88 | /** | ||
89 | * mei_amthif_read - read data from AMTHIF client | ||
90 | * | ||
91 | * @dev: the device structure | ||
92 | * @file: pointer to file object | ||
93 | * @ubuf: pointer to user data in user space | ||
94 | * @length: data length to read | ||
95 | * @offset: data read offset | ||
96 | * | ||
97 | * Locking: called under "dev->device_lock" lock | ||
98 | * | ||
99 | * Return: | ||
100 | * returned data length on success, | ||
101 | * zero if no data to read, | ||
102 | * negative on failure. | ||
103 | */ | ||
104 | int mei_amthif_read(struct mei_device *dev, struct file *file, | ||
105 | char __user *ubuf, size_t length, loff_t *offset) | ||
106 | { | ||
107 | struct mei_cl *cl = file->private_data; | ||
108 | struct mei_cl_cb *cb; | ||
109 | int rets; | ||
110 | int wait_ret; | ||
111 | |||
112 | dev_dbg(dev->dev, "checking amthif data\n"); | ||
113 | cb = mei_cl_read_cb(cl, file); | ||
114 | |||
115 | /* Check for if we can block or not*/ | ||
116 | if (cb == NULL && file->f_flags & O_NONBLOCK) | ||
117 | return -EAGAIN; | ||
118 | |||
119 | |||
120 | dev_dbg(dev->dev, "waiting for amthif data\n"); | ||
121 | while (cb == NULL) { | ||
122 | /* unlock the Mutex */ | ||
123 | mutex_unlock(&dev->device_lock); | ||
124 | |||
125 | wait_ret = wait_event_interruptible(cl->rx_wait, | ||
126 | !list_empty(&cl->rd_completed) || | ||
127 | !mei_cl_is_connected(cl)); | ||
128 | |||
129 | /* Locking again the Mutex */ | ||
130 | mutex_lock(&dev->device_lock); | ||
131 | |||
132 | if (wait_ret) | ||
133 | return -ERESTARTSYS; | ||
134 | |||
135 | if (!mei_cl_is_connected(cl)) { | ||
136 | rets = -EBUSY; | ||
137 | goto out; | ||
138 | } | ||
139 | |||
140 | cb = mei_cl_read_cb(cl, file); | ||
141 | } | ||
142 | |||
143 | if (cb->status) { | ||
144 | rets = cb->status; | ||
145 | dev_dbg(dev->dev, "read operation failed %d\n", rets); | ||
146 | goto free; | ||
147 | } | ||
148 | |||
149 | dev_dbg(dev->dev, "Got amthif data\n"); | ||
150 | /* if the whole message will fit remove it from the list */ | ||
151 | if (cb->buf_idx >= *offset && length >= (cb->buf_idx - *offset)) | ||
152 | list_del_init(&cb->list); | ||
153 | else if (cb->buf_idx <= *offset) { | ||
154 | /* end of the message has been reached */ | ||
155 | list_del_init(&cb->list); | ||
156 | rets = 0; | ||
157 | goto free; | ||
158 | } | ||
159 | /* else means that not full buffer will be read and do not | ||
160 | * remove message from deletion list | ||
161 | */ | ||
162 | |||
163 | dev_dbg(dev->dev, "amthif cb->buf.size - %zu cb->buf_idx - %zu\n", | ||
164 | cb->buf.size, cb->buf_idx); | ||
165 | |||
166 | /* length is being truncated to PAGE_SIZE, however, | ||
167 | * the buf_idx may point beyond */ | ||
168 | length = min_t(size_t, length, (cb->buf_idx - *offset)); | ||
169 | |||
170 | if (copy_to_user(ubuf, cb->buf.data + *offset, length)) { | ||
171 | dev_dbg(dev->dev, "failed to copy data to userland\n"); | ||
172 | rets = -EFAULT; | ||
173 | } else { | ||
174 | rets = length; | ||
175 | if ((*offset + length) < cb->buf_idx) { | ||
176 | *offset += length; | ||
177 | goto out; | ||
178 | } | ||
179 | } | ||
180 | free: | ||
181 | dev_dbg(dev->dev, "free amthif cb memory.\n"); | ||
182 | *offset = 0; | ||
183 | mei_io_cb_free(cb); | ||
184 | out: | 88 | out: |
185 | return rets; | 89 | mutex_unlock(&dev->device_lock); |
90 | return ret; | ||
186 | } | 91 | } |
187 | 92 | ||
188 | /** | 93 | /** |
189 | * mei_amthif_read_start - queue message for sending read credential | 94 | * mei_amthif_read_start - queue message for sending read credential |
190 | * | 95 | * |
191 | * @cl: host client | 96 | * @cl: host client |
192 | * @file: file pointer of message recipient | 97 | * @fp: file pointer of message recipient |
193 | * | 98 | * |
194 | * Return: 0 on success, <0 on failure. | 99 | * Return: 0 on success, <0 on failure. |
195 | */ | 100 | */ |
196 | static int mei_amthif_read_start(struct mei_cl *cl, const struct file *file) | 101 | static int mei_amthif_read_start(struct mei_cl *cl, const struct file *fp) |
197 | { | 102 | { |
198 | struct mei_device *dev = cl->dev; | 103 | struct mei_device *dev = cl->dev; |
199 | struct mei_cl_cb *cb; | 104 | struct mei_cl_cb *cb; |
200 | int rets; | ||
201 | |||
202 | cb = mei_io_cb_init(cl, MEI_FOP_READ, file); | ||
203 | if (!cb) { | ||
204 | rets = -ENOMEM; | ||
205 | goto err; | ||
206 | } | ||
207 | 105 | ||
208 | rets = mei_io_cb_alloc_buf(cb, mei_cl_mtu(cl)); | 106 | cb = mei_cl_enqueue_ctrl_wr_cb(cl, mei_cl_mtu(cl), MEI_FOP_READ, fp); |
209 | if (rets) | 107 | if (!cb) |
210 | goto err; | 108 | return -ENOMEM; |
211 | 109 | ||
212 | list_add_tail(&cb->list, &dev->ctrl_wr_list.list); | 110 | cl->rx_flow_ctrl_creds++; |
213 | 111 | ||
214 | dev->iamthif_state = MEI_IAMTHIF_READING; | 112 | dev->iamthif_state = MEI_IAMTHIF_READING; |
215 | dev->iamthif_fp = cb->fp; | 113 | cl->fp = cb->fp; |
216 | dev->iamthif_current_cb = cb; | ||
217 | |||
218 | return 0; | ||
219 | err: | ||
220 | mei_io_cb_free(cb); | ||
221 | return rets; | ||
222 | } | ||
223 | |||
224 | /** | ||
225 | * mei_amthif_send_cmd - send amthif command to the ME | ||
226 | * | ||
227 | * @cl: the host client | ||
228 | * @cb: mei call back struct | ||
229 | * | ||
230 | * Return: 0 on success, <0 on failure. | ||
231 | */ | ||
232 | static int mei_amthif_send_cmd(struct mei_cl *cl, struct mei_cl_cb *cb) | ||
233 | { | ||
234 | struct mei_device *dev; | ||
235 | int ret; | ||
236 | |||
237 | if (!cl->dev || !cb) | ||
238 | return -ENODEV; | ||
239 | |||
240 | dev = cl->dev; | ||
241 | |||
242 | dev->iamthif_state = MEI_IAMTHIF_WRITING; | ||
243 | dev->iamthif_current_cb = cb; | ||
244 | dev->iamthif_fp = cb->fp; | ||
245 | dev->iamthif_canceled = false; | ||
246 | |||
247 | ret = mei_cl_write(cl, cb, false); | ||
248 | if (ret < 0) | ||
249 | return ret; | ||
250 | |||
251 | if (cb->completed) | ||
252 | cb->status = mei_amthif_read_start(cl, cb->fp); | ||
253 | 114 | ||
254 | return 0; | 115 | return 0; |
255 | } | 116 | } |
@@ -265,20 +126,32 @@ int mei_amthif_run_next_cmd(struct mei_device *dev) | |||
265 | { | 126 | { |
266 | struct mei_cl *cl = &dev->iamthif_cl; | 127 | struct mei_cl *cl = &dev->iamthif_cl; |
267 | struct mei_cl_cb *cb; | 128 | struct mei_cl_cb *cb; |
129 | int ret; | ||
268 | 130 | ||
269 | dev->iamthif_canceled = false; | 131 | dev->iamthif_canceled = false; |
270 | dev->iamthif_state = MEI_IAMTHIF_IDLE; | ||
271 | dev->iamthif_fp = NULL; | ||
272 | 132 | ||
273 | dev_dbg(dev->dev, "complete amthif cmd_list cb.\n"); | 133 | dev_dbg(dev->dev, "complete amthif cmd_list cb.\n"); |
274 | 134 | ||
275 | cb = list_first_entry_or_null(&dev->amthif_cmd_list.list, | 135 | cb = list_first_entry_or_null(&dev->amthif_cmd_list.list, |
276 | typeof(*cb), list); | 136 | typeof(*cb), list); |
277 | if (!cb) | 137 | if (!cb) { |
138 | dev->iamthif_state = MEI_IAMTHIF_IDLE; | ||
139 | cl->fp = NULL; | ||
278 | return 0; | 140 | return 0; |
141 | } | ||
279 | 142 | ||
280 | list_del_init(&cb->list); | 143 | list_del_init(&cb->list); |
281 | return mei_amthif_send_cmd(cl, cb); | 144 | dev->iamthif_state = MEI_IAMTHIF_WRITING; |
145 | cl->fp = cb->fp; | ||
146 | |||
147 | ret = mei_cl_write(cl, cb, false); | ||
148 | if (ret < 0) | ||
149 | return ret; | ||
150 | |||
151 | if (cb->completed) | ||
152 | cb->status = mei_amthif_read_start(cl, cb->fp); | ||
153 | |||
154 | return 0; | ||
282 | } | 155 | } |
283 | 156 | ||
284 | /** | 157 | /** |
@@ -299,8 +172,7 @@ int mei_amthif_write(struct mei_cl *cl, struct mei_cl_cb *cb) | |||
299 | /* | 172 | /* |
300 | * The previous request is still in processing, queue this one. | 173 | * The previous request is still in processing, queue this one. |
301 | */ | 174 | */ |
302 | if (dev->iamthif_state > MEI_IAMTHIF_IDLE && | 175 | if (dev->iamthif_state != MEI_IAMTHIF_IDLE) |
303 | dev->iamthif_state < MEI_IAMTHIF_READ_COMPLETE) | ||
304 | return 0; | 176 | return 0; |
305 | 177 | ||
306 | return mei_amthif_run_next_cmd(dev); | 178 | return mei_amthif_run_next_cmd(dev); |
@@ -309,7 +181,6 @@ int mei_amthif_write(struct mei_cl *cl, struct mei_cl_cb *cb) | |||
309 | /** | 181 | /** |
310 | * mei_amthif_poll - the amthif poll function | 182 | * mei_amthif_poll - the amthif poll function |
311 | * | 183 | * |
312 | * @dev: the device structure | ||
313 | * @file: pointer to file structure | 184 | * @file: pointer to file structure |
314 | * @wait: pointer to poll_table structure | 185 | * @wait: pointer to poll_table structure |
315 | * | 186 | * |
@@ -317,26 +188,19 @@ int mei_amthif_write(struct mei_cl *cl, struct mei_cl_cb *cb) | |||
317 | * | 188 | * |
318 | * Locking: called under "dev->device_lock" lock | 189 | * Locking: called under "dev->device_lock" lock |
319 | */ | 190 | */ |
320 | 191 | unsigned int mei_amthif_poll(struct file *file, poll_table *wait) | |
321 | unsigned int mei_amthif_poll(struct mei_device *dev, | ||
322 | struct file *file, poll_table *wait) | ||
323 | { | 192 | { |
193 | struct mei_cl *cl = file->private_data; | ||
194 | struct mei_cl_cb *cb = mei_cl_read_cb(cl, file); | ||
324 | unsigned int mask = 0; | 195 | unsigned int mask = 0; |
325 | 196 | ||
326 | poll_wait(file, &dev->iamthif_cl.rx_wait, wait); | 197 | poll_wait(file, &cl->rx_wait, wait); |
327 | 198 | if (cb) | |
328 | if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE && | ||
329 | dev->iamthif_fp == file) { | ||
330 | |||
331 | mask |= POLLIN | POLLRDNORM; | 199 | mask |= POLLIN | POLLRDNORM; |
332 | mei_amthif_run_next_cmd(dev); | ||
333 | } | ||
334 | 200 | ||
335 | return mask; | 201 | return mask; |
336 | } | 202 | } |
337 | 203 | ||
338 | |||
339 | |||
340 | /** | 204 | /** |
341 | * mei_amthif_irq_write - write iamthif command in irq thread context. | 205 | * mei_amthif_irq_write - write iamthif command in irq thread context. |
342 | * | 206 | * |
@@ -393,7 +257,6 @@ int mei_amthif_irq_read_msg(struct mei_cl *cl, | |||
393 | return 0; | 257 | return 0; |
394 | 258 | ||
395 | dev_dbg(dev->dev, "completed amthif read.\n "); | 259 | dev_dbg(dev->dev, "completed amthif read.\n "); |
396 | dev->iamthif_current_cb = NULL; | ||
397 | dev->iamthif_stall_timer = 0; | 260 | dev->iamthif_stall_timer = 0; |
398 | 261 | ||
399 | return 0; | 262 | return 0; |
@@ -409,115 +272,63 @@ void mei_amthif_complete(struct mei_cl *cl, struct mei_cl_cb *cb) | |||
409 | { | 272 | { |
410 | struct mei_device *dev = cl->dev; | 273 | struct mei_device *dev = cl->dev; |
411 | 274 | ||
412 | if (cb->fop_type == MEI_FOP_WRITE) { | 275 | dev_dbg(dev->dev, "completing amthif call back.\n"); |
276 | switch (cb->fop_type) { | ||
277 | case MEI_FOP_WRITE: | ||
413 | if (!cb->status) { | 278 | if (!cb->status) { |
414 | dev->iamthif_stall_timer = MEI_IAMTHIF_STALL_TIMER; | 279 | dev->iamthif_stall_timer = MEI_IAMTHIF_STALL_TIMER; |
280 | mei_schedule_stall_timer(dev); | ||
415 | mei_io_cb_free(cb); | 281 | mei_io_cb_free(cb); |
416 | return; | 282 | return; |
417 | } | 283 | } |
418 | /* | 284 | dev->iamthif_state = MEI_IAMTHIF_IDLE; |
419 | * in case of error enqueue the write cb to complete read list | 285 | cl->fp = NULL; |
420 | * so it can be propagated to the reader | 286 | if (!dev->iamthif_canceled) { |
421 | */ | 287 | /* |
422 | list_add_tail(&cb->list, &cl->rd_completed); | 288 | * in case of error enqueue the write cb to complete |
423 | wake_up_interruptible(&cl->rx_wait); | 289 | * read list so it can be propagated to the reader |
424 | return; | 290 | */ |
425 | } | 291 | list_add_tail(&cb->list, &cl->rd_completed); |
292 | wake_up_interruptible(&cl->rx_wait); | ||
293 | } else { | ||
294 | mei_io_cb_free(cb); | ||
295 | } | ||
296 | break; | ||
297 | case MEI_FOP_READ: | ||
298 | if (!dev->iamthif_canceled) { | ||
299 | list_add_tail(&cb->list, &cl->rd_completed); | ||
300 | dev_dbg(dev->dev, "amthif read completed\n"); | ||
301 | wake_up_interruptible(&cl->rx_wait); | ||
302 | } else { | ||
303 | mei_io_cb_free(cb); | ||
304 | } | ||
426 | 305 | ||
427 | if (!dev->iamthif_canceled) { | ||
428 | dev->iamthif_state = MEI_IAMTHIF_READ_COMPLETE; | ||
429 | dev->iamthif_stall_timer = 0; | 306 | dev->iamthif_stall_timer = 0; |
430 | list_add_tail(&cb->list, &cl->rd_completed); | ||
431 | dev_dbg(dev->dev, "amthif read completed\n"); | ||
432 | } else { | ||
433 | mei_amthif_run_next_cmd(dev); | 307 | mei_amthif_run_next_cmd(dev); |
308 | break; | ||
309 | default: | ||
310 | WARN_ON(1); | ||
434 | } | 311 | } |
435 | |||
436 | dev_dbg(dev->dev, "completing amthif call back.\n"); | ||
437 | wake_up_interruptible(&cl->rx_wait); | ||
438 | } | 312 | } |
439 | 313 | ||
440 | /** | 314 | /** |
441 | * mei_clear_list - removes all callbacks associated with file | 315 | * mei_clear_list - removes all callbacks associated with file |
442 | * from mei_cb_list | 316 | * from mei_cb_list |
443 | * | 317 | * |
444 | * @dev: device structure. | ||
445 | * @file: file structure | 318 | * @file: file structure |
446 | * @mei_cb_list: callbacks list | 319 | * @mei_cb_list: callbacks list |
447 | * | 320 | * |
448 | * mei_clear_list is called to clear resources associated with file | 321 | * mei_clear_list is called to clear resources associated with file |
449 | * when application calls close function or Ctrl-C was pressed | 322 | * when application calls close function or Ctrl-C was pressed |
450 | * | ||
451 | * Return: true if callback removed from the list, false otherwise | ||
452 | */ | 323 | */ |
453 | static bool mei_clear_list(struct mei_device *dev, | 324 | static void mei_clear_list(const struct file *file, |
454 | const struct file *file, struct list_head *mei_cb_list) | 325 | struct list_head *mei_cb_list) |
455 | { | 326 | { |
456 | struct mei_cl *cl = &dev->iamthif_cl; | ||
457 | struct mei_cl_cb *cb, *next; | 327 | struct mei_cl_cb *cb, *next; |
458 | bool removed = false; | ||
459 | |||
460 | /* list all list member */ | ||
461 | list_for_each_entry_safe(cb, next, mei_cb_list, list) { | ||
462 | /* check if list member associated with a file */ | ||
463 | if (file == cb->fp) { | ||
464 | /* check if cb equal to current iamthif cb */ | ||
465 | if (dev->iamthif_current_cb == cb) { | ||
466 | dev->iamthif_current_cb = NULL; | ||
467 | /* send flow control to iamthif client */ | ||
468 | mei_hbm_cl_flow_control_req(dev, cl); | ||
469 | } | ||
470 | /* free all allocated buffers */ | ||
471 | mei_io_cb_free(cb); | ||
472 | removed = true; | ||
473 | } | ||
474 | } | ||
475 | return removed; | ||
476 | } | ||
477 | 328 | ||
478 | /** | 329 | list_for_each_entry_safe(cb, next, mei_cb_list, list) |
479 | * mei_clear_lists - removes all callbacks associated with file | 330 | if (file == cb->fp) |
480 | * | 331 | mei_io_cb_free(cb); |
481 | * @dev: device structure | ||
482 | * @file: file structure | ||
483 | * | ||
484 | * mei_clear_lists is called to clear resources associated with file | ||
485 | * when application calls close function or Ctrl-C was pressed | ||
486 | * | ||
487 | * Return: true if callback removed from the list, false otherwise | ||
488 | */ | ||
489 | static bool mei_clear_lists(struct mei_device *dev, const struct file *file) | ||
490 | { | ||
491 | bool removed = false; | ||
492 | struct mei_cl *cl = &dev->iamthif_cl; | ||
493 | |||
494 | /* remove callbacks associated with a file */ | ||
495 | mei_clear_list(dev, file, &dev->amthif_cmd_list.list); | ||
496 | if (mei_clear_list(dev, file, &cl->rd_completed)) | ||
497 | removed = true; | ||
498 | |||
499 | mei_clear_list(dev, file, &dev->ctrl_rd_list.list); | ||
500 | |||
501 | if (mei_clear_list(dev, file, &dev->ctrl_wr_list.list)) | ||
502 | removed = true; | ||
503 | |||
504 | if (mei_clear_list(dev, file, &dev->write_waiting_list.list)) | ||
505 | removed = true; | ||
506 | |||
507 | if (mei_clear_list(dev, file, &dev->write_list.list)) | ||
508 | removed = true; | ||
509 | |||
510 | /* check if iamthif_current_cb not NULL */ | ||
511 | if (dev->iamthif_current_cb && !removed) { | ||
512 | /* check file and iamthif current cb association */ | ||
513 | if (dev->iamthif_current_cb->fp == file) { | ||
514 | /* remove cb */ | ||
515 | mei_io_cb_free(dev->iamthif_current_cb); | ||
516 | dev->iamthif_current_cb = NULL; | ||
517 | removed = true; | ||
518 | } | ||
519 | } | ||
520 | return removed; | ||
521 | } | 332 | } |
522 | 333 | ||
523 | /** | 334 | /** |
@@ -530,23 +341,21 @@ static bool mei_clear_lists(struct mei_device *dev, const struct file *file) | |||
530 | */ | 341 | */ |
531 | int mei_amthif_release(struct mei_device *dev, struct file *file) | 342 | int mei_amthif_release(struct mei_device *dev, struct file *file) |
532 | { | 343 | { |
344 | struct mei_cl *cl = file->private_data; | ||
345 | |||
533 | if (dev->iamthif_open_count > 0) | 346 | if (dev->iamthif_open_count > 0) |
534 | dev->iamthif_open_count--; | 347 | dev->iamthif_open_count--; |
535 | 348 | ||
536 | if (dev->iamthif_fp == file && | 349 | if (cl->fp == file && dev->iamthif_state != MEI_IAMTHIF_IDLE) { |
537 | dev->iamthif_state != MEI_IAMTHIF_IDLE) { | ||
538 | 350 | ||
539 | dev_dbg(dev->dev, "amthif canceled iamthif state %d\n", | 351 | dev_dbg(dev->dev, "amthif canceled iamthif state %d\n", |
540 | dev->iamthif_state); | 352 | dev->iamthif_state); |
541 | dev->iamthif_canceled = true; | 353 | dev->iamthif_canceled = true; |
542 | if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE) { | ||
543 | dev_dbg(dev->dev, "run next amthif iamthif cb\n"); | ||
544 | mei_amthif_run_next_cmd(dev); | ||
545 | } | ||
546 | } | 354 | } |
547 | 355 | ||
548 | if (mei_clear_lists(dev, file)) | 356 | mei_clear_list(file, &dev->amthif_cmd_list.list); |
549 | dev->iamthif_state = MEI_IAMTHIF_IDLE; | 357 | mei_clear_list(file, &cl->rd_completed); |
358 | mei_clear_list(file, &dev->ctrl_rd_list.list); | ||
550 | 359 | ||
551 | return 0; | 360 | return 0; |
552 | } | 361 | } |
diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c index 1f33fea9299f..8cac7ef9ad0d 100644 --- a/drivers/misc/mei/bus.c +++ b/drivers/misc/mei/bus.c | |||
@@ -126,7 +126,8 @@ ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length) | |||
126 | goto out; | 126 | goto out; |
127 | 127 | ||
128 | /* wait on event only if there is no other waiter */ | 128 | /* wait on event only if there is no other waiter */ |
129 | if (list_empty(&cl->rd_completed) && !waitqueue_active(&cl->rx_wait)) { | 129 | /* synchronized under device mutex */ |
130 | if (!waitqueue_active(&cl->rx_wait)) { | ||
130 | 131 | ||
131 | mutex_unlock(&bus->device_lock); | 132 | mutex_unlock(&bus->device_lock); |
132 | 133 | ||
@@ -142,7 +143,7 @@ ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length) | |||
142 | mutex_lock(&bus->device_lock); | 143 | mutex_lock(&bus->device_lock); |
143 | 144 | ||
144 | if (!mei_cl_is_connected(cl)) { | 145 | if (!mei_cl_is_connected(cl)) { |
145 | rets = -EBUSY; | 146 | rets = -ENODEV; |
146 | goto out; | 147 | goto out; |
147 | } | 148 | } |
148 | } | 149 | } |
@@ -234,7 +235,7 @@ static void mei_cl_bus_event_work(struct work_struct *work) | |||
234 | /* Prepare for the next read */ | 235 | /* Prepare for the next read */ |
235 | if (cldev->events_mask & BIT(MEI_CL_EVENT_RX)) { | 236 | if (cldev->events_mask & BIT(MEI_CL_EVENT_RX)) { |
236 | mutex_lock(&bus->device_lock); | 237 | mutex_lock(&bus->device_lock); |
237 | mei_cl_read_start(cldev->cl, 0, NULL); | 238 | mei_cl_read_start(cldev->cl, mei_cl_mtu(cldev->cl), NULL); |
238 | mutex_unlock(&bus->device_lock); | 239 | mutex_unlock(&bus->device_lock); |
239 | } | 240 | } |
240 | } | 241 | } |
@@ -324,7 +325,7 @@ int mei_cldev_register_event_cb(struct mei_cl_device *cldev, | |||
324 | 325 | ||
325 | if (cldev->events_mask & BIT(MEI_CL_EVENT_RX)) { | 326 | if (cldev->events_mask & BIT(MEI_CL_EVENT_RX)) { |
326 | mutex_lock(&bus->device_lock); | 327 | mutex_lock(&bus->device_lock); |
327 | ret = mei_cl_read_start(cldev->cl, 0, NULL); | 328 | ret = mei_cl_read_start(cldev->cl, mei_cl_mtu(cldev->cl), NULL); |
328 | mutex_unlock(&bus->device_lock); | 329 | mutex_unlock(&bus->device_lock); |
329 | if (ret && ret != -EBUSY) | 330 | if (ret && ret != -EBUSY) |
330 | return ret; | 331 | return ret; |
@@ -983,12 +984,10 @@ void mei_cl_bus_rescan_work(struct work_struct *work) | |||
983 | container_of(work, struct mei_device, bus_rescan_work); | 984 | container_of(work, struct mei_device, bus_rescan_work); |
984 | struct mei_me_client *me_cl; | 985 | struct mei_me_client *me_cl; |
985 | 986 | ||
986 | mutex_lock(&bus->device_lock); | ||
987 | me_cl = mei_me_cl_by_uuid(bus, &mei_amthif_guid); | 987 | me_cl = mei_me_cl_by_uuid(bus, &mei_amthif_guid); |
988 | if (me_cl) | 988 | if (me_cl) |
989 | mei_amthif_host_init(bus, me_cl); | 989 | mei_amthif_host_init(bus, me_cl); |
990 | mei_me_cl_put(me_cl); | 990 | mei_me_cl_put(me_cl); |
991 | mutex_unlock(&bus->device_lock); | ||
992 | 991 | ||
993 | mei_cl_bus_rescan(bus); | 992 | mei_cl_bus_rescan(bus); |
994 | } | 993 | } |
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c index 641c1a566687..6fe02350578d 100644 --- a/drivers/misc/mei/client.c +++ b/drivers/misc/mei/client.c | |||
@@ -358,8 +358,9 @@ void mei_io_cb_free(struct mei_cl_cb *cb) | |||
358 | * | 358 | * |
359 | * Return: mei_cl_cb pointer or NULL; | 359 | * Return: mei_cl_cb pointer or NULL; |
360 | */ | 360 | */ |
361 | struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, enum mei_cb_file_ops type, | 361 | static struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, |
362 | const struct file *fp) | 362 | enum mei_cb_file_ops type, |
363 | const struct file *fp) | ||
363 | { | 364 | { |
364 | struct mei_cl_cb *cb; | 365 | struct mei_cl_cb *cb; |
365 | 366 | ||
@@ -420,32 +421,41 @@ static inline void mei_io_list_free(struct mei_cl_cb *list, struct mei_cl *cl) | |||
420 | } | 421 | } |
421 | 422 | ||
422 | /** | 423 | /** |
423 | * mei_io_cb_alloc_buf - allocate callback buffer | 424 | * mei_cl_alloc_cb - a convenient wrapper for allocating read cb |
424 | * | 425 | * |
425 | * @cb: io callback structure | 426 | * @cl: host client |
426 | * @length: size of the buffer | 427 | * @length: size of the buffer |
428 | * @type: operation type | ||
429 | * @fp: associated file pointer (might be NULL) | ||
427 | * | 430 | * |
428 | * Return: 0 on success | 431 | * Return: cb on success and NULL on failure |
429 | * -EINVAL if cb is NULL | ||
430 | * -ENOMEM if allocation failed | ||
431 | */ | 432 | */ |
432 | int mei_io_cb_alloc_buf(struct mei_cl_cb *cb, size_t length) | 433 | struct mei_cl_cb *mei_cl_alloc_cb(struct mei_cl *cl, size_t length, |
434 | enum mei_cb_file_ops fop_type, | ||
435 | const struct file *fp) | ||
433 | { | 436 | { |
437 | struct mei_cl_cb *cb; | ||
438 | |||
439 | cb = mei_io_cb_init(cl, fop_type, fp); | ||
434 | if (!cb) | 440 | if (!cb) |
435 | return -EINVAL; | 441 | return NULL; |
436 | 442 | ||
437 | if (length == 0) | 443 | if (length == 0) |
438 | return 0; | 444 | return cb; |
439 | 445 | ||
440 | cb->buf.data = kmalloc(length, GFP_KERNEL); | 446 | cb->buf.data = kmalloc(length, GFP_KERNEL); |
441 | if (!cb->buf.data) | 447 | if (!cb->buf.data) { |
442 | return -ENOMEM; | 448 | mei_io_cb_free(cb); |
449 | return NULL; | ||
450 | } | ||
443 | cb->buf.size = length; | 451 | cb->buf.size = length; |
444 | return 0; | 452 | |
453 | return cb; | ||
445 | } | 454 | } |
446 | 455 | ||
447 | /** | 456 | /** |
448 | * mei_cl_alloc_cb - a convenient wrapper for allocating read cb | 457 | * mei_cl_enqueue_ctrl_wr_cb - a convenient wrapper for allocating |
458 | * and enqueuing of the control commands cb | ||
449 | * | 459 | * |
450 | * @cl: host client | 460 | * @cl: host client |
451 | * @length: size of the buffer | 461 | * @length: size of the buffer |
@@ -453,22 +463,23 @@ int mei_io_cb_alloc_buf(struct mei_cl_cb *cb, size_t length) | |||
453 | * @fp: associated file pointer (might be NULL) | 463 | * @fp: associated file pointer (might be NULL) |
454 | * | 464 | * |
455 | * Return: cb on success and NULL on failure | 465 | * Return: cb on success and NULL on failure |
466 | * Locking: called under "dev->device_lock" lock | ||
456 | */ | 467 | */ |
457 | struct mei_cl_cb *mei_cl_alloc_cb(struct mei_cl *cl, size_t length, | 468 | struct mei_cl_cb *mei_cl_enqueue_ctrl_wr_cb(struct mei_cl *cl, size_t length, |
458 | enum mei_cb_file_ops type, | 469 | enum mei_cb_file_ops fop_type, |
459 | const struct file *fp) | 470 | const struct file *fp) |
460 | { | 471 | { |
461 | struct mei_cl_cb *cb; | 472 | struct mei_cl_cb *cb; |
462 | 473 | ||
463 | cb = mei_io_cb_init(cl, type, fp); | 474 | /* for RX always allocate at least client's mtu */ |
464 | if (!cb) | 475 | if (length) |
465 | return NULL; | 476 | length = max_t(size_t, length, mei_cl_mtu(cl)); |
466 | 477 | ||
467 | if (mei_io_cb_alloc_buf(cb, length)) { | 478 | cb = mei_cl_alloc_cb(cl, length, fop_type, fp); |
468 | mei_io_cb_free(cb); | 479 | if (!cb) |
469 | return NULL; | 480 | return NULL; |
470 | } | ||
471 | 481 | ||
482 | list_add_tail(&cb->list, &cl->dev->ctrl_wr_list.list); | ||
472 | return cb; | 483 | return cb; |
473 | } | 484 | } |
474 | 485 | ||
@@ -754,7 +765,8 @@ void mei_cl_set_disconnected(struct mei_cl *cl) | |||
754 | mei_io_list_flush(&dev->ctrl_rd_list, cl); | 765 | mei_io_list_flush(&dev->ctrl_rd_list, cl); |
755 | mei_io_list_flush(&dev->ctrl_wr_list, cl); | 766 | mei_io_list_flush(&dev->ctrl_wr_list, cl); |
756 | mei_cl_wake_all(cl); | 767 | mei_cl_wake_all(cl); |
757 | cl->mei_flow_ctrl_creds = 0; | 768 | cl->rx_flow_ctrl_creds = 0; |
769 | cl->tx_flow_ctrl_creds = 0; | ||
758 | cl->timer_count = 0; | 770 | cl->timer_count = 0; |
759 | 771 | ||
760 | if (!cl->me_cl) | 772 | if (!cl->me_cl) |
@@ -764,7 +776,7 @@ void mei_cl_set_disconnected(struct mei_cl *cl) | |||
764 | cl->me_cl->connect_count--; | 776 | cl->me_cl->connect_count--; |
765 | 777 | ||
766 | if (cl->me_cl->connect_count == 0) | 778 | if (cl->me_cl->connect_count == 0) |
767 | cl->me_cl->mei_flow_ctrl_creds = 0; | 779 | cl->me_cl->tx_flow_ctrl_creds = 0; |
768 | 780 | ||
769 | mei_me_cl_put(cl->me_cl); | 781 | mei_me_cl_put(cl->me_cl); |
770 | cl->me_cl = NULL; | 782 | cl->me_cl = NULL; |
@@ -814,6 +826,7 @@ static int mei_cl_send_disconnect(struct mei_cl *cl, struct mei_cl_cb *cb) | |||
814 | 826 | ||
815 | list_move_tail(&cb->list, &dev->ctrl_rd_list.list); | 827 | list_move_tail(&cb->list, &dev->ctrl_rd_list.list); |
816 | cl->timer_count = MEI_CONNECT_TIMEOUT; | 828 | cl->timer_count = MEI_CONNECT_TIMEOUT; |
829 | mei_schedule_stall_timer(dev); | ||
817 | 830 | ||
818 | return 0; | 831 | return 0; |
819 | } | 832 | } |
@@ -867,13 +880,11 @@ static int __mei_cl_disconnect(struct mei_cl *cl) | |||
867 | 880 | ||
868 | cl->state = MEI_FILE_DISCONNECTING; | 881 | cl->state = MEI_FILE_DISCONNECTING; |
869 | 882 | ||
870 | cb = mei_io_cb_init(cl, MEI_FOP_DISCONNECT, NULL); | 883 | cb = mei_cl_enqueue_ctrl_wr_cb(cl, 0, MEI_FOP_DISCONNECT, NULL); |
871 | rets = cb ? 0 : -ENOMEM; | 884 | if (!cb) { |
872 | if (rets) | 885 | rets = -ENOMEM; |
873 | goto out; | 886 | goto out; |
874 | 887 | } | |
875 | cl_dbg(dev, cl, "add disconnect cb to control write list\n"); | ||
876 | list_add_tail(&cb->list, &dev->ctrl_wr_list.list); | ||
877 | 888 | ||
878 | if (mei_hbuf_acquire(dev)) { | 889 | if (mei_hbuf_acquire(dev)) { |
879 | rets = mei_cl_send_disconnect(cl, cb); | 890 | rets = mei_cl_send_disconnect(cl, cb); |
@@ -1001,6 +1012,7 @@ static int mei_cl_send_connect(struct mei_cl *cl, struct mei_cl_cb *cb) | |||
1001 | 1012 | ||
1002 | list_move_tail(&cb->list, &dev->ctrl_rd_list.list); | 1013 | list_move_tail(&cb->list, &dev->ctrl_rd_list.list); |
1003 | cl->timer_count = MEI_CONNECT_TIMEOUT; | 1014 | cl->timer_count = MEI_CONNECT_TIMEOUT; |
1015 | mei_schedule_stall_timer(dev); | ||
1004 | return 0; | 1016 | return 0; |
1005 | } | 1017 | } |
1006 | 1018 | ||
@@ -1042,14 +1054,14 @@ int mei_cl_irq_connect(struct mei_cl *cl, struct mei_cl_cb *cb, | |||
1042 | * | 1054 | * |
1043 | * @cl: host client | 1055 | * @cl: host client |
1044 | * @me_cl: me client | 1056 | * @me_cl: me client |
1045 | * @file: pointer to file structure | 1057 | * @fp: pointer to file structure |
1046 | * | 1058 | * |
1047 | * Locking: called under "dev->device_lock" lock | 1059 | * Locking: called under "dev->device_lock" lock |
1048 | * | 1060 | * |
1049 | * Return: 0 on success, <0 on failure. | 1061 | * Return: 0 on success, <0 on failure. |
1050 | */ | 1062 | */ |
1051 | int mei_cl_connect(struct mei_cl *cl, struct mei_me_client *me_cl, | 1063 | int mei_cl_connect(struct mei_cl *cl, struct mei_me_client *me_cl, |
1052 | const struct file *file) | 1064 | const struct file *fp) |
1053 | { | 1065 | { |
1054 | struct mei_device *dev; | 1066 | struct mei_device *dev; |
1055 | struct mei_cl_cb *cb; | 1067 | struct mei_cl_cb *cb; |
@@ -1076,12 +1088,11 @@ int mei_cl_connect(struct mei_cl *cl, struct mei_me_client *me_cl, | |||
1076 | goto nortpm; | 1088 | goto nortpm; |
1077 | } | 1089 | } |
1078 | 1090 | ||
1079 | cb = mei_io_cb_init(cl, MEI_FOP_CONNECT, file); | 1091 | cb = mei_cl_enqueue_ctrl_wr_cb(cl, 0, MEI_FOP_CONNECT, fp); |
1080 | rets = cb ? 0 : -ENOMEM; | 1092 | if (!cb) { |
1081 | if (rets) | 1093 | rets = -ENOMEM; |
1082 | goto out; | 1094 | goto out; |
1083 | 1095 | } | |
1084 | list_add_tail(&cb->list, &dev->ctrl_wr_list.list); | ||
1085 | 1096 | ||
1086 | /* run hbuf acquire last so we don't have to undo */ | 1097 | /* run hbuf acquire last so we don't have to undo */ |
1087 | if (!mei_cl_is_other_connecting(cl) && mei_hbuf_acquire(dev)) { | 1098 | if (!mei_cl_is_other_connecting(cl) && mei_hbuf_acquire(dev)) { |
@@ -1159,50 +1170,42 @@ err: | |||
1159 | return ERR_PTR(ret); | 1170 | return ERR_PTR(ret); |
1160 | } | 1171 | } |
1161 | 1172 | ||
1162 | |||
1163 | |||
1164 | /** | 1173 | /** |
1165 | * mei_cl_flow_ctrl_creds - checks flow_control credits for cl. | 1174 | * mei_cl_tx_flow_ctrl_creds - checks flow_control credits for cl. |
1166 | * | 1175 | * |
1167 | * @cl: host client | 1176 | * @cl: host client |
1168 | * @fp: the file pointer associated with the pointer | ||
1169 | * | 1177 | * |
1170 | * Return: 1 if mei_flow_ctrl_creds >0, 0 - otherwise. | 1178 | * Return: 1 if tx_flow_ctrl_creds >0, 0 - otherwise. |
1171 | */ | 1179 | */ |
1172 | static int mei_cl_flow_ctrl_creds(struct mei_cl *cl, const struct file *fp) | 1180 | static int mei_cl_tx_flow_ctrl_creds(struct mei_cl *cl) |
1173 | { | 1181 | { |
1174 | int rets; | ||
1175 | |||
1176 | if (WARN_ON(!cl || !cl->me_cl)) | 1182 | if (WARN_ON(!cl || !cl->me_cl)) |
1177 | return -EINVAL; | 1183 | return -EINVAL; |
1178 | 1184 | ||
1179 | if (cl->mei_flow_ctrl_creds > 0) | 1185 | if (cl->tx_flow_ctrl_creds > 0) |
1180 | return 1; | 1186 | return 1; |
1181 | 1187 | ||
1182 | if (mei_cl_is_fixed_address(cl)) { | 1188 | if (mei_cl_is_fixed_address(cl)) |
1183 | rets = mei_cl_read_start(cl, mei_cl_mtu(cl), fp); | ||
1184 | if (rets && rets != -EBUSY) | ||
1185 | return rets; | ||
1186 | return 1; | 1189 | return 1; |
1187 | } | ||
1188 | 1190 | ||
1189 | if (mei_cl_is_single_recv_buf(cl)) { | 1191 | if (mei_cl_is_single_recv_buf(cl)) { |
1190 | if (cl->me_cl->mei_flow_ctrl_creds > 0) | 1192 | if (cl->me_cl->tx_flow_ctrl_creds > 0) |
1191 | return 1; | 1193 | return 1; |
1192 | } | 1194 | } |
1193 | return 0; | 1195 | return 0; |
1194 | } | 1196 | } |
1195 | 1197 | ||
1196 | /** | 1198 | /** |
1197 | * mei_cl_flow_ctrl_reduce - reduces flow_control. | 1199 | * mei_cl_tx_flow_ctrl_creds_reduce - reduces transmit flow control credits |
1200 | * for a client | ||
1198 | * | 1201 | * |
1199 | * @cl: private data of the file object | 1202 | * @cl: host client |
1200 | * | 1203 | * |
1201 | * Return: | 1204 | * Return: |
1202 | * 0 on success | 1205 | * 0 on success |
1203 | * -EINVAL when ctrl credits are <= 0 | 1206 | * -EINVAL when ctrl credits are <= 0 |
1204 | */ | 1207 | */ |
1205 | static int mei_cl_flow_ctrl_reduce(struct mei_cl *cl) | 1208 | static int mei_cl_tx_flow_ctrl_creds_reduce(struct mei_cl *cl) |
1206 | { | 1209 | { |
1207 | if (WARN_ON(!cl || !cl->me_cl)) | 1210 | if (WARN_ON(!cl || !cl->me_cl)) |
1208 | return -EINVAL; | 1211 | return -EINVAL; |
@@ -1211,13 +1214,13 @@ static int mei_cl_flow_ctrl_reduce(struct mei_cl *cl) | |||
1211 | return 0; | 1214 | return 0; |
1212 | 1215 | ||
1213 | if (mei_cl_is_single_recv_buf(cl)) { | 1216 | if (mei_cl_is_single_recv_buf(cl)) { |
1214 | if (WARN_ON(cl->me_cl->mei_flow_ctrl_creds <= 0)) | 1217 | if (WARN_ON(cl->me_cl->tx_flow_ctrl_creds <= 0)) |
1215 | return -EINVAL; | 1218 | return -EINVAL; |
1216 | cl->me_cl->mei_flow_ctrl_creds--; | 1219 | cl->me_cl->tx_flow_ctrl_creds--; |
1217 | } else { | 1220 | } else { |
1218 | if (WARN_ON(cl->mei_flow_ctrl_creds <= 0)) | 1221 | if (WARN_ON(cl->tx_flow_ctrl_creds <= 0)) |
1219 | return -EINVAL; | 1222 | return -EINVAL; |
1220 | cl->mei_flow_ctrl_creds--; | 1223 | cl->tx_flow_ctrl_creds--; |
1221 | } | 1224 | } |
1222 | return 0; | 1225 | return 0; |
1223 | } | 1226 | } |
@@ -1292,7 +1295,7 @@ int mei_cl_irq_notify(struct mei_cl *cl, struct mei_cl_cb *cb, | |||
1292 | * mei_cl_notify_request - send notification stop/start request | 1295 | * mei_cl_notify_request - send notification stop/start request |
1293 | * | 1296 | * |
1294 | * @cl: host client | 1297 | * @cl: host client |
1295 | * @file: associate request with file | 1298 | * @fp: associate request with file |
1296 | * @request: 1 for start or 0 for stop | 1299 | * @request: 1 for start or 0 for stop |
1297 | * | 1300 | * |
1298 | * Locking: called under "dev->device_lock" lock | 1301 | * Locking: called under "dev->device_lock" lock |
@@ -1300,7 +1303,7 @@ int mei_cl_irq_notify(struct mei_cl *cl, struct mei_cl_cb *cb, | |||
1300 | * Return: 0 on such and error otherwise. | 1303 | * Return: 0 on such and error otherwise. |
1301 | */ | 1304 | */ |
1302 | int mei_cl_notify_request(struct mei_cl *cl, | 1305 | int mei_cl_notify_request(struct mei_cl *cl, |
1303 | const struct file *file, u8 request) | 1306 | const struct file *fp, u8 request) |
1304 | { | 1307 | { |
1305 | struct mei_device *dev; | 1308 | struct mei_device *dev; |
1306 | struct mei_cl_cb *cb; | 1309 | struct mei_cl_cb *cb; |
@@ -1325,7 +1328,7 @@ int mei_cl_notify_request(struct mei_cl *cl, | |||
1325 | } | 1328 | } |
1326 | 1329 | ||
1327 | fop_type = mei_cl_notify_req2fop(request); | 1330 | fop_type = mei_cl_notify_req2fop(request); |
1328 | cb = mei_io_cb_init(cl, fop_type, file); | 1331 | cb = mei_cl_enqueue_ctrl_wr_cb(cl, 0, fop_type, fp); |
1329 | if (!cb) { | 1332 | if (!cb) { |
1330 | rets = -ENOMEM; | 1333 | rets = -ENOMEM; |
1331 | goto out; | 1334 | goto out; |
@@ -1336,9 +1339,7 @@ int mei_cl_notify_request(struct mei_cl *cl, | |||
1336 | rets = -ENODEV; | 1339 | rets = -ENODEV; |
1337 | goto out; | 1340 | goto out; |
1338 | } | 1341 | } |
1339 | list_add_tail(&cb->list, &dev->ctrl_rd_list.list); | 1342 | list_move_tail(&cb->list, &dev->ctrl_rd_list.list); |
1340 | } else { | ||
1341 | list_add_tail(&cb->list, &dev->ctrl_wr_list.list); | ||
1342 | } | 1343 | } |
1343 | 1344 | ||
1344 | mutex_unlock(&dev->device_lock); | 1345 | mutex_unlock(&dev->device_lock); |
@@ -1436,25 +1437,6 @@ out: | |||
1436 | } | 1437 | } |
1437 | 1438 | ||
1438 | /** | 1439 | /** |
1439 | * mei_cl_is_read_fc_cb - check if read cb is waiting for flow control | ||
1440 | * for given host client | ||
1441 | * | ||
1442 | * @cl: host client | ||
1443 | * | ||
1444 | * Return: true, if found at least one cb. | ||
1445 | */ | ||
1446 | static bool mei_cl_is_read_fc_cb(struct mei_cl *cl) | ||
1447 | { | ||
1448 | struct mei_device *dev = cl->dev; | ||
1449 | struct mei_cl_cb *cb; | ||
1450 | |||
1451 | list_for_each_entry(cb, &dev->ctrl_wr_list.list, list) | ||
1452 | if (cb->fop_type == MEI_FOP_READ && cb->cl == cl) | ||
1453 | return true; | ||
1454 | return false; | ||
1455 | } | ||
1456 | |||
1457 | /** | ||
1458 | * mei_cl_read_start - the start read client message function. | 1440 | * mei_cl_read_start - the start read client message function. |
1459 | * | 1441 | * |
1460 | * @cl: host client | 1442 | * @cl: host client |
@@ -1477,26 +1459,22 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length, const struct file *fp) | |||
1477 | if (!mei_cl_is_connected(cl)) | 1459 | if (!mei_cl_is_connected(cl)) |
1478 | return -ENODEV; | 1460 | return -ENODEV; |
1479 | 1461 | ||
1480 | /* HW currently supports only one pending read */ | ||
1481 | if (!list_empty(&cl->rd_pending) || mei_cl_is_read_fc_cb(cl)) | ||
1482 | return -EBUSY; | ||
1483 | |||
1484 | if (!mei_me_cl_is_active(cl->me_cl)) { | 1462 | if (!mei_me_cl_is_active(cl->me_cl)) { |
1485 | cl_err(dev, cl, "no such me client\n"); | 1463 | cl_err(dev, cl, "no such me client\n"); |
1486 | return -ENOTTY; | 1464 | return -ENOTTY; |
1487 | } | 1465 | } |
1488 | 1466 | ||
1489 | /* always allocate at least client max message */ | 1467 | if (mei_cl_is_fixed_address(cl) || cl == &dev->iamthif_cl) |
1490 | length = max_t(size_t, length, mei_cl_mtu(cl)); | 1468 | return 0; |
1491 | cb = mei_cl_alloc_cb(cl, length, MEI_FOP_READ, fp); | 1469 | |
1470 | /* HW currently supports only one pending read */ | ||
1471 | if (cl->rx_flow_ctrl_creds) | ||
1472 | return -EBUSY; | ||
1473 | |||
1474 | cb = mei_cl_enqueue_ctrl_wr_cb(cl, length, MEI_FOP_READ, fp); | ||
1492 | if (!cb) | 1475 | if (!cb) |
1493 | return -ENOMEM; | 1476 | return -ENOMEM; |
1494 | 1477 | ||
1495 | if (mei_cl_is_fixed_address(cl)) { | ||
1496 | list_add_tail(&cb->list, &cl->rd_pending); | ||
1497 | return 0; | ||
1498 | } | ||
1499 | |||
1500 | rets = pm_runtime_get(dev->dev); | 1478 | rets = pm_runtime_get(dev->dev); |
1501 | if (rets < 0 && rets != -EINPROGRESS) { | 1479 | if (rets < 0 && rets != -EINPROGRESS) { |
1502 | pm_runtime_put_noidle(dev->dev); | 1480 | pm_runtime_put_noidle(dev->dev); |
@@ -1504,16 +1482,15 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length, const struct file *fp) | |||
1504 | goto nortpm; | 1482 | goto nortpm; |
1505 | } | 1483 | } |
1506 | 1484 | ||
1485 | rets = 0; | ||
1507 | if (mei_hbuf_acquire(dev)) { | 1486 | if (mei_hbuf_acquire(dev)) { |
1508 | rets = mei_hbm_cl_flow_control_req(dev, cl); | 1487 | rets = mei_hbm_cl_flow_control_req(dev, cl); |
1509 | if (rets < 0) | 1488 | if (rets < 0) |
1510 | goto out; | 1489 | goto out; |
1511 | 1490 | ||
1512 | list_add_tail(&cb->list, &cl->rd_pending); | 1491 | list_move_tail(&cb->list, &cl->rd_pending); |
1513 | } else { | ||
1514 | rets = 0; | ||
1515 | list_add_tail(&cb->list, &dev->ctrl_wr_list.list); | ||
1516 | } | 1492 | } |
1493 | cl->rx_flow_ctrl_creds++; | ||
1517 | 1494 | ||
1518 | out: | 1495 | out: |
1519 | cl_dbg(dev, cl, "rpm: autosuspend\n"); | 1496 | cl_dbg(dev, cl, "rpm: autosuspend\n"); |
@@ -1557,7 +1534,7 @@ int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb, | |||
1557 | 1534 | ||
1558 | first_chunk = cb->buf_idx == 0; | 1535 | first_chunk = cb->buf_idx == 0; |
1559 | 1536 | ||
1560 | rets = first_chunk ? mei_cl_flow_ctrl_creds(cl, cb->fp) : 1; | 1537 | rets = first_chunk ? mei_cl_tx_flow_ctrl_creds(cl) : 1; |
1561 | if (rets < 0) | 1538 | if (rets < 0) |
1562 | return rets; | 1539 | return rets; |
1563 | 1540 | ||
@@ -1605,7 +1582,7 @@ int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb, | |||
1605 | cb->completed = mei_hdr.msg_complete == 1; | 1582 | cb->completed = mei_hdr.msg_complete == 1; |
1606 | 1583 | ||
1607 | if (first_chunk) { | 1584 | if (first_chunk) { |
1608 | if (mei_cl_flow_ctrl_reduce(cl)) | 1585 | if (mei_cl_tx_flow_ctrl_creds_reduce(cl)) |
1609 | return -EIO; | 1586 | return -EIO; |
1610 | } | 1587 | } |
1611 | 1588 | ||
@@ -1663,7 +1640,7 @@ int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking) | |||
1663 | mei_hdr.msg_complete = 0; | 1640 | mei_hdr.msg_complete = 0; |
1664 | mei_hdr.internal = cb->internal; | 1641 | mei_hdr.internal = cb->internal; |
1665 | 1642 | ||
1666 | rets = mei_cl_flow_ctrl_creds(cl, cb->fp); | 1643 | rets = mei_cl_tx_flow_ctrl_creds(cl); |
1667 | if (rets < 0) | 1644 | if (rets < 0) |
1668 | goto err; | 1645 | goto err; |
1669 | 1646 | ||
@@ -1691,7 +1668,7 @@ int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking) | |||
1691 | if (rets) | 1668 | if (rets) |
1692 | goto err; | 1669 | goto err; |
1693 | 1670 | ||
1694 | rets = mei_cl_flow_ctrl_reduce(cl); | 1671 | rets = mei_cl_tx_flow_ctrl_creds_reduce(cl); |
1695 | if (rets) | 1672 | if (rets) |
1696 | goto err; | 1673 | goto err; |
1697 | 1674 | ||
@@ -1761,6 +1738,9 @@ void mei_cl_complete(struct mei_cl *cl, struct mei_cl_cb *cb) | |||
1761 | 1738 | ||
1762 | case MEI_FOP_READ: | 1739 | case MEI_FOP_READ: |
1763 | list_add_tail(&cb->list, &cl->rd_completed); | 1740 | list_add_tail(&cb->list, &cl->rd_completed); |
1741 | if (!mei_cl_is_fixed_address(cl) && | ||
1742 | !WARN_ON(!cl->rx_flow_ctrl_creds)) | ||
1743 | cl->rx_flow_ctrl_creds--; | ||
1764 | if (!mei_cl_bus_rx_event(cl)) | 1744 | if (!mei_cl_bus_rx_event(cl)) |
1765 | wake_up_interruptible(&cl->rx_wait); | 1745 | wake_up_interruptible(&cl->rx_wait); |
1766 | break; | 1746 | break; |
diff --git a/drivers/misc/mei/client.h b/drivers/misc/mei/client.h index 0d7a3a1fef78..d2bfabecd882 100644 --- a/drivers/misc/mei/client.h +++ b/drivers/misc/mei/client.h | |||
@@ -82,11 +82,7 @@ static inline u8 mei_me_cl_ver(const struct mei_me_client *me_cl) | |||
82 | /* | 82 | /* |
83 | * MEI IO Functions | 83 | * MEI IO Functions |
84 | */ | 84 | */ |
85 | struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, enum mei_cb_file_ops type, | ||
86 | const struct file *fp); | ||
87 | void mei_io_cb_free(struct mei_cl_cb *priv_cb); | 85 | void mei_io_cb_free(struct mei_cl_cb *priv_cb); |
88 | int mei_io_cb_alloc_buf(struct mei_cl_cb *cb, size_t length); | ||
89 | |||
90 | 86 | ||
91 | /** | 87 | /** |
92 | * mei_io_list_init - Sets up a queue list. | 88 | * mei_io_list_init - Sets up a queue list. |
@@ -118,6 +114,9 @@ void mei_cl_read_cb_flush(const struct mei_cl *cl, const struct file *fp); | |||
118 | struct mei_cl_cb *mei_cl_alloc_cb(struct mei_cl *cl, size_t length, | 114 | struct mei_cl_cb *mei_cl_alloc_cb(struct mei_cl *cl, size_t length, |
119 | enum mei_cb_file_ops type, | 115 | enum mei_cb_file_ops type, |
120 | const struct file *fp); | 116 | const struct file *fp); |
117 | struct mei_cl_cb *mei_cl_enqueue_ctrl_wr_cb(struct mei_cl *cl, size_t length, | ||
118 | enum mei_cb_file_ops type, | ||
119 | const struct file *fp); | ||
121 | int mei_cl_flush_queues(struct mei_cl *cl, const struct file *fp); | 120 | int mei_cl_flush_queues(struct mei_cl *cl, const struct file *fp); |
122 | 121 | ||
123 | /* | 122 | /* |
diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c index 085f3aafe6fa..dd7f15a65eed 100644 --- a/drivers/misc/mei/hbm.c +++ b/drivers/misc/mei/hbm.c | |||
@@ -161,6 +161,7 @@ void mei_hbm_cl_hdr(struct mei_cl *cl, u8 hbm_cmd, void *buf, size_t len) | |||
161 | * @dev: the device structure | 161 | * @dev: the device structure |
162 | * @cl: client | 162 | * @cl: client |
163 | * @hbm_cmd: host bus message command | 163 | * @hbm_cmd: host bus message command |
164 | * @buf: message buffer | ||
164 | * @len: buffer length | 165 | * @len: buffer length |
165 | * | 166 | * |
166 | * Return: 0 on success, <0 on failure. | 167 | * Return: 0 on success, <0 on failure. |
@@ -276,6 +277,7 @@ int mei_hbm_start_req(struct mei_device *dev) | |||
276 | 277 | ||
277 | dev->hbm_state = MEI_HBM_STARTING; | 278 | dev->hbm_state = MEI_HBM_STARTING; |
278 | dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT; | 279 | dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT; |
280 | mei_schedule_stall_timer(dev); | ||
279 | return 0; | 281 | return 0; |
280 | } | 282 | } |
281 | 283 | ||
@@ -311,6 +313,7 @@ static int mei_hbm_enum_clients_req(struct mei_device *dev) | |||
311 | } | 313 | } |
312 | dev->hbm_state = MEI_HBM_ENUM_CLIENTS; | 314 | dev->hbm_state = MEI_HBM_ENUM_CLIENTS; |
313 | dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT; | 315 | dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT; |
316 | mei_schedule_stall_timer(dev); | ||
314 | return 0; | 317 | return 0; |
315 | } | 318 | } |
316 | 319 | ||
@@ -339,7 +342,7 @@ static int mei_hbm_me_cl_add(struct mei_device *dev, | |||
339 | 342 | ||
340 | me_cl->props = res->client_properties; | 343 | me_cl->props = res->client_properties; |
341 | me_cl->client_id = res->me_addr; | 344 | me_cl->client_id = res->me_addr; |
342 | me_cl->mei_flow_ctrl_creds = 0; | 345 | me_cl->tx_flow_ctrl_creds = 0; |
343 | 346 | ||
344 | mei_me_cl_add(dev, me_cl); | 347 | mei_me_cl_add(dev, me_cl); |
345 | 348 | ||
@@ -561,6 +564,7 @@ static int mei_hbm_prop_req(struct mei_device *dev, unsigned long start_idx) | |||
561 | } | 564 | } |
562 | 565 | ||
563 | dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT; | 566 | dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT; |
567 | mei_schedule_stall_timer(dev); | ||
564 | 568 | ||
565 | return 0; | 569 | return 0; |
566 | } | 570 | } |
@@ -636,23 +640,22 @@ int mei_hbm_cl_flow_control_req(struct mei_device *dev, struct mei_cl *cl) | |||
636 | } | 640 | } |
637 | 641 | ||
638 | /** | 642 | /** |
639 | * mei_hbm_add_single_flow_creds - adds single buffer credentials. | 643 | * mei_hbm_add_single_tx_flow_ctrl_creds - adds single buffer credentials. |
640 | * | 644 | * |
641 | * @dev: the device structure | 645 | * @dev: the device structure |
642 | * @flow: flow control. | 646 | * @fctrl: flow control response bus message |
643 | * | 647 | * |
644 | * Return: 0 on success, < 0 otherwise | 648 | * Return: 0 on success, < 0 otherwise |
645 | */ | 649 | */ |
646 | static int mei_hbm_add_single_flow_creds(struct mei_device *dev, | 650 | static int mei_hbm_add_single_tx_flow_ctrl_creds(struct mei_device *dev, |
647 | struct hbm_flow_control *flow) | 651 | struct hbm_flow_control *fctrl) |
648 | { | 652 | { |
649 | struct mei_me_client *me_cl; | 653 | struct mei_me_client *me_cl; |
650 | int rets; | 654 | int rets; |
651 | 655 | ||
652 | me_cl = mei_me_cl_by_id(dev, flow->me_addr); | 656 | me_cl = mei_me_cl_by_id(dev, fctrl->me_addr); |
653 | if (!me_cl) { | 657 | if (!me_cl) { |
654 | dev_err(dev->dev, "no such me client %d\n", | 658 | dev_err(dev->dev, "no such me client %d\n", fctrl->me_addr); |
655 | flow->me_addr); | ||
656 | return -ENOENT; | 659 | return -ENOENT; |
657 | } | 660 | } |
658 | 661 | ||
@@ -661,9 +664,9 @@ static int mei_hbm_add_single_flow_creds(struct mei_device *dev, | |||
661 | goto out; | 664 | goto out; |
662 | } | 665 | } |
663 | 666 | ||
664 | me_cl->mei_flow_ctrl_creds++; | 667 | me_cl->tx_flow_ctrl_creds++; |
665 | dev_dbg(dev->dev, "recv flow ctrl msg ME %d (single) creds = %d.\n", | 668 | dev_dbg(dev->dev, "recv flow ctrl msg ME %d (single) creds = %d.\n", |
666 | flow->me_addr, me_cl->mei_flow_ctrl_creds); | 669 | fctrl->me_addr, me_cl->tx_flow_ctrl_creds); |
667 | 670 | ||
668 | rets = 0; | 671 | rets = 0; |
669 | out: | 672 | out: |
@@ -675,24 +678,24 @@ out: | |||
675 | * mei_hbm_cl_flow_control_res - flow control response from me | 678 | * mei_hbm_cl_flow_control_res - flow control response from me |
676 | * | 679 | * |
677 | * @dev: the device structure | 680 | * @dev: the device structure |
678 | * @flow_control: flow control response bus message | 681 | * @fctrl: flow control response bus message |
679 | */ | 682 | */ |
680 | static void mei_hbm_cl_flow_control_res(struct mei_device *dev, | 683 | static void mei_hbm_cl_tx_flow_ctrl_creds_res(struct mei_device *dev, |
681 | struct hbm_flow_control *flow_control) | 684 | struct hbm_flow_control *fctrl) |
682 | { | 685 | { |
683 | struct mei_cl *cl; | 686 | struct mei_cl *cl; |
684 | 687 | ||
685 | if (!flow_control->host_addr) { | 688 | if (!fctrl->host_addr) { |
686 | /* single receive buffer */ | 689 | /* single receive buffer */ |
687 | mei_hbm_add_single_flow_creds(dev, flow_control); | 690 | mei_hbm_add_single_tx_flow_ctrl_creds(dev, fctrl); |
688 | return; | 691 | return; |
689 | } | 692 | } |
690 | 693 | ||
691 | cl = mei_hbm_cl_find_by_cmd(dev, flow_control); | 694 | cl = mei_hbm_cl_find_by_cmd(dev, fctrl); |
692 | if (cl) { | 695 | if (cl) { |
693 | cl->mei_flow_ctrl_creds++; | 696 | cl->tx_flow_ctrl_creds++; |
694 | cl_dbg(dev, cl, "flow control creds = %d.\n", | 697 | cl_dbg(dev, cl, "flow control creds = %d.\n", |
695 | cl->mei_flow_ctrl_creds); | 698 | cl->tx_flow_ctrl_creds); |
696 | } | 699 | } |
697 | } | 700 | } |
698 | 701 | ||
@@ -871,10 +874,10 @@ static int mei_hbm_fw_disconnect_req(struct mei_device *dev, | |||
871 | cl->state = MEI_FILE_DISCONNECTING; | 874 | cl->state = MEI_FILE_DISCONNECTING; |
872 | cl->timer_count = 0; | 875 | cl->timer_count = 0; |
873 | 876 | ||
874 | cb = mei_io_cb_init(cl, MEI_FOP_DISCONNECT_RSP, NULL); | 877 | cb = mei_cl_enqueue_ctrl_wr_cb(cl, 0, MEI_FOP_DISCONNECT_RSP, |
878 | NULL); | ||
875 | if (!cb) | 879 | if (!cb) |
876 | return -ENOMEM; | 880 | return -ENOMEM; |
877 | list_add_tail(&cb->list, &dev->ctrl_wr_list.list); | ||
878 | } | 881 | } |
879 | return 0; | 882 | return 0; |
880 | } | 883 | } |
@@ -1022,7 +1025,7 @@ int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr) | |||
1022 | 1025 | ||
1023 | struct mei_hbm_cl_cmd *cl_cmd; | 1026 | struct mei_hbm_cl_cmd *cl_cmd; |
1024 | struct hbm_client_connect_request *disconnect_req; | 1027 | struct hbm_client_connect_request *disconnect_req; |
1025 | struct hbm_flow_control *flow_control; | 1028 | struct hbm_flow_control *fctrl; |
1026 | 1029 | ||
1027 | /* read the message to our buffer */ | 1030 | /* read the message to our buffer */ |
1028 | BUG_ON(hdr->length >= sizeof(dev->rd_msg_buf)); | 1031 | BUG_ON(hdr->length >= sizeof(dev->rd_msg_buf)); |
@@ -1102,8 +1105,8 @@ int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr) | |||
1102 | case MEI_FLOW_CONTROL_CMD: | 1105 | case MEI_FLOW_CONTROL_CMD: |
1103 | dev_dbg(dev->dev, "hbm: client flow control response: message received.\n"); | 1106 | dev_dbg(dev->dev, "hbm: client flow control response: message received.\n"); |
1104 | 1107 | ||
1105 | flow_control = (struct hbm_flow_control *) mei_msg; | 1108 | fctrl = (struct hbm_flow_control *)mei_msg; |
1106 | mei_hbm_cl_flow_control_res(dev, flow_control); | 1109 | mei_hbm_cl_tx_flow_ctrl_creds_res(dev, fctrl); |
1107 | break; | 1110 | break; |
1108 | 1111 | ||
1109 | case MEI_PG_ISOLATION_ENTRY_RES_CMD: | 1112 | case MEI_PG_ISOLATION_ENTRY_RES_CMD: |
diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h index 0dcb854b4bfc..7ad15d678878 100644 --- a/drivers/misc/mei/hw-me-regs.h +++ b/drivers/misc/mei/hw-me-regs.h | |||
@@ -125,6 +125,9 @@ | |||
125 | #define MEI_DEV_ID_BXT_M 0x1A9A /* Broxton M */ | 125 | #define MEI_DEV_ID_BXT_M 0x1A9A /* Broxton M */ |
126 | #define MEI_DEV_ID_APL_I 0x5A9A /* Apollo Lake I */ | 126 | #define MEI_DEV_ID_APL_I 0x5A9A /* Apollo Lake I */ |
127 | 127 | ||
128 | #define MEI_DEV_ID_KBP 0xA2BA /* Kaby Point */ | ||
129 | #define MEI_DEV_ID_KBP_2 0xA2BB /* Kaby Point 2 */ | ||
130 | |||
128 | /* | 131 | /* |
129 | * MEI HW Section | 132 | * MEI HW Section |
130 | */ | 133 | */ |
diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c index dc3a854e02d3..56c2101e80ad 100644 --- a/drivers/misc/mei/hw-me.c +++ b/drivers/misc/mei/hw-me.c | |||
@@ -18,6 +18,7 @@ | |||
18 | 18 | ||
19 | #include <linux/kthread.h> | 19 | #include <linux/kthread.h> |
20 | #include <linux/interrupt.h> | 20 | #include <linux/interrupt.h> |
21 | #include <linux/pm_runtime.h> | ||
21 | 22 | ||
22 | #include "mei_dev.h" | 23 | #include "mei_dev.h" |
23 | #include "hbm.h" | 24 | #include "hbm.h" |
@@ -1063,6 +1064,8 @@ static int mei_me_hw_reset(struct mei_device *dev, bool intr_enable) | |||
1063 | } | 1064 | } |
1064 | } | 1065 | } |
1065 | 1066 | ||
1067 | pm_runtime_set_active(dev->dev); | ||
1068 | |||
1066 | hcsr = mei_hcsr_read(dev); | 1069 | hcsr = mei_hcsr_read(dev); |
1067 | /* H_RST may be found lit before reset is started, | 1070 | /* H_RST may be found lit before reset is started, |
1068 | * for example if preceding reset flow hasn't completed. | 1071 | * for example if preceding reset flow hasn't completed. |
diff --git a/drivers/misc/mei/hw-txe.c b/drivers/misc/mei/hw-txe.c index 4a6c1b85f11e..e6e5e55a12ed 100644 --- a/drivers/misc/mei/hw-txe.c +++ b/drivers/misc/mei/hw-txe.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/delay.h> | 20 | #include <linux/delay.h> |
21 | #include <linux/kthread.h> | 21 | #include <linux/kthread.h> |
22 | #include <linux/irqreturn.h> | 22 | #include <linux/irqreturn.h> |
23 | #include <linux/pm_runtime.h> | ||
23 | 24 | ||
24 | #include <linux/mei.h> | 25 | #include <linux/mei.h> |
25 | 26 | ||
@@ -935,6 +936,8 @@ static int mei_txe_hw_start(struct mei_device *dev) | |||
935 | return ret; | 936 | return ret; |
936 | } | 937 | } |
937 | 938 | ||
939 | pm_runtime_set_active(dev->dev); | ||
940 | |||
938 | /* enable input ready interrupts: | 941 | /* enable input ready interrupts: |
939 | * SEC_IPC_HOST_INT_MASK.IPC_INPUT_READY_INT_MASK | 942 | * SEC_IPC_HOST_INT_MASK.IPC_INPUT_READY_INT_MASK |
940 | */ | 943 | */ |
diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c index f7c8dfdb6a12..9a9c2484d107 100644 --- a/drivers/misc/mei/init.c +++ b/drivers/misc/mei/init.c | |||
@@ -94,7 +94,7 @@ void mei_cancel_work(struct mei_device *dev) | |||
94 | cancel_work_sync(&dev->reset_work); | 94 | cancel_work_sync(&dev->reset_work); |
95 | cancel_work_sync(&dev->bus_rescan_work); | 95 | cancel_work_sync(&dev->bus_rescan_work); |
96 | 96 | ||
97 | cancel_delayed_work(&dev->timer_work); | 97 | cancel_delayed_work_sync(&dev->timer_work); |
98 | } | 98 | } |
99 | EXPORT_SYMBOL_GPL(mei_cancel_work); | 99 | EXPORT_SYMBOL_GPL(mei_cancel_work); |
100 | 100 | ||
diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c index 3831a7ba2531..5a4893ce9c24 100644 --- a/drivers/misc/mei/interrupt.c +++ b/drivers/misc/mei/interrupt.c | |||
@@ -102,26 +102,25 @@ int mei_cl_irq_read_msg(struct mei_cl *cl, | |||
102 | { | 102 | { |
103 | struct mei_device *dev = cl->dev; | 103 | struct mei_device *dev = cl->dev; |
104 | struct mei_cl_cb *cb; | 104 | struct mei_cl_cb *cb; |
105 | unsigned char *buffer = NULL; | ||
106 | size_t buf_sz; | 105 | size_t buf_sz; |
107 | 106 | ||
108 | cb = list_first_entry_or_null(&cl->rd_pending, struct mei_cl_cb, list); | 107 | cb = list_first_entry_or_null(&cl->rd_pending, struct mei_cl_cb, list); |
109 | if (!cb) { | 108 | if (!cb) { |
110 | cl_err(dev, cl, "pending read cb not found\n"); | 109 | if (!mei_cl_is_fixed_address(cl)) { |
111 | goto out; | 110 | cl_err(dev, cl, "pending read cb not found\n"); |
111 | goto discard; | ||
112 | } | ||
113 | cb = mei_cl_alloc_cb(cl, mei_cl_mtu(cl), MEI_FOP_READ, cl->fp); | ||
114 | if (!cb) | ||
115 | goto discard; | ||
116 | list_add_tail(&cb->list, &cl->rd_pending); | ||
112 | } | 117 | } |
113 | 118 | ||
114 | if (!mei_cl_is_connected(cl)) { | 119 | if (!mei_cl_is_connected(cl)) { |
115 | cl_dbg(dev, cl, "not connected\n"); | 120 | cl_dbg(dev, cl, "not connected\n"); |
116 | cb->status = -ENODEV; | ||
117 | goto out; | ||
118 | } | ||
119 | |||
120 | if (cb->buf.size == 0 || cb->buf.data == NULL) { | ||
121 | cl_err(dev, cl, "response buffer is not allocated.\n"); | ||
122 | list_move_tail(&cb->list, &complete_list->list); | 121 | list_move_tail(&cb->list, &complete_list->list); |
123 | cb->status = -ENOMEM; | 122 | cb->status = -ENODEV; |
124 | goto out; | 123 | goto discard; |
125 | } | 124 | } |
126 | 125 | ||
127 | buf_sz = mei_hdr->length + cb->buf_idx; | 126 | buf_sz = mei_hdr->length + cb->buf_idx; |
@@ -132,25 +131,19 @@ int mei_cl_irq_read_msg(struct mei_cl *cl, | |||
132 | 131 | ||
133 | list_move_tail(&cb->list, &complete_list->list); | 132 | list_move_tail(&cb->list, &complete_list->list); |
134 | cb->status = -EMSGSIZE; | 133 | cb->status = -EMSGSIZE; |
135 | goto out; | 134 | goto discard; |
136 | } | 135 | } |
137 | 136 | ||
138 | if (cb->buf.size < buf_sz) { | 137 | if (cb->buf.size < buf_sz) { |
139 | cl_dbg(dev, cl, "message overflow. size %zu len %d idx %zu\n", | 138 | cl_dbg(dev, cl, "message overflow. size %zu len %d idx %zu\n", |
140 | cb->buf.size, mei_hdr->length, cb->buf_idx); | 139 | cb->buf.size, mei_hdr->length, cb->buf_idx); |
141 | buffer = krealloc(cb->buf.data, buf_sz, GFP_KERNEL); | ||
142 | 140 | ||
143 | if (!buffer) { | 141 | list_move_tail(&cb->list, &complete_list->list); |
144 | cb->status = -ENOMEM; | 142 | cb->status = -EMSGSIZE; |
145 | list_move_tail(&cb->list, &complete_list->list); | 143 | goto discard; |
146 | goto out; | ||
147 | } | ||
148 | cb->buf.data = buffer; | ||
149 | cb->buf.size = buf_sz; | ||
150 | } | 144 | } |
151 | 145 | ||
152 | buffer = cb->buf.data + cb->buf_idx; | 146 | mei_read_slots(dev, cb->buf.data + cb->buf_idx, mei_hdr->length); |
153 | mei_read_slots(dev, buffer, mei_hdr->length); | ||
154 | 147 | ||
155 | cb->buf_idx += mei_hdr->length; | 148 | cb->buf_idx += mei_hdr->length; |
156 | 149 | ||
@@ -162,10 +155,10 @@ int mei_cl_irq_read_msg(struct mei_cl *cl, | |||
162 | pm_request_autosuspend(dev->dev); | 155 | pm_request_autosuspend(dev->dev); |
163 | } | 156 | } |
164 | 157 | ||
165 | out: | 158 | return 0; |
166 | if (!buffer) | ||
167 | mei_irq_discard_msg(dev, mei_hdr); | ||
168 | 159 | ||
160 | discard: | ||
161 | mei_irq_discard_msg(dev, mei_hdr); | ||
169 | return 0; | 162 | return 0; |
170 | } | 163 | } |
171 | 164 | ||
@@ -216,6 +209,9 @@ static int mei_cl_irq_read(struct mei_cl *cl, struct mei_cl_cb *cb, | |||
216 | int slots; | 209 | int slots; |
217 | int ret; | 210 | int ret; |
218 | 211 | ||
212 | if (!list_empty(&cl->rd_pending)) | ||
213 | return 0; | ||
214 | |||
219 | msg_slots = mei_data2slots(sizeof(struct hbm_flow_control)); | 215 | msg_slots = mei_data2slots(sizeof(struct hbm_flow_control)); |
220 | slots = mei_hbuf_empty_slots(dev); | 216 | slots = mei_hbuf_empty_slots(dev); |
221 | 217 | ||
@@ -463,6 +459,19 @@ static void mei_connect_timeout(struct mei_cl *cl) | |||
463 | mei_reset(dev); | 459 | mei_reset(dev); |
464 | } | 460 | } |
465 | 461 | ||
462 | #define MEI_STALL_TIMER_FREQ (2 * HZ) | ||
463 | /** | ||
464 | * mei_schedule_stall_timer - re-arm stall_timer work | ||
465 | * | ||
466 | * Schedule stall timer | ||
467 | * | ||
468 | * @dev: the device structure | ||
469 | */ | ||
470 | void mei_schedule_stall_timer(struct mei_device *dev) | ||
471 | { | ||
472 | schedule_delayed_work(&dev->timer_work, MEI_STALL_TIMER_FREQ); | ||
473 | } | ||
474 | |||
466 | /** | 475 | /** |
467 | * mei_timer - timer function. | 476 | * mei_timer - timer function. |
468 | * | 477 | * |
@@ -472,10 +481,9 @@ static void mei_connect_timeout(struct mei_cl *cl) | |||
472 | void mei_timer(struct work_struct *work) | 481 | void mei_timer(struct work_struct *work) |
473 | { | 482 | { |
474 | struct mei_cl *cl; | 483 | struct mei_cl *cl; |
475 | |||
476 | struct mei_device *dev = container_of(work, | 484 | struct mei_device *dev = container_of(work, |
477 | struct mei_device, timer_work.work); | 485 | struct mei_device, timer_work.work); |
478 | 486 | bool reschedule_timer = false; | |
479 | 487 | ||
480 | mutex_lock(&dev->device_lock); | 488 | mutex_lock(&dev->device_lock); |
481 | 489 | ||
@@ -490,6 +498,7 @@ void mei_timer(struct work_struct *work) | |||
490 | mei_reset(dev); | 498 | mei_reset(dev); |
491 | goto out; | 499 | goto out; |
492 | } | 500 | } |
501 | reschedule_timer = true; | ||
493 | } | 502 | } |
494 | } | 503 | } |
495 | 504 | ||
@@ -504,6 +513,7 @@ void mei_timer(struct work_struct *work) | |||
504 | mei_connect_timeout(cl); | 513 | mei_connect_timeout(cl); |
505 | goto out; | 514 | goto out; |
506 | } | 515 | } |
516 | reschedule_timer = true; | ||
507 | } | 517 | } |
508 | } | 518 | } |
509 | 519 | ||
@@ -514,19 +524,16 @@ void mei_timer(struct work_struct *work) | |||
514 | if (--dev->iamthif_stall_timer == 0) { | 524 | if (--dev->iamthif_stall_timer == 0) { |
515 | dev_err(dev->dev, "timer: amthif hanged.\n"); | 525 | dev_err(dev->dev, "timer: amthif hanged.\n"); |
516 | mei_reset(dev); | 526 | mei_reset(dev); |
517 | dev->iamthif_canceled = false; | ||
518 | dev->iamthif_state = MEI_IAMTHIF_IDLE; | ||
519 | 527 | ||
520 | mei_io_cb_free(dev->iamthif_current_cb); | ||
521 | dev->iamthif_current_cb = NULL; | ||
522 | |||
523 | dev->iamthif_fp = NULL; | ||
524 | mei_amthif_run_next_cmd(dev); | 528 | mei_amthif_run_next_cmd(dev); |
529 | goto out; | ||
525 | } | 530 | } |
531 | reschedule_timer = true; | ||
526 | } | 532 | } |
527 | 533 | ||
528 | out: | 534 | out: |
529 | if (dev->dev_state != MEI_DEV_DISABLED) | 535 | if (dev->dev_state != MEI_DEV_DISABLED && reschedule_timer) |
530 | schedule_delayed_work(&dev->timer_work, 2 * HZ); | 536 | mei_schedule_stall_timer(dev); |
537 | |||
531 | mutex_unlock(&dev->device_lock); | 538 | mutex_unlock(&dev->device_lock); |
532 | } | 539 | } |
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index 52635b063873..fa50635512e8 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c | |||
@@ -71,6 +71,7 @@ static int mei_open(struct inode *inode, struct file *file) | |||
71 | goto err_unlock; | 71 | goto err_unlock; |
72 | } | 72 | } |
73 | 73 | ||
74 | cl->fp = file; | ||
74 | file->private_data = cl; | 75 | file->private_data = cl; |
75 | 76 | ||
76 | mutex_unlock(&dev->device_lock); | 77 | mutex_unlock(&dev->device_lock); |
@@ -138,9 +139,8 @@ static ssize_t mei_read(struct file *file, char __user *ubuf, | |||
138 | struct mei_cl *cl = file->private_data; | 139 | struct mei_cl *cl = file->private_data; |
139 | struct mei_device *dev; | 140 | struct mei_device *dev; |
140 | struct mei_cl_cb *cb = NULL; | 141 | struct mei_cl_cb *cb = NULL; |
142 | bool nonblock = !!(file->f_flags & O_NONBLOCK); | ||
141 | int rets; | 143 | int rets; |
142 | int err; | ||
143 | |||
144 | 144 | ||
145 | if (WARN_ON(!cl || !cl->dev)) | 145 | if (WARN_ON(!cl || !cl->dev)) |
146 | return -ENODEV; | 146 | return -ENODEV; |
@@ -164,11 +164,6 @@ static ssize_t mei_read(struct file *file, char __user *ubuf, | |||
164 | goto out; | 164 | goto out; |
165 | } | 165 | } |
166 | 166 | ||
167 | if (cl == &dev->iamthif_cl) { | ||
168 | rets = mei_amthif_read(dev, file, ubuf, length, offset); | ||
169 | goto out; | ||
170 | } | ||
171 | |||
172 | cb = mei_cl_read_cb(cl, file); | 167 | cb = mei_cl_read_cb(cl, file); |
173 | if (cb) | 168 | if (cb) |
174 | goto copy_buffer; | 169 | goto copy_buffer; |
@@ -176,24 +171,29 @@ static ssize_t mei_read(struct file *file, char __user *ubuf, | |||
176 | if (*offset > 0) | 171 | if (*offset > 0) |
177 | *offset = 0; | 172 | *offset = 0; |
178 | 173 | ||
179 | err = mei_cl_read_start(cl, length, file); | 174 | rets = mei_cl_read_start(cl, length, file); |
180 | if (err && err != -EBUSY) { | 175 | if (rets && rets != -EBUSY) { |
181 | cl_dbg(dev, cl, "mei start read failure status = %d\n", err); | 176 | cl_dbg(dev, cl, "mei start read failure status = %d\n", rets); |
182 | rets = err; | ||
183 | goto out; | 177 | goto out; |
184 | } | 178 | } |
185 | 179 | ||
186 | if (list_empty(&cl->rd_completed) && !waitqueue_active(&cl->rx_wait)) { | 180 | if (nonblock) { |
187 | if (file->f_flags & O_NONBLOCK) { | 181 | rets = -EAGAIN; |
188 | rets = -EAGAIN; | 182 | goto out; |
189 | goto out; | 183 | } |
190 | } | ||
191 | 184 | ||
185 | if (rets == -EBUSY && | ||
186 | !mei_cl_enqueue_ctrl_wr_cb(cl, length, MEI_FOP_READ, file)) { | ||
187 | rets = -ENOMEM; | ||
188 | goto out; | ||
189 | } | ||
190 | |||
191 | do { | ||
192 | mutex_unlock(&dev->device_lock); | 192 | mutex_unlock(&dev->device_lock); |
193 | 193 | ||
194 | if (wait_event_interruptible(cl->rx_wait, | 194 | if (wait_event_interruptible(cl->rx_wait, |
195 | (!list_empty(&cl->rd_completed)) || | 195 | (!list_empty(&cl->rd_completed)) || |
196 | (!mei_cl_is_connected(cl)))) { | 196 | (!mei_cl_is_connected(cl)))) { |
197 | 197 | ||
198 | if (signal_pending(current)) | 198 | if (signal_pending(current)) |
199 | return -EINTR; | 199 | return -EINTR; |
@@ -202,16 +202,12 @@ static ssize_t mei_read(struct file *file, char __user *ubuf, | |||
202 | 202 | ||
203 | mutex_lock(&dev->device_lock); | 203 | mutex_lock(&dev->device_lock); |
204 | if (!mei_cl_is_connected(cl)) { | 204 | if (!mei_cl_is_connected(cl)) { |
205 | rets = -EBUSY; | 205 | rets = -ENODEV; |
206 | goto out; | 206 | goto out; |
207 | } | 207 | } |
208 | } | ||
209 | 208 | ||
210 | cb = mei_cl_read_cb(cl, file); | 209 | cb = mei_cl_read_cb(cl, file); |
211 | if (!cb) { | 210 | } while (!cb); |
212 | rets = 0; | ||
213 | goto out; | ||
214 | } | ||
215 | 211 | ||
216 | copy_buffer: | 212 | copy_buffer: |
217 | /* now copy the data to user space */ | 213 | /* now copy the data to user space */ |
@@ -609,24 +605,24 @@ static unsigned int mei_poll(struct file *file, poll_table *wait) | |||
609 | goto out; | 605 | goto out; |
610 | } | 606 | } |
611 | 607 | ||
612 | if (cl == &dev->iamthif_cl) { | ||
613 | mask = mei_amthif_poll(dev, file, wait); | ||
614 | goto out; | ||
615 | } | ||
616 | |||
617 | if (notify_en) { | 608 | if (notify_en) { |
618 | poll_wait(file, &cl->ev_wait, wait); | 609 | poll_wait(file, &cl->ev_wait, wait); |
619 | if (cl->notify_ev) | 610 | if (cl->notify_ev) |
620 | mask |= POLLPRI; | 611 | mask |= POLLPRI; |
621 | } | 612 | } |
622 | 613 | ||
614 | if (cl == &dev->iamthif_cl) { | ||
615 | mask |= mei_amthif_poll(file, wait); | ||
616 | goto out; | ||
617 | } | ||
618 | |||
623 | if (req_events & (POLLIN | POLLRDNORM)) { | 619 | if (req_events & (POLLIN | POLLRDNORM)) { |
624 | poll_wait(file, &cl->rx_wait, wait); | 620 | poll_wait(file, &cl->rx_wait, wait); |
625 | 621 | ||
626 | if (!list_empty(&cl->rd_completed)) | 622 | if (!list_empty(&cl->rd_completed)) |
627 | mask |= POLLIN | POLLRDNORM; | 623 | mask |= POLLIN | POLLRDNORM; |
628 | else | 624 | else |
629 | mei_cl_read_start(cl, 0, file); | 625 | mei_cl_read_start(cl, mei_cl_mtu(cl), file); |
630 | } | 626 | } |
631 | 627 | ||
632 | out: | 628 | out: |
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index e5e32503d4bc..1169fd9e7d02 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h | |||
@@ -80,18 +80,13 @@ const char *mei_dev_state_str(int state); | |||
80 | enum iamthif_states { | 80 | enum iamthif_states { |
81 | MEI_IAMTHIF_IDLE, | 81 | MEI_IAMTHIF_IDLE, |
82 | MEI_IAMTHIF_WRITING, | 82 | MEI_IAMTHIF_WRITING, |
83 | MEI_IAMTHIF_FLOW_CONTROL, | ||
84 | MEI_IAMTHIF_READING, | 83 | MEI_IAMTHIF_READING, |
85 | MEI_IAMTHIF_READ_COMPLETE | ||
86 | }; | 84 | }; |
87 | 85 | ||
88 | enum mei_file_transaction_states { | 86 | enum mei_file_transaction_states { |
89 | MEI_IDLE, | 87 | MEI_IDLE, |
90 | MEI_WRITING, | 88 | MEI_WRITING, |
91 | MEI_WRITE_COMPLETE, | 89 | MEI_WRITE_COMPLETE, |
92 | MEI_FLOW_CONTROL, | ||
93 | MEI_READING, | ||
94 | MEI_READ_COMPLETE | ||
95 | }; | 90 | }; |
96 | 91 | ||
97 | /** | 92 | /** |
@@ -146,7 +141,7 @@ struct mei_fw_status { | |||
146 | * @refcnt: struct reference count | 141 | * @refcnt: struct reference count |
147 | * @props: client properties | 142 | * @props: client properties |
148 | * @client_id: me client id | 143 | * @client_id: me client id |
149 | * @mei_flow_ctrl_creds: flow control credits | 144 | * @tx_flow_ctrl_creds: flow control credits |
150 | * @connect_count: number connections to this client | 145 | * @connect_count: number connections to this client |
151 | * @bus_added: added to bus | 146 | * @bus_added: added to bus |
152 | */ | 147 | */ |
@@ -155,7 +150,7 @@ struct mei_me_client { | |||
155 | struct kref refcnt; | 150 | struct kref refcnt; |
156 | struct mei_client_properties props; | 151 | struct mei_client_properties props; |
157 | u8 client_id; | 152 | u8 client_id; |
158 | u8 mei_flow_ctrl_creds; | 153 | u8 tx_flow_ctrl_creds; |
159 | u8 connect_count; | 154 | u8 connect_count; |
160 | u8 bus_added; | 155 | u8 bus_added; |
161 | }; | 156 | }; |
@@ -202,10 +197,11 @@ struct mei_cl_cb { | |||
202 | * @ev_async: event async notification | 197 | * @ev_async: event async notification |
203 | * @status: connection status | 198 | * @status: connection status |
204 | * @me_cl: fw client connected | 199 | * @me_cl: fw client connected |
200 | * @fp: file associated with client | ||
205 | * @host_client_id: host id | 201 | * @host_client_id: host id |
206 | * @mei_flow_ctrl_creds: transmit flow credentials | 202 | * @tx_flow_ctrl_creds: transmit flow credentials |
203 | * @rx_flow_ctrl_creds: receive flow credentials | ||
207 | * @timer_count: watchdog timer for operation completion | 204 | * @timer_count: watchdog timer for operation completion |
208 | * @reserved: reserved for alignment | ||
209 | * @notify_en: notification - enabled/disabled | 205 | * @notify_en: notification - enabled/disabled |
210 | * @notify_ev: pending notification event | 206 | * @notify_ev: pending notification event |
211 | * @writing_state: state of the tx | 207 | * @writing_state: state of the tx |
@@ -225,10 +221,11 @@ struct mei_cl { | |||
225 | struct fasync_struct *ev_async; | 221 | struct fasync_struct *ev_async; |
226 | int status; | 222 | int status; |
227 | struct mei_me_client *me_cl; | 223 | struct mei_me_client *me_cl; |
224 | const struct file *fp; | ||
228 | u8 host_client_id; | 225 | u8 host_client_id; |
229 | u8 mei_flow_ctrl_creds; | 226 | u8 tx_flow_ctrl_creds; |
227 | u8 rx_flow_ctrl_creds; | ||
230 | u8 timer_count; | 228 | u8 timer_count; |
231 | u8 reserved; | ||
232 | u8 notify_en; | 229 | u8 notify_en; |
233 | u8 notify_ev; | 230 | u8 notify_ev; |
234 | enum mei_file_transaction_states writing_state; | 231 | enum mei_file_transaction_states writing_state; |
@@ -400,9 +397,7 @@ const char *mei_pg_state_str(enum mei_pg_state state); | |||
400 | * @override_fixed_address: force allow fixed address behavior | 397 | * @override_fixed_address: force allow fixed address behavior |
401 | * | 398 | * |
402 | * @amthif_cmd_list : amthif list for cmd waiting | 399 | * @amthif_cmd_list : amthif list for cmd waiting |
403 | * @iamthif_fp : file for current amthif operation | ||
404 | * @iamthif_cl : amthif host client | 400 | * @iamthif_cl : amthif host client |
405 | * @iamthif_current_cb : amthif current operation callback | ||
406 | * @iamthif_open_count : number of opened amthif connections | 401 | * @iamthif_open_count : number of opened amthif connections |
407 | * @iamthif_stall_timer : timer to detect amthif hang | 402 | * @iamthif_stall_timer : timer to detect amthif hang |
408 | * @iamthif_state : amthif processor state | 403 | * @iamthif_state : amthif processor state |
@@ -484,10 +479,7 @@ struct mei_device { | |||
484 | 479 | ||
485 | /* amthif list for cmd waiting */ | 480 | /* amthif list for cmd waiting */ |
486 | struct mei_cl_cb amthif_cmd_list; | 481 | struct mei_cl_cb amthif_cmd_list; |
487 | /* driver managed amthif list for reading completed amthif cmd data */ | ||
488 | const struct file *iamthif_fp; | ||
489 | struct mei_cl iamthif_cl; | 482 | struct mei_cl iamthif_cl; |
490 | struct mei_cl_cb *iamthif_current_cb; | ||
491 | long iamthif_open_count; | 483 | long iamthif_open_count; |
492 | u32 iamthif_stall_timer; | 484 | u32 iamthif_stall_timer; |
493 | enum iamthif_states iamthif_state; | 485 | enum iamthif_states iamthif_state; |
@@ -556,6 +548,7 @@ void mei_cancel_work(struct mei_device *dev); | |||
556 | */ | 548 | */ |
557 | 549 | ||
558 | void mei_timer(struct work_struct *work); | 550 | void mei_timer(struct work_struct *work); |
551 | void mei_schedule_stall_timer(struct mei_device *dev); | ||
559 | int mei_irq_read_handler(struct mei_device *dev, | 552 | int mei_irq_read_handler(struct mei_device *dev, |
560 | struct mei_cl_cb *cmpl_list, s32 *slots); | 553 | struct mei_cl_cb *cmpl_list, s32 *slots); |
561 | 554 | ||
@@ -569,11 +562,7 @@ void mei_amthif_reset_params(struct mei_device *dev); | |||
569 | 562 | ||
570 | int mei_amthif_host_init(struct mei_device *dev, struct mei_me_client *me_cl); | 563 | int mei_amthif_host_init(struct mei_device *dev, struct mei_me_client *me_cl); |
571 | 564 | ||
572 | int mei_amthif_read(struct mei_device *dev, struct file *file, | 565 | unsigned int mei_amthif_poll(struct file *file, poll_table *wait); |
573 | char __user *ubuf, size_t length, loff_t *offset); | ||
574 | |||
575 | unsigned int mei_amthif_poll(struct mei_device *dev, | ||
576 | struct file *file, poll_table *wait); | ||
577 | 566 | ||
578 | int mei_amthif_release(struct mei_device *dev, struct file *file); | 567 | int mei_amthif_release(struct mei_device *dev, struct file *file); |
579 | 568 | ||
diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c index 71cea9b296b2..f3ffd883b232 100644 --- a/drivers/misc/mei/pci-me.c +++ b/drivers/misc/mei/pci-me.c | |||
@@ -91,6 +91,9 @@ static const struct pci_device_id mei_me_pci_tbl[] = { | |||
91 | {MEI_PCI_DEVICE(MEI_DEV_ID_BXT_M, mei_me_pch8_cfg)}, | 91 | {MEI_PCI_DEVICE(MEI_DEV_ID_BXT_M, mei_me_pch8_cfg)}, |
92 | {MEI_PCI_DEVICE(MEI_DEV_ID_APL_I, mei_me_pch8_cfg)}, | 92 | {MEI_PCI_DEVICE(MEI_DEV_ID_APL_I, mei_me_pch8_cfg)}, |
93 | 93 | ||
94 | {MEI_PCI_DEVICE(MEI_DEV_ID_KBP, mei_me_pch8_cfg)}, | ||
95 | {MEI_PCI_DEVICE(MEI_DEV_ID_KBP_2, mei_me_pch8_cfg)}, | ||
96 | |||
94 | /* required last entry */ | 97 | /* required last entry */ |
95 | {0, } | 98 | {0, } |
96 | }; | 99 | }; |
@@ -217,8 +220,6 @@ static int mei_me_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
217 | 220 | ||
218 | pci_set_drvdata(pdev, dev); | 221 | pci_set_drvdata(pdev, dev); |
219 | 222 | ||
220 | schedule_delayed_work(&dev->timer_work, HZ); | ||
221 | |||
222 | /* | 223 | /* |
223 | * For not wake-able HW runtime pm framework | 224 | * For not wake-able HW runtime pm framework |
224 | * can't be used on pci device level. | 225 | * can't be used on pci device level. |
@@ -400,6 +401,9 @@ static int mei_me_pm_runtime_suspend(struct device *device) | |||
400 | 401 | ||
401 | dev_dbg(&pdev->dev, "rpm: me: runtime suspend ret=%d\n", ret); | 402 | dev_dbg(&pdev->dev, "rpm: me: runtime suspend ret=%d\n", ret); |
402 | 403 | ||
404 | if (ret && ret != -EAGAIN) | ||
405 | schedule_work(&dev->reset_work); | ||
406 | |||
403 | return ret; | 407 | return ret; |
404 | } | 408 | } |
405 | 409 | ||
@@ -423,6 +427,9 @@ static int mei_me_pm_runtime_resume(struct device *device) | |||
423 | 427 | ||
424 | dev_dbg(&pdev->dev, "rpm: me: runtime resume ret = %d\n", ret); | 428 | dev_dbg(&pdev->dev, "rpm: me: runtime resume ret = %d\n", ret); |
425 | 429 | ||
430 | if (ret) | ||
431 | schedule_work(&dev->reset_work); | ||
432 | |||
426 | return ret; | 433 | return ret; |
427 | } | 434 | } |
428 | 435 | ||
diff --git a/drivers/misc/mei/pci-txe.c b/drivers/misc/mei/pci-txe.c index 30cc30683c07..58ffd30dcc91 100644 --- a/drivers/misc/mei/pci-txe.c +++ b/drivers/misc/mei/pci-txe.c | |||
@@ -347,6 +347,10 @@ static int mei_txe_pm_runtime_suspend(struct device *device) | |||
347 | dev_dbg(&pdev->dev, "rpm: txe: runtime suspend ret=%d\n", ret); | 347 | dev_dbg(&pdev->dev, "rpm: txe: runtime suspend ret=%d\n", ret); |
348 | 348 | ||
349 | mutex_unlock(&dev->device_lock); | 349 | mutex_unlock(&dev->device_lock); |
350 | |||
351 | if (ret && ret != -EAGAIN) | ||
352 | schedule_work(&dev->reset_work); | ||
353 | |||
350 | return ret; | 354 | return ret; |
351 | } | 355 | } |
352 | 356 | ||
@@ -372,6 +376,9 @@ static int mei_txe_pm_runtime_resume(struct device *device) | |||
372 | 376 | ||
373 | dev_dbg(&pdev->dev, "rpm: txe: runtime resume ret = %d\n", ret); | 377 | dev_dbg(&pdev->dev, "rpm: txe: runtime resume ret = %d\n", ret); |
374 | 378 | ||
379 | if (ret) | ||
380 | schedule_work(&dev->reset_work); | ||
381 | |||
375 | return ret; | 382 | return ret; |
376 | } | 383 | } |
377 | 384 | ||
diff --git a/drivers/misc/mic/scif/scif_dma.c b/drivers/misc/mic/scif/scif_dma.c index cd01a0efda6b..64d5760d069a 100644 --- a/drivers/misc/mic/scif/scif_dma.c +++ b/drivers/misc/mic/scif/scif_dma.c | |||
@@ -115,7 +115,6 @@ int scif_reserve_dma_chan(struct scif_endpt *ep) | |||
115 | */ | 115 | */ |
116 | static | 116 | static |
117 | void __scif_rma_destroy_tcw(struct scif_mmu_notif *mmn, | 117 | void __scif_rma_destroy_tcw(struct scif_mmu_notif *mmn, |
118 | struct scif_endpt *ep, | ||
119 | u64 start, u64 len) | 118 | u64 start, u64 len) |
120 | { | 119 | { |
121 | struct list_head *item, *tmp; | 120 | struct list_head *item, *tmp; |
@@ -128,7 +127,6 @@ void __scif_rma_destroy_tcw(struct scif_mmu_notif *mmn, | |||
128 | 127 | ||
129 | list_for_each_safe(item, tmp, &mmn->tc_reg_list) { | 128 | list_for_each_safe(item, tmp, &mmn->tc_reg_list) { |
130 | window = list_entry(item, struct scif_window, list); | 129 | window = list_entry(item, struct scif_window, list); |
131 | ep = (struct scif_endpt *)window->ep; | ||
132 | if (!len) | 130 | if (!len) |
133 | break; | 131 | break; |
134 | start_va = window->va_for_temp; | 132 | start_va = window->va_for_temp; |
@@ -146,7 +144,7 @@ static void scif_rma_destroy_tcw(struct scif_mmu_notif *mmn, u64 start, u64 len) | |||
146 | struct scif_endpt *ep = mmn->ep; | 144 | struct scif_endpt *ep = mmn->ep; |
147 | 145 | ||
148 | spin_lock(&ep->rma_info.tc_lock); | 146 | spin_lock(&ep->rma_info.tc_lock); |
149 | __scif_rma_destroy_tcw(mmn, ep, start, len); | 147 | __scif_rma_destroy_tcw(mmn, start, len); |
150 | spin_unlock(&ep->rma_info.tc_lock); | 148 | spin_unlock(&ep->rma_info.tc_lock); |
151 | } | 149 | } |
152 | 150 | ||
@@ -169,7 +167,7 @@ static void __scif_rma_destroy_tcw_ep(struct scif_endpt *ep) | |||
169 | spin_lock(&ep->rma_info.tc_lock); | 167 | spin_lock(&ep->rma_info.tc_lock); |
170 | list_for_each_safe(item, tmp, &ep->rma_info.mmn_list) { | 168 | list_for_each_safe(item, tmp, &ep->rma_info.mmn_list) { |
171 | mmn = list_entry(item, struct scif_mmu_notif, list); | 169 | mmn = list_entry(item, struct scif_mmu_notif, list); |
172 | __scif_rma_destroy_tcw(mmn, ep, 0, ULONG_MAX); | 170 | __scif_rma_destroy_tcw(mmn, 0, ULONG_MAX); |
173 | } | 171 | } |
174 | spin_unlock(&ep->rma_info.tc_lock); | 172 | spin_unlock(&ep->rma_info.tc_lock); |
175 | } | 173 | } |
diff --git a/drivers/misc/mic/scif/scif_mmap.c b/drivers/misc/mic/scif/scif_mmap.c index 49cb8f7b4672..928211677079 100644 --- a/drivers/misc/mic/scif/scif_mmap.c +++ b/drivers/misc/mic/scif/scif_mmap.c | |||
@@ -552,7 +552,7 @@ static void scif_munmap(struct vm_area_struct *vma) | |||
552 | { | 552 | { |
553 | struct scif_endpt *ep; | 553 | struct scif_endpt *ep; |
554 | struct vma_pvt *vmapvt = vma->vm_private_data; | 554 | struct vma_pvt *vmapvt = vma->vm_private_data; |
555 | int nr_pages = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; | 555 | int nr_pages = vma_pages(vma); |
556 | s64 offset; | 556 | s64 offset; |
557 | struct scif_rma_req req; | 557 | struct scif_rma_req req; |
558 | struct scif_window *window = NULL; | 558 | struct scif_window *window = NULL; |
@@ -614,7 +614,7 @@ int scif_mmap(struct vm_area_struct *vma, scif_epd_t epd) | |||
614 | struct scif_window *window = NULL; | 614 | struct scif_window *window = NULL; |
615 | struct scif_endpt *ep = (struct scif_endpt *)epd; | 615 | struct scif_endpt *ep = (struct scif_endpt *)epd; |
616 | s64 start_offset = vma->vm_pgoff << PAGE_SHIFT; | 616 | s64 start_offset = vma->vm_pgoff << PAGE_SHIFT; |
617 | int nr_pages = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; | 617 | int nr_pages = vma_pages(vma); |
618 | int err; | 618 | int err; |
619 | struct vma_pvt *vmapvt; | 619 | struct vma_pvt *vmapvt; |
620 | 620 | ||
diff --git a/drivers/misc/pch_phub.c b/drivers/misc/pch_phub.c index 4810e039bbec..e42bdc90fa27 100644 --- a/drivers/misc/pch_phub.c +++ b/drivers/misc/pch_phub.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/if_ether.h> | 28 | #include <linux/if_ether.h> |
29 | #include <linux/ctype.h> | 29 | #include <linux/ctype.h> |
30 | #include <linux/dmi.h> | 30 | #include <linux/dmi.h> |
31 | #include <linux/of.h> | ||
31 | 32 | ||
32 | #define PHUB_STATUS 0x00 /* Status Register offset */ | 33 | #define PHUB_STATUS 0x00 /* Status Register offset */ |
33 | #define PHUB_CONTROL 0x04 /* Control Register offset */ | 34 | #define PHUB_CONTROL 0x04 /* Control Register offset */ |
@@ -57,6 +58,7 @@ | |||
57 | 58 | ||
58 | /* CM-iTC */ | 59 | /* CM-iTC */ |
59 | #define CLKCFG_UART_48MHZ (1 << 16) | 60 | #define CLKCFG_UART_48MHZ (1 << 16) |
61 | #define CLKCFG_UART_25MHZ (2 << 16) | ||
60 | #define CLKCFG_BAUDDIV (2 << 20) | 62 | #define CLKCFG_BAUDDIV (2 << 20) |
61 | #define CLKCFG_PLL2VCO (8 << 9) | 63 | #define CLKCFG_PLL2VCO (8 << 9) |
62 | #define CLKCFG_UARTCLKSEL (1 << 18) | 64 | #define CLKCFG_UARTCLKSEL (1 << 18) |
@@ -711,6 +713,12 @@ static int pch_phub_probe(struct pci_dev *pdev, | |||
711 | 713 | ||
712 | if (id->driver_data == 1) { /* EG20T PCH */ | 714 | if (id->driver_data == 1) { /* EG20T PCH */ |
713 | const char *board_name; | 715 | const char *board_name; |
716 | unsigned int prefetch = 0x000affaa; | ||
717 | |||
718 | if (pdev->dev.of_node) | ||
719 | of_property_read_u32(pdev->dev.of_node, | ||
720 | "intel,eg20t-prefetch", | ||
721 | &prefetch); | ||
714 | 722 | ||
715 | ret = sysfs_create_file(&pdev->dev.kobj, | 723 | ret = sysfs_create_file(&pdev->dev.kobj, |
716 | &dev_attr_pch_mac.attr); | 724 | &dev_attr_pch_mac.attr); |
@@ -736,11 +744,21 @@ static int pch_phub_probe(struct pci_dev *pdev, | |||
736 | CLKCFG_UART_MASK); | 744 | CLKCFG_UART_MASK); |
737 | 745 | ||
738 | /* set the prefech value */ | 746 | /* set the prefech value */ |
739 | iowrite32(0x000affaa, chip->pch_phub_base_address + 0x14); | 747 | iowrite32(prefetch, chip->pch_phub_base_address + 0x14); |
740 | /* set the interrupt delay value */ | 748 | /* set the interrupt delay value */ |
741 | iowrite32(0x25, chip->pch_phub_base_address + 0x44); | 749 | iowrite32(0x25, chip->pch_phub_base_address + 0x44); |
742 | chip->pch_opt_rom_start_address = PCH_PHUB_ROM_START_ADDR_EG20T; | 750 | chip->pch_opt_rom_start_address = PCH_PHUB_ROM_START_ADDR_EG20T; |
743 | chip->pch_mac_start_address = PCH_PHUB_MAC_START_ADDR_EG20T; | 751 | chip->pch_mac_start_address = PCH_PHUB_MAC_START_ADDR_EG20T; |
752 | |||
753 | /* quirk for MIPS Boston platform */ | ||
754 | if (pdev->dev.of_node) { | ||
755 | if (of_machine_is_compatible("img,boston")) { | ||
756 | pch_phub_read_modify_write_reg(chip, | ||
757 | (unsigned int)CLKCFG_REG_OFFSET, | ||
758 | CLKCFG_UART_25MHZ, | ||
759 | CLKCFG_UART_MASK); | ||
760 | } | ||
761 | } | ||
744 | } else if (id->driver_data == 2) { /* ML7213 IOH */ | 762 | } else if (id->driver_data == 2) { /* ML7213 IOH */ |
745 | ret = sysfs_create_bin_file(&pdev->dev.kobj, &pch_bin_attr); | 763 | ret = sysfs_create_bin_file(&pdev->dev.kobj, &pch_bin_attr); |
746 | if (ret) | 764 | if (ret) |
diff --git a/drivers/misc/vmw_vmci/vmci_host.c b/drivers/misc/vmw_vmci/vmci_host.c index 9ec262a52656..ec090105eb4b 100644 --- a/drivers/misc/vmw_vmci/vmci_host.c +++ b/drivers/misc/vmw_vmci/vmci_host.c | |||
@@ -381,18 +381,12 @@ static int vmci_host_do_send_datagram(struct vmci_host_dev *vmci_host_dev, | |||
381 | return -EINVAL; | 381 | return -EINVAL; |
382 | } | 382 | } |
383 | 383 | ||
384 | dg = kmalloc(send_info.len, GFP_KERNEL); | 384 | dg = memdup_user((void __user *)(uintptr_t)send_info.addr, |
385 | if (!dg) { | 385 | send_info.len); |
386 | if (IS_ERR(dg)) { | ||
386 | vmci_ioctl_err( | 387 | vmci_ioctl_err( |
387 | "cannot allocate memory to dispatch datagram\n"); | 388 | "cannot allocate memory to dispatch datagram\n"); |
388 | return -ENOMEM; | 389 | return PTR_ERR(dg); |
389 | } | ||
390 | |||
391 | if (copy_from_user(dg, (void __user *)(uintptr_t)send_info.addr, | ||
392 | send_info.len)) { | ||
393 | vmci_ioctl_err("error getting datagram\n"); | ||
394 | kfree(dg); | ||
395 | return -EFAULT; | ||
396 | } | 390 | } |
397 | 391 | ||
398 | if (VMCI_DG_SIZE(dg) != send_info.len) { | 392 | if (VMCI_DG_SIZE(dg) != send_info.len) { |
diff --git a/drivers/nvmem/rockchip-efuse.c b/drivers/nvmem/rockchip-efuse.c index 4d3f391f0a0b..423907bdd259 100644 --- a/drivers/nvmem/rockchip-efuse.c +++ b/drivers/nvmem/rockchip-efuse.c | |||
@@ -22,17 +22,29 @@ | |||
22 | #include <linux/nvmem-provider.h> | 22 | #include <linux/nvmem-provider.h> |
23 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
24 | #include <linux/of.h> | 24 | #include <linux/of.h> |
25 | #include <linux/of_platform.h> | ||
25 | #include <linux/platform_device.h> | 26 | #include <linux/platform_device.h> |
26 | 27 | ||
27 | #define EFUSE_A_SHIFT 6 | 28 | #define RK3288_A_SHIFT 6 |
28 | #define EFUSE_A_MASK 0x3ff | 29 | #define RK3288_A_MASK 0x3ff |
29 | #define EFUSE_PGENB BIT(3) | 30 | #define RK3288_PGENB BIT(3) |
30 | #define EFUSE_LOAD BIT(2) | 31 | #define RK3288_LOAD BIT(2) |
31 | #define EFUSE_STROBE BIT(1) | 32 | #define RK3288_STROBE BIT(1) |
32 | #define EFUSE_CSB BIT(0) | 33 | #define RK3288_CSB BIT(0) |
33 | 34 | ||
34 | #define REG_EFUSE_CTRL 0x0000 | 35 | #define RK3399_A_SHIFT 16 |
35 | #define REG_EFUSE_DOUT 0x0004 | 36 | #define RK3399_A_MASK 0x3ff |
37 | #define RK3399_NBYTES 4 | ||
38 | #define RK3399_STROBSFTSEL BIT(9) | ||
39 | #define RK3399_RSB BIT(7) | ||
40 | #define RK3399_PD BIT(5) | ||
41 | #define RK3399_PGENB BIT(3) | ||
42 | #define RK3399_LOAD BIT(2) | ||
43 | #define RK3399_STROBE BIT(1) | ||
44 | #define RK3399_CSB BIT(0) | ||
45 | |||
46 | #define REG_EFUSE_CTRL 0x0000 | ||
47 | #define REG_EFUSE_DOUT 0x0004 | ||
36 | 48 | ||
37 | struct rockchip_efuse_chip { | 49 | struct rockchip_efuse_chip { |
38 | struct device *dev; | 50 | struct device *dev; |
@@ -40,8 +52,8 @@ struct rockchip_efuse_chip { | |||
40 | struct clk *clk; | 52 | struct clk *clk; |
41 | }; | 53 | }; |
42 | 54 | ||
43 | static int rockchip_efuse_read(void *context, unsigned int offset, | 55 | static int rockchip_rk3288_efuse_read(void *context, unsigned int offset, |
44 | void *val, size_t bytes) | 56 | void *val, size_t bytes) |
45 | { | 57 | { |
46 | struct rockchip_efuse_chip *efuse = context; | 58 | struct rockchip_efuse_chip *efuse = context; |
47 | u8 *buf = val; | 59 | u8 *buf = val; |
@@ -53,27 +65,82 @@ static int rockchip_efuse_read(void *context, unsigned int offset, | |||
53 | return ret; | 65 | return ret; |
54 | } | 66 | } |
55 | 67 | ||
56 | writel(EFUSE_LOAD | EFUSE_PGENB, efuse->base + REG_EFUSE_CTRL); | 68 | writel(RK3288_LOAD | RK3288_PGENB, efuse->base + REG_EFUSE_CTRL); |
57 | udelay(1); | 69 | udelay(1); |
58 | while (bytes--) { | 70 | while (bytes--) { |
59 | writel(readl(efuse->base + REG_EFUSE_CTRL) & | 71 | writel(readl(efuse->base + REG_EFUSE_CTRL) & |
60 | (~(EFUSE_A_MASK << EFUSE_A_SHIFT)), | 72 | (~(RK3288_A_MASK << RK3288_A_SHIFT)), |
61 | efuse->base + REG_EFUSE_CTRL); | 73 | efuse->base + REG_EFUSE_CTRL); |
62 | writel(readl(efuse->base + REG_EFUSE_CTRL) | | 74 | writel(readl(efuse->base + REG_EFUSE_CTRL) | |
63 | ((offset++ & EFUSE_A_MASK) << EFUSE_A_SHIFT), | 75 | ((offset++ & RK3288_A_MASK) << RK3288_A_SHIFT), |
64 | efuse->base + REG_EFUSE_CTRL); | 76 | efuse->base + REG_EFUSE_CTRL); |
65 | udelay(1); | 77 | udelay(1); |
66 | writel(readl(efuse->base + REG_EFUSE_CTRL) | | 78 | writel(readl(efuse->base + REG_EFUSE_CTRL) | |
67 | EFUSE_STROBE, efuse->base + REG_EFUSE_CTRL); | 79 | RK3288_STROBE, efuse->base + REG_EFUSE_CTRL); |
68 | udelay(1); | 80 | udelay(1); |
69 | *buf++ = readb(efuse->base + REG_EFUSE_DOUT); | 81 | *buf++ = readb(efuse->base + REG_EFUSE_DOUT); |
70 | writel(readl(efuse->base + REG_EFUSE_CTRL) & | 82 | writel(readl(efuse->base + REG_EFUSE_CTRL) & |
71 | (~EFUSE_STROBE), efuse->base + REG_EFUSE_CTRL); | 83 | (~RK3288_STROBE), efuse->base + REG_EFUSE_CTRL); |
84 | udelay(1); | ||
85 | } | ||
86 | |||
87 | /* Switch to standby mode */ | ||
88 | writel(RK3288_PGENB | RK3288_CSB, efuse->base + REG_EFUSE_CTRL); | ||
89 | |||
90 | clk_disable_unprepare(efuse->clk); | ||
91 | |||
92 | return 0; | ||
93 | } | ||
94 | |||
95 | static int rockchip_rk3399_efuse_read(void *context, unsigned int offset, | ||
96 | void *val, size_t bytes) | ||
97 | { | ||
98 | struct rockchip_efuse_chip *efuse = context; | ||
99 | unsigned int addr_start, addr_end, addr_offset, addr_len; | ||
100 | u32 out_value; | ||
101 | u8 *buf; | ||
102 | int ret, i = 0; | ||
103 | |||
104 | ret = clk_prepare_enable(efuse->clk); | ||
105 | if (ret < 0) { | ||
106 | dev_err(efuse->dev, "failed to prepare/enable efuse clk\n"); | ||
107 | return ret; | ||
108 | } | ||
109 | |||
110 | addr_start = rounddown(offset, RK3399_NBYTES) / RK3399_NBYTES; | ||
111 | addr_end = roundup(offset + bytes, RK3399_NBYTES) / RK3399_NBYTES; | ||
112 | addr_offset = offset % RK3399_NBYTES; | ||
113 | addr_len = addr_end - addr_start; | ||
114 | |||
115 | buf = kzalloc(sizeof(*buf) * addr_len * RK3399_NBYTES, GFP_KERNEL); | ||
116 | if (!buf) { | ||
117 | clk_disable_unprepare(efuse->clk); | ||
118 | return -ENOMEM; | ||
119 | } | ||
120 | |||
121 | writel(RK3399_LOAD | RK3399_PGENB | RK3399_STROBSFTSEL | RK3399_RSB, | ||
122 | efuse->base + REG_EFUSE_CTRL); | ||
123 | udelay(1); | ||
124 | while (addr_len--) { | ||
125 | writel(readl(efuse->base + REG_EFUSE_CTRL) | RK3399_STROBE | | ||
126 | ((addr_start++ & RK3399_A_MASK) << RK3399_A_SHIFT), | ||
127 | efuse->base + REG_EFUSE_CTRL); | ||
72 | udelay(1); | 128 | udelay(1); |
129 | out_value = readl(efuse->base + REG_EFUSE_DOUT); | ||
130 | writel(readl(efuse->base + REG_EFUSE_CTRL) & (~RK3399_STROBE), | ||
131 | efuse->base + REG_EFUSE_CTRL); | ||
132 | udelay(1); | ||
133 | |||
134 | memcpy(&buf[i], &out_value, RK3399_NBYTES); | ||
135 | i += RK3399_NBYTES; | ||
73 | } | 136 | } |
74 | 137 | ||
75 | /* Switch to standby mode */ | 138 | /* Switch to standby mode */ |
76 | writel(EFUSE_PGENB | EFUSE_CSB, efuse->base + REG_EFUSE_CTRL); | 139 | writel(RK3399_PD | RK3399_CSB, efuse->base + REG_EFUSE_CTRL); |
140 | |||
141 | memcpy(val, buf + addr_offset, bytes); | ||
142 | |||
143 | kfree(buf); | ||
77 | 144 | ||
78 | clk_disable_unprepare(efuse->clk); | 145 | clk_disable_unprepare(efuse->clk); |
79 | 146 | ||
@@ -89,7 +156,27 @@ static struct nvmem_config econfig = { | |||
89 | }; | 156 | }; |
90 | 157 | ||
91 | static const struct of_device_id rockchip_efuse_match[] = { | 158 | static const struct of_device_id rockchip_efuse_match[] = { |
92 | { .compatible = "rockchip,rockchip-efuse", }, | 159 | /* deprecated but kept around for dts binding compatibility */ |
160 | { | ||
161 | .compatible = "rockchip,rockchip-efuse", | ||
162 | .data = (void *)&rockchip_rk3288_efuse_read, | ||
163 | }, | ||
164 | { | ||
165 | .compatible = "rockchip,rk3066a-efuse", | ||
166 | .data = (void *)&rockchip_rk3288_efuse_read, | ||
167 | }, | ||
168 | { | ||
169 | .compatible = "rockchip,rk3188-efuse", | ||
170 | .data = (void *)&rockchip_rk3288_efuse_read, | ||
171 | }, | ||
172 | { | ||
173 | .compatible = "rockchip,rk3288-efuse", | ||
174 | .data = (void *)&rockchip_rk3288_efuse_read, | ||
175 | }, | ||
176 | { | ||
177 | .compatible = "rockchip,rk3399-efuse", | ||
178 | .data = (void *)&rockchip_rk3399_efuse_read, | ||
179 | }, | ||
93 | { /* sentinel */}, | 180 | { /* sentinel */}, |
94 | }; | 181 | }; |
95 | MODULE_DEVICE_TABLE(of, rockchip_efuse_match); | 182 | MODULE_DEVICE_TABLE(of, rockchip_efuse_match); |
@@ -99,6 +186,14 @@ static int rockchip_efuse_probe(struct platform_device *pdev) | |||
99 | struct resource *res; | 186 | struct resource *res; |
100 | struct nvmem_device *nvmem; | 187 | struct nvmem_device *nvmem; |
101 | struct rockchip_efuse_chip *efuse; | 188 | struct rockchip_efuse_chip *efuse; |
189 | const struct of_device_id *match; | ||
190 | struct device *dev = &pdev->dev; | ||
191 | |||
192 | match = of_match_device(dev->driver->of_match_table, dev); | ||
193 | if (!match || !match->data) { | ||
194 | dev_err(dev, "failed to get match data\n"); | ||
195 | return -EINVAL; | ||
196 | } | ||
102 | 197 | ||
103 | efuse = devm_kzalloc(&pdev->dev, sizeof(struct rockchip_efuse_chip), | 198 | efuse = devm_kzalloc(&pdev->dev, sizeof(struct rockchip_efuse_chip), |
104 | GFP_KERNEL); | 199 | GFP_KERNEL); |
@@ -116,7 +211,7 @@ static int rockchip_efuse_probe(struct platform_device *pdev) | |||
116 | 211 | ||
117 | efuse->dev = &pdev->dev; | 212 | efuse->dev = &pdev->dev; |
118 | econfig.size = resource_size(res); | 213 | econfig.size = resource_size(res); |
119 | econfig.reg_read = rockchip_efuse_read; | 214 | econfig.reg_read = match->data; |
120 | econfig.priv = efuse; | 215 | econfig.priv = efuse; |
121 | econfig.dev = efuse->dev; | 216 | econfig.dev = efuse->dev; |
122 | nvmem = nvmem_register(&econfig); | 217 | nvmem = nvmem_register(&econfig); |
diff --git a/drivers/s390/char/sclp_ctl.c b/drivers/s390/char/sclp_ctl.c index ea607a4a1bdd..554eaa1e347d 100644 --- a/drivers/s390/char/sclp_ctl.c +++ b/drivers/s390/char/sclp_ctl.c | |||
@@ -126,21 +126,4 @@ static struct miscdevice sclp_ctl_device = { | |||
126 | .name = "sclp", | 126 | .name = "sclp", |
127 | .fops = &sclp_ctl_fops, | 127 | .fops = &sclp_ctl_fops, |
128 | }; | 128 | }; |
129 | 129 | module_misc_device(sclp_ctl_device); | |
130 | /* | ||
131 | * Register sclp_ctl misc device | ||
132 | */ | ||
133 | static int __init sclp_ctl_init(void) | ||
134 | { | ||
135 | return misc_register(&sclp_ctl_device); | ||
136 | } | ||
137 | module_init(sclp_ctl_init); | ||
138 | |||
139 | /* | ||
140 | * Deregister sclp_ctl misc device | ||
141 | */ | ||
142 | static void __exit sclp_ctl_exit(void) | ||
143 | { | ||
144 | misc_deregister(&sclp_ctl_device); | ||
145 | } | ||
146 | module_exit(sclp_ctl_exit); | ||
diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c index aca282d45421..5ec3a595dc7d 100644 --- a/drivers/spmi/spmi-pmic-arb.c +++ b/drivers/spmi/spmi-pmic-arb.c | |||
@@ -954,6 +954,7 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev) | |||
954 | if (channel > 5) { | 954 | if (channel > 5) { |
955 | dev_err(&pdev->dev, "invalid channel (%u) specified.\n", | 955 | dev_err(&pdev->dev, "invalid channel (%u) specified.\n", |
956 | channel); | 956 | channel); |
957 | err = -EINVAL; | ||
957 | goto err_put_ctrl; | 958 | goto err_put_ctrl; |
958 | } | 959 | } |
959 | 960 | ||
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 518db24a5b36..c7831407a882 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig | |||
@@ -1380,7 +1380,7 @@ config SERIAL_IFX6X60 | |||
1380 | 1380 | ||
1381 | config SERIAL_PCH_UART | 1381 | config SERIAL_PCH_UART |
1382 | tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) UART" | 1382 | tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) UART" |
1383 | depends on PCI && (X86_32 || COMPILE_TEST) | 1383 | depends on PCI && (X86_32 || MIPS || COMPILE_TEST) |
1384 | select SERIAL_CORE | 1384 | select SERIAL_CORE |
1385 | help | 1385 | help |
1386 | This driver is for PCH(Platform controller Hub) UART of Intel EG20T | 1386 | This driver is for PCH(Platform controller Hub) UART of Intel EG20T |
diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index ea4ffc2ebb2f..23672f8a343e 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/dmi.h> | 31 | #include <linux/dmi.h> |
32 | #include <linux/nmi.h> | 32 | #include <linux/nmi.h> |
33 | #include <linux/delay.h> | 33 | #include <linux/delay.h> |
34 | #include <linux/of.h> | ||
34 | 35 | ||
35 | #include <linux/debugfs.h> | 36 | #include <linux/debugfs.h> |
36 | #include <linux/dmaengine.h> | 37 | #include <linux/dmaengine.h> |
@@ -1826,6 +1827,10 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev, | |||
1826 | priv->trigger_level = 1; | 1827 | priv->trigger_level = 1; |
1827 | priv->fcr = 0; | 1828 | priv->fcr = 0; |
1828 | 1829 | ||
1830 | if (pdev->dev.of_node) | ||
1831 | of_property_read_u32(pdev->dev.of_node, "clock-frequency" | ||
1832 | , &user_uartclk); | ||
1833 | |||
1829 | #ifdef CONFIG_SERIAL_PCH_UART_CONSOLE | 1834 | #ifdef CONFIG_SERIAL_PCH_UART_CONSOLE |
1830 | pch_uart_ports[board->line_no] = priv; | 1835 | pch_uart_ports[board->line_no] = priv; |
1831 | #endif | 1836 | #endif |
diff --git a/drivers/uio/uio_dmem_genirq.c b/drivers/uio/uio_dmem_genirq.c index 915facbf552e..e1134a4d97f3 100644 --- a/drivers/uio/uio_dmem_genirq.c +++ b/drivers/uio/uio_dmem_genirq.c | |||
@@ -229,7 +229,7 @@ static int uio_dmem_genirq_probe(struct platform_device *pdev) | |||
229 | ++uiomem; | 229 | ++uiomem; |
230 | } | 230 | } |
231 | 231 | ||
232 | priv->dmem_region_start = i; | 232 | priv->dmem_region_start = uiomem - &uioinfo->mem[0]; |
233 | priv->num_dmem_regions = pdata->num_dynamic_regions; | 233 | priv->num_dmem_regions = pdata->num_dynamic_regions; |
234 | 234 | ||
235 | for (i = 0; i < pdata->num_dynamic_regions; ++i) { | 235 | for (i = 0; i < pdata->num_dynamic_regions; ++i) { |
diff --git a/drivers/vhost/test.c b/drivers/vhost/test.c index 97fb2f8fa930..3cc98c07dcd3 100644 --- a/drivers/vhost/test.c +++ b/drivers/vhost/test.c | |||
@@ -322,18 +322,7 @@ static struct miscdevice vhost_test_misc = { | |||
322 | "vhost-test", | 322 | "vhost-test", |
323 | &vhost_test_fops, | 323 | &vhost_test_fops, |
324 | }; | 324 | }; |
325 | 325 | module_misc_device(vhost_test_misc); | |
326 | static int vhost_test_init(void) | ||
327 | { | ||
328 | return misc_register(&vhost_test_misc); | ||
329 | } | ||
330 | module_init(vhost_test_init); | ||
331 | |||
332 | static void vhost_test_exit(void) | ||
333 | { | ||
334 | misc_deregister(&vhost_test_misc); | ||
335 | } | ||
336 | module_exit(vhost_test_exit); | ||
337 | 326 | ||
338 | MODULE_VERSION("0.0.1"); | 327 | MODULE_VERSION("0.0.1"); |
339 | MODULE_LICENSE("GPL v2"); | 328 | MODULE_LICENSE("GPL v2"); |
diff --git a/drivers/vme/bridges/Kconfig b/drivers/vme/bridges/Kconfig index f6d854584906..f6ddc3715401 100644 --- a/drivers/vme/bridges/Kconfig +++ b/drivers/vme/bridges/Kconfig | |||
@@ -13,3 +13,11 @@ config VME_TSI148 | |||
13 | help | 13 | help |
14 | If you say Y here you get support for the Tundra TSI148 VME bridge | 14 | If you say Y here you get support for the Tundra TSI148 VME bridge |
15 | chip. | 15 | chip. |
16 | |||
17 | config VME_FAKE | ||
18 | tristate "Fake" | ||
19 | help | ||
20 | If you say Y here you get support for the fake VME bridge. This | ||
21 | provides a virtualised VME Bus for devices with no VME bridge. This | ||
22 | is mainly useful for VME development (in the absence of VME | ||
23 | hardware). | ||
diff --git a/drivers/vme/bridges/Makefile b/drivers/vme/bridges/Makefile index 59638afcd502..b074542495c5 100644 --- a/drivers/vme/bridges/Makefile +++ b/drivers/vme/bridges/Makefile | |||
@@ -1,2 +1,3 @@ | |||
1 | obj-$(CONFIG_VME_CA91CX42) += vme_ca91cx42.o | 1 | obj-$(CONFIG_VME_CA91CX42) += vme_ca91cx42.o |
2 | obj-$(CONFIG_VME_TSI148) += vme_tsi148.o | 2 | obj-$(CONFIG_VME_TSI148) += vme_tsi148.o |
3 | obj-$(CONFIG_VME_FAKE) += vme_fake.o | ||
diff --git a/drivers/vme/bridges/vme_ca91cx42.c b/drivers/vme/bridges/vme_ca91cx42.c index 9f2c834e43e0..6b5ee896af63 100644 --- a/drivers/vme/bridges/vme_ca91cx42.c +++ b/drivers/vme/bridges/vme_ca91cx42.c | |||
@@ -47,6 +47,8 @@ static const struct pci_device_id ca91cx42_ids[] = { | |||
47 | { }, | 47 | { }, |
48 | }; | 48 | }; |
49 | 49 | ||
50 | MODULE_DEVICE_TABLE(pci, ca91cx42_ids); | ||
51 | |||
50 | static struct pci_driver ca91cx42_driver = { | 52 | static struct pci_driver ca91cx42_driver = { |
51 | .name = driver_name, | 53 | .name = driver_name, |
52 | .id_table = ca91cx42_ids, | 54 | .id_table = ca91cx42_ids, |
@@ -69,7 +71,7 @@ static u32 ca91cx42_LM_irqhandler(struct ca91cx42_driver *bridge, u32 stat) | |||
69 | for (i = 0; i < 4; i++) { | 71 | for (i = 0; i < 4; i++) { |
70 | if (stat & CA91CX42_LINT_LM[i]) { | 72 | if (stat & CA91CX42_LINT_LM[i]) { |
71 | /* We only enable interrupts if the callback is set */ | 73 | /* We only enable interrupts if the callback is set */ |
72 | bridge->lm_callback[i](i); | 74 | bridge->lm_callback[i](bridge->lm_data[i]); |
73 | serviced |= CA91CX42_LINT_LM[i]; | 75 | serviced |= CA91CX42_LINT_LM[i]; |
74 | } | 76 | } |
75 | } | 77 | } |
@@ -1410,7 +1412,7 @@ static int ca91cx42_lm_get(struct vme_lm_resource *lm, | |||
1410 | * Callback will be passed the monitor triggered. | 1412 | * Callback will be passed the monitor triggered. |
1411 | */ | 1413 | */ |
1412 | static int ca91cx42_lm_attach(struct vme_lm_resource *lm, int monitor, | 1414 | static int ca91cx42_lm_attach(struct vme_lm_resource *lm, int monitor, |
1413 | void (*callback)(int)) | 1415 | void (*callback)(void *), void *data) |
1414 | { | 1416 | { |
1415 | u32 lm_ctl, tmp; | 1417 | u32 lm_ctl, tmp; |
1416 | struct ca91cx42_driver *bridge; | 1418 | struct ca91cx42_driver *bridge; |
@@ -1438,6 +1440,7 @@ static int ca91cx42_lm_attach(struct vme_lm_resource *lm, int monitor, | |||
1438 | 1440 | ||
1439 | /* Attach callback */ | 1441 | /* Attach callback */ |
1440 | bridge->lm_callback[monitor] = callback; | 1442 | bridge->lm_callback[monitor] = callback; |
1443 | bridge->lm_data[monitor] = data; | ||
1441 | 1444 | ||
1442 | /* Enable Location Monitor interrupt */ | 1445 | /* Enable Location Monitor interrupt */ |
1443 | tmp = ioread32(bridge->base + LINT_EN); | 1446 | tmp = ioread32(bridge->base + LINT_EN); |
@@ -1477,6 +1480,7 @@ static int ca91cx42_lm_detach(struct vme_lm_resource *lm, int monitor) | |||
1477 | 1480 | ||
1478 | /* Detach callback */ | 1481 | /* Detach callback */ |
1479 | bridge->lm_callback[monitor] = NULL; | 1482 | bridge->lm_callback[monitor] = NULL; |
1483 | bridge->lm_data[monitor] = NULL; | ||
1480 | 1484 | ||
1481 | /* If all location monitors disabled, disable global Location Monitor */ | 1485 | /* If all location monitors disabled, disable global Location Monitor */ |
1482 | if ((tmp & (CA91CX42_LINT_LM0 | CA91CX42_LINT_LM1 | CA91CX42_LINT_LM2 | | 1486 | if ((tmp & (CA91CX42_LINT_LM0 | CA91CX42_LINT_LM1 | CA91CX42_LINT_LM2 | |
diff --git a/drivers/vme/bridges/vme_ca91cx42.h b/drivers/vme/bridges/vme_ca91cx42.h index d54119e59d55..f35c9f5348a9 100644 --- a/drivers/vme/bridges/vme_ca91cx42.h +++ b/drivers/vme/bridges/vme_ca91cx42.h | |||
@@ -43,7 +43,8 @@ struct ca91cx42_driver { | |||
43 | wait_queue_head_t dma_queue; | 43 | wait_queue_head_t dma_queue; |
44 | wait_queue_head_t iack_queue; | 44 | wait_queue_head_t iack_queue; |
45 | wait_queue_head_t mbox_queue; | 45 | wait_queue_head_t mbox_queue; |
46 | void (*lm_callback[4])(int); /* Called in interrupt handler */ | 46 | void (*lm_callback[4])(void *); /* Called in interrupt handler */ |
47 | void *lm_data[4]; | ||
47 | void *crcsr_kernel; | 48 | void *crcsr_kernel; |
48 | dma_addr_t crcsr_bus; | 49 | dma_addr_t crcsr_bus; |
49 | struct mutex vme_rmw; /* Only one RMW cycle at a time */ | 50 | struct mutex vme_rmw; /* Only one RMW cycle at a time */ |
diff --git a/drivers/vme/bridges/vme_fake.c b/drivers/vme/bridges/vme_fake.c new file mode 100644 index 000000000000..30b3acc93833 --- /dev/null +++ b/drivers/vme/bridges/vme_fake.c | |||
@@ -0,0 +1,1306 @@ | |||
1 | /* | ||
2 | * Fake VME bridge support. | ||
3 | * | ||
4 | * This drive provides a fake VME bridge chip, this enables debugging of the | ||
5 | * VME framework in the absence of a VME system. | ||
6 | * | ||
7 | * This driver has to do a number of things in software that would be driven | ||
8 | * by hardware if it was available, it will also result in extra overhead at | ||
9 | * times when compared with driving actual hardware. | ||
10 | * | ||
11 | * Author: Martyn Welch <martyn@welches.me.uk> | ||
12 | * Copyright (c) 2014 Martyn Welch | ||
13 | * | ||
14 | * Based on vme_tsi148.c: | ||
15 | * | ||
16 | * Author: Martyn Welch <martyn.welch@ge.com> | ||
17 | * Copyright 2008 GE Intelligent Platforms Embedded Systems, Inc. | ||
18 | * | ||
19 | * Based on work by Tom Armistead and Ajit Prem | ||
20 | * Copyright 2004 Motorola Inc. | ||
21 | * | ||
22 | * This program is free software; you can redistribute it and/or modify it | ||
23 | * under the terms of the GNU General Public License as published by the | ||
24 | * Free Software Foundation; either version 2 of the License, or (at your | ||
25 | * option) any later version. | ||
26 | */ | ||
27 | |||
28 | #include <linux/device.h> | ||
29 | #include <linux/errno.h> | ||
30 | #include <linux/interrupt.h> | ||
31 | #include <linux/module.h> | ||
32 | #include <linux/moduleparam.h> | ||
33 | #include <linux/slab.h> | ||
34 | #include <linux/spinlock.h> | ||
35 | #include <linux/types.h> | ||
36 | #include <linux/vme.h> | ||
37 | |||
38 | #include "../vme_bridge.h" | ||
39 | |||
40 | /* | ||
41 | * Define the number of each that the fake driver supports. | ||
42 | */ | ||
43 | #define FAKE_MAX_MASTER 8 /* Max Master Windows */ | ||
44 | #define FAKE_MAX_SLAVE 8 /* Max Slave Windows */ | ||
45 | |||
46 | /* Structures to hold information normally held in device registers */ | ||
47 | struct fake_slave_window { | ||
48 | int enabled; | ||
49 | unsigned long long vme_base; | ||
50 | unsigned long long size; | ||
51 | void *buf_base; | ||
52 | u32 aspace; | ||
53 | u32 cycle; | ||
54 | }; | ||
55 | |||
56 | struct fake_master_window { | ||
57 | int enabled; | ||
58 | unsigned long long vme_base; | ||
59 | unsigned long long size; | ||
60 | u32 aspace; | ||
61 | u32 cycle; | ||
62 | u32 dwidth; | ||
63 | }; | ||
64 | |||
65 | /* Structure used to hold driver specific information */ | ||
66 | struct fake_driver { | ||
67 | struct vme_bridge *parent; | ||
68 | struct fake_slave_window slaves[FAKE_MAX_SLAVE]; | ||
69 | struct fake_master_window masters[FAKE_MAX_MASTER]; | ||
70 | u32 lm_enabled; | ||
71 | unsigned long long lm_base; | ||
72 | u32 lm_aspace; | ||
73 | u32 lm_cycle; | ||
74 | void (*lm_callback[4])(void *); | ||
75 | void *lm_data[4]; | ||
76 | struct tasklet_struct int_tasklet; | ||
77 | int int_level; | ||
78 | int int_statid; | ||
79 | void *crcsr_kernel; | ||
80 | dma_addr_t crcsr_bus; | ||
81 | /* Only one VME interrupt can be generated at a time, provide locking */ | ||
82 | struct mutex vme_int; | ||
83 | }; | ||
84 | |||
85 | /* Module parameter */ | ||
86 | static int geoid; | ||
87 | |||
88 | static const char driver_name[] = "vme_fake"; | ||
89 | |||
90 | static struct vme_bridge *exit_pointer; | ||
91 | |||
92 | static struct device *vme_root; | ||
93 | |||
94 | /* | ||
95 | * Calling VME bus interrupt callback if provided. | ||
96 | */ | ||
97 | static void fake_VIRQ_tasklet(unsigned long data) | ||
98 | { | ||
99 | struct vme_bridge *fake_bridge; | ||
100 | struct fake_driver *bridge; | ||
101 | |||
102 | fake_bridge = (struct vme_bridge *) data; | ||
103 | bridge = fake_bridge->driver_priv; | ||
104 | |||
105 | vme_irq_handler(fake_bridge, bridge->int_level, bridge->int_statid); | ||
106 | } | ||
107 | |||
108 | /* | ||
109 | * Configure VME interrupt | ||
110 | */ | ||
111 | static void fake_irq_set(struct vme_bridge *fake_bridge, int level, | ||
112 | int state, int sync) | ||
113 | { | ||
114 | /* Nothing to do */ | ||
115 | } | ||
116 | |||
117 | static void *fake_pci_to_ptr(dma_addr_t addr) | ||
118 | { | ||
119 | return (void *)(uintptr_t)addr; | ||
120 | } | ||
121 | |||
122 | static dma_addr_t fake_ptr_to_pci(void *addr) | ||
123 | { | ||
124 | return (dma_addr_t)(uintptr_t)addr; | ||
125 | } | ||
126 | |||
127 | /* | ||
128 | * Generate a VME bus interrupt at the requested level & vector. Wait for | ||
129 | * interrupt to be acked. | ||
130 | */ | ||
131 | static int fake_irq_generate(struct vme_bridge *fake_bridge, int level, | ||
132 | int statid) | ||
133 | { | ||
134 | struct fake_driver *bridge; | ||
135 | |||
136 | bridge = fake_bridge->driver_priv; | ||
137 | |||
138 | mutex_lock(&bridge->vme_int); | ||
139 | |||
140 | bridge->int_level = level; | ||
141 | |||
142 | bridge->int_statid = statid; | ||
143 | |||
144 | /* | ||
145 | * Schedule tasklet to run VME handler to emulate normal VME interrupt | ||
146 | * handler behaviour. | ||
147 | */ | ||
148 | tasklet_schedule(&bridge->int_tasklet); | ||
149 | |||
150 | mutex_unlock(&bridge->vme_int); | ||
151 | |||
152 | return 0; | ||
153 | } | ||
154 | |||
155 | /* | ||
156 | * Initialize a slave window with the requested attributes. | ||
157 | */ | ||
158 | static int fake_slave_set(struct vme_slave_resource *image, int enabled, | ||
159 | unsigned long long vme_base, unsigned long long size, | ||
160 | dma_addr_t buf_base, u32 aspace, u32 cycle) | ||
161 | { | ||
162 | unsigned int i, granularity = 0; | ||
163 | unsigned long long vme_bound; | ||
164 | struct vme_bridge *fake_bridge; | ||
165 | struct fake_driver *bridge; | ||
166 | |||
167 | fake_bridge = image->parent; | ||
168 | bridge = fake_bridge->driver_priv; | ||
169 | |||
170 | i = image->number; | ||
171 | |||
172 | switch (aspace) { | ||
173 | case VME_A16: | ||
174 | granularity = 0x10; | ||
175 | break; | ||
176 | case VME_A24: | ||
177 | granularity = 0x1000; | ||
178 | break; | ||
179 | case VME_A32: | ||
180 | granularity = 0x10000; | ||
181 | break; | ||
182 | case VME_A64: | ||
183 | granularity = 0x10000; | ||
184 | break; | ||
185 | case VME_CRCSR: | ||
186 | case VME_USER1: | ||
187 | case VME_USER2: | ||
188 | case VME_USER3: | ||
189 | case VME_USER4: | ||
190 | default: | ||
191 | pr_err("Invalid address space\n"); | ||
192 | return -EINVAL; | ||
193 | } | ||
194 | |||
195 | /* | ||
196 | * Bound address is a valid address for the window, adjust | ||
197 | * accordingly | ||
198 | */ | ||
199 | vme_bound = vme_base + size - granularity; | ||
200 | |||
201 | if (vme_base & (granularity - 1)) { | ||
202 | pr_err("Invalid VME base alignment\n"); | ||
203 | return -EINVAL; | ||
204 | } | ||
205 | if (vme_bound & (granularity - 1)) { | ||
206 | pr_err("Invalid VME bound alignment\n"); | ||
207 | return -EINVAL; | ||
208 | } | ||
209 | |||
210 | mutex_lock(&image->mtx); | ||
211 | |||
212 | bridge->slaves[i].enabled = enabled; | ||
213 | bridge->slaves[i].vme_base = vme_base; | ||
214 | bridge->slaves[i].size = size; | ||
215 | bridge->slaves[i].buf_base = fake_pci_to_ptr(buf_base); | ||
216 | bridge->slaves[i].aspace = aspace; | ||
217 | bridge->slaves[i].cycle = cycle; | ||
218 | |||
219 | mutex_unlock(&image->mtx); | ||
220 | |||
221 | return 0; | ||
222 | } | ||
223 | |||
224 | /* | ||
225 | * Get slave window configuration. | ||
226 | */ | ||
227 | static int fake_slave_get(struct vme_slave_resource *image, int *enabled, | ||
228 | unsigned long long *vme_base, unsigned long long *size, | ||
229 | dma_addr_t *buf_base, u32 *aspace, u32 *cycle) | ||
230 | { | ||
231 | unsigned int i; | ||
232 | struct fake_driver *bridge; | ||
233 | |||
234 | bridge = image->parent->driver_priv; | ||
235 | |||
236 | i = image->number; | ||
237 | |||
238 | mutex_lock(&image->mtx); | ||
239 | |||
240 | *enabled = bridge->slaves[i].enabled; | ||
241 | *vme_base = bridge->slaves[i].vme_base; | ||
242 | *size = bridge->slaves[i].size; | ||
243 | *buf_base = fake_ptr_to_pci(bridge->slaves[i].buf_base); | ||
244 | *aspace = bridge->slaves[i].aspace; | ||
245 | *cycle = bridge->slaves[i].cycle; | ||
246 | |||
247 | mutex_unlock(&image->mtx); | ||
248 | |||
249 | return 0; | ||
250 | } | ||
251 | |||
252 | /* | ||
253 | * Set the attributes of an outbound window. | ||
254 | */ | ||
255 | static int fake_master_set(struct vme_master_resource *image, int enabled, | ||
256 | unsigned long long vme_base, unsigned long long size, | ||
257 | u32 aspace, u32 cycle, u32 dwidth) | ||
258 | { | ||
259 | int retval = 0; | ||
260 | unsigned int i; | ||
261 | struct vme_bridge *fake_bridge; | ||
262 | struct fake_driver *bridge; | ||
263 | |||
264 | fake_bridge = image->parent; | ||
265 | |||
266 | bridge = fake_bridge->driver_priv; | ||
267 | |||
268 | /* Verify input data */ | ||
269 | if (vme_base & 0xFFFF) { | ||
270 | pr_err("Invalid VME Window alignment\n"); | ||
271 | retval = -EINVAL; | ||
272 | goto err_window; | ||
273 | } | ||
274 | |||
275 | if (size & 0xFFFF) { | ||
276 | pr_err("Invalid size alignment\n"); | ||
277 | retval = -EINVAL; | ||
278 | goto err_window; | ||
279 | } | ||
280 | |||
281 | if ((size == 0) && (enabled != 0)) { | ||
282 | pr_err("Size must be non-zero for enabled windows\n"); | ||
283 | retval = -EINVAL; | ||
284 | goto err_window; | ||
285 | } | ||
286 | |||
287 | /* Setup data width */ | ||
288 | switch (dwidth) { | ||
289 | case VME_D8: | ||
290 | case VME_D16: | ||
291 | case VME_D32: | ||
292 | break; | ||
293 | default: | ||
294 | pr_err("Invalid data width\n"); | ||
295 | retval = -EINVAL; | ||
296 | goto err_dwidth; | ||
297 | } | ||
298 | |||
299 | /* Setup address space */ | ||
300 | switch (aspace) { | ||
301 | case VME_A16: | ||
302 | case VME_A24: | ||
303 | case VME_A32: | ||
304 | case VME_A64: | ||
305 | case VME_CRCSR: | ||
306 | case VME_USER1: | ||
307 | case VME_USER2: | ||
308 | case VME_USER3: | ||
309 | case VME_USER4: | ||
310 | break; | ||
311 | default: | ||
312 | pr_err("Invalid address space\n"); | ||
313 | retval = -EINVAL; | ||
314 | goto err_aspace; | ||
315 | } | ||
316 | |||
317 | spin_lock(&image->lock); | ||
318 | |||
319 | i = image->number; | ||
320 | |||
321 | bridge->masters[i].enabled = enabled; | ||
322 | bridge->masters[i].vme_base = vme_base; | ||
323 | bridge->masters[i].size = size; | ||
324 | bridge->masters[i].aspace = aspace; | ||
325 | bridge->masters[i].cycle = cycle; | ||
326 | bridge->masters[i].dwidth = dwidth; | ||
327 | |||
328 | spin_unlock(&image->lock); | ||
329 | |||
330 | return 0; | ||
331 | |||
332 | err_aspace: | ||
333 | err_dwidth: | ||
334 | err_window: | ||
335 | return retval; | ||
336 | |||
337 | } | ||
338 | |||
339 | /* | ||
340 | * Set the attributes of an outbound window. | ||
341 | */ | ||
342 | static int __fake_master_get(struct vme_master_resource *image, int *enabled, | ||
343 | unsigned long long *vme_base, unsigned long long *size, | ||
344 | u32 *aspace, u32 *cycle, u32 *dwidth) | ||
345 | { | ||
346 | unsigned int i; | ||
347 | struct fake_driver *bridge; | ||
348 | |||
349 | bridge = image->parent->driver_priv; | ||
350 | |||
351 | i = image->number; | ||
352 | |||
353 | *enabled = bridge->masters[i].enabled; | ||
354 | *vme_base = bridge->masters[i].vme_base; | ||
355 | *size = bridge->masters[i].size; | ||
356 | *aspace = bridge->masters[i].aspace; | ||
357 | *cycle = bridge->masters[i].cycle; | ||
358 | *dwidth = bridge->masters[i].dwidth; | ||
359 | |||
360 | return 0; | ||
361 | } | ||
362 | |||
363 | |||
364 | static int fake_master_get(struct vme_master_resource *image, int *enabled, | ||
365 | unsigned long long *vme_base, unsigned long long *size, | ||
366 | u32 *aspace, u32 *cycle, u32 *dwidth) | ||
367 | { | ||
368 | int retval; | ||
369 | |||
370 | spin_lock(&image->lock); | ||
371 | |||
372 | retval = __fake_master_get(image, enabled, vme_base, size, aspace, | ||
373 | cycle, dwidth); | ||
374 | |||
375 | spin_unlock(&image->lock); | ||
376 | |||
377 | return retval; | ||
378 | } | ||
379 | |||
380 | |||
381 | static void fake_lm_check(struct fake_driver *bridge, unsigned long long addr, | ||
382 | u32 aspace, u32 cycle) | ||
383 | { | ||
384 | struct vme_bridge *fake_bridge; | ||
385 | unsigned long long lm_base; | ||
386 | u32 lm_aspace, lm_cycle; | ||
387 | int i; | ||
388 | struct vme_lm_resource *lm; | ||
389 | struct list_head *pos = NULL, *n; | ||
390 | |||
391 | /* Get vme_bridge */ | ||
392 | fake_bridge = bridge->parent; | ||
393 | |||
394 | /* Loop through each location monitor resource */ | ||
395 | list_for_each_safe(pos, n, &fake_bridge->lm_resources) { | ||
396 | lm = list_entry(pos, struct vme_lm_resource, list); | ||
397 | |||
398 | /* If disabled, we're done */ | ||
399 | if (bridge->lm_enabled == 0) | ||
400 | return; | ||
401 | |||
402 | lm_base = bridge->lm_base; | ||
403 | lm_aspace = bridge->lm_aspace; | ||
404 | lm_cycle = bridge->lm_cycle; | ||
405 | |||
406 | /* First make sure that the cycle and address space match */ | ||
407 | if ((lm_aspace == aspace) && (lm_cycle == cycle)) { | ||
408 | for (i = 0; i < lm->monitors; i++) { | ||
409 | /* Each location monitor covers 8 bytes */ | ||
410 | if (((lm_base + (8 * i)) <= addr) && | ||
411 | ((lm_base + (8 * i) + 8) > addr)) { | ||
412 | if (bridge->lm_callback[i] != NULL) | ||
413 | bridge->lm_callback[i]( | ||
414 | bridge->lm_data[i]); | ||
415 | } | ||
416 | } | ||
417 | } | ||
418 | } | ||
419 | } | ||
420 | |||
421 | static u8 fake_vmeread8(struct fake_driver *bridge, unsigned long long addr, | ||
422 | u32 aspace, u32 cycle) | ||
423 | { | ||
424 | u8 retval = 0xff; | ||
425 | int i; | ||
426 | unsigned long long start, end, offset; | ||
427 | u8 *loc; | ||
428 | |||
429 | for (i = 0; i < FAKE_MAX_SLAVE; i++) { | ||
430 | start = bridge->slaves[i].vme_base; | ||
431 | end = bridge->slaves[i].vme_base + bridge->slaves[i].size; | ||
432 | |||
433 | if (aspace != bridge->slaves[i].aspace) | ||
434 | continue; | ||
435 | |||
436 | if (cycle != bridge->slaves[i].cycle) | ||
437 | continue; | ||
438 | |||
439 | if ((addr >= start) && (addr < end)) { | ||
440 | offset = addr - bridge->slaves[i].vme_base; | ||
441 | loc = (u8 *)(bridge->slaves[i].buf_base + offset); | ||
442 | retval = *loc; | ||
443 | |||
444 | break; | ||
445 | } | ||
446 | } | ||
447 | |||
448 | fake_lm_check(bridge, addr, aspace, cycle); | ||
449 | |||
450 | return retval; | ||
451 | } | ||
452 | |||
453 | static u16 fake_vmeread16(struct fake_driver *bridge, unsigned long long addr, | ||
454 | u32 aspace, u32 cycle) | ||
455 | { | ||
456 | u16 retval = 0xffff; | ||
457 | int i; | ||
458 | unsigned long long start, end, offset; | ||
459 | u16 *loc; | ||
460 | |||
461 | for (i = 0; i < FAKE_MAX_SLAVE; i++) { | ||
462 | if (aspace != bridge->slaves[i].aspace) | ||
463 | continue; | ||
464 | |||
465 | if (cycle != bridge->slaves[i].cycle) | ||
466 | continue; | ||
467 | |||
468 | start = bridge->slaves[i].vme_base; | ||
469 | end = bridge->slaves[i].vme_base + bridge->slaves[i].size; | ||
470 | |||
471 | if ((addr >= start) && ((addr + 1) < end)) { | ||
472 | offset = addr - bridge->slaves[i].vme_base; | ||
473 | loc = (u16 *)(bridge->slaves[i].buf_base + offset); | ||
474 | retval = *loc; | ||
475 | |||
476 | break; | ||
477 | } | ||
478 | } | ||
479 | |||
480 | fake_lm_check(bridge, addr, aspace, cycle); | ||
481 | |||
482 | return retval; | ||
483 | } | ||
484 | |||
485 | static u32 fake_vmeread32(struct fake_driver *bridge, unsigned long long addr, | ||
486 | u32 aspace, u32 cycle) | ||
487 | { | ||
488 | u32 retval = 0xffffffff; | ||
489 | int i; | ||
490 | unsigned long long start, end, offset; | ||
491 | u32 *loc; | ||
492 | |||
493 | for (i = 0; i < FAKE_MAX_SLAVE; i++) { | ||
494 | if (aspace != bridge->slaves[i].aspace) | ||
495 | continue; | ||
496 | |||
497 | if (cycle != bridge->slaves[i].cycle) | ||
498 | continue; | ||
499 | |||
500 | start = bridge->slaves[i].vme_base; | ||
501 | end = bridge->slaves[i].vme_base + bridge->slaves[i].size; | ||
502 | |||
503 | if ((addr >= start) && ((addr + 3) < end)) { | ||
504 | offset = addr - bridge->slaves[i].vme_base; | ||
505 | loc = (u32 *)(bridge->slaves[i].buf_base + offset); | ||
506 | retval = *loc; | ||
507 | |||
508 | break; | ||
509 | } | ||
510 | } | ||
511 | |||
512 | fake_lm_check(bridge, addr, aspace, cycle); | ||
513 | |||
514 | return retval; | ||
515 | } | ||
516 | |||
517 | static ssize_t fake_master_read(struct vme_master_resource *image, void *buf, | ||
518 | size_t count, loff_t offset) | ||
519 | { | ||
520 | int retval; | ||
521 | u32 aspace, cycle, dwidth; | ||
522 | struct vme_bridge *fake_bridge; | ||
523 | struct fake_driver *priv; | ||
524 | int i; | ||
525 | unsigned long long addr; | ||
526 | unsigned int done = 0; | ||
527 | unsigned int count32; | ||
528 | |||
529 | fake_bridge = image->parent; | ||
530 | |||
531 | priv = fake_bridge->driver_priv; | ||
532 | |||
533 | i = image->number; | ||
534 | |||
535 | addr = (unsigned long long)priv->masters[i].vme_base + offset; | ||
536 | aspace = priv->masters[i].aspace; | ||
537 | cycle = priv->masters[i].cycle; | ||
538 | dwidth = priv->masters[i].dwidth; | ||
539 | |||
540 | spin_lock(&image->lock); | ||
541 | |||
542 | /* The following code handles VME address alignment. We cannot use | ||
543 | * memcpy_xxx here because it may cut data transfers in to 8-bit | ||
544 | * cycles when D16 or D32 cycles are required on the VME bus. | ||
545 | * On the other hand, the bridge itself assures that the maximum data | ||
546 | * cycle configured for the transfer is used and splits it | ||
547 | * automatically for non-aligned addresses, so we don't want the | ||
548 | * overhead of needlessly forcing small transfers for the entire cycle. | ||
549 | */ | ||
550 | if (addr & 0x1) { | ||
551 | *(u8 *)buf = fake_vmeread8(priv, addr, aspace, cycle); | ||
552 | done += 1; | ||
553 | if (done == count) | ||
554 | goto out; | ||
555 | } | ||
556 | if ((dwidth == VME_D16) || (dwidth == VME_D32)) { | ||
557 | if ((addr + done) & 0x2) { | ||
558 | if ((count - done) < 2) { | ||
559 | *(u8 *)(buf + done) = fake_vmeread8(priv, | ||
560 | addr + done, aspace, cycle); | ||
561 | done += 1; | ||
562 | goto out; | ||
563 | } else { | ||
564 | *(u16 *)(buf + done) = fake_vmeread16(priv, | ||
565 | addr + done, aspace, cycle); | ||
566 | done += 2; | ||
567 | } | ||
568 | } | ||
569 | } | ||
570 | |||
571 | if (dwidth == VME_D32) { | ||
572 | count32 = (count - done) & ~0x3; | ||
573 | while (done < count32) { | ||
574 | *(u32 *)(buf + done) = fake_vmeread32(priv, addr + done, | ||
575 | aspace, cycle); | ||
576 | done += 4; | ||
577 | } | ||
578 | } else if (dwidth == VME_D16) { | ||
579 | count32 = (count - done) & ~0x3; | ||
580 | while (done < count32) { | ||
581 | *(u16 *)(buf + done) = fake_vmeread16(priv, addr + done, | ||
582 | aspace, cycle); | ||
583 | done += 2; | ||
584 | } | ||
585 | } else if (dwidth == VME_D8) { | ||
586 | count32 = (count - done); | ||
587 | while (done < count32) { | ||
588 | *(u8 *)(buf + done) = fake_vmeread8(priv, addr + done, | ||
589 | aspace, cycle); | ||
590 | done += 1; | ||
591 | } | ||
592 | |||
593 | } | ||
594 | |||
595 | if ((dwidth == VME_D16) || (dwidth == VME_D32)) { | ||
596 | if ((count - done) & 0x2) { | ||
597 | *(u16 *)(buf + done) = fake_vmeread16(priv, addr + done, | ||
598 | aspace, cycle); | ||
599 | done += 2; | ||
600 | } | ||
601 | } | ||
602 | if ((count - done) & 0x1) { | ||
603 | *(u8 *)(buf + done) = fake_vmeread8(priv, addr + done, aspace, | ||
604 | cycle); | ||
605 | done += 1; | ||
606 | } | ||
607 | |||
608 | out: | ||
609 | retval = count; | ||
610 | |||
611 | spin_unlock(&image->lock); | ||
612 | |||
613 | return retval; | ||
614 | } | ||
615 | |||
616 | static void fake_vmewrite8(struct fake_driver *bridge, u8 *buf, | ||
617 | unsigned long long addr, u32 aspace, u32 cycle) | ||
618 | { | ||
619 | int i; | ||
620 | unsigned long long start, end, offset; | ||
621 | u8 *loc; | ||
622 | |||
623 | for (i = 0; i < FAKE_MAX_SLAVE; i++) { | ||
624 | if (aspace != bridge->slaves[i].aspace) | ||
625 | continue; | ||
626 | |||
627 | if (cycle != bridge->slaves[i].cycle) | ||
628 | continue; | ||
629 | |||
630 | start = bridge->slaves[i].vme_base; | ||
631 | end = bridge->slaves[i].vme_base + bridge->slaves[i].size; | ||
632 | |||
633 | if ((addr >= start) && (addr < end)) { | ||
634 | offset = addr - bridge->slaves[i].vme_base; | ||
635 | loc = (u8 *)((void *)bridge->slaves[i].buf_base + offset); | ||
636 | *loc = *buf; | ||
637 | |||
638 | break; | ||
639 | } | ||
640 | } | ||
641 | |||
642 | fake_lm_check(bridge, addr, aspace, cycle); | ||
643 | |||
644 | } | ||
645 | |||
646 | static void fake_vmewrite16(struct fake_driver *bridge, u16 *buf, | ||
647 | unsigned long long addr, u32 aspace, u32 cycle) | ||
648 | { | ||
649 | int i; | ||
650 | unsigned long long start, end, offset; | ||
651 | u16 *loc; | ||
652 | |||
653 | for (i = 0; i < FAKE_MAX_SLAVE; i++) { | ||
654 | if (aspace != bridge->slaves[i].aspace) | ||
655 | continue; | ||
656 | |||
657 | if (cycle != bridge->slaves[i].cycle) | ||
658 | continue; | ||
659 | |||
660 | start = bridge->slaves[i].vme_base; | ||
661 | end = bridge->slaves[i].vme_base + bridge->slaves[i].size; | ||
662 | |||
663 | if ((addr >= start) && ((addr + 1) < end)) { | ||
664 | offset = addr - bridge->slaves[i].vme_base; | ||
665 | loc = (u16 *)((void *)bridge->slaves[i].buf_base + offset); | ||
666 | *loc = *buf; | ||
667 | |||
668 | break; | ||
669 | } | ||
670 | } | ||
671 | |||
672 | fake_lm_check(bridge, addr, aspace, cycle); | ||
673 | |||
674 | } | ||
675 | |||
676 | static void fake_vmewrite32(struct fake_driver *bridge, u32 *buf, | ||
677 | unsigned long long addr, u32 aspace, u32 cycle) | ||
678 | { | ||
679 | int i; | ||
680 | unsigned long long start, end, offset; | ||
681 | u32 *loc; | ||
682 | |||
683 | for (i = 0; i < FAKE_MAX_SLAVE; i++) { | ||
684 | if (aspace != bridge->slaves[i].aspace) | ||
685 | continue; | ||
686 | |||
687 | if (cycle != bridge->slaves[i].cycle) | ||
688 | continue; | ||
689 | |||
690 | start = bridge->slaves[i].vme_base; | ||
691 | end = bridge->slaves[i].vme_base + bridge->slaves[i].size; | ||
692 | |||
693 | if ((addr >= start) && ((addr + 3) < end)) { | ||
694 | offset = addr - bridge->slaves[i].vme_base; | ||
695 | loc = (u32 *)((void *)bridge->slaves[i].buf_base + offset); | ||
696 | *loc = *buf; | ||
697 | |||
698 | break; | ||
699 | } | ||
700 | } | ||
701 | |||
702 | fake_lm_check(bridge, addr, aspace, cycle); | ||
703 | |||
704 | } | ||
705 | |||
706 | static ssize_t fake_master_write(struct vme_master_resource *image, void *buf, | ||
707 | size_t count, loff_t offset) | ||
708 | { | ||
709 | int retval = 0; | ||
710 | u32 aspace, cycle, dwidth; | ||
711 | unsigned long long addr; | ||
712 | int i; | ||
713 | unsigned int done = 0; | ||
714 | unsigned int count32; | ||
715 | |||
716 | struct vme_bridge *fake_bridge; | ||
717 | struct fake_driver *bridge; | ||
718 | |||
719 | fake_bridge = image->parent; | ||
720 | |||
721 | bridge = fake_bridge->driver_priv; | ||
722 | |||
723 | i = image->number; | ||
724 | |||
725 | addr = bridge->masters[i].vme_base + offset; | ||
726 | aspace = bridge->masters[i].aspace; | ||
727 | cycle = bridge->masters[i].cycle; | ||
728 | dwidth = bridge->masters[i].dwidth; | ||
729 | |||
730 | spin_lock(&image->lock); | ||
731 | |||
732 | /* Here we apply for the same strategy we do in master_read | ||
733 | * function in order to assure the correct cycles. | ||
734 | */ | ||
735 | if (addr & 0x1) { | ||
736 | fake_vmewrite8(bridge, (u8 *)buf, addr, aspace, cycle); | ||
737 | done += 1; | ||
738 | if (done == count) | ||
739 | goto out; | ||
740 | } | ||
741 | |||
742 | if ((dwidth == VME_D16) || (dwidth == VME_D32)) { | ||
743 | if ((addr + done) & 0x2) { | ||
744 | if ((count - done) < 2) { | ||
745 | fake_vmewrite8(bridge, (u8 *)(buf + done), | ||
746 | addr + done, aspace, cycle); | ||
747 | done += 1; | ||
748 | goto out; | ||
749 | } else { | ||
750 | fake_vmewrite16(bridge, (u16 *)(buf + done), | ||
751 | addr + done, aspace, cycle); | ||
752 | done += 2; | ||
753 | } | ||
754 | } | ||
755 | } | ||
756 | |||
757 | if (dwidth == VME_D32) { | ||
758 | count32 = (count - done) & ~0x3; | ||
759 | while (done < count32) { | ||
760 | fake_vmewrite32(bridge, (u32 *)(buf + done), | ||
761 | addr + done, aspace, cycle); | ||
762 | done += 4; | ||
763 | } | ||
764 | } else if (dwidth == VME_D16) { | ||
765 | count32 = (count - done) & ~0x3; | ||
766 | while (done < count32) { | ||
767 | fake_vmewrite16(bridge, (u16 *)(buf + done), | ||
768 | addr + done, aspace, cycle); | ||
769 | done += 2; | ||
770 | } | ||
771 | } else if (dwidth == VME_D8) { | ||
772 | count32 = (count - done); | ||
773 | while (done < count32) { | ||
774 | fake_vmewrite8(bridge, (u8 *)(buf + done), addr + done, | ||
775 | aspace, cycle); | ||
776 | done += 1; | ||
777 | } | ||
778 | |||
779 | } | ||
780 | |||
781 | if ((dwidth == VME_D16) || (dwidth == VME_D32)) { | ||
782 | if ((count - done) & 0x2) { | ||
783 | fake_vmewrite16(bridge, (u16 *)(buf + done), | ||
784 | addr + done, aspace, cycle); | ||
785 | done += 2; | ||
786 | } | ||
787 | } | ||
788 | |||
789 | if ((count - done) & 0x1) { | ||
790 | fake_vmewrite8(bridge, (u8 *)(buf + done), addr + done, aspace, | ||
791 | cycle); | ||
792 | done += 1; | ||
793 | } | ||
794 | |||
795 | out: | ||
796 | retval = count; | ||
797 | |||
798 | spin_unlock(&image->lock); | ||
799 | |||
800 | return retval; | ||
801 | } | ||
802 | |||
803 | /* | ||
804 | * Perform an RMW cycle on the VME bus. | ||
805 | * | ||
806 | * Requires a previously configured master window, returns final value. | ||
807 | */ | ||
808 | static unsigned int fake_master_rmw(struct vme_master_resource *image, | ||
809 | unsigned int mask, unsigned int compare, unsigned int swap, | ||
810 | loff_t offset) | ||
811 | { | ||
812 | u32 tmp, base; | ||
813 | u32 aspace, cycle; | ||
814 | int i; | ||
815 | struct fake_driver *bridge; | ||
816 | |||
817 | bridge = image->parent->driver_priv; | ||
818 | |||
819 | /* Find the PCI address that maps to the desired VME address */ | ||
820 | i = image->number; | ||
821 | |||
822 | base = bridge->masters[i].vme_base; | ||
823 | aspace = bridge->masters[i].aspace; | ||
824 | cycle = bridge->masters[i].cycle; | ||
825 | |||
826 | /* Lock image */ | ||
827 | spin_lock(&image->lock); | ||
828 | |||
829 | /* Read existing value */ | ||
830 | tmp = fake_vmeread32(bridge, base + offset, aspace, cycle); | ||
831 | |||
832 | /* Perform check */ | ||
833 | if ((tmp && mask) == (compare && mask)) { | ||
834 | tmp = tmp | (mask | swap); | ||
835 | tmp = tmp & (~mask | swap); | ||
836 | |||
837 | /* Write back */ | ||
838 | fake_vmewrite32(bridge, &tmp, base + offset, aspace, cycle); | ||
839 | } | ||
840 | |||
841 | /* Unlock image */ | ||
842 | spin_unlock(&image->lock); | ||
843 | |||
844 | return tmp; | ||
845 | } | ||
846 | |||
847 | /* | ||
848 | * All 4 location monitors reside at the same base - this is therefore a | ||
849 | * system wide configuration. | ||
850 | * | ||
851 | * This does not enable the LM monitor - that should be done when the first | ||
852 | * callback is attached and disabled when the last callback is removed. | ||
853 | */ | ||
854 | static int fake_lm_set(struct vme_lm_resource *lm, unsigned long long lm_base, | ||
855 | u32 aspace, u32 cycle) | ||
856 | { | ||
857 | int i; | ||
858 | struct vme_bridge *fake_bridge; | ||
859 | struct fake_driver *bridge; | ||
860 | |||
861 | fake_bridge = lm->parent; | ||
862 | |||
863 | bridge = fake_bridge->driver_priv; | ||
864 | |||
865 | mutex_lock(&lm->mtx); | ||
866 | |||
867 | /* If we already have a callback attached, we can't move it! */ | ||
868 | for (i = 0; i < lm->monitors; i++) { | ||
869 | if (bridge->lm_callback[i] != NULL) { | ||
870 | mutex_unlock(&lm->mtx); | ||
871 | pr_err("Location monitor callback attached, can't reset\n"); | ||
872 | return -EBUSY; | ||
873 | } | ||
874 | } | ||
875 | |||
876 | switch (aspace) { | ||
877 | case VME_A16: | ||
878 | case VME_A24: | ||
879 | case VME_A32: | ||
880 | case VME_A64: | ||
881 | break; | ||
882 | default: | ||
883 | mutex_unlock(&lm->mtx); | ||
884 | pr_err("Invalid address space\n"); | ||
885 | return -EINVAL; | ||
886 | } | ||
887 | |||
888 | bridge->lm_base = lm_base; | ||
889 | bridge->lm_aspace = aspace; | ||
890 | bridge->lm_cycle = cycle; | ||
891 | |||
892 | mutex_unlock(&lm->mtx); | ||
893 | |||
894 | return 0; | ||
895 | } | ||
896 | |||
897 | /* Get configuration of the callback monitor and return whether it is enabled | ||
898 | * or disabled. | ||
899 | */ | ||
900 | static int fake_lm_get(struct vme_lm_resource *lm, | ||
901 | unsigned long long *lm_base, u32 *aspace, u32 *cycle) | ||
902 | { | ||
903 | struct fake_driver *bridge; | ||
904 | |||
905 | bridge = lm->parent->driver_priv; | ||
906 | |||
907 | mutex_lock(&lm->mtx); | ||
908 | |||
909 | *lm_base = bridge->lm_base; | ||
910 | *aspace = bridge->lm_aspace; | ||
911 | *cycle = bridge->lm_cycle; | ||
912 | |||
913 | mutex_unlock(&lm->mtx); | ||
914 | |||
915 | return bridge->lm_enabled; | ||
916 | } | ||
917 | |||
918 | /* | ||
919 | * Attach a callback to a specific location monitor. | ||
920 | * | ||
921 | * Callback will be passed the monitor triggered. | ||
922 | */ | ||
923 | static int fake_lm_attach(struct vme_lm_resource *lm, int monitor, | ||
924 | void (*callback)(void *), void *data) | ||
925 | { | ||
926 | struct vme_bridge *fake_bridge; | ||
927 | struct fake_driver *bridge; | ||
928 | |||
929 | fake_bridge = lm->parent; | ||
930 | |||
931 | bridge = fake_bridge->driver_priv; | ||
932 | |||
933 | mutex_lock(&lm->mtx); | ||
934 | |||
935 | /* Ensure that the location monitor is configured - need PGM or DATA */ | ||
936 | if (bridge->lm_cycle == 0) { | ||
937 | mutex_unlock(&lm->mtx); | ||
938 | pr_err("Location monitor not properly configured\n"); | ||
939 | return -EINVAL; | ||
940 | } | ||
941 | |||
942 | /* Check that a callback isn't already attached */ | ||
943 | if (bridge->lm_callback[monitor] != NULL) { | ||
944 | mutex_unlock(&lm->mtx); | ||
945 | pr_err("Existing callback attached\n"); | ||
946 | return -EBUSY; | ||
947 | } | ||
948 | |||
949 | /* Attach callback */ | ||
950 | bridge->lm_callback[monitor] = callback; | ||
951 | bridge->lm_data[monitor] = data; | ||
952 | |||
953 | /* Ensure that global Location Monitor Enable set */ | ||
954 | bridge->lm_enabled = 1; | ||
955 | |||
956 | mutex_unlock(&lm->mtx); | ||
957 | |||
958 | return 0; | ||
959 | } | ||
960 | |||
961 | /* | ||
962 | * Detach a callback function forn a specific location monitor. | ||
963 | */ | ||
964 | static int fake_lm_detach(struct vme_lm_resource *lm, int monitor) | ||
965 | { | ||
966 | u32 tmp; | ||
967 | int i; | ||
968 | struct fake_driver *bridge; | ||
969 | |||
970 | bridge = lm->parent->driver_priv; | ||
971 | |||
972 | mutex_lock(&lm->mtx); | ||
973 | |||
974 | /* Detach callback */ | ||
975 | bridge->lm_callback[monitor] = NULL; | ||
976 | bridge->lm_data[monitor] = NULL; | ||
977 | |||
978 | /* If all location monitors disabled, disable global Location Monitor */ | ||
979 | tmp = 0; | ||
980 | for (i = 0; i < lm->monitors; i++) { | ||
981 | if (bridge->lm_callback[i] != NULL) | ||
982 | tmp = 1; | ||
983 | } | ||
984 | |||
985 | if (tmp == 0) | ||
986 | bridge->lm_enabled = 0; | ||
987 | |||
988 | mutex_unlock(&lm->mtx); | ||
989 | |||
990 | return 0; | ||
991 | } | ||
992 | |||
993 | /* | ||
994 | * Determine Geographical Addressing | ||
995 | */ | ||
996 | static int fake_slot_get(struct vme_bridge *fake_bridge) | ||
997 | { | ||
998 | return geoid; | ||
999 | } | ||
1000 | |||
1001 | static void *fake_alloc_consistent(struct device *parent, size_t size, | ||
1002 | dma_addr_t *dma) | ||
1003 | { | ||
1004 | void *alloc = kmalloc(size, GFP_KERNEL); | ||
1005 | |||
1006 | if (alloc != NULL) | ||
1007 | *dma = fake_ptr_to_pci(alloc); | ||
1008 | |||
1009 | return alloc; | ||
1010 | } | ||
1011 | |||
1012 | static void fake_free_consistent(struct device *parent, size_t size, | ||
1013 | void *vaddr, dma_addr_t dma) | ||
1014 | { | ||
1015 | kfree(vaddr); | ||
1016 | /* | ||
1017 | dma_free_coherent(parent, size, vaddr, dma); | ||
1018 | */ | ||
1019 | } | ||
1020 | |||
1021 | /* | ||
1022 | * Configure CR/CSR space | ||
1023 | * | ||
1024 | * Access to the CR/CSR can be configured at power-up. The location of the | ||
1025 | * CR/CSR registers in the CR/CSR address space is determined by the boards | ||
1026 | * Geographic address. | ||
1027 | * | ||
1028 | * Each board has a 512kB window, with the highest 4kB being used for the | ||
1029 | * boards registers, this means there is a fix length 508kB window which must | ||
1030 | * be mapped onto PCI memory. | ||
1031 | */ | ||
1032 | static int fake_crcsr_init(struct vme_bridge *fake_bridge) | ||
1033 | { | ||
1034 | u32 vstat; | ||
1035 | struct fake_driver *bridge; | ||
1036 | |||
1037 | bridge = fake_bridge->driver_priv; | ||
1038 | |||
1039 | /* Allocate mem for CR/CSR image */ | ||
1040 | bridge->crcsr_kernel = kzalloc(VME_CRCSR_BUF_SIZE, GFP_KERNEL); | ||
1041 | bridge->crcsr_bus = fake_ptr_to_pci(bridge->crcsr_kernel); | ||
1042 | if (bridge->crcsr_kernel == NULL) | ||
1043 | return -ENOMEM; | ||
1044 | |||
1045 | vstat = fake_slot_get(fake_bridge); | ||
1046 | |||
1047 | pr_info("CR/CSR Offset: %d\n", vstat); | ||
1048 | |||
1049 | return 0; | ||
1050 | } | ||
1051 | |||
1052 | static void fake_crcsr_exit(struct vme_bridge *fake_bridge) | ||
1053 | { | ||
1054 | struct fake_driver *bridge; | ||
1055 | |||
1056 | bridge = fake_bridge->driver_priv; | ||
1057 | |||
1058 | kfree(bridge->crcsr_kernel); | ||
1059 | } | ||
1060 | |||
1061 | |||
1062 | static int __init fake_init(void) | ||
1063 | { | ||
1064 | int retval, i; | ||
1065 | struct list_head *pos = NULL, *n; | ||
1066 | struct vme_bridge *fake_bridge; | ||
1067 | struct fake_driver *fake_device; | ||
1068 | struct vme_master_resource *master_image; | ||
1069 | struct vme_slave_resource *slave_image; | ||
1070 | struct vme_lm_resource *lm; | ||
1071 | |||
1072 | /* We need a fake parent device */ | ||
1073 | vme_root = __root_device_register("vme", THIS_MODULE); | ||
1074 | |||
1075 | /* If we want to support more than one bridge at some point, we need to | ||
1076 | * dynamically allocate this so we get one per device. | ||
1077 | */ | ||
1078 | fake_bridge = kzalloc(sizeof(struct vme_bridge), GFP_KERNEL); | ||
1079 | if (fake_bridge == NULL) { | ||
1080 | retval = -ENOMEM; | ||
1081 | goto err_struct; | ||
1082 | } | ||
1083 | |||
1084 | fake_device = kzalloc(sizeof(struct fake_driver), GFP_KERNEL); | ||
1085 | if (fake_device == NULL) { | ||
1086 | retval = -ENOMEM; | ||
1087 | goto err_driver; | ||
1088 | } | ||
1089 | |||
1090 | fake_bridge->driver_priv = fake_device; | ||
1091 | |||
1092 | fake_bridge->parent = vme_root; | ||
1093 | |||
1094 | fake_device->parent = fake_bridge; | ||
1095 | |||
1096 | /* Initialize wait queues & mutual exclusion flags */ | ||
1097 | mutex_init(&fake_device->vme_int); | ||
1098 | mutex_init(&fake_bridge->irq_mtx); | ||
1099 | tasklet_init(&fake_device->int_tasklet, fake_VIRQ_tasklet, | ||
1100 | (unsigned long) fake_bridge); | ||
1101 | |||
1102 | strcpy(fake_bridge->name, driver_name); | ||
1103 | |||
1104 | /* Add master windows to list */ | ||
1105 | INIT_LIST_HEAD(&fake_bridge->master_resources); | ||
1106 | for (i = 0; i < FAKE_MAX_MASTER; i++) { | ||
1107 | master_image = kmalloc(sizeof(struct vme_master_resource), | ||
1108 | GFP_KERNEL); | ||
1109 | if (master_image == NULL) { | ||
1110 | retval = -ENOMEM; | ||
1111 | goto err_master; | ||
1112 | } | ||
1113 | master_image->parent = fake_bridge; | ||
1114 | spin_lock_init(&master_image->lock); | ||
1115 | master_image->locked = 0; | ||
1116 | master_image->number = i; | ||
1117 | master_image->address_attr = VME_A16 | VME_A24 | VME_A32 | | ||
1118 | VME_A64; | ||
1119 | master_image->cycle_attr = VME_SCT | VME_BLT | VME_MBLT | | ||
1120 | VME_2eVME | VME_2eSST | VME_2eSSTB | VME_2eSST160 | | ||
1121 | VME_2eSST267 | VME_2eSST320 | VME_SUPER | VME_USER | | ||
1122 | VME_PROG | VME_DATA; | ||
1123 | master_image->width_attr = VME_D16 | VME_D32; | ||
1124 | memset(&master_image->bus_resource, 0, | ||
1125 | sizeof(struct resource)); | ||
1126 | master_image->kern_base = NULL; | ||
1127 | list_add_tail(&master_image->list, | ||
1128 | &fake_bridge->master_resources); | ||
1129 | } | ||
1130 | |||
1131 | /* Add slave windows to list */ | ||
1132 | INIT_LIST_HEAD(&fake_bridge->slave_resources); | ||
1133 | for (i = 0; i < FAKE_MAX_SLAVE; i++) { | ||
1134 | slave_image = kmalloc(sizeof(struct vme_slave_resource), | ||
1135 | GFP_KERNEL); | ||
1136 | if (slave_image == NULL) { | ||
1137 | retval = -ENOMEM; | ||
1138 | goto err_slave; | ||
1139 | } | ||
1140 | slave_image->parent = fake_bridge; | ||
1141 | mutex_init(&slave_image->mtx); | ||
1142 | slave_image->locked = 0; | ||
1143 | slave_image->number = i; | ||
1144 | slave_image->address_attr = VME_A16 | VME_A24 | VME_A32 | | ||
1145 | VME_A64 | VME_CRCSR | VME_USER1 | VME_USER2 | | ||
1146 | VME_USER3 | VME_USER4; | ||
1147 | slave_image->cycle_attr = VME_SCT | VME_BLT | VME_MBLT | | ||
1148 | VME_2eVME | VME_2eSST | VME_2eSSTB | VME_2eSST160 | | ||
1149 | VME_2eSST267 | VME_2eSST320 | VME_SUPER | VME_USER | | ||
1150 | VME_PROG | VME_DATA; | ||
1151 | list_add_tail(&slave_image->list, | ||
1152 | &fake_bridge->slave_resources); | ||
1153 | } | ||
1154 | |||
1155 | /* Add location monitor to list */ | ||
1156 | INIT_LIST_HEAD(&fake_bridge->lm_resources); | ||
1157 | lm = kmalloc(sizeof(struct vme_lm_resource), GFP_KERNEL); | ||
1158 | if (lm == NULL) { | ||
1159 | pr_err("Failed to allocate memory for location monitor resource structure\n"); | ||
1160 | retval = -ENOMEM; | ||
1161 | goto err_lm; | ||
1162 | } | ||
1163 | lm->parent = fake_bridge; | ||
1164 | mutex_init(&lm->mtx); | ||
1165 | lm->locked = 0; | ||
1166 | lm->number = 1; | ||
1167 | lm->monitors = 4; | ||
1168 | list_add_tail(&lm->list, &fake_bridge->lm_resources); | ||
1169 | |||
1170 | fake_bridge->slave_get = fake_slave_get; | ||
1171 | fake_bridge->slave_set = fake_slave_set; | ||
1172 | fake_bridge->master_get = fake_master_get; | ||
1173 | fake_bridge->master_set = fake_master_set; | ||
1174 | fake_bridge->master_read = fake_master_read; | ||
1175 | fake_bridge->master_write = fake_master_write; | ||
1176 | fake_bridge->master_rmw = fake_master_rmw; | ||
1177 | fake_bridge->irq_set = fake_irq_set; | ||
1178 | fake_bridge->irq_generate = fake_irq_generate; | ||
1179 | fake_bridge->lm_set = fake_lm_set; | ||
1180 | fake_bridge->lm_get = fake_lm_get; | ||
1181 | fake_bridge->lm_attach = fake_lm_attach; | ||
1182 | fake_bridge->lm_detach = fake_lm_detach; | ||
1183 | fake_bridge->slot_get = fake_slot_get; | ||
1184 | fake_bridge->alloc_consistent = fake_alloc_consistent; | ||
1185 | fake_bridge->free_consistent = fake_free_consistent; | ||
1186 | |||
1187 | pr_info("Board is%s the VME system controller\n", | ||
1188 | (geoid == 1) ? "" : " not"); | ||
1189 | |||
1190 | pr_info("VME geographical address is set to %d\n", geoid); | ||
1191 | |||
1192 | retval = fake_crcsr_init(fake_bridge); | ||
1193 | if (retval) { | ||
1194 | pr_err("CR/CSR configuration failed.\n"); | ||
1195 | goto err_crcsr; | ||
1196 | } | ||
1197 | |||
1198 | retval = vme_register_bridge(fake_bridge); | ||
1199 | if (retval != 0) { | ||
1200 | pr_err("Chip Registration failed.\n"); | ||
1201 | goto err_reg; | ||
1202 | } | ||
1203 | |||
1204 | exit_pointer = fake_bridge; | ||
1205 | |||
1206 | return 0; | ||
1207 | |||
1208 | err_reg: | ||
1209 | fake_crcsr_exit(fake_bridge); | ||
1210 | err_crcsr: | ||
1211 | err_lm: | ||
1212 | /* resources are stored in link list */ | ||
1213 | list_for_each_safe(pos, n, &fake_bridge->lm_resources) { | ||
1214 | lm = list_entry(pos, struct vme_lm_resource, list); | ||
1215 | list_del(pos); | ||
1216 | kfree(lm); | ||
1217 | } | ||
1218 | err_slave: | ||
1219 | /* resources are stored in link list */ | ||
1220 | list_for_each_safe(pos, n, &fake_bridge->slave_resources) { | ||
1221 | slave_image = list_entry(pos, struct vme_slave_resource, list); | ||
1222 | list_del(pos); | ||
1223 | kfree(slave_image); | ||
1224 | } | ||
1225 | err_master: | ||
1226 | /* resources are stored in link list */ | ||
1227 | list_for_each_safe(pos, n, &fake_bridge->master_resources) { | ||
1228 | master_image = list_entry(pos, struct vme_master_resource, | ||
1229 | list); | ||
1230 | list_del(pos); | ||
1231 | kfree(master_image); | ||
1232 | } | ||
1233 | |||
1234 | kfree(fake_device); | ||
1235 | err_driver: | ||
1236 | kfree(fake_bridge); | ||
1237 | err_struct: | ||
1238 | return retval; | ||
1239 | |||
1240 | } | ||
1241 | |||
1242 | |||
1243 | static void __exit fake_exit(void) | ||
1244 | { | ||
1245 | struct list_head *pos = NULL; | ||
1246 | struct list_head *tmplist; | ||
1247 | struct vme_master_resource *master_image; | ||
1248 | struct vme_slave_resource *slave_image; | ||
1249 | int i; | ||
1250 | struct vme_bridge *fake_bridge; | ||
1251 | struct fake_driver *bridge; | ||
1252 | |||
1253 | fake_bridge = exit_pointer; | ||
1254 | |||
1255 | bridge = fake_bridge->driver_priv; | ||
1256 | |||
1257 | pr_debug("Driver is being unloaded.\n"); | ||
1258 | |||
1259 | /* | ||
1260 | * Shutdown all inbound and outbound windows. | ||
1261 | */ | ||
1262 | for (i = 0; i < FAKE_MAX_MASTER; i++) | ||
1263 | bridge->masters[i].enabled = 0; | ||
1264 | |||
1265 | for (i = 0; i < FAKE_MAX_SLAVE; i++) | ||
1266 | bridge->slaves[i].enabled = 0; | ||
1267 | |||
1268 | /* | ||
1269 | * Shutdown Location monitor. | ||
1270 | */ | ||
1271 | bridge->lm_enabled = 0; | ||
1272 | |||
1273 | vme_unregister_bridge(fake_bridge); | ||
1274 | |||
1275 | fake_crcsr_exit(fake_bridge); | ||
1276 | /* resources are stored in link list */ | ||
1277 | list_for_each_safe(pos, tmplist, &fake_bridge->slave_resources) { | ||
1278 | slave_image = list_entry(pos, struct vme_slave_resource, list); | ||
1279 | list_del(pos); | ||
1280 | kfree(slave_image); | ||
1281 | } | ||
1282 | |||
1283 | /* resources are stored in link list */ | ||
1284 | list_for_each_safe(pos, tmplist, &fake_bridge->master_resources) { | ||
1285 | master_image = list_entry(pos, struct vme_master_resource, | ||
1286 | list); | ||
1287 | list_del(pos); | ||
1288 | kfree(master_image); | ||
1289 | } | ||
1290 | |||
1291 | kfree(fake_bridge->driver_priv); | ||
1292 | |||
1293 | kfree(fake_bridge); | ||
1294 | |||
1295 | root_device_unregister(vme_root); | ||
1296 | } | ||
1297 | |||
1298 | |||
1299 | MODULE_PARM_DESC(geoid, "Set geographical addressing"); | ||
1300 | module_param(geoid, int, 0); | ||
1301 | |||
1302 | MODULE_DESCRIPTION("Fake VME bridge driver"); | ||
1303 | MODULE_LICENSE("GPL"); | ||
1304 | |||
1305 | module_init(fake_init); | ||
1306 | module_exit(fake_exit); | ||
diff --git a/drivers/vme/bridges/vme_tsi148.c b/drivers/vme/bridges/vme_tsi148.c index 4bc5d451ec6c..fc1b634b969a 100644 --- a/drivers/vme/bridges/vme_tsi148.c +++ b/drivers/vme/bridges/vme_tsi148.c | |||
@@ -50,6 +50,8 @@ static const struct pci_device_id tsi148_ids[] = { | |||
50 | { }, | 50 | { }, |
51 | }; | 51 | }; |
52 | 52 | ||
53 | MODULE_DEVICE_TABLE(pci, tsi148_ids); | ||
54 | |||
53 | static struct pci_driver tsi148_driver = { | 55 | static struct pci_driver tsi148_driver = { |
54 | .name = driver_name, | 56 | .name = driver_name, |
55 | .id_table = tsi148_ids, | 57 | .id_table = tsi148_ids, |
@@ -102,7 +104,7 @@ static u32 tsi148_LM_irqhandler(struct tsi148_driver *bridge, u32 stat) | |||
102 | for (i = 0; i < 4; i++) { | 104 | for (i = 0; i < 4; i++) { |
103 | if (stat & TSI148_LCSR_INTS_LMS[i]) { | 105 | if (stat & TSI148_LCSR_INTS_LMS[i]) { |
104 | /* We only enable interrupts if the callback is set */ | 106 | /* We only enable interrupts if the callback is set */ |
105 | bridge->lm_callback[i](i); | 107 | bridge->lm_callback[i](bridge->lm_data[i]); |
106 | serviced |= TSI148_LCSR_INTC_LMC[i]; | 108 | serviced |= TSI148_LCSR_INTC_LMC[i]; |
107 | } | 109 | } |
108 | } | 110 | } |
@@ -2047,7 +2049,7 @@ static int tsi148_lm_get(struct vme_lm_resource *lm, | |||
2047 | * Callback will be passed the monitor triggered. | 2049 | * Callback will be passed the monitor triggered. |
2048 | */ | 2050 | */ |
2049 | static int tsi148_lm_attach(struct vme_lm_resource *lm, int monitor, | 2051 | static int tsi148_lm_attach(struct vme_lm_resource *lm, int monitor, |
2050 | void (*callback)(int)) | 2052 | void (*callback)(void *), void *data) |
2051 | { | 2053 | { |
2052 | u32 lm_ctl, tmp; | 2054 | u32 lm_ctl, tmp; |
2053 | struct vme_bridge *tsi148_bridge; | 2055 | struct vme_bridge *tsi148_bridge; |
@@ -2077,6 +2079,7 @@ static int tsi148_lm_attach(struct vme_lm_resource *lm, int monitor, | |||
2077 | 2079 | ||
2078 | /* Attach callback */ | 2080 | /* Attach callback */ |
2079 | bridge->lm_callback[monitor] = callback; | 2081 | bridge->lm_callback[monitor] = callback; |
2082 | bridge->lm_data[monitor] = data; | ||
2080 | 2083 | ||
2081 | /* Enable Location Monitor interrupt */ | 2084 | /* Enable Location Monitor interrupt */ |
2082 | tmp = ioread32be(bridge->base + TSI148_LCSR_INTEN); | 2085 | tmp = ioread32be(bridge->base + TSI148_LCSR_INTEN); |
@@ -2124,6 +2127,7 @@ static int tsi148_lm_detach(struct vme_lm_resource *lm, int monitor) | |||
2124 | 2127 | ||
2125 | /* Detach callback */ | 2128 | /* Detach callback */ |
2126 | bridge->lm_callback[monitor] = NULL; | 2129 | bridge->lm_callback[monitor] = NULL; |
2130 | bridge->lm_data[monitor] = NULL; | ||
2127 | 2131 | ||
2128 | /* If all location monitors disabled, disable global Location Monitor */ | 2132 | /* If all location monitors disabled, disable global Location Monitor */ |
2129 | if ((lm_en & (TSI148_LCSR_INTS_LM0S | TSI148_LCSR_INTS_LM1S | | 2133 | if ((lm_en & (TSI148_LCSR_INTS_LM0S | TSI148_LCSR_INTS_LM1S | |
diff --git a/drivers/vme/bridges/vme_tsi148.h b/drivers/vme/bridges/vme_tsi148.h index f5ed14382a8d..0935d85d32ec 100644 --- a/drivers/vme/bridges/vme_tsi148.h +++ b/drivers/vme/bridges/vme_tsi148.h | |||
@@ -38,7 +38,8 @@ struct tsi148_driver { | |||
38 | void __iomem *base; /* Base Address of device registers */ | 38 | void __iomem *base; /* Base Address of device registers */ |
39 | wait_queue_head_t dma_queue[2]; | 39 | wait_queue_head_t dma_queue[2]; |
40 | wait_queue_head_t iack_queue; | 40 | wait_queue_head_t iack_queue; |
41 | void (*lm_callback[4])(int); /* Called in interrupt handler */ | 41 | void (*lm_callback[4])(void *); /* Called in interrupt handler */ |
42 | void *lm_data[4]; | ||
42 | void *crcsr_kernel; | 43 | void *crcsr_kernel; |
43 | dma_addr_t crcsr_bus; | 44 | dma_addr_t crcsr_bus; |
44 | struct vme_master_resource *flush_image; | 45 | struct vme_master_resource *flush_image; |
diff --git a/drivers/vme/vme.c b/drivers/vme/vme.c index 37ac0a58e59a..15b64076bc26 100644 --- a/drivers/vme/vme.c +++ b/drivers/vme/vme.c | |||
@@ -13,8 +13,8 @@ | |||
13 | * option) any later version. | 13 | * option) any later version. |
14 | */ | 14 | */ |
15 | 15 | ||
16 | #include <linux/module.h> | 16 | #include <linux/init.h> |
17 | #include <linux/moduleparam.h> | 17 | #include <linux/export.h> |
18 | #include <linux/mm.h> | 18 | #include <linux/mm.h> |
19 | #include <linux/types.h> | 19 | #include <linux/types.h> |
20 | #include <linux/kernel.h> | 20 | #include <linux/kernel.h> |
@@ -39,7 +39,6 @@ static unsigned int vme_bus_numbers; | |||
39 | static LIST_HEAD(vme_bus_list); | 39 | static LIST_HEAD(vme_bus_list); |
40 | static DEFINE_MUTEX(vme_buses_lock); | 40 | static DEFINE_MUTEX(vme_buses_lock); |
41 | 41 | ||
42 | static void __exit vme_exit(void); | ||
43 | static int __init vme_init(void); | 42 | static int __init vme_init(void); |
44 | 43 | ||
45 | static struct vme_dev *dev_to_vme_dev(struct device *dev) | 44 | static struct vme_dev *dev_to_vme_dev(struct device *dev) |
@@ -1321,7 +1320,7 @@ int vme_lm_get(struct vme_resource *resource, unsigned long long *lm_base, | |||
1321 | EXPORT_SYMBOL(vme_lm_get); | 1320 | EXPORT_SYMBOL(vme_lm_get); |
1322 | 1321 | ||
1323 | int vme_lm_attach(struct vme_resource *resource, int monitor, | 1322 | int vme_lm_attach(struct vme_resource *resource, int monitor, |
1324 | void (*callback)(int)) | 1323 | void (*callback)(void *), void *data) |
1325 | { | 1324 | { |
1326 | struct vme_bridge *bridge = find_bridge(resource); | 1325 | struct vme_bridge *bridge = find_bridge(resource); |
1327 | struct vme_lm_resource *lm; | 1326 | struct vme_lm_resource *lm; |
@@ -1338,7 +1337,7 @@ int vme_lm_attach(struct vme_resource *resource, int monitor, | |||
1338 | return -EINVAL; | 1337 | return -EINVAL; |
1339 | } | 1338 | } |
1340 | 1339 | ||
1341 | return bridge->lm_attach(lm, monitor, callback); | 1340 | return bridge->lm_attach(lm, monitor, callback, data); |
1342 | } | 1341 | } |
1343 | EXPORT_SYMBOL(vme_lm_attach); | 1342 | EXPORT_SYMBOL(vme_lm_attach); |
1344 | 1343 | ||
@@ -1622,25 +1621,10 @@ static int vme_bus_probe(struct device *dev) | |||
1622 | return retval; | 1621 | return retval; |
1623 | } | 1622 | } |
1624 | 1623 | ||
1625 | static int vme_bus_remove(struct device *dev) | ||
1626 | { | ||
1627 | int retval = -ENODEV; | ||
1628 | struct vme_driver *driver; | ||
1629 | struct vme_dev *vdev = dev_to_vme_dev(dev); | ||
1630 | |||
1631 | driver = dev->platform_data; | ||
1632 | |||
1633 | if (driver->remove != NULL) | ||
1634 | retval = driver->remove(vdev); | ||
1635 | |||
1636 | return retval; | ||
1637 | } | ||
1638 | |||
1639 | struct bus_type vme_bus_type = { | 1624 | struct bus_type vme_bus_type = { |
1640 | .name = "vme", | 1625 | .name = "vme", |
1641 | .match = vme_bus_match, | 1626 | .match = vme_bus_match, |
1642 | .probe = vme_bus_probe, | 1627 | .probe = vme_bus_probe, |
1643 | .remove = vme_bus_remove, | ||
1644 | }; | 1628 | }; |
1645 | EXPORT_SYMBOL(vme_bus_type); | 1629 | EXPORT_SYMBOL(vme_bus_type); |
1646 | 1630 | ||
@@ -1648,11 +1632,4 @@ static int __init vme_init(void) | |||
1648 | { | 1632 | { |
1649 | return bus_register(&vme_bus_type); | 1633 | return bus_register(&vme_bus_type); |
1650 | } | 1634 | } |
1651 | |||
1652 | static void __exit vme_exit(void) | ||
1653 | { | ||
1654 | bus_unregister(&vme_bus_type); | ||
1655 | } | ||
1656 | |||
1657 | subsys_initcall(vme_init); | 1635 | subsys_initcall(vme_init); |
1658 | module_exit(vme_exit); | ||
diff --git a/drivers/vme/vme_bridge.h b/drivers/vme/vme_bridge.h index cb8246fd97be..2662e916b96a 100644 --- a/drivers/vme/vme_bridge.h +++ b/drivers/vme/vme_bridge.h | |||
@@ -160,7 +160,8 @@ struct vme_bridge { | |||
160 | int (*lm_set) (struct vme_lm_resource *, unsigned long long, u32, u32); | 160 | int (*lm_set) (struct vme_lm_resource *, unsigned long long, u32, u32); |
161 | int (*lm_get) (struct vme_lm_resource *, unsigned long long *, u32 *, | 161 | int (*lm_get) (struct vme_lm_resource *, unsigned long long *, u32 *, |
162 | u32 *); | 162 | u32 *); |
163 | int (*lm_attach) (struct vme_lm_resource *, int, void (*callback)(int)); | 163 | int (*lm_attach)(struct vme_lm_resource *, int, |
164 | void (*callback)(void *), void *); | ||
164 | int (*lm_detach) (struct vme_lm_resource *, int); | 165 | int (*lm_detach) (struct vme_lm_resource *, int); |
165 | 166 | ||
166 | /* CR/CSR space functions */ | 167 | /* CR/CSR space functions */ |
diff --git a/drivers/w1/slaves/w1_therm.c b/drivers/w1/slaves/w1_therm.c index 581a300fd6cd..82611f197b0a 100644 --- a/drivers/w1/slaves/w1_therm.c +++ b/drivers/w1/slaves/w1_therm.c | |||
@@ -66,7 +66,7 @@ struct w1_therm_family_data { | |||
66 | 66 | ||
67 | /* return the address of the refcnt in the family data */ | 67 | /* return the address of the refcnt in the family data */ |
68 | #define THERM_REFCNT(family_data) \ | 68 | #define THERM_REFCNT(family_data) \ |
69 | (&((struct w1_therm_family_data*)family_data)->refcnt) | 69 | (&((struct w1_therm_family_data *)family_data)->refcnt) |
70 | 70 | ||
71 | static int w1_therm_add_slave(struct w1_slave *sl) | 71 | static int w1_therm_add_slave(struct w1_slave *sl) |
72 | { | 72 | { |
@@ -81,7 +81,8 @@ static int w1_therm_add_slave(struct w1_slave *sl) | |||
81 | static void w1_therm_remove_slave(struct w1_slave *sl) | 81 | static void w1_therm_remove_slave(struct w1_slave *sl) |
82 | { | 82 | { |
83 | int refcnt = atomic_sub_return(1, THERM_REFCNT(sl->family_data)); | 83 | int refcnt = atomic_sub_return(1, THERM_REFCNT(sl->family_data)); |
84 | while(refcnt) { | 84 | |
85 | while (refcnt) { | ||
85 | msleep(1000); | 86 | msleep(1000); |
86 | refcnt = atomic_read(THERM_REFCNT(sl->family_data)); | 87 | refcnt = atomic_read(THERM_REFCNT(sl->family_data)); |
87 | } | 88 | } |
@@ -151,8 +152,7 @@ static struct w1_family w1_therm_family_DS1825 = { | |||
151 | .fops = &w1_therm_fops, | 152 | .fops = &w1_therm_fops, |
152 | }; | 153 | }; |
153 | 154 | ||
154 | struct w1_therm_family_converter | 155 | struct w1_therm_family_converter { |
155 | { | ||
156 | u8 broken; | 156 | u8 broken; |
157 | u16 reserved; | 157 | u16 reserved; |
158 | struct w1_family *f; | 158 | struct w1_family *f; |
@@ -293,7 +293,7 @@ static inline int w1_DS18B20_precision(struct device *device, int val) | |||
293 | uint8_t precision_bits; | 293 | uint8_t precision_bits; |
294 | uint8_t mask = 0x60; | 294 | uint8_t mask = 0x60; |
295 | 295 | ||
296 | if(val > 12 || val < 9) { | 296 | if (val > 12 || val < 9) { |
297 | pr_warn("Unsupported precision\n"); | 297 | pr_warn("Unsupported precision\n"); |
298 | return -1; | 298 | return -1; |
299 | } | 299 | } |
@@ -336,7 +336,8 @@ static inline int w1_DS18B20_precision(struct device *device, int val) | |||
336 | 336 | ||
337 | /* read values to only alter precision bits */ | 337 | /* read values to only alter precision bits */ |
338 | w1_write_8(dev, W1_READ_SCRATCHPAD); | 338 | w1_write_8(dev, W1_READ_SCRATCHPAD); |
339 | if ((count = w1_read_block(dev, rom, 9)) != 9) | 339 | count = w1_read_block(dev, rom, 9); |
340 | if (count != 9) | ||
340 | dev_warn(device, "w1_read_block() returned %u instead of 9.\n", count); | 341 | dev_warn(device, "w1_read_block() returned %u instead of 9.\n", count); |
341 | 342 | ||
342 | crc = w1_calc_crc8(rom, 8); | 343 | crc = w1_calc_crc8(rom, 8); |
@@ -366,6 +367,7 @@ post_unlock: | |||
366 | static inline int w1_DS18B20_convert_temp(u8 rom[9]) | 367 | static inline int w1_DS18B20_convert_temp(u8 rom[9]) |
367 | { | 368 | { |
368 | s16 t = le16_to_cpup((__le16 *)rom); | 369 | s16 t = le16_to_cpup((__le16 *)rom); |
370 | |||
369 | return t*1000/16; | 371 | return t*1000/16; |
370 | } | 372 | } |
371 | 373 | ||
@@ -415,7 +417,7 @@ static ssize_t w1_slave_store(struct device *device, | |||
415 | for (i = 0; i < ARRAY_SIZE(w1_therm_families); ++i) { | 417 | for (i = 0; i < ARRAY_SIZE(w1_therm_families); ++i) { |
416 | if (w1_therm_families[i].f->fid == sl->family->fid) { | 418 | if (w1_therm_families[i].f->fid == sl->family->fid) { |
417 | /* zero value indicates to write current configuration to eeprom */ | 419 | /* zero value indicates to write current configuration to eeprom */ |
418 | if (0 == val) | 420 | if (val == 0) |
419 | ret = w1_therm_families[i].eeprom(device); | 421 | ret = w1_therm_families[i].eeprom(device); |
420 | else | 422 | else |
421 | ret = w1_therm_families[i].precision(device, val); | 423 | ret = w1_therm_families[i].precision(device, val); |
@@ -439,8 +441,7 @@ static ssize_t w1_slave_show(struct device *device, | |||
439 | if (ret != 0) | 441 | if (ret != 0) |
440 | goto post_unlock; | 442 | goto post_unlock; |
441 | 443 | ||
442 | if(!sl->family_data) | 444 | if (!sl->family_data) { |
443 | { | ||
444 | ret = -ENODEV; | 445 | ret = -ENODEV; |
445 | goto pre_unlock; | 446 | goto pre_unlock; |
446 | } | 447 | } |
@@ -495,7 +496,8 @@ static ssize_t w1_slave_show(struct device *device, | |||
495 | if (!w1_reset_select_slave(sl)) { | 496 | if (!w1_reset_select_slave(sl)) { |
496 | 497 | ||
497 | w1_write_8(dev, W1_READ_SCRATCHPAD); | 498 | w1_write_8(dev, W1_READ_SCRATCHPAD); |
498 | if ((count = w1_read_block(dev, rom, 9)) != 9) { | 499 | count = w1_read_block(dev, rom, 9); |
500 | if (count != 9) { | ||
499 | dev_warn(device, "w1_read_block() " | 501 | dev_warn(device, "w1_read_block() " |
500 | "returned %u instead of 9.\n", | 502 | "returned %u instead of 9.\n", |
501 | count); | 503 | count); |
diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c index bb34362e930a..e213c678bbfe 100644 --- a/drivers/w1/w1.c +++ b/drivers/w1/w1.c | |||
@@ -53,8 +53,8 @@ int w1_max_slave_ttl = 10; | |||
53 | module_param_named(timeout, w1_timeout, int, 0); | 53 | module_param_named(timeout, w1_timeout, int, 0); |
54 | MODULE_PARM_DESC(timeout, "time in seconds between automatic slave searches"); | 54 | MODULE_PARM_DESC(timeout, "time in seconds between automatic slave searches"); |
55 | module_param_named(timeout_us, w1_timeout_us, int, 0); | 55 | module_param_named(timeout_us, w1_timeout_us, int, 0); |
56 | MODULE_PARM_DESC(timeout, "time in microseconds between automatic slave" | 56 | MODULE_PARM_DESC(timeout_us, |
57 | " searches"); | 57 | "time in microseconds between automatic slave searches"); |
58 | /* A search stops when w1_max_slave_count devices have been found in that | 58 | /* A search stops when w1_max_slave_count devices have been found in that |
59 | * search. The next search will start over and detect the same set of devices | 59 | * search. The next search will start over and detect the same set of devices |
60 | * on a static 1-wire bus. Memory is not allocated based on this number, just | 60 | * on a static 1-wire bus. Memory is not allocated based on this number, just |
diff --git a/include/linux/coresight.h b/include/linux/coresight.h index 385d62e64abb..2a5982c37dfb 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h | |||
@@ -232,8 +232,9 @@ struct coresight_ops_source { | |||
232 | int (*cpu_id)(struct coresight_device *csdev); | 232 | int (*cpu_id)(struct coresight_device *csdev); |
233 | int (*trace_id)(struct coresight_device *csdev); | 233 | int (*trace_id)(struct coresight_device *csdev); |
234 | int (*enable)(struct coresight_device *csdev, | 234 | int (*enable)(struct coresight_device *csdev, |
235 | struct perf_event_attr *attr, u32 mode); | 235 | struct perf_event *event, u32 mode); |
236 | void (*disable)(struct coresight_device *csdev); | 236 | void (*disable)(struct coresight_device *csdev, |
237 | struct perf_event *event); | ||
237 | }; | 238 | }; |
238 | 239 | ||
239 | struct coresight_ops { | 240 | struct coresight_ops { |
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index b10954a66939..cd184bdca58f 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h | |||
@@ -674,6 +674,11 @@ enum hv_signal_policy { | |||
674 | HV_SIGNAL_POLICY_EXPLICIT, | 674 | HV_SIGNAL_POLICY_EXPLICIT, |
675 | }; | 675 | }; |
676 | 676 | ||
677 | enum hv_numa_policy { | ||
678 | HV_BALANCED = 0, | ||
679 | HV_LOCALIZED, | ||
680 | }; | ||
681 | |||
677 | enum vmbus_device_type { | 682 | enum vmbus_device_type { |
678 | HV_IDE = 0, | 683 | HV_IDE = 0, |
679 | HV_SCSI, | 684 | HV_SCSI, |
@@ -701,9 +706,6 @@ struct vmbus_device { | |||
701 | }; | 706 | }; |
702 | 707 | ||
703 | struct vmbus_channel { | 708 | struct vmbus_channel { |
704 | /* Unique channel id */ | ||
705 | int id; | ||
706 | |||
707 | struct list_head listentry; | 709 | struct list_head listentry; |
708 | 710 | ||
709 | struct hv_device *device_obj; | 711 | struct hv_device *device_obj; |
@@ -850,6 +852,43 @@ struct vmbus_channel { | |||
850 | * ring lock to preserve the current behavior. | 852 | * ring lock to preserve the current behavior. |
851 | */ | 853 | */ |
852 | bool acquire_ring_lock; | 854 | bool acquire_ring_lock; |
855 | /* | ||
856 | * For performance critical channels (storage, networking | ||
857 | * etc,), Hyper-V has a mechanism to enhance the throughput | ||
858 | * at the expense of latency: | ||
859 | * When the host is to be signaled, we just set a bit in a shared page | ||
860 | * and this bit will be inspected by the hypervisor within a certain | ||
861 | * window and if the bit is set, the host will be signaled. The window | ||
862 | * of time is the monitor latency - currently around 100 usecs. This | ||
863 | * mechanism improves throughput by: | ||
864 | * | ||
865 | * A) Making the host more efficient - each time it wakes up, | ||
866 | * potentially it will process morev number of packets. The | ||
867 | * monitor latency allows a batch to build up. | ||
868 | * B) By deferring the hypercall to signal, we will also minimize | ||
869 | * the interrupts. | ||
870 | * | ||
871 | * Clearly, these optimizations improve throughput at the expense of | ||
872 | * latency. Furthermore, since the channel is shared for both | ||
873 | * control and data messages, control messages currently suffer | ||
874 | * unnecessary latency adversley impacting performance and boot | ||
875 | * time. To fix this issue, permit tagging the channel as being | ||
876 | * in "low latency" mode. In this mode, we will bypass the monitor | ||
877 | * mechanism. | ||
878 | */ | ||
879 | bool low_latency; | ||
880 | |||
881 | /* | ||
882 | * NUMA distribution policy: | ||
883 | * We support teo policies: | ||
884 | * 1) Balanced: Here all performance critical channels are | ||
885 | * distributed evenly amongst all the NUMA nodes. | ||
886 | * This policy will be the default policy. | ||
887 | * 2) Localized: All channels of a given instance of a | ||
888 | * performance critical service will be assigned CPUs | ||
889 | * within a selected NUMA node. | ||
890 | */ | ||
891 | enum hv_numa_policy affinity_policy; | ||
853 | 892 | ||
854 | }; | 893 | }; |
855 | 894 | ||
@@ -870,6 +909,12 @@ static inline void set_channel_signal_state(struct vmbus_channel *c, | |||
870 | c->signal_policy = policy; | 909 | c->signal_policy = policy; |
871 | } | 910 | } |
872 | 911 | ||
912 | static inline void set_channel_affinity_state(struct vmbus_channel *c, | ||
913 | enum hv_numa_policy policy) | ||
914 | { | ||
915 | c->affinity_policy = policy; | ||
916 | } | ||
917 | |||
873 | static inline void set_channel_read_state(struct vmbus_channel *c, bool state) | 918 | static inline void set_channel_read_state(struct vmbus_channel *c, bool state) |
874 | { | 919 | { |
875 | c->batched_reading = state; | 920 | c->batched_reading = state; |
@@ -891,6 +936,16 @@ static inline void set_channel_pending_send_size(struct vmbus_channel *c, | |||
891 | c->outbound.ring_buffer->pending_send_sz = size; | 936 | c->outbound.ring_buffer->pending_send_sz = size; |
892 | } | 937 | } |
893 | 938 | ||
939 | static inline void set_low_latency_mode(struct vmbus_channel *c) | ||
940 | { | ||
941 | c->low_latency = true; | ||
942 | } | ||
943 | |||
944 | static inline void clear_low_latency_mode(struct vmbus_channel *c) | ||
945 | { | ||
946 | c->low_latency = false; | ||
947 | } | ||
948 | |||
894 | void vmbus_onmessage(void *context); | 949 | void vmbus_onmessage(void *context); |
895 | 950 | ||
896 | int vmbus_request_offers(void); | 951 | int vmbus_request_offers(void); |
@@ -1257,6 +1312,27 @@ u64 hv_do_hypercall(u64 control, void *input, void *output); | |||
1257 | 0x80, 0x2e, 0x27, 0xed, 0xe1, 0x9f) | 1312 | 0x80, 0x2e, 0x27, 0xed, 0xe1, 0x9f) |
1258 | 1313 | ||
1259 | /* | 1314 | /* |
1315 | * Linux doesn't support the 3 devices: the first two are for | ||
1316 | * Automatic Virtual Machine Activation, and the third is for | ||
1317 | * Remote Desktop Virtualization. | ||
1318 | * {f8e65716-3cb3-4a06-9a60-1889c5cccab5} | ||
1319 | * {3375baf4-9e15-4b30-b765-67acb10d607b} | ||
1320 | * {276aacf4-ac15-426c-98dd-7521ad3f01fe} | ||
1321 | */ | ||
1322 | |||
1323 | #define HV_AVMA1_GUID \ | ||
1324 | .guid = UUID_LE(0xf8e65716, 0x3cb3, 0x4a06, 0x9a, 0x60, \ | ||
1325 | 0x18, 0x89, 0xc5, 0xcc, 0xca, 0xb5) | ||
1326 | |||
1327 | #define HV_AVMA2_GUID \ | ||
1328 | .guid = UUID_LE(0x3375baf4, 0x9e15, 0x4b30, 0xb7, 0x65, \ | ||
1329 | 0x67, 0xac, 0xb1, 0x0d, 0x60, 0x7b) | ||
1330 | |||
1331 | #define HV_RDV_GUID \ | ||
1332 | .guid = UUID_LE(0x276aacf4, 0xac15, 0x426c, 0x98, 0xdd, \ | ||
1333 | 0x75, 0x21, 0xad, 0x3f, 0x01, 0xfe) | ||
1334 | |||
1335 | /* | ||
1260 | * Common header for Hyper-V ICs | 1336 | * Common header for Hyper-V ICs |
1261 | */ | 1337 | */ |
1262 | 1338 | ||
@@ -1344,6 +1420,15 @@ struct ictimesync_data { | |||
1344 | u8 flags; | 1420 | u8 flags; |
1345 | } __packed; | 1421 | } __packed; |
1346 | 1422 | ||
1423 | struct ictimesync_ref_data { | ||
1424 | u64 parenttime; | ||
1425 | u64 vmreferencetime; | ||
1426 | u8 flags; | ||
1427 | char leapflags; | ||
1428 | char stratum; | ||
1429 | u8 reserved[3]; | ||
1430 | } __packed; | ||
1431 | |||
1347 | struct hyperv_service_callback { | 1432 | struct hyperv_service_callback { |
1348 | u8 msg_type; | 1433 | u8 msg_type; |
1349 | char *log_msg; | 1434 | char *log_msg; |
@@ -1357,6 +1442,9 @@ extern bool vmbus_prep_negotiate_resp(struct icmsg_hdr *, | |||
1357 | struct icmsg_negotiate *, u8 *, int, | 1442 | struct icmsg_negotiate *, u8 *, int, |
1358 | int); | 1443 | int); |
1359 | 1444 | ||
1445 | void hv_event_tasklet_disable(struct vmbus_channel *channel); | ||
1446 | void hv_event_tasklet_enable(struct vmbus_channel *channel); | ||
1447 | |||
1360 | void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid); | 1448 | void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid); |
1361 | 1449 | ||
1362 | /* | 1450 | /* |
diff --git a/include/linux/mcb.h b/include/linux/mcb.h index ead13d233a97..4097ac9ea13a 100644 --- a/include/linux/mcb.h +++ b/include/linux/mcb.h | |||
@@ -41,15 +41,17 @@ struct mcb_bus { | |||
41 | char name[CHAMELEON_FILENAME_LEN + 1]; | 41 | char name[CHAMELEON_FILENAME_LEN + 1]; |
42 | int (*get_irq)(struct mcb_device *dev); | 42 | int (*get_irq)(struct mcb_device *dev); |
43 | }; | 43 | }; |
44 | #define to_mcb_bus(b) container_of((b), struct mcb_bus, dev) | 44 | |
45 | static inline struct mcb_bus *to_mcb_bus(struct device *dev) | ||
46 | { | ||
47 | return container_of(dev, struct mcb_bus, dev); | ||
48 | } | ||
45 | 49 | ||
46 | /** | 50 | /** |
47 | * struct mcb_device - MEN Chameleon Bus device | 51 | * struct mcb_device - MEN Chameleon Bus device |
48 | * | 52 | * |
49 | * @bus_list: internal list handling for bus code | ||
50 | * @dev: device in kernel representation | 53 | * @dev: device in kernel representation |
51 | * @bus: mcb bus the device is plugged to | 54 | * @bus: mcb bus the device is plugged to |
52 | * @subordinate: subordinate MCBus in case of bridge | ||
53 | * @is_added: flag to check if device is added to bus | 55 | * @is_added: flag to check if device is added to bus |
54 | * @driver: associated mcb_driver | 56 | * @driver: associated mcb_driver |
55 | * @id: mcb device id | 57 | * @id: mcb device id |
@@ -62,10 +64,8 @@ struct mcb_bus { | |||
62 | * @memory: memory resource | 64 | * @memory: memory resource |
63 | */ | 65 | */ |
64 | struct mcb_device { | 66 | struct mcb_device { |
65 | struct list_head bus_list; | ||
66 | struct device dev; | 67 | struct device dev; |
67 | struct mcb_bus *bus; | 68 | struct mcb_bus *bus; |
68 | struct mcb_bus *subordinate; | ||
69 | bool is_added; | 69 | bool is_added; |
70 | struct mcb_driver *driver; | 70 | struct mcb_driver *driver; |
71 | u16 id; | 71 | u16 id; |
@@ -76,8 +76,13 @@ struct mcb_device { | |||
76 | int rev; | 76 | int rev; |
77 | struct resource irq; | 77 | struct resource irq; |
78 | struct resource mem; | 78 | struct resource mem; |
79 | struct device *dma_dev; | ||
79 | }; | 80 | }; |
80 | #define to_mcb_device(x) container_of((x), struct mcb_device, dev) | 81 | |
82 | static inline struct mcb_device *to_mcb_device(struct device *dev) | ||
83 | { | ||
84 | return container_of(dev, struct mcb_device, dev); | ||
85 | } | ||
81 | 86 | ||
82 | /** | 87 | /** |
83 | * struct mcb_driver - MEN Chameleon Bus device driver | 88 | * struct mcb_driver - MEN Chameleon Bus device driver |
@@ -95,7 +100,11 @@ struct mcb_driver { | |||
95 | void (*remove)(struct mcb_device *mdev); | 100 | void (*remove)(struct mcb_device *mdev); |
96 | void (*shutdown)(struct mcb_device *mdev); | 101 | void (*shutdown)(struct mcb_device *mdev); |
97 | }; | 102 | }; |
98 | #define to_mcb_driver(x) container_of((x), struct mcb_driver, driver) | 103 | |
104 | static inline struct mcb_driver *to_mcb_driver(struct device_driver *drv) | ||
105 | { | ||
106 | return container_of(drv, struct mcb_driver, driver); | ||
107 | } | ||
99 | 108 | ||
100 | static inline void *mcb_get_drvdata(struct mcb_device *dev) | 109 | static inline void *mcb_get_drvdata(struct mcb_device *dev) |
101 | { | 110 | { |
diff --git a/include/linux/miscdevice.h b/include/linux/miscdevice.h index 543037465973..722698a43d79 100644 --- a/include/linux/miscdevice.h +++ b/include/linux/miscdevice.h | |||
@@ -3,6 +3,7 @@ | |||
3 | #include <linux/major.h> | 3 | #include <linux/major.h> |
4 | #include <linux/list.h> | 4 | #include <linux/list.h> |
5 | #include <linux/types.h> | 5 | #include <linux/types.h> |
6 | #include <linux/device.h> | ||
6 | 7 | ||
7 | /* | 8 | /* |
8 | * These allocations are managed by device@lanana.org. If you use an | 9 | * These allocations are managed by device@lanana.org. If you use an |
@@ -70,6 +71,13 @@ struct miscdevice { | |||
70 | extern int misc_register(struct miscdevice *misc); | 71 | extern int misc_register(struct miscdevice *misc); |
71 | extern void misc_deregister(struct miscdevice *misc); | 72 | extern void misc_deregister(struct miscdevice *misc); |
72 | 73 | ||
74 | /* | ||
75 | * Helper macro for drivers that don't do anything special in module init / exit | ||
76 | * call. This helps in eleminating of boilerplate code. | ||
77 | */ | ||
78 | #define module_misc_device(__misc_device) \ | ||
79 | module_driver(__misc_device, misc_register, misc_deregister) | ||
80 | |||
73 | #define MODULE_ALIAS_MISCDEV(minor) \ | 81 | #define MODULE_ALIAS_MISCDEV(minor) \ |
74 | MODULE_ALIAS("char-major-" __stringify(MISC_MAJOR) \ | 82 | MODULE_ALIAS("char-major-" __stringify(MISC_MAJOR) \ |
75 | "-" __stringify(minor)) | 83 | "-" __stringify(minor)) |
diff --git a/include/linux/vme.h b/include/linux/vme.h index 71e4a6dec5ac..ea6095deba20 100644 --- a/include/linux/vme.h +++ b/include/linux/vme.h | |||
@@ -166,7 +166,7 @@ struct vme_resource *vme_lm_request(struct vme_dev *); | |||
166 | int vme_lm_count(struct vme_resource *); | 166 | int vme_lm_count(struct vme_resource *); |
167 | int vme_lm_set(struct vme_resource *, unsigned long long, u32, u32); | 167 | int vme_lm_set(struct vme_resource *, unsigned long long, u32, u32); |
168 | int vme_lm_get(struct vme_resource *, unsigned long long *, u32 *, u32 *); | 168 | int vme_lm_get(struct vme_resource *, unsigned long long *, u32 *, u32 *); |
169 | int vme_lm_attach(struct vme_resource *, int, void (*callback)(int)); | 169 | int vme_lm_attach(struct vme_resource *, int, void (*callback)(void *), void *); |
170 | int vme_lm_detach(struct vme_resource *, int); | 170 | int vme_lm_detach(struct vme_resource *, int); |
171 | void vme_lm_free(struct vme_resource *); | 171 | void vme_lm_free(struct vme_resource *); |
172 | 172 | ||
diff --git a/scripts/checkkconfigsymbols.py b/scripts/checkkconfigsymbols.py index df643f60bb41..a32e4da4c117 100755 --- a/scripts/checkkconfigsymbols.py +++ b/scripts/checkkconfigsymbols.py | |||
@@ -1,98 +1,99 @@ | |||
1 | #!/usr/bin/env python2 | 1 | #!/usr/bin/env python3 |
2 | 2 | ||
3 | """Find Kconfig symbols that are referenced but not defined.""" | 3 | """Find Kconfig symbols that are referenced but not defined.""" |
4 | 4 | ||
5 | # (c) 2014-2015 Valentin Rothberg <valentinrothberg@gmail.com> | 5 | # (c) 2014-2016 Valentin Rothberg <valentinrothberg@gmail.com> |
6 | # (c) 2014 Stefan Hengelein <stefan.hengelein@fau.de> | 6 | # (c) 2014 Stefan Hengelein <stefan.hengelein@fau.de> |
7 | # | 7 | # |
8 | # Licensed under the terms of the GNU GPL License version 2 | 8 | # Licensed under the terms of the GNU GPL License version 2 |
9 | 9 | ||
10 | 10 | ||
11 | import argparse | ||
11 | import difflib | 12 | import difflib |
12 | import os | 13 | import os |
13 | import re | 14 | import re |
14 | import signal | 15 | import signal |
16 | import subprocess | ||
15 | import sys | 17 | import sys |
16 | from multiprocessing import Pool, cpu_count | 18 | from multiprocessing import Pool, cpu_count |
17 | from optparse import OptionParser | ||
18 | from subprocess import Popen, PIPE, STDOUT | ||
19 | 19 | ||
20 | 20 | ||
21 | # regex expressions | 21 | # regex expressions |
22 | OPERATORS = r"&|\(|\)|\||\!" | 22 | OPERATORS = r"&|\(|\)|\||\!" |
23 | FEATURE = r"(?:\w*[A-Z0-9]\w*){2,}" | 23 | SYMBOL = r"(?:\w*[A-Z0-9]\w*){2,}" |
24 | DEF = r"^\s*(?:menu){,1}config\s+(" + FEATURE + r")\s*" | 24 | DEF = r"^\s*(?:menu){,1}config\s+(" + SYMBOL + r")\s*" |
25 | EXPR = r"(?:" + OPERATORS + r"|\s|" + FEATURE + r")+" | 25 | EXPR = r"(?:" + OPERATORS + r"|\s|" + SYMBOL + r")+" |
26 | DEFAULT = r"default\s+.*?(?:if\s.+){,1}" | 26 | DEFAULT = r"default\s+.*?(?:if\s.+){,1}" |
27 | STMT = r"^\s*(?:if|select|depends\s+on|(?:" + DEFAULT + r"))\s+" + EXPR | 27 | STMT = r"^\s*(?:if|select|depends\s+on|(?:" + DEFAULT + r"))\s+" + EXPR |
28 | SOURCE_FEATURE = r"(?:\W|\b)+[D]{,1}CONFIG_(" + FEATURE + r")" | 28 | SOURCE_SYMBOL = r"(?:\W|\b)+[D]{,1}CONFIG_(" + SYMBOL + r")" |
29 | 29 | ||
30 | # regex objects | 30 | # regex objects |
31 | REGEX_FILE_KCONFIG = re.compile(r".*Kconfig[\.\w+\-]*$") | 31 | REGEX_FILE_KCONFIG = re.compile(r".*Kconfig[\.\w+\-]*$") |
32 | REGEX_FEATURE = re.compile(r'(?!\B)' + FEATURE + r'(?!\B)') | 32 | REGEX_SYMBOL = re.compile(r'(?!\B)' + SYMBOL + r'(?!\B)') |
33 | REGEX_SOURCE_FEATURE = re.compile(SOURCE_FEATURE) | 33 | REGEX_SOURCE_SYMBOL = re.compile(SOURCE_SYMBOL) |
34 | REGEX_KCONFIG_DEF = re.compile(DEF) | 34 | REGEX_KCONFIG_DEF = re.compile(DEF) |
35 | REGEX_KCONFIG_EXPR = re.compile(EXPR) | 35 | REGEX_KCONFIG_EXPR = re.compile(EXPR) |
36 | REGEX_KCONFIG_STMT = re.compile(STMT) | 36 | REGEX_KCONFIG_STMT = re.compile(STMT) |
37 | REGEX_KCONFIG_HELP = re.compile(r"^\s+(help|---help---)\s*$") | 37 | REGEX_KCONFIG_HELP = re.compile(r"^\s+(help|---help---)\s*$") |
38 | REGEX_FILTER_FEATURES = re.compile(r"[A-Za-z0-9]$") | 38 | REGEX_FILTER_SYMBOLS = re.compile(r"[A-Za-z0-9]$") |
39 | REGEX_NUMERIC = re.compile(r"0[xX][0-9a-fA-F]+|[0-9]+") | 39 | REGEX_NUMERIC = re.compile(r"0[xX][0-9a-fA-F]+|[0-9]+") |
40 | REGEX_QUOTES = re.compile("(\"(.*?)\")") | 40 | REGEX_QUOTES = re.compile("(\"(.*?)\")") |
41 | 41 | ||
42 | 42 | ||
43 | def parse_options(): | 43 | def parse_options(): |
44 | """The user interface of this module.""" | 44 | """The user interface of this module.""" |
45 | usage = "%prog [options]\n\n" \ | 45 | usage = "Run this tool to detect Kconfig symbols that are referenced but " \ |
46 | "Run this tool to detect Kconfig symbols that are referenced but " \ | 46 | "not defined in Kconfig. If no option is specified, " \ |
47 | "not defined in\nKconfig. The output of this tool has the " \ | 47 | "checkkconfigsymbols defaults to check your current tree. " \ |
48 | "format \'Undefined symbol\\tFile list\'\n\n" \ | 48 | "Please note that specifying commits will 'git reset --hard\' " \ |
49 | "If no option is specified, %prog will default to check your\n" \ | 49 | "your current tree! You may save uncommitted changes to avoid " \ |
50 | "current tree. Please note that specifying commits will " \ | 50 | "losing data." |
51 | "\'git reset --hard\'\nyour current tree! You may save " \ | 51 | |
52 | "uncommitted changes to avoid losing data." | 52 | parser = argparse.ArgumentParser(description=usage) |
53 | 53 | ||
54 | parser = OptionParser(usage=usage) | 54 | parser.add_argument('-c', '--commit', dest='commit', action='store', |
55 | 55 | default="", | |
56 | parser.add_option('-c', '--commit', dest='commit', action='store', | 56 | help="check if the specified commit (hash) introduces " |
57 | default="", | 57 | "undefined Kconfig symbols") |
58 | help="Check if the specified commit (hash) introduces " | 58 | |
59 | "undefined Kconfig symbols.") | 59 | parser.add_argument('-d', '--diff', dest='diff', action='store', |
60 | 60 | default="", | |
61 | parser.add_option('-d', '--diff', dest='diff', action='store', | 61 | help="diff undefined symbols between two commits " |
62 | default="", | 62 | "(e.g., -d commmit1..commit2)") |
63 | help="Diff undefined symbols between two commits. The " | 63 | |
64 | "input format bases on Git log's " | 64 | parser.add_argument('-f', '--find', dest='find', action='store_true', |
65 | "\'commmit1..commit2\'.") | 65 | default=False, |
66 | 66 | help="find and show commits that may cause symbols to be " | |
67 | parser.add_option('-f', '--find', dest='find', action='store_true', | 67 | "missing (required to run with --diff)") |
68 | default=False, | 68 | |
69 | help="Find and show commits that may cause symbols to be " | 69 | parser.add_argument('-i', '--ignore', dest='ignore', action='store', |
70 | "missing. Required to run with --diff.") | 70 | default="", |
71 | 71 | help="ignore files matching this Python regex " | |
72 | parser.add_option('-i', '--ignore', dest='ignore', action='store', | 72 | "(e.g., -i '.*defconfig')") |
73 | default="", | 73 | |
74 | help="Ignore files matching this pattern. Note that " | 74 | parser.add_argument('-s', '--sim', dest='sim', action='store', default="", |
75 | "the pattern needs to be a Python regex. To " | 75 | help="print a list of max. 10 string-similar symbols") |
76 | "ignore defconfigs, specify -i '.*defconfig'.") | 76 | |
77 | 77 | parser.add_argument('--force', dest='force', action='store_true', | |
78 | parser.add_option('-s', '--sim', dest='sim', action='store', default="", | 78 | default=False, |
79 | help="Print a list of maximum 10 string-similar symbols.") | 79 | help="reset current Git tree even when it's dirty") |
80 | 80 | ||
81 | parser.add_option('', '--force', dest='force', action='store_true', | 81 | parser.add_argument('--no-color', dest='color', action='store_false', |
82 | default=False, | 82 | default=True, |
83 | help="Reset current Git tree even when it's dirty.") | 83 | help="don't print colored output (default when not " |
84 | 84 | "outputting to a terminal)") | |
85 | (opts, _) = parser.parse_args() | 85 | |
86 | 86 | args = parser.parse_args() | |
87 | if opts.commit and opts.diff: | 87 | |
88 | if args.commit and args.diff: | ||
88 | sys.exit("Please specify only one option at once.") | 89 | sys.exit("Please specify only one option at once.") |
89 | 90 | ||
90 | if opts.diff and not re.match(r"^[\w\-\.]+\.\.[\w\-\.]+$", opts.diff): | 91 | if args.diff and not re.match(r"^[\w\-\.]+\.\.[\w\-\.]+$", args.diff): |
91 | sys.exit("Please specify valid input in the following format: " | 92 | sys.exit("Please specify valid input in the following format: " |
92 | "\'commit1..commit2\'") | 93 | "\'commit1..commit2\'") |
93 | 94 | ||
94 | if opts.commit or opts.diff: | 95 | if args.commit or args.diff: |
95 | if not opts.force and tree_is_dirty(): | 96 | if not args.force and tree_is_dirty(): |
96 | sys.exit("The current Git tree is dirty (see 'git status'). " | 97 | sys.exit("The current Git tree is dirty (see 'git status'). " |
97 | "Running this script may\ndelete important data since it " | 98 | "Running this script may\ndelete important data since it " |
98 | "calls 'git reset --hard' for some performance\nreasons. " | 99 | "calls 'git reset --hard' for some performance\nreasons. " |
@@ -100,138 +101,148 @@ def parse_options(): | |||
100 | "'--force' if you\nwant to ignore this warning and " | 101 | "'--force' if you\nwant to ignore this warning and " |
101 | "continue.") | 102 | "continue.") |
102 | 103 | ||
103 | if opts.commit: | 104 | if args.commit: |
104 | opts.find = False | 105 | args.find = False |
105 | 106 | ||
106 | if opts.ignore: | 107 | if args.ignore: |
107 | try: | 108 | try: |
108 | re.match(opts.ignore, "this/is/just/a/test.c") | 109 | re.match(args.ignore, "this/is/just/a/test.c") |
109 | except: | 110 | except: |
110 | sys.exit("Please specify a valid Python regex.") | 111 | sys.exit("Please specify a valid Python regex.") |
111 | 112 | ||
112 | return opts | 113 | return args |
113 | 114 | ||
114 | 115 | ||
115 | def main(): | 116 | def main(): |
116 | """Main function of this module.""" | 117 | """Main function of this module.""" |
117 | opts = parse_options() | 118 | args = parse_options() |
118 | 119 | ||
119 | if opts.sim and not opts.commit and not opts.diff: | 120 | global COLOR |
120 | sims = find_sims(opts.sim, opts.ignore) | 121 | COLOR = args.color and sys.stdout.isatty() |
122 | |||
123 | if args.sim and not args.commit and not args.diff: | ||
124 | sims = find_sims(args.sim, args.ignore) | ||
121 | if sims: | 125 | if sims: |
122 | print "%s: %s" % (yel("Similar symbols"), ', '.join(sims)) | 126 | print("%s: %s" % (yel("Similar symbols"), ', '.join(sims))) |
123 | else: | 127 | else: |
124 | print "%s: no similar symbols found" % yel("Similar symbols") | 128 | print("%s: no similar symbols found" % yel("Similar symbols")) |
125 | sys.exit(0) | 129 | sys.exit(0) |
126 | 130 | ||
127 | # dictionary of (un)defined symbols | 131 | # dictionary of (un)defined symbols |
128 | defined = {} | 132 | defined = {} |
129 | undefined = {} | 133 | undefined = {} |
130 | 134 | ||
131 | if opts.commit or opts.diff: | 135 | if args.commit or args.diff: |
132 | head = get_head() | 136 | head = get_head() |
133 | 137 | ||
134 | # get commit range | 138 | # get commit range |
135 | commit_a = None | 139 | commit_a = None |
136 | commit_b = None | 140 | commit_b = None |
137 | if opts.commit: | 141 | if args.commit: |
138 | commit_a = opts.commit + "~" | 142 | commit_a = args.commit + "~" |
139 | commit_b = opts.commit | 143 | commit_b = args.commit |
140 | elif opts.diff: | 144 | elif args.diff: |
141 | split = opts.diff.split("..") | 145 | split = args.diff.split("..") |
142 | commit_a = split[0] | 146 | commit_a = split[0] |
143 | commit_b = split[1] | 147 | commit_b = split[1] |
144 | undefined_a = {} | 148 | undefined_a = {} |
145 | undefined_b = {} | 149 | undefined_b = {} |
146 | 150 | ||
147 | # get undefined items before the commit | 151 | # get undefined items before the commit |
148 | execute("git reset --hard %s" % commit_a) | 152 | reset(commit_a) |
149 | undefined_a, _ = check_symbols(opts.ignore) | 153 | undefined_a, _ = check_symbols(args.ignore) |
150 | 154 | ||
151 | # get undefined items for the commit | 155 | # get undefined items for the commit |
152 | execute("git reset --hard %s" % commit_b) | 156 | reset(commit_b) |
153 | undefined_b, defined = check_symbols(opts.ignore) | 157 | undefined_b, defined = check_symbols(args.ignore) |
154 | 158 | ||
155 | # report cases that are present for the commit but not before | 159 | # report cases that are present for the commit but not before |
156 | for feature in sorted(undefined_b): | 160 | for symbol in sorted(undefined_b): |
157 | # feature has not been undefined before | 161 | # symbol has not been undefined before |
158 | if not feature in undefined_a: | 162 | if symbol not in undefined_a: |
159 | files = sorted(undefined_b.get(feature)) | 163 | files = sorted(undefined_b.get(symbol)) |
160 | undefined[feature] = files | 164 | undefined[symbol] = files |
161 | # check if there are new files that reference the undefined feature | 165 | # check if there are new files that reference the undefined symbol |
162 | else: | 166 | else: |
163 | files = sorted(undefined_b.get(feature) - | 167 | files = sorted(undefined_b.get(symbol) - |
164 | undefined_a.get(feature)) | 168 | undefined_a.get(symbol)) |
165 | if files: | 169 | if files: |
166 | undefined[feature] = files | 170 | undefined[symbol] = files |
167 | 171 | ||
168 | # reset to head | 172 | # reset to head |
169 | execute("git reset --hard %s" % head) | 173 | reset(head) |
170 | 174 | ||
171 | # default to check the entire tree | 175 | # default to check the entire tree |
172 | else: | 176 | else: |
173 | undefined, defined = check_symbols(opts.ignore) | 177 | undefined, defined = check_symbols(args.ignore) |
174 | 178 | ||
175 | # now print the output | 179 | # now print the output |
176 | for feature in sorted(undefined): | 180 | for symbol in sorted(undefined): |
177 | print red(feature) | 181 | print(red(symbol)) |
178 | 182 | ||
179 | files = sorted(undefined.get(feature)) | 183 | files = sorted(undefined.get(symbol)) |
180 | print "%s: %s" % (yel("Referencing files"), ", ".join(files)) | 184 | print("%s: %s" % (yel("Referencing files"), ", ".join(files))) |
181 | 185 | ||
182 | sims = find_sims(feature, opts.ignore, defined) | 186 | sims = find_sims(symbol, args.ignore, defined) |
183 | sims_out = yel("Similar symbols") | 187 | sims_out = yel("Similar symbols") |
184 | if sims: | 188 | if sims: |
185 | print "%s: %s" % (sims_out, ', '.join(sims)) | 189 | print("%s: %s" % (sims_out, ', '.join(sims))) |
186 | else: | 190 | else: |
187 | print "%s: %s" % (sims_out, "no similar symbols found") | 191 | print("%s: %s" % (sims_out, "no similar symbols found")) |
188 | 192 | ||
189 | if opts.find: | 193 | if args.find: |
190 | print "%s:" % yel("Commits changing symbol") | 194 | print("%s:" % yel("Commits changing symbol")) |
191 | commits = find_commits(feature, opts.diff) | 195 | commits = find_commits(symbol, args.diff) |
192 | if commits: | 196 | if commits: |
193 | for commit in commits: | 197 | for commit in commits: |
194 | commit = commit.split(" ", 1) | 198 | commit = commit.split(" ", 1) |
195 | print "\t- %s (\"%s\")" % (yel(commit[0]), commit[1]) | 199 | print("\t- %s (\"%s\")" % (yel(commit[0]), commit[1])) |
196 | else: | 200 | else: |
197 | print "\t- no commit found" | 201 | print("\t- no commit found") |
198 | print # new line | 202 | print() # new line |
203 | |||
204 | |||
205 | def reset(commit): | ||
206 | """Reset current git tree to %commit.""" | ||
207 | execute(["git", "reset", "--hard", commit]) | ||
199 | 208 | ||
200 | 209 | ||
201 | def yel(string): | 210 | def yel(string): |
202 | """ | 211 | """ |
203 | Color %string yellow. | 212 | Color %string yellow. |
204 | """ | 213 | """ |
205 | return "\033[33m%s\033[0m" % string | 214 | return "\033[33m%s\033[0m" % string if COLOR else string |
206 | 215 | ||
207 | 216 | ||
208 | def red(string): | 217 | def red(string): |
209 | """ | 218 | """ |
210 | Color %string red. | 219 | Color %string red. |
211 | """ | 220 | """ |
212 | return "\033[31m%s\033[0m" % string | 221 | return "\033[31m%s\033[0m" % string if COLOR else string |
213 | 222 | ||
214 | 223 | ||
215 | def execute(cmd): | 224 | def execute(cmd): |
216 | """Execute %cmd and return stdout. Exit in case of error.""" | 225 | """Execute %cmd and return stdout. Exit in case of error.""" |
217 | pop = Popen(cmd, stdout=PIPE, stderr=STDOUT, shell=True) | 226 | try: |
218 | (stdout, _) = pop.communicate() # wait until finished | 227 | stdout = subprocess.check_output(cmd, stderr=subprocess.STDOUT, shell=False) |
219 | if pop.returncode != 0: | 228 | stdout = stdout.decode(errors='replace') |
220 | sys.exit(stdout) | 229 | except subprocess.CalledProcessError as fail: |
230 | exit(fail) | ||
221 | return stdout | 231 | return stdout |
222 | 232 | ||
223 | 233 | ||
224 | def find_commits(symbol, diff): | 234 | def find_commits(symbol, diff): |
225 | """Find commits changing %symbol in the given range of %diff.""" | 235 | """Find commits changing %symbol in the given range of %diff.""" |
226 | commits = execute("git log --pretty=oneline --abbrev-commit -G %s %s" | 236 | commits = execute(["git", "log", "--pretty=oneline", |
227 | % (symbol, diff)) | 237 | "--abbrev-commit", "-G", |
238 | symbol, diff]) | ||
228 | return [x for x in commits.split("\n") if x] | 239 | return [x for x in commits.split("\n") if x] |
229 | 240 | ||
230 | 241 | ||
231 | def tree_is_dirty(): | 242 | def tree_is_dirty(): |
232 | """Return true if the current working tree is dirty (i.e., if any file has | 243 | """Return true if the current working tree is dirty (i.e., if any file has |
233 | been added, deleted, modified, renamed or copied but not committed).""" | 244 | been added, deleted, modified, renamed or copied but not committed).""" |
234 | stdout = execute("git status --porcelain") | 245 | stdout = execute(["git", "status", "--porcelain"]) |
235 | for line in stdout: | 246 | for line in stdout: |
236 | if re.findall(r"[URMADC]{1}", line[:2]): | 247 | if re.findall(r"[URMADC]{1}", line[:2]): |
237 | return True | 248 | return True |
@@ -240,13 +251,13 @@ def tree_is_dirty(): | |||
240 | 251 | ||
241 | def get_head(): | 252 | def get_head(): |
242 | """Return commit hash of current HEAD.""" | 253 | """Return commit hash of current HEAD.""" |
243 | stdout = execute("git rev-parse HEAD") | 254 | stdout = execute(["git", "rev-parse", "HEAD"]) |
244 | return stdout.strip('\n') | 255 | return stdout.strip('\n') |
245 | 256 | ||
246 | 257 | ||
247 | def partition(lst, size): | 258 | def partition(lst, size): |
248 | """Partition list @lst into eveni-sized lists of size @size.""" | 259 | """Partition list @lst into eveni-sized lists of size @size.""" |
249 | return [lst[i::size] for i in xrange(size)] | 260 | return [lst[i::size] for i in range(size)] |
250 | 261 | ||
251 | 262 | ||
252 | def init_worker(): | 263 | def init_worker(): |
@@ -254,7 +265,7 @@ def init_worker(): | |||
254 | signal.signal(signal.SIGINT, signal.SIG_IGN) | 265 | signal.signal(signal.SIGINT, signal.SIG_IGN) |
255 | 266 | ||
256 | 267 | ||
257 | def find_sims(symbol, ignore, defined = []): | 268 | def find_sims(symbol, ignore, defined=[]): |
258 | """Return a list of max. ten Kconfig symbols that are string-similar to | 269 | """Return a list of max. ten Kconfig symbols that are string-similar to |
259 | @symbol.""" | 270 | @symbol.""" |
260 | if defined: | 271 | if defined: |
@@ -279,7 +290,7 @@ def find_sims(symbol, ignore, defined = []): | |||
279 | def get_files(): | 290 | def get_files(): |
280 | """Return a list of all files in the current git directory.""" | 291 | """Return a list of all files in the current git directory.""" |
281 | # use 'git ls-files' to get the worklist | 292 | # use 'git ls-files' to get the worklist |
282 | stdout = execute("git ls-files") | 293 | stdout = execute(["git", "ls-files"]) |
283 | if len(stdout) > 0 and stdout[-1] == "\n": | 294 | if len(stdout) > 0 and stdout[-1] == "\n": |
284 | stdout = stdout[:-1] | 295 | stdout = stdout[:-1] |
285 | 296 | ||
@@ -311,8 +322,8 @@ def check_symbols_helper(pool, ignore): | |||
311 | check_symbols() in order to properly terminate running worker processes.""" | 322 | check_symbols() in order to properly terminate running worker processes.""" |
312 | source_files = [] | 323 | source_files = [] |
313 | kconfig_files = [] | 324 | kconfig_files = [] |
314 | defined_features = [] | 325 | defined_symbols = [] |
315 | referenced_features = dict() # {file: [features]} | 326 | referenced_symbols = dict() # {file: [symbols]} |
316 | 327 | ||
317 | for gitfile in get_files(): | 328 | for gitfile in get_files(): |
318 | if REGEX_FILE_KCONFIG.match(gitfile): | 329 | if REGEX_FILE_KCONFIG.match(gitfile): |
@@ -326,76 +337,75 @@ def check_symbols_helper(pool, ignore): | |||
326 | # parse source files | 337 | # parse source files |
327 | arglist = partition(source_files, cpu_count()) | 338 | arglist = partition(source_files, cpu_count()) |
328 | for res in pool.map(parse_source_files, arglist): | 339 | for res in pool.map(parse_source_files, arglist): |
329 | referenced_features.update(res) | 340 | referenced_symbols.update(res) |
330 | |||
331 | 341 | ||
332 | # parse kconfig files | 342 | # parse kconfig files |
333 | arglist = [] | 343 | arglist = [] |
334 | for part in partition(kconfig_files, cpu_count()): | 344 | for part in partition(kconfig_files, cpu_count()): |
335 | arglist.append((part, ignore)) | 345 | arglist.append((part, ignore)) |
336 | for res in pool.map(parse_kconfig_files, arglist): | 346 | for res in pool.map(parse_kconfig_files, arglist): |
337 | defined_features.extend(res[0]) | 347 | defined_symbols.extend(res[0]) |
338 | referenced_features.update(res[1]) | 348 | referenced_symbols.update(res[1]) |
339 | defined_features = set(defined_features) | 349 | defined_symbols = set(defined_symbols) |
340 | 350 | ||
341 | # inverse mapping of referenced_features to dict(feature: [files]) | 351 | # inverse mapping of referenced_symbols to dict(symbol: [files]) |
342 | inv_map = dict() | 352 | inv_map = dict() |
343 | for _file, features in referenced_features.iteritems(): | 353 | for _file, symbols in referenced_symbols.items(): |
344 | for feature in features: | 354 | for symbol in symbols: |
345 | inv_map[feature] = inv_map.get(feature, set()) | 355 | inv_map[symbol] = inv_map.get(symbol, set()) |
346 | inv_map[feature].add(_file) | 356 | inv_map[symbol].add(_file) |
347 | referenced_features = inv_map | 357 | referenced_symbols = inv_map |
348 | 358 | ||
349 | undefined = {} # {feature: [files]} | 359 | undefined = {} # {symbol: [files]} |
350 | for feature in sorted(referenced_features): | 360 | for symbol in sorted(referenced_symbols): |
351 | # filter some false positives | 361 | # filter some false positives |
352 | if feature == "FOO" or feature == "BAR" or \ | 362 | if symbol == "FOO" or symbol == "BAR" or \ |
353 | feature == "FOO_BAR" or feature == "XXX": | 363 | symbol == "FOO_BAR" or symbol == "XXX": |
354 | continue | 364 | continue |
355 | if feature not in defined_features: | 365 | if symbol not in defined_symbols: |
356 | if feature.endswith("_MODULE"): | 366 | if symbol.endswith("_MODULE"): |
357 | # avoid false positives for kernel modules | 367 | # avoid false positives for kernel modules |
358 | if feature[:-len("_MODULE")] in defined_features: | 368 | if symbol[:-len("_MODULE")] in defined_symbols: |
359 | continue | 369 | continue |
360 | undefined[feature] = referenced_features.get(feature) | 370 | undefined[symbol] = referenced_symbols.get(symbol) |
361 | return undefined, defined_features | 371 | return undefined, defined_symbols |
362 | 372 | ||
363 | 373 | ||
364 | def parse_source_files(source_files): | 374 | def parse_source_files(source_files): |
365 | """Parse each source file in @source_files and return dictionary with source | 375 | """Parse each source file in @source_files and return dictionary with source |
366 | files as keys and lists of references Kconfig symbols as values.""" | 376 | files as keys and lists of references Kconfig symbols as values.""" |
367 | referenced_features = dict() | 377 | referenced_symbols = dict() |
368 | for sfile in source_files: | 378 | for sfile in source_files: |
369 | referenced_features[sfile] = parse_source_file(sfile) | 379 | referenced_symbols[sfile] = parse_source_file(sfile) |
370 | return referenced_features | 380 | return referenced_symbols |
371 | 381 | ||
372 | 382 | ||
373 | def parse_source_file(sfile): | 383 | def parse_source_file(sfile): |
374 | """Parse @sfile and return a list of referenced Kconfig features.""" | 384 | """Parse @sfile and return a list of referenced Kconfig symbols.""" |
375 | lines = [] | 385 | lines = [] |
376 | references = [] | 386 | references = [] |
377 | 387 | ||
378 | if not os.path.exists(sfile): | 388 | if not os.path.exists(sfile): |
379 | return references | 389 | return references |
380 | 390 | ||
381 | with open(sfile, "r") as stream: | 391 | with open(sfile, "r", encoding='utf-8', errors='replace') as stream: |
382 | lines = stream.readlines() | 392 | lines = stream.readlines() |
383 | 393 | ||
384 | for line in lines: | 394 | for line in lines: |
385 | if not "CONFIG_" in line: | 395 | if "CONFIG_" not in line: |
386 | continue | 396 | continue |
387 | features = REGEX_SOURCE_FEATURE.findall(line) | 397 | symbols = REGEX_SOURCE_SYMBOL.findall(line) |
388 | for feature in features: | 398 | for symbol in symbols: |
389 | if not REGEX_FILTER_FEATURES.search(feature): | 399 | if not REGEX_FILTER_SYMBOLS.search(symbol): |
390 | continue | 400 | continue |
391 | references.append(feature) | 401 | references.append(symbol) |
392 | 402 | ||
393 | return references | 403 | return references |
394 | 404 | ||
395 | 405 | ||
396 | def get_features_in_line(line): | 406 | def get_symbols_in_line(line): |
397 | """Return mentioned Kconfig features in @line.""" | 407 | """Return mentioned Kconfig symbols in @line.""" |
398 | return REGEX_FEATURE.findall(line) | 408 | return REGEX_SYMBOL.findall(line) |
399 | 409 | ||
400 | 410 | ||
401 | def parse_kconfig_files(args): | 411 | def parse_kconfig_files(args): |
@@ -404,21 +414,21 @@ def parse_kconfig_files(args): | |||
404 | pattern.""" | 414 | pattern.""" |
405 | kconfig_files = args[0] | 415 | kconfig_files = args[0] |
406 | ignore = args[1] | 416 | ignore = args[1] |
407 | defined_features = [] | 417 | defined_symbols = [] |
408 | referenced_features = dict() | 418 | referenced_symbols = dict() |
409 | 419 | ||
410 | for kfile in kconfig_files: | 420 | for kfile in kconfig_files: |
411 | defined, references = parse_kconfig_file(kfile) | 421 | defined, references = parse_kconfig_file(kfile) |
412 | defined_features.extend(defined) | 422 | defined_symbols.extend(defined) |
413 | if ignore and re.match(ignore, kfile): | 423 | if ignore and re.match(ignore, kfile): |
414 | # do not collect references for files that match the ignore pattern | 424 | # do not collect references for files that match the ignore pattern |
415 | continue | 425 | continue |
416 | referenced_features[kfile] = references | 426 | referenced_symbols[kfile] = references |
417 | return (defined_features, referenced_features) | 427 | return (defined_symbols, referenced_symbols) |
418 | 428 | ||
419 | 429 | ||
420 | def parse_kconfig_file(kfile): | 430 | def parse_kconfig_file(kfile): |
421 | """Parse @kfile and update feature definitions and references.""" | 431 | """Parse @kfile and update symbol definitions and references.""" |
422 | lines = [] | 432 | lines = [] |
423 | defined = [] | 433 | defined = [] |
424 | references = [] | 434 | references = [] |
@@ -427,7 +437,7 @@ def parse_kconfig_file(kfile): | |||
427 | if not os.path.exists(kfile): | 437 | if not os.path.exists(kfile): |
428 | return defined, references | 438 | return defined, references |
429 | 439 | ||
430 | with open(kfile, "r") as stream: | 440 | with open(kfile, "r", encoding='utf-8', errors='replace') as stream: |
431 | lines = stream.readlines() | 441 | lines = stream.readlines() |
432 | 442 | ||
433 | for i in range(len(lines)): | 443 | for i in range(len(lines)): |
@@ -436,8 +446,8 @@ def parse_kconfig_file(kfile): | |||
436 | line = line.split("#")[0] # ignore comments | 446 | line = line.split("#")[0] # ignore comments |
437 | 447 | ||
438 | if REGEX_KCONFIG_DEF.match(line): | 448 | if REGEX_KCONFIG_DEF.match(line): |
439 | feature_def = REGEX_KCONFIG_DEF.findall(line) | 449 | symbol_def = REGEX_KCONFIG_DEF.findall(line) |
440 | defined.append(feature_def[0]) | 450 | defined.append(symbol_def[0]) |
441 | skip = False | 451 | skip = False |
442 | elif REGEX_KCONFIG_HELP.match(line): | 452 | elif REGEX_KCONFIG_HELP.match(line): |
443 | skip = True | 453 | skip = True |
@@ -446,18 +456,18 @@ def parse_kconfig_file(kfile): | |||
446 | pass | 456 | pass |
447 | elif REGEX_KCONFIG_STMT.match(line): | 457 | elif REGEX_KCONFIG_STMT.match(line): |
448 | line = REGEX_QUOTES.sub("", line) | 458 | line = REGEX_QUOTES.sub("", line) |
449 | features = get_features_in_line(line) | 459 | symbols = get_symbols_in_line(line) |
450 | # multi-line statements | 460 | # multi-line statements |
451 | while line.endswith("\\"): | 461 | while line.endswith("\\"): |
452 | i += 1 | 462 | i += 1 |
453 | line = lines[i] | 463 | line = lines[i] |
454 | line = line.strip('\n') | 464 | line = line.strip('\n') |
455 | features.extend(get_features_in_line(line)) | 465 | symbols.extend(get_symbols_in_line(line)) |
456 | for feature in set(features): | 466 | for symbol in set(symbols): |
457 | if REGEX_NUMERIC.match(feature): | 467 | if REGEX_NUMERIC.match(symbol): |
458 | # ignore numeric values | 468 | # ignore numeric values |
459 | continue | 469 | continue |
460 | references.append(feature) | 470 | references.append(symbol) |
461 | 471 | ||
462 | return defined, references | 472 | return defined, references |
463 | 473 | ||
diff --git a/scripts/ver_linux b/scripts/ver_linux index 0d8bd29b1bd6..430b201f3e25 100755 --- a/scripts/ver_linux +++ b/scripts/ver_linux | |||
@@ -1,193 +1,89 @@ | |||
1 | #!/bin/sh | 1 | #!/bin/awk -f |
2 | # Before running this script please ensure that your PATH is | 2 | # Before running this script please ensure that your PATH is |
3 | # typical as you use for compilation/installation. I use | 3 | # typical as you use for compilation/installation. I use |
4 | # /bin /sbin /usr/bin /usr/sbin /usr/local/bin, but it may | 4 | # /bin /sbin /usr/bin /usr/sbin /usr/local/bin, but it may |
5 | # differ on your system. | 5 | # differ on your system. |
6 | # | ||
7 | echo 'If some fields are empty or look unusual you may have an old version.' | ||
8 | echo 'Compare to the current minimal requirements in Documentation/Changes.' | ||
9 | echo ' ' | ||
10 | 6 | ||
11 | uname -a | 7 | BEGIN { |
12 | echo ' ' | 8 | usage = "If some fields are empty or look unusual you may have an old version.\n" |
13 | 9 | usage = usage "Compare to the current minimal requirements in Documentation/Changes.\n" | |
14 | gcc -dumpversion 2>&1 | | 10 | print usage |
15 | awk '/[0-9]+([.]?[0-9]+)+/ && !/not found$/{ | 11 | |
16 | match($0, /[0-9]+([.]?[0-9]+)+/) | 12 | system("uname -a") |
17 | printf("GNU C\t\t\t%s\n", | 13 | printf("\n") |
18 | substr($0,RSTART,RLENGTH)) | 14 | |
19 | }' | 15 | printversion("GNU C", version("gcc -dumpversion 2>&1")) |
20 | 16 | printversion("GNU Make", version("make --version 2>&1")) | |
21 | make --version 2>&1 | | 17 | printversion("Binutils", version("ld -v 2>&1")) |
22 | awk '/GNU Make/{ | 18 | printversion("Util-linux", version("mount --version 2>&1")) |
23 | match($0, /[0-9]+([.]?[0-9]+)+/) | 19 | printversion("Mount", version("mount --version 2>&1")) |
24 | printf("GNU Make\t\t%s\n", | 20 | printversion("Module-init-tools", version("depmod -V 2>&1")) |
25 | substr($0,RSTART,RLENGTH)) | 21 | printversion("E2fsprogs", version("tune2fs 2>&1")) |
26 | }' | 22 | printversion("Jfsutils", version("fsck.jfs -V 2>&1")) |
27 | 23 | printversion("Reiserfsprogs", version("reiserfsck -V 2>&1")) | |
28 | ld -v 2>&1 | | 24 | printversion("Reiser4fsprogs", version("fsck.reiser4 -V 2>&1")) |
29 | awk '/[0-9]+([.]?[0-9]+)+/ && !/not found$/{ | 25 | printversion("Xfsprogs", version("xfs_db -V 2>&1")) |
30 | match($0, /[0-9]+([.]?[0-9]+)+/) | 26 | printversion("Pcmciautils", version("pccardctl -V 2>&1")) |
31 | printf("Binutils\t\t%s\n", | 27 | printversion("Pcmcia-cs", version("cardmgr -V 2>&1")) |
32 | substr($0,RSTART,RLENGTH)) | 28 | printversion("Quota-tools", version("quota -V 2>&1")) |
33 | }' | 29 | printversion("PPP", version("pppd --version 2>&1")) |
34 | 30 | printversion("Isdn4k-utils", version("isdnctrl 2>&1")) | |
35 | mount --version 2>&1 | | 31 | printversion("Nfs-utils", version("showmount --version 2>&1")) |
36 | awk '/[0-9]+([.]?[0-9]+)+/ && !/not found$/{ | 32 | |
37 | match($0, /[0-9]+([.]?[0-9]+)+/) | 33 | if (system("test -r /proc/self/maps") == 0) { |
38 | $0 = substr($0,RSTART,RLENGTH) | 34 | while (getline <"/proc/self/maps" > 0) { |
39 | printf("Util-linux\t\t%s\nMount\t\t\t%s\n",$0,$0) | 35 | n = split($0, procmaps, "/") |
40 | }' | 36 | if (/libc.*so$/ && match(procmaps[n], /[0-9]+([.]?[0-9]+)+/)) { |
41 | 37 | ver = substr(procmaps[n], RSTART, RLENGTH) | |
42 | depmod -V 2>&1 | | 38 | printversion("Linux C Library", ver) |
43 | awk '/[0-9]+([.]?[0-9]+)+/ && !/not found$/{ | 39 | break |
44 | match($0, /[0-9]+([.]?[0-9]+)+/) | 40 | } |
45 | printf("Module-init-tools\t%s\n", | 41 | } |
46 | substr($0,RSTART,RLENGTH)) | ||
47 | }' | ||
48 | |||
49 | tune2fs 2>&1 | | ||
50 | awk '/^tune2fs/{ | ||
51 | match($0, /[0-9]+([.]?[0-9]+)+/) | ||
52 | printf("E2fsprogs\t\t%s\n", | ||
53 | substr($0,RSTART,RLENGTH)) | ||
54 | }' | ||
55 | |||
56 | fsck.jfs -V 2>&1 | | ||
57 | awk '/version/{ | ||
58 | match($0, /[0-9]+([.]?[0-9]+)+/) | ||
59 | printf("Jfsutils\t\t%s\n", | ||
60 | substr($0,RSTART,RLENGTH)) | ||
61 | }' | ||
62 | |||
63 | reiserfsck -V 2>&1 | | ||
64 | awk '/^reiserfsck/{ | ||
65 | match($0, /[0-9]+([.]?[0-9]+)+/) | ||
66 | printf("Reiserfsprogs\t\t%s\n", | ||
67 | substr($0,RSTART,RLENGTH)) | ||
68 | }' | ||
69 | |||
70 | fsck.reiser4 -V 2>&1 | grep ^fsck.reiser4 | awk \ | ||
71 | 'NR==1{print "reiser4progs ", $2}' | ||
72 | |||
73 | xfs_db -V 2>&1 | | ||
74 | awk '/version/{ | ||
75 | match($0, /[0-9]+([.]?[0-9]+)+/) | ||
76 | printf("Xfsprogs\t\t%s\n", | ||
77 | substr($0,RSTART,RLENGTH)) | ||
78 | }' | ||
79 | |||
80 | pccardctl -V 2>&1 | | ||
81 | awk '/pcmciautils/{ | ||
82 | match($0, /[0-9]+([.]?[0-9]+)+/) | ||
83 | printf("Pcmciautils\t\t%s\n", | ||
84 | substr($0,RSTART,RLENGTH)) | ||
85 | }' | ||
86 | |||
87 | cardmgr -V 2>&1| grep version | awk \ | ||
88 | 'NR==1{print "pcmcia-cs ", $3}' | ||
89 | |||
90 | quota -V 2>&1 | | ||
91 | awk '/version/{ | ||
92 | match($0, /[0-9]+([.]?[0-9]+)+/) | ||
93 | printf("Quota-tools\t\t%s\n", | ||
94 | substr($0,RSTART,RLENGTH)) | ||
95 | }' | ||
96 | |||
97 | pppd --version 2>&1 | | ||
98 | awk '/version/{ | ||
99 | match($0, /[0-9]+([.]?[0-9]+)+/) | ||
100 | printf("PPP\t\t\t%s\n", | ||
101 | substr($0,RSTART,RLENGTH)) | ||
102 | }' | ||
103 | |||
104 | isdnctrl 2>&1 | grep version | awk \ | ||
105 | 'NR==1{print "isdn4k-utils ", $NF}' | ||
106 | |||
107 | showmount --version 2>&1 | grep nfs-utils | awk \ | ||
108 | 'NR==1{print "nfs-utils ", $NF}' | ||
109 | |||
110 | test -r /proc/self/maps && | ||
111 | sed ' | ||
112 | /.*libc-\(.*\)\.so$/!d | ||
113 | s//Linux C Library\t\t\1/ | ||
114 | q | ||
115 | ' /proc/self/maps | ||
116 | |||
117 | ldd --version 2>&1 | | ||
118 | awk '/^ldd/{ | ||
119 | match($0, /[0-9]+([.]?[0-9]+)+/) | ||
120 | printf("Dynamic linker (ldd)\t%s\n", | ||
121 | substr($0,RSTART,RLENGTH)) | ||
122 | }' | ||
123 | |||
124 | libcpp=`ldconfig -p 2>/dev/null | | ||
125 | awk '/(libg|stdc)[+]+\.so/ { | ||
126 | print $NF | ||
127 | exit | ||
128 | } | 42 | } |
129 | '` | ||
130 | test -r "$libcpp" && | ||
131 | ls -l $libcpp | | ||
132 | sed ' | ||
133 | s!.*so\.!! | ||
134 | s!^!Linux C++ Library\t! | ||
135 | ' | ||
136 | ps --version 2>&1 | | ||
137 | awk '/version/{ | ||
138 | match($0, /[0-9]+([.]?[0-9]+)+/) | ||
139 | printf("Procps\t\t\t%s\n", | ||
140 | substr($0,RSTART,RLENGTH)) | ||
141 | }' | ||
142 | |||
143 | ifconfig --version 2>&1 | | ||
144 | awk '/tools/{ | ||
145 | match($0, /[0-9]+([.]?[0-9]+)+/) | ||
146 | printf("Net-tools\t\t%s\n", | ||
147 | substr($0,RSTART,RLENGTH)) | ||
148 | }' | ||
149 | |||
150 | loadkeys -V 2>&1 | | ||
151 | awk '/[0-9]+([.]?[0-9]+)+/ && !/not found$/{ | ||
152 | match($0, /[0-9]+([.]?[0-9]+)+/) | ||
153 | $0 = substr($0,RSTART,RLENGTH) | ||
154 | printf("Kbd\t\t\t%s\nConsole-tools\t\t%s\n",$0,$0) | ||
155 | }' | ||
156 | 43 | ||
157 | oprofiled --version 2>&1 | awk \ | 44 | printversion("Dynamic linker (ldd)", version("ldd --version 2>&1")) |
158 | '(NR==1 && ($2 == "oprofile")) {print "oprofile ", $3}' | ||
159 | 45 | ||
160 | expr --v 2>&1 | | 46 | while ("ldconfig -p 2>/dev/null" | getline > 0) { |
161 | awk '/^expr/{ | 47 | if (/(libg|stdc)[+]+\.so/) { |
162 | match($0, /[0-9]+([.]?[0-9]+)+/) | 48 | libcpp = $NF |
163 | printf("Sh-utils\t\t%s\n", | 49 | break |
164 | substr($0,RSTART,RLENGTH)) | 50 | } |
165 | }' | 51 | } |
166 | 52 | if (system("test -r " libcpp) == 0) | |
167 | udevadm --version 2>&1 | | 53 | printversion("Linux C++ Library", version("readlink " libcpp)) |
168 | awk '/[0-9]+([.]?[0-9]+)+/ && !/not found$/{ | 54 | |
169 | match($0, /[0-9]+([.]?[0-9]+)+/) | 55 | printversion("Procps", version("ps --version 2>&1")) |
170 | printf("Udev\t\t\t%s\n", | 56 | printversion("Net-tools", version("ifconfig --version 2>&1")) |
171 | substr($0,RSTART,RLENGTH)) | 57 | printversion("Kbd", version("loadkeys -V 2>&1")) |
172 | }' | 58 | printversion("Console-tools", version("loadkeys -V 2>&1")) |
59 | printversion("Oprofile", version("oprofiled --version 2>&1")) | ||
60 | printversion("Sh-utils", version("expr --v 2>&1")) | ||
61 | printversion("Udev", version("udevadm --version 2>&1")) | ||
62 | printversion("Wireless-tools", version("iwconfig --version 2>&1")) | ||
63 | |||
64 | if (system("test -r /proc/modules") == 0) { | ||
65 | while ("sort /proc/modules" | getline > 0) { | ||
66 | mods = mods sep $1 | ||
67 | sep = " " | ||
68 | } | ||
69 | printversion("Modules Loaded", mods) | ||
70 | } | ||
71 | } | ||
173 | 72 | ||
174 | iwconfig --version 2>&1 | | 73 | function version(cmd, ver) { |
175 | awk '/version/{ | 74 | while (cmd | getline > 0) { |
176 | match($0, /[0-9]+([.]?[0-9]+)+/) | 75 | if (!/ver_linux/ && match($0, /[0-9]+([.]?[0-9]+)+/)) { |
177 | printf("Wireless-tools\t\t%s\n", | 76 | ver = substr($0, RSTART, RLENGTH) |
178 | substr($0,RSTART,RLENGTH)) | 77 | break |
179 | }' | 78 | } |
79 | } | ||
80 | close(cmd) | ||
81 | return ver | ||
82 | } | ||
180 | 83 | ||
181 | test -e /proc/modules && | 84 | function printversion(name, value, ofmt) { |
182 | sort /proc/modules | | 85 | if (value != "") { |
183 | sed ' | 86 | ofmt = "%-20s\t%s\n" |
184 | s/ .*// | 87 | printf(ofmt, name, value) |
185 | H | 88 | } |
186 | ${ | ||
187 | g | ||
188 | s/^\n/Modules Loaded\t\t/ | ||
189 | y/\n/ / | ||
190 | q | ||
191 | } | 89 | } |
192 | d | ||
193 | ' | ||
diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c index 0d9f48ec42bb..bc7adb84e679 100644 --- a/tools/hv/hv_kvp_daemon.c +++ b/tools/hv/hv_kvp_daemon.c | |||
@@ -1433,7 +1433,7 @@ int main(int argc, char *argv[]) | |||
1433 | openlog("KVP", 0, LOG_USER); | 1433 | openlog("KVP", 0, LOG_USER); |
1434 | syslog(LOG_INFO, "KVP starting; pid is:%d", getpid()); | 1434 | syslog(LOG_INFO, "KVP starting; pid is:%d", getpid()); |
1435 | 1435 | ||
1436 | kvp_fd = open("/dev/vmbus/hv_kvp", O_RDWR); | 1436 | kvp_fd = open("/dev/vmbus/hv_kvp", O_RDWR | O_CLOEXEC); |
1437 | 1437 | ||
1438 | if (kvp_fd < 0) { | 1438 | if (kvp_fd < 0) { |
1439 | syslog(LOG_ERR, "open /dev/vmbus/hv_kvp failed; error: %d %s", | 1439 | syslog(LOG_ERR, "open /dev/vmbus/hv_kvp failed; error: %d %s", |
diff --git a/tools/hv/hv_vss_daemon.c b/tools/hv/hv_vss_daemon.c index 5d51d6ff08e6..e0829809c897 100644 --- a/tools/hv/hv_vss_daemon.c +++ b/tools/hv/hv_vss_daemon.c | |||
@@ -250,6 +250,9 @@ int main(int argc, char *argv[]) | |||
250 | syslog(LOG_ERR, "/etc/fstab and /proc/mounts"); | 250 | syslog(LOG_ERR, "/etc/fstab and /proc/mounts"); |
251 | } | 251 | } |
252 | break; | 252 | break; |
253 | case VSS_OP_HOT_BACKUP: | ||
254 | syslog(LOG_INFO, "VSS: op=CHECK HOT BACKUP\n"); | ||
255 | break; | ||
253 | default: | 256 | default: |
254 | syslog(LOG_ERR, "Illegal op:%d\n", op); | 257 | syslog(LOG_ERR, "Illegal op:%d\n", op); |
255 | } | 258 | } |