diff options
132 files changed, 8981 insertions, 1234 deletions
diff --git a/Documentation/ABI/stable/sysfs-bus-vmbus b/Documentation/ABI/stable/sysfs-bus-vmbus index 0c9d9dcd2151..3eaffbb2d468 100644 --- a/Documentation/ABI/stable/sysfs-bus-vmbus +++ b/Documentation/ABI/stable/sysfs-bus-vmbus | |||
@@ -1,25 +1,25 @@ | |||
1 | What: /sys/bus/vmbus/devices/vmbus_*/id | 1 | What: /sys/bus/vmbus/devices/<UUID>/id |
2 | Date: Jul 2009 | 2 | Date: Jul 2009 |
3 | KernelVersion: 2.6.31 | 3 | KernelVersion: 2.6.31 |
4 | Contact: K. Y. Srinivasan <kys@microsoft.com> | 4 | Contact: K. Y. Srinivasan <kys@microsoft.com> |
5 | Description: The VMBus child_relid of the device's primary channel | 5 | Description: The VMBus child_relid of the device's primary channel |
6 | Users: tools/hv/lsvmbus | 6 | Users: tools/hv/lsvmbus |
7 | 7 | ||
8 | What: /sys/bus/vmbus/devices/vmbus_*/class_id | 8 | What: /sys/bus/vmbus/devices/<UUID>/class_id |
9 | Date: Jul 2009 | 9 | Date: Jul 2009 |
10 | KernelVersion: 2.6.31 | 10 | KernelVersion: 2.6.31 |
11 | Contact: K. Y. Srinivasan <kys@microsoft.com> | 11 | Contact: K. Y. Srinivasan <kys@microsoft.com> |
12 | Description: The VMBus interface type GUID of the device | 12 | Description: The VMBus interface type GUID of the device |
13 | Users: tools/hv/lsvmbus | 13 | Users: tools/hv/lsvmbus |
14 | 14 | ||
15 | What: /sys/bus/vmbus/devices/vmbus_*/device_id | 15 | What: /sys/bus/vmbus/devices/<UUID>/device_id |
16 | Date: Jul 2009 | 16 | Date: Jul 2009 |
17 | KernelVersion: 2.6.31 | 17 | KernelVersion: 2.6.31 |
18 | Contact: K. Y. Srinivasan <kys@microsoft.com> | 18 | Contact: K. Y. Srinivasan <kys@microsoft.com> |
19 | Description: The VMBus interface instance GUID of the device | 19 | Description: The VMBus interface instance GUID of the device |
20 | Users: tools/hv/lsvmbus | 20 | Users: tools/hv/lsvmbus |
21 | 21 | ||
22 | What: /sys/bus/vmbus/devices/vmbus_*/channel_vp_mapping | 22 | What: /sys/bus/vmbus/devices/<UUID>/channel_vp_mapping |
23 | Date: Jul 2015 | 23 | Date: Jul 2015 |
24 | KernelVersion: 4.2.0 | 24 | KernelVersion: 4.2.0 |
25 | Contact: K. Y. Srinivasan <kys@microsoft.com> | 25 | Contact: K. Y. Srinivasan <kys@microsoft.com> |
@@ -28,112 +28,112 @@ Description: The mapping of which primary/sub channels are bound to which | |||
28 | Format: <channel's child_relid:the bound cpu's number> | 28 | Format: <channel's child_relid:the bound cpu's number> |
29 | Users: tools/hv/lsvmbus | 29 | Users: tools/hv/lsvmbus |
30 | 30 | ||
31 | What: /sys/bus/vmbus/devices/vmbus_*/device | 31 | What: /sys/bus/vmbus/devices/<UUID>/device |
32 | Date: Dec. 2015 | 32 | Date: Dec. 2015 |
33 | KernelVersion: 4.5 | 33 | KernelVersion: 4.5 |
34 | Contact: K. Y. Srinivasan <kys@microsoft.com> | 34 | Contact: K. Y. Srinivasan <kys@microsoft.com> |
35 | Description: The 16 bit device ID of the device | 35 | Description: The 16 bit device ID of the device |
36 | Users: tools/hv/lsvmbus and user level RDMA libraries | 36 | Users: tools/hv/lsvmbus and user level RDMA libraries |
37 | 37 | ||
38 | What: /sys/bus/vmbus/devices/vmbus_*/vendor | 38 | What: /sys/bus/vmbus/devices/<UUID>/vendor |
39 | Date: Dec. 2015 | 39 | Date: Dec. 2015 |
40 | KernelVersion: 4.5 | 40 | KernelVersion: 4.5 |
41 | Contact: K. Y. Srinivasan <kys@microsoft.com> | 41 | Contact: K. Y. Srinivasan <kys@microsoft.com> |
42 | Description: The 16 bit vendor ID of the device | 42 | Description: The 16 bit vendor ID of the device |
43 | Users: tools/hv/lsvmbus and user level RDMA libraries | 43 | Users: tools/hv/lsvmbus and user level RDMA libraries |
44 | 44 | ||
45 | What: /sys/bus/vmbus/devices/vmbus_*/channels/NN | 45 | What: /sys/bus/vmbus/devices/<UUID>/channels/<N> |
46 | Date: September. 2017 | 46 | Date: September. 2017 |
47 | KernelVersion: 4.14 | 47 | KernelVersion: 4.14 |
48 | Contact: Stephen Hemminger <sthemmin@microsoft.com> | 48 | Contact: Stephen Hemminger <sthemmin@microsoft.com> |
49 | Description: Directory for per-channel information | 49 | Description: Directory for per-channel information |
50 | NN is the VMBUS relid associtated with the channel. | 50 | NN is the VMBUS relid associtated with the channel. |
51 | 51 | ||
52 | What: /sys/bus/vmbus/devices/vmbus_*/channels/NN/cpu | 52 | What: /sys/bus/vmbus/devices/<UUID>/channels/<N>/cpu |
53 | Date: September. 2017 | 53 | Date: September. 2017 |
54 | KernelVersion: 4.14 | 54 | KernelVersion: 4.14 |
55 | Contact: Stephen Hemminger <sthemmin@microsoft.com> | 55 | Contact: Stephen Hemminger <sthemmin@microsoft.com> |
56 | Description: VCPU (sub)channel is affinitized to | 56 | Description: VCPU (sub)channel is affinitized to |
57 | Users: tools/hv/lsvmbus and other debugging tools | 57 | Users: tools/hv/lsvmbus and other debugging tools |
58 | 58 | ||
59 | What: /sys/bus/vmbus/devices/vmbus_*/channels/NN/cpu | 59 | What: /sys/bus/vmbus/devices/<UUID>/channels/<N>/cpu |
60 | Date: September. 2017 | 60 | Date: September. 2017 |
61 | KernelVersion: 4.14 | 61 | KernelVersion: 4.14 |
62 | Contact: Stephen Hemminger <sthemmin@microsoft.com> | 62 | Contact: Stephen Hemminger <sthemmin@microsoft.com> |
63 | Description: VCPU (sub)channel is affinitized to | 63 | Description: VCPU (sub)channel is affinitized to |
64 | Users: tools/hv/lsvmbus and other debugging tools | 64 | Users: tools/hv/lsvmbus and other debugging tools |
65 | 65 | ||
66 | What: /sys/bus/vmbus/devices/vmbus_*/channels/NN/in_mask | 66 | What: /sys/bus/vmbus/devices/<UUID>/channels/<N>/in_mask |
67 | Date: September. 2017 | 67 | Date: September. 2017 |
68 | KernelVersion: 4.14 | 68 | KernelVersion: 4.14 |
69 | Contact: Stephen Hemminger <sthemmin@microsoft.com> | 69 | Contact: Stephen Hemminger <sthemmin@microsoft.com> |
70 | Description: Host to guest channel interrupt mask | 70 | Description: Host to guest channel interrupt mask |
71 | Users: Debugging tools | 71 | Users: Debugging tools |
72 | 72 | ||
73 | What: /sys/bus/vmbus/devices/vmbus_*/channels/NN/latency | 73 | What: /sys/bus/vmbus/devices/<UUID>/channels/<N>/latency |
74 | Date: September. 2017 | 74 | Date: September. 2017 |
75 | KernelVersion: 4.14 | 75 | KernelVersion: 4.14 |
76 | Contact: Stephen Hemminger <sthemmin@microsoft.com> | 76 | Contact: Stephen Hemminger <sthemmin@microsoft.com> |
77 | Description: Channel signaling latency | 77 | Description: Channel signaling latency |
78 | Users: Debugging tools | 78 | Users: Debugging tools |
79 | 79 | ||
80 | What: /sys/bus/vmbus/devices/vmbus_*/channels/NN/out_mask | 80 | What: /sys/bus/vmbus/devices/<UUID>/channels/<N>/out_mask |
81 | Date: September. 2017 | 81 | Date: September. 2017 |
82 | KernelVersion: 4.14 | 82 | KernelVersion: 4.14 |
83 | Contact: Stephen Hemminger <sthemmin@microsoft.com> | 83 | Contact: Stephen Hemminger <sthemmin@microsoft.com> |
84 | Description: Guest to host channel interrupt mask | 84 | Description: Guest to host channel interrupt mask |
85 | Users: Debugging tools | 85 | Users: Debugging tools |
86 | 86 | ||
87 | What: /sys/bus/vmbus/devices/vmbus_*/channels/NN/pending | 87 | What: /sys/bus/vmbus/devices/<UUID>/channels/<N>/pending |
88 | Date: September. 2017 | 88 | Date: September. 2017 |
89 | KernelVersion: 4.14 | 89 | KernelVersion: 4.14 |
90 | Contact: Stephen Hemminger <sthemmin@microsoft.com> | 90 | Contact: Stephen Hemminger <sthemmin@microsoft.com> |
91 | Description: Channel interrupt pending state | 91 | Description: Channel interrupt pending state |
92 | Users: Debugging tools | 92 | Users: Debugging tools |
93 | 93 | ||
94 | What: /sys/bus/vmbus/devices/vmbus_*/channels/NN/read_avail | 94 | What: /sys/bus/vmbus/devices/<UUID>/channels/<N>/read_avail |
95 | Date: September. 2017 | 95 | Date: September. 2017 |
96 | KernelVersion: 4.14 | 96 | KernelVersion: 4.14 |
97 | Contact: Stephen Hemminger <sthemmin@microsoft.com> | 97 | Contact: Stephen Hemminger <sthemmin@microsoft.com> |
98 | Description: Bytes available to read | 98 | Description: Bytes available to read |
99 | Users: Debugging tools | 99 | Users: Debugging tools |
100 | 100 | ||
101 | What: /sys/bus/vmbus/devices/vmbus_*/channels/NN/write_avail | 101 | What: /sys/bus/vmbus/devices/<UUID>/channels/<N>/write_avail |
102 | Date: September. 2017 | 102 | Date: September. 2017 |
103 | KernelVersion: 4.14 | 103 | KernelVersion: 4.14 |
104 | Contact: Stephen Hemminger <sthemmin@microsoft.com> | 104 | Contact: Stephen Hemminger <sthemmin@microsoft.com> |
105 | Description: Bytes available to write | 105 | Description: Bytes available to write |
106 | Users: Debugging tools | 106 | Users: Debugging tools |
107 | 107 | ||
108 | What: /sys/bus/vmbus/devices/vmbus_*/channels/NN/events | 108 | What: /sys/bus/vmbus/devices/<UUID>/channels/<N>/events |
109 | Date: September. 2017 | 109 | Date: September. 2017 |
110 | KernelVersion: 4.14 | 110 | KernelVersion: 4.14 |
111 | Contact: Stephen Hemminger <sthemmin@microsoft.com> | 111 | Contact: Stephen Hemminger <sthemmin@microsoft.com> |
112 | Description: Number of times we have signaled the host | 112 | Description: Number of times we have signaled the host |
113 | Users: Debugging tools | 113 | Users: Debugging tools |
114 | 114 | ||
115 | What: /sys/bus/vmbus/devices/vmbus_*/channels/NN/interrupts | 115 | What: /sys/bus/vmbus/devices/<UUID>/channels/<N>/interrupts |
116 | Date: September. 2017 | 116 | Date: September. 2017 |
117 | KernelVersion: 4.14 | 117 | KernelVersion: 4.14 |
118 | Contact: Stephen Hemminger <sthemmin@microsoft.com> | 118 | Contact: Stephen Hemminger <sthemmin@microsoft.com> |
119 | Description: Number of times we have taken an interrupt (incoming) | 119 | Description: Number of times we have taken an interrupt (incoming) |
120 | Users: Debugging tools | 120 | Users: Debugging tools |
121 | 121 | ||
122 | What: /sys/bus/vmbus/devices/vmbus_*/channels/NN/subchannel_id | 122 | What: /sys/bus/vmbus/devices/<UUID>/channels/<N>/subchannel_id |
123 | Date: January. 2018 | 123 | Date: January. 2018 |
124 | KernelVersion: 4.16 | 124 | KernelVersion: 4.16 |
125 | Contact: Stephen Hemminger <sthemmin@microsoft.com> | 125 | Contact: Stephen Hemminger <sthemmin@microsoft.com> |
126 | Description: Subchannel ID associated with VMBUS channel | 126 | Description: Subchannel ID associated with VMBUS channel |
127 | Users: Debugging tools and userspace drivers | 127 | Users: Debugging tools and userspace drivers |
128 | 128 | ||
129 | What: /sys/bus/vmbus/devices/vmbus_*/channels/NN/monitor_id | 129 | What: /sys/bus/vmbus/devices/<UUID>/channels/<N>/monitor_id |
130 | Date: January. 2018 | 130 | Date: January. 2018 |
131 | KernelVersion: 4.16 | 131 | KernelVersion: 4.16 |
132 | Contact: Stephen Hemminger <sthemmin@microsoft.com> | 132 | Contact: Stephen Hemminger <sthemmin@microsoft.com> |
133 | Description: Monitor bit associated with channel | 133 | Description: Monitor bit associated with channel |
134 | Users: Debugging tools and userspace drivers | 134 | Users: Debugging tools and userspace drivers |
135 | 135 | ||
136 | What: /sys/bus/vmbus/devices/vmbus_*/channels/NN/ring | 136 | What: /sys/bus/vmbus/devices/<UUID>/channels/<N>/ring |
137 | Date: January. 2018 | 137 | Date: January. 2018 |
138 | KernelVersion: 4.16 | 138 | KernelVersion: 4.16 |
139 | Contact: Stephen Hemminger <sthemmin@microsoft.com> | 139 | Contact: Stephen Hemminger <sthemmin@microsoft.com> |
diff --git a/Documentation/devicetree/bindings/fpga/lattice-machxo2-spi.txt b/Documentation/devicetree/bindings/fpga/lattice-machxo2-spi.txt new file mode 100644 index 000000000000..a8c362eb160c --- /dev/null +++ b/Documentation/devicetree/bindings/fpga/lattice-machxo2-spi.txt | |||
@@ -0,0 +1,29 @@ | |||
1 | Lattice MachXO2 Slave SPI FPGA Manager | ||
2 | |||
3 | Lattice MachXO2 FPGAs support a method of loading the bitstream over | ||
4 | 'slave SPI' interface. | ||
5 | |||
6 | See 'MachXO2ProgrammingandConfigurationUsageGuide.pdf' on www.latticesemi.com | ||
7 | |||
8 | Required properties: | ||
9 | - compatible: should contain "lattice,machxo2-slave-spi" | ||
10 | - reg: spi chip select of the FPGA | ||
11 | |||
12 | Example for full FPGA configuration: | ||
13 | |||
14 | fpga-region0 { | ||
15 | compatible = "fpga-region"; | ||
16 | fpga-mgr = <&fpga_mgr_spi>; | ||
17 | #address-cells = <0x1>; | ||
18 | #size-cells = <0x1>; | ||
19 | }; | ||
20 | |||
21 | spi1: spi@2000 { | ||
22 | ... | ||
23 | |||
24 | fpga_mgr_spi: fpga-mgr@0 { | ||
25 | compatible = "lattice,machxo2-slave-spi"; | ||
26 | spi-max-frequency = <8000000>; | ||
27 | reg = <0>; | ||
28 | }; | ||
29 | }; | ||
diff --git a/Documentation/devicetree/bindings/nvmem/zii,rave-sp-eeprom.txt b/Documentation/devicetree/bindings/nvmem/zii,rave-sp-eeprom.txt new file mode 100644 index 000000000000..d5e22fc67d66 --- /dev/null +++ b/Documentation/devicetree/bindings/nvmem/zii,rave-sp-eeprom.txt | |||
@@ -0,0 +1,40 @@ | |||
1 | Zodiac Inflight Innovations RAVE EEPROM Bindings | ||
2 | |||
3 | RAVE SP EEPROM device is a "MFD cell" device exposing physical EEPROM | ||
4 | attached to RAVE Supervisory Processor. It is expected that its Device | ||
5 | Tree node is specified as a child of the node corresponding to the | ||
6 | parent RAVE SP device (as documented in | ||
7 | Documentation/devicetree/bindings/mfd/zii,rave-sp.txt) | ||
8 | |||
9 | Required properties: | ||
10 | |||
11 | - compatible: Should be "zii,rave-sp-eeprom" | ||
12 | |||
13 | Optional properties: | ||
14 | |||
15 | - zii,eeprom-name: Unique EEPROM identifier describing its function in the | ||
16 | system. Will be used as created NVMEM deivce's name. | ||
17 | |||
18 | Data cells: | ||
19 | |||
20 | Data cells are child nodes of eerpom node, bindings for which are | ||
21 | documented in Documentation/bindings/nvmem/nvmem.txt | ||
22 | |||
23 | Example: | ||
24 | |||
25 | rave-sp { | ||
26 | compatible = "zii,rave-sp-rdu1"; | ||
27 | current-speed = <38400>; | ||
28 | |||
29 | eeprom@a4 { | ||
30 | compatible = "zii,rave-sp-eeprom"; | ||
31 | reg = <0xa4 0x4000>; | ||
32 | #address-cells = <1>; | ||
33 | #size-cells = <1>; | ||
34 | zii,eeprom-name = "main-eeprom"; | ||
35 | |||
36 | wdt_timeout: wdt-timeout@81 { | ||
37 | reg = <0x81 2>; | ||
38 | }; | ||
39 | }; | ||
40 | } | ||
diff --git a/Documentation/driver-api/fpga/fpga-bridge.rst b/Documentation/driver-api/fpga/fpga-bridge.rst new file mode 100644 index 000000000000..2c2aaca894bf --- /dev/null +++ b/Documentation/driver-api/fpga/fpga-bridge.rst | |||
@@ -0,0 +1,49 @@ | |||
1 | FPGA Bridge | ||
2 | =========== | ||
3 | |||
4 | API to implement a new FPGA bridge | ||
5 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
6 | |||
7 | .. kernel-doc:: include/linux/fpga/fpga-bridge.h | ||
8 | :functions: fpga_bridge | ||
9 | |||
10 | .. kernel-doc:: include/linux/fpga/fpga-bridge.h | ||
11 | :functions: fpga_bridge_ops | ||
12 | |||
13 | .. kernel-doc:: drivers/fpga/fpga-bridge.c | ||
14 | :functions: fpga_bridge_create | ||
15 | |||
16 | .. kernel-doc:: drivers/fpga/fpga-bridge.c | ||
17 | :functions: fpga_bridge_free | ||
18 | |||
19 | .. kernel-doc:: drivers/fpga/fpga-bridge.c | ||
20 | :functions: fpga_bridge_register | ||
21 | |||
22 | .. kernel-doc:: drivers/fpga/fpga-bridge.c | ||
23 | :functions: fpga_bridge_unregister | ||
24 | |||
25 | API to control an FPGA bridge | ||
26 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
27 | |||
28 | You probably won't need these directly. FPGA regions should handle this. | ||
29 | |||
30 | .. kernel-doc:: drivers/fpga/fpga-bridge.c | ||
31 | :functions: of_fpga_bridge_get | ||
32 | |||
33 | .. kernel-doc:: drivers/fpga/fpga-bridge.c | ||
34 | :functions: fpga_bridge_get | ||
35 | |||
36 | .. kernel-doc:: drivers/fpga/fpga-bridge.c | ||
37 | :functions: fpga_bridge_put | ||
38 | |||
39 | .. kernel-doc:: drivers/fpga/fpga-bridge.c | ||
40 | :functions: fpga_bridge_get_to_list | ||
41 | |||
42 | .. kernel-doc:: drivers/fpga/fpga-bridge.c | ||
43 | :functions: of_fpga_bridge_get_to_list | ||
44 | |||
45 | .. kernel-doc:: drivers/fpga/fpga-bridge.c | ||
46 | :functions: fpga_bridge_enable | ||
47 | |||
48 | .. kernel-doc:: drivers/fpga/fpga-bridge.c | ||
49 | :functions: fpga_bridge_disable | ||
diff --git a/Documentation/driver-api/fpga/fpga-mgr.rst b/Documentation/driver-api/fpga/fpga-mgr.rst new file mode 100644 index 000000000000..bcf2dd24e179 --- /dev/null +++ b/Documentation/driver-api/fpga/fpga-mgr.rst | |||
@@ -0,0 +1,220 @@ | |||
1 | FPGA Manager | ||
2 | ============ | ||
3 | |||
4 | Overview | ||
5 | -------- | ||
6 | |||
7 | The FPGA manager core exports a set of functions for programming an FPGA with | ||
8 | an image. The API is manufacturer agnostic. All manufacturer specifics are | ||
9 | hidden away in a low level driver which registers a set of ops with the core. | ||
10 | The FPGA image data itself is very manufacturer specific, but for our purposes | ||
11 | it's just binary data. The FPGA manager core won't parse it. | ||
12 | |||
13 | The FPGA image to be programmed can be in a scatter gather list, a single | ||
14 | contiguous buffer, or a firmware file. Because allocating contiguous kernel | ||
15 | memory for the buffer should be avoided, users are encouraged to use a scatter | ||
16 | gather list instead if possible. | ||
17 | |||
18 | The particulars for programming the image are presented in a structure (struct | ||
19 | fpga_image_info). This struct contains parameters such as pointers to the | ||
20 | FPGA image as well as image-specific particulars such as whether the image was | ||
21 | built for full or partial reconfiguration. | ||
22 | |||
23 | How to support a new FPGA device | ||
24 | -------------------------------- | ||
25 | |||
26 | To add another FPGA manager, write a driver that implements a set of ops. The | ||
27 | probe function calls fpga_mgr_register(), such as:: | ||
28 | |||
29 | static const struct fpga_manager_ops socfpga_fpga_ops = { | ||
30 | .write_init = socfpga_fpga_ops_configure_init, | ||
31 | .write = socfpga_fpga_ops_configure_write, | ||
32 | .write_complete = socfpga_fpga_ops_configure_complete, | ||
33 | .state = socfpga_fpga_ops_state, | ||
34 | }; | ||
35 | |||
36 | static int socfpga_fpga_probe(struct platform_device *pdev) | ||
37 | { | ||
38 | struct device *dev = &pdev->dev; | ||
39 | struct socfpga_fpga_priv *priv; | ||
40 | struct fpga_manager *mgr; | ||
41 | int ret; | ||
42 | |||
43 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | ||
44 | if (!priv) | ||
45 | return -ENOMEM; | ||
46 | |||
47 | /* | ||
48 | * do ioremaps, get interrupts, etc. and save | ||
49 | * them in priv | ||
50 | */ | ||
51 | |||
52 | mgr = fpga_mgr_create(dev, "Altera SOCFPGA FPGA Manager", | ||
53 | &socfpga_fpga_ops, priv); | ||
54 | if (!mgr) | ||
55 | return -ENOMEM; | ||
56 | |||
57 | platform_set_drvdata(pdev, mgr); | ||
58 | |||
59 | ret = fpga_mgr_register(mgr); | ||
60 | if (ret) | ||
61 | fpga_mgr_free(mgr); | ||
62 | |||
63 | return ret; | ||
64 | } | ||
65 | |||
66 | static int socfpga_fpga_remove(struct platform_device *pdev) | ||
67 | { | ||
68 | struct fpga_manager *mgr = platform_get_drvdata(pdev); | ||
69 | |||
70 | fpga_mgr_unregister(mgr); | ||
71 | |||
72 | return 0; | ||
73 | } | ||
74 | |||
75 | |||
76 | The ops will implement whatever device specific register writes are needed to | ||
77 | do the programming sequence for this particular FPGA. These ops return 0 for | ||
78 | success or negative error codes otherwise. | ||
79 | |||
80 | The programming sequence is:: | ||
81 | 1. .write_init | ||
82 | 2. .write or .write_sg (may be called once or multiple times) | ||
83 | 3. .write_complete | ||
84 | |||
85 | The .write_init function will prepare the FPGA to receive the image data. The | ||
86 | buffer passed into .write_init will be atmost .initial_header_size bytes long, | ||
87 | if the whole bitstream is not immediately available then the core code will | ||
88 | buffer up at least this much before starting. | ||
89 | |||
90 | The .write function writes a buffer to the FPGA. The buffer may be contain the | ||
91 | whole FPGA image or may be a smaller chunk of an FPGA image. In the latter | ||
92 | case, this function is called multiple times for successive chunks. This interface | ||
93 | is suitable for drivers which use PIO. | ||
94 | |||
95 | The .write_sg version behaves the same as .write except the input is a sg_table | ||
96 | scatter list. This interface is suitable for drivers which use DMA. | ||
97 | |||
98 | The .write_complete function is called after all the image has been written | ||
99 | to put the FPGA into operating mode. | ||
100 | |||
101 | The ops include a .state function which will read the hardware FPGA manager and | ||
102 | return a code of type enum fpga_mgr_states. It doesn't result in a change in | ||
103 | hardware state. | ||
104 | |||
105 | How to write an image buffer to a supported FPGA | ||
106 | ------------------------------------------------ | ||
107 | |||
108 | Some sample code:: | ||
109 | |||
110 | #include <linux/fpga/fpga-mgr.h> | ||
111 | |||
112 | struct fpga_manager *mgr; | ||
113 | struct fpga_image_info *info; | ||
114 | int ret; | ||
115 | |||
116 | /* | ||
117 | * Get a reference to FPGA manager. The manager is not locked, so you can | ||
118 | * hold onto this reference without it preventing programming. | ||
119 | * | ||
120 | * This example uses the device node of the manager. Alternatively, use | ||
121 | * fpga_mgr_get(dev) instead if you have the device. | ||
122 | */ | ||
123 | mgr = of_fpga_mgr_get(mgr_node); | ||
124 | |||
125 | /* struct with information about the FPGA image to program. */ | ||
126 | info = fpga_image_info_alloc(dev); | ||
127 | |||
128 | /* flags indicates whether to do full or partial reconfiguration */ | ||
129 | info->flags = FPGA_MGR_PARTIAL_RECONFIG; | ||
130 | |||
131 | /* | ||
132 | * At this point, indicate where the image is. This is pseudo-code; you're | ||
133 | * going to use one of these three. | ||
134 | */ | ||
135 | if (image is in a scatter gather table) { | ||
136 | |||
137 | info->sgt = [your scatter gather table] | ||
138 | |||
139 | } else if (image is in a buffer) { | ||
140 | |||
141 | info->buf = [your image buffer] | ||
142 | info->count = [image buffer size] | ||
143 | |||
144 | } else if (image is in a firmware file) { | ||
145 | |||
146 | info->firmware_name = devm_kstrdup(dev, firmware_name, GFP_KERNEL); | ||
147 | |||
148 | } | ||
149 | |||
150 | /* Get exclusive control of FPGA manager */ | ||
151 | ret = fpga_mgr_lock(mgr); | ||
152 | |||
153 | /* Load the buffer to the FPGA */ | ||
154 | ret = fpga_mgr_buf_load(mgr, &info, buf, count); | ||
155 | |||
156 | /* Release the FPGA manager */ | ||
157 | fpga_mgr_unlock(mgr); | ||
158 | fpga_mgr_put(mgr); | ||
159 | |||
160 | /* Deallocate the image info if you're done with it */ | ||
161 | fpga_image_info_free(info); | ||
162 | |||
163 | API for implementing a new FPGA Manager driver | ||
164 | ---------------------------------------------- | ||
165 | |||
166 | .. kernel-doc:: include/linux/fpga/fpga-mgr.h | ||
167 | :functions: fpga_manager | ||
168 | |||
169 | .. kernel-doc:: include/linux/fpga/fpga-mgr.h | ||
170 | :functions: fpga_manager_ops | ||
171 | |||
172 | .. kernel-doc:: drivers/fpga/fpga-mgr.c | ||
173 | :functions: fpga_mgr_create | ||
174 | |||
175 | .. kernel-doc:: drivers/fpga/fpga-mgr.c | ||
176 | :functions: fpga_mgr_free | ||
177 | |||
178 | .. kernel-doc:: drivers/fpga/fpga-mgr.c | ||
179 | :functions: fpga_mgr_register | ||
180 | |||
181 | .. kernel-doc:: drivers/fpga/fpga-mgr.c | ||
182 | :functions: fpga_mgr_unregister | ||
183 | |||
184 | API for programming a FPGA | ||
185 | -------------------------- | ||
186 | |||
187 | .. kernel-doc:: include/linux/fpga/fpga-mgr.h | ||
188 | :functions: fpga_image_info | ||
189 | |||
190 | .. kernel-doc:: include/linux/fpga/fpga-mgr.h | ||
191 | :functions: fpga_mgr_states | ||
192 | |||
193 | .. kernel-doc:: drivers/fpga/fpga-mgr.c | ||
194 | :functions: fpga_image_info_alloc | ||
195 | |||
196 | .. kernel-doc:: drivers/fpga/fpga-mgr.c | ||
197 | :functions: fpga_image_info_free | ||
198 | |||
199 | .. kernel-doc:: drivers/fpga/fpga-mgr.c | ||
200 | :functions: of_fpga_mgr_get | ||
201 | |||
202 | .. kernel-doc:: drivers/fpga/fpga-mgr.c | ||
203 | :functions: fpga_mgr_get | ||
204 | |||
205 | .. kernel-doc:: drivers/fpga/fpga-mgr.c | ||
206 | :functions: fpga_mgr_put | ||
207 | |||
208 | .. kernel-doc:: drivers/fpga/fpga-mgr.c | ||
209 | :functions: fpga_mgr_lock | ||
210 | |||
211 | .. kernel-doc:: drivers/fpga/fpga-mgr.c | ||
212 | :functions: fpga_mgr_unlock | ||
213 | |||
214 | .. kernel-doc:: include/linux/fpga/fpga-mgr.h | ||
215 | :functions: fpga_mgr_states | ||
216 | |||
217 | Note - use :c:func:`fpga_region_program_fpga()` instead of :c:func:`fpga_mgr_load()` | ||
218 | |||
219 | .. kernel-doc:: drivers/fpga/fpga-mgr.c | ||
220 | :functions: fpga_mgr_load | ||
diff --git a/Documentation/driver-api/fpga/fpga-region.rst b/Documentation/driver-api/fpga/fpga-region.rst new file mode 100644 index 000000000000..f89e4a311722 --- /dev/null +++ b/Documentation/driver-api/fpga/fpga-region.rst | |||
@@ -0,0 +1,102 @@ | |||
1 | FPGA Region | ||
2 | =========== | ||
3 | |||
4 | Overview | ||
5 | -------- | ||
6 | |||
7 | This document is meant to be an brief overview of the FPGA region API usage. A | ||
8 | more conceptual look at regions can be found in the Device Tree binding | ||
9 | document [#f1]_. | ||
10 | |||
11 | For the purposes of this API document, let's just say that a region associates | ||
12 | an FPGA Manager and a bridge (or bridges) with a reprogrammable region of an | ||
13 | FPGA or the whole FPGA. The API provides a way to register a region and to | ||
14 | program a region. | ||
15 | |||
16 | Currently the only layer above fpga-region.c in the kernel is the Device Tree | ||
17 | support (of-fpga-region.c) described in [#f1]_. The DT support layer uses regions | ||
18 | to program the FPGA and then DT to handle enumeration. The common region code | ||
19 | is intended to be used by other schemes that have other ways of accomplishing | ||
20 | enumeration after programming. | ||
21 | |||
22 | An fpga-region can be set up to know the following things: | ||
23 | |||
24 | * which FPGA manager to use to do the programming | ||
25 | |||
26 | * which bridges to disable before programming and enable afterwards. | ||
27 | |||
28 | Additional info needed to program the FPGA image is passed in the struct | ||
29 | fpga_image_info including: | ||
30 | |||
31 | * pointers to the image as either a scatter-gather buffer, a contiguous | ||
32 | buffer, or the name of firmware file | ||
33 | |||
34 | * flags indicating specifics such as whether the image if for partial | ||
35 | reconfiguration. | ||
36 | |||
37 | How to program a FPGA using a region | ||
38 | ------------------------------------ | ||
39 | |||
40 | First, allocate the info struct:: | ||
41 | |||
42 | info = fpga_image_info_alloc(dev); | ||
43 | if (!info) | ||
44 | return -ENOMEM; | ||
45 | |||
46 | Set flags as needed, i.e.:: | ||
47 | |||
48 | info->flags |= FPGA_MGR_PARTIAL_RECONFIG; | ||
49 | |||
50 | Point to your FPGA image, such as:: | ||
51 | |||
52 | info->sgt = &sgt; | ||
53 | |||
54 | Add info to region and do the programming:: | ||
55 | |||
56 | region->info = info; | ||
57 | ret = fpga_region_program_fpga(region); | ||
58 | |||
59 | :c:func:`fpga_region_program_fpga()` operates on info passed in the | ||
60 | fpga_image_info (region->info). This function will attempt to: | ||
61 | |||
62 | * lock the region's mutex | ||
63 | * lock the region's FPGA manager | ||
64 | * build a list of FPGA bridges if a method has been specified to do so | ||
65 | * disable the bridges | ||
66 | * program the FPGA | ||
67 | * re-enable the bridges | ||
68 | * release the locks | ||
69 | |||
70 | Then you will want to enumerate whatever hardware has appeared in the FPGA. | ||
71 | |||
72 | How to add a new FPGA region | ||
73 | ---------------------------- | ||
74 | |||
75 | An example of usage can be seen in the probe function of [#f2]_. | ||
76 | |||
77 | .. [#f1] ../devicetree/bindings/fpga/fpga-region.txt | ||
78 | .. [#f2] ../../drivers/fpga/of-fpga-region.c | ||
79 | |||
80 | API to program a FGPA | ||
81 | --------------------- | ||
82 | |||
83 | .. kernel-doc:: drivers/fpga/fpga-region.c | ||
84 | :functions: fpga_region_program_fpga | ||
85 | |||
86 | API to add a new FPGA region | ||
87 | ---------------------------- | ||
88 | |||
89 | .. kernel-doc:: include/linux/fpga/fpga-region.h | ||
90 | :functions: fpga_region | ||
91 | |||
92 | .. kernel-doc:: drivers/fpga/fpga-region.c | ||
93 | :functions: fpga_region_create | ||
94 | |||
95 | .. kernel-doc:: drivers/fpga/fpga-region.c | ||
96 | :functions: fpga_region_free | ||
97 | |||
98 | .. kernel-doc:: drivers/fpga/fpga-region.c | ||
99 | :functions: fpga_region_register | ||
100 | |||
101 | .. kernel-doc:: drivers/fpga/fpga-region.c | ||
102 | :functions: fpga_region_unregister | ||
diff --git a/Documentation/driver-api/fpga/index.rst b/Documentation/driver-api/fpga/index.rst new file mode 100644 index 000000000000..c51e5ebd544a --- /dev/null +++ b/Documentation/driver-api/fpga/index.rst | |||
@@ -0,0 +1,13 @@ | |||
1 | ============== | ||
2 | FPGA Subsystem | ||
3 | ============== | ||
4 | |||
5 | :Author: Alan Tull | ||
6 | |||
7 | .. toctree:: | ||
8 | :maxdepth: 2 | ||
9 | |||
10 | intro | ||
11 | fpga-mgr | ||
12 | fpga-bridge | ||
13 | fpga-region | ||
diff --git a/Documentation/driver-api/fpga/intro.rst b/Documentation/driver-api/fpga/intro.rst new file mode 100644 index 000000000000..51cd81dbb4dc --- /dev/null +++ b/Documentation/driver-api/fpga/intro.rst | |||
@@ -0,0 +1,54 @@ | |||
1 | Introduction | ||
2 | ============ | ||
3 | |||
4 | The FPGA subsystem supports reprogramming FPGAs dynamically under | ||
5 | Linux. Some of the core intentions of the FPGA subsystems are: | ||
6 | |||
7 | * The FPGA subsystem is vendor agnostic. | ||
8 | |||
9 | * The FPGA subsystem separates upper layers (userspace interfaces and | ||
10 | enumeration) from lower layers that know how to program a specific | ||
11 | FPGA. | ||
12 | |||
13 | * Code should not be shared between upper and lower layers. This | ||
14 | should go without saying. If that seems necessary, there's probably | ||
15 | framework functionality that that can be added that will benefit | ||
16 | other users. Write the linux-fpga mailing list and maintainers and | ||
17 | seek out a solution that expands the framework for broad reuse. | ||
18 | |||
19 | * Generally, when adding code, think of the future. Plan for re-use. | ||
20 | |||
21 | The framework in the kernel is divided into: | ||
22 | |||
23 | FPGA Manager | ||
24 | ------------ | ||
25 | |||
26 | If you are adding a new FPGA or a new method of programming a FPGA, | ||
27 | this is the subsystem for you. Low level FPGA manager drivers contain | ||
28 | the knowledge of how to program a specific device. This subsystem | ||
29 | includes the framework in fpga-mgr.c and the low level drivers that | ||
30 | are registered with it. | ||
31 | |||
32 | FPGA Bridge | ||
33 | ----------- | ||
34 | |||
35 | FPGA Bridges prevent spurious signals from going out of a FPGA or a | ||
36 | region of a FPGA during programming. They are disabled before | ||
37 | programming begins and re-enabled afterwards. An FPGA bridge may be | ||
38 | actual hard hardware that gates a bus to a cpu or a soft ("freeze") | ||
39 | bridge in FPGA fabric that surrounds a partial reconfiguration region | ||
40 | of an FPGA. This subsystem includes fpga-bridge.c and the low level | ||
41 | drivers that are registered with it. | ||
42 | |||
43 | FPGA Region | ||
44 | ----------- | ||
45 | |||
46 | If you are adding a new interface to the FPGA framework, add it on top | ||
47 | of a FPGA region to allow the most reuse of your interface. | ||
48 | |||
49 | The FPGA Region framework (fpga-region.c) associates managers and | ||
50 | bridges as reconfigurable regions. A region may refer to the whole | ||
51 | FPGA in full reconfiguration or to a partial reconfiguration region. | ||
52 | |||
53 | The Device Tree FPGA Region support (of-fpga-region.c) handles | ||
54 | reprogramming FPGAs when device tree overlays are applied. | ||
diff --git a/Documentation/driver-api/index.rst b/Documentation/driver-api/index.rst index 5d04296f5ce0..f4180e7c7ed5 100644 --- a/Documentation/driver-api/index.rst +++ b/Documentation/driver-api/index.rst | |||
@@ -51,6 +51,7 @@ available subsections can be seen below. | |||
51 | dmaengine/index | 51 | dmaengine/index |
52 | slimbus | 52 | slimbus |
53 | soundwire/index | 53 | soundwire/index |
54 | fpga/index | ||
54 | 55 | ||
55 | .. only:: subproject and html | 56 | .. only:: subproject and html |
56 | 57 | ||
diff --git a/Documentation/driver-api/soundwire/error_handling.rst b/Documentation/driver-api/soundwire/error_handling.rst new file mode 100644 index 000000000000..aa3a0a23a066 --- /dev/null +++ b/Documentation/driver-api/soundwire/error_handling.rst | |||
@@ -0,0 +1,65 @@ | |||
1 | ======================== | ||
2 | SoundWire Error Handling | ||
3 | ======================== | ||
4 | |||
5 | The SoundWire PHY was designed with care and errors on the bus are going to | ||
6 | be very unlikely, and if they happen it should be limited to single bit | ||
7 | errors. Examples of this design can be found in the synchronization | ||
8 | mechanism (sync loss after two errors) and short CRCs used for the Bulk | ||
9 | Register Access. | ||
10 | |||
11 | The errors can be detected with multiple mechanisms: | ||
12 | |||
13 | 1. Bus clash or parity errors: This mechanism relies on low-level detectors | ||
14 | that are independent of the payload and usages, and they cover both control | ||
15 | and audio data. The current implementation only logs such errors. | ||
16 | Improvements could be invalidating an entire programming sequence and | ||
17 | restarting from a known position. In the case of such errors outside of a | ||
18 | control/command sequence, there is no concealment or recovery for audio | ||
19 | data enabled by the SoundWire protocol, the location of the error will also | ||
20 | impact its audibility (most-significant bits will be more impacted in PCM), | ||
21 | and after a number of such errors are detected the bus might be reset. Note | ||
22 | that bus clashes due to programming errors (two streams using the same bit | ||
23 | slots) or electrical issues during the transmit/receive transition cannot | ||
24 | be distinguished, although a recurring bus clash when audio is enabled is a | ||
25 | indication of a bus allocation issue. The interrupt mechanism can also help | ||
26 | identify Slaves which detected a Bus Clash or a Parity Error, but they may | ||
27 | not be responsible for the errors so resetting them individually is not a | ||
28 | viable recovery strategy. | ||
29 | |||
30 | 2. Command status: Each command is associated with a status, which only | ||
31 | covers transmission of the data between devices. The ACK status indicates | ||
32 | that the command was received and will be executed by the end of the | ||
33 | current frame. A NAK indicates that the command was in error and will not | ||
34 | be applied. In case of a bad programming (command sent to non-existent | ||
35 | Slave or to a non-implemented register) or electrical issue, no response | ||
36 | signals the command was ignored. Some Master implementations allow for a | ||
37 | command to be retransmitted several times. If the retransmission fails, | ||
38 | backtracking and restarting the entire programming sequence might be a | ||
39 | solution. Alternatively some implementations might directly issue a bus | ||
40 | reset and re-enumerate all devices. | ||
41 | |||
42 | 3. Timeouts: In a number of cases such as ChannelPrepare or | ||
43 | ClockStopPrepare, the bus driver is supposed to poll a register field until | ||
44 | it transitions to a NotFinished value of zero. The MIPI SoundWire spec 1.1 | ||
45 | does not define timeouts but the MIPI SoundWire DisCo document adds | ||
46 | recommendation on timeouts. If such configurations do not complete, the | ||
47 | driver will return a -ETIMEOUT. Such timeouts are symptoms of a faulty | ||
48 | Slave device and are likely impossible to recover from. | ||
49 | |||
50 | Errors during global reconfiguration sequences are extremely difficult to | ||
51 | handle: | ||
52 | |||
53 | 1. BankSwitch: An error during the last command issuing a BankSwitch is | ||
54 | difficult to backtrack from. Retransmitting the Bank Switch command may be | ||
55 | possible in a single segment setup, but this can lead to synchronization | ||
56 | problems when enabling multiple bus segments (a command with side effects | ||
57 | such as frame reconfiguration would be handled at different times). A global | ||
58 | hard-reset might be the best solution. | ||
59 | |||
60 | Note that SoundWire does not provide a mechanism to detect illegal values | ||
61 | written in valid registers. In a number of cases the standard even mentions | ||
62 | that the Slave might behave in implementation-defined ways. The bus | ||
63 | implementation does not provide a recovery mechanism for such errors, Slave | ||
64 | or Master driver implementers are responsible for writing valid values in | ||
65 | valid registers and implement additional range checking if needed. | ||
diff --git a/Documentation/driver-api/soundwire/index.rst b/Documentation/driver-api/soundwire/index.rst index 647e94654752..6db026028f27 100644 --- a/Documentation/driver-api/soundwire/index.rst +++ b/Documentation/driver-api/soundwire/index.rst | |||
@@ -6,6 +6,9 @@ SoundWire Documentation | |||
6 | :maxdepth: 1 | 6 | :maxdepth: 1 |
7 | 7 | ||
8 | summary | 8 | summary |
9 | stream | ||
10 | error_handling | ||
11 | locking | ||
9 | 12 | ||
10 | .. only:: subproject | 13 | .. only:: subproject |
11 | 14 | ||
diff --git a/Documentation/driver-api/soundwire/locking.rst b/Documentation/driver-api/soundwire/locking.rst new file mode 100644 index 000000000000..253f73555255 --- /dev/null +++ b/Documentation/driver-api/soundwire/locking.rst | |||
@@ -0,0 +1,106 @@ | |||
1 | ================= | ||
2 | SoundWire Locking | ||
3 | ================= | ||
4 | |||
5 | This document explains locking mechanism of the SoundWire Bus. Bus uses | ||
6 | following locks in order to avoid race conditions in Bus operations on | ||
7 | shared resources. | ||
8 | |||
9 | - Bus lock | ||
10 | |||
11 | - Message lock | ||
12 | |||
13 | Bus lock | ||
14 | ======== | ||
15 | |||
16 | SoundWire Bus lock is a mutex and is part of Bus data structure | ||
17 | (sdw_bus) which is used for every Bus instance. This lock is used to | ||
18 | serialize each of the following operations(s) within SoundWire Bus instance. | ||
19 | |||
20 | - Addition and removal of Slave(s), changing Slave status. | ||
21 | |||
22 | - Prepare, Enable, Disable and De-prepare stream operations. | ||
23 | |||
24 | - Access of Stream data structure. | ||
25 | |||
26 | Message lock | ||
27 | ============ | ||
28 | |||
29 | SoundWire message transfer lock. This mutex is part of | ||
30 | Bus data structure (sdw_bus). This lock is used to serialize the message | ||
31 | transfers (read/write) within a SoundWire Bus instance. | ||
32 | |||
33 | Below examples show how locks are acquired. | ||
34 | |||
35 | Example 1 | ||
36 | --------- | ||
37 | |||
38 | Message transfer. | ||
39 | |||
40 | 1. For every message transfer | ||
41 | |||
42 | a. Acquire Message lock. | ||
43 | |||
44 | b. Transfer message (Read/Write) to Slave1 or broadcast message on | ||
45 | Bus in case of bank switch. | ||
46 | |||
47 | c. Release Message lock :: | ||
48 | |||
49 | +----------+ +---------+ | ||
50 | | | | | | ||
51 | | Bus | | Master | | ||
52 | | | | Driver | | ||
53 | | | | | | ||
54 | +----+-----+ +----+----+ | ||
55 | | | | ||
56 | | bus->ops->xfer_msg() | | ||
57 | <-------------------------------+ a. Acquire Message lock | ||
58 | | | b. Transfer message | ||
59 | | | | ||
60 | +-------------------------------> c. Release Message lock | ||
61 | | return success/error | d. Return success/error | ||
62 | | | | ||
63 | + + | ||
64 | |||
65 | Example 2 | ||
66 | --------- | ||
67 | |||
68 | Prepare operation. | ||
69 | |||
70 | 1. Acquire lock for Bus instance associated with Master 1. | ||
71 | |||
72 | 2. For every message transfer in Prepare operation | ||
73 | |||
74 | a. Acquire Message lock. | ||
75 | |||
76 | b. Transfer message (Read/Write) to Slave1 or broadcast message on | ||
77 | Bus in case of bank switch. | ||
78 | |||
79 | c. Release Message lock. | ||
80 | |||
81 | 3. Release lock for Bus instance associated with Master 1 :: | ||
82 | |||
83 | +----------+ +---------+ | ||
84 | | | | | | ||
85 | | Bus | | Master | | ||
86 | | | | Driver | | ||
87 | | | | | | ||
88 | +----+-----+ +----+----+ | ||
89 | | | | ||
90 | | sdw_prepare_stream() | | ||
91 | <-------------------------------+ 1. Acquire bus lock | ||
92 | | | 2. Perform stream prepare | ||
93 | | | | ||
94 | | | | ||
95 | | bus->ops->xfer_msg() | | ||
96 | <-------------------------------+ a. Acquire Message lock | ||
97 | | | b. Transfer message | ||
98 | | | | ||
99 | +-------------------------------> c. Release Message lock | ||
100 | | return success/error | d. Return success/error | ||
101 | | | | ||
102 | | | | ||
103 | | return success/error | 3. Release bus lock | ||
104 | +-------------------------------> 4. Return success/error | ||
105 | | | | ||
106 | + + | ||
diff --git a/Documentation/driver-api/soundwire/stream.rst b/Documentation/driver-api/soundwire/stream.rst new file mode 100644 index 000000000000..29121aa55fb9 --- /dev/null +++ b/Documentation/driver-api/soundwire/stream.rst | |||
@@ -0,0 +1,372 @@ | |||
1 | ========================= | ||
2 | Audio Stream in SoundWire | ||
3 | ========================= | ||
4 | |||
5 | An audio stream is a logical or virtual connection created between | ||
6 | |||
7 | (1) System memory buffer(s) and Codec(s) | ||
8 | |||
9 | (2) DSP memory buffer(s) and Codec(s) | ||
10 | |||
11 | (3) FIFO(s) and Codec(s) | ||
12 | |||
13 | (4) Codec(s) and Codec(s) | ||
14 | |||
15 | which is typically driven by a DMA(s) channel through the data link. An | ||
16 | audio stream contains one or more channels of data. All channels within | ||
17 | stream must have same sample rate and same sample size. | ||
18 | |||
19 | Assume a stream with two channels (Left & Right) is opened using SoundWire | ||
20 | interface. Below are some ways a stream can be represented in SoundWire. | ||
21 | |||
22 | Stream Sample in memory (System memory, DSP memory or FIFOs) :: | ||
23 | |||
24 | ------------------------- | ||
25 | | L | R | L | R | L | R | | ||
26 | ------------------------- | ||
27 | |||
28 | Example 1: Stereo Stream with L and R channels is rendered from Master to | ||
29 | Slave. Both Master and Slave is using single port. :: | ||
30 | |||
31 | +---------------+ Clock Signal +---------------+ | ||
32 | | Master +----------------------------------+ Slave | | ||
33 | | Interface | | Interface | | ||
34 | | | | 1 | | ||
35 | | | Data Signal | | | ||
36 | | L + R +----------------------------------+ L + R | | ||
37 | | (Data) | Data Direction | (Data) | | ||
38 | +---------------+ +-----------------------> +---------------+ | ||
39 | |||
40 | |||
41 | Example 2: Stereo Stream with L and R channels is captured from Slave to | ||
42 | Master. Both Master and Slave is using single port. :: | ||
43 | |||
44 | |||
45 | +---------------+ Clock Signal +---------------+ | ||
46 | | Master +----------------------------------+ Slave | | ||
47 | | Interface | | Interface | | ||
48 | | | | 1 | | ||
49 | | | Data Signal | | | ||
50 | | L + R +----------------------------------+ L + R | | ||
51 | | (Data) | Data Direction | (Data) | | ||
52 | +---------------+ <-----------------------+ +---------------+ | ||
53 | |||
54 | |||
55 | Example 3: Stereo Stream with L and R channels is rendered by Master. Each | ||
56 | of the L and R channel is received by two different Slaves. Master and both | ||
57 | Slaves are using single port. :: | ||
58 | |||
59 | +---------------+ Clock Signal +---------------+ | ||
60 | | Master +---------+------------------------+ Slave | | ||
61 | | Interface | | | Interface | | ||
62 | | | | | 1 | | ||
63 | | | | Data Signal | | | ||
64 | | L + R +---+------------------------------+ L | | ||
65 | | (Data) | | | Data Direction | (Data) | | ||
66 | +---------------+ | | +-------------> +---------------+ | ||
67 | | | | ||
68 | | | | ||
69 | | | +---------------+ | ||
70 | | +----------------------> | Slave | | ||
71 | | | Interface | | ||
72 | | | 2 | | ||
73 | | | | | ||
74 | +----------------------------> | R | | ||
75 | | (Data) | | ||
76 | +---------------+ | ||
77 | |||
78 | |||
79 | Example 4: Stereo Stream with L and R channel is rendered by two different | ||
80 | Ports of the Master and is received by only single Port of the Slave | ||
81 | interface. :: | ||
82 | |||
83 | +--------------------+ | ||
84 | | | | ||
85 | | +--------------+ +----------------+ | ||
86 | | | || | | | ||
87 | | | Data Port || L Channel | | | ||
88 | | | 1 |------------+ | | | ||
89 | | | L Channel || | +-----+----+ | | ||
90 | | | (Data) || | L + R Channel || Data | | | ||
91 | | Master +----------+ | +---+---------> || Port | | | ||
92 | | Interface | | || 1 | | | ||
93 | | +--------------+ | || | | | ||
94 | | | || | +----------+ | | ||
95 | | | Data Port |------------+ | | | ||
96 | | | 2 || R Channel | Slave | | ||
97 | | | R Channel || | Interface | | ||
98 | | | (Data) || | 1 | | ||
99 | | +--------------+ Clock Signal | L + R | | ||
100 | | +---------------------------> | (Data) | | ||
101 | +--------------------+ | | | ||
102 | +----------------+ | ||
103 | |||
104 | SoundWire Stream Management flow | ||
105 | ================================ | ||
106 | |||
107 | Stream definitions | ||
108 | ------------------ | ||
109 | |||
110 | (1) Current stream: This is classified as the stream on which operation has | ||
111 | to be performed like prepare, enable, disable, de-prepare etc. | ||
112 | |||
113 | (2) Active stream: This is classified as the stream which is already active | ||
114 | on Bus other than current stream. There can be multiple active streams | ||
115 | on the Bus. | ||
116 | |||
117 | SoundWire Bus manages stream operations for each stream getting | ||
118 | rendered/captured on the SoundWire Bus. This section explains Bus operations | ||
119 | done for each of the stream allocated/released on Bus. Following are the | ||
120 | stream states maintained by the Bus for each of the audio stream. | ||
121 | |||
122 | |||
123 | SoundWire stream states | ||
124 | ----------------------- | ||
125 | |||
126 | Below shows the SoundWire stream states and state transition diagram. :: | ||
127 | |||
128 | +-----------+ +------------+ +----------+ +----------+ | ||
129 | | ALLOCATED +---->| CONFIGURED +---->| PREPARED +---->| ENABLED | | ||
130 | | STATE | | STATE | | STATE | | STATE | | ||
131 | +-----------+ +------------+ +----------+ +----+-----+ | ||
132 | ^ | ||
133 | | | ||
134 | | | ||
135 | v | ||
136 | +----------+ +------------+ +----+-----+ | ||
137 | | RELEASED |<----------+ DEPREPARED |<-------+ DISABLED | | ||
138 | | STATE | | STATE | | STATE | | ||
139 | +----------+ +------------+ +----------+ | ||
140 | |||
141 | NOTE: State transition between prepare and deprepare is supported in Spec | ||
142 | but not in the software (subsystem) | ||
143 | |||
144 | NOTE2: Stream state transition checks need to be handled by caller | ||
145 | framework, for example ALSA/ASoC. No checks for stream transition exist in | ||
146 | SoundWire subsystem. | ||
147 | |||
148 | Stream State Operations | ||
149 | ----------------------- | ||
150 | |||
151 | Below section explains the operations done by the Bus on Master(s) and | ||
152 | Slave(s) as part of stream state transitions. | ||
153 | |||
154 | SDW_STREAM_ALLOCATED | ||
155 | ~~~~~~~~~~~~~~~~~~~~ | ||
156 | |||
157 | Allocation state for stream. This is the entry state | ||
158 | of the stream. Operations performed before entering in this state: | ||
159 | |||
160 | (1) A stream runtime is allocated for the stream. This stream | ||
161 | runtime is used as a reference for all the operations performed | ||
162 | on the stream. | ||
163 | |||
164 | (2) The resources required for holding stream runtime information are | ||
165 | allocated and initialized. This holds all stream related information | ||
166 | such as stream type (PCM/PDM) and parameters, Master and Slave | ||
167 | interface associated with the stream, stream state etc. | ||
168 | |||
169 | After all above operations are successful, stream state is set to | ||
170 | ``SDW_STREAM_ALLOCATED``. | ||
171 | |||
172 | Bus implements below API for allocate a stream which needs to be called once | ||
173 | per stream. From ASoC DPCM framework, this stream state maybe linked to | ||
174 | .startup() operation. | ||
175 | |||
176 | .. code-block:: c | ||
177 | int sdw_alloc_stream(char * stream_name); | ||
178 | |||
179 | |||
180 | SDW_STREAM_CONFIGURED | ||
181 | ~~~~~~~~~~~~~~~~~~~~~ | ||
182 | |||
183 | Configuration state of stream. Operations performed before entering in | ||
184 | this state: | ||
185 | |||
186 | (1) The resources allocated for stream information in SDW_STREAM_ALLOCATED | ||
187 | state are updated here. This includes stream parameters, Master(s) | ||
188 | and Slave(s) runtime information associated with current stream. | ||
189 | |||
190 | (2) All the Master(s) and Slave(s) associated with current stream provide | ||
191 | the port information to Bus which includes port numbers allocated by | ||
192 | Master(s) and Slave(s) for current stream and their channel mask. | ||
193 | |||
194 | After all above operations are successful, stream state is set to | ||
195 | ``SDW_STREAM_CONFIGURED``. | ||
196 | |||
197 | Bus implements below APIs for CONFIG state which needs to be called by | ||
198 | the respective Master(s) and Slave(s) associated with stream. These APIs can | ||
199 | only be invoked once by respective Master(s) and Slave(s). From ASoC DPCM | ||
200 | framework, this stream state is linked to .hw_params() operation. | ||
201 | |||
202 | .. code-block:: c | ||
203 | int sdw_stream_add_master(struct sdw_bus * bus, | ||
204 | struct sdw_stream_config * stream_config, | ||
205 | struct sdw_ports_config * ports_config, | ||
206 | struct sdw_stream_runtime * stream); | ||
207 | |||
208 | int sdw_stream_add_slave(struct sdw_slave * slave, | ||
209 | struct sdw_stream_config * stream_config, | ||
210 | struct sdw_ports_config * ports_config, | ||
211 | struct sdw_stream_runtime * stream); | ||
212 | |||
213 | |||
214 | SDW_STREAM_PREPARED | ||
215 | ~~~~~~~~~~~~~~~~~~~ | ||
216 | |||
217 | Prepare state of stream. Operations performed before entering in this state: | ||
218 | |||
219 | (1) Bus parameters such as bandwidth, frame shape, clock frequency, | ||
220 | are computed based on current stream as well as already active | ||
221 | stream(s) on Bus. Re-computation is required to accommodate current | ||
222 | stream on the Bus. | ||
223 | |||
224 | (2) Transport and port parameters of all Master(s) and Slave(s) port(s) are | ||
225 | computed for the current as well as already active stream based on frame | ||
226 | shape and clock frequency computed in step 1. | ||
227 | |||
228 | (3) Computed Bus and transport parameters are programmed in Master(s) and | ||
229 | Slave(s) registers. The banked registers programming is done on the | ||
230 | alternate bank (bank currently unused). Port(s) are enabled for the | ||
231 | already active stream(s) on the alternate bank (bank currently unused). | ||
232 | This is done in order to not disrupt already active stream(s). | ||
233 | |||
234 | (4) Once all the values are programmed, Bus initiates switch to alternate | ||
235 | bank where all new values programmed gets into effect. | ||
236 | |||
237 | (5) Ports of Master(s) and Slave(s) for current stream are prepared by | ||
238 | programming PrepareCtrl register. | ||
239 | |||
240 | After all above operations are successful, stream state is set to | ||
241 | ``SDW_STREAM_PREPARED``. | ||
242 | |||
243 | Bus implements below API for PREPARE state which needs to be called once per | ||
244 | stream. From ASoC DPCM framework, this stream state is linked to | ||
245 | .prepare() operation. | ||
246 | |||
247 | .. code-block:: c | ||
248 | int sdw_prepare_stream(struct sdw_stream_runtime * stream); | ||
249 | |||
250 | |||
251 | SDW_STREAM_ENABLED | ||
252 | ~~~~~~~~~~~~~~~~~~ | ||
253 | |||
254 | Enable state of stream. The data port(s) are enabled upon entering this state. | ||
255 | Operations performed before entering in this state: | ||
256 | |||
257 | (1) All the values computed in SDW_STREAM_PREPARED state are programmed | ||
258 | in alternate bank (bank currently unused). It includes programming of | ||
259 | already active stream(s) as well. | ||
260 | |||
261 | (2) All the Master(s) and Slave(s) port(s) for the current stream are | ||
262 | enabled on alternate bank (bank currently unused) by programming | ||
263 | ChannelEn register. | ||
264 | |||
265 | (3) Once all the values are programmed, Bus initiates switch to alternate | ||
266 | bank where all new values programmed gets into effect and port(s) | ||
267 | associated with current stream are enabled. | ||
268 | |||
269 | After all above operations are successful, stream state is set to | ||
270 | ``SDW_STREAM_ENABLED``. | ||
271 | |||
272 | Bus implements below API for ENABLE state which needs to be called once per | ||
273 | stream. From ASoC DPCM framework, this stream state is linked to | ||
274 | .trigger() start operation. | ||
275 | |||
276 | .. code-block:: c | ||
277 | int sdw_enable_stream(struct sdw_stream_runtime * stream); | ||
278 | |||
279 | SDW_STREAM_DISABLED | ||
280 | ~~~~~~~~~~~~~~~~~~~ | ||
281 | |||
282 | Disable state of stream. The data port(s) are disabled upon exiting this state. | ||
283 | Operations performed before entering in this state: | ||
284 | |||
285 | (1) All the Master(s) and Slave(s) port(s) for the current stream are | ||
286 | disabled on alternate bank (bank currently unused) by programming | ||
287 | ChannelEn register. | ||
288 | |||
289 | (2) All the current configuration of Bus and active stream(s) are programmed | ||
290 | into alternate bank (bank currently unused). | ||
291 | |||
292 | (3) Once all the values are programmed, Bus initiates switch to alternate | ||
293 | bank where all new values programmed gets into effect and port(s) associated | ||
294 | with current stream are disabled. | ||
295 | |||
296 | After all above operations are successful, stream state is set to | ||
297 | ``SDW_STREAM_DISABLED``. | ||
298 | |||
299 | Bus implements below API for DISABLED state which needs to be called once | ||
300 | per stream. From ASoC DPCM framework, this stream state is linked to | ||
301 | .trigger() stop operation. | ||
302 | |||
303 | .. code-block:: c | ||
304 | int sdw_disable_stream(struct sdw_stream_runtime * stream); | ||
305 | |||
306 | |||
307 | SDW_STREAM_DEPREPARED | ||
308 | ~~~~~~~~~~~~~~~~~~~~~ | ||
309 | |||
310 | De-prepare state of stream. Operations performed before entering in this | ||
311 | state: | ||
312 | |||
313 | (1) All the port(s) of Master(s) and Slave(s) for current stream are | ||
314 | de-prepared by programming PrepareCtrl register. | ||
315 | |||
316 | (2) The payload bandwidth of current stream is reduced from the total | ||
317 | bandwidth requirement of bus and new parameters calculated and | ||
318 | applied by performing bank switch etc. | ||
319 | |||
320 | After all above operations are successful, stream state is set to | ||
321 | ``SDW_STREAM_DEPREPARED``. | ||
322 | |||
323 | Bus implements below API for DEPREPARED state which needs to be called once | ||
324 | per stream. From ASoC DPCM framework, this stream state is linked to | ||
325 | .trigger() stop operation. | ||
326 | |||
327 | .. code-block:: c | ||
328 | int sdw_deprepare_stream(struct sdw_stream_runtime * stream); | ||
329 | |||
330 | |||
331 | SDW_STREAM_RELEASED | ||
332 | ~~~~~~~~~~~~~~~~~~~ | ||
333 | |||
334 | Release state of stream. Operations performed before entering in this state: | ||
335 | |||
336 | (1) Release port resources for all Master(s) and Slave(s) port(s) | ||
337 | associated with current stream. | ||
338 | |||
339 | (2) Release Master(s) and Slave(s) runtime resources associated with | ||
340 | current stream. | ||
341 | |||
342 | (3) Release stream runtime resources associated with current stream. | ||
343 | |||
344 | After all above operations are successful, stream state is set to | ||
345 | ``SDW_STREAM_RELEASED``. | ||
346 | |||
347 | Bus implements below APIs for RELEASE state which needs to be called by | ||
348 | all the Master(s) and Slave(s) associated with stream. From ASoC DPCM | ||
349 | framework, this stream state is linked to .hw_free() operation. | ||
350 | |||
351 | .. code-block:: c | ||
352 | int sdw_stream_remove_master(struct sdw_bus * bus, | ||
353 | struct sdw_stream_runtime * stream); | ||
354 | int sdw_stream_remove_slave(struct sdw_slave * slave, | ||
355 | struct sdw_stream_runtime * stream); | ||
356 | |||
357 | |||
358 | The .shutdown() ASoC DPCM operation calls below Bus API to release | ||
359 | stream assigned as part of ALLOCATED state. | ||
360 | |||
361 | In .shutdown() the data structure maintaining stream state are freed up. | ||
362 | |||
363 | .. code-block:: c | ||
364 | void sdw_release_stream(struct sdw_stream_runtime * stream); | ||
365 | |||
366 | Not Supported | ||
367 | ============= | ||
368 | |||
369 | 1. A single port with multiple channels supported cannot be used between two | ||
370 | streams or across stream. For example a port with 4 channels cannot be used | ||
371 | to handle 2 independent stereo streams even though it's possible in theory | ||
372 | in SoundWire. | ||
diff --git a/Documentation/fpga/fpga-mgr.txt b/Documentation/fpga/fpga-mgr.txt deleted file mode 100644 index cc6413ed6fc9..000000000000 --- a/Documentation/fpga/fpga-mgr.txt +++ /dev/null | |||
@@ -1,199 +0,0 @@ | |||
1 | FPGA Manager Core | ||
2 | |||
3 | Alan Tull 2015 | ||
4 | |||
5 | Overview | ||
6 | ======== | ||
7 | |||
8 | The FPGA manager core exports a set of functions for programming an FPGA with | ||
9 | an image. The API is manufacturer agnostic. All manufacturer specifics are | ||
10 | hidden away in a low level driver which registers a set of ops with the core. | ||
11 | The FPGA image data itself is very manufacturer specific, but for our purposes | ||
12 | it's just binary data. The FPGA manager core won't parse it. | ||
13 | |||
14 | The FPGA image to be programmed can be in a scatter gather list, a single | ||
15 | contiguous buffer, or a firmware file. Because allocating contiguous kernel | ||
16 | memory for the buffer should be avoided, users are encouraged to use a scatter | ||
17 | gather list instead if possible. | ||
18 | |||
19 | The particulars for programming the image are presented in a structure (struct | ||
20 | fpga_image_info). This struct contains parameters such as pointers to the | ||
21 | FPGA image as well as image-specific particulars such as whether the image was | ||
22 | built for full or partial reconfiguration. | ||
23 | |||
24 | API Functions: | ||
25 | ============== | ||
26 | |||
27 | To program the FPGA: | ||
28 | -------------------- | ||
29 | |||
30 | int fpga_mgr_load(struct fpga_manager *mgr, | ||
31 | struct fpga_image_info *info); | ||
32 | |||
33 | Load the FPGA from an image which is indicated in the info. If successful, | ||
34 | the FPGA ends up in operating mode. Return 0 on success or a negative error | ||
35 | code. | ||
36 | |||
37 | To allocate or free a struct fpga_image_info: | ||
38 | --------------------------------------------- | ||
39 | |||
40 | struct fpga_image_info *fpga_image_info_alloc(struct device *dev); | ||
41 | |||
42 | void fpga_image_info_free(struct fpga_image_info *info); | ||
43 | |||
44 | To get/put a reference to a FPGA manager: | ||
45 | ----------------------------------------- | ||
46 | |||
47 | struct fpga_manager *of_fpga_mgr_get(struct device_node *node); | ||
48 | struct fpga_manager *fpga_mgr_get(struct device *dev); | ||
49 | void fpga_mgr_put(struct fpga_manager *mgr); | ||
50 | |||
51 | Given a DT node or device, get a reference to a FPGA manager. This pointer | ||
52 | can be saved until you are ready to program the FPGA. fpga_mgr_put releases | ||
53 | the reference. | ||
54 | |||
55 | |||
56 | To get exclusive control of a FPGA manager: | ||
57 | ------------------------------------------- | ||
58 | |||
59 | int fpga_mgr_lock(struct fpga_manager *mgr); | ||
60 | void fpga_mgr_unlock(struct fpga_manager *mgr); | ||
61 | |||
62 | The user should call fpga_mgr_lock and verify that it returns 0 before | ||
63 | attempting to program the FPGA. Likewise, the user should call | ||
64 | fpga_mgr_unlock when done programming the FPGA. | ||
65 | |||
66 | |||
67 | To register or unregister the low level FPGA-specific driver: | ||
68 | ------------------------------------------------------------- | ||
69 | |||
70 | int fpga_mgr_register(struct device *dev, const char *name, | ||
71 | const struct fpga_manager_ops *mops, | ||
72 | void *priv); | ||
73 | |||
74 | void fpga_mgr_unregister(struct device *dev); | ||
75 | |||
76 | Use of these two functions is described below in "How To Support a new FPGA | ||
77 | device." | ||
78 | |||
79 | |||
80 | How to write an image buffer to a supported FPGA | ||
81 | ================================================ | ||
82 | #include <linux/fpga/fpga-mgr.h> | ||
83 | |||
84 | struct fpga_manager *mgr; | ||
85 | struct fpga_image_info *info; | ||
86 | int ret; | ||
87 | |||
88 | /* | ||
89 | * Get a reference to FPGA manager. The manager is not locked, so you can | ||
90 | * hold onto this reference without it preventing programming. | ||
91 | * | ||
92 | * This example uses the device node of the manager. Alternatively, use | ||
93 | * fpga_mgr_get(dev) instead if you have the device. | ||
94 | */ | ||
95 | mgr = of_fpga_mgr_get(mgr_node); | ||
96 | |||
97 | /* struct with information about the FPGA image to program. */ | ||
98 | info = fpga_image_info_alloc(dev); | ||
99 | |||
100 | /* flags indicates whether to do full or partial reconfiguration */ | ||
101 | info->flags = FPGA_MGR_PARTIAL_RECONFIG; | ||
102 | |||
103 | /* | ||
104 | * At this point, indicate where the image is. This is pseudo-code; you're | ||
105 | * going to use one of these three. | ||
106 | */ | ||
107 | if (image is in a scatter gather table) { | ||
108 | |||
109 | info->sgt = [your scatter gather table] | ||
110 | |||
111 | } else if (image is in a buffer) { | ||
112 | |||
113 | info->buf = [your image buffer] | ||
114 | info->count = [image buffer size] | ||
115 | |||
116 | } else if (image is in a firmware file) { | ||
117 | |||
118 | info->firmware_name = devm_kstrdup(dev, firmware_name, GFP_KERNEL); | ||
119 | |||
120 | } | ||
121 | |||
122 | /* Get exclusive control of FPGA manager */ | ||
123 | ret = fpga_mgr_lock(mgr); | ||
124 | |||
125 | /* Load the buffer to the FPGA */ | ||
126 | ret = fpga_mgr_buf_load(mgr, &info, buf, count); | ||
127 | |||
128 | /* Release the FPGA manager */ | ||
129 | fpga_mgr_unlock(mgr); | ||
130 | fpga_mgr_put(mgr); | ||
131 | |||
132 | /* Deallocate the image info if you're done with it */ | ||
133 | fpga_image_info_free(info); | ||
134 | |||
135 | How to support a new FPGA device | ||
136 | ================================ | ||
137 | To add another FPGA manager, write a driver that implements a set of ops. The | ||
138 | probe function calls fpga_mgr_register(), such as: | ||
139 | |||
140 | static const struct fpga_manager_ops socfpga_fpga_ops = { | ||
141 | .write_init = socfpga_fpga_ops_configure_init, | ||
142 | .write = socfpga_fpga_ops_configure_write, | ||
143 | .write_complete = socfpga_fpga_ops_configure_complete, | ||
144 | .state = socfpga_fpga_ops_state, | ||
145 | }; | ||
146 | |||
147 | static int socfpga_fpga_probe(struct platform_device *pdev) | ||
148 | { | ||
149 | struct device *dev = &pdev->dev; | ||
150 | struct socfpga_fpga_priv *priv; | ||
151 | int ret; | ||
152 | |||
153 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | ||
154 | if (!priv) | ||
155 | return -ENOMEM; | ||
156 | |||
157 | /* ... do ioremaps, get interrupts, etc. and save | ||
158 | them in priv... */ | ||
159 | |||
160 | return fpga_mgr_register(dev, "Altera SOCFPGA FPGA Manager", | ||
161 | &socfpga_fpga_ops, priv); | ||
162 | } | ||
163 | |||
164 | static int socfpga_fpga_remove(struct platform_device *pdev) | ||
165 | { | ||
166 | fpga_mgr_unregister(&pdev->dev); | ||
167 | |||
168 | return 0; | ||
169 | } | ||
170 | |||
171 | |||
172 | The ops will implement whatever device specific register writes are needed to | ||
173 | do the programming sequence for this particular FPGA. These ops return 0 for | ||
174 | success or negative error codes otherwise. | ||
175 | |||
176 | The programming sequence is: | ||
177 | 1. .write_init | ||
178 | 2. .write or .write_sg (may be called once or multiple times) | ||
179 | 3. .write_complete | ||
180 | |||
181 | The .write_init function will prepare the FPGA to receive the image data. The | ||
182 | buffer passed into .write_init will be atmost .initial_header_size bytes long, | ||
183 | if the whole bitstream is not immediately available then the core code will | ||
184 | buffer up at least this much before starting. | ||
185 | |||
186 | The .write function writes a buffer to the FPGA. The buffer may be contain the | ||
187 | whole FPGA image or may be a smaller chunk of an FPGA image. In the latter | ||
188 | case, this function is called multiple times for successive chunks. This interface | ||
189 | is suitable for drivers which use PIO. | ||
190 | |||
191 | The .write_sg version behaves the same as .write except the input is a sg_table | ||
192 | scatter list. This interface is suitable for drivers which use DMA. | ||
193 | |||
194 | The .write_complete function is called after all the image has been written | ||
195 | to put the FPGA into operating mode. | ||
196 | |||
197 | The ops include a .state function which will read the hardware FPGA manager and | ||
198 | return a code of type enum fpga_mgr_states. It doesn't result in a change in | ||
199 | hardware state. | ||
diff --git a/Documentation/fpga/fpga-region.txt b/Documentation/fpga/fpga-region.txt deleted file mode 100644 index 139a02ba1ff6..000000000000 --- a/Documentation/fpga/fpga-region.txt +++ /dev/null | |||
@@ -1,95 +0,0 @@ | |||
1 | FPGA Regions | ||
2 | |||
3 | Alan Tull 2017 | ||
4 | |||
5 | CONTENTS | ||
6 | - Introduction | ||
7 | - The FPGA region API | ||
8 | - Usage example | ||
9 | |||
10 | Introduction | ||
11 | ============ | ||
12 | |||
13 | This document is meant to be an brief overview of the FPGA region API usage. A | ||
14 | more conceptual look at regions can be found in [1]. | ||
15 | |||
16 | For the purposes of this API document, let's just say that a region associates | ||
17 | an FPGA Manager and a bridge (or bridges) with a reprogrammable region of an | ||
18 | FPGA or the whole FPGA. The API provides a way to register a region and to | ||
19 | program a region. | ||
20 | |||
21 | Currently the only layer above fpga-region.c in the kernel is the Device Tree | ||
22 | support (of-fpga-region.c) described in [1]. The DT support layer uses regions | ||
23 | to program the FPGA and then DT to handle enumeration. The common region code | ||
24 | is intended to be used by other schemes that have other ways of accomplishing | ||
25 | enumeration after programming. | ||
26 | |||
27 | An fpga-region can be set up to know the following things: | ||
28 | * which FPGA manager to use to do the programming | ||
29 | * which bridges to disable before programming and enable afterwards. | ||
30 | |||
31 | Additional info needed to program the FPGA image is passed in the struct | ||
32 | fpga_image_info [2] including: | ||
33 | * pointers to the image as either a scatter-gather buffer, a contiguous | ||
34 | buffer, or the name of firmware file | ||
35 | * flags indicating specifics such as whether the image if for partial | ||
36 | reconfiguration. | ||
37 | |||
38 | =================== | ||
39 | The FPGA region API | ||
40 | =================== | ||
41 | |||
42 | To register or unregister a region: | ||
43 | ----------------------------------- | ||
44 | |||
45 | int fpga_region_register(struct device *dev, | ||
46 | struct fpga_region *region); | ||
47 | int fpga_region_unregister(struct fpga_region *region); | ||
48 | |||
49 | An example of usage can be seen in the probe function of [3] | ||
50 | |||
51 | To program an FPGA: | ||
52 | ------------------- | ||
53 | int fpga_region_program_fpga(struct fpga_region *region); | ||
54 | |||
55 | This function operates on info passed in the fpga_image_info | ||
56 | (region->info). | ||
57 | |||
58 | This function will attempt to: | ||
59 | * lock the region's mutex | ||
60 | * lock the region's FPGA manager | ||
61 | * build a list of FPGA bridges if a method has been specified to do so | ||
62 | * disable the bridges | ||
63 | * program the FPGA | ||
64 | * re-enable the bridges | ||
65 | * release the locks | ||
66 | |||
67 | ============= | ||
68 | Usage example | ||
69 | ============= | ||
70 | |||
71 | First, allocate the info struct: | ||
72 | |||
73 | info = fpga_image_info_alloc(dev); | ||
74 | if (!info) | ||
75 | return -ENOMEM; | ||
76 | |||
77 | Set flags as needed, i.e. | ||
78 | |||
79 | info->flags |= FPGA_MGR_PARTIAL_RECONFIG; | ||
80 | |||
81 | Point to your FPGA image, such as: | ||
82 | |||
83 | info->sgt = &sgt; | ||
84 | |||
85 | Add info to region and do the programming: | ||
86 | |||
87 | region->info = info; | ||
88 | ret = fpga_region_program_fpga(region); | ||
89 | |||
90 | Then enumerate whatever hardware has appeared in the FPGA. | ||
91 | |||
92 | -- | ||
93 | [1] ../devicetree/bindings/fpga/fpga-region.txt | ||
94 | [2] ./fpga-mgr.txt | ||
95 | [3] ../../drivers/fpga/of-fpga-region.c | ||
diff --git a/Documentation/fpga/overview.txt b/Documentation/fpga/overview.txt deleted file mode 100644 index 0f1236e7e675..000000000000 --- a/Documentation/fpga/overview.txt +++ /dev/null | |||
@@ -1,23 +0,0 @@ | |||
1 | Linux kernel FPGA support | ||
2 | |||
3 | Alan Tull 2017 | ||
4 | |||
5 | The main point of this project has been to separate the out the upper layers | ||
6 | that know when to reprogram a FPGA from the lower layers that know how to | ||
7 | reprogram a specific FPGA device. The intention is to make this manufacturer | ||
8 | agnostic, understanding that of course the FPGA images are very device specific | ||
9 | themselves. | ||
10 | |||
11 | The framework in the kernel includes: | ||
12 | * low level FPGA manager drivers that know how to program a specific device | ||
13 | * the fpga-mgr framework they are registered with | ||
14 | * low level FPGA bridge drivers for hard/soft bridges which are intended to | ||
15 | be disable during FPGA programming | ||
16 | * the fpga-bridge framework they are registered with | ||
17 | * the fpga-region framework which associates and controls managers and bridges | ||
18 | as reconfigurable regions | ||
19 | * the of-fpga-region support for reprogramming FPGAs when device tree overlays | ||
20 | are applied. | ||
21 | |||
22 | I would encourage you the user to add code that creates FPGA regions rather | ||
23 | that trying to control managers and bridges separately. | ||
diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt index 27c1b7b78504..a12488d45c40 100644 --- a/Documentation/ioctl/ioctl-number.txt +++ b/Documentation/ioctl/ioctl-number.txt | |||
@@ -328,6 +328,7 @@ Code Seq#(hex) Include File Comments | |||
328 | 0xCA 80-BF uapi/scsi/cxlflash_ioctl.h | 328 | 0xCA 80-BF uapi/scsi/cxlflash_ioctl.h |
329 | 0xCB 00-1F CBM serial IEC bus in development: | 329 | 0xCB 00-1F CBM serial IEC bus in development: |
330 | <mailto:michael.klein@puffin.lb.shuttle.de> | 330 | <mailto:michael.klein@puffin.lb.shuttle.de> |
331 | 0xCC 00-0F drivers/misc/ibmvmc.h pseries VMC driver | ||
331 | 0xCD 01 linux/reiserfs_fs.h | 332 | 0xCD 01 linux/reiserfs_fs.h |
332 | 0xCF 02 fs/cifs/ioctl.c | 333 | 0xCF 02 fs/cifs/ioctl.c |
333 | 0xDB 00-0F drivers/char/mwave/mwavepub.h | 334 | 0xDB 00-0F drivers/char/mwave/mwavepub.h |
diff --git a/Documentation/misc-devices/ibmvmc.rst b/Documentation/misc-devices/ibmvmc.rst new file mode 100644 index 000000000000..46ded79554d4 --- /dev/null +++ b/Documentation/misc-devices/ibmvmc.rst | |||
@@ -0,0 +1,226 @@ | |||
1 | .. SPDX-License-Identifier: GPL-2.0+ | ||
2 | ====================================================== | ||
3 | IBM Virtual Management Channel Kernel Driver (IBMVMC) | ||
4 | ====================================================== | ||
5 | |||
6 | :Authors: | ||
7 | Dave Engebretsen <engebret@us.ibm.com>, | ||
8 | Adam Reznechek <adreznec@linux.vnet.ibm.com>, | ||
9 | Steven Royer <seroyer@linux.vnet.ibm.com>, | ||
10 | Bryant G. Ly <bryantly@linux.vnet.ibm.com>, | ||
11 | |||
12 | Introduction | ||
13 | ============ | ||
14 | |||
15 | Note: Knowledge of virtualization technology is required to understand | ||
16 | this document. | ||
17 | |||
18 | A good reference document would be: | ||
19 | |||
20 | https://openpowerfoundation.org/wp-content/uploads/2016/05/LoPAPR_DRAFT_v11_24March2016_cmt1.pdf | ||
21 | |||
22 | The Virtual Management Channel (VMC) is a logical device which provides an | ||
23 | interface between the hypervisor and a management partition. This interface | ||
24 | is like a message passing interface. This management partition is intended | ||
25 | to provide an alternative to systems that use a Hardware Management | ||
26 | Console (HMC) - based system management. | ||
27 | |||
28 | The primary hardware management solution that is developed by IBM relies | ||
29 | on an appliance server named the Hardware Management Console (HMC), | ||
30 | packaged as an external tower or rack-mounted personal computer. In a | ||
31 | Power Systems environment, a single HMC can manage multiple POWER | ||
32 | processor-based systems. | ||
33 | |||
34 | Management Application | ||
35 | ---------------------- | ||
36 | |||
37 | In the management partition, a management application exists which enables | ||
38 | a system administrator to configure the system’s partitioning | ||
39 | characteristics via a command line interface (CLI) or Representational | ||
40 | State Transfer Application (REST API's). | ||
41 | |||
42 | The management application runs on a Linux logical partition on a | ||
43 | POWER8 or newer processor-based server that is virtualized by PowerVM. | ||
44 | System configuration, maintenance, and control functions which | ||
45 | traditionally require an HMC can be implemented in the management | ||
46 | application using a combination of HMC to hypervisor interfaces and | ||
47 | existing operating system methods. This tool provides a subset of the | ||
48 | functions implemented by the HMC and enables basic partition configuration. | ||
49 | The set of HMC to hypervisor messages supported by the management | ||
50 | application component are passed to the hypervisor over a VMC interface, | ||
51 | which is defined below. | ||
52 | |||
53 | The VMC enables the management partition to provide basic partitioning | ||
54 | functions: | ||
55 | |||
56 | - Logical Partitioning Configuration | ||
57 | - Start, and stop actions for individual partitions | ||
58 | - Display of partition status | ||
59 | - Management of virtual Ethernet | ||
60 | - Management of virtual Storage | ||
61 | - Basic system management | ||
62 | |||
63 | Virtual Management Channel (VMC) | ||
64 | -------------------------------- | ||
65 | |||
66 | A logical device, called the Virtual Management Channel (VMC), is defined | ||
67 | for communicating between the management application and the hypervisor. It | ||
68 | basically creates the pipes that enable virtualization management | ||
69 | software. This device is presented to a designated management partition as | ||
70 | a virtual device. | ||
71 | |||
72 | This communication device uses Command/Response Queue (CRQ) and the | ||
73 | Remote Direct Memory Access (RDMA) interfaces. A three-way handshake is | ||
74 | defined that must take place to establish that both the hypervisor and | ||
75 | management partition sides of the channel are running prior to | ||
76 | sending/receiving any of the protocol messages. | ||
77 | |||
78 | This driver also utilizes Transport Event CRQs. CRQ messages are sent | ||
79 | when the hypervisor detects one of the peer partitions has abnormally | ||
80 | terminated, or one side has called H_FREE_CRQ to close their CRQ. | ||
81 | Two new classes of CRQ messages are introduced for the VMC device. VMC | ||
82 | Administrative messages are used for each partition using the VMC to | ||
83 | communicate capabilities to their partner. HMC Interface messages are used | ||
84 | for the actual flow of HMC messages between the management partition and | ||
85 | the hypervisor. As most HMC messages far exceed the size of a CRQ buffer, | ||
86 | a virtual DMA (RMDA) of the HMC message data is done prior to each HMC | ||
87 | Interface CRQ message. Only the management partition drives RDMA | ||
88 | operations; hypervisors never directly cause the movement of message data. | ||
89 | |||
90 | |||
91 | Terminology | ||
92 | ----------- | ||
93 | RDMA | ||
94 | Remote Direct Memory Access is DMA transfer from the server to its | ||
95 | client or from the server to its partner partition. DMA refers | ||
96 | to both physical I/O to and from memory operations and to memory | ||
97 | to memory move operations. | ||
98 | CRQ | ||
99 | Command/Response Queue a facility which is used to communicate | ||
100 | between partner partitions. Transport events which are signaled | ||
101 | from the hypervisor to partition are also reported in this queue. | ||
102 | |||
103 | Example Management Partition VMC Driver Interface | ||
104 | ================================================= | ||
105 | |||
106 | This section provides an example for the management application | ||
107 | implementation where a device driver is used to interface to the VMC | ||
108 | device. This driver consists of a new device, for example /dev/ibmvmc, | ||
109 | which provides interfaces to open, close, read, write, and perform | ||
110 | ioctl’s against the VMC device. | ||
111 | |||
112 | VMC Interface Initialization | ||
113 | ---------------------------- | ||
114 | |||
115 | The device driver is responsible for initializing the VMC when the driver | ||
116 | is loaded. It first creates and initializes the CRQ. Next, an exchange of | ||
117 | VMC capabilities is performed to indicate the code version and number of | ||
118 | resources available in both the management partition and the hypervisor. | ||
119 | Finally, the hypervisor requests that the management partition create an | ||
120 | initial pool of VMC buffers, one buffer for each possible HMC connection, | ||
121 | which will be used for management application session initialization. | ||
122 | Prior to completion of this initialization sequence, the device returns | ||
123 | EBUSY to open() calls. EIO is returned for all open() failures. | ||
124 | |||
125 | :: | ||
126 | |||
127 | Management Partition Hypervisor | ||
128 | CRQ INIT | ||
129 | ----------------------------------------> | ||
130 | CRQ INIT COMPLETE | ||
131 | <---------------------------------------- | ||
132 | CAPABILITIES | ||
133 | ----------------------------------------> | ||
134 | CAPABILITIES RESPONSE | ||
135 | <---------------------------------------- | ||
136 | ADD BUFFER (HMC IDX=0,1,..) _ | ||
137 | <---------------------------------------- | | ||
138 | ADD BUFFER RESPONSE | - Perform # HMCs Iterations | ||
139 | ----------------------------------------> - | ||
140 | |||
141 | VMC Interface Open | ||
142 | ------------------ | ||
143 | |||
144 | After the basic VMC channel has been initialized, an HMC session level | ||
145 | connection can be established. The application layer performs an open() to | ||
146 | the VMC device and executes an ioctl() against it, indicating the HMC ID | ||
147 | (32 bytes of data) for this session. If the VMC device is in an invalid | ||
148 | state, EIO will be returned for the ioctl(). The device driver creates a | ||
149 | new HMC session value (ranging from 1 to 255) and HMC index value (starting | ||
150 | at index 0 and ranging to 254) for this HMC ID. The driver then does an | ||
151 | RDMA of the HMC ID to the hypervisor, and then sends an Interface Open | ||
152 | message to the hypervisor to establish the session over the VMC. After the | ||
153 | hypervisor receives this information, it sends Add Buffer messages to the | ||
154 | management partition to seed an initial pool of buffers for the new HMC | ||
155 | connection. Finally, the hypervisor sends an Interface Open Response | ||
156 | message, to indicate that it is ready for normal runtime messaging. The | ||
157 | following illustrates this VMC flow: | ||
158 | |||
159 | :: | ||
160 | |||
161 | Management Partition Hypervisor | ||
162 | RDMA HMC ID | ||
163 | ----------------------------------------> | ||
164 | Interface Open | ||
165 | ----------------------------------------> | ||
166 | Add Buffer _ | ||
167 | <---------------------------------------- | | ||
168 | Add Buffer Response | - Perform N Iterations | ||
169 | ----------------------------------------> - | ||
170 | Interface Open Response | ||
171 | <---------------------------------------- | ||
172 | |||
173 | VMC Interface Runtime | ||
174 | --------------------- | ||
175 | |||
176 | During normal runtime, the management application and the hypervisor | ||
177 | exchange HMC messages via the Signal VMC message and RDMA operations. When | ||
178 | sending data to the hypervisor, the management application performs a | ||
179 | write() to the VMC device, and the driver RDMA’s the data to the hypervisor | ||
180 | and then sends a Signal Message. If a write() is attempted before VMC | ||
181 | device buffers have been made available by the hypervisor, or no buffers | ||
182 | are currently available, EBUSY is returned in response to the write(). A | ||
183 | write() will return EIO for all other errors, such as an invalid device | ||
184 | state. When the hypervisor sends a message to the management, the data is | ||
185 | put into a VMC buffer and an Signal Message is sent to the VMC driver in | ||
186 | the management partition. The driver RDMA’s the buffer into the partition | ||
187 | and passes the data up to the appropriate management application via a | ||
188 | read() to the VMC device. The read() request blocks if there is no buffer | ||
189 | available to read. The management application may use select() to wait for | ||
190 | the VMC device to become ready with data to read. | ||
191 | |||
192 | :: | ||
193 | |||
194 | Management Partition Hypervisor | ||
195 | MSG RDMA | ||
196 | ----------------------------------------> | ||
197 | SIGNAL MSG | ||
198 | ----------------------------------------> | ||
199 | SIGNAL MSG | ||
200 | <---------------------------------------- | ||
201 | MSG RDMA | ||
202 | <---------------------------------------- | ||
203 | |||
204 | VMC Interface Close | ||
205 | ------------------- | ||
206 | |||
207 | HMC session level connections are closed by the management partition when | ||
208 | the application layer performs a close() against the device. This action | ||
209 | results in an Interface Close message flowing to the hypervisor, which | ||
210 | causes the session to be terminated. The device driver must free any | ||
211 | storage allocated for buffers for this HMC connection. | ||
212 | |||
213 | :: | ||
214 | |||
215 | Management Partition Hypervisor | ||
216 | INTERFACE CLOSE | ||
217 | ----------------------------------------> | ||
218 | INTERFACE CLOSE RESPONSE | ||
219 | <---------------------------------------- | ||
220 | |||
221 | Additional Information | ||
222 | ====================== | ||
223 | |||
224 | For more information on the documentation for CRQ Messages, VMC Messages, | ||
225 | HMC interface Buffers, and signal messages please refer to the Linux on | ||
226 | Power Architecture Platform Reference. Section F. | ||
diff --git a/Documentation/trace/coresight-cpu-debug.txt b/Documentation/trace/coresight-cpu-debug.txt index 2b9b51cd501e..89ab09e78e8d 100644 --- a/Documentation/trace/coresight-cpu-debug.txt +++ b/Documentation/trace/coresight-cpu-debug.txt | |||
@@ -177,11 +177,11 @@ Here is an example of the debugging output format: | |||
177 | ARM external debug module: | 177 | ARM external debug module: |
178 | coresight-cpu-debug 850000.debug: CPU[0]: | 178 | coresight-cpu-debug 850000.debug: CPU[0]: |
179 | coresight-cpu-debug 850000.debug: EDPRSR: 00000001 (Power:On DLK:Unlock) | 179 | coresight-cpu-debug 850000.debug: EDPRSR: 00000001 (Power:On DLK:Unlock) |
180 | coresight-cpu-debug 850000.debug: EDPCSR: [<ffff00000808e9bc>] handle_IPI+0x174/0x1d8 | 180 | coresight-cpu-debug 850000.debug: EDPCSR: handle_IPI+0x174/0x1d8 |
181 | coresight-cpu-debug 850000.debug: EDCIDSR: 00000000 | 181 | coresight-cpu-debug 850000.debug: EDCIDSR: 00000000 |
182 | coresight-cpu-debug 850000.debug: EDVIDSR: 90000000 (State:Non-secure Mode:EL1/0 Width:64bits VMID:0) | 182 | coresight-cpu-debug 850000.debug: EDVIDSR: 90000000 (State:Non-secure Mode:EL1/0 Width:64bits VMID:0) |
183 | coresight-cpu-debug 852000.debug: CPU[1]: | 183 | coresight-cpu-debug 852000.debug: CPU[1]: |
184 | coresight-cpu-debug 852000.debug: EDPRSR: 00000001 (Power:On DLK:Unlock) | 184 | coresight-cpu-debug 852000.debug: EDPRSR: 00000001 (Power:On DLK:Unlock) |
185 | coresight-cpu-debug 852000.debug: EDPCSR: [<ffff0000087fab34>] debug_notifier_call+0x23c/0x358 | 185 | coresight-cpu-debug 852000.debug: EDPCSR: debug_notifier_call+0x23c/0x358 |
186 | coresight-cpu-debug 852000.debug: EDCIDSR: 00000000 | 186 | coresight-cpu-debug 852000.debug: EDCIDSR: 00000000 |
187 | coresight-cpu-debug 852000.debug: EDVIDSR: 90000000 (State:Non-secure Mode:EL1/0 Width:64bits VMID:0) | 187 | coresight-cpu-debug 852000.debug: EDVIDSR: 90000000 (State:Non-secure Mode:EL1/0 Width:64bits VMID:0) |
diff --git a/MAINTAINERS b/MAINTAINERS index 756cbfaad7f9..5c374d97c967 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -5586,6 +5586,7 @@ S: Maintained | |||
5586 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/atull/linux-fpga.git | 5586 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/atull/linux-fpga.git |
5587 | Q: http://patchwork.kernel.org/project/linux-fpga/list/ | 5587 | Q: http://patchwork.kernel.org/project/linux-fpga/list/ |
5588 | F: Documentation/fpga/ | 5588 | F: Documentation/fpga/ |
5589 | F: Documentation/driver-api/fpga/ | ||
5589 | F: Documentation/devicetree/bindings/fpga/ | 5590 | F: Documentation/devicetree/bindings/fpga/ |
5590 | F: drivers/fpga/ | 5591 | F: drivers/fpga/ |
5591 | F: include/linux/fpga/ | 5592 | F: include/linux/fpga/ |
@@ -6773,6 +6774,12 @@ L: linux-scsi@vger.kernel.org | |||
6773 | S: Supported | 6774 | S: Supported |
6774 | F: drivers/scsi/ibmvscsi/ibmvfc* | 6775 | F: drivers/scsi/ibmvscsi/ibmvfc* |
6775 | 6776 | ||
6777 | IBM Power Virtual Management Channel Driver | ||
6778 | M: Bryant G. Ly <bryantly@linux.vnet.ibm.com> | ||
6779 | M: Steven Royer <seroyer@linux.vnet.ibm.com> | ||
6780 | S: Supported | ||
6781 | F: drivers/misc/ibmvmc.* | ||
6782 | |||
6776 | IBM Power Virtual SCSI Device Drivers | 6783 | IBM Power Virtual SCSI Device Drivers |
6777 | M: Tyrel Datwyler <tyreld@linux.vnet.ibm.com> | 6784 | M: Tyrel Datwyler <tyreld@linux.vnet.ibm.com> |
6778 | L: linux-scsi@vger.kernel.org | 6785 | L: linux-scsi@vger.kernel.org |
@@ -13136,7 +13143,7 @@ F: include/uapi/sound/ | |||
13136 | F: sound/ | 13143 | F: sound/ |
13137 | 13144 | ||
13138 | SOUND - COMPRESSED AUDIO | 13145 | SOUND - COMPRESSED AUDIO |
13139 | M: Vinod Koul <vinod.koul@intel.com> | 13146 | M: Vinod Koul <vkoul@kernel.org> |
13140 | L: alsa-devel@alsa-project.org (moderated for non-subscribers) | 13147 | L: alsa-devel@alsa-project.org (moderated for non-subscribers) |
13141 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git | 13148 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git |
13142 | S: Supported | 13149 | S: Supported |
diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h index 2e2dddab5d65..662c8347d699 100644 --- a/arch/powerpc/include/asm/hvcall.h +++ b/arch/powerpc/include/asm/hvcall.h | |||
@@ -279,6 +279,7 @@ | |||
279 | #define H_GET_MPP_X 0x314 | 279 | #define H_GET_MPP_X 0x314 |
280 | #define H_SET_MODE 0x31C | 280 | #define H_SET_MODE 0x31C |
281 | #define H_CLEAR_HPT 0x358 | 281 | #define H_CLEAR_HPT 0x358 |
282 | #define H_REQUEST_VMC 0x360 | ||
282 | #define H_RESIZE_HPT_PREPARE 0x36C | 283 | #define H_RESIZE_HPT_PREPARE 0x36C |
283 | #define H_RESIZE_HPT_COMMIT 0x370 | 284 | #define H_RESIZE_HPT_COMMIT 0x370 |
284 | #define H_REGISTER_PROC_TBL 0x37C | 285 | #define H_REGISTER_PROC_TBL 0x37C |
diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c index 0cf51d57e4ae..3ece711a6a17 100644 --- a/drivers/amba/bus.c +++ b/drivers/amba/bus.c | |||
@@ -102,8 +102,8 @@ static ssize_t driver_override_store(struct device *_dev, | |||
102 | if (strlen(driver_override)) { | 102 | if (strlen(driver_override)) { |
103 | dev->driver_override = driver_override; | 103 | dev->driver_override = driver_override; |
104 | } else { | 104 | } else { |
105 | kfree(driver_override); | 105 | kfree(driver_override); |
106 | dev->driver_override = NULL; | 106 | dev->driver_override = NULL; |
107 | } | 107 | } |
108 | device_unlock(_dev); | 108 | device_unlock(_dev); |
109 | 109 | ||
diff --git a/drivers/android/Kconfig b/drivers/android/Kconfig index 7dce3795b887..ee4880bfdcdc 100644 --- a/drivers/android/Kconfig +++ b/drivers/android/Kconfig | |||
@@ -10,7 +10,7 @@ if ANDROID | |||
10 | 10 | ||
11 | config ANDROID_BINDER_IPC | 11 | config ANDROID_BINDER_IPC |
12 | bool "Android Binder IPC Driver" | 12 | bool "Android Binder IPC Driver" |
13 | depends on MMU | 13 | depends on MMU && !M68K |
14 | default n | 14 | default n |
15 | ---help--- | 15 | ---help--- |
16 | Binder is used in Android for both communication between processes, | 16 | Binder is used in Android for both communication between processes, |
@@ -32,19 +32,6 @@ config ANDROID_BINDER_DEVICES | |||
32 | created. Each binder device has its own context manager, and is | 32 | created. Each binder device has its own context manager, and is |
33 | therefore logically separated from the other devices. | 33 | therefore logically separated from the other devices. |
34 | 34 | ||
35 | config ANDROID_BINDER_IPC_32BIT | ||
36 | bool "Use old (Android 4.4 and earlier) 32-bit binder API" | ||
37 | depends on !64BIT && ANDROID_BINDER_IPC | ||
38 | default y | ||
39 | ---help--- | ||
40 | The Binder API has been changed to support both 32 and 64bit | ||
41 | applications in a mixed environment. | ||
42 | |||
43 | Enable this to support an old 32-bit Android user-space (v4.4 and | ||
44 | earlier). | ||
45 | |||
46 | Note that enabling this will break newer Android user-space. | ||
47 | |||
48 | config ANDROID_BINDER_IPC_SELFTEST | 35 | config ANDROID_BINDER_IPC_SELFTEST |
49 | bool "Android Binder IPC Driver Selftest" | 36 | bool "Android Binder IPC Driver Selftest" |
50 | depends on ANDROID_BINDER_IPC | 37 | depends on ANDROID_BINDER_IPC |
diff --git a/drivers/android/binder.c b/drivers/android/binder.c index e578eee31589..95283f3bb51c 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c | |||
@@ -72,10 +72,6 @@ | |||
72 | #include <linux/security.h> | 72 | #include <linux/security.h> |
73 | #include <linux/spinlock.h> | 73 | #include <linux/spinlock.h> |
74 | 74 | ||
75 | #ifdef CONFIG_ANDROID_BINDER_IPC_32BIT | ||
76 | #define BINDER_IPC_32BIT 1 | ||
77 | #endif | ||
78 | |||
79 | #include <uapi/linux/android/binder.h> | 75 | #include <uapi/linux/android/binder.h> |
80 | #include "binder_alloc.h" | 76 | #include "binder_alloc.h" |
81 | #include "binder_trace.h" | 77 | #include "binder_trace.h" |
@@ -2058,8 +2054,8 @@ static size_t binder_validate_object(struct binder_buffer *buffer, u64 offset) | |||
2058 | struct binder_object_header *hdr; | 2054 | struct binder_object_header *hdr; |
2059 | size_t object_size = 0; | 2055 | size_t object_size = 0; |
2060 | 2056 | ||
2061 | if (offset > buffer->data_size - sizeof(*hdr) || | 2057 | if (buffer->data_size < sizeof(*hdr) || |
2062 | buffer->data_size < sizeof(*hdr) || | 2058 | offset > buffer->data_size - sizeof(*hdr) || |
2063 | !IS_ALIGNED(offset, sizeof(u32))) | 2059 | !IS_ALIGNED(offset, sizeof(u32))) |
2064 | return 0; | 2060 | return 0; |
2065 | 2061 | ||
@@ -3925,10 +3921,11 @@ retry: | |||
3925 | binder_inner_proc_unlock(proc); | 3921 | binder_inner_proc_unlock(proc); |
3926 | if (put_user(e->cmd, (uint32_t __user *)ptr)) | 3922 | if (put_user(e->cmd, (uint32_t __user *)ptr)) |
3927 | return -EFAULT; | 3923 | return -EFAULT; |
3924 | cmd = e->cmd; | ||
3928 | e->cmd = BR_OK; | 3925 | e->cmd = BR_OK; |
3929 | ptr += sizeof(uint32_t); | 3926 | ptr += sizeof(uint32_t); |
3930 | 3927 | ||
3931 | binder_stat_br(proc, thread, e->cmd); | 3928 | binder_stat_br(proc, thread, cmd); |
3932 | } break; | 3929 | } break; |
3933 | case BINDER_WORK_TRANSACTION_COMPLETE: { | 3930 | case BINDER_WORK_TRANSACTION_COMPLETE: { |
3934 | binder_inner_proc_unlock(proc); | 3931 | binder_inner_proc_unlock(proc); |
@@ -4696,7 +4693,7 @@ static void binder_vma_close(struct vm_area_struct *vma) | |||
4696 | binder_defer_work(proc, BINDER_DEFERRED_PUT_FILES); | 4693 | binder_defer_work(proc, BINDER_DEFERRED_PUT_FILES); |
4697 | } | 4694 | } |
4698 | 4695 | ||
4699 | static int binder_vm_fault(struct vm_fault *vmf) | 4696 | static vm_fault_t binder_vm_fault(struct vm_fault *vmf) |
4700 | { | 4697 | { |
4701 | return VM_FAULT_SIGBUS; | 4698 | return VM_FAULT_SIGBUS; |
4702 | } | 4699 | } |
@@ -4730,7 +4727,9 @@ static int binder_mmap(struct file *filp, struct vm_area_struct *vma) | |||
4730 | failure_string = "bad vm_flags"; | 4727 | failure_string = "bad vm_flags"; |
4731 | goto err_bad_arg; | 4728 | goto err_bad_arg; |
4732 | } | 4729 | } |
4733 | vma->vm_flags = (vma->vm_flags | VM_DONTCOPY) & ~VM_MAYWRITE; | 4730 | vma->vm_flags |= VM_DONTCOPY | VM_MIXEDMAP; |
4731 | vma->vm_flags &= ~VM_MAYWRITE; | ||
4732 | |||
4734 | vma->vm_ops = &binder_vm_ops; | 4733 | vma->vm_ops = &binder_vm_ops; |
4735 | vma->vm_private_data = proc; | 4734 | vma->vm_private_data = proc; |
4736 | 4735 | ||
diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c index 5a426c877dfb..4f382d51def1 100644 --- a/drivers/android/binder_alloc.c +++ b/drivers/android/binder_alloc.c | |||
@@ -219,7 +219,7 @@ static int binder_update_page_range(struct binder_alloc *alloc, int allocate, | |||
219 | mm = alloc->vma_vm_mm; | 219 | mm = alloc->vma_vm_mm; |
220 | 220 | ||
221 | if (mm) { | 221 | if (mm) { |
222 | down_write(&mm->mmap_sem); | 222 | down_read(&mm->mmap_sem); |
223 | vma = alloc->vma; | 223 | vma = alloc->vma; |
224 | } | 224 | } |
225 | 225 | ||
@@ -288,7 +288,7 @@ static int binder_update_page_range(struct binder_alloc *alloc, int allocate, | |||
288 | /* vm_insert_page does not seem to increment the refcount */ | 288 | /* vm_insert_page does not seem to increment the refcount */ |
289 | } | 289 | } |
290 | if (mm) { | 290 | if (mm) { |
291 | up_write(&mm->mmap_sem); | 291 | up_read(&mm->mmap_sem); |
292 | mmput(mm); | 292 | mmput(mm); |
293 | } | 293 | } |
294 | return 0; | 294 | return 0; |
@@ -321,7 +321,7 @@ err_page_ptr_cleared: | |||
321 | } | 321 | } |
322 | err_no_vma: | 322 | err_no_vma: |
323 | if (mm) { | 323 | if (mm) { |
324 | up_write(&mm->mmap_sem); | 324 | up_read(&mm->mmap_sem); |
325 | mmput(mm); | 325 | mmput(mm); |
326 | } | 326 | } |
327 | return vma ? -ENOMEM : -ESRCH; | 327 | return vma ? -ENOMEM : -ESRCH; |
diff --git a/drivers/char/mspec.c b/drivers/char/mspec.c index 7b75669d3670..058876b55b09 100644 --- a/drivers/char/mspec.c +++ b/drivers/char/mspec.c | |||
@@ -191,7 +191,7 @@ mspec_close(struct vm_area_struct *vma) | |||
191 | * | 191 | * |
192 | * Creates a mspec page and maps it to user space. | 192 | * Creates a mspec page and maps it to user space. |
193 | */ | 193 | */ |
194 | static int | 194 | static vm_fault_t |
195 | mspec_fault(struct vm_fault *vmf) | 195 | mspec_fault(struct vm_fault *vmf) |
196 | { | 196 | { |
197 | unsigned long paddr, maddr; | 197 | unsigned long paddr, maddr; |
@@ -223,14 +223,7 @@ mspec_fault(struct vm_fault *vmf) | |||
223 | 223 | ||
224 | pfn = paddr >> PAGE_SHIFT; | 224 | pfn = paddr >> PAGE_SHIFT; |
225 | 225 | ||
226 | /* | 226 | return vmf_insert_pfn(vmf->vma, vmf->address, pfn); |
227 | * vm_insert_pfn can fail with -EBUSY, but in that case it will | ||
228 | * be because another thread has installed the pte first, so it | ||
229 | * is no problem. | ||
230 | */ | ||
231 | vm_insert_pfn(vmf->vma, vmf->address, pfn); | ||
232 | |||
233 | return VM_FAULT_NOPAGE; | ||
234 | } | 227 | } |
235 | 228 | ||
236 | static const struct vm_operations_struct mspec_vm_ops = { | 229 | static const struct vm_operations_struct mspec_vm_ops = { |
diff --git a/drivers/firmware/google/Kconfig b/drivers/firmware/google/Kconfig index f16b381a569c..a456a000048b 100644 --- a/drivers/firmware/google/Kconfig +++ b/drivers/firmware/google/Kconfig | |||
@@ -55,6 +55,14 @@ config GOOGLE_MEMCONSOLE_X86_LEGACY | |||
55 | the EBDA on Google servers. If found, this log is exported to | 55 | the EBDA on Google servers. If found, this log is exported to |
56 | userland in the file /sys/firmware/log. | 56 | userland in the file /sys/firmware/log. |
57 | 57 | ||
58 | config GOOGLE_FRAMEBUFFER_COREBOOT | ||
59 | tristate "Coreboot Framebuffer" | ||
60 | depends on FB_SIMPLE | ||
61 | depends on GOOGLE_COREBOOT_TABLE | ||
62 | help | ||
63 | This option enables the kernel to search for a framebuffer in | ||
64 | the coreboot table. If found, it is registered with simplefb. | ||
65 | |||
58 | config GOOGLE_MEMCONSOLE_COREBOOT | 66 | config GOOGLE_MEMCONSOLE_COREBOOT |
59 | tristate "Firmware Memory Console" | 67 | tristate "Firmware Memory Console" |
60 | depends on GOOGLE_COREBOOT_TABLE | 68 | depends on GOOGLE_COREBOOT_TABLE |
diff --git a/drivers/firmware/google/Makefile b/drivers/firmware/google/Makefile index dcd3675efcfc..d0b3fba96194 100644 --- a/drivers/firmware/google/Makefile +++ b/drivers/firmware/google/Makefile | |||
@@ -4,6 +4,7 @@ obj-$(CONFIG_GOOGLE_SMI) += gsmi.o | |||
4 | obj-$(CONFIG_GOOGLE_COREBOOT_TABLE) += coreboot_table.o | 4 | obj-$(CONFIG_GOOGLE_COREBOOT_TABLE) += coreboot_table.o |
5 | obj-$(CONFIG_GOOGLE_COREBOOT_TABLE_ACPI) += coreboot_table-acpi.o | 5 | obj-$(CONFIG_GOOGLE_COREBOOT_TABLE_ACPI) += coreboot_table-acpi.o |
6 | obj-$(CONFIG_GOOGLE_COREBOOT_TABLE_OF) += coreboot_table-of.o | 6 | obj-$(CONFIG_GOOGLE_COREBOOT_TABLE_OF) += coreboot_table-of.o |
7 | obj-$(CONFIG_GOOGLE_FRAMEBUFFER_COREBOOT) += framebuffer-coreboot.o | ||
7 | obj-$(CONFIG_GOOGLE_MEMCONSOLE) += memconsole.o | 8 | obj-$(CONFIG_GOOGLE_MEMCONSOLE) += memconsole.o |
8 | obj-$(CONFIG_GOOGLE_MEMCONSOLE_COREBOOT) += memconsole-coreboot.o | 9 | obj-$(CONFIG_GOOGLE_MEMCONSOLE_COREBOOT) += memconsole-coreboot.o |
9 | obj-$(CONFIG_GOOGLE_MEMCONSOLE_X86_LEGACY) += memconsole-x86-legacy.o | 10 | obj-$(CONFIG_GOOGLE_MEMCONSOLE_X86_LEGACY) += memconsole-x86-legacy.o |
diff --git a/drivers/firmware/google/coreboot_table-acpi.c b/drivers/firmware/google/coreboot_table-acpi.c index fb98db2d20e2..77197fe3d42f 100644 --- a/drivers/firmware/google/coreboot_table-acpi.c +++ b/drivers/firmware/google/coreboot_table-acpi.c | |||
@@ -53,7 +53,7 @@ static int coreboot_table_acpi_probe(struct platform_device *pdev) | |||
53 | if (!ptr) | 53 | if (!ptr) |
54 | return -ENOMEM; | 54 | return -ENOMEM; |
55 | 55 | ||
56 | return coreboot_table_init(ptr); | 56 | return coreboot_table_init(&pdev->dev, ptr); |
57 | } | 57 | } |
58 | 58 | ||
59 | static int coreboot_table_acpi_remove(struct platform_device *pdev) | 59 | static int coreboot_table_acpi_remove(struct platform_device *pdev) |
diff --git a/drivers/firmware/google/coreboot_table-of.c b/drivers/firmware/google/coreboot_table-of.c index 727acdc83e83..f15bf404c579 100644 --- a/drivers/firmware/google/coreboot_table-of.c +++ b/drivers/firmware/google/coreboot_table-of.c | |||
@@ -34,7 +34,7 @@ static int coreboot_table_of_probe(struct platform_device *pdev) | |||
34 | if (!ptr) | 34 | if (!ptr) |
35 | return -ENOMEM; | 35 | return -ENOMEM; |
36 | 36 | ||
37 | return coreboot_table_init(ptr); | 37 | return coreboot_table_init(&pdev->dev, ptr); |
38 | } | 38 | } |
39 | 39 | ||
40 | static int coreboot_table_of_remove(struct platform_device *pdev) | 40 | static int coreboot_table_of_remove(struct platform_device *pdev) |
diff --git a/drivers/firmware/google/coreboot_table.c b/drivers/firmware/google/coreboot_table.c index 0019d3ec18dd..19db5709ae28 100644 --- a/drivers/firmware/google/coreboot_table.c +++ b/drivers/firmware/google/coreboot_table.c | |||
@@ -4,6 +4,7 @@ | |||
4 | * Module providing coreboot table access. | 4 | * Module providing coreboot table access. |
5 | * | 5 | * |
6 | * Copyright 2017 Google Inc. | 6 | * Copyright 2017 Google Inc. |
7 | * Copyright 2017 Samuel Holland <samuel@sholland.org> | ||
7 | * | 8 | * |
8 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License v2.0 as published by | 10 | * it under the terms of the GNU General Public License v2.0 as published by |
@@ -15,37 +16,96 @@ | |||
15 | * GNU General Public License for more details. | 16 | * GNU General Public License for more details. |
16 | */ | 17 | */ |
17 | 18 | ||
19 | #include <linux/device.h> | ||
18 | #include <linux/err.h> | 20 | #include <linux/err.h> |
19 | #include <linux/init.h> | 21 | #include <linux/init.h> |
20 | #include <linux/io.h> | 22 | #include <linux/io.h> |
21 | #include <linux/kernel.h> | 23 | #include <linux/kernel.h> |
22 | #include <linux/module.h> | 24 | #include <linux/module.h> |
25 | #include <linux/slab.h> | ||
23 | 26 | ||
24 | #include "coreboot_table.h" | 27 | #include "coreboot_table.h" |
25 | 28 | ||
26 | struct coreboot_table_entry { | 29 | #define CB_DEV(d) container_of(d, struct coreboot_device, dev) |
27 | u32 tag; | 30 | #define CB_DRV(d) container_of(d, struct coreboot_driver, drv) |
28 | u32 size; | ||
29 | }; | ||
30 | 31 | ||
31 | static struct coreboot_table_header __iomem *ptr_header; | 32 | static struct coreboot_table_header __iomem *ptr_header; |
32 | 33 | ||
33 | /* | 34 | static int coreboot_bus_match(struct device *dev, struct device_driver *drv) |
34 | * This function parses the coreboot table for an entry that contains the base | ||
35 | * address of the given entry tag. The coreboot table consists of a header | ||
36 | * directly followed by a number of small, variable-sized entries, which each | ||
37 | * contain an identifying tag and their length as the first two fields. | ||
38 | */ | ||
39 | int coreboot_table_find(int tag, void *data, size_t data_size) | ||
40 | { | 35 | { |
41 | struct coreboot_table_header header; | 36 | struct coreboot_device *device = CB_DEV(dev); |
42 | struct coreboot_table_entry entry; | 37 | struct coreboot_driver *driver = CB_DRV(drv); |
43 | void *ptr_entry; | ||
44 | int i; | ||
45 | 38 | ||
46 | if (!ptr_header) | 39 | return device->entry.tag == driver->tag; |
47 | return -EPROBE_DEFER; | 40 | } |
48 | 41 | ||
42 | static int coreboot_bus_probe(struct device *dev) | ||
43 | { | ||
44 | int ret = -ENODEV; | ||
45 | struct coreboot_device *device = CB_DEV(dev); | ||
46 | struct coreboot_driver *driver = CB_DRV(dev->driver); | ||
47 | |||
48 | if (driver->probe) | ||
49 | ret = driver->probe(device); | ||
50 | |||
51 | return ret; | ||
52 | } | ||
53 | |||
54 | static int coreboot_bus_remove(struct device *dev) | ||
55 | { | ||
56 | int ret = 0; | ||
57 | struct coreboot_device *device = CB_DEV(dev); | ||
58 | struct coreboot_driver *driver = CB_DRV(dev->driver); | ||
59 | |||
60 | if (driver->remove) | ||
61 | ret = driver->remove(device); | ||
62 | |||
63 | return ret; | ||
64 | } | ||
65 | |||
66 | static struct bus_type coreboot_bus_type = { | ||
67 | .name = "coreboot", | ||
68 | .match = coreboot_bus_match, | ||
69 | .probe = coreboot_bus_probe, | ||
70 | .remove = coreboot_bus_remove, | ||
71 | }; | ||
72 | |||
73 | static int __init coreboot_bus_init(void) | ||
74 | { | ||
75 | return bus_register(&coreboot_bus_type); | ||
76 | } | ||
77 | module_init(coreboot_bus_init); | ||
78 | |||
79 | static void coreboot_device_release(struct device *dev) | ||
80 | { | ||
81 | struct coreboot_device *device = CB_DEV(dev); | ||
82 | |||
83 | kfree(device); | ||
84 | } | ||
85 | |||
86 | int coreboot_driver_register(struct coreboot_driver *driver) | ||
87 | { | ||
88 | driver->drv.bus = &coreboot_bus_type; | ||
89 | |||
90 | return driver_register(&driver->drv); | ||
91 | } | ||
92 | EXPORT_SYMBOL(coreboot_driver_register); | ||
93 | |||
94 | void coreboot_driver_unregister(struct coreboot_driver *driver) | ||
95 | { | ||
96 | driver_unregister(&driver->drv); | ||
97 | } | ||
98 | EXPORT_SYMBOL(coreboot_driver_unregister); | ||
99 | |||
100 | int coreboot_table_init(struct device *dev, void __iomem *ptr) | ||
101 | { | ||
102 | int i, ret; | ||
103 | void *ptr_entry; | ||
104 | struct coreboot_device *device; | ||
105 | struct coreboot_table_entry entry; | ||
106 | struct coreboot_table_header header; | ||
107 | |||
108 | ptr_header = ptr; | ||
49 | memcpy_fromio(&header, ptr_header, sizeof(header)); | 109 | memcpy_fromio(&header, ptr_header, sizeof(header)); |
50 | 110 | ||
51 | if (strncmp(header.signature, "LBIO", sizeof(header.signature))) { | 111 | if (strncmp(header.signature, "LBIO", sizeof(header.signature))) { |
@@ -54,37 +114,41 @@ int coreboot_table_find(int tag, void *data, size_t data_size) | |||
54 | } | 114 | } |
55 | 115 | ||
56 | ptr_entry = (void *)ptr_header + header.header_bytes; | 116 | ptr_entry = (void *)ptr_header + header.header_bytes; |
57 | |||
58 | for (i = 0; i < header.table_entries; i++) { | 117 | for (i = 0; i < header.table_entries; i++) { |
59 | memcpy_fromio(&entry, ptr_entry, sizeof(entry)); | 118 | memcpy_fromio(&entry, ptr_entry, sizeof(entry)); |
60 | if (entry.tag == tag) { | ||
61 | if (data_size < entry.size) | ||
62 | return -EINVAL; | ||
63 | 119 | ||
64 | memcpy_fromio(data, ptr_entry, entry.size); | 120 | device = kzalloc(sizeof(struct device) + entry.size, GFP_KERNEL); |
121 | if (!device) { | ||
122 | ret = -ENOMEM; | ||
123 | break; | ||
124 | } | ||
125 | |||
126 | dev_set_name(&device->dev, "coreboot%d", i); | ||
127 | device->dev.parent = dev; | ||
128 | device->dev.bus = &coreboot_bus_type; | ||
129 | device->dev.release = coreboot_device_release; | ||
130 | memcpy_fromio(&device->entry, ptr_entry, entry.size); | ||
65 | 131 | ||
66 | return 0; | 132 | ret = device_register(&device->dev); |
133 | if (ret) { | ||
134 | put_device(&device->dev); | ||
135 | break; | ||
67 | } | 136 | } |
68 | 137 | ||
69 | ptr_entry += entry.size; | 138 | ptr_entry += entry.size; |
70 | } | 139 | } |
71 | 140 | ||
72 | return -ENOENT; | 141 | return ret; |
73 | } | ||
74 | EXPORT_SYMBOL(coreboot_table_find); | ||
75 | |||
76 | int coreboot_table_init(void __iomem *ptr) | ||
77 | { | ||
78 | ptr_header = ptr; | ||
79 | |||
80 | return 0; | ||
81 | } | 142 | } |
82 | EXPORT_SYMBOL(coreboot_table_init); | 143 | EXPORT_SYMBOL(coreboot_table_init); |
83 | 144 | ||
84 | int coreboot_table_exit(void) | 145 | int coreboot_table_exit(void) |
85 | { | 146 | { |
86 | if (ptr_header) | 147 | if (ptr_header) { |
148 | bus_unregister(&coreboot_bus_type); | ||
87 | iounmap(ptr_header); | 149 | iounmap(ptr_header); |
150 | ptr_header = NULL; | ||
151 | } | ||
88 | 152 | ||
89 | return 0; | 153 | return 0; |
90 | } | 154 | } |
diff --git a/drivers/firmware/google/coreboot_table.h b/drivers/firmware/google/coreboot_table.h index 6eff1ae0c5d3..8ad95a94481b 100644 --- a/drivers/firmware/google/coreboot_table.h +++ b/drivers/firmware/google/coreboot_table.h | |||
@@ -3,7 +3,9 @@ | |||
3 | * | 3 | * |
4 | * Internal header for coreboot table access. | 4 | * Internal header for coreboot table access. |
5 | * | 5 | * |
6 | * Copyright 2014 Gerd Hoffmann <kraxel@redhat.com> | ||
6 | * Copyright 2017 Google Inc. | 7 | * Copyright 2017 Google Inc. |
8 | * Copyright 2017 Samuel Holland <samuel@sholland.org> | ||
7 | * | 9 | * |
8 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License v2.0 as published by | 11 | * it under the terms of the GNU General Public License v2.0 as published by |
@@ -20,14 +22,6 @@ | |||
20 | 22 | ||
21 | #include <linux/io.h> | 23 | #include <linux/io.h> |
22 | 24 | ||
23 | /* List of coreboot entry structures that is used */ | ||
24 | struct lb_cbmem_ref { | ||
25 | uint32_t tag; | ||
26 | uint32_t size; | ||
27 | |||
28 | uint64_t cbmem_addr; | ||
29 | }; | ||
30 | |||
31 | /* Coreboot table header structure */ | 25 | /* Coreboot table header structure */ |
32 | struct coreboot_table_header { | 26 | struct coreboot_table_header { |
33 | char signature[4]; | 27 | char signature[4]; |
@@ -38,11 +32,67 @@ struct coreboot_table_header { | |||
38 | u32 table_entries; | 32 | u32 table_entries; |
39 | }; | 33 | }; |
40 | 34 | ||
41 | /* Retrieve coreboot table entry with tag *tag* and copy it to data */ | 35 | /* List of coreboot entry structures that is used */ |
42 | int coreboot_table_find(int tag, void *data, size_t data_size); | 36 | /* Generic */ |
37 | struct coreboot_table_entry { | ||
38 | u32 tag; | ||
39 | u32 size; | ||
40 | }; | ||
41 | |||
42 | /* Points to a CBMEM entry */ | ||
43 | struct lb_cbmem_ref { | ||
44 | u32 tag; | ||
45 | u32 size; | ||
46 | |||
47 | u64 cbmem_addr; | ||
48 | }; | ||
49 | |||
50 | /* Describes framebuffer setup by coreboot */ | ||
51 | struct lb_framebuffer { | ||
52 | u32 tag; | ||
53 | u32 size; | ||
54 | |||
55 | u64 physical_address; | ||
56 | u32 x_resolution; | ||
57 | u32 y_resolution; | ||
58 | u32 bytes_per_line; | ||
59 | u8 bits_per_pixel; | ||
60 | u8 red_mask_pos; | ||
61 | u8 red_mask_size; | ||
62 | u8 green_mask_pos; | ||
63 | u8 green_mask_size; | ||
64 | u8 blue_mask_pos; | ||
65 | u8 blue_mask_size; | ||
66 | u8 reserved_mask_pos; | ||
67 | u8 reserved_mask_size; | ||
68 | }; | ||
69 | |||
70 | /* A device, additionally with information from coreboot. */ | ||
71 | struct coreboot_device { | ||
72 | struct device dev; | ||
73 | union { | ||
74 | struct coreboot_table_entry entry; | ||
75 | struct lb_cbmem_ref cbmem_ref; | ||
76 | struct lb_framebuffer framebuffer; | ||
77 | }; | ||
78 | }; | ||
79 | |||
80 | /* A driver for handling devices described in coreboot tables. */ | ||
81 | struct coreboot_driver { | ||
82 | int (*probe)(struct coreboot_device *); | ||
83 | int (*remove)(struct coreboot_device *); | ||
84 | struct device_driver drv; | ||
85 | u32 tag; | ||
86 | }; | ||
87 | |||
88 | /* Register a driver that uses the data from a coreboot table. */ | ||
89 | int coreboot_driver_register(struct coreboot_driver *driver); | ||
90 | |||
91 | /* Unregister a driver that uses the data from a coreboot table. */ | ||
92 | void coreboot_driver_unregister(struct coreboot_driver *driver); | ||
43 | 93 | ||
44 | /* Initialize coreboot table module given a pointer to iomem */ | 94 | /* Initialize coreboot table module given a pointer to iomem */ |
45 | int coreboot_table_init(void __iomem *ptr); | 95 | int coreboot_table_init(struct device *dev, void __iomem *ptr); |
46 | 96 | ||
47 | /* Cleanup coreboot table module */ | 97 | /* Cleanup coreboot table module */ |
48 | int coreboot_table_exit(void); | 98 | int coreboot_table_exit(void); |
diff --git a/drivers/firmware/google/framebuffer-coreboot.c b/drivers/firmware/google/framebuffer-coreboot.c new file mode 100644 index 000000000000..b8b49c067157 --- /dev/null +++ b/drivers/firmware/google/framebuffer-coreboot.c | |||
@@ -0,0 +1,115 @@ | |||
1 | /* | ||
2 | * framebuffer-coreboot.c | ||
3 | * | ||
4 | * Memory based framebuffer accessed through coreboot table. | ||
5 | * | ||
6 | * Copyright 2012-2013 David Herrmann <dh.herrmann@gmail.com> | ||
7 | * Copyright 2017 Google Inc. | ||
8 | * Copyright 2017 Samuel Holland <samuel@sholland.org> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License v2.0 as published by | ||
12 | * the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | */ | ||
19 | |||
20 | #include <linux/device.h> | ||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/mm.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/platform_data/simplefb.h> | ||
25 | #include <linux/platform_device.h> | ||
26 | |||
27 | #include "coreboot_table.h" | ||
28 | |||
29 | #define CB_TAG_FRAMEBUFFER 0x12 | ||
30 | |||
31 | static const struct simplefb_format formats[] = SIMPLEFB_FORMATS; | ||
32 | |||
33 | static int framebuffer_probe(struct coreboot_device *dev) | ||
34 | { | ||
35 | int i; | ||
36 | u32 length; | ||
37 | struct lb_framebuffer *fb = &dev->framebuffer; | ||
38 | struct platform_device *pdev; | ||
39 | struct resource res; | ||
40 | struct simplefb_platform_data pdata = { | ||
41 | .width = fb->x_resolution, | ||
42 | .height = fb->y_resolution, | ||
43 | .stride = fb->bytes_per_line, | ||
44 | .format = NULL, | ||
45 | }; | ||
46 | |||
47 | for (i = 0; i < ARRAY_SIZE(formats); ++i) { | ||
48 | if (fb->bits_per_pixel == formats[i].bits_per_pixel && | ||
49 | fb->red_mask_pos == formats[i].red.offset && | ||
50 | fb->red_mask_size == formats[i].red.length && | ||
51 | fb->green_mask_pos == formats[i].green.offset && | ||
52 | fb->green_mask_size == formats[i].green.length && | ||
53 | fb->blue_mask_pos == formats[i].blue.offset && | ||
54 | fb->blue_mask_size == formats[i].blue.length && | ||
55 | fb->reserved_mask_pos == formats[i].transp.offset && | ||
56 | fb->reserved_mask_size == formats[i].transp.length) | ||
57 | pdata.format = formats[i].name; | ||
58 | } | ||
59 | if (!pdata.format) | ||
60 | return -ENODEV; | ||
61 | |||
62 | memset(&res, 0, sizeof(res)); | ||
63 | res.flags = IORESOURCE_MEM | IORESOURCE_BUSY; | ||
64 | res.name = "Coreboot Framebuffer"; | ||
65 | res.start = fb->physical_address; | ||
66 | length = PAGE_ALIGN(fb->y_resolution * fb->bytes_per_line); | ||
67 | res.end = res.start + length - 1; | ||
68 | if (res.end <= res.start) | ||
69 | return -EINVAL; | ||
70 | |||
71 | pdev = platform_device_register_resndata(&dev->dev, | ||
72 | "simple-framebuffer", 0, | ||
73 | &res, 1, &pdata, | ||
74 | sizeof(pdata)); | ||
75 | if (IS_ERR(pdev)) | ||
76 | pr_warn("coreboot: could not register framebuffer\n"); | ||
77 | else | ||
78 | dev_set_drvdata(&dev->dev, pdev); | ||
79 | |||
80 | return PTR_ERR_OR_ZERO(pdev); | ||
81 | } | ||
82 | |||
83 | static int framebuffer_remove(struct coreboot_device *dev) | ||
84 | { | ||
85 | struct platform_device *pdev = dev_get_drvdata(&dev->dev); | ||
86 | |||
87 | platform_device_unregister(pdev); | ||
88 | |||
89 | return 0; | ||
90 | } | ||
91 | |||
92 | static struct coreboot_driver framebuffer_driver = { | ||
93 | .probe = framebuffer_probe, | ||
94 | .remove = framebuffer_remove, | ||
95 | .drv = { | ||
96 | .name = "framebuffer", | ||
97 | }, | ||
98 | .tag = CB_TAG_FRAMEBUFFER, | ||
99 | }; | ||
100 | |||
101 | static int __init coreboot_framebuffer_init(void) | ||
102 | { | ||
103 | return coreboot_driver_register(&framebuffer_driver); | ||
104 | } | ||
105 | |||
106 | static void coreboot_framebuffer_exit(void) | ||
107 | { | ||
108 | coreboot_driver_unregister(&framebuffer_driver); | ||
109 | } | ||
110 | |||
111 | module_init(coreboot_framebuffer_init); | ||
112 | module_exit(coreboot_framebuffer_exit); | ||
113 | |||
114 | MODULE_AUTHOR("Samuel Holland <samuel@sholland.org>"); | ||
115 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/firmware/google/memconsole-coreboot.c b/drivers/firmware/google/memconsole-coreboot.c index 52738887735c..b29e10757bfb 100644 --- a/drivers/firmware/google/memconsole-coreboot.c +++ b/drivers/firmware/google/memconsole-coreboot.c | |||
@@ -15,9 +15,9 @@ | |||
15 | * GNU General Public License for more details. | 15 | * GNU General Public License for more details. |
16 | */ | 16 | */ |
17 | 17 | ||
18 | #include <linux/device.h> | ||
18 | #include <linux/kernel.h> | 19 | #include <linux/kernel.h> |
19 | #include <linux/module.h> | 20 | #include <linux/module.h> |
20 | #include <linux/platform_device.h> | ||
21 | 21 | ||
22 | #include "memconsole.h" | 22 | #include "memconsole.h" |
23 | #include "coreboot_table.h" | 23 | #include "coreboot_table.h" |
@@ -73,18 +73,19 @@ static ssize_t memconsole_coreboot_read(char *buf, loff_t pos, size_t count) | |||
73 | return done; | 73 | return done; |
74 | } | 74 | } |
75 | 75 | ||
76 | static int memconsole_coreboot_init(phys_addr_t physaddr) | 76 | static int memconsole_probe(struct coreboot_device *dev) |
77 | { | 77 | { |
78 | struct cbmem_cons __iomem *tmp_cbmc; | 78 | struct cbmem_cons __iomem *tmp_cbmc; |
79 | 79 | ||
80 | tmp_cbmc = memremap(physaddr, sizeof(*tmp_cbmc), MEMREMAP_WB); | 80 | tmp_cbmc = memremap(dev->cbmem_ref.cbmem_addr, |
81 | sizeof(*tmp_cbmc), MEMREMAP_WB); | ||
81 | 82 | ||
82 | if (!tmp_cbmc) | 83 | if (!tmp_cbmc) |
83 | return -ENOMEM; | 84 | return -ENOMEM; |
84 | 85 | ||
85 | /* Read size only once to prevent overrun attack through /dev/mem. */ | 86 | /* Read size only once to prevent overrun attack through /dev/mem. */ |
86 | cbmem_console_size = tmp_cbmc->size_dont_access_after_boot; | 87 | cbmem_console_size = tmp_cbmc->size_dont_access_after_boot; |
87 | cbmem_console = memremap(physaddr, | 88 | cbmem_console = memremap(dev->cbmem_ref.cbmem_addr, |
88 | cbmem_console_size + sizeof(*cbmem_console), | 89 | cbmem_console_size + sizeof(*cbmem_console), |
89 | MEMREMAP_WB); | 90 | MEMREMAP_WB); |
90 | memunmap(tmp_cbmc); | 91 | memunmap(tmp_cbmc); |
@@ -93,26 +94,11 @@ static int memconsole_coreboot_init(phys_addr_t physaddr) | |||
93 | return -ENOMEM; | 94 | return -ENOMEM; |
94 | 95 | ||
95 | memconsole_setup(memconsole_coreboot_read); | 96 | memconsole_setup(memconsole_coreboot_read); |
96 | return 0; | ||
97 | } | ||
98 | |||
99 | static int memconsole_probe(struct platform_device *pdev) | ||
100 | { | ||
101 | int ret; | ||
102 | struct lb_cbmem_ref entry; | ||
103 | |||
104 | ret = coreboot_table_find(CB_TAG_CBMEM_CONSOLE, &entry, sizeof(entry)); | ||
105 | if (ret) | ||
106 | return ret; | ||
107 | |||
108 | ret = memconsole_coreboot_init(entry.cbmem_addr); | ||
109 | if (ret) | ||
110 | return ret; | ||
111 | 97 | ||
112 | return memconsole_sysfs_init(); | 98 | return memconsole_sysfs_init(); |
113 | } | 99 | } |
114 | 100 | ||
115 | static int memconsole_remove(struct platform_device *pdev) | 101 | static int memconsole_remove(struct coreboot_device *dev) |
116 | { | 102 | { |
117 | memconsole_exit(); | 103 | memconsole_exit(); |
118 | 104 | ||
@@ -122,28 +108,27 @@ static int memconsole_remove(struct platform_device *pdev) | |||
122 | return 0; | 108 | return 0; |
123 | } | 109 | } |
124 | 110 | ||
125 | static struct platform_driver memconsole_driver = { | 111 | static struct coreboot_driver memconsole_driver = { |
126 | .probe = memconsole_probe, | 112 | .probe = memconsole_probe, |
127 | .remove = memconsole_remove, | 113 | .remove = memconsole_remove, |
128 | .driver = { | 114 | .drv = { |
129 | .name = "memconsole", | 115 | .name = "memconsole", |
130 | }, | 116 | }, |
117 | .tag = CB_TAG_CBMEM_CONSOLE, | ||
131 | }; | 118 | }; |
132 | 119 | ||
133 | static int __init platform_memconsole_init(void) | 120 | static void coreboot_memconsole_exit(void) |
134 | { | 121 | { |
135 | struct platform_device *pdev; | 122 | coreboot_driver_unregister(&memconsole_driver); |
136 | 123 | } | |
137 | pdev = platform_device_register_simple("memconsole", -1, NULL, 0); | ||
138 | if (IS_ERR(pdev)) | ||
139 | return PTR_ERR(pdev); | ||
140 | |||
141 | platform_driver_register(&memconsole_driver); | ||
142 | 124 | ||
143 | return 0; | 125 | static int __init coreboot_memconsole_init(void) |
126 | { | ||
127 | return coreboot_driver_register(&memconsole_driver); | ||
144 | } | 128 | } |
145 | 129 | ||
146 | module_init(platform_memconsole_init); | 130 | module_exit(coreboot_memconsole_exit); |
131 | module_init(coreboot_memconsole_init); | ||
147 | 132 | ||
148 | MODULE_AUTHOR("Google, Inc."); | 133 | MODULE_AUTHOR("Google, Inc."); |
149 | MODULE_LICENSE("GPL"); | 134 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/firmware/google/vpd.c b/drivers/firmware/google/vpd.c index e4b40f2b4627..e9db895916c3 100644 --- a/drivers/firmware/google/vpd.c +++ b/drivers/firmware/google/vpd.c | |||
@@ -286,20 +286,15 @@ static int vpd_sections_init(phys_addr_t physaddr) | |||
286 | return 0; | 286 | return 0; |
287 | } | 287 | } |
288 | 288 | ||
289 | static int vpd_probe(struct platform_device *pdev) | 289 | static int vpd_probe(struct coreboot_device *dev) |
290 | { | 290 | { |
291 | int ret; | 291 | int ret; |
292 | struct lb_cbmem_ref entry; | ||
293 | |||
294 | ret = coreboot_table_find(CB_TAG_VPD, &entry, sizeof(entry)); | ||
295 | if (ret) | ||
296 | return ret; | ||
297 | 292 | ||
298 | vpd_kobj = kobject_create_and_add("vpd", firmware_kobj); | 293 | vpd_kobj = kobject_create_and_add("vpd", firmware_kobj); |
299 | if (!vpd_kobj) | 294 | if (!vpd_kobj) |
300 | return -ENOMEM; | 295 | return -ENOMEM; |
301 | 296 | ||
302 | ret = vpd_sections_init(entry.cbmem_addr); | 297 | ret = vpd_sections_init(dev->cbmem_ref.cbmem_addr); |
303 | if (ret) { | 298 | if (ret) { |
304 | kobject_put(vpd_kobj); | 299 | kobject_put(vpd_kobj); |
305 | return ret; | 300 | return ret; |
@@ -308,7 +303,7 @@ static int vpd_probe(struct platform_device *pdev) | |||
308 | return 0; | 303 | return 0; |
309 | } | 304 | } |
310 | 305 | ||
311 | static int vpd_remove(struct platform_device *pdev) | 306 | static int vpd_remove(struct coreboot_device *dev) |
312 | { | 307 | { |
313 | vpd_section_destroy(&ro_vpd); | 308 | vpd_section_destroy(&ro_vpd); |
314 | vpd_section_destroy(&rw_vpd); | 309 | vpd_section_destroy(&rw_vpd); |
@@ -318,41 +313,27 @@ static int vpd_remove(struct platform_device *pdev) | |||
318 | return 0; | 313 | return 0; |
319 | } | 314 | } |
320 | 315 | ||
321 | static struct platform_driver vpd_driver = { | 316 | static struct coreboot_driver vpd_driver = { |
322 | .probe = vpd_probe, | 317 | .probe = vpd_probe, |
323 | .remove = vpd_remove, | 318 | .remove = vpd_remove, |
324 | .driver = { | 319 | .drv = { |
325 | .name = "vpd", | 320 | .name = "vpd", |
326 | }, | 321 | }, |
322 | .tag = CB_TAG_VPD, | ||
327 | }; | 323 | }; |
328 | 324 | ||
329 | static struct platform_device *vpd_pdev; | 325 | static int __init coreboot_vpd_init(void) |
330 | |||
331 | static int __init vpd_platform_init(void) | ||
332 | { | 326 | { |
333 | int ret; | 327 | return coreboot_driver_register(&vpd_driver); |
334 | |||
335 | ret = platform_driver_register(&vpd_driver); | ||
336 | if (ret) | ||
337 | return ret; | ||
338 | |||
339 | vpd_pdev = platform_device_register_simple("vpd", -1, NULL, 0); | ||
340 | if (IS_ERR(vpd_pdev)) { | ||
341 | platform_driver_unregister(&vpd_driver); | ||
342 | return PTR_ERR(vpd_pdev); | ||
343 | } | ||
344 | |||
345 | return 0; | ||
346 | } | 328 | } |
347 | 329 | ||
348 | static void __exit vpd_platform_exit(void) | 330 | static void __exit coreboot_vpd_exit(void) |
349 | { | 331 | { |
350 | platform_device_unregister(vpd_pdev); | 332 | coreboot_driver_unregister(&vpd_driver); |
351 | platform_driver_unregister(&vpd_driver); | ||
352 | } | 333 | } |
353 | 334 | ||
354 | module_init(vpd_platform_init); | 335 | module_init(coreboot_vpd_init); |
355 | module_exit(vpd_platform_exit); | 336 | module_exit(coreboot_vpd_exit); |
356 | 337 | ||
357 | MODULE_AUTHOR("Google, Inc."); | 338 | MODULE_AUTHOR("Google, Inc."); |
358 | MODULE_LICENSE("GPL"); | 339 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig index f47ef848bcd0..ee9c5420c47f 100644 --- a/drivers/fpga/Kconfig +++ b/drivers/fpga/Kconfig | |||
@@ -53,7 +53,6 @@ config FPGA_MGR_ALTERA_CVP | |||
53 | config FPGA_MGR_ZYNQ_FPGA | 53 | config FPGA_MGR_ZYNQ_FPGA |
54 | tristate "Xilinx Zynq FPGA" | 54 | tristate "Xilinx Zynq FPGA" |
55 | depends on ARCH_ZYNQ || COMPILE_TEST | 55 | depends on ARCH_ZYNQ || COMPILE_TEST |
56 | depends on HAS_DMA | ||
57 | help | 56 | help |
58 | FPGA manager driver support for Xilinx Zynq FPGAs. | 57 | FPGA manager driver support for Xilinx Zynq FPGAs. |
59 | 58 | ||
@@ -70,6 +69,13 @@ config FPGA_MGR_ICE40_SPI | |||
70 | help | 69 | help |
71 | FPGA manager driver support for Lattice iCE40 FPGAs over SPI. | 70 | FPGA manager driver support for Lattice iCE40 FPGAs over SPI. |
72 | 71 | ||
72 | config FPGA_MGR_MACHXO2_SPI | ||
73 | tristate "Lattice MachXO2 SPI" | ||
74 | depends on SPI | ||
75 | help | ||
76 | FPGA manager driver support for Lattice MachXO2 configuration | ||
77 | over slave SPI interface. | ||
78 | |||
73 | config FPGA_MGR_TS73XX | 79 | config FPGA_MGR_TS73XX |
74 | tristate "Technologic Systems TS-73xx SBC FPGA Manager" | 80 | tristate "Technologic Systems TS-73xx SBC FPGA Manager" |
75 | depends on ARCH_EP93XX && MACH_TS72XX | 81 | depends on ARCH_EP93XX && MACH_TS72XX |
diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile index 3cb276a0f88d..f9803dad6919 100644 --- a/drivers/fpga/Makefile +++ b/drivers/fpga/Makefile | |||
@@ -10,6 +10,7 @@ obj-$(CONFIG_FPGA) += fpga-mgr.o | |||
10 | obj-$(CONFIG_FPGA_MGR_ALTERA_CVP) += altera-cvp.o | 10 | obj-$(CONFIG_FPGA_MGR_ALTERA_CVP) += altera-cvp.o |
11 | obj-$(CONFIG_FPGA_MGR_ALTERA_PS_SPI) += altera-ps-spi.o | 11 | obj-$(CONFIG_FPGA_MGR_ALTERA_PS_SPI) += altera-ps-spi.o |
12 | obj-$(CONFIG_FPGA_MGR_ICE40_SPI) += ice40-spi.o | 12 | obj-$(CONFIG_FPGA_MGR_ICE40_SPI) += ice40-spi.o |
13 | obj-$(CONFIG_FPGA_MGR_MACHXO2_SPI) += machxo2-spi.o | ||
13 | obj-$(CONFIG_FPGA_MGR_SOCFPGA) += socfpga.o | 14 | obj-$(CONFIG_FPGA_MGR_SOCFPGA) += socfpga.o |
14 | obj-$(CONFIG_FPGA_MGR_SOCFPGA_A10) += socfpga-a10.o | 15 | obj-$(CONFIG_FPGA_MGR_SOCFPGA_A10) += socfpga-a10.o |
15 | obj-$(CONFIG_FPGA_MGR_TS73XX) += ts73xx-fpga.o | 16 | obj-$(CONFIG_FPGA_MGR_TS73XX) += ts73xx-fpga.o |
diff --git a/drivers/fpga/altera-cvp.c b/drivers/fpga/altera-cvp.c index 77b04e4b3254..dd4edd8f22ce 100644 --- a/drivers/fpga/altera-cvp.c +++ b/drivers/fpga/altera-cvp.c | |||
@@ -401,6 +401,7 @@ static int altera_cvp_probe(struct pci_dev *pdev, | |||
401 | const struct pci_device_id *dev_id) | 401 | const struct pci_device_id *dev_id) |
402 | { | 402 | { |
403 | struct altera_cvp_conf *conf; | 403 | struct altera_cvp_conf *conf; |
404 | struct fpga_manager *mgr; | ||
404 | u16 cmd, val; | 405 | u16 cmd, val; |
405 | int ret; | 406 | int ret; |
406 | 407 | ||
@@ -452,16 +453,24 @@ static int altera_cvp_probe(struct pci_dev *pdev, | |||
452 | snprintf(conf->mgr_name, sizeof(conf->mgr_name), "%s @%s", | 453 | snprintf(conf->mgr_name, sizeof(conf->mgr_name), "%s @%s", |
453 | ALTERA_CVP_MGR_NAME, pci_name(pdev)); | 454 | ALTERA_CVP_MGR_NAME, pci_name(pdev)); |
454 | 455 | ||
455 | ret = fpga_mgr_register(&pdev->dev, conf->mgr_name, | 456 | mgr = fpga_mgr_create(&pdev->dev, conf->mgr_name, |
456 | &altera_cvp_ops, conf); | 457 | &altera_cvp_ops, conf); |
457 | if (ret) | 458 | if (!mgr) |
459 | return -ENOMEM; | ||
460 | |||
461 | pci_set_drvdata(pdev, mgr); | ||
462 | |||
463 | ret = fpga_mgr_register(mgr); | ||
464 | if (ret) { | ||
465 | fpga_mgr_free(mgr); | ||
458 | goto err_unmap; | 466 | goto err_unmap; |
467 | } | ||
459 | 468 | ||
460 | ret = driver_create_file(&altera_cvp_driver.driver, | 469 | ret = driver_create_file(&altera_cvp_driver.driver, |
461 | &driver_attr_chkcfg); | 470 | &driver_attr_chkcfg); |
462 | if (ret) { | 471 | if (ret) { |
463 | dev_err(&pdev->dev, "Can't create sysfs chkcfg file\n"); | 472 | dev_err(&pdev->dev, "Can't create sysfs chkcfg file\n"); |
464 | fpga_mgr_unregister(&pdev->dev); | 473 | fpga_mgr_unregister(mgr); |
465 | goto err_unmap; | 474 | goto err_unmap; |
466 | } | 475 | } |
467 | 476 | ||
@@ -483,7 +492,7 @@ static void altera_cvp_remove(struct pci_dev *pdev) | |||
483 | u16 cmd; | 492 | u16 cmd; |
484 | 493 | ||
485 | driver_remove_file(&altera_cvp_driver.driver, &driver_attr_chkcfg); | 494 | driver_remove_file(&altera_cvp_driver.driver, &driver_attr_chkcfg); |
486 | fpga_mgr_unregister(&pdev->dev); | 495 | fpga_mgr_unregister(mgr); |
487 | pci_iounmap(pdev, conf->map); | 496 | pci_iounmap(pdev, conf->map); |
488 | pci_release_region(pdev, CVP_BAR); | 497 | pci_release_region(pdev, CVP_BAR); |
489 | pci_read_config_word(pdev, PCI_COMMAND, &cmd); | 498 | pci_read_config_word(pdev, PCI_COMMAND, &cmd); |
diff --git a/drivers/fpga/altera-fpga2sdram.c b/drivers/fpga/altera-fpga2sdram.c index d4eeb74388da..23660ccd634b 100644 --- a/drivers/fpga/altera-fpga2sdram.c +++ b/drivers/fpga/altera-fpga2sdram.c | |||
@@ -1,19 +1,8 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
1 | /* | 2 | /* |
2 | * FPGA to SDRAM Bridge Driver for Altera SoCFPGA Devices | 3 | * FPGA to SDRAM Bridge Driver for Altera SoCFPGA Devices |
3 | * | 4 | * |
4 | * Copyright (C) 2013-2016 Altera Corporation, All Rights Reserved. | 5 | * Copyright (C) 2013-2016 Altera Corporation, All Rights Reserved. |
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License along with | ||
16 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | 6 | */ |
18 | 7 | ||
19 | /* | 8 | /* |
@@ -106,6 +95,7 @@ static int alt_fpga_bridge_probe(struct platform_device *pdev) | |||
106 | { | 95 | { |
107 | struct device *dev = &pdev->dev; | 96 | struct device *dev = &pdev->dev; |
108 | struct alt_fpga2sdram_data *priv; | 97 | struct alt_fpga2sdram_data *priv; |
98 | struct fpga_bridge *br; | ||
109 | u32 enable; | 99 | u32 enable; |
110 | struct regmap *sysmgr; | 100 | struct regmap *sysmgr; |
111 | int ret = 0; | 101 | int ret = 0; |
@@ -131,10 +121,18 @@ static int alt_fpga_bridge_probe(struct platform_device *pdev) | |||
131 | /* Get f2s bridge configuration saved in handoff register */ | 121 | /* Get f2s bridge configuration saved in handoff register */ |
132 | regmap_read(sysmgr, SYSMGR_ISWGRP_HANDOFF3, &priv->mask); | 122 | regmap_read(sysmgr, SYSMGR_ISWGRP_HANDOFF3, &priv->mask); |
133 | 123 | ||
134 | ret = fpga_bridge_register(dev, F2S_BRIDGE_NAME, | 124 | br = fpga_bridge_create(dev, F2S_BRIDGE_NAME, |
135 | &altera_fpga2sdram_br_ops, priv); | 125 | &altera_fpga2sdram_br_ops, priv); |
136 | if (ret) | 126 | if (!br) |
127 | return -ENOMEM; | ||
128 | |||
129 | platform_set_drvdata(pdev, br); | ||
130 | |||
131 | ret = fpga_bridge_register(br); | ||
132 | if (ret) { | ||
133 | fpga_bridge_free(br); | ||
137 | return ret; | 134 | return ret; |
135 | } | ||
138 | 136 | ||
139 | dev_info(dev, "driver initialized with handoff %08x\n", priv->mask); | 137 | dev_info(dev, "driver initialized with handoff %08x\n", priv->mask); |
140 | 138 | ||
@@ -146,7 +144,7 @@ static int alt_fpga_bridge_probe(struct platform_device *pdev) | |||
146 | (enable ? "enabling" : "disabling")); | 144 | (enable ? "enabling" : "disabling")); |
147 | ret = _alt_fpga2sdram_enable_set(priv, enable); | 145 | ret = _alt_fpga2sdram_enable_set(priv, enable); |
148 | if (ret) { | 146 | if (ret) { |
149 | fpga_bridge_unregister(&pdev->dev); | 147 | fpga_bridge_unregister(br); |
150 | return ret; | 148 | return ret; |
151 | } | 149 | } |
152 | } | 150 | } |
@@ -157,7 +155,9 @@ static int alt_fpga_bridge_probe(struct platform_device *pdev) | |||
157 | 155 | ||
158 | static int alt_fpga_bridge_remove(struct platform_device *pdev) | 156 | static int alt_fpga_bridge_remove(struct platform_device *pdev) |
159 | { | 157 | { |
160 | fpga_bridge_unregister(&pdev->dev); | 158 | struct fpga_bridge *br = platform_get_drvdata(pdev); |
159 | |||
160 | fpga_bridge_unregister(br); | ||
161 | 161 | ||
162 | return 0; | 162 | return 0; |
163 | } | 163 | } |
diff --git a/drivers/fpga/altera-freeze-bridge.c b/drivers/fpga/altera-freeze-bridge.c index 6159cfcf78a2..ffd586c48ecf 100644 --- a/drivers/fpga/altera-freeze-bridge.c +++ b/drivers/fpga/altera-freeze-bridge.c | |||
@@ -1,19 +1,8 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
1 | /* | 2 | /* |
2 | * FPGA Freeze Bridge Controller | 3 | * FPGA Freeze Bridge Controller |
3 | * | 4 | * |
4 | * Copyright (C) 2016 Altera Corporation. All rights reserved. | 5 | * Copyright (C) 2016 Altera Corporation. All rights reserved. |
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License along with | ||
16 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | 6 | */ |
18 | #include <linux/delay.h> | 7 | #include <linux/delay.h> |
19 | #include <linux/io.h> | 8 | #include <linux/io.h> |
@@ -221,8 +210,10 @@ static int altera_freeze_br_probe(struct platform_device *pdev) | |||
221 | struct device_node *np = pdev->dev.of_node; | 210 | struct device_node *np = pdev->dev.of_node; |
222 | void __iomem *base_addr; | 211 | void __iomem *base_addr; |
223 | struct altera_freeze_br_data *priv; | 212 | struct altera_freeze_br_data *priv; |
213 | struct fpga_bridge *br; | ||
224 | struct resource *res; | 214 | struct resource *res; |
225 | u32 status, revision; | 215 | u32 status, revision; |
216 | int ret; | ||
226 | 217 | ||
227 | if (!np) | 218 | if (!np) |
228 | return -ENODEV; | 219 | return -ENODEV; |
@@ -254,13 +245,27 @@ static int altera_freeze_br_probe(struct platform_device *pdev) | |||
254 | 245 | ||
255 | priv->base_addr = base_addr; | 246 | priv->base_addr = base_addr; |
256 | 247 | ||
257 | return fpga_bridge_register(dev, FREEZE_BRIDGE_NAME, | 248 | br = fpga_bridge_create(dev, FREEZE_BRIDGE_NAME, |
258 | &altera_freeze_br_br_ops, priv); | 249 | &altera_freeze_br_br_ops, priv); |
250 | if (!br) | ||
251 | return -ENOMEM; | ||
252 | |||
253 | platform_set_drvdata(pdev, br); | ||
254 | |||
255 | ret = fpga_bridge_register(br); | ||
256 | if (ret) { | ||
257 | fpga_bridge_free(br); | ||
258 | return ret; | ||
259 | } | ||
260 | |||
261 | return 0; | ||
259 | } | 262 | } |
260 | 263 | ||
261 | static int altera_freeze_br_remove(struct platform_device *pdev) | 264 | static int altera_freeze_br_remove(struct platform_device *pdev) |
262 | { | 265 | { |
263 | fpga_bridge_unregister(&pdev->dev); | 266 | struct fpga_bridge *br = platform_get_drvdata(pdev); |
267 | |||
268 | fpga_bridge_unregister(br); | ||
264 | 269 | ||
265 | return 0; | 270 | return 0; |
266 | } | 271 | } |
diff --git a/drivers/fpga/altera-hps2fpga.c b/drivers/fpga/altera-hps2fpga.c index 406d2f10741f..a974d3f60321 100644 --- a/drivers/fpga/altera-hps2fpga.c +++ b/drivers/fpga/altera-hps2fpga.c | |||
@@ -1,3 +1,4 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
1 | /* | 2 | /* |
2 | * FPGA to/from HPS Bridge Driver for Altera SoCFPGA Devices | 3 | * FPGA to/from HPS Bridge Driver for Altera SoCFPGA Devices |
3 | * | 4 | * |
@@ -6,18 +7,6 @@ | |||
6 | * Includes this patch from the mailing list: | 7 | * Includes this patch from the mailing list: |
7 | * fpga: altera-hps2fpga: fix HPS2FPGA bridge visibility to L3 masters | 8 | * fpga: altera-hps2fpga: fix HPS2FPGA bridge visibility to L3 masters |
8 | * Signed-off-by: Anatolij Gustschin <agust@denx.de> | 9 | * Signed-off-by: Anatolij Gustschin <agust@denx.de> |
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify it | ||
11 | * under the terms and conditions of the GNU General Public License, | ||
12 | * version 2, as published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
17 | * more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License along with | ||
20 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
21 | */ | 10 | */ |
22 | 11 | ||
23 | /* | 12 | /* |
@@ -139,6 +128,7 @@ static int alt_fpga_bridge_probe(struct platform_device *pdev) | |||
139 | struct device *dev = &pdev->dev; | 128 | struct device *dev = &pdev->dev; |
140 | struct altera_hps2fpga_data *priv; | 129 | struct altera_hps2fpga_data *priv; |
141 | const struct of_device_id *of_id; | 130 | const struct of_device_id *of_id; |
131 | struct fpga_bridge *br; | ||
142 | u32 enable; | 132 | u32 enable; |
143 | int ret; | 133 | int ret; |
144 | 134 | ||
@@ -190,11 +180,24 @@ static int alt_fpga_bridge_probe(struct platform_device *pdev) | |||
190 | } | 180 | } |
191 | } | 181 | } |
192 | 182 | ||
193 | ret = fpga_bridge_register(dev, priv->name, &altera_hps2fpga_br_ops, | 183 | br = fpga_bridge_create(dev, priv->name, &altera_hps2fpga_br_ops, priv); |
194 | priv); | 184 | if (!br) { |
195 | err: | 185 | ret = -ENOMEM; |
186 | goto err; | ||
187 | } | ||
188 | |||
189 | platform_set_drvdata(pdev, br); | ||
190 | |||
191 | ret = fpga_bridge_register(br); | ||
196 | if (ret) | 192 | if (ret) |
197 | clk_disable_unprepare(priv->clk); | 193 | goto err_free; |
194 | |||
195 | return 0; | ||
196 | |||
197 | err_free: | ||
198 | fpga_bridge_free(br); | ||
199 | err: | ||
200 | clk_disable_unprepare(priv->clk); | ||
198 | 201 | ||
199 | return ret; | 202 | return ret; |
200 | } | 203 | } |
@@ -204,7 +207,7 @@ static int alt_fpga_bridge_remove(struct platform_device *pdev) | |||
204 | struct fpga_bridge *bridge = platform_get_drvdata(pdev); | 207 | struct fpga_bridge *bridge = platform_get_drvdata(pdev); |
205 | struct altera_hps2fpga_data *priv = bridge->priv; | 208 | struct altera_hps2fpga_data *priv = bridge->priv; |
206 | 209 | ||
207 | fpga_bridge_unregister(&pdev->dev); | 210 | fpga_bridge_unregister(bridge); |
208 | 211 | ||
209 | clk_disable_unprepare(priv->clk); | 212 | clk_disable_unprepare(priv->clk); |
210 | 213 | ||
diff --git a/drivers/fpga/altera-pr-ip-core-plat.c b/drivers/fpga/altera-pr-ip-core-plat.c index 8fb36b8b4648..b293d83143f1 100644 --- a/drivers/fpga/altera-pr-ip-core-plat.c +++ b/drivers/fpga/altera-pr-ip-core-plat.c | |||
@@ -1,3 +1,4 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
1 | /* | 2 | /* |
2 | * Driver for Altera Partial Reconfiguration IP Core | 3 | * Driver for Altera Partial Reconfiguration IP Core |
3 | * | 4 | * |
@@ -5,18 +6,6 @@ | |||
5 | * | 6 | * |
6 | * Based on socfpga-a10.c Copyright (C) 2015-2016 Altera Corporation | 7 | * Based on socfpga-a10.c Copyright (C) 2015-2016 Altera Corporation |
7 | * by Alan Tull <atull@opensource.altera.com> | 8 | * by Alan Tull <atull@opensource.altera.com> |
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms and conditions of the GNU General Public License, | ||
11 | * version 2, as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
14 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
15 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
16 | * more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License along with | ||
19 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
20 | */ | 9 | */ |
21 | #include <linux/fpga/altera-pr-ip-core.h> | 10 | #include <linux/fpga/altera-pr-ip-core.h> |
22 | #include <linux/module.h> | 11 | #include <linux/module.h> |
diff --git a/drivers/fpga/altera-pr-ip-core.c b/drivers/fpga/altera-pr-ip-core.c index a7b31f9797ce..65e0b6a2c031 100644 --- a/drivers/fpga/altera-pr-ip-core.c +++ b/drivers/fpga/altera-pr-ip-core.c | |||
@@ -1,3 +1,4 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
1 | /* | 2 | /* |
2 | * Driver for Altera Partial Reconfiguration IP Core | 3 | * Driver for Altera Partial Reconfiguration IP Core |
3 | * | 4 | * |
@@ -5,18 +6,6 @@ | |||
5 | * | 6 | * |
6 | * Based on socfpga-a10.c Copyright (C) 2015-2016 Altera Corporation | 7 | * Based on socfpga-a10.c Copyright (C) 2015-2016 Altera Corporation |
7 | * by Alan Tull <atull@opensource.altera.com> | 8 | * by Alan Tull <atull@opensource.altera.com> |
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms and conditions of the GNU General Public License, | ||
11 | * version 2, as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
14 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
15 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
16 | * more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License along with | ||
19 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
20 | */ | 9 | */ |
21 | #include <linux/delay.h> | 10 | #include <linux/delay.h> |
22 | #include <linux/fpga/altera-pr-ip-core.h> | 11 | #include <linux/fpga/altera-pr-ip-core.h> |
@@ -187,6 +176,8 @@ static const struct fpga_manager_ops alt_pr_ops = { | |||
187 | int alt_pr_register(struct device *dev, void __iomem *reg_base) | 176 | int alt_pr_register(struct device *dev, void __iomem *reg_base) |
188 | { | 177 | { |
189 | struct alt_pr_priv *priv; | 178 | struct alt_pr_priv *priv; |
179 | struct fpga_manager *mgr; | ||
180 | int ret; | ||
190 | u32 val; | 181 | u32 val; |
191 | 182 | ||
192 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | 183 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); |
@@ -201,15 +192,27 @@ int alt_pr_register(struct device *dev, void __iomem *reg_base) | |||
201 | (val & ALT_PR_CSR_STATUS_MSK) >> ALT_PR_CSR_STATUS_SFT, | 192 | (val & ALT_PR_CSR_STATUS_MSK) >> ALT_PR_CSR_STATUS_SFT, |
202 | (int)(val & ALT_PR_CSR_PR_START)); | 193 | (int)(val & ALT_PR_CSR_PR_START)); |
203 | 194 | ||
204 | return fpga_mgr_register(dev, dev_name(dev), &alt_pr_ops, priv); | 195 | mgr = fpga_mgr_create(dev, dev_name(dev), &alt_pr_ops, priv); |
196 | if (!mgr) | ||
197 | return -ENOMEM; | ||
198 | |||
199 | dev_set_drvdata(dev, mgr); | ||
200 | |||
201 | ret = fpga_mgr_register(mgr); | ||
202 | if (ret) | ||
203 | fpga_mgr_free(mgr); | ||
204 | |||
205 | return ret; | ||
205 | } | 206 | } |
206 | EXPORT_SYMBOL_GPL(alt_pr_register); | 207 | EXPORT_SYMBOL_GPL(alt_pr_register); |
207 | 208 | ||
208 | int alt_pr_unregister(struct device *dev) | 209 | int alt_pr_unregister(struct device *dev) |
209 | { | 210 | { |
211 | struct fpga_manager *mgr = dev_get_drvdata(dev); | ||
212 | |||
210 | dev_dbg(dev, "%s\n", __func__); | 213 | dev_dbg(dev, "%s\n", __func__); |
211 | 214 | ||
212 | fpga_mgr_unregister(dev); | 215 | fpga_mgr_unregister(mgr); |
213 | 216 | ||
214 | return 0; | 217 | return 0; |
215 | } | 218 | } |
diff --git a/drivers/fpga/altera-ps-spi.c b/drivers/fpga/altera-ps-spi.c index 06d212a3d49d..24b25c626036 100644 --- a/drivers/fpga/altera-ps-spi.c +++ b/drivers/fpga/altera-ps-spi.c | |||
@@ -238,6 +238,8 @@ static int altera_ps_probe(struct spi_device *spi) | |||
238 | { | 238 | { |
239 | struct altera_ps_conf *conf; | 239 | struct altera_ps_conf *conf; |
240 | const struct of_device_id *of_id; | 240 | const struct of_device_id *of_id; |
241 | struct fpga_manager *mgr; | ||
242 | int ret; | ||
241 | 243 | ||
242 | conf = devm_kzalloc(&spi->dev, sizeof(*conf), GFP_KERNEL); | 244 | conf = devm_kzalloc(&spi->dev, sizeof(*conf), GFP_KERNEL); |
243 | if (!conf) | 245 | if (!conf) |
@@ -273,13 +275,25 @@ static int altera_ps_probe(struct spi_device *spi) | |||
273 | snprintf(conf->mgr_name, sizeof(conf->mgr_name), "%s %s", | 275 | snprintf(conf->mgr_name, sizeof(conf->mgr_name), "%s %s", |
274 | dev_driver_string(&spi->dev), dev_name(&spi->dev)); | 276 | dev_driver_string(&spi->dev), dev_name(&spi->dev)); |
275 | 277 | ||
276 | return fpga_mgr_register(&spi->dev, conf->mgr_name, | 278 | mgr = fpga_mgr_create(&spi->dev, conf->mgr_name, |
277 | &altera_ps_ops, conf); | 279 | &altera_ps_ops, conf); |
280 | if (!mgr) | ||
281 | return -ENOMEM; | ||
282 | |||
283 | spi_set_drvdata(spi, mgr); | ||
284 | |||
285 | ret = fpga_mgr_register(mgr); | ||
286 | if (ret) | ||
287 | fpga_mgr_free(mgr); | ||
288 | |||
289 | return ret; | ||
278 | } | 290 | } |
279 | 291 | ||
280 | static int altera_ps_remove(struct spi_device *spi) | 292 | static int altera_ps_remove(struct spi_device *spi) |
281 | { | 293 | { |
282 | fpga_mgr_unregister(&spi->dev); | 294 | struct fpga_manager *mgr = spi_get_drvdata(spi); |
295 | |||
296 | fpga_mgr_unregister(mgr); | ||
283 | 297 | ||
284 | return 0; | 298 | return 0; |
285 | } | 299 | } |
diff --git a/drivers/fpga/fpga-bridge.c b/drivers/fpga/fpga-bridge.c index 31bd2c59c305..24b8f98b73ec 100644 --- a/drivers/fpga/fpga-bridge.c +++ b/drivers/fpga/fpga-bridge.c | |||
@@ -1,20 +1,9 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
1 | /* | 2 | /* |
2 | * FPGA Bridge Framework Driver | 3 | * FPGA Bridge Framework Driver |
3 | * | 4 | * |
4 | * Copyright (C) 2013-2016 Altera Corporation, All Rights Reserved. | 5 | * Copyright (C) 2013-2016 Altera Corporation, All Rights Reserved. |
5 | * Copyright (C) 2017 Intel Corporation | 6 | * Copyright (C) 2017 Intel Corporation |
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms and conditions of the GNU General Public License, | ||
9 | * version 2, as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
14 | * more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along with | ||
17 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
18 | */ | 7 | */ |
19 | #include <linux/fpga/fpga-bridge.h> | 8 | #include <linux/fpga/fpga-bridge.h> |
20 | #include <linux/idr.h> | 9 | #include <linux/idr.h> |
@@ -132,6 +121,7 @@ static int fpga_bridge_dev_match(struct device *dev, const void *data) | |||
132 | /** | 121 | /** |
133 | * fpga_bridge_get - get an exclusive reference to a fpga bridge | 122 | * fpga_bridge_get - get an exclusive reference to a fpga bridge |
134 | * @dev: parent device that fpga bridge was registered with | 123 | * @dev: parent device that fpga bridge was registered with |
124 | * @info: fpga manager info | ||
135 | * | 125 | * |
136 | * Given a device, get an exclusive reference to a fpga bridge. | 126 | * Given a device, get an exclusive reference to a fpga bridge. |
137 | * | 127 | * |
@@ -328,28 +318,29 @@ static struct attribute *fpga_bridge_attrs[] = { | |||
328 | ATTRIBUTE_GROUPS(fpga_bridge); | 318 | ATTRIBUTE_GROUPS(fpga_bridge); |
329 | 319 | ||
330 | /** | 320 | /** |
331 | * fpga_bridge_register - register a fpga bridge driver | 321 | * fpga_bridge_create - create and initialize a struct fpga_bridge |
332 | * @dev: FPGA bridge device from pdev | 322 | * @dev: FPGA bridge device from pdev |
333 | * @name: FPGA bridge name | 323 | * @name: FPGA bridge name |
334 | * @br_ops: pointer to structure of fpga bridge ops | 324 | * @br_ops: pointer to structure of fpga bridge ops |
335 | * @priv: FPGA bridge private data | 325 | * @priv: FPGA bridge private data |
336 | * | 326 | * |
337 | * Return: 0 for success, error code otherwise. | 327 | * Return: struct fpga_bridge or NULL |
338 | */ | 328 | */ |
339 | int fpga_bridge_register(struct device *dev, const char *name, | 329 | struct fpga_bridge *fpga_bridge_create(struct device *dev, const char *name, |
340 | const struct fpga_bridge_ops *br_ops, void *priv) | 330 | const struct fpga_bridge_ops *br_ops, |
331 | void *priv) | ||
341 | { | 332 | { |
342 | struct fpga_bridge *bridge; | 333 | struct fpga_bridge *bridge; |
343 | int id, ret = 0; | 334 | int id, ret = 0; |
344 | 335 | ||
345 | if (!name || !strlen(name)) { | 336 | if (!name || !strlen(name)) { |
346 | dev_err(dev, "Attempt to register with no name!\n"); | 337 | dev_err(dev, "Attempt to register with no name!\n"); |
347 | return -EINVAL; | 338 | return NULL; |
348 | } | 339 | } |
349 | 340 | ||
350 | bridge = kzalloc(sizeof(*bridge), GFP_KERNEL); | 341 | bridge = kzalloc(sizeof(*bridge), GFP_KERNEL); |
351 | if (!bridge) | 342 | if (!bridge) |
352 | return -ENOMEM; | 343 | return NULL; |
353 | 344 | ||
354 | id = ida_simple_get(&fpga_bridge_ida, 0, 0, GFP_KERNEL); | 345 | id = ida_simple_get(&fpga_bridge_ida, 0, 0, GFP_KERNEL); |
355 | if (id < 0) { | 346 | if (id < 0) { |
@@ -370,40 +361,62 @@ int fpga_bridge_register(struct device *dev, const char *name, | |||
370 | bridge->dev.parent = dev; | 361 | bridge->dev.parent = dev; |
371 | bridge->dev.of_node = dev->of_node; | 362 | bridge->dev.of_node = dev->of_node; |
372 | bridge->dev.id = id; | 363 | bridge->dev.id = id; |
373 | dev_set_drvdata(dev, bridge); | ||
374 | 364 | ||
375 | ret = dev_set_name(&bridge->dev, "br%d", id); | 365 | ret = dev_set_name(&bridge->dev, "br%d", id); |
376 | if (ret) | 366 | if (ret) |
377 | goto error_device; | 367 | goto error_device; |
378 | 368 | ||
379 | ret = device_add(&bridge->dev); | 369 | return bridge; |
380 | if (ret) | ||
381 | goto error_device; | ||
382 | |||
383 | of_platform_populate(dev->of_node, NULL, NULL, dev); | ||
384 | |||
385 | dev_info(bridge->dev.parent, "fpga bridge [%s] registered\n", | ||
386 | bridge->name); | ||
387 | |||
388 | return 0; | ||
389 | 370 | ||
390 | error_device: | 371 | error_device: |
391 | ida_simple_remove(&fpga_bridge_ida, id); | 372 | ida_simple_remove(&fpga_bridge_ida, id); |
392 | error_kfree: | 373 | error_kfree: |
393 | kfree(bridge); | 374 | kfree(bridge); |
394 | 375 | ||
395 | return ret; | 376 | return NULL; |
396 | } | 377 | } |
397 | EXPORT_SYMBOL_GPL(fpga_bridge_register); | 378 | EXPORT_SYMBOL_GPL(fpga_bridge_create); |
398 | 379 | ||
399 | /** | 380 | /** |
400 | * fpga_bridge_unregister - unregister a fpga bridge driver | 381 | * fpga_bridge_free - free a fpga bridge and its id |
401 | * @dev: FPGA bridge device from pdev | 382 | * @bridge: FPGA bridge struct created by fpga_bridge_create |
402 | */ | 383 | */ |
403 | void fpga_bridge_unregister(struct device *dev) | 384 | void fpga_bridge_free(struct fpga_bridge *bridge) |
404 | { | 385 | { |
405 | struct fpga_bridge *bridge = dev_get_drvdata(dev); | 386 | ida_simple_remove(&fpga_bridge_ida, bridge->dev.id); |
387 | kfree(bridge); | ||
388 | } | ||
389 | EXPORT_SYMBOL_GPL(fpga_bridge_free); | ||
406 | 390 | ||
391 | /** | ||
392 | * fpga_bridge_register - register a fpga bridge | ||
393 | * @bridge: FPGA bridge struct created by fpga_bridge_create | ||
394 | * | ||
395 | * Return: 0 for success, error code otherwise. | ||
396 | */ | ||
397 | int fpga_bridge_register(struct fpga_bridge *bridge) | ||
398 | { | ||
399 | struct device *dev = &bridge->dev; | ||
400 | int ret; | ||
401 | |||
402 | ret = device_add(dev); | ||
403 | if (ret) | ||
404 | return ret; | ||
405 | |||
406 | of_platform_populate(dev->of_node, NULL, NULL, dev); | ||
407 | |||
408 | dev_info(dev->parent, "fpga bridge [%s] registered\n", bridge->name); | ||
409 | |||
410 | return 0; | ||
411 | } | ||
412 | EXPORT_SYMBOL_GPL(fpga_bridge_register); | ||
413 | |||
414 | /** | ||
415 | * fpga_bridge_unregister - unregister and free a fpga bridge | ||
416 | * @bridge: FPGA bridge struct created by fpga_bridge_create | ||
417 | */ | ||
418 | void fpga_bridge_unregister(struct fpga_bridge *bridge) | ||
419 | { | ||
407 | /* | 420 | /* |
408 | * If the low level driver provides a method for putting bridge into | 421 | * If the low level driver provides a method for putting bridge into |
409 | * a desired state upon unregister, do it. | 422 | * a desired state upon unregister, do it. |
@@ -419,8 +432,7 @@ static void fpga_bridge_dev_release(struct device *dev) | |||
419 | { | 432 | { |
420 | struct fpga_bridge *bridge = to_fpga_bridge(dev); | 433 | struct fpga_bridge *bridge = to_fpga_bridge(dev); |
421 | 434 | ||
422 | ida_simple_remove(&fpga_bridge_ida, bridge->dev.id); | 435 | fpga_bridge_free(bridge); |
423 | kfree(bridge); | ||
424 | } | 436 | } |
425 | 437 | ||
426 | static int __init fpga_bridge_dev_init(void) | 438 | static int __init fpga_bridge_dev_init(void) |
diff --git a/drivers/fpga/fpga-mgr.c b/drivers/fpga/fpga-mgr.c index 9939d2cbc9a6..c1564cf827fe 100644 --- a/drivers/fpga/fpga-mgr.c +++ b/drivers/fpga/fpga-mgr.c | |||
@@ -1,3 +1,4 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
1 | /* | 2 | /* |
2 | * FPGA Manager Core | 3 | * FPGA Manager Core |
3 | * | 4 | * |
@@ -6,18 +7,6 @@ | |||
6 | * | 7 | * |
7 | * With code from the mailing list: | 8 | * With code from the mailing list: |
8 | * Copyright (C) 2013 Xilinx, Inc. | 9 | * Copyright (C) 2013 Xilinx, Inc. |
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify it | ||
11 | * under the terms and conditions of the GNU General Public License, | ||
12 | * version 2, as published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
17 | * more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License along with | ||
20 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
21 | */ | 10 | */ |
22 | #include <linux/firmware.h> | 11 | #include <linux/firmware.h> |
23 | #include <linux/fpga/fpga-mgr.h> | 12 | #include <linux/fpga/fpga-mgr.h> |
@@ -32,6 +21,12 @@ | |||
32 | static DEFINE_IDA(fpga_mgr_ida); | 21 | static DEFINE_IDA(fpga_mgr_ida); |
33 | static struct class *fpga_mgr_class; | 22 | static struct class *fpga_mgr_class; |
34 | 23 | ||
24 | /** | ||
25 | * fpga_image_info_alloc - Allocate a FPGA image info struct | ||
26 | * @dev: owning device | ||
27 | * | ||
28 | * Return: struct fpga_image_info or NULL | ||
29 | */ | ||
35 | struct fpga_image_info *fpga_image_info_alloc(struct device *dev) | 30 | struct fpga_image_info *fpga_image_info_alloc(struct device *dev) |
36 | { | 31 | { |
37 | struct fpga_image_info *info; | 32 | struct fpga_image_info *info; |
@@ -50,6 +45,10 @@ struct fpga_image_info *fpga_image_info_alloc(struct device *dev) | |||
50 | } | 45 | } |
51 | EXPORT_SYMBOL_GPL(fpga_image_info_alloc); | 46 | EXPORT_SYMBOL_GPL(fpga_image_info_alloc); |
52 | 47 | ||
48 | /** | ||
49 | * fpga_image_info_free - Free a FPGA image info struct | ||
50 | * @info: FPGA image info struct to free | ||
51 | */ | ||
53 | void fpga_image_info_free(struct fpga_image_info *info) | 52 | void fpga_image_info_free(struct fpga_image_info *info) |
54 | { | 53 | { |
55 | struct device *dev; | 54 | struct device *dev; |
@@ -234,7 +233,7 @@ static int fpga_mgr_buf_load_mapped(struct fpga_manager *mgr, | |||
234 | /** | 233 | /** |
235 | * fpga_mgr_buf_load - load fpga from image in buffer | 234 | * fpga_mgr_buf_load - load fpga from image in buffer |
236 | * @mgr: fpga manager | 235 | * @mgr: fpga manager |
237 | * @flags: flags setting fpga confuration modes | 236 | * @info: fpga image info |
238 | * @buf: buffer contain fpga image | 237 | * @buf: buffer contain fpga image |
239 | * @count: byte count of buf | 238 | * @count: byte count of buf |
240 | * | 239 | * |
@@ -343,6 +342,16 @@ static int fpga_mgr_firmware_load(struct fpga_manager *mgr, | |||
343 | return ret; | 342 | return ret; |
344 | } | 343 | } |
345 | 344 | ||
345 | /** | ||
346 | * fpga_mgr_load - load FPGA from scatter/gather table, buffer, or firmware | ||
347 | * @mgr: fpga manager | ||
348 | * @info: fpga image information. | ||
349 | * | ||
350 | * Load the FPGA from an image which is indicated in @info. If successful, the | ||
351 | * FPGA ends up in operating mode. | ||
352 | * | ||
353 | * Return: 0 on success, negative error code otherwise. | ||
354 | */ | ||
346 | int fpga_mgr_load(struct fpga_manager *mgr, struct fpga_image_info *info) | 355 | int fpga_mgr_load(struct fpga_manager *mgr, struct fpga_image_info *info) |
347 | { | 356 | { |
348 | if (info->sgt) | 357 | if (info->sgt) |
@@ -429,11 +438,9 @@ static int fpga_mgr_dev_match(struct device *dev, const void *data) | |||
429 | } | 438 | } |
430 | 439 | ||
431 | /** | 440 | /** |
432 | * fpga_mgr_get - get a reference to a fpga mgr | 441 | * fpga_mgr_get - Given a device, get a reference to a fpga mgr. |
433 | * @dev: parent device that fpga mgr was registered with | 442 | * @dev: parent device that fpga mgr was registered with |
434 | * | 443 | * |
435 | * Given a device, get a reference to a fpga mgr. | ||
436 | * | ||
437 | * Return: fpga manager struct or IS_ERR() condition containing error code. | 444 | * Return: fpga manager struct or IS_ERR() condition containing error code. |
438 | */ | 445 | */ |
439 | struct fpga_manager *fpga_mgr_get(struct device *dev) | 446 | struct fpga_manager *fpga_mgr_get(struct device *dev) |
@@ -453,10 +460,9 @@ static int fpga_mgr_of_node_match(struct device *dev, const void *data) | |||
453 | } | 460 | } |
454 | 461 | ||
455 | /** | 462 | /** |
456 | * of_fpga_mgr_get - get a reference to a fpga mgr | 463 | * of_fpga_mgr_get - Given a device node, get a reference to a fpga mgr. |
457 | * @node: device node | ||
458 | * | 464 | * |
459 | * Given a device node, get a reference to a fpga mgr. | 465 | * @node: device node |
460 | * | 466 | * |
461 | * Return: fpga manager struct or IS_ERR() condition containing error code. | 467 | * Return: fpga manager struct or IS_ERR() condition containing error code. |
462 | */ | 468 | */ |
@@ -489,7 +495,10 @@ EXPORT_SYMBOL_GPL(fpga_mgr_put); | |||
489 | * @mgr: fpga manager | 495 | * @mgr: fpga manager |
490 | * | 496 | * |
491 | * Given a pointer to FPGA Manager (from fpga_mgr_get() or | 497 | * Given a pointer to FPGA Manager (from fpga_mgr_get() or |
492 | * of_fpga_mgr_put()) attempt to get the mutex. | 498 | * of_fpga_mgr_put()) attempt to get the mutex. The user should call |
499 | * fpga_mgr_lock() and verify that it returns 0 before attempting to | ||
500 | * program the FPGA. Likewise, the user should call fpga_mgr_unlock | ||
501 | * when done programming the FPGA. | ||
493 | * | 502 | * |
494 | * Return: 0 for success or -EBUSY | 503 | * Return: 0 for success or -EBUSY |
495 | */ | 504 | */ |
@@ -505,7 +514,7 @@ int fpga_mgr_lock(struct fpga_manager *mgr) | |||
505 | EXPORT_SYMBOL_GPL(fpga_mgr_lock); | 514 | EXPORT_SYMBOL_GPL(fpga_mgr_lock); |
506 | 515 | ||
507 | /** | 516 | /** |
508 | * fpga_mgr_unlock - Unlock FPGA manager | 517 | * fpga_mgr_unlock - Unlock FPGA manager after done programming |
509 | * @mgr: fpga manager | 518 | * @mgr: fpga manager |
510 | */ | 519 | */ |
511 | void fpga_mgr_unlock(struct fpga_manager *mgr) | 520 | void fpga_mgr_unlock(struct fpga_manager *mgr) |
@@ -515,17 +524,17 @@ void fpga_mgr_unlock(struct fpga_manager *mgr) | |||
515 | EXPORT_SYMBOL_GPL(fpga_mgr_unlock); | 524 | EXPORT_SYMBOL_GPL(fpga_mgr_unlock); |
516 | 525 | ||
517 | /** | 526 | /** |
518 | * fpga_mgr_register - register a low level fpga manager driver | 527 | * fpga_mgr_create - create and initialize a FPGA manager struct |
519 | * @dev: fpga manager device from pdev | 528 | * @dev: fpga manager device from pdev |
520 | * @name: fpga manager name | 529 | * @name: fpga manager name |
521 | * @mops: pointer to structure of fpga manager ops | 530 | * @mops: pointer to structure of fpga manager ops |
522 | * @priv: fpga manager private data | 531 | * @priv: fpga manager private data |
523 | * | 532 | * |
524 | * Return: 0 on success, negative error code otherwise. | 533 | * Return: pointer to struct fpga_manager or NULL |
525 | */ | 534 | */ |
526 | int fpga_mgr_register(struct device *dev, const char *name, | 535 | struct fpga_manager *fpga_mgr_create(struct device *dev, const char *name, |
527 | const struct fpga_manager_ops *mops, | 536 | const struct fpga_manager_ops *mops, |
528 | void *priv) | 537 | void *priv) |
529 | { | 538 | { |
530 | struct fpga_manager *mgr; | 539 | struct fpga_manager *mgr; |
531 | int id, ret; | 540 | int id, ret; |
@@ -534,17 +543,17 @@ int fpga_mgr_register(struct device *dev, const char *name, | |||
534 | !mops->write_init || (!mops->write && !mops->write_sg) || | 543 | !mops->write_init || (!mops->write && !mops->write_sg) || |
535 | (mops->write && mops->write_sg)) { | 544 | (mops->write && mops->write_sg)) { |
536 | dev_err(dev, "Attempt to register without fpga_manager_ops\n"); | 545 | dev_err(dev, "Attempt to register without fpga_manager_ops\n"); |
537 | return -EINVAL; | 546 | return NULL; |
538 | } | 547 | } |
539 | 548 | ||
540 | if (!name || !strlen(name)) { | 549 | if (!name || !strlen(name)) { |
541 | dev_err(dev, "Attempt to register with no name!\n"); | 550 | dev_err(dev, "Attempt to register with no name!\n"); |
542 | return -EINVAL; | 551 | return NULL; |
543 | } | 552 | } |
544 | 553 | ||
545 | mgr = kzalloc(sizeof(*mgr), GFP_KERNEL); | 554 | mgr = kzalloc(sizeof(*mgr), GFP_KERNEL); |
546 | if (!mgr) | 555 | if (!mgr) |
547 | return -ENOMEM; | 556 | return NULL; |
548 | 557 | ||
549 | id = ida_simple_get(&fpga_mgr_ida, 0, 0, GFP_KERNEL); | 558 | id = ida_simple_get(&fpga_mgr_ida, 0, 0, GFP_KERNEL); |
550 | if (id < 0) { | 559 | if (id < 0) { |
@@ -558,25 +567,56 @@ int fpga_mgr_register(struct device *dev, const char *name, | |||
558 | mgr->mops = mops; | 567 | mgr->mops = mops; |
559 | mgr->priv = priv; | 568 | mgr->priv = priv; |
560 | 569 | ||
561 | /* | ||
562 | * Initialize framework state by requesting low level driver read state | ||
563 | * from device. FPGA may be in reset mode or may have been programmed | ||
564 | * by bootloader or EEPROM. | ||
565 | */ | ||
566 | mgr->state = mgr->mops->state(mgr); | ||
567 | |||
568 | device_initialize(&mgr->dev); | 570 | device_initialize(&mgr->dev); |
569 | mgr->dev.class = fpga_mgr_class; | 571 | mgr->dev.class = fpga_mgr_class; |
570 | mgr->dev.groups = mops->groups; | 572 | mgr->dev.groups = mops->groups; |
571 | mgr->dev.parent = dev; | 573 | mgr->dev.parent = dev; |
572 | mgr->dev.of_node = dev->of_node; | 574 | mgr->dev.of_node = dev->of_node; |
573 | mgr->dev.id = id; | 575 | mgr->dev.id = id; |
574 | dev_set_drvdata(dev, mgr); | ||
575 | 576 | ||
576 | ret = dev_set_name(&mgr->dev, "fpga%d", id); | 577 | ret = dev_set_name(&mgr->dev, "fpga%d", id); |
577 | if (ret) | 578 | if (ret) |
578 | goto error_device; | 579 | goto error_device; |
579 | 580 | ||
581 | return mgr; | ||
582 | |||
583 | error_device: | ||
584 | ida_simple_remove(&fpga_mgr_ida, id); | ||
585 | error_kfree: | ||
586 | kfree(mgr); | ||
587 | |||
588 | return NULL; | ||
589 | } | ||
590 | EXPORT_SYMBOL_GPL(fpga_mgr_create); | ||
591 | |||
592 | /** | ||
593 | * fpga_mgr_free - deallocate a FPGA manager | ||
594 | * @mgr: fpga manager struct created by fpga_mgr_create | ||
595 | */ | ||
596 | void fpga_mgr_free(struct fpga_manager *mgr) | ||
597 | { | ||
598 | ida_simple_remove(&fpga_mgr_ida, mgr->dev.id); | ||
599 | kfree(mgr); | ||
600 | } | ||
601 | EXPORT_SYMBOL_GPL(fpga_mgr_free); | ||
602 | |||
603 | /** | ||
604 | * fpga_mgr_register - register a FPGA manager | ||
605 | * @mgr: fpga manager struct created by fpga_mgr_create | ||
606 | * | ||
607 | * Return: 0 on success, negative error code otherwise. | ||
608 | */ | ||
609 | int fpga_mgr_register(struct fpga_manager *mgr) | ||
610 | { | ||
611 | int ret; | ||
612 | |||
613 | /* | ||
614 | * Initialize framework state by requesting low level driver read state | ||
615 | * from device. FPGA may be in reset mode or may have been programmed | ||
616 | * by bootloader or EEPROM. | ||
617 | */ | ||
618 | mgr->state = mgr->mops->state(mgr); | ||
619 | |||
580 | ret = device_add(&mgr->dev); | 620 | ret = device_add(&mgr->dev); |
581 | if (ret) | 621 | if (ret) |
582 | goto error_device; | 622 | goto error_device; |
@@ -586,22 +626,18 @@ int fpga_mgr_register(struct device *dev, const char *name, | |||
586 | return 0; | 626 | return 0; |
587 | 627 | ||
588 | error_device: | 628 | error_device: |
589 | ida_simple_remove(&fpga_mgr_ida, id); | 629 | ida_simple_remove(&fpga_mgr_ida, mgr->dev.id); |
590 | error_kfree: | ||
591 | kfree(mgr); | ||
592 | 630 | ||
593 | return ret; | 631 | return ret; |
594 | } | 632 | } |
595 | EXPORT_SYMBOL_GPL(fpga_mgr_register); | 633 | EXPORT_SYMBOL_GPL(fpga_mgr_register); |
596 | 634 | ||
597 | /** | 635 | /** |
598 | * fpga_mgr_unregister - unregister a low level fpga manager driver | 636 | * fpga_mgr_unregister - unregister and free a FPGA manager |
599 | * @dev: fpga manager device from pdev | 637 | * @mgr: fpga manager struct |
600 | */ | 638 | */ |
601 | void fpga_mgr_unregister(struct device *dev) | 639 | void fpga_mgr_unregister(struct fpga_manager *mgr) |
602 | { | 640 | { |
603 | struct fpga_manager *mgr = dev_get_drvdata(dev); | ||
604 | |||
605 | dev_info(&mgr->dev, "%s %s\n", __func__, mgr->name); | 641 | dev_info(&mgr->dev, "%s %s\n", __func__, mgr->name); |
606 | 642 | ||
607 | /* | 643 | /* |
@@ -619,8 +655,7 @@ static void fpga_mgr_dev_release(struct device *dev) | |||
619 | { | 655 | { |
620 | struct fpga_manager *mgr = to_fpga_manager(dev); | 656 | struct fpga_manager *mgr = to_fpga_manager(dev); |
621 | 657 | ||
622 | ida_simple_remove(&fpga_mgr_ida, mgr->dev.id); | 658 | fpga_mgr_free(mgr); |
623 | kfree(mgr); | ||
624 | } | 659 | } |
625 | 660 | ||
626 | static int __init fpga_mgr_class_init(void) | 661 | static int __init fpga_mgr_class_init(void) |
diff --git a/drivers/fpga/fpga-region.c b/drivers/fpga/fpga-region.c index edab2a2e03ef..6d214d75c7be 100644 --- a/drivers/fpga/fpga-region.c +++ b/drivers/fpga/fpga-region.c | |||
@@ -1,22 +1,10 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
1 | /* | 2 | /* |
2 | * FPGA Region - Device Tree support for FPGA programming under Linux | 3 | * FPGA Region - Device Tree support for FPGA programming under Linux |
3 | * | 4 | * |
4 | * Copyright (C) 2013-2016 Altera Corporation | 5 | * Copyright (C) 2013-2016 Altera Corporation |
5 | * Copyright (C) 2017 Intel Corporation | 6 | * Copyright (C) 2017 Intel Corporation |
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms and conditions of the GNU General Public License, | ||
9 | * version 2, as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
14 | * more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along with | ||
17 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
18 | */ | 7 | */ |
19 | |||
20 | #include <linux/fpga/fpga-bridge.h> | 8 | #include <linux/fpga/fpga-bridge.h> |
21 | #include <linux/fpga/fpga-mgr.h> | 9 | #include <linux/fpga/fpga-mgr.h> |
22 | #include <linux/fpga/fpga-region.h> | 10 | #include <linux/fpga/fpga-region.h> |
@@ -93,8 +81,16 @@ static void fpga_region_put(struct fpga_region *region) | |||
93 | 81 | ||
94 | /** | 82 | /** |
95 | * fpga_region_program_fpga - program FPGA | 83 | * fpga_region_program_fpga - program FPGA |
84 | * | ||
96 | * @region: FPGA region | 85 | * @region: FPGA region |
86 | * | ||
97 | * Program an FPGA using fpga image info (region->info). | 87 | * Program an FPGA using fpga image info (region->info). |
88 | * If the region has a get_bridges function, the exclusive reference for the | ||
89 | * bridges will be held if programming succeeds. This is intended to prevent | ||
90 | * reprogramming the region until the caller considers it safe to do so. | ||
91 | * The caller will need to call fpga_bridges_put() before attempting to | ||
92 | * reprogram the region. | ||
93 | * | ||
98 | * Return 0 for success or negative error code. | 94 | * Return 0 for success or negative error code. |
99 | */ | 95 | */ |
100 | int fpga_region_program_fpga(struct fpga_region *region) | 96 | int fpga_region_program_fpga(struct fpga_region *region) |
@@ -162,45 +158,86 @@ err_put_region: | |||
162 | } | 158 | } |
163 | EXPORT_SYMBOL_GPL(fpga_region_program_fpga); | 159 | EXPORT_SYMBOL_GPL(fpga_region_program_fpga); |
164 | 160 | ||
165 | int fpga_region_register(struct device *dev, struct fpga_region *region) | 161 | /** |
162 | * fpga_region_create - alloc and init a struct fpga_region | ||
163 | * @dev: device parent | ||
164 | * @mgr: manager that programs this region | ||
165 | * @get_bridges: optional function to get bridges to a list | ||
166 | * | ||
167 | * Return: struct fpga_region or NULL | ||
168 | */ | ||
169 | struct fpga_region | ||
170 | *fpga_region_create(struct device *dev, | ||
171 | struct fpga_manager *mgr, | ||
172 | int (*get_bridges)(struct fpga_region *)) | ||
166 | { | 173 | { |
174 | struct fpga_region *region; | ||
167 | int id, ret = 0; | 175 | int id, ret = 0; |
168 | 176 | ||
177 | region = kzalloc(sizeof(*region), GFP_KERNEL); | ||
178 | if (!region) | ||
179 | return NULL; | ||
180 | |||
169 | id = ida_simple_get(&fpga_region_ida, 0, 0, GFP_KERNEL); | 181 | id = ida_simple_get(&fpga_region_ida, 0, 0, GFP_KERNEL); |
170 | if (id < 0) | 182 | if (id < 0) |
171 | return id; | 183 | goto err_free; |
172 | 184 | ||
185 | region->mgr = mgr; | ||
186 | region->get_bridges = get_bridges; | ||
173 | mutex_init(®ion->mutex); | 187 | mutex_init(®ion->mutex); |
174 | INIT_LIST_HEAD(®ion->bridge_list); | 188 | INIT_LIST_HEAD(®ion->bridge_list); |
189 | |||
175 | device_initialize(®ion->dev); | 190 | device_initialize(®ion->dev); |
176 | region->dev.groups = region->groups; | ||
177 | region->dev.class = fpga_region_class; | 191 | region->dev.class = fpga_region_class; |
178 | region->dev.parent = dev; | 192 | region->dev.parent = dev; |
179 | region->dev.of_node = dev->of_node; | 193 | region->dev.of_node = dev->of_node; |
180 | region->dev.id = id; | 194 | region->dev.id = id; |
181 | dev_set_drvdata(dev, region); | ||
182 | 195 | ||
183 | ret = dev_set_name(®ion->dev, "region%d", id); | 196 | ret = dev_set_name(®ion->dev, "region%d", id); |
184 | if (ret) | 197 | if (ret) |
185 | goto err_remove; | 198 | goto err_remove; |
186 | 199 | ||
187 | ret = device_add(®ion->dev); | 200 | return region; |
188 | if (ret) | ||
189 | goto err_remove; | ||
190 | |||
191 | return 0; | ||
192 | 201 | ||
193 | err_remove: | 202 | err_remove: |
194 | ida_simple_remove(&fpga_region_ida, id); | 203 | ida_simple_remove(&fpga_region_ida, id); |
195 | return ret; | 204 | err_free: |
205 | kfree(region); | ||
206 | |||
207 | return NULL; | ||
208 | } | ||
209 | EXPORT_SYMBOL_GPL(fpga_region_create); | ||
210 | |||
211 | /** | ||
212 | * fpga_region_free - free a struct fpga_region | ||
213 | * @region: FPGA region created by fpga_region_create | ||
214 | */ | ||
215 | void fpga_region_free(struct fpga_region *region) | ||
216 | { | ||
217 | ida_simple_remove(&fpga_region_ida, region->dev.id); | ||
218 | kfree(region); | ||
219 | } | ||
220 | EXPORT_SYMBOL_GPL(fpga_region_free); | ||
221 | |||
222 | /** | ||
223 | * fpga_region_register - register a FPGA region | ||
224 | * @region: FPGA region created by fpga_region_create | ||
225 | * Return: 0 or -errno | ||
226 | */ | ||
227 | int fpga_region_register(struct fpga_region *region) | ||
228 | { | ||
229 | return device_add(®ion->dev); | ||
230 | |||
196 | } | 231 | } |
197 | EXPORT_SYMBOL_GPL(fpga_region_register); | 232 | EXPORT_SYMBOL_GPL(fpga_region_register); |
198 | 233 | ||
199 | int fpga_region_unregister(struct fpga_region *region) | 234 | /** |
235 | * fpga_region_unregister - unregister and free a FPGA region | ||
236 | * @region: FPGA region | ||
237 | */ | ||
238 | void fpga_region_unregister(struct fpga_region *region) | ||
200 | { | 239 | { |
201 | device_unregister(®ion->dev); | 240 | device_unregister(®ion->dev); |
202 | |||
203 | return 0; | ||
204 | } | 241 | } |
205 | EXPORT_SYMBOL_GPL(fpga_region_unregister); | 242 | EXPORT_SYMBOL_GPL(fpga_region_unregister); |
206 | 243 | ||
@@ -208,7 +245,7 @@ static void fpga_region_dev_release(struct device *dev) | |||
208 | { | 245 | { |
209 | struct fpga_region *region = to_fpga_region(dev); | 246 | struct fpga_region *region = to_fpga_region(dev); |
210 | 247 | ||
211 | ida_simple_remove(&fpga_region_ida, region->dev.id); | 248 | fpga_region_free(region); |
212 | } | 249 | } |
213 | 250 | ||
214 | /** | 251 | /** |
diff --git a/drivers/fpga/ice40-spi.c b/drivers/fpga/ice40-spi.c index 7fca82023062..5981c7ee7a7d 100644 --- a/drivers/fpga/ice40-spi.c +++ b/drivers/fpga/ice40-spi.c | |||
@@ -133,6 +133,7 @@ static int ice40_fpga_probe(struct spi_device *spi) | |||
133 | { | 133 | { |
134 | struct device *dev = &spi->dev; | 134 | struct device *dev = &spi->dev; |
135 | struct ice40_fpga_priv *priv; | 135 | struct ice40_fpga_priv *priv; |
136 | struct fpga_manager *mgr; | ||
136 | int ret; | 137 | int ret; |
137 | 138 | ||
138 | priv = devm_kzalloc(&spi->dev, sizeof(*priv), GFP_KERNEL); | 139 | priv = devm_kzalloc(&spi->dev, sizeof(*priv), GFP_KERNEL); |
@@ -174,14 +175,26 @@ static int ice40_fpga_probe(struct spi_device *spi) | |||
174 | return ret; | 175 | return ret; |
175 | } | 176 | } |
176 | 177 | ||
177 | /* Register with the FPGA manager */ | 178 | mgr = fpga_mgr_create(dev, "Lattice iCE40 FPGA Manager", |
178 | return fpga_mgr_register(dev, "Lattice iCE40 FPGA Manager", | 179 | &ice40_fpga_ops, priv); |
179 | &ice40_fpga_ops, priv); | 180 | if (!mgr) |
181 | return -ENOMEM; | ||
182 | |||
183 | spi_set_drvdata(spi, mgr); | ||
184 | |||
185 | ret = fpga_mgr_register(mgr); | ||
186 | if (ret) | ||
187 | fpga_mgr_free(mgr); | ||
188 | |||
189 | return ret; | ||
180 | } | 190 | } |
181 | 191 | ||
182 | static int ice40_fpga_remove(struct spi_device *spi) | 192 | static int ice40_fpga_remove(struct spi_device *spi) |
183 | { | 193 | { |
184 | fpga_mgr_unregister(&spi->dev); | 194 | struct fpga_manager *mgr = spi_get_drvdata(spi); |
195 | |||
196 | fpga_mgr_unregister(mgr); | ||
197 | |||
185 | return 0; | 198 | return 0; |
186 | } | 199 | } |
187 | 200 | ||
diff --git a/drivers/fpga/machxo2-spi.c b/drivers/fpga/machxo2-spi.c new file mode 100644 index 000000000000..a582e0000c97 --- /dev/null +++ b/drivers/fpga/machxo2-spi.c | |||
@@ -0,0 +1,415 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | /* | ||
3 | * Lattice MachXO2 Slave SPI Driver | ||
4 | * | ||
5 | * Manage Lattice FPGA firmware that is loaded over SPI using | ||
6 | * the slave serial configuration interface. | ||
7 | * | ||
8 | * Copyright (C) 2018 Paolo Pisati <p.pisati@gmail.com> | ||
9 | */ | ||
10 | |||
11 | #include <linux/delay.h> | ||
12 | #include <linux/fpga/fpga-mgr.h> | ||
13 | #include <linux/gpio/consumer.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/of.h> | ||
16 | #include <linux/spi/spi.h> | ||
17 | |||
18 | /* MachXO2 Programming Guide - sysCONFIG Programming Commands */ | ||
19 | #define IDCODE_PUB {0xe0, 0x00, 0x00, 0x00} | ||
20 | #define ISC_ENABLE {0xc6, 0x08, 0x00, 0x00} | ||
21 | #define ISC_ERASE {0x0e, 0x04, 0x00, 0x00} | ||
22 | #define ISC_PROGRAMDONE {0x5e, 0x00, 0x00, 0x00} | ||
23 | #define LSC_INITADDRESS {0x46, 0x00, 0x00, 0x00} | ||
24 | #define LSC_PROGINCRNV {0x70, 0x00, 0x00, 0x01} | ||
25 | #define LSC_READ_STATUS {0x3c, 0x00, 0x00, 0x00} | ||
26 | #define LSC_REFRESH {0x79, 0x00, 0x00, 0x00} | ||
27 | |||
28 | /* | ||
29 | * Max CCLK in Slave SPI mode according to 'MachXO2 Family Data | ||
30 | * Sheet' sysCONFIG Port Timing Specifications (3-36) | ||
31 | */ | ||
32 | #define MACHXO2_MAX_SPEED 66000000 | ||
33 | |||
34 | #define MACHXO2_LOW_DELAY_USEC 5 | ||
35 | #define MACHXO2_HIGH_DELAY_USEC 200 | ||
36 | #define MACHXO2_REFRESH_USEC 4800 | ||
37 | #define MACHXO2_MAX_BUSY_LOOP 128 | ||
38 | #define MACHXO2_MAX_REFRESH_LOOP 16 | ||
39 | |||
40 | #define MACHXO2_PAGE_SIZE 16 | ||
41 | #define MACHXO2_BUF_SIZE (MACHXO2_PAGE_SIZE + 4) | ||
42 | |||
43 | /* Status register bits, errors and error mask */ | ||
44 | #define BUSY 12 | ||
45 | #define DONE 8 | ||
46 | #define DVER 27 | ||
47 | #define ENAB 9 | ||
48 | #define ERRBITS 23 | ||
49 | #define ERRMASK 7 | ||
50 | #define FAIL 13 | ||
51 | |||
52 | #define ENOERR 0 /* no error */ | ||
53 | #define EID 1 | ||
54 | #define ECMD 2 | ||
55 | #define ECRC 3 | ||
56 | #define EPREAM 4 /* preamble error */ | ||
57 | #define EABRT 5 /* abort error */ | ||
58 | #define EOVERFL 6 /* overflow error */ | ||
59 | #define ESDMEOF 7 /* SDM EOF */ | ||
60 | |||
61 | static inline u8 get_err(unsigned long *status) | ||
62 | { | ||
63 | return (*status >> ERRBITS) & ERRMASK; | ||
64 | } | ||
65 | |||
66 | static int get_status(struct spi_device *spi, unsigned long *status) | ||
67 | { | ||
68 | struct spi_message msg; | ||
69 | struct spi_transfer rx, tx; | ||
70 | static const u8 cmd[] = LSC_READ_STATUS; | ||
71 | int ret; | ||
72 | |||
73 | memset(&rx, 0, sizeof(rx)); | ||
74 | memset(&tx, 0, sizeof(tx)); | ||
75 | tx.tx_buf = cmd; | ||
76 | tx.len = sizeof(cmd); | ||
77 | rx.rx_buf = status; | ||
78 | rx.len = 4; | ||
79 | spi_message_init(&msg); | ||
80 | spi_message_add_tail(&tx, &msg); | ||
81 | spi_message_add_tail(&rx, &msg); | ||
82 | ret = spi_sync(spi, &msg); | ||
83 | if (ret) | ||
84 | return ret; | ||
85 | |||
86 | *status = be32_to_cpu(*status); | ||
87 | |||
88 | return 0; | ||
89 | } | ||
90 | |||
91 | #ifdef DEBUG | ||
92 | static const char *get_err_string(u8 err) | ||
93 | { | ||
94 | switch (err) { | ||
95 | case ENOERR: return "No Error"; | ||
96 | case EID: return "ID ERR"; | ||
97 | case ECMD: return "CMD ERR"; | ||
98 | case ECRC: return "CRC ERR"; | ||
99 | case EPREAM: return "Preamble ERR"; | ||
100 | case EABRT: return "Abort ERR"; | ||
101 | case EOVERFL: return "Overflow ERR"; | ||
102 | case ESDMEOF: return "SDM EOF"; | ||
103 | } | ||
104 | |||
105 | return "Default switch case"; | ||
106 | } | ||
107 | #endif | ||
108 | |||
109 | static void dump_status_reg(unsigned long *status) | ||
110 | { | ||
111 | #ifdef DEBUG | ||
112 | pr_debug("machxo2 status: 0x%08lX - done=%d, cfgena=%d, busy=%d, fail=%d, devver=%d, err=%s\n", | ||
113 | *status, test_bit(DONE, status), test_bit(ENAB, status), | ||
114 | test_bit(BUSY, status), test_bit(FAIL, status), | ||
115 | test_bit(DVER, status), get_err_string(get_err(status))); | ||
116 | #endif | ||
117 | } | ||
118 | |||
119 | static int wait_until_not_busy(struct spi_device *spi) | ||
120 | { | ||
121 | unsigned long status; | ||
122 | int ret, loop = 0; | ||
123 | |||
124 | do { | ||
125 | ret = get_status(spi, &status); | ||
126 | if (ret) | ||
127 | return ret; | ||
128 | if (++loop >= MACHXO2_MAX_BUSY_LOOP) | ||
129 | return -EBUSY; | ||
130 | } while (test_bit(BUSY, &status)); | ||
131 | |||
132 | return 0; | ||
133 | } | ||
134 | |||
135 | static int machxo2_cleanup(struct fpga_manager *mgr) | ||
136 | { | ||
137 | struct spi_device *spi = mgr->priv; | ||
138 | struct spi_message msg; | ||
139 | struct spi_transfer tx[2]; | ||
140 | static const u8 erase[] = ISC_ERASE; | ||
141 | static const u8 refresh[] = LSC_REFRESH; | ||
142 | int ret; | ||
143 | |||
144 | memset(tx, 0, sizeof(tx)); | ||
145 | spi_message_init(&msg); | ||
146 | tx[0].tx_buf = &erase; | ||
147 | tx[0].len = sizeof(erase); | ||
148 | spi_message_add_tail(&tx[0], &msg); | ||
149 | ret = spi_sync(spi, &msg); | ||
150 | if (ret) | ||
151 | goto fail; | ||
152 | |||
153 | ret = wait_until_not_busy(spi); | ||
154 | if (ret) | ||
155 | goto fail; | ||
156 | |||
157 | spi_message_init(&msg); | ||
158 | tx[1].tx_buf = &refresh; | ||
159 | tx[1].len = sizeof(refresh); | ||
160 | tx[1].delay_usecs = MACHXO2_REFRESH_USEC; | ||
161 | spi_message_add_tail(&tx[1], &msg); | ||
162 | ret = spi_sync(spi, &msg); | ||
163 | if (ret) | ||
164 | goto fail; | ||
165 | |||
166 | return 0; | ||
167 | fail: | ||
168 | dev_err(&mgr->dev, "Cleanup failed\n"); | ||
169 | |||
170 | return ret; | ||
171 | } | ||
172 | |||
173 | static enum fpga_mgr_states machxo2_spi_state(struct fpga_manager *mgr) | ||
174 | { | ||
175 | struct spi_device *spi = mgr->priv; | ||
176 | unsigned long status; | ||
177 | |||
178 | get_status(spi, &status); | ||
179 | if (!test_bit(BUSY, &status) && test_bit(DONE, &status) && | ||
180 | get_err(&status) == ENOERR) | ||
181 | return FPGA_MGR_STATE_OPERATING; | ||
182 | |||
183 | return FPGA_MGR_STATE_UNKNOWN; | ||
184 | } | ||
185 | |||
186 | static int machxo2_write_init(struct fpga_manager *mgr, | ||
187 | struct fpga_image_info *info, | ||
188 | const char *buf, size_t count) | ||
189 | { | ||
190 | struct spi_device *spi = mgr->priv; | ||
191 | struct spi_message msg; | ||
192 | struct spi_transfer tx[3]; | ||
193 | static const u8 enable[] = ISC_ENABLE; | ||
194 | static const u8 erase[] = ISC_ERASE; | ||
195 | static const u8 initaddr[] = LSC_INITADDRESS; | ||
196 | unsigned long status; | ||
197 | int ret; | ||
198 | |||
199 | if ((info->flags & FPGA_MGR_PARTIAL_RECONFIG)) { | ||
200 | dev_err(&mgr->dev, | ||
201 | "Partial reconfiguration is not supported\n"); | ||
202 | return -ENOTSUPP; | ||
203 | } | ||
204 | |||
205 | get_status(spi, &status); | ||
206 | dump_status_reg(&status); | ||
207 | memset(tx, 0, sizeof(tx)); | ||
208 | spi_message_init(&msg); | ||
209 | tx[0].tx_buf = &enable; | ||
210 | tx[0].len = sizeof(enable); | ||
211 | tx[0].delay_usecs = MACHXO2_LOW_DELAY_USEC; | ||
212 | spi_message_add_tail(&tx[0], &msg); | ||
213 | |||
214 | tx[1].tx_buf = &erase; | ||
215 | tx[1].len = sizeof(erase); | ||
216 | spi_message_add_tail(&tx[1], &msg); | ||
217 | ret = spi_sync(spi, &msg); | ||
218 | if (ret) | ||
219 | goto fail; | ||
220 | |||
221 | ret = wait_until_not_busy(spi); | ||
222 | if (ret) | ||
223 | goto fail; | ||
224 | |||
225 | get_status(spi, &status); | ||
226 | if (test_bit(FAIL, &status)) | ||
227 | goto fail; | ||
228 | dump_status_reg(&status); | ||
229 | |||
230 | spi_message_init(&msg); | ||
231 | tx[2].tx_buf = &initaddr; | ||
232 | tx[2].len = sizeof(initaddr); | ||
233 | spi_message_add_tail(&tx[2], &msg); | ||
234 | ret = spi_sync(spi, &msg); | ||
235 | if (ret) | ||
236 | goto fail; | ||
237 | |||
238 | get_status(spi, &status); | ||
239 | dump_status_reg(&status); | ||
240 | |||
241 | return 0; | ||
242 | fail: | ||
243 | dev_err(&mgr->dev, "Error during FPGA init.\n"); | ||
244 | |||
245 | return ret; | ||
246 | } | ||
247 | |||
248 | static int machxo2_write(struct fpga_manager *mgr, const char *buf, | ||
249 | size_t count) | ||
250 | { | ||
251 | struct spi_device *spi = mgr->priv; | ||
252 | struct spi_message msg; | ||
253 | struct spi_transfer tx; | ||
254 | static const u8 progincr[] = LSC_PROGINCRNV; | ||
255 | u8 payload[MACHXO2_BUF_SIZE]; | ||
256 | unsigned long status; | ||
257 | int i, ret; | ||
258 | |||
259 | if (count % MACHXO2_PAGE_SIZE != 0) { | ||
260 | dev_err(&mgr->dev, "Malformed payload.\n"); | ||
261 | return -EINVAL; | ||
262 | } | ||
263 | get_status(spi, &status); | ||
264 | dump_status_reg(&status); | ||
265 | memcpy(payload, &progincr, sizeof(progincr)); | ||
266 | for (i = 0; i < count; i += MACHXO2_PAGE_SIZE) { | ||
267 | memcpy(&payload[sizeof(progincr)], &buf[i], MACHXO2_PAGE_SIZE); | ||
268 | memset(&tx, 0, sizeof(tx)); | ||
269 | spi_message_init(&msg); | ||
270 | tx.tx_buf = payload; | ||
271 | tx.len = MACHXO2_BUF_SIZE; | ||
272 | tx.delay_usecs = MACHXO2_HIGH_DELAY_USEC; | ||
273 | spi_message_add_tail(&tx, &msg); | ||
274 | ret = spi_sync(spi, &msg); | ||
275 | if (ret) { | ||
276 | dev_err(&mgr->dev, "Error loading the bitstream.\n"); | ||
277 | return ret; | ||
278 | } | ||
279 | } | ||
280 | get_status(spi, &status); | ||
281 | dump_status_reg(&status); | ||
282 | |||
283 | return 0; | ||
284 | } | ||
285 | |||
286 | static int machxo2_write_complete(struct fpga_manager *mgr, | ||
287 | struct fpga_image_info *info) | ||
288 | { | ||
289 | struct spi_device *spi = mgr->priv; | ||
290 | struct spi_message msg; | ||
291 | struct spi_transfer tx[2]; | ||
292 | static const u8 progdone[] = ISC_PROGRAMDONE; | ||
293 | static const u8 refresh[] = LSC_REFRESH; | ||
294 | unsigned long status; | ||
295 | int ret, refreshloop = 0; | ||
296 | |||
297 | memset(tx, 0, sizeof(tx)); | ||
298 | spi_message_init(&msg); | ||
299 | tx[0].tx_buf = &progdone; | ||
300 | tx[0].len = sizeof(progdone); | ||
301 | spi_message_add_tail(&tx[0], &msg); | ||
302 | ret = spi_sync(spi, &msg); | ||
303 | if (ret) | ||
304 | goto fail; | ||
305 | ret = wait_until_not_busy(spi); | ||
306 | if (ret) | ||
307 | goto fail; | ||
308 | |||
309 | get_status(spi, &status); | ||
310 | dump_status_reg(&status); | ||
311 | if (!test_bit(DONE, &status)) { | ||
312 | machxo2_cleanup(mgr); | ||
313 | goto fail; | ||
314 | } | ||
315 | |||
316 | do { | ||
317 | spi_message_init(&msg); | ||
318 | tx[1].tx_buf = &refresh; | ||
319 | tx[1].len = sizeof(refresh); | ||
320 | tx[1].delay_usecs = MACHXO2_REFRESH_USEC; | ||
321 | spi_message_add_tail(&tx[1], &msg); | ||
322 | ret = spi_sync(spi, &msg); | ||
323 | if (ret) | ||
324 | goto fail; | ||
325 | |||
326 | /* check refresh status */ | ||
327 | get_status(spi, &status); | ||
328 | dump_status_reg(&status); | ||
329 | if (!test_bit(BUSY, &status) && test_bit(DONE, &status) && | ||
330 | get_err(&status) == ENOERR) | ||
331 | break; | ||
332 | if (++refreshloop == MACHXO2_MAX_REFRESH_LOOP) { | ||
333 | machxo2_cleanup(mgr); | ||
334 | goto fail; | ||
335 | } | ||
336 | } while (1); | ||
337 | |||
338 | get_status(spi, &status); | ||
339 | dump_status_reg(&status); | ||
340 | |||
341 | return 0; | ||
342 | fail: | ||
343 | dev_err(&mgr->dev, "Refresh failed.\n"); | ||
344 | |||
345 | return ret; | ||
346 | } | ||
347 | |||
348 | static const struct fpga_manager_ops machxo2_ops = { | ||
349 | .state = machxo2_spi_state, | ||
350 | .write_init = machxo2_write_init, | ||
351 | .write = machxo2_write, | ||
352 | .write_complete = machxo2_write_complete, | ||
353 | }; | ||
354 | |||
355 | static int machxo2_spi_probe(struct spi_device *spi) | ||
356 | { | ||
357 | struct device *dev = &spi->dev; | ||
358 | struct fpga_manager *mgr; | ||
359 | int ret; | ||
360 | |||
361 | if (spi->max_speed_hz > MACHXO2_MAX_SPEED) { | ||
362 | dev_err(dev, "Speed is too high\n"); | ||
363 | return -EINVAL; | ||
364 | } | ||
365 | |||
366 | mgr = fpga_mgr_create(dev, "Lattice MachXO2 SPI FPGA Manager", | ||
367 | &machxo2_ops, spi); | ||
368 | if (!mgr) | ||
369 | return -ENOMEM; | ||
370 | |||
371 | spi_set_drvdata(spi, mgr); | ||
372 | |||
373 | ret = fpga_mgr_register(mgr); | ||
374 | if (ret) | ||
375 | fpga_mgr_free(mgr); | ||
376 | |||
377 | return ret; | ||
378 | } | ||
379 | |||
380 | static int machxo2_spi_remove(struct spi_device *spi) | ||
381 | { | ||
382 | struct fpga_manager *mgr = spi_get_drvdata(spi); | ||
383 | |||
384 | fpga_mgr_unregister(mgr); | ||
385 | |||
386 | return 0; | ||
387 | } | ||
388 | |||
389 | static const struct of_device_id of_match[] = { | ||
390 | { .compatible = "lattice,machxo2-slave-spi", }, | ||
391 | {} | ||
392 | }; | ||
393 | MODULE_DEVICE_TABLE(of, of_match); | ||
394 | |||
395 | static const struct spi_device_id lattice_ids[] = { | ||
396 | { "machxo2-slave-spi", 0 }, | ||
397 | { }, | ||
398 | }; | ||
399 | MODULE_DEVICE_TABLE(spi, lattice_ids); | ||
400 | |||
401 | static struct spi_driver machxo2_spi_driver = { | ||
402 | .driver = { | ||
403 | .name = "machxo2-slave-spi", | ||
404 | .of_match_table = of_match_ptr(of_match), | ||
405 | }, | ||
406 | .probe = machxo2_spi_probe, | ||
407 | .remove = machxo2_spi_remove, | ||
408 | .id_table = lattice_ids, | ||
409 | }; | ||
410 | |||
411 | module_spi_driver(machxo2_spi_driver) | ||
412 | |||
413 | MODULE_AUTHOR("Paolo Pisati <p.pisati@gmail.com>"); | ||
414 | MODULE_DESCRIPTION("Load Lattice FPGA firmware over SPI"); | ||
415 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/fpga/of-fpga-region.c b/drivers/fpga/of-fpga-region.c index 119ff75522f1..35fabb8083fb 100644 --- a/drivers/fpga/of-fpga-region.c +++ b/drivers/fpga/of-fpga-region.c | |||
@@ -1,22 +1,10 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
1 | /* | 2 | /* |
2 | * FPGA Region - Device Tree support for FPGA programming under Linux | 3 | * FPGA Region - Device Tree support for FPGA programming under Linux |
3 | * | 4 | * |
4 | * Copyright (C) 2013-2016 Altera Corporation | 5 | * Copyright (C) 2013-2016 Altera Corporation |
5 | * Copyright (C) 2017 Intel Corporation | 6 | * Copyright (C) 2017 Intel Corporation |
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms and conditions of the GNU General Public License, | ||
9 | * version 2, as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
14 | * more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along with | ||
17 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
18 | */ | 7 | */ |
19 | |||
20 | #include <linux/fpga/fpga-bridge.h> | 8 | #include <linux/fpga/fpga-bridge.h> |
21 | #include <linux/fpga/fpga-mgr.h> | 9 | #include <linux/fpga/fpga-mgr.h> |
22 | #include <linux/fpga/fpga-region.h> | 10 | #include <linux/fpga/fpga-region.h> |
@@ -422,27 +410,25 @@ static int of_fpga_region_probe(struct platform_device *pdev) | |||
422 | if (IS_ERR(mgr)) | 410 | if (IS_ERR(mgr)) |
423 | return -EPROBE_DEFER; | 411 | return -EPROBE_DEFER; |
424 | 412 | ||
425 | region = devm_kzalloc(dev, sizeof(*region), GFP_KERNEL); | 413 | region = fpga_region_create(dev, mgr, of_fpga_region_get_bridges); |
426 | if (!region) { | 414 | if (!region) { |
427 | ret = -ENOMEM; | 415 | ret = -ENOMEM; |
428 | goto eprobe_mgr_put; | 416 | goto eprobe_mgr_put; |
429 | } | 417 | } |
430 | 418 | ||
431 | region->mgr = mgr; | 419 | ret = fpga_region_register(region); |
432 | |||
433 | /* Specify how to get bridges for this type of region. */ | ||
434 | region->get_bridges = of_fpga_region_get_bridges; | ||
435 | |||
436 | ret = fpga_region_register(dev, region); | ||
437 | if (ret) | 420 | if (ret) |
438 | goto eprobe_mgr_put; | 421 | goto eprobe_free; |
439 | 422 | ||
440 | of_platform_populate(np, fpga_region_of_match, NULL, ®ion->dev); | 423 | of_platform_populate(np, fpga_region_of_match, NULL, ®ion->dev); |
424 | dev_set_drvdata(dev, region); | ||
441 | 425 | ||
442 | dev_info(dev, "FPGA Region probed\n"); | 426 | dev_info(dev, "FPGA Region probed\n"); |
443 | 427 | ||
444 | return 0; | 428 | return 0; |
445 | 429 | ||
430 | eprobe_free: | ||
431 | fpga_region_free(region); | ||
446 | eprobe_mgr_put: | 432 | eprobe_mgr_put: |
447 | fpga_mgr_put(mgr); | 433 | fpga_mgr_put(mgr); |
448 | return ret; | 434 | return ret; |
diff --git a/drivers/fpga/socfpga-a10.c b/drivers/fpga/socfpga-a10.c index a46e343a5b72..be30c48eb6e4 100644 --- a/drivers/fpga/socfpga-a10.c +++ b/drivers/fpga/socfpga-a10.c | |||
@@ -1,21 +1,9 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
1 | /* | 2 | /* |
2 | * FPGA Manager Driver for Altera Arria10 SoCFPGA | 3 | * FPGA Manager Driver for Altera Arria10 SoCFPGA |
3 | * | 4 | * |
4 | * Copyright (C) 2015-2016 Altera Corporation | 5 | * Copyright (C) 2015-2016 Altera Corporation |
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License along with | ||
16 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | 6 | */ |
18 | |||
19 | #include <linux/clk.h> | 7 | #include <linux/clk.h> |
20 | #include <linux/device.h> | 8 | #include <linux/device.h> |
21 | #include <linux/delay.h> | 9 | #include <linux/delay.h> |
@@ -482,6 +470,7 @@ static int socfpga_a10_fpga_probe(struct platform_device *pdev) | |||
482 | struct device *dev = &pdev->dev; | 470 | struct device *dev = &pdev->dev; |
483 | struct a10_fpga_priv *priv; | 471 | struct a10_fpga_priv *priv; |
484 | void __iomem *reg_base; | 472 | void __iomem *reg_base; |
473 | struct fpga_manager *mgr; | ||
485 | struct resource *res; | 474 | struct resource *res; |
486 | int ret; | 475 | int ret; |
487 | 476 | ||
@@ -519,9 +508,16 @@ static int socfpga_a10_fpga_probe(struct platform_device *pdev) | |||
519 | return -EBUSY; | 508 | return -EBUSY; |
520 | } | 509 | } |
521 | 510 | ||
522 | ret = fpga_mgr_register(dev, "SoCFPGA Arria10 FPGA Manager", | 511 | mgr = fpga_mgr_create(dev, "SoCFPGA Arria10 FPGA Manager", |
523 | &socfpga_a10_fpga_mgr_ops, priv); | 512 | &socfpga_a10_fpga_mgr_ops, priv); |
513 | if (!mgr) | ||
514 | return -ENOMEM; | ||
515 | |||
516 | platform_set_drvdata(pdev, mgr); | ||
517 | |||
518 | ret = fpga_mgr_register(mgr); | ||
524 | if (ret) { | 519 | if (ret) { |
520 | fpga_mgr_free(mgr); | ||
525 | clk_disable_unprepare(priv->clk); | 521 | clk_disable_unprepare(priv->clk); |
526 | return ret; | 522 | return ret; |
527 | } | 523 | } |
@@ -534,7 +530,7 @@ static int socfpga_a10_fpga_remove(struct platform_device *pdev) | |||
534 | struct fpga_manager *mgr = platform_get_drvdata(pdev); | 530 | struct fpga_manager *mgr = platform_get_drvdata(pdev); |
535 | struct a10_fpga_priv *priv = mgr->priv; | 531 | struct a10_fpga_priv *priv = mgr->priv; |
536 | 532 | ||
537 | fpga_mgr_unregister(&pdev->dev); | 533 | fpga_mgr_unregister(mgr); |
538 | clk_disable_unprepare(priv->clk); | 534 | clk_disable_unprepare(priv->clk); |
539 | 535 | ||
540 | return 0; | 536 | return 0; |
diff --git a/drivers/fpga/socfpga.c b/drivers/fpga/socfpga.c index b6672e66cda6..959d71f26896 100644 --- a/drivers/fpga/socfpga.c +++ b/drivers/fpga/socfpga.c | |||
@@ -1,19 +1,8 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
1 | /* | 2 | /* |
2 | * FPGA Manager Driver for Altera SOCFPGA | 3 | * FPGA Manager Driver for Altera SOCFPGA |
3 | * | 4 | * |
4 | * Copyright (C) 2013-2015 Altera Corporation | 5 | * Copyright (C) 2013-2015 Altera Corporation |
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License along with | ||
16 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | 6 | */ |
18 | #include <linux/completion.h> | 7 | #include <linux/completion.h> |
19 | #include <linux/delay.h> | 8 | #include <linux/delay.h> |
@@ -555,6 +544,7 @@ static int socfpga_fpga_probe(struct platform_device *pdev) | |||
555 | { | 544 | { |
556 | struct device *dev = &pdev->dev; | 545 | struct device *dev = &pdev->dev; |
557 | struct socfpga_fpga_priv *priv; | 546 | struct socfpga_fpga_priv *priv; |
547 | struct fpga_manager *mgr; | ||
558 | struct resource *res; | 548 | struct resource *res; |
559 | int ret; | 549 | int ret; |
560 | 550 | ||
@@ -581,13 +571,25 @@ static int socfpga_fpga_probe(struct platform_device *pdev) | |||
581 | if (ret) | 571 | if (ret) |
582 | return ret; | 572 | return ret; |
583 | 573 | ||
584 | return fpga_mgr_register(dev, "Altera SOCFPGA FPGA Manager", | 574 | mgr = fpga_mgr_create(dev, "Altera SOCFPGA FPGA Manager", |
585 | &socfpga_fpga_ops, priv); | 575 | &socfpga_fpga_ops, priv); |
576 | if (!mgr) | ||
577 | return -ENOMEM; | ||
578 | |||
579 | platform_set_drvdata(pdev, mgr); | ||
580 | |||
581 | ret = fpga_mgr_register(mgr); | ||
582 | if (ret) | ||
583 | fpga_mgr_free(mgr); | ||
584 | |||
585 | return ret; | ||
586 | } | 586 | } |
587 | 587 | ||
588 | static int socfpga_fpga_remove(struct platform_device *pdev) | 588 | static int socfpga_fpga_remove(struct platform_device *pdev) |
589 | { | 589 | { |
590 | fpga_mgr_unregister(&pdev->dev); | 590 | struct fpga_manager *mgr = platform_get_drvdata(pdev); |
591 | |||
592 | fpga_mgr_unregister(mgr); | ||
591 | 593 | ||
592 | return 0; | 594 | return 0; |
593 | } | 595 | } |
diff --git a/drivers/fpga/ts73xx-fpga.c b/drivers/fpga/ts73xx-fpga.c index f6a96b42e2ca..08efd1895b1b 100644 --- a/drivers/fpga/ts73xx-fpga.c +++ b/drivers/fpga/ts73xx-fpga.c | |||
@@ -116,7 +116,9 @@ static int ts73xx_fpga_probe(struct platform_device *pdev) | |||
116 | { | 116 | { |
117 | struct device *kdev = &pdev->dev; | 117 | struct device *kdev = &pdev->dev; |
118 | struct ts73xx_fpga_priv *priv; | 118 | struct ts73xx_fpga_priv *priv; |
119 | struct fpga_manager *mgr; | ||
119 | struct resource *res; | 120 | struct resource *res; |
121 | int ret; | ||
120 | 122 | ||
121 | priv = devm_kzalloc(kdev, sizeof(*priv), GFP_KERNEL); | 123 | priv = devm_kzalloc(kdev, sizeof(*priv), GFP_KERNEL); |
122 | if (!priv) | 124 | if (!priv) |
@@ -131,13 +133,25 @@ static int ts73xx_fpga_probe(struct platform_device *pdev) | |||
131 | return PTR_ERR(priv->io_base); | 133 | return PTR_ERR(priv->io_base); |
132 | } | 134 | } |
133 | 135 | ||
134 | return fpga_mgr_register(kdev, "TS-73xx FPGA Manager", | 136 | mgr = fpga_mgr_create(kdev, "TS-73xx FPGA Manager", |
135 | &ts73xx_fpga_ops, priv); | 137 | &ts73xx_fpga_ops, priv); |
138 | if (!mgr) | ||
139 | return -ENOMEM; | ||
140 | |||
141 | platform_set_drvdata(pdev, mgr); | ||
142 | |||
143 | ret = fpga_mgr_register(mgr); | ||
144 | if (ret) | ||
145 | fpga_mgr_free(mgr); | ||
146 | |||
147 | return ret; | ||
136 | } | 148 | } |
137 | 149 | ||
138 | static int ts73xx_fpga_remove(struct platform_device *pdev) | 150 | static int ts73xx_fpga_remove(struct platform_device *pdev) |
139 | { | 151 | { |
140 | fpga_mgr_unregister(&pdev->dev); | 152 | struct fpga_manager *mgr = platform_get_drvdata(pdev); |
153 | |||
154 | fpga_mgr_unregister(mgr); | ||
141 | 155 | ||
142 | return 0; | 156 | return 0; |
143 | } | 157 | } |
diff --git a/drivers/fpga/xilinx-pr-decoupler.c b/drivers/fpga/xilinx-pr-decoupler.c index 0d7743089414..07ba1539e82c 100644 --- a/drivers/fpga/xilinx-pr-decoupler.c +++ b/drivers/fpga/xilinx-pr-decoupler.c | |||
@@ -94,6 +94,7 @@ MODULE_DEVICE_TABLE(of, xlnx_pr_decoupler_of_match); | |||
94 | static int xlnx_pr_decoupler_probe(struct platform_device *pdev) | 94 | static int xlnx_pr_decoupler_probe(struct platform_device *pdev) |
95 | { | 95 | { |
96 | struct xlnx_pr_decoupler_data *priv; | 96 | struct xlnx_pr_decoupler_data *priv; |
97 | struct fpga_bridge *br; | ||
97 | int err; | 98 | int err; |
98 | struct resource *res; | 99 | struct resource *res; |
99 | 100 | ||
@@ -120,16 +121,27 @@ static int xlnx_pr_decoupler_probe(struct platform_device *pdev) | |||
120 | 121 | ||
121 | clk_disable(priv->clk); | 122 | clk_disable(priv->clk); |
122 | 123 | ||
123 | err = fpga_bridge_register(&pdev->dev, "Xilinx PR Decoupler", | 124 | br = fpga_bridge_create(&pdev->dev, "Xilinx PR Decoupler", |
124 | &xlnx_pr_decoupler_br_ops, priv); | 125 | &xlnx_pr_decoupler_br_ops, priv); |
126 | if (!br) { | ||
127 | err = -ENOMEM; | ||
128 | goto err_clk; | ||
129 | } | ||
130 | |||
131 | platform_set_drvdata(pdev, br); | ||
125 | 132 | ||
133 | err = fpga_bridge_register(br); | ||
126 | if (err) { | 134 | if (err) { |
127 | dev_err(&pdev->dev, "unable to register Xilinx PR Decoupler"); | 135 | dev_err(&pdev->dev, "unable to register Xilinx PR Decoupler"); |
128 | clk_unprepare(priv->clk); | 136 | goto err_clk; |
129 | return err; | ||
130 | } | 137 | } |
131 | 138 | ||
132 | return 0; | 139 | return 0; |
140 | |||
141 | err_clk: | ||
142 | clk_unprepare(priv->clk); | ||
143 | |||
144 | return err; | ||
133 | } | 145 | } |
134 | 146 | ||
135 | static int xlnx_pr_decoupler_remove(struct platform_device *pdev) | 147 | static int xlnx_pr_decoupler_remove(struct platform_device *pdev) |
@@ -137,7 +149,7 @@ static int xlnx_pr_decoupler_remove(struct platform_device *pdev) | |||
137 | struct fpga_bridge *bridge = platform_get_drvdata(pdev); | 149 | struct fpga_bridge *bridge = platform_get_drvdata(pdev); |
138 | struct xlnx_pr_decoupler_data *p = bridge->priv; | 150 | struct xlnx_pr_decoupler_data *p = bridge->priv; |
139 | 151 | ||
140 | fpga_bridge_unregister(&pdev->dev); | 152 | fpga_bridge_unregister(bridge); |
141 | 153 | ||
142 | clk_unprepare(p->clk); | 154 | clk_unprepare(p->clk); |
143 | 155 | ||
diff --git a/drivers/fpga/xilinx-spi.c b/drivers/fpga/xilinx-spi.c index 9b62a4c2a3df..8d1945966533 100644 --- a/drivers/fpga/xilinx-spi.c +++ b/drivers/fpga/xilinx-spi.c | |||
@@ -143,6 +143,8 @@ static const struct fpga_manager_ops xilinx_spi_ops = { | |||
143 | static int xilinx_spi_probe(struct spi_device *spi) | 143 | static int xilinx_spi_probe(struct spi_device *spi) |
144 | { | 144 | { |
145 | struct xilinx_spi_conf *conf; | 145 | struct xilinx_spi_conf *conf; |
146 | struct fpga_manager *mgr; | ||
147 | int ret; | ||
146 | 148 | ||
147 | conf = devm_kzalloc(&spi->dev, sizeof(*conf), GFP_KERNEL); | 149 | conf = devm_kzalloc(&spi->dev, sizeof(*conf), GFP_KERNEL); |
148 | if (!conf) | 150 | if (!conf) |
@@ -165,13 +167,25 @@ static int xilinx_spi_probe(struct spi_device *spi) | |||
165 | return PTR_ERR(conf->done); | 167 | return PTR_ERR(conf->done); |
166 | } | 168 | } |
167 | 169 | ||
168 | return fpga_mgr_register(&spi->dev, "Xilinx Slave Serial FPGA Manager", | 170 | mgr = fpga_mgr_create(&spi->dev, "Xilinx Slave Serial FPGA Manager", |
169 | &xilinx_spi_ops, conf); | 171 | &xilinx_spi_ops, conf); |
172 | if (!mgr) | ||
173 | return -ENOMEM; | ||
174 | |||
175 | spi_set_drvdata(spi, mgr); | ||
176 | |||
177 | ret = fpga_mgr_register(mgr); | ||
178 | if (ret) | ||
179 | fpga_mgr_free(mgr); | ||
180 | |||
181 | return ret; | ||
170 | } | 182 | } |
171 | 183 | ||
172 | static int xilinx_spi_remove(struct spi_device *spi) | 184 | static int xilinx_spi_remove(struct spi_device *spi) |
173 | { | 185 | { |
174 | fpga_mgr_unregister(&spi->dev); | 186 | struct fpga_manager *mgr = spi_get_drvdata(spi); |
187 | |||
188 | fpga_mgr_unregister(mgr); | ||
175 | 189 | ||
176 | return 0; | 190 | return 0; |
177 | } | 191 | } |
diff --git a/drivers/fpga/zynq-fpga.c b/drivers/fpga/zynq-fpga.c index 70b15b303471..3110e00121ca 100644 --- a/drivers/fpga/zynq-fpga.c +++ b/drivers/fpga/zynq-fpga.c | |||
@@ -558,6 +558,7 @@ static int zynq_fpga_probe(struct platform_device *pdev) | |||
558 | { | 558 | { |
559 | struct device *dev = &pdev->dev; | 559 | struct device *dev = &pdev->dev; |
560 | struct zynq_fpga_priv *priv; | 560 | struct zynq_fpga_priv *priv; |
561 | struct fpga_manager *mgr; | ||
561 | struct resource *res; | 562 | struct resource *res; |
562 | int err; | 563 | int err; |
563 | 564 | ||
@@ -613,10 +614,17 @@ static int zynq_fpga_probe(struct platform_device *pdev) | |||
613 | 614 | ||
614 | clk_disable(priv->clk); | 615 | clk_disable(priv->clk); |
615 | 616 | ||
616 | err = fpga_mgr_register(dev, "Xilinx Zynq FPGA Manager", | 617 | mgr = fpga_mgr_create(dev, "Xilinx Zynq FPGA Manager", |
617 | &zynq_fpga_ops, priv); | 618 | &zynq_fpga_ops, priv); |
619 | if (!mgr) | ||
620 | return -ENOMEM; | ||
621 | |||
622 | platform_set_drvdata(pdev, mgr); | ||
623 | |||
624 | err = fpga_mgr_register(mgr); | ||
618 | if (err) { | 625 | if (err) { |
619 | dev_err(dev, "unable to register FPGA manager\n"); | 626 | dev_err(dev, "unable to register FPGA manager\n"); |
627 | fpga_mgr_free(mgr); | ||
620 | clk_unprepare(priv->clk); | 628 | clk_unprepare(priv->clk); |
621 | return err; | 629 | return err; |
622 | } | 630 | } |
@@ -632,7 +640,7 @@ static int zynq_fpga_remove(struct platform_device *pdev) | |||
632 | mgr = platform_get_drvdata(pdev); | 640 | mgr = platform_get_drvdata(pdev); |
633 | priv = mgr->priv; | 641 | priv = mgr->priv; |
634 | 642 | ||
635 | fpga_mgr_unregister(&pdev->dev); | 643 | fpga_mgr_unregister(mgr); |
636 | 644 | ||
637 | clk_unprepare(priv->clk); | 645 | clk_unprepare(priv->clk); |
638 | 646 | ||
diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c index 72855182b191..ced041899456 100644 --- a/drivers/hv/connection.c +++ b/drivers/hv/connection.c | |||
@@ -63,6 +63,9 @@ static __u32 vmbus_get_next_version(__u32 current_version) | |||
63 | case (VERSION_WIN10): | 63 | case (VERSION_WIN10): |
64 | return VERSION_WIN8_1; | 64 | return VERSION_WIN8_1; |
65 | 65 | ||
66 | case (VERSION_WIN10_V5): | ||
67 | return VERSION_WIN10; | ||
68 | |||
66 | case (VERSION_WS2008): | 69 | case (VERSION_WS2008): |
67 | default: | 70 | default: |
68 | return VERSION_INVAL; | 71 | return VERSION_INVAL; |
@@ -80,9 +83,29 @@ static int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, | |||
80 | 83 | ||
81 | msg = (struct vmbus_channel_initiate_contact *)msginfo->msg; | 84 | msg = (struct vmbus_channel_initiate_contact *)msginfo->msg; |
82 | 85 | ||
86 | memset(msg, 0, sizeof(*msg)); | ||
83 | msg->header.msgtype = CHANNELMSG_INITIATE_CONTACT; | 87 | msg->header.msgtype = CHANNELMSG_INITIATE_CONTACT; |
84 | msg->vmbus_version_requested = version; | 88 | msg->vmbus_version_requested = version; |
85 | msg->interrupt_page = virt_to_phys(vmbus_connection.int_page); | 89 | |
90 | /* | ||
91 | * VMBus protocol 5.0 (VERSION_WIN10_V5) requires that we must use | ||
92 | * VMBUS_MESSAGE_CONNECTION_ID_4 for the Initiate Contact Message, | ||
93 | * and for subsequent messages, we must use the Message Connection ID | ||
94 | * field in the host-returned Version Response Message. And, with | ||
95 | * VERSION_WIN10_V5, we don't use msg->interrupt_page, but we tell | ||
96 | * the host explicitly that we still use VMBUS_MESSAGE_SINT(2) for | ||
97 | * compatibility. | ||
98 | * | ||
99 | * On old hosts, we should always use VMBUS_MESSAGE_CONNECTION_ID (1). | ||
100 | */ | ||
101 | if (version >= VERSION_WIN10_V5) { | ||
102 | msg->msg_sint = VMBUS_MESSAGE_SINT; | ||
103 | vmbus_connection.msg_conn_id = VMBUS_MESSAGE_CONNECTION_ID_4; | ||
104 | } else { | ||
105 | msg->interrupt_page = virt_to_phys(vmbus_connection.int_page); | ||
106 | vmbus_connection.msg_conn_id = VMBUS_MESSAGE_CONNECTION_ID; | ||
107 | } | ||
108 | |||
86 | msg->monitor_page1 = virt_to_phys(vmbus_connection.monitor_pages[0]); | 109 | msg->monitor_page1 = virt_to_phys(vmbus_connection.monitor_pages[0]); |
87 | msg->monitor_page2 = virt_to_phys(vmbus_connection.monitor_pages[1]); | 110 | msg->monitor_page2 = virt_to_phys(vmbus_connection.monitor_pages[1]); |
88 | /* | 111 | /* |
@@ -137,6 +160,10 @@ static int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, | |||
137 | /* Check if successful */ | 160 | /* Check if successful */ |
138 | if (msginfo->response.version_response.version_supported) { | 161 | if (msginfo->response.version_response.version_supported) { |
139 | vmbus_connection.conn_state = CONNECTED; | 162 | vmbus_connection.conn_state = CONNECTED; |
163 | |||
164 | if (version >= VERSION_WIN10_V5) | ||
165 | vmbus_connection.msg_conn_id = | ||
166 | msginfo->response.version_response.msg_conn_id; | ||
140 | } else { | 167 | } else { |
141 | return -ECONNREFUSED; | 168 | return -ECONNREFUSED; |
142 | } | 169 | } |
@@ -354,13 +381,14 @@ void vmbus_on_event(unsigned long data) | |||
354 | */ | 381 | */ |
355 | int vmbus_post_msg(void *buffer, size_t buflen, bool can_sleep) | 382 | int vmbus_post_msg(void *buffer, size_t buflen, bool can_sleep) |
356 | { | 383 | { |
384 | struct vmbus_channel_message_header *hdr; | ||
357 | union hv_connection_id conn_id; | 385 | union hv_connection_id conn_id; |
358 | int ret = 0; | 386 | int ret = 0; |
359 | int retries = 0; | 387 | int retries = 0; |
360 | u32 usec = 1; | 388 | u32 usec = 1; |
361 | 389 | ||
362 | conn_id.asu32 = 0; | 390 | conn_id.asu32 = 0; |
363 | conn_id.u.id = VMBUS_MESSAGE_CONNECTION_ID; | 391 | conn_id.u.id = vmbus_connection.msg_conn_id; |
364 | 392 | ||
365 | /* | 393 | /* |
366 | * hv_post_message() can have transient failures because of | 394 | * hv_post_message() can have transient failures because of |
@@ -373,6 +401,18 @@ int vmbus_post_msg(void *buffer, size_t buflen, bool can_sleep) | |||
373 | switch (ret) { | 401 | switch (ret) { |
374 | case HV_STATUS_INVALID_CONNECTION_ID: | 402 | case HV_STATUS_INVALID_CONNECTION_ID: |
375 | /* | 403 | /* |
404 | * See vmbus_negotiate_version(): VMBus protocol 5.0 | ||
405 | * requires that we must use | ||
406 | * VMBUS_MESSAGE_CONNECTION_ID_4 for the Initiate | ||
407 | * Contact message, but on old hosts that only | ||
408 | * support VMBus protocol 4.0 or lower, here we get | ||
409 | * HV_STATUS_INVALID_CONNECTION_ID and we should | ||
410 | * return an error immediately without retrying. | ||
411 | */ | ||
412 | hdr = buffer; | ||
413 | if (hdr->msgtype == CHANNELMSG_INITIATE_CONTACT) | ||
414 | return -EINVAL; | ||
415 | /* | ||
376 | * We could get this if we send messages too | 416 | * We could get this if we send messages too |
377 | * frequently. | 417 | * frequently. |
378 | */ | 418 | */ |
diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h index f761bef36e77..72eaba3d50fc 100644 --- a/drivers/hv/hyperv_vmbus.h +++ b/drivers/hv/hyperv_vmbus.h | |||
@@ -187,6 +187,7 @@ struct hv_input_post_message { | |||
187 | 187 | ||
188 | enum { | 188 | enum { |
189 | VMBUS_MESSAGE_CONNECTION_ID = 1, | 189 | VMBUS_MESSAGE_CONNECTION_ID = 1, |
190 | VMBUS_MESSAGE_CONNECTION_ID_4 = 4, | ||
190 | VMBUS_MESSAGE_PORT_ID = 1, | 191 | VMBUS_MESSAGE_PORT_ID = 1, |
191 | VMBUS_EVENT_CONNECTION_ID = 2, | 192 | VMBUS_EVENT_CONNECTION_ID = 2, |
192 | VMBUS_EVENT_PORT_ID = 2, | 193 | VMBUS_EVENT_PORT_ID = 2, |
@@ -302,6 +303,8 @@ struct vmbus_connection { | |||
302 | */ | 303 | */ |
303 | int connect_cpu; | 304 | int connect_cpu; |
304 | 305 | ||
306 | u32 msg_conn_id; | ||
307 | |||
305 | atomic_t offer_in_progress; | 308 | atomic_t offer_in_progress; |
306 | 309 | ||
307 | enum vmbus_connect_state conn_state; | 310 | enum vmbus_connect_state conn_state; |
diff --git a/drivers/hwtracing/coresight/coresight-cpu-debug.c b/drivers/hwtracing/coresight/coresight-cpu-debug.c index 9cdb3fbc8c1f..45b2460f3166 100644 --- a/drivers/hwtracing/coresight/coresight-cpu-debug.c +++ b/drivers/hwtracing/coresight/coresight-cpu-debug.c | |||
@@ -1,20 +1,8 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
1 | /* | 2 | /* |
2 | * Copyright (c) 2017 Linaro Limited. All rights reserved. | 3 | * Copyright (c) 2017 Linaro Limited. All rights reserved. |
3 | * | 4 | * |
4 | * Author: Leo Yan <leo.yan@linaro.org> | 5 | * Author: Leo Yan <leo.yan@linaro.org> |
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License version 2 as published by | ||
8 | * the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License along with | ||
16 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | * | ||
18 | */ | 6 | */ |
19 | #include <linux/amba/bus.h> | 7 | #include <linux/amba/bus.h> |
20 | #include <linux/coresight.h> | 8 | #include <linux/coresight.h> |
@@ -315,7 +303,7 @@ static void debug_dump_regs(struct debug_drvdata *drvdata) | |||
315 | } | 303 | } |
316 | 304 | ||
317 | pc = debug_adjust_pc(drvdata); | 305 | pc = debug_adjust_pc(drvdata); |
318 | dev_emerg(dev, " EDPCSR: [<%px>] %pS\n", (void *)pc, (void *)pc); | 306 | dev_emerg(dev, " EDPCSR: %pS\n", (void *)pc); |
319 | 307 | ||
320 | if (drvdata->edcidsr_present) | 308 | if (drvdata->edcidsr_present) |
321 | dev_emerg(dev, " EDCIDSR: %08x\n", drvdata->edcidsr); | 309 | dev_emerg(dev, " EDCIDSR: %08x\n", drvdata->edcidsr); |
diff --git a/drivers/hwtracing/coresight/coresight-dynamic-replicator.c b/drivers/hwtracing/coresight/coresight-dynamic-replicator.c index 043da86b0fe9..f6d0571ab9dd 100644 --- a/drivers/hwtracing/coresight/coresight-dynamic-replicator.c +++ b/drivers/hwtracing/coresight/coresight-dynamic-replicator.c | |||
@@ -1,14 +1,6 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
1 | /* | 2 | /* |
2 | * Copyright (c) 2011-2015, The Linux Foundation. All rights reserved. | 3 | * Copyright (c) 2011-2015, The Linux Foundation. All rights reserved. |
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 and | ||
6 | * only version 2 as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | */ | 4 | */ |
13 | 5 | ||
14 | #include <linux/amba/bus.h> | 6 | #include <linux/amba/bus.h> |
diff --git a/drivers/hwtracing/coresight/coresight-etb10.c b/drivers/hwtracing/coresight/coresight-etb10.c index 580cd381adf3..9b6c55523c58 100644 --- a/drivers/hwtracing/coresight/coresight-etb10.c +++ b/drivers/hwtracing/coresight/coresight-etb10.c | |||
@@ -1,15 +1,8 @@ | |||
1 | /* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. | 1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | ||
3 | * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. | ||
2 | * | 4 | * |
3 | * Description: CoreSight Embedded Trace Buffer driver | 5 | * Description: CoreSight Embedded Trace Buffer driver |
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 version 2 and | ||
7 | * only version 2 as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | */ | 6 | */ |
14 | 7 | ||
15 | #include <asm/local.h> | 8 | #include <asm/local.h> |
diff --git a/drivers/hwtracing/coresight/coresight-etm-cp14.c b/drivers/hwtracing/coresight/coresight-etm-cp14.c index 12a220682117..4174a8d355d2 100644 --- a/drivers/hwtracing/coresight/coresight-etm-cp14.c +++ b/drivers/hwtracing/coresight/coresight-etm-cp14.c | |||
@@ -1,13 +1,6 @@ | |||
1 | /* Copyright (c) 2012, The Linux Foundation. All rights reserved. | 1 | // SPDX-License-Identifier: GPL-2.0 |
2 | * | 2 | /* |
3 | * This program is free software; you can redistribute it and/or modify | 3 | * Copyright (c) 2012, The Linux Foundation. All rights reserved. |
4 | * it under the terms of the GNU General Public License version 2 and | ||
5 | * only version 2 as published by the Free Software Foundation. | ||
6 | * | ||
7 | * This program is distributed in the hope that it will be useful, | ||
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
10 | * GNU General Public License for more details. | ||
11 | */ | 4 | */ |
12 | 5 | ||
13 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | 6 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c index 4e5ed6597f2f..677695635211 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.c +++ b/drivers/hwtracing/coresight/coresight-etm-perf.c | |||
@@ -1,18 +1,7 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
1 | /* | 2 | /* |
2 | * Copyright(C) 2015 Linaro Limited. All rights reserved. | 3 | * Copyright(C) 2015 Linaro Limited. All rights reserved. |
3 | * Author: Mathieu Poirier <mathieu.poirier@linaro.org> | 4 | * Author: Mathieu Poirier <mathieu.poirier@linaro.org> |
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License version 2 as published by | ||
7 | * the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along with | ||
15 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | 5 | */ |
17 | 6 | ||
18 | #include <linux/coresight.h> | 7 | #include <linux/coresight.h> |
diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.h b/drivers/hwtracing/coresight/coresight-etm-perf.h index 3ffc9feb2d64..4197df4faf5e 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.h +++ b/drivers/hwtracing/coresight/coresight-etm-perf.h | |||
@@ -1,18 +1,7 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
1 | /* | 2 | /* |
2 | * Copyright(C) 2015 Linaro Limited. All rights reserved. | 3 | * Copyright(C) 2015 Linaro Limited. All rights reserved. |
3 | * Author: Mathieu Poirier <mathieu.poirier@linaro.org> | 4 | * Author: Mathieu Poirier <mathieu.poirier@linaro.org> |
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License version 2 as published by | ||
7 | * the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along with | ||
15 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | 5 | */ |
17 | 6 | ||
18 | #ifndef _CORESIGHT_ETM_PERF_H | 7 | #ifndef _CORESIGHT_ETM_PERF_H |
diff --git a/drivers/hwtracing/coresight/coresight-etm.h b/drivers/hwtracing/coresight/coresight-etm.h index 70b0a248c321..e8b4549e30e2 100644 --- a/drivers/hwtracing/coresight/coresight-etm.h +++ b/drivers/hwtracing/coresight/coresight-etm.h | |||
@@ -1,13 +1,6 @@ | |||
1 | /* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
2 | * | 2 | /* |
3 | * This program is free software; you can redistribute it and/or modify | 3 | * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. |
4 | * it under the terms of the GNU General Public License version 2 and | ||
5 | * only version 2 as published by the Free Software Foundation. | ||
6 | * | ||
7 | * This program is distributed in the hope that it will be useful, | ||
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
10 | * GNU General Public License for more details. | ||
11 | */ | 4 | */ |
12 | 5 | ||
13 | #ifndef _CORESIGHT_CORESIGHT_ETM_H | 6 | #ifndef _CORESIGHT_CORESIGHT_ETM_H |
diff --git a/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c index 6e547ec6fead..9435c1481f61 100644 --- a/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c | |||
@@ -1,18 +1,7 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
1 | /* | 2 | /* |
2 | * Copyright(C) 2015 Linaro Limited. All rights reserved. | 3 | * Copyright(C) 2015 Linaro Limited. All rights reserved. |
3 | * Author: Mathieu Poirier <mathieu.poirier@linaro.org> | 4 | * Author: Mathieu Poirier <mathieu.poirier@linaro.org> |
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License version 2 as published by | ||
7 | * the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along with | ||
15 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | 5 | */ |
17 | 6 | ||
18 | #include <linux/pm_runtime.h> | 7 | #include <linux/pm_runtime.h> |
diff --git a/drivers/hwtracing/coresight/coresight-etm3x.c b/drivers/hwtracing/coresight/coresight-etm3x.c index 39f42fdd503d..15ed64d51a5b 100644 --- a/drivers/hwtracing/coresight/coresight-etm3x.c +++ b/drivers/hwtracing/coresight/coresight-etm3x.c | |||
@@ -1,15 +1,8 @@ | |||
1 | /* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. | 1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | ||
3 | * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. | ||
2 | * | 4 | * |
3 | * Description: CoreSight Program Flow Trace driver | 5 | * Description: CoreSight Program Flow Trace driver |
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 version 2 and | ||
7 | * only version 2 as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | */ | 6 | */ |
14 | 7 | ||
15 | #include <linux/kernel.h> | 8 | #include <linux/kernel.h> |
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c index d21961710713..4eb8da785ce0 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c | |||
@@ -1,18 +1,7 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
1 | /* | 2 | /* |
2 | * Copyright(C) 2015 Linaro Limited. All rights reserved. | 3 | * Copyright(C) 2015 Linaro Limited. All rights reserved. |
3 | * Author: Mathieu Poirier <mathieu.poirier@linaro.org> | 4 | * Author: Mathieu Poirier <mathieu.poirier@linaro.org> |
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License version 2 as published by | ||
7 | * the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along with | ||
15 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | 5 | */ |
17 | 6 | ||
18 | #include <linux/pm_runtime.h> | 7 | #include <linux/pm_runtime.h> |
diff --git a/drivers/hwtracing/coresight/coresight-etm4x.c b/drivers/hwtracing/coresight/coresight-etm4x.c index cf364a514c12..9bc04c50d45b 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x.c +++ b/drivers/hwtracing/coresight/coresight-etm4x.c | |||
@@ -1,13 +1,6 @@ | |||
1 | /* Copyright (c) 2014, The Linux Foundation. All rights reserved. | 1 | // SPDX-License-Identifier: GPL-2.0 |
2 | * | 2 | /* |
3 | * This program is free software; you can redistribute it and/or modify | 3 | * Copyright (c) 2014, The Linux Foundation. All rights reserved. |
4 | * it under the terms of the GNU General Public License version 2 and | ||
5 | * only version 2 as published by the Free Software Foundation. | ||
6 | * | ||
7 | * This program is distributed in the hope that it will be useful, | ||
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
10 | * GNU General Public License for more details. | ||
11 | */ | 4 | */ |
12 | 5 | ||
13 | #include <linux/kernel.h> | 6 | #include <linux/kernel.h> |
diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h index b3b5ea7b7fb3..b7c4a6f6c6b9 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x.h +++ b/drivers/hwtracing/coresight/coresight-etm4x.h | |||
@@ -1,13 +1,6 @@ | |||
1 | /* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
2 | * | 2 | /* |
3 | * This program is free software; you can redistribute it and/or modify | 3 | * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. |
4 | * it under the terms of the GNU General Public License version 2 and | ||
5 | * only version 2 as published by the Free Software Foundation. | ||
6 | * | ||
7 | * This program is distributed in the hope that it will be useful, | ||
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
10 | * GNU General Public License for more details. | ||
11 | */ | 4 | */ |
12 | 5 | ||
13 | #ifndef _CORESIGHT_CORESIGHT_ETM_H | 6 | #ifndef _CORESIGHT_CORESIGHT_ETM_H |
diff --git a/drivers/hwtracing/coresight/coresight-funnel.c b/drivers/hwtracing/coresight/coresight-funnel.c index 9f8ac0bef853..448145a36675 100644 --- a/drivers/hwtracing/coresight/coresight-funnel.c +++ b/drivers/hwtracing/coresight/coresight-funnel.c | |||
@@ -1,15 +1,8 @@ | |||
1 | /* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. | 1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | ||
3 | * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. | ||
2 | * | 4 | * |
3 | * Description: CoreSight Funnel driver | 5 | * Description: CoreSight Funnel driver |
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 version 2 and | ||
7 | * only version 2 as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | */ | 6 | */ |
14 | 7 | ||
15 | #include <linux/kernel.h> | 8 | #include <linux/kernel.h> |
diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h index f1d0e21d8cab..0e5a74dae6a6 100644 --- a/drivers/hwtracing/coresight/coresight-priv.h +++ b/drivers/hwtracing/coresight/coresight-priv.h | |||
@@ -1,13 +1,6 @@ | |||
1 | /* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
2 | * | 2 | /* |
3 | * This program is free software; you can redistribute it and/or modify | 3 | * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. |
4 | * it under the terms of the GNU General Public License version 2 and | ||
5 | * only version 2 as published by the Free Software Foundation. | ||
6 | * | ||
7 | * This program is distributed in the hope that it will be useful, | ||
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
10 | * GNU General Public License for more details. | ||
11 | */ | 4 | */ |
12 | 5 | ||
13 | #ifndef _CORESIGHT_PRIV_H | 6 | #ifndef _CORESIGHT_PRIV_H |
diff --git a/drivers/hwtracing/coresight/coresight-replicator.c b/drivers/hwtracing/coresight/coresight-replicator.c index 3756e71cb8f5..8d2eaaab6c2f 100644 --- a/drivers/hwtracing/coresight/coresight-replicator.c +++ b/drivers/hwtracing/coresight/coresight-replicator.c | |||
@@ -1,15 +1,8 @@ | |||
1 | /* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. | 1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | ||
3 | * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. | ||
2 | * | 4 | * |
3 | * Description: CoreSight Replicator driver | 5 | * Description: CoreSight Replicator driver |
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 version 2 and | ||
7 | * only version 2 as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | */ | 6 | */ |
14 | 7 | ||
15 | #include <linux/kernel.h> | 8 | #include <linux/kernel.h> |
diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/hwtracing/coresight/coresight-stm.c index 15e7ef3891f5..c46c70aec1d5 100644 --- a/drivers/hwtracing/coresight/coresight-stm.c +++ b/drivers/hwtracing/coresight/coresight-stm.c | |||
@@ -1,16 +1,9 @@ | |||
1 | /* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. | 1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | ||
3 | * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. | ||
2 | * | 4 | * |
3 | * Description: CoreSight System Trace Macrocell driver | 5 | * Description: CoreSight System Trace Macrocell driver |
4 | * | 6 | * |
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 and | ||
7 | * only version 2 as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * Initial implementation by Pratik Patel | 7 | * Initial implementation by Pratik Patel |
15 | * (C) 2014-2015 Pratik Patel <pratikp@codeaurora.org> | 8 | * (C) 2014-2015 Pratik Patel <pratikp@codeaurora.org> |
16 | * | 9 | * |
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c index e2513b786242..61d849b11c26 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etf.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c | |||
@@ -1,18 +1,7 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
1 | /* | 2 | /* |
2 | * Copyright(C) 2016 Linaro Limited. All rights reserved. | 3 | * Copyright(C) 2016 Linaro Limited. All rights reserved. |
3 | * Author: Mathieu Poirier <mathieu.poirier@linaro.org> | 4 | * Author: Mathieu Poirier <mathieu.poirier@linaro.org> |
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License version 2 as published by | ||
7 | * the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along with | ||
15 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | 5 | */ |
17 | 6 | ||
18 | #include <linux/circ_buf.h> | 7 | #include <linux/circ_buf.h> |
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c index 68fbc8f7450e..02f747afa2ba 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c | |||
@@ -1,18 +1,7 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
1 | /* | 2 | /* |
2 | * Copyright(C) 2016 Linaro Limited. All rights reserved. | 3 | * Copyright(C) 2016 Linaro Limited. All rights reserved. |
3 | * Author: Mathieu Poirier <mathieu.poirier@linaro.org> | 4 | * Author: Mathieu Poirier <mathieu.poirier@linaro.org> |
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License version 2 as published by | ||
7 | * the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along with | ||
15 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | 5 | */ |
17 | 6 | ||
18 | #include <linux/coresight.h> | 7 | #include <linux/coresight.h> |
@@ -124,10 +113,9 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev) | |||
124 | bool used = false; | 113 | bool used = false; |
125 | unsigned long flags; | 114 | unsigned long flags; |
126 | void __iomem *vaddr = NULL; | 115 | void __iomem *vaddr = NULL; |
127 | dma_addr_t paddr; | 116 | dma_addr_t paddr = 0; |
128 | struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); | 117 | struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); |
129 | 118 | ||
130 | |||
131 | /* | 119 | /* |
132 | * If we don't have a buffer release the lock and allocate memory. | 120 | * If we don't have a buffer release the lock and allocate memory. |
133 | * Otherwise keep the lock and move along. | 121 | * Otherwise keep the lock and move along. |
@@ -164,11 +152,11 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev) | |||
164 | goto out; | 152 | goto out; |
165 | 153 | ||
166 | /* | 154 | /* |
167 | * If drvdata::buf == NULL, use the memory allocated above. | 155 | * If drvdata::vaddr == NULL, use the memory allocated above. |
168 | * Otherwise a buffer still exists from a previous session, so | 156 | * Otherwise a buffer still exists from a previous session, so |
169 | * simply use that. | 157 | * simply use that. |
170 | */ | 158 | */ |
171 | if (drvdata->buf == NULL) { | 159 | if (drvdata->vaddr == NULL) { |
172 | used = true; | 160 | used = true; |
173 | drvdata->vaddr = vaddr; | 161 | drvdata->vaddr = vaddr; |
174 | drvdata->paddr = paddr; | 162 | drvdata->paddr = paddr; |
diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c index 0ea04f588de0..456f122df74f 100644 --- a/drivers/hwtracing/coresight/coresight-tmc.c +++ b/drivers/hwtracing/coresight/coresight-tmc.c | |||
@@ -1,15 +1,7 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
1 | /* Copyright (c) 2012, The Linux Foundation. All rights reserved. | 2 | /* Copyright (c) 2012, The Linux Foundation. All rights reserved. |
2 | * | 3 | * |
3 | * Description: CoreSight Trace Memory Controller driver | 4 | * Description: CoreSight Trace Memory Controller driver |
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 version 2 and | ||
7 | * only version 2 as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | */ | 5 | */ |
14 | 6 | ||
15 | #include <linux/kernel.h> | 7 | #include <linux/kernel.h> |
diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h index 8df7a813f537..dfaff077a7fc 100644 --- a/drivers/hwtracing/coresight/coresight-tmc.h +++ b/drivers/hwtracing/coresight/coresight-tmc.h | |||
@@ -1,18 +1,7 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
1 | /* | 2 | /* |
2 | * Copyright(C) 2015 Linaro Limited. All rights reserved. | 3 | * Copyright(C) 2015 Linaro Limited. All rights reserved. |
3 | * Author: Mathieu Poirier <mathieu.poirier@linaro.org> | 4 | * Author: Mathieu Poirier <mathieu.poirier@linaro.org> |
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License version 2 as published by | ||
7 | * the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along with | ||
15 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | 5 | */ |
17 | 6 | ||
18 | #ifndef _CORESIGHT_TMC_H | 7 | #ifndef _CORESIGHT_TMC_H |
diff --git a/drivers/hwtracing/coresight/coresight-tpiu.c b/drivers/hwtracing/coresight/coresight-tpiu.c index 805f7c2210fe..01b7457fe8fc 100644 --- a/drivers/hwtracing/coresight/coresight-tpiu.c +++ b/drivers/hwtracing/coresight/coresight-tpiu.c | |||
@@ -1,15 +1,8 @@ | |||
1 | /* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. | 1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | ||
3 | * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. | ||
2 | * | 4 | * |
3 | * Description: CoreSight Trace Port Interface Unit driver | 5 | * Description: CoreSight Trace Port Interface Unit driver |
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 version 2 and | ||
7 | * only version 2 as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | */ | 6 | */ |
14 | 7 | ||
15 | #include <linux/kernel.h> | 8 | #include <linux/kernel.h> |
diff --git a/drivers/hwtracing/coresight/coresight.c b/drivers/hwtracing/coresight/coresight.c index 389c4baeca9d..29e834aab539 100644 --- a/drivers/hwtracing/coresight/coresight.c +++ b/drivers/hwtracing/coresight/coresight.c | |||
@@ -1,13 +1,6 @@ | |||
1 | /* Copyright (c) 2012, The Linux Foundation. All rights reserved. | 1 | // SPDX-License-Identifier: GPL-2.0 |
2 | * | 2 | /* |
3 | * This program is free software; you can redistribute it and/or modify | 3 | * Copyright (c) 2012, The Linux Foundation. All rights reserved. |
4 | * it under the terms of the GNU General Public License version 2 and | ||
5 | * only version 2 as published by the Free Software Foundation. | ||
6 | * | ||
7 | * This program is distributed in the hope that it will be useful, | ||
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
10 | * GNU General Public License for more details. | ||
11 | */ | 4 | */ |
12 | 5 | ||
13 | #include <linux/kernel.h> | 6 | #include <linux/kernel.h> |
@@ -1026,8 +1019,10 @@ struct coresight_device *coresight_register(struct coresight_desc *desc) | |||
1026 | dev_set_name(&csdev->dev, "%s", desc->pdata->name); | 1019 | dev_set_name(&csdev->dev, "%s", desc->pdata->name); |
1027 | 1020 | ||
1028 | ret = device_register(&csdev->dev); | 1021 | ret = device_register(&csdev->dev); |
1029 | if (ret) | 1022 | if (ret) { |
1030 | goto err_device_register; | 1023 | put_device(&csdev->dev); |
1024 | goto err_kzalloc_csdev; | ||
1025 | } | ||
1031 | 1026 | ||
1032 | mutex_lock(&coresight_mutex); | 1027 | mutex_lock(&coresight_mutex); |
1033 | 1028 | ||
@@ -1038,8 +1033,6 @@ struct coresight_device *coresight_register(struct coresight_desc *desc) | |||
1038 | 1033 | ||
1039 | return csdev; | 1034 | return csdev; |
1040 | 1035 | ||
1041 | err_device_register: | ||
1042 | kfree(conns); | ||
1043 | err_kzalloc_conns: | 1036 | err_kzalloc_conns: |
1044 | kfree(refcnts); | 1037 | kfree(refcnts); |
1045 | err_kzalloc_refcnts: | 1038 | err_kzalloc_refcnts: |
diff --git a/drivers/hwtracing/coresight/of_coresight.c b/drivers/hwtracing/coresight/of_coresight.c index 7c375443ede6..a33a92ebe74b 100644 --- a/drivers/hwtracing/coresight/of_coresight.c +++ b/drivers/hwtracing/coresight/of_coresight.c | |||
@@ -1,13 +1,6 @@ | |||
1 | /* Copyright (c) 2012, The Linux Foundation. All rights reserved. | 1 | // SPDX-License-Identifier: GPL-2.0 |
2 | * | 2 | /* |
3 | * This program is free software; you can redistribute it and/or modify | 3 | * Copyright (c) 2012, The Linux Foundation. All rights reserved. |
4 | * it under the terms of the GNU General Public License version 2 and | ||
5 | * only version 2 as published by the Free Software Foundation. | ||
6 | * | ||
7 | * This program is distributed in the hope that it will be useful, | ||
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
10 | * GNU General Public License for more details. | ||
11 | */ | 4 | */ |
12 | 5 | ||
13 | #include <linux/types.h> | 6 | #include <linux/types.h> |
diff --git a/drivers/hwtracing/stm/ftrace.c b/drivers/hwtracing/stm/ftrace.c index 7da75644c750..ce868e095410 100644 --- a/drivers/hwtracing/stm/ftrace.c +++ b/drivers/hwtracing/stm/ftrace.c | |||
@@ -1,16 +1,8 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
1 | /* | 2 | /* |
2 | * Simple kernel driver to link kernel Ftrace and an STM device | 3 | * Simple kernel driver to link kernel Ftrace and an STM device |
3 | * Copyright (c) 2016, Linaro Ltd. | 4 | * Copyright (c) 2016, Linaro Ltd. |
4 | * | 5 | * |
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms and conditions of the GNU General Public License, | ||
7 | * version 2, as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | * STM Ftrace will be registered as a trace_export. | 6 | * STM Ftrace will be registered as a trace_export. |
15 | */ | 7 | */ |
16 | 8 | ||
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 5d713008749b..3726eacdf65d 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig | |||
@@ -113,6 +113,20 @@ config IBM_ASM | |||
113 | for information on the specific driver level and support statement | 113 | for information on the specific driver level and support statement |
114 | for your IBM server. | 114 | for your IBM server. |
115 | 115 | ||
116 | config IBMVMC | ||
117 | tristate "IBM Virtual Management Channel support" | ||
118 | depends on PPC_PSERIES | ||
119 | help | ||
120 | This is the IBM POWER Virtual Management Channel | ||
121 | |||
122 | This driver is to be used for the POWER Virtual | ||
123 | Management Channel virtual adapter on the PowerVM | ||
124 | platform. It provides both request/response and | ||
125 | async message support through the /dev/ibmvmc node. | ||
126 | |||
127 | To compile this driver as a module, choose M here: the | ||
128 | module will be called ibmvmc. | ||
129 | |||
116 | config PHANTOM | 130 | config PHANTOM |
117 | tristate "Sensable PHANToM (PCI)" | 131 | tristate "Sensable PHANToM (PCI)" |
118 | depends on PCI | 132 | depends on PCI |
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 20be70c3f118..af22bbc3d00c 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile | |||
@@ -4,6 +4,7 @@ | |||
4 | # | 4 | # |
5 | 5 | ||
6 | obj-$(CONFIG_IBM_ASM) += ibmasm/ | 6 | obj-$(CONFIG_IBM_ASM) += ibmasm/ |
7 | obj-$(CONFIG_IBMVMC) += ibmvmc.o | ||
7 | obj-$(CONFIG_AD525X_DPOT) += ad525x_dpot.o | 8 | obj-$(CONFIG_AD525X_DPOT) += ad525x_dpot.o |
8 | obj-$(CONFIG_AD525X_DPOT_I2C) += ad525x_dpot-i2c.o | 9 | obj-$(CONFIG_AD525X_DPOT_I2C) += ad525x_dpot-i2c.o |
9 | obj-$(CONFIG_AD525X_DPOT_SPI) += ad525x_dpot-spi.o | 10 | obj-$(CONFIG_AD525X_DPOT_SPI) += ad525x_dpot-spi.o |
diff --git a/drivers/misc/cxl/context.c b/drivers/misc/cxl/context.c index 7ff315ad3692..c6ec872800a2 100644 --- a/drivers/misc/cxl/context.c +++ b/drivers/misc/cxl/context.c | |||
@@ -128,11 +128,12 @@ void cxl_context_set_mapping(struct cxl_context *ctx, | |||
128 | mutex_unlock(&ctx->mapping_lock); | 128 | mutex_unlock(&ctx->mapping_lock); |
129 | } | 129 | } |
130 | 130 | ||
131 | static int cxl_mmap_fault(struct vm_fault *vmf) | 131 | static vm_fault_t cxl_mmap_fault(struct vm_fault *vmf) |
132 | { | 132 | { |
133 | struct vm_area_struct *vma = vmf->vma; | 133 | struct vm_area_struct *vma = vmf->vma; |
134 | struct cxl_context *ctx = vma->vm_file->private_data; | 134 | struct cxl_context *ctx = vma->vm_file->private_data; |
135 | u64 area, offset; | 135 | u64 area, offset; |
136 | vm_fault_t ret; | ||
136 | 137 | ||
137 | offset = vmf->pgoff << PAGE_SHIFT; | 138 | offset = vmf->pgoff << PAGE_SHIFT; |
138 | 139 | ||
@@ -169,11 +170,11 @@ static int cxl_mmap_fault(struct vm_fault *vmf) | |||
169 | return VM_FAULT_SIGBUS; | 170 | return VM_FAULT_SIGBUS; |
170 | } | 171 | } |
171 | 172 | ||
172 | vm_insert_pfn(vma, vmf->address, (area + offset) >> PAGE_SHIFT); | 173 | ret = vmf_insert_pfn(vma, vmf->address, (area + offset) >> PAGE_SHIFT); |
173 | 174 | ||
174 | mutex_unlock(&ctx->status_mutex); | 175 | mutex_unlock(&ctx->status_mutex); |
175 | 176 | ||
176 | return VM_FAULT_NOPAGE; | 177 | return ret; |
177 | } | 178 | } |
178 | 179 | ||
179 | static const struct vm_operations_struct cxl_mmap_vmops = { | 180 | static const struct vm_operations_struct cxl_mmap_vmops = { |
diff --git a/drivers/misc/ibmvmc.c b/drivers/misc/ibmvmc.c new file mode 100644 index 000000000000..fb83d1375638 --- /dev/null +++ b/drivers/misc/ibmvmc.c | |||
@@ -0,0 +1,2418 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0+ | ||
2 | /* | ||
3 | * IBM Power Systems Virtual Management Channel Support. | ||
4 | * | ||
5 | * Copyright (c) 2004, 2018 IBM Corp. | ||
6 | * Dave Engebretsen engebret@us.ibm.com | ||
7 | * Steven Royer seroyer@linux.vnet.ibm.com | ||
8 | * Adam Reznechek adreznec@linux.vnet.ibm.com | ||
9 | * Bryant G. Ly <bryantly@linux.vnet.ibm.com> | ||
10 | */ | ||
11 | |||
12 | #include <linux/module.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/kthread.h> | ||
15 | #include <linux/major.h> | ||
16 | #include <linux/string.h> | ||
17 | #include <linux/fcntl.h> | ||
18 | #include <linux/slab.h> | ||
19 | #include <linux/poll.h> | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/fs.h> | ||
22 | #include <linux/interrupt.h> | ||
23 | #include <linux/spinlock.h> | ||
24 | #include <linux/percpu.h> | ||
25 | #include <linux/delay.h> | ||
26 | #include <linux/uaccess.h> | ||
27 | #include <linux/io.h> | ||
28 | #include <linux/miscdevice.h> | ||
29 | #include <linux/sched/signal.h> | ||
30 | |||
31 | #include <asm/byteorder.h> | ||
32 | #include <asm/irq.h> | ||
33 | #include <asm/vio.h> | ||
34 | |||
35 | #include "ibmvmc.h" | ||
36 | |||
37 | #define IBMVMC_DRIVER_VERSION "1.0" | ||
38 | |||
39 | /* | ||
40 | * Static global variables | ||
41 | */ | ||
42 | static DECLARE_WAIT_QUEUE_HEAD(ibmvmc_read_wait); | ||
43 | |||
44 | static const char ibmvmc_driver_name[] = "ibmvmc"; | ||
45 | |||
46 | static struct ibmvmc_struct ibmvmc; | ||
47 | static struct ibmvmc_hmc hmcs[MAX_HMCS]; | ||
48 | static struct crq_server_adapter ibmvmc_adapter; | ||
49 | |||
50 | static int ibmvmc_max_buf_pool_size = DEFAULT_BUF_POOL_SIZE; | ||
51 | static int ibmvmc_max_hmcs = DEFAULT_HMCS; | ||
52 | static int ibmvmc_max_mtu = DEFAULT_MTU; | ||
53 | |||
54 | static inline long h_copy_rdma(s64 length, u64 sliobn, u64 slioba, | ||
55 | u64 dliobn, u64 dlioba) | ||
56 | { | ||
57 | long rc = 0; | ||
58 | |||
59 | /* Ensure all writes to source memory are visible before hcall */ | ||
60 | dma_wmb(); | ||
61 | pr_debug("ibmvmc: h_copy_rdma(0x%llx, 0x%llx, 0x%llx, 0x%llx, 0x%llx\n", | ||
62 | length, sliobn, slioba, dliobn, dlioba); | ||
63 | rc = plpar_hcall_norets(H_COPY_RDMA, length, sliobn, slioba, | ||
64 | dliobn, dlioba); | ||
65 | pr_debug("ibmvmc: h_copy_rdma rc = 0x%lx\n", rc); | ||
66 | |||
67 | return rc; | ||
68 | } | ||
69 | |||
70 | static inline void h_free_crq(uint32_t unit_address) | ||
71 | { | ||
72 | long rc = 0; | ||
73 | |||
74 | do { | ||
75 | if (H_IS_LONG_BUSY(rc)) | ||
76 | msleep(get_longbusy_msecs(rc)); | ||
77 | |||
78 | rc = plpar_hcall_norets(H_FREE_CRQ, unit_address); | ||
79 | } while ((rc == H_BUSY) || (H_IS_LONG_BUSY(rc))); | ||
80 | } | ||
81 | |||
82 | /** | ||
83 | * h_request_vmc: - request a hypervisor virtual management channel device | ||
84 | * @vmc_index: drc index of the vmc device created | ||
85 | * | ||
86 | * Requests the hypervisor create a new virtual management channel device, | ||
87 | * allowing this partition to send hypervisor virtualization control | ||
88 | * commands. | ||
89 | * | ||
90 | * Return: | ||
91 | * 0 - Success | ||
92 | * Non-zero - Failure | ||
93 | */ | ||
94 | static inline long h_request_vmc(u32 *vmc_index) | ||
95 | { | ||
96 | long rc = 0; | ||
97 | unsigned long retbuf[PLPAR_HCALL_BUFSIZE]; | ||
98 | |||
99 | do { | ||
100 | if (H_IS_LONG_BUSY(rc)) | ||
101 | msleep(get_longbusy_msecs(rc)); | ||
102 | |||
103 | /* Call to request the VMC device from phyp */ | ||
104 | rc = plpar_hcall(H_REQUEST_VMC, retbuf); | ||
105 | pr_debug("ibmvmc: %s rc = 0x%lx\n", __func__, rc); | ||
106 | *vmc_index = retbuf[0]; | ||
107 | } while ((rc == H_BUSY) || (H_IS_LONG_BUSY(rc))); | ||
108 | |||
109 | return rc; | ||
110 | } | ||
111 | |||
112 | /* routines for managing a command/response queue */ | ||
113 | /** | ||
114 | * ibmvmc_handle_event: - Interrupt handler for crq events | ||
115 | * @irq: number of irq to handle, not used | ||
116 | * @dev_instance: crq_server_adapter that received interrupt | ||
117 | * | ||
118 | * Disables interrupts and schedules ibmvmc_task | ||
119 | * | ||
120 | * Always returns IRQ_HANDLED | ||
121 | */ | ||
122 | static irqreturn_t ibmvmc_handle_event(int irq, void *dev_instance) | ||
123 | { | ||
124 | struct crq_server_adapter *adapter = | ||
125 | (struct crq_server_adapter *)dev_instance; | ||
126 | |||
127 | vio_disable_interrupts(to_vio_dev(adapter->dev)); | ||
128 | tasklet_schedule(&adapter->work_task); | ||
129 | |||
130 | return IRQ_HANDLED; | ||
131 | } | ||
132 | |||
133 | /** | ||
134 | * ibmvmc_release_crq_queue - Release CRQ Queue | ||
135 | * | ||
136 | * @adapter: crq_server_adapter struct | ||
137 | * | ||
138 | * Return: | ||
139 | * 0 - Success | ||
140 | * Non-Zero - Failure | ||
141 | */ | ||
142 | static void ibmvmc_release_crq_queue(struct crq_server_adapter *adapter) | ||
143 | { | ||
144 | struct vio_dev *vdev = to_vio_dev(adapter->dev); | ||
145 | struct crq_queue *queue = &adapter->queue; | ||
146 | |||
147 | free_irq(vdev->irq, (void *)adapter); | ||
148 | tasklet_kill(&adapter->work_task); | ||
149 | |||
150 | if (adapter->reset_task) | ||
151 | kthread_stop(adapter->reset_task); | ||
152 | |||
153 | h_free_crq(vdev->unit_address); | ||
154 | dma_unmap_single(adapter->dev, | ||
155 | queue->msg_token, | ||
156 | queue->size * sizeof(*queue->msgs), DMA_BIDIRECTIONAL); | ||
157 | free_page((unsigned long)queue->msgs); | ||
158 | } | ||
159 | |||
160 | /** | ||
161 | * ibmvmc_reset_crq_queue - Reset CRQ Queue | ||
162 | * | ||
163 | * @adapter: crq_server_adapter struct | ||
164 | * | ||
165 | * This function calls h_free_crq and then calls H_REG_CRQ and does all the | ||
166 | * bookkeeping to get us back to where we can communicate. | ||
167 | * | ||
168 | * Return: | ||
169 | * 0 - Success | ||
170 | * Non-Zero - Failure | ||
171 | */ | ||
172 | static int ibmvmc_reset_crq_queue(struct crq_server_adapter *adapter) | ||
173 | { | ||
174 | struct vio_dev *vdev = to_vio_dev(adapter->dev); | ||
175 | struct crq_queue *queue = &adapter->queue; | ||
176 | int rc = 0; | ||
177 | |||
178 | /* Close the CRQ */ | ||
179 | h_free_crq(vdev->unit_address); | ||
180 | |||
181 | /* Clean out the queue */ | ||
182 | memset(queue->msgs, 0x00, PAGE_SIZE); | ||
183 | queue->cur = 0; | ||
184 | |||
185 | /* And re-open it again */ | ||
186 | rc = plpar_hcall_norets(H_REG_CRQ, | ||
187 | vdev->unit_address, | ||
188 | queue->msg_token, PAGE_SIZE); | ||
189 | if (rc == 2) | ||
190 | /* Adapter is good, but other end is not ready */ | ||
191 | dev_warn(adapter->dev, "Partner adapter not ready\n"); | ||
192 | else if (rc != 0) | ||
193 | dev_err(adapter->dev, "couldn't register crq--rc 0x%x\n", rc); | ||
194 | |||
195 | return rc; | ||
196 | } | ||
197 | |||
198 | /** | ||
199 | * crq_queue_next_crq: - Returns the next entry in message queue | ||
200 | * @queue: crq_queue to use | ||
201 | * | ||
202 | * Returns pointer to next entry in queue, or NULL if there are no new | ||
203 | * entried in the CRQ. | ||
204 | */ | ||
205 | static struct ibmvmc_crq_msg *crq_queue_next_crq(struct crq_queue *queue) | ||
206 | { | ||
207 | struct ibmvmc_crq_msg *crq; | ||
208 | unsigned long flags; | ||
209 | |||
210 | spin_lock_irqsave(&queue->lock, flags); | ||
211 | crq = &queue->msgs[queue->cur]; | ||
212 | if (crq->valid & 0x80) { | ||
213 | if (++queue->cur == queue->size) | ||
214 | queue->cur = 0; | ||
215 | |||
216 | /* Ensure the read of the valid bit occurs before reading any | ||
217 | * other bits of the CRQ entry | ||
218 | */ | ||
219 | dma_rmb(); | ||
220 | } else { | ||
221 | crq = NULL; | ||
222 | } | ||
223 | |||
224 | spin_unlock_irqrestore(&queue->lock, flags); | ||
225 | |||
226 | return crq; | ||
227 | } | ||
228 | |||
229 | /** | ||
230 | * ibmvmc_send_crq - Send CRQ | ||
231 | * | ||
232 | * @adapter: crq_server_adapter struct | ||
233 | * @word1: Word1 Data field | ||
234 | * @word2: Word2 Data field | ||
235 | * | ||
236 | * Return: | ||
237 | * 0 - Success | ||
238 | * Non-Zero - Failure | ||
239 | */ | ||
240 | static long ibmvmc_send_crq(struct crq_server_adapter *adapter, | ||
241 | u64 word1, u64 word2) | ||
242 | { | ||
243 | struct vio_dev *vdev = to_vio_dev(adapter->dev); | ||
244 | long rc = 0; | ||
245 | |||
246 | dev_dbg(adapter->dev, "(0x%x, 0x%016llx, 0x%016llx)\n", | ||
247 | vdev->unit_address, word1, word2); | ||
248 | |||
249 | /* | ||
250 | * Ensure the command buffer is flushed to memory before handing it | ||
251 | * over to the other side to prevent it from fetching any stale data. | ||
252 | */ | ||
253 | dma_wmb(); | ||
254 | rc = plpar_hcall_norets(H_SEND_CRQ, vdev->unit_address, word1, word2); | ||
255 | dev_dbg(adapter->dev, "rc = 0x%lx\n", rc); | ||
256 | |||
257 | return rc; | ||
258 | } | ||
259 | |||
260 | /** | ||
261 | * alloc_dma_buffer - Create DMA Buffer | ||
262 | * | ||
263 | * @vdev: vio_dev struct | ||
264 | * @size: Size field | ||
265 | * @dma_handle: DMA address field | ||
266 | * | ||
267 | * Allocates memory for the command queue and maps remote memory into an | ||
268 | * ioba. | ||
269 | * | ||
270 | * Returns a pointer to the buffer | ||
271 | */ | ||
272 | static void *alloc_dma_buffer(struct vio_dev *vdev, size_t size, | ||
273 | dma_addr_t *dma_handle) | ||
274 | { | ||
275 | /* allocate memory */ | ||
276 | void *buffer = kzalloc(size, GFP_KERNEL); | ||
277 | |||
278 | if (!buffer) { | ||
279 | *dma_handle = 0; | ||
280 | return NULL; | ||
281 | } | ||
282 | |||
283 | /* DMA map */ | ||
284 | *dma_handle = dma_map_single(&vdev->dev, buffer, size, | ||
285 | DMA_BIDIRECTIONAL); | ||
286 | |||
287 | if (dma_mapping_error(&vdev->dev, *dma_handle)) { | ||
288 | *dma_handle = 0; | ||
289 | kzfree(buffer); | ||
290 | return NULL; | ||
291 | } | ||
292 | |||
293 | return buffer; | ||
294 | } | ||
295 | |||
296 | /** | ||
297 | * free_dma_buffer - Free DMA Buffer | ||
298 | * | ||
299 | * @vdev: vio_dev struct | ||
300 | * @size: Size field | ||
301 | * @vaddr: Address field | ||
302 | * @dma_handle: DMA address field | ||
303 | * | ||
304 | * Releases memory for a command queue and unmaps mapped remote memory. | ||
305 | */ | ||
306 | static void free_dma_buffer(struct vio_dev *vdev, size_t size, void *vaddr, | ||
307 | dma_addr_t dma_handle) | ||
308 | { | ||
309 | /* DMA unmap */ | ||
310 | dma_unmap_single(&vdev->dev, dma_handle, size, DMA_BIDIRECTIONAL); | ||
311 | |||
312 | /* deallocate memory */ | ||
313 | kzfree(vaddr); | ||
314 | } | ||
315 | |||
316 | /** | ||
317 | * ibmvmc_get_valid_hmc_buffer - Retrieve Valid HMC Buffer | ||
318 | * | ||
319 | * @hmc_index: HMC Index Field | ||
320 | * | ||
321 | * Return: | ||
322 | * Pointer to ibmvmc_buffer | ||
323 | */ | ||
324 | static struct ibmvmc_buffer *ibmvmc_get_valid_hmc_buffer(u8 hmc_index) | ||
325 | { | ||
326 | struct ibmvmc_buffer *buffer; | ||
327 | struct ibmvmc_buffer *ret_buf = NULL; | ||
328 | unsigned long i; | ||
329 | |||
330 | if (hmc_index > ibmvmc.max_hmc_index) | ||
331 | return NULL; | ||
332 | |||
333 | buffer = hmcs[hmc_index].buffer; | ||
334 | |||
335 | for (i = 0; i < ibmvmc_max_buf_pool_size; i++) { | ||
336 | if (buffer[i].valid && buffer[i].free && | ||
337 | buffer[i].owner == VMC_BUF_OWNER_ALPHA) { | ||
338 | buffer[i].free = 0; | ||
339 | ret_buf = &buffer[i]; | ||
340 | break; | ||
341 | } | ||
342 | } | ||
343 | |||
344 | return ret_buf; | ||
345 | } | ||
346 | |||
347 | /** | ||
348 | * ibmvmc_get_free_hmc_buffer - Get Free HMC Buffer | ||
349 | * | ||
350 | * @adapter: crq_server_adapter struct | ||
351 | * @hmc_index: Hmc Index field | ||
352 | * | ||
353 | * Return: | ||
354 | * Pointer to ibmvmc_buffer | ||
355 | */ | ||
356 | static struct ibmvmc_buffer *ibmvmc_get_free_hmc_buffer(struct crq_server_adapter *adapter, | ||
357 | u8 hmc_index) | ||
358 | { | ||
359 | struct ibmvmc_buffer *buffer; | ||
360 | struct ibmvmc_buffer *ret_buf = NULL; | ||
361 | unsigned long i; | ||
362 | |||
363 | if (hmc_index > ibmvmc.max_hmc_index) { | ||
364 | dev_info(adapter->dev, "get_free_hmc_buffer: invalid hmc_index=0x%x\n", | ||
365 | hmc_index); | ||
366 | return NULL; | ||
367 | } | ||
368 | |||
369 | buffer = hmcs[hmc_index].buffer; | ||
370 | |||
371 | for (i = 0; i < ibmvmc_max_buf_pool_size; i++) { | ||
372 | if (buffer[i].free && | ||
373 | buffer[i].owner == VMC_BUF_OWNER_ALPHA) { | ||
374 | buffer[i].free = 0; | ||
375 | ret_buf = &buffer[i]; | ||
376 | break; | ||
377 | } | ||
378 | } | ||
379 | |||
380 | return ret_buf; | ||
381 | } | ||
382 | |||
383 | /** | ||
384 | * ibmvmc_free_hmc_buffer - Free an HMC Buffer | ||
385 | * | ||
386 | * @hmc: ibmvmc_hmc struct | ||
387 | * @buffer: ibmvmc_buffer struct | ||
388 | * | ||
389 | */ | ||
390 | static void ibmvmc_free_hmc_buffer(struct ibmvmc_hmc *hmc, | ||
391 | struct ibmvmc_buffer *buffer) | ||
392 | { | ||
393 | unsigned long flags; | ||
394 | |||
395 | spin_lock_irqsave(&hmc->lock, flags); | ||
396 | buffer->free = 1; | ||
397 | spin_unlock_irqrestore(&hmc->lock, flags); | ||
398 | } | ||
399 | |||
400 | /** | ||
401 | * ibmvmc_count_hmc_buffers - Count HMC Buffers | ||
402 | * | ||
403 | * @hmc_index: HMC Index field | ||
404 | * @valid: Valid number of buffers field | ||
405 | * @free: Free number of buffers field | ||
406 | * | ||
407 | */ | ||
408 | static void ibmvmc_count_hmc_buffers(u8 hmc_index, unsigned int *valid, | ||
409 | unsigned int *free) | ||
410 | { | ||
411 | struct ibmvmc_buffer *buffer; | ||
412 | unsigned long i; | ||
413 | unsigned long flags; | ||
414 | |||
415 | if (hmc_index > ibmvmc.max_hmc_index) | ||
416 | return; | ||
417 | |||
418 | if (!valid || !free) | ||
419 | return; | ||
420 | |||
421 | *valid = 0; *free = 0; | ||
422 | |||
423 | buffer = hmcs[hmc_index].buffer; | ||
424 | spin_lock_irqsave(&hmcs[hmc_index].lock, flags); | ||
425 | |||
426 | for (i = 0; i < ibmvmc_max_buf_pool_size; i++) { | ||
427 | if (buffer[i].valid) { | ||
428 | *valid = *valid + 1; | ||
429 | if (buffer[i].free) | ||
430 | *free = *free + 1; | ||
431 | } | ||
432 | } | ||
433 | |||
434 | spin_unlock_irqrestore(&hmcs[hmc_index].lock, flags); | ||
435 | } | ||
436 | |||
437 | /** | ||
438 | * ibmvmc_get_free_hmc - Get Free HMC | ||
439 | * | ||
440 | * Return: | ||
441 | * Pointer to an available HMC Connection | ||
442 | * Null otherwise | ||
443 | */ | ||
444 | static struct ibmvmc_hmc *ibmvmc_get_free_hmc(void) | ||
445 | { | ||
446 | unsigned long i; | ||
447 | unsigned long flags; | ||
448 | |||
449 | /* | ||
450 | * Find an available HMC connection. | ||
451 | */ | ||
452 | for (i = 0; i <= ibmvmc.max_hmc_index; i++) { | ||
453 | spin_lock_irqsave(&hmcs[i].lock, flags); | ||
454 | if (hmcs[i].state == ibmhmc_state_free) { | ||
455 | hmcs[i].index = i; | ||
456 | hmcs[i].state = ibmhmc_state_initial; | ||
457 | spin_unlock_irqrestore(&hmcs[i].lock, flags); | ||
458 | return &hmcs[i]; | ||
459 | } | ||
460 | spin_unlock_irqrestore(&hmcs[i].lock, flags); | ||
461 | } | ||
462 | |||
463 | return NULL; | ||
464 | } | ||
465 | |||
466 | /** | ||
467 | * ibmvmc_return_hmc - Return an HMC Connection | ||
468 | * | ||
469 | * @hmc: ibmvmc_hmc struct | ||
470 | * @release_readers: Number of readers connected to session | ||
471 | * | ||
472 | * This function releases the HMC connections back into the pool. | ||
473 | * | ||
474 | * Return: | ||
475 | * 0 - Success | ||
476 | * Non-zero - Failure | ||
477 | */ | ||
478 | static int ibmvmc_return_hmc(struct ibmvmc_hmc *hmc, bool release_readers) | ||
479 | { | ||
480 | struct ibmvmc_buffer *buffer; | ||
481 | struct crq_server_adapter *adapter; | ||
482 | struct vio_dev *vdev; | ||
483 | unsigned long i; | ||
484 | unsigned long flags; | ||
485 | |||
486 | if (!hmc || !hmc->adapter) | ||
487 | return -EIO; | ||
488 | |||
489 | if (release_readers) { | ||
490 | if (hmc->file_session) { | ||
491 | struct ibmvmc_file_session *session = hmc->file_session; | ||
492 | |||
493 | session->valid = 0; | ||
494 | wake_up_interruptible(&ibmvmc_read_wait); | ||
495 | } | ||
496 | } | ||
497 | |||
498 | adapter = hmc->adapter; | ||
499 | vdev = to_vio_dev(adapter->dev); | ||
500 | |||
501 | spin_lock_irqsave(&hmc->lock, flags); | ||
502 | hmc->index = 0; | ||
503 | hmc->state = ibmhmc_state_free; | ||
504 | hmc->queue_head = 0; | ||
505 | hmc->queue_tail = 0; | ||
506 | buffer = hmc->buffer; | ||
507 | for (i = 0; i < ibmvmc_max_buf_pool_size; i++) { | ||
508 | if (buffer[i].valid) { | ||
509 | free_dma_buffer(vdev, | ||
510 | ibmvmc.max_mtu, | ||
511 | buffer[i].real_addr_local, | ||
512 | buffer[i].dma_addr_local); | ||
513 | dev_dbg(adapter->dev, "Forgot buffer id 0x%lx\n", i); | ||
514 | } | ||
515 | memset(&buffer[i], 0, sizeof(struct ibmvmc_buffer)); | ||
516 | |||
517 | hmc->queue_outbound_msgs[i] = VMC_INVALID_BUFFER_ID; | ||
518 | } | ||
519 | |||
520 | spin_unlock_irqrestore(&hmc->lock, flags); | ||
521 | |||
522 | return 0; | ||
523 | } | ||
524 | |||
525 | /** | ||
526 | * ibmvmc_send_open - Interface Open | ||
527 | * @buffer: Pointer to ibmvmc_buffer struct | ||
528 | * @hmc: Pointer to ibmvmc_hmc struct | ||
529 | * | ||
530 | * This command is sent by the management partition as the result of a | ||
531 | * management partition device request. It causes the hypervisor to | ||
532 | * prepare a set of data buffers for the management application connection | ||
533 | * indicated HMC idx. A unique HMC Idx would be used if multiple management | ||
534 | * applications running concurrently were desired. Before responding to this | ||
535 | * command, the hypervisor must provide the management partition with at | ||
536 | * least one of these new buffers via the Add Buffer. This indicates whether | ||
537 | * the messages are inbound or outbound from the hypervisor. | ||
538 | * | ||
539 | * Return: | ||
540 | * 0 - Success | ||
541 | * Non-zero - Failure | ||
542 | */ | ||
543 | static int ibmvmc_send_open(struct ibmvmc_buffer *buffer, | ||
544 | struct ibmvmc_hmc *hmc) | ||
545 | { | ||
546 | struct ibmvmc_crq_msg crq_msg; | ||
547 | struct crq_server_adapter *adapter; | ||
548 | __be64 *crq_as_u64 = (__be64 *)&crq_msg; | ||
549 | int rc = 0; | ||
550 | |||
551 | if (!hmc || !hmc->adapter) | ||
552 | return -EIO; | ||
553 | |||
554 | adapter = hmc->adapter; | ||
555 | |||
556 | dev_dbg(adapter->dev, "send_open: 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx\n", | ||
557 | (unsigned long)buffer->size, (unsigned long)adapter->liobn, | ||
558 | (unsigned long)buffer->dma_addr_local, | ||
559 | (unsigned long)adapter->riobn, | ||
560 | (unsigned long)buffer->dma_addr_remote); | ||
561 | |||
562 | rc = h_copy_rdma(buffer->size, | ||
563 | adapter->liobn, | ||
564 | buffer->dma_addr_local, | ||
565 | adapter->riobn, | ||
566 | buffer->dma_addr_remote); | ||
567 | if (rc) { | ||
568 | dev_err(adapter->dev, "Error: In send_open, h_copy_rdma rc 0x%x\n", | ||
569 | rc); | ||
570 | return -EIO; | ||
571 | } | ||
572 | |||
573 | hmc->state = ibmhmc_state_opening; | ||
574 | |||
575 | crq_msg.valid = 0x80; | ||
576 | crq_msg.type = VMC_MSG_OPEN; | ||
577 | crq_msg.status = 0; | ||
578 | crq_msg.var1.rsvd = 0; | ||
579 | crq_msg.hmc_session = hmc->session; | ||
580 | crq_msg.hmc_index = hmc->index; | ||
581 | crq_msg.var2.buffer_id = cpu_to_be16(buffer->id); | ||
582 | crq_msg.rsvd = 0; | ||
583 | crq_msg.var3.rsvd = 0; | ||
584 | |||
585 | ibmvmc_send_crq(adapter, be64_to_cpu(crq_as_u64[0]), | ||
586 | be64_to_cpu(crq_as_u64[1])); | ||
587 | |||
588 | return rc; | ||
589 | } | ||
590 | |||
591 | /** | ||
592 | * ibmvmc_send_close - Interface Close | ||
593 | * @hmc: Pointer to ibmvmc_hmc struct | ||
594 | * | ||
595 | * This command is sent by the management partition to terminate a | ||
596 | * management application to hypervisor connection. When this command is | ||
597 | * sent, the management partition has quiesced all I/O operations to all | ||
598 | * buffers associated with this management application connection, and | ||
599 | * has freed any storage for these buffers. | ||
600 | * | ||
601 | * Return: | ||
602 | * 0 - Success | ||
603 | * Non-zero - Failure | ||
604 | */ | ||
605 | static int ibmvmc_send_close(struct ibmvmc_hmc *hmc) | ||
606 | { | ||
607 | struct ibmvmc_crq_msg crq_msg; | ||
608 | struct crq_server_adapter *adapter; | ||
609 | __be64 *crq_as_u64 = (__be64 *)&crq_msg; | ||
610 | int rc = 0; | ||
611 | |||
612 | if (!hmc || !hmc->adapter) | ||
613 | return -EIO; | ||
614 | |||
615 | adapter = hmc->adapter; | ||
616 | |||
617 | dev_info(adapter->dev, "CRQ send: close\n"); | ||
618 | |||
619 | crq_msg.valid = 0x80; | ||
620 | crq_msg.type = VMC_MSG_CLOSE; | ||
621 | crq_msg.status = 0; | ||
622 | crq_msg.var1.rsvd = 0; | ||
623 | crq_msg.hmc_session = hmc->session; | ||
624 | crq_msg.hmc_index = hmc->index; | ||
625 | crq_msg.var2.rsvd = 0; | ||
626 | crq_msg.rsvd = 0; | ||
627 | crq_msg.var3.rsvd = 0; | ||
628 | |||
629 | ibmvmc_send_crq(adapter, be64_to_cpu(crq_as_u64[0]), | ||
630 | be64_to_cpu(crq_as_u64[1])); | ||
631 | |||
632 | return rc; | ||
633 | } | ||
634 | |||
635 | /** | ||
636 | * ibmvmc_send_capabilities - Send VMC Capabilities | ||
637 | * | ||
638 | * @adapter: crq_server_adapter struct | ||
639 | * | ||
640 | * The capabilities message is an administrative message sent after the CRQ | ||
641 | * initialization sequence of messages and is used to exchange VMC capabilities | ||
642 | * between the management partition and the hypervisor. The management | ||
643 | * partition must send this message and the hypervisor must respond with VMC | ||
644 | * capabilities Response message before HMC interface message can begin. Any | ||
645 | * HMC interface messages received before the exchange of capabilities has | ||
646 | * complete are dropped. | ||
647 | * | ||
648 | * Return: | ||
649 | * 0 - Success | ||
650 | */ | ||
651 | static int ibmvmc_send_capabilities(struct crq_server_adapter *adapter) | ||
652 | { | ||
653 | struct ibmvmc_admin_crq_msg crq_msg; | ||
654 | __be64 *crq_as_u64 = (__be64 *)&crq_msg; | ||
655 | |||
656 | dev_dbg(adapter->dev, "ibmvmc: CRQ send: capabilities\n"); | ||
657 | crq_msg.valid = 0x80; | ||
658 | crq_msg.type = VMC_MSG_CAP; | ||
659 | crq_msg.status = 0; | ||
660 | crq_msg.rsvd[0] = 0; | ||
661 | crq_msg.rsvd[1] = 0; | ||
662 | crq_msg.max_hmc = ibmvmc_max_hmcs; | ||
663 | crq_msg.max_mtu = cpu_to_be32(ibmvmc_max_mtu); | ||
664 | crq_msg.pool_size = cpu_to_be16(ibmvmc_max_buf_pool_size); | ||
665 | crq_msg.crq_size = cpu_to_be16(adapter->queue.size); | ||
666 | crq_msg.version = cpu_to_be16(IBMVMC_PROTOCOL_VERSION); | ||
667 | |||
668 | ibmvmc_send_crq(adapter, be64_to_cpu(crq_as_u64[0]), | ||
669 | be64_to_cpu(crq_as_u64[1])); | ||
670 | |||
671 | ibmvmc.state = ibmvmc_state_capabilities; | ||
672 | |||
673 | return 0; | ||
674 | } | ||
675 | |||
676 | /** | ||
677 | * ibmvmc_send_add_buffer_resp - Add Buffer Response | ||
678 | * | ||
679 | * @adapter: crq_server_adapter struct | ||
680 | * @status: Status field | ||
681 | * @hmc_session: HMC Session field | ||
682 | * @hmc_index: HMC Index field | ||
683 | * @buffer_id: Buffer Id field | ||
684 | * | ||
685 | * This command is sent by the management partition to the hypervisor in | ||
686 | * response to the Add Buffer message. The Status field indicates the result of | ||
687 | * the command. | ||
688 | * | ||
689 | * Return: | ||
690 | * 0 - Success | ||
691 | */ | ||
692 | static int ibmvmc_send_add_buffer_resp(struct crq_server_adapter *adapter, | ||
693 | u8 status, u8 hmc_session, | ||
694 | u8 hmc_index, u16 buffer_id) | ||
695 | { | ||
696 | struct ibmvmc_crq_msg crq_msg; | ||
697 | __be64 *crq_as_u64 = (__be64 *)&crq_msg; | ||
698 | |||
699 | dev_dbg(adapter->dev, "CRQ send: add_buffer_resp\n"); | ||
700 | crq_msg.valid = 0x80; | ||
701 | crq_msg.type = VMC_MSG_ADD_BUF_RESP; | ||
702 | crq_msg.status = status; | ||
703 | crq_msg.var1.rsvd = 0; | ||
704 | crq_msg.hmc_session = hmc_session; | ||
705 | crq_msg.hmc_index = hmc_index; | ||
706 | crq_msg.var2.buffer_id = cpu_to_be16(buffer_id); | ||
707 | crq_msg.rsvd = 0; | ||
708 | crq_msg.var3.rsvd = 0; | ||
709 | |||
710 | ibmvmc_send_crq(adapter, be64_to_cpu(crq_as_u64[0]), | ||
711 | be64_to_cpu(crq_as_u64[1])); | ||
712 | |||
713 | return 0; | ||
714 | } | ||
715 | |||
716 | /** | ||
717 | * ibmvmc_send_rem_buffer_resp - Remove Buffer Response | ||
718 | * | ||
719 | * @adapter: crq_server_adapter struct | ||
720 | * @status: Status field | ||
721 | * @hmc_session: HMC Session field | ||
722 | * @hmc_index: HMC Index field | ||
723 | * @buffer_id: Buffer Id field | ||
724 | * | ||
725 | * This command is sent by the management partition to the hypervisor in | ||
726 | * response to the Remove Buffer message. The Buffer ID field indicates | ||
727 | * which buffer the management partition selected to remove. The Status | ||
728 | * field indicates the result of the command. | ||
729 | * | ||
730 | * Return: | ||
731 | * 0 - Success | ||
732 | */ | ||
733 | static int ibmvmc_send_rem_buffer_resp(struct crq_server_adapter *adapter, | ||
734 | u8 status, u8 hmc_session, | ||
735 | u8 hmc_index, u16 buffer_id) | ||
736 | { | ||
737 | struct ibmvmc_crq_msg crq_msg; | ||
738 | __be64 *crq_as_u64 = (__be64 *)&crq_msg; | ||
739 | |||
740 | dev_dbg(adapter->dev, "CRQ send: rem_buffer_resp\n"); | ||
741 | crq_msg.valid = 0x80; | ||
742 | crq_msg.type = VMC_MSG_REM_BUF_RESP; | ||
743 | crq_msg.status = status; | ||
744 | crq_msg.var1.rsvd = 0; | ||
745 | crq_msg.hmc_session = hmc_session; | ||
746 | crq_msg.hmc_index = hmc_index; | ||
747 | crq_msg.var2.buffer_id = cpu_to_be16(buffer_id); | ||
748 | crq_msg.rsvd = 0; | ||
749 | crq_msg.var3.rsvd = 0; | ||
750 | |||
751 | ibmvmc_send_crq(adapter, be64_to_cpu(crq_as_u64[0]), | ||
752 | be64_to_cpu(crq_as_u64[1])); | ||
753 | |||
754 | return 0; | ||
755 | } | ||
756 | |||
757 | /** | ||
758 | * ibmvmc_send_msg - Signal Message | ||
759 | * | ||
760 | * @adapter: crq_server_adapter struct | ||
761 | * @buffer: ibmvmc_buffer struct | ||
762 | * @hmc: ibmvmc_hmc struct | ||
763 | * @msg_length: message length field | ||
764 | * | ||
765 | * This command is sent between the management partition and the hypervisor | ||
766 | * in order to signal the arrival of an HMC protocol message. The command | ||
767 | * can be sent by both the management partition and the hypervisor. It is | ||
768 | * used for all traffic between the management application and the hypervisor, | ||
769 | * regardless of who initiated the communication. | ||
770 | * | ||
771 | * There is no response to this message. | ||
772 | * | ||
773 | * Return: | ||
774 | * 0 - Success | ||
775 | * Non-zero - Failure | ||
776 | */ | ||
777 | static int ibmvmc_send_msg(struct crq_server_adapter *adapter, | ||
778 | struct ibmvmc_buffer *buffer, | ||
779 | struct ibmvmc_hmc *hmc, int msg_len) | ||
780 | { | ||
781 | struct ibmvmc_crq_msg crq_msg; | ||
782 | __be64 *crq_as_u64 = (__be64 *)&crq_msg; | ||
783 | int rc = 0; | ||
784 | |||
785 | dev_dbg(adapter->dev, "CRQ send: rdma to HV\n"); | ||
786 | rc = h_copy_rdma(msg_len, | ||
787 | adapter->liobn, | ||
788 | buffer->dma_addr_local, | ||
789 | adapter->riobn, | ||
790 | buffer->dma_addr_remote); | ||
791 | if (rc) { | ||
792 | dev_err(adapter->dev, "Error in send_msg, h_copy_rdma rc 0x%x\n", | ||
793 | rc); | ||
794 | return rc; | ||
795 | } | ||
796 | |||
797 | crq_msg.valid = 0x80; | ||
798 | crq_msg.type = VMC_MSG_SIGNAL; | ||
799 | crq_msg.status = 0; | ||
800 | crq_msg.var1.rsvd = 0; | ||
801 | crq_msg.hmc_session = hmc->session; | ||
802 | crq_msg.hmc_index = hmc->index; | ||
803 | crq_msg.var2.buffer_id = cpu_to_be16(buffer->id); | ||
804 | crq_msg.var3.msg_len = cpu_to_be32(msg_len); | ||
805 | dev_dbg(adapter->dev, "CRQ send: msg to HV 0x%llx 0x%llx\n", | ||
806 | be64_to_cpu(crq_as_u64[0]), be64_to_cpu(crq_as_u64[1])); | ||
807 | |||
808 | buffer->owner = VMC_BUF_OWNER_HV; | ||
809 | ibmvmc_send_crq(adapter, be64_to_cpu(crq_as_u64[0]), | ||
810 | be64_to_cpu(crq_as_u64[1])); | ||
811 | |||
812 | return rc; | ||
813 | } | ||
814 | |||
815 | /** | ||
816 | * ibmvmc_open - Open Session | ||
817 | * | ||
818 | * @inode: inode struct | ||
819 | * @file: file struct | ||
820 | * | ||
821 | * Return: | ||
822 | * 0 - Success | ||
823 | */ | ||
824 | static int ibmvmc_open(struct inode *inode, struct file *file) | ||
825 | { | ||
826 | struct ibmvmc_file_session *session; | ||
827 | int rc = 0; | ||
828 | |||
829 | pr_debug("%s: inode = 0x%lx, file = 0x%lx, state = 0x%x\n", __func__, | ||
830 | (unsigned long)inode, (unsigned long)file, | ||
831 | ibmvmc.state); | ||
832 | |||
833 | session = kzalloc(sizeof(*session), GFP_KERNEL); | ||
834 | session->file = file; | ||
835 | file->private_data = session; | ||
836 | |||
837 | return rc; | ||
838 | } | ||
839 | |||
840 | /** | ||
841 | * ibmvmc_close - Close Session | ||
842 | * | ||
843 | * @inode: inode struct | ||
844 | * @file: file struct | ||
845 | * | ||
846 | * Return: | ||
847 | * 0 - Success | ||
848 | * Non-zero - Failure | ||
849 | */ | ||
850 | static int ibmvmc_close(struct inode *inode, struct file *file) | ||
851 | { | ||
852 | struct ibmvmc_file_session *session; | ||
853 | struct ibmvmc_hmc *hmc; | ||
854 | int rc = 0; | ||
855 | unsigned long flags; | ||
856 | |||
857 | pr_debug("%s: file = 0x%lx, state = 0x%x\n", __func__, | ||
858 | (unsigned long)file, ibmvmc.state); | ||
859 | |||
860 | session = file->private_data; | ||
861 | if (!session) | ||
862 | return -EIO; | ||
863 | |||
864 | hmc = session->hmc; | ||
865 | if (hmc) { | ||
866 | if (!hmc->adapter) | ||
867 | return -EIO; | ||
868 | |||
869 | if (ibmvmc.state == ibmvmc_state_failed) { | ||
870 | dev_warn(hmc->adapter->dev, "close: state_failed\n"); | ||
871 | return -EIO; | ||
872 | } | ||
873 | |||
874 | spin_lock_irqsave(&hmc->lock, flags); | ||
875 | if (hmc->state >= ibmhmc_state_opening) { | ||
876 | rc = ibmvmc_send_close(hmc); | ||
877 | if (rc) | ||
878 | dev_warn(hmc->adapter->dev, "close: send_close failed.\n"); | ||
879 | } | ||
880 | spin_unlock_irqrestore(&hmc->lock, flags); | ||
881 | } | ||
882 | |||
883 | kzfree(session); | ||
884 | |||
885 | return rc; | ||
886 | } | ||
887 | |||
888 | /** | ||
889 | * ibmvmc_read - Read | ||
890 | * | ||
891 | * @file: file struct | ||
892 | * @buf: Character buffer | ||
893 | * @nbytes: Size in bytes | ||
894 | * @ppos: Offset | ||
895 | * | ||
896 | * Return: | ||
897 | * 0 - Success | ||
898 | * Non-zero - Failure | ||
899 | */ | ||
900 | static ssize_t ibmvmc_read(struct file *file, char *buf, size_t nbytes, | ||
901 | loff_t *ppos) | ||
902 | { | ||
903 | struct ibmvmc_file_session *session; | ||
904 | struct ibmvmc_hmc *hmc; | ||
905 | struct crq_server_adapter *adapter; | ||
906 | struct ibmvmc_buffer *buffer; | ||
907 | ssize_t n; | ||
908 | ssize_t retval = 0; | ||
909 | unsigned long flags; | ||
910 | DEFINE_WAIT(wait); | ||
911 | |||
912 | pr_debug("ibmvmc: read: file = 0x%lx, buf = 0x%lx, nbytes = 0x%lx\n", | ||
913 | (unsigned long)file, (unsigned long)buf, | ||
914 | (unsigned long)nbytes); | ||
915 | |||
916 | if (nbytes == 0) | ||
917 | return 0; | ||
918 | |||
919 | if (nbytes > ibmvmc.max_mtu) { | ||
920 | pr_warn("ibmvmc: read: nbytes invalid 0x%x\n", | ||
921 | (unsigned int)nbytes); | ||
922 | return -EINVAL; | ||
923 | } | ||
924 | |||
925 | session = file->private_data; | ||
926 | if (!session) { | ||
927 | pr_warn("ibmvmc: read: no session\n"); | ||
928 | return -EIO; | ||
929 | } | ||
930 | |||
931 | hmc = session->hmc; | ||
932 | if (!hmc) { | ||
933 | pr_warn("ibmvmc: read: no hmc\n"); | ||
934 | return -EIO; | ||
935 | } | ||
936 | |||
937 | adapter = hmc->adapter; | ||
938 | if (!adapter) { | ||
939 | pr_warn("ibmvmc: read: no adapter\n"); | ||
940 | return -EIO; | ||
941 | } | ||
942 | |||
943 | do { | ||
944 | prepare_to_wait(&ibmvmc_read_wait, &wait, TASK_INTERRUPTIBLE); | ||
945 | |||
946 | spin_lock_irqsave(&hmc->lock, flags); | ||
947 | if (hmc->queue_tail != hmc->queue_head) | ||
948 | /* Data is available */ | ||
949 | break; | ||
950 | |||
951 | spin_unlock_irqrestore(&hmc->lock, flags); | ||
952 | |||
953 | if (!session->valid) { | ||
954 | retval = -EBADFD; | ||
955 | goto out; | ||
956 | } | ||
957 | if (file->f_flags & O_NONBLOCK) { | ||
958 | retval = -EAGAIN; | ||
959 | goto out; | ||
960 | } | ||
961 | |||
962 | schedule(); | ||
963 | |||
964 | if (signal_pending(current)) { | ||
965 | retval = -ERESTARTSYS; | ||
966 | goto out; | ||
967 | } | ||
968 | } while (1); | ||
969 | |||
970 | buffer = &(hmc->buffer[hmc->queue_outbound_msgs[hmc->queue_tail]]); | ||
971 | hmc->queue_tail++; | ||
972 | if (hmc->queue_tail == ibmvmc_max_buf_pool_size) | ||
973 | hmc->queue_tail = 0; | ||
974 | spin_unlock_irqrestore(&hmc->lock, flags); | ||
975 | |||
976 | nbytes = min_t(size_t, nbytes, buffer->msg_len); | ||
977 | n = copy_to_user((void *)buf, buffer->real_addr_local, nbytes); | ||
978 | dev_dbg(adapter->dev, "read: copy to user nbytes = 0x%lx.\n", nbytes); | ||
979 | ibmvmc_free_hmc_buffer(hmc, buffer); | ||
980 | retval = nbytes; | ||
981 | |||
982 | if (n) { | ||
983 | dev_warn(adapter->dev, "read: copy to user failed.\n"); | ||
984 | retval = -EFAULT; | ||
985 | } | ||
986 | |||
987 | out: | ||
988 | finish_wait(&ibmvmc_read_wait, &wait); | ||
989 | dev_dbg(adapter->dev, "read: out %ld\n", retval); | ||
990 | return retval; | ||
991 | } | ||
992 | |||
993 | /** | ||
994 | * ibmvmc_poll - Poll | ||
995 | * | ||
996 | * @file: file struct | ||
997 | * @wait: Poll Table | ||
998 | * | ||
999 | * Return: | ||
1000 | * poll.h return values | ||
1001 | */ | ||
1002 | static unsigned int ibmvmc_poll(struct file *file, poll_table *wait) | ||
1003 | { | ||
1004 | struct ibmvmc_file_session *session; | ||
1005 | struct ibmvmc_hmc *hmc; | ||
1006 | unsigned int mask = 0; | ||
1007 | |||
1008 | session = file->private_data; | ||
1009 | if (!session) | ||
1010 | return 0; | ||
1011 | |||
1012 | hmc = session->hmc; | ||
1013 | if (!hmc) | ||
1014 | return 0; | ||
1015 | |||
1016 | poll_wait(file, &ibmvmc_read_wait, wait); | ||
1017 | |||
1018 | if (hmc->queue_head != hmc->queue_tail) | ||
1019 | mask |= POLLIN | POLLRDNORM; | ||
1020 | |||
1021 | return mask; | ||
1022 | } | ||
1023 | |||
1024 | /** | ||
1025 | * ibmvmc_write - Write | ||
1026 | * | ||
1027 | * @file: file struct | ||
1028 | * @buf: Character buffer | ||
1029 | * @count: Count field | ||
1030 | * @ppos: Offset | ||
1031 | * | ||
1032 | * Return: | ||
1033 | * 0 - Success | ||
1034 | * Non-zero - Failure | ||
1035 | */ | ||
1036 | static ssize_t ibmvmc_write(struct file *file, const char *buffer, | ||
1037 | size_t count, loff_t *ppos) | ||
1038 | { | ||
1039 | struct ibmvmc_buffer *vmc_buffer; | ||
1040 | struct ibmvmc_file_session *session; | ||
1041 | struct crq_server_adapter *adapter; | ||
1042 | struct ibmvmc_hmc *hmc; | ||
1043 | unsigned char *buf; | ||
1044 | unsigned long flags; | ||
1045 | size_t bytes; | ||
1046 | const char *p = buffer; | ||
1047 | size_t c = count; | ||
1048 | int ret = 0; | ||
1049 | |||
1050 | session = file->private_data; | ||
1051 | if (!session) | ||
1052 | return -EIO; | ||
1053 | |||
1054 | hmc = session->hmc; | ||
1055 | if (!hmc) | ||
1056 | return -EIO; | ||
1057 | |||
1058 | spin_lock_irqsave(&hmc->lock, flags); | ||
1059 | if (hmc->state == ibmhmc_state_free) { | ||
1060 | /* HMC connection is not valid (possibly was reset under us). */ | ||
1061 | ret = -EIO; | ||
1062 | goto out; | ||
1063 | } | ||
1064 | |||
1065 | adapter = hmc->adapter; | ||
1066 | if (!adapter) { | ||
1067 | ret = -EIO; | ||
1068 | goto out; | ||
1069 | } | ||
1070 | |||
1071 | if (count > ibmvmc.max_mtu) { | ||
1072 | dev_warn(adapter->dev, "invalid buffer size 0x%lx\n", | ||
1073 | (unsigned long)count); | ||
1074 | ret = -EIO; | ||
1075 | goto out; | ||
1076 | } | ||
1077 | |||
1078 | /* Waiting for the open resp message to the ioctl(1) - retry */ | ||
1079 | if (hmc->state == ibmhmc_state_opening) { | ||
1080 | ret = -EBUSY; | ||
1081 | goto out; | ||
1082 | } | ||
1083 | |||
1084 | /* Make sure the ioctl() was called & the open msg sent, and that | ||
1085 | * the HMC connection has not failed. | ||
1086 | */ | ||
1087 | if (hmc->state != ibmhmc_state_ready) { | ||
1088 | ret = -EIO; | ||
1089 | goto out; | ||
1090 | } | ||
1091 | |||
1092 | vmc_buffer = ibmvmc_get_valid_hmc_buffer(hmc->index); | ||
1093 | if (!vmc_buffer) { | ||
1094 | /* No buffer available for the msg send, or we have not yet | ||
1095 | * completed the open/open_resp sequence. Retry until this is | ||
1096 | * complete. | ||
1097 | */ | ||
1098 | ret = -EBUSY; | ||
1099 | goto out; | ||
1100 | } | ||
1101 | if (!vmc_buffer->real_addr_local) { | ||
1102 | dev_err(adapter->dev, "no buffer storage assigned\n"); | ||
1103 | ret = -EIO; | ||
1104 | goto out; | ||
1105 | } | ||
1106 | buf = vmc_buffer->real_addr_local; | ||
1107 | |||
1108 | while (c > 0) { | ||
1109 | bytes = min_t(size_t, c, vmc_buffer->size); | ||
1110 | |||
1111 | bytes -= copy_from_user(buf, p, bytes); | ||
1112 | if (!bytes) { | ||
1113 | ret = -EFAULT; | ||
1114 | goto out; | ||
1115 | } | ||
1116 | c -= bytes; | ||
1117 | p += bytes; | ||
1118 | } | ||
1119 | if (p == buffer) | ||
1120 | goto out; | ||
1121 | |||
1122 | file->f_path.dentry->d_inode->i_mtime = current_time(file_inode(file)); | ||
1123 | mark_inode_dirty(file->f_path.dentry->d_inode); | ||
1124 | |||
1125 | dev_dbg(adapter->dev, "write: file = 0x%lx, count = 0x%lx\n", | ||
1126 | (unsigned long)file, (unsigned long)count); | ||
1127 | |||
1128 | ibmvmc_send_msg(adapter, vmc_buffer, hmc, count); | ||
1129 | ret = p - buffer; | ||
1130 | out: | ||
1131 | spin_unlock_irqrestore(&hmc->lock, flags); | ||
1132 | return (ssize_t)(ret); | ||
1133 | } | ||
1134 | |||
1135 | /** | ||
1136 | * ibmvmc_setup_hmc - Setup the HMC | ||
1137 | * | ||
1138 | * @session: ibmvmc_file_session struct | ||
1139 | * | ||
1140 | * Return: | ||
1141 | * 0 - Success | ||
1142 | * Non-zero - Failure | ||
1143 | */ | ||
1144 | static long ibmvmc_setup_hmc(struct ibmvmc_file_session *session) | ||
1145 | { | ||
1146 | struct ibmvmc_hmc *hmc; | ||
1147 | unsigned int valid, free, index; | ||
1148 | |||
1149 | if (ibmvmc.state == ibmvmc_state_failed) { | ||
1150 | pr_warn("ibmvmc: Reserve HMC: state_failed\n"); | ||
1151 | return -EIO; | ||
1152 | } | ||
1153 | |||
1154 | if (ibmvmc.state < ibmvmc_state_ready) { | ||
1155 | pr_warn("ibmvmc: Reserve HMC: not state_ready\n"); | ||
1156 | return -EAGAIN; | ||
1157 | } | ||
1158 | |||
1159 | /* Device is busy until capabilities have been exchanged and we | ||
1160 | * have a generic buffer for each possible HMC connection. | ||
1161 | */ | ||
1162 | for (index = 0; index <= ibmvmc.max_hmc_index; index++) { | ||
1163 | valid = 0; | ||
1164 | ibmvmc_count_hmc_buffers(index, &valid, &free); | ||
1165 | if (valid == 0) { | ||
1166 | pr_warn("ibmvmc: buffers not ready for index %d\n", | ||
1167 | index); | ||
1168 | return -ENOBUFS; | ||
1169 | } | ||
1170 | } | ||
1171 | |||
1172 | /* Get an hmc object, and transition to ibmhmc_state_initial */ | ||
1173 | hmc = ibmvmc_get_free_hmc(); | ||
1174 | if (!hmc) { | ||
1175 | pr_warn("%s: free hmc not found\n", __func__); | ||
1176 | return -EBUSY; | ||
1177 | } | ||
1178 | |||
1179 | hmc->session = hmc->session + 1; | ||
1180 | if (hmc->session == 0xff) | ||
1181 | hmc->session = 1; | ||
1182 | |||
1183 | session->hmc = hmc; | ||
1184 | hmc->adapter = &ibmvmc_adapter; | ||
1185 | hmc->file_session = session; | ||
1186 | session->valid = 1; | ||
1187 | |||
1188 | return 0; | ||
1189 | } | ||
1190 | |||
1191 | /** | ||
1192 | * ibmvmc_ioctl_sethmcid - IOCTL Set HMC ID | ||
1193 | * | ||
1194 | * @session: ibmvmc_file_session struct | ||
1195 | * @new_hmc_id: HMC id field | ||
1196 | * | ||
1197 | * IOCTL command to setup the hmc id | ||
1198 | * | ||
1199 | * Return: | ||
1200 | * 0 - Success | ||
1201 | * Non-zero - Failure | ||
1202 | */ | ||
1203 | static long ibmvmc_ioctl_sethmcid(struct ibmvmc_file_session *session, | ||
1204 | unsigned char __user *new_hmc_id) | ||
1205 | { | ||
1206 | struct ibmvmc_hmc *hmc; | ||
1207 | struct ibmvmc_buffer *buffer; | ||
1208 | size_t bytes; | ||
1209 | char print_buffer[HMC_ID_LEN + 1]; | ||
1210 | unsigned long flags; | ||
1211 | long rc = 0; | ||
1212 | |||
1213 | /* Reserve HMC session */ | ||
1214 | hmc = session->hmc; | ||
1215 | if (!hmc) { | ||
1216 | rc = ibmvmc_setup_hmc(session); | ||
1217 | if (rc) | ||
1218 | return rc; | ||
1219 | |||
1220 | hmc = session->hmc; | ||
1221 | if (!hmc) { | ||
1222 | pr_err("ibmvmc: setup_hmc success but no hmc\n"); | ||
1223 | return -EIO; | ||
1224 | } | ||
1225 | } | ||
1226 | |||
1227 | if (hmc->state != ibmhmc_state_initial) { | ||
1228 | pr_warn("ibmvmc: sethmcid: invalid state to send open 0x%x\n", | ||
1229 | hmc->state); | ||
1230 | return -EIO; | ||
1231 | } | ||
1232 | |||
1233 | bytes = copy_from_user(hmc->hmc_id, new_hmc_id, HMC_ID_LEN); | ||
1234 | if (bytes) | ||
1235 | return -EFAULT; | ||
1236 | |||
1237 | /* Send Open Session command */ | ||
1238 | spin_lock_irqsave(&hmc->lock, flags); | ||
1239 | buffer = ibmvmc_get_valid_hmc_buffer(hmc->index); | ||
1240 | spin_unlock_irqrestore(&hmc->lock, flags); | ||
1241 | |||
1242 | if (!buffer || !buffer->real_addr_local) { | ||
1243 | pr_warn("ibmvmc: sethmcid: no buffer available\n"); | ||
1244 | return -EIO; | ||
1245 | } | ||
1246 | |||
1247 | /* Make sure buffer is NULL terminated before trying to print it */ | ||
1248 | memset(print_buffer, 0, HMC_ID_LEN + 1); | ||
1249 | strncpy(print_buffer, hmc->hmc_id, HMC_ID_LEN); | ||
1250 | pr_info("ibmvmc: sethmcid: Set HMC ID: \"%s\"\n", print_buffer); | ||
1251 | |||
1252 | memcpy(buffer->real_addr_local, hmc->hmc_id, HMC_ID_LEN); | ||
1253 | /* RDMA over ID, send open msg, change state to ibmhmc_state_opening */ | ||
1254 | rc = ibmvmc_send_open(buffer, hmc); | ||
1255 | |||
1256 | return rc; | ||
1257 | } | ||
1258 | |||
1259 | /** | ||
1260 | * ibmvmc_ioctl_query - IOCTL Query | ||
1261 | * | ||
1262 | * @session: ibmvmc_file_session struct | ||
1263 | * @ret_struct: ibmvmc_query_struct | ||
1264 | * | ||
1265 | * Return: | ||
1266 | * 0 - Success | ||
1267 | * Non-zero - Failure | ||
1268 | */ | ||
1269 | static long ibmvmc_ioctl_query(struct ibmvmc_file_session *session, | ||
1270 | struct ibmvmc_query_struct __user *ret_struct) | ||
1271 | { | ||
1272 | struct ibmvmc_query_struct query_struct; | ||
1273 | size_t bytes; | ||
1274 | |||
1275 | memset(&query_struct, 0, sizeof(query_struct)); | ||
1276 | query_struct.have_vmc = (ibmvmc.state > ibmvmc_state_initial); | ||
1277 | query_struct.state = ibmvmc.state; | ||
1278 | query_struct.vmc_drc_index = ibmvmc.vmc_drc_index; | ||
1279 | |||
1280 | bytes = copy_to_user(ret_struct, &query_struct, | ||
1281 | sizeof(query_struct)); | ||
1282 | if (bytes) | ||
1283 | return -EFAULT; | ||
1284 | |||
1285 | return 0; | ||
1286 | } | ||
1287 | |||
1288 | /** | ||
1289 | * ibmvmc_ioctl_requestvmc - IOCTL Request VMC | ||
1290 | * | ||
1291 | * @session: ibmvmc_file_session struct | ||
1292 | * @ret_vmc_index: VMC Index | ||
1293 | * | ||
1294 | * Return: | ||
1295 | * 0 - Success | ||
1296 | * Non-zero - Failure | ||
1297 | */ | ||
1298 | static long ibmvmc_ioctl_requestvmc(struct ibmvmc_file_session *session, | ||
1299 | u32 __user *ret_vmc_index) | ||
1300 | { | ||
1301 | /* TODO: (adreznec) Add locking to control multiple process access */ | ||
1302 | size_t bytes; | ||
1303 | long rc; | ||
1304 | u32 vmc_drc_index; | ||
1305 | |||
1306 | /* Call to request the VMC device from phyp*/ | ||
1307 | rc = h_request_vmc(&vmc_drc_index); | ||
1308 | pr_debug("ibmvmc: requestvmc: H_REQUEST_VMC rc = 0x%lx\n", rc); | ||
1309 | |||
1310 | if (rc == H_SUCCESS) { | ||
1311 | rc = 0; | ||
1312 | } else if (rc == H_FUNCTION) { | ||
1313 | pr_err("ibmvmc: requestvmc: h_request_vmc not supported\n"); | ||
1314 | return -EPERM; | ||
1315 | } else if (rc == H_AUTHORITY) { | ||
1316 | pr_err("ibmvmc: requestvmc: hypervisor denied vmc request\n"); | ||
1317 | return -EPERM; | ||
1318 | } else if (rc == H_HARDWARE) { | ||
1319 | pr_err("ibmvmc: requestvmc: hypervisor hardware fault\n"); | ||
1320 | return -EIO; | ||
1321 | } else if (rc == H_RESOURCE) { | ||
1322 | pr_err("ibmvmc: requestvmc: vmc resource unavailable\n"); | ||
1323 | return -ENODEV; | ||
1324 | } else if (rc == H_NOT_AVAILABLE) { | ||
1325 | pr_err("ibmvmc: requestvmc: system cannot be vmc managed\n"); | ||
1326 | return -EPERM; | ||
1327 | } else if (rc == H_PARAMETER) { | ||
1328 | pr_err("ibmvmc: requestvmc: invalid parameter\n"); | ||
1329 | return -EINVAL; | ||
1330 | } | ||
1331 | |||
1332 | /* Success, set the vmc index in global struct */ | ||
1333 | ibmvmc.vmc_drc_index = vmc_drc_index; | ||
1334 | |||
1335 | bytes = copy_to_user(ret_vmc_index, &vmc_drc_index, | ||
1336 | sizeof(*ret_vmc_index)); | ||
1337 | if (bytes) { | ||
1338 | pr_warn("ibmvmc: requestvmc: copy to user failed.\n"); | ||
1339 | return -EFAULT; | ||
1340 | } | ||
1341 | return rc; | ||
1342 | } | ||
1343 | |||
1344 | /** | ||
1345 | * ibmvmc_ioctl - IOCTL | ||
1346 | * | ||
1347 | * @session: ibmvmc_file_session struct | ||
1348 | * @cmd: cmd field | ||
1349 | * @arg: Argument field | ||
1350 | * | ||
1351 | * Return: | ||
1352 | * 0 - Success | ||
1353 | * Non-zero - Failure | ||
1354 | */ | ||
1355 | static long ibmvmc_ioctl(struct file *file, | ||
1356 | unsigned int cmd, unsigned long arg) | ||
1357 | { | ||
1358 | struct ibmvmc_file_session *session = file->private_data; | ||
1359 | |||
1360 | pr_debug("ibmvmc: ioctl file=0x%lx, cmd=0x%x, arg=0x%lx, ses=0x%lx\n", | ||
1361 | (unsigned long)file, cmd, arg, | ||
1362 | (unsigned long)session); | ||
1363 | |||
1364 | if (!session) { | ||
1365 | pr_warn("ibmvmc: ioctl: no session\n"); | ||
1366 | return -EIO; | ||
1367 | } | ||
1368 | |||
1369 | switch (cmd) { | ||
1370 | case VMC_IOCTL_SETHMCID: | ||
1371 | return ibmvmc_ioctl_sethmcid(session, | ||
1372 | (unsigned char __user *)arg); | ||
1373 | case VMC_IOCTL_QUERY: | ||
1374 | return ibmvmc_ioctl_query(session, | ||
1375 | (struct ibmvmc_query_struct __user *)arg); | ||
1376 | case VMC_IOCTL_REQUESTVMC: | ||
1377 | return ibmvmc_ioctl_requestvmc(session, | ||
1378 | (unsigned int __user *)arg); | ||
1379 | default: | ||
1380 | pr_warn("ibmvmc: unknown ioctl 0x%x\n", cmd); | ||
1381 | return -EINVAL; | ||
1382 | } | ||
1383 | } | ||
1384 | |||
1385 | static const struct file_operations ibmvmc_fops = { | ||
1386 | .owner = THIS_MODULE, | ||
1387 | .read = ibmvmc_read, | ||
1388 | .write = ibmvmc_write, | ||
1389 | .poll = ibmvmc_poll, | ||
1390 | .unlocked_ioctl = ibmvmc_ioctl, | ||
1391 | .open = ibmvmc_open, | ||
1392 | .release = ibmvmc_close, | ||
1393 | }; | ||
1394 | |||
1395 | /** | ||
1396 | * ibmvmc_add_buffer - Add Buffer | ||
1397 | * | ||
1398 | * @adapter: crq_server_adapter struct | ||
1399 | * @crq: ibmvmc_crq_msg struct | ||
1400 | * | ||
1401 | * This message transfers a buffer from hypervisor ownership to management | ||
1402 | * partition ownership. The LIOBA is obtained from the virtual TCE table | ||
1403 | * associated with the hypervisor side of the VMC device, and points to a | ||
1404 | * buffer of size MTU (as established in the capabilities exchange). | ||
1405 | * | ||
1406 | * Typical flow for ading buffers: | ||
1407 | * 1. A new management application connection is opened by the management | ||
1408 | * partition. | ||
1409 | * 2. The hypervisor assigns new buffers for the traffic associated with | ||
1410 | * that connection. | ||
1411 | * 3. The hypervisor sends VMC Add Buffer messages to the management | ||
1412 | * partition, informing it of the new buffers. | ||
1413 | * 4. The hypervisor sends an HMC protocol message (to the management | ||
1414 | * application) notifying it of the new buffers. This informs the | ||
1415 | * application that it has buffers available for sending HMC | ||
1416 | * commands. | ||
1417 | * | ||
1418 | * Return: | ||
1419 | * 0 - Success | ||
1420 | * Non-zero - Failure | ||
1421 | */ | ||
1422 | static int ibmvmc_add_buffer(struct crq_server_adapter *adapter, | ||
1423 | struct ibmvmc_crq_msg *crq) | ||
1424 | { | ||
1425 | struct ibmvmc_buffer *buffer; | ||
1426 | u8 hmc_index; | ||
1427 | u8 hmc_session; | ||
1428 | u16 buffer_id; | ||
1429 | unsigned long flags; | ||
1430 | int rc = 0; | ||
1431 | |||
1432 | if (!crq) | ||
1433 | return -1; | ||
1434 | |||
1435 | hmc_session = crq->hmc_session; | ||
1436 | hmc_index = crq->hmc_index; | ||
1437 | buffer_id = be16_to_cpu(crq->var2.buffer_id); | ||
1438 | |||
1439 | if (hmc_index > ibmvmc.max_hmc_index) { | ||
1440 | dev_err(adapter->dev, "add_buffer: invalid hmc_index = 0x%x\n", | ||
1441 | hmc_index); | ||
1442 | ibmvmc_send_add_buffer_resp(adapter, VMC_MSG_INVALID_HMC_INDEX, | ||
1443 | hmc_session, hmc_index, buffer_id); | ||
1444 | return -1; | ||
1445 | } | ||
1446 | |||
1447 | if (buffer_id >= ibmvmc.max_buffer_pool_size) { | ||
1448 | dev_err(adapter->dev, "add_buffer: invalid buffer_id = 0x%x\n", | ||
1449 | buffer_id); | ||
1450 | ibmvmc_send_add_buffer_resp(adapter, VMC_MSG_INVALID_BUFFER_ID, | ||
1451 | hmc_session, hmc_index, buffer_id); | ||
1452 | return -1; | ||
1453 | } | ||
1454 | |||
1455 | spin_lock_irqsave(&hmcs[hmc_index].lock, flags); | ||
1456 | buffer = &hmcs[hmc_index].buffer[buffer_id]; | ||
1457 | |||
1458 | if (buffer->real_addr_local || buffer->dma_addr_local) { | ||
1459 | dev_warn(adapter->dev, "add_buffer: already allocated id = 0x%lx\n", | ||
1460 | (unsigned long)buffer_id); | ||
1461 | spin_unlock_irqrestore(&hmcs[hmc_index].lock, flags); | ||
1462 | ibmvmc_send_add_buffer_resp(adapter, VMC_MSG_INVALID_BUFFER_ID, | ||
1463 | hmc_session, hmc_index, buffer_id); | ||
1464 | return -1; | ||
1465 | } | ||
1466 | |||
1467 | buffer->real_addr_local = alloc_dma_buffer(to_vio_dev(adapter->dev), | ||
1468 | ibmvmc.max_mtu, | ||
1469 | &buffer->dma_addr_local); | ||
1470 | |||
1471 | if (!buffer->real_addr_local) { | ||
1472 | dev_err(adapter->dev, "add_buffer: alloc_dma_buffer failed.\n"); | ||
1473 | spin_unlock_irqrestore(&hmcs[hmc_index].lock, flags); | ||
1474 | ibmvmc_send_add_buffer_resp(adapter, VMC_MSG_INTERFACE_FAILURE, | ||
1475 | hmc_session, hmc_index, buffer_id); | ||
1476 | return -1; | ||
1477 | } | ||
1478 | |||
1479 | buffer->dma_addr_remote = be32_to_cpu(crq->var3.lioba); | ||
1480 | buffer->size = ibmvmc.max_mtu; | ||
1481 | buffer->owner = crq->var1.owner; | ||
1482 | buffer->free = 1; | ||
1483 | /* Must ensure valid==1 is observable only after all other fields are */ | ||
1484 | dma_wmb(); | ||
1485 | buffer->valid = 1; | ||
1486 | buffer->id = buffer_id; | ||
1487 | |||
1488 | dev_dbg(adapter->dev, "add_buffer: successfully added a buffer:\n"); | ||
1489 | dev_dbg(adapter->dev, " index: %d, session: %d, buffer: 0x%x, owner: %d\n", | ||
1490 | hmc_index, hmc_session, buffer_id, buffer->owner); | ||
1491 | dev_dbg(adapter->dev, " local: 0x%x, remote: 0x%x\n", | ||
1492 | (u32)buffer->dma_addr_local, | ||
1493 | (u32)buffer->dma_addr_remote); | ||
1494 | spin_unlock_irqrestore(&hmcs[hmc_index].lock, flags); | ||
1495 | |||
1496 | ibmvmc_send_add_buffer_resp(adapter, VMC_MSG_SUCCESS, hmc_session, | ||
1497 | hmc_index, buffer_id); | ||
1498 | |||
1499 | return rc; | ||
1500 | } | ||
1501 | |||
1502 | /** | ||
1503 | * ibmvmc_rem_buffer - Remove Buffer | ||
1504 | * | ||
1505 | * @adapter: crq_server_adapter struct | ||
1506 | * @crq: ibmvmc_crq_msg struct | ||
1507 | * | ||
1508 | * This message requests an HMC buffer to be transferred from management | ||
1509 | * partition ownership to hypervisor ownership. The management partition may | ||
1510 | * not be able to satisfy the request at a particular point in time if all its | ||
1511 | * buffers are in use. The management partition requires a depth of at least | ||
1512 | * one inbound buffer to allow management application commands to flow to the | ||
1513 | * hypervisor. It is, therefore, an interface error for the hypervisor to | ||
1514 | * attempt to remove the management partition's last buffer. | ||
1515 | * | ||
1516 | * The hypervisor is expected to manage buffer usage with the management | ||
1517 | * application directly and inform the management partition when buffers may be | ||
1518 | * removed. The typical flow for removing buffers: | ||
1519 | * | ||
1520 | * 1. The management application no longer needs a communication path to a | ||
1521 | * particular hypervisor function. That function is closed. | ||
1522 | * 2. The hypervisor and the management application quiesce all traffic to that | ||
1523 | * function. The hypervisor requests a reduction in buffer pool size. | ||
1524 | * 3. The management application acknowledges the reduction in buffer pool size. | ||
1525 | * 4. The hypervisor sends a Remove Buffer message to the management partition, | ||
1526 | * informing it of the reduction in buffers. | ||
1527 | * 5. The management partition verifies it can remove the buffer. This is | ||
1528 | * possible if buffers have been quiesced. | ||
1529 | * | ||
1530 | * Return: | ||
1531 | * 0 - Success | ||
1532 | * Non-zero - Failure | ||
1533 | */ | ||
1534 | /* | ||
1535 | * The hypervisor requested that we pick an unused buffer, and return it. | ||
1536 | * Before sending the buffer back, we free any storage associated with the | ||
1537 | * buffer. | ||
1538 | */ | ||
1539 | static int ibmvmc_rem_buffer(struct crq_server_adapter *adapter, | ||
1540 | struct ibmvmc_crq_msg *crq) | ||
1541 | { | ||
1542 | struct ibmvmc_buffer *buffer; | ||
1543 | u8 hmc_index; | ||
1544 | u8 hmc_session; | ||
1545 | u16 buffer_id = 0; | ||
1546 | unsigned long flags; | ||
1547 | int rc = 0; | ||
1548 | |||
1549 | if (!crq) | ||
1550 | return -1; | ||
1551 | |||
1552 | hmc_session = crq->hmc_session; | ||
1553 | hmc_index = crq->hmc_index; | ||
1554 | |||
1555 | if (hmc_index > ibmvmc.max_hmc_index) { | ||
1556 | dev_warn(adapter->dev, "rem_buffer: invalid hmc_index = 0x%x\n", | ||
1557 | hmc_index); | ||
1558 | ibmvmc_send_rem_buffer_resp(adapter, VMC_MSG_INVALID_HMC_INDEX, | ||
1559 | hmc_session, hmc_index, buffer_id); | ||
1560 | return -1; | ||
1561 | } | ||
1562 | |||
1563 | spin_lock_irqsave(&hmcs[hmc_index].lock, flags); | ||
1564 | buffer = ibmvmc_get_free_hmc_buffer(adapter, hmc_index); | ||
1565 | if (!buffer) { | ||
1566 | dev_info(adapter->dev, "rem_buffer: no buffer to remove\n"); | ||
1567 | spin_unlock_irqrestore(&hmcs[hmc_index].lock, flags); | ||
1568 | ibmvmc_send_rem_buffer_resp(adapter, VMC_MSG_NO_BUFFER, | ||
1569 | hmc_session, hmc_index, | ||
1570 | VMC_INVALID_BUFFER_ID); | ||
1571 | return -1; | ||
1572 | } | ||
1573 | |||
1574 | buffer_id = buffer->id; | ||
1575 | |||
1576 | if (buffer->valid) | ||
1577 | free_dma_buffer(to_vio_dev(adapter->dev), | ||
1578 | ibmvmc.max_mtu, | ||
1579 | buffer->real_addr_local, | ||
1580 | buffer->dma_addr_local); | ||
1581 | |||
1582 | memset(buffer, 0, sizeof(struct ibmvmc_buffer)); | ||
1583 | spin_unlock_irqrestore(&hmcs[hmc_index].lock, flags); | ||
1584 | |||
1585 | dev_dbg(adapter->dev, "rem_buffer: removed buffer 0x%x.\n", buffer_id); | ||
1586 | ibmvmc_send_rem_buffer_resp(adapter, VMC_MSG_SUCCESS, hmc_session, | ||
1587 | hmc_index, buffer_id); | ||
1588 | |||
1589 | return rc; | ||
1590 | } | ||
1591 | |||
1592 | static int ibmvmc_recv_msg(struct crq_server_adapter *adapter, | ||
1593 | struct ibmvmc_crq_msg *crq) | ||
1594 | { | ||
1595 | struct ibmvmc_buffer *buffer; | ||
1596 | struct ibmvmc_hmc *hmc; | ||
1597 | unsigned long msg_len; | ||
1598 | u8 hmc_index; | ||
1599 | u8 hmc_session; | ||
1600 | u16 buffer_id; | ||
1601 | unsigned long flags; | ||
1602 | int rc = 0; | ||
1603 | |||
1604 | if (!crq) | ||
1605 | return -1; | ||
1606 | |||
1607 | /* Hypervisor writes CRQs directly into our memory in big endian */ | ||
1608 | dev_dbg(adapter->dev, "Recv_msg: msg from HV 0x%016llx 0x%016llx\n", | ||
1609 | be64_to_cpu(*((unsigned long *)crq)), | ||
1610 | be64_to_cpu(*(((unsigned long *)crq) + 1))); | ||
1611 | |||
1612 | hmc_session = crq->hmc_session; | ||
1613 | hmc_index = crq->hmc_index; | ||
1614 | buffer_id = be16_to_cpu(crq->var2.buffer_id); | ||
1615 | msg_len = be32_to_cpu(crq->var3.msg_len); | ||
1616 | |||
1617 | if (hmc_index > ibmvmc.max_hmc_index) { | ||
1618 | dev_err(adapter->dev, "Recv_msg: invalid hmc_index = 0x%x\n", | ||
1619 | hmc_index); | ||
1620 | ibmvmc_send_add_buffer_resp(adapter, VMC_MSG_INVALID_HMC_INDEX, | ||
1621 | hmc_session, hmc_index, buffer_id); | ||
1622 | return -1; | ||
1623 | } | ||
1624 | |||
1625 | if (buffer_id >= ibmvmc.max_buffer_pool_size) { | ||
1626 | dev_err(adapter->dev, "Recv_msg: invalid buffer_id = 0x%x\n", | ||
1627 | buffer_id); | ||
1628 | ibmvmc_send_add_buffer_resp(adapter, VMC_MSG_INVALID_BUFFER_ID, | ||
1629 | hmc_session, hmc_index, buffer_id); | ||
1630 | return -1; | ||
1631 | } | ||
1632 | |||
1633 | hmc = &hmcs[hmc_index]; | ||
1634 | spin_lock_irqsave(&hmc->lock, flags); | ||
1635 | |||
1636 | if (hmc->state == ibmhmc_state_free) { | ||
1637 | dev_err(adapter->dev, "Recv_msg: invalid hmc state = 0x%x\n", | ||
1638 | hmc->state); | ||
1639 | /* HMC connection is not valid (possibly was reset under us). */ | ||
1640 | spin_unlock_irqrestore(&hmc->lock, flags); | ||
1641 | return -1; | ||
1642 | } | ||
1643 | |||
1644 | buffer = &hmc->buffer[buffer_id]; | ||
1645 | |||
1646 | if (buffer->valid == 0 || buffer->owner == VMC_BUF_OWNER_ALPHA) { | ||
1647 | dev_err(adapter->dev, "Recv_msg: not valid, or not HV. 0x%x 0x%x\n", | ||
1648 | buffer->valid, buffer->owner); | ||
1649 | spin_unlock_irqrestore(&hmc->lock, flags); | ||
1650 | return -1; | ||
1651 | } | ||
1652 | |||
1653 | /* RDMA the data into the partition. */ | ||
1654 | rc = h_copy_rdma(msg_len, | ||
1655 | adapter->riobn, | ||
1656 | buffer->dma_addr_remote, | ||
1657 | adapter->liobn, | ||
1658 | buffer->dma_addr_local); | ||
1659 | |||
1660 | dev_dbg(adapter->dev, "Recv_msg: msg_len = 0x%x, buffer_id = 0x%x, queue_head = 0x%x, hmc_idx = 0x%x\n", | ||
1661 | (unsigned int)msg_len, (unsigned int)buffer_id, | ||
1662 | (unsigned int)hmc->queue_head, (unsigned int)hmc_index); | ||
1663 | buffer->msg_len = msg_len; | ||
1664 | buffer->free = 0; | ||
1665 | buffer->owner = VMC_BUF_OWNER_ALPHA; | ||
1666 | |||
1667 | if (rc) { | ||
1668 | dev_err(adapter->dev, "Failure in recv_msg: h_copy_rdma = 0x%x\n", | ||
1669 | rc); | ||
1670 | spin_unlock_irqrestore(&hmc->lock, flags); | ||
1671 | return -1; | ||
1672 | } | ||
1673 | |||
1674 | /* Must be locked because read operates on the same data */ | ||
1675 | hmc->queue_outbound_msgs[hmc->queue_head] = buffer_id; | ||
1676 | hmc->queue_head++; | ||
1677 | if (hmc->queue_head == ibmvmc_max_buf_pool_size) | ||
1678 | hmc->queue_head = 0; | ||
1679 | |||
1680 | if (hmc->queue_head == hmc->queue_tail) | ||
1681 | dev_err(adapter->dev, "outbound buffer queue wrapped.\n"); | ||
1682 | |||
1683 | spin_unlock_irqrestore(&hmc->lock, flags); | ||
1684 | |||
1685 | wake_up_interruptible(&ibmvmc_read_wait); | ||
1686 | |||
1687 | return 0; | ||
1688 | } | ||
1689 | |||
1690 | /** | ||
1691 | * ibmvmc_process_capabilities - Process Capabilities | ||
1692 | * | ||
1693 | * @adapter: crq_server_adapter struct | ||
1694 | * @crqp: ibmvmc_crq_msg struct | ||
1695 | * | ||
1696 | */ | ||
1697 | static void ibmvmc_process_capabilities(struct crq_server_adapter *adapter, | ||
1698 | struct ibmvmc_crq_msg *crqp) | ||
1699 | { | ||
1700 | struct ibmvmc_admin_crq_msg *crq = (struct ibmvmc_admin_crq_msg *)crqp; | ||
1701 | |||
1702 | if ((be16_to_cpu(crq->version) >> 8) != | ||
1703 | (IBMVMC_PROTOCOL_VERSION >> 8)) { | ||
1704 | dev_err(adapter->dev, "init failed, incompatible versions 0x%x 0x%x\n", | ||
1705 | be16_to_cpu(crq->version), | ||
1706 | IBMVMC_PROTOCOL_VERSION); | ||
1707 | ibmvmc.state = ibmvmc_state_failed; | ||
1708 | return; | ||
1709 | } | ||
1710 | |||
1711 | ibmvmc.max_mtu = min_t(u32, ibmvmc_max_mtu, be32_to_cpu(crq->max_mtu)); | ||
1712 | ibmvmc.max_buffer_pool_size = min_t(u16, ibmvmc_max_buf_pool_size, | ||
1713 | be16_to_cpu(crq->pool_size)); | ||
1714 | ibmvmc.max_hmc_index = min_t(u8, ibmvmc_max_hmcs, crq->max_hmc) - 1; | ||
1715 | ibmvmc.state = ibmvmc_state_ready; | ||
1716 | |||
1717 | dev_info(adapter->dev, "Capabilities: mtu=0x%x, pool_size=0x%x, max_hmc=0x%x\n", | ||
1718 | ibmvmc.max_mtu, ibmvmc.max_buffer_pool_size, | ||
1719 | ibmvmc.max_hmc_index); | ||
1720 | } | ||
1721 | |||
1722 | /** | ||
1723 | * ibmvmc_validate_hmc_session - Validate HMC Session | ||
1724 | * | ||
1725 | * @adapter: crq_server_adapter struct | ||
1726 | * @crq: ibmvmc_crq_msg struct | ||
1727 | * | ||
1728 | * Return: | ||
1729 | * 0 - Success | ||
1730 | * Non-zero - Failure | ||
1731 | */ | ||
1732 | static int ibmvmc_validate_hmc_session(struct crq_server_adapter *adapter, | ||
1733 | struct ibmvmc_crq_msg *crq) | ||
1734 | { | ||
1735 | unsigned char hmc_index; | ||
1736 | |||
1737 | hmc_index = crq->hmc_index; | ||
1738 | |||
1739 | if (crq->hmc_session == 0) | ||
1740 | return 0; | ||
1741 | |||
1742 | if (hmc_index > ibmvmc.max_hmc_index) | ||
1743 | return -1; | ||
1744 | |||
1745 | if (hmcs[hmc_index].session != crq->hmc_session) { | ||
1746 | dev_warn(adapter->dev, "Drop, bad session: expected 0x%x, recv 0x%x\n", | ||
1747 | hmcs[hmc_index].session, crq->hmc_session); | ||
1748 | return -1; | ||
1749 | } | ||
1750 | |||
1751 | return 0; | ||
1752 | } | ||
1753 | |||
1754 | /** | ||
1755 | * ibmvmc_reset - Reset | ||
1756 | * | ||
1757 | * @adapter: crq_server_adapter struct | ||
1758 | * @xport_event: export_event field | ||
1759 | * | ||
1760 | * Closes all HMC sessions and conditionally schedules a CRQ reset. | ||
1761 | * @xport_event: If true, the partner closed their CRQ; we don't need to reset. | ||
1762 | * If false, we need to schedule a CRQ reset. | ||
1763 | */ | ||
1764 | static void ibmvmc_reset(struct crq_server_adapter *adapter, bool xport_event) | ||
1765 | { | ||
1766 | int i; | ||
1767 | |||
1768 | if (ibmvmc.state != ibmvmc_state_sched_reset) { | ||
1769 | dev_info(adapter->dev, "*** Reset to initial state.\n"); | ||
1770 | for (i = 0; i < ibmvmc_max_hmcs; i++) | ||
1771 | ibmvmc_return_hmc(&hmcs[i], xport_event); | ||
1772 | |||
1773 | if (xport_event) { | ||
1774 | /* CRQ was closed by the partner. We don't need to do | ||
1775 | * anything except set ourself to the correct state to | ||
1776 | * handle init msgs. | ||
1777 | */ | ||
1778 | ibmvmc.state = ibmvmc_state_crqinit; | ||
1779 | } else { | ||
1780 | /* The partner did not close their CRQ - instead, we're | ||
1781 | * closing the CRQ on our end. Need to schedule this | ||
1782 | * for process context, because CRQ reset may require a | ||
1783 | * sleep. | ||
1784 | * | ||
1785 | * Setting ibmvmc.state here immediately prevents | ||
1786 | * ibmvmc_open from completing until the reset | ||
1787 | * completes in process context. | ||
1788 | */ | ||
1789 | ibmvmc.state = ibmvmc_state_sched_reset; | ||
1790 | dev_dbg(adapter->dev, "Device reset scheduled"); | ||
1791 | wake_up_interruptible(&adapter->reset_wait_queue); | ||
1792 | } | ||
1793 | } | ||
1794 | } | ||
1795 | |||
1796 | /** | ||
1797 | * ibmvmc_reset_task - Reset Task | ||
1798 | * | ||
1799 | * @data: Data field | ||
1800 | * | ||
1801 | * Performs a CRQ reset of the VMC device in process context. | ||
1802 | * NOTE: This function should not be called directly, use ibmvmc_reset. | ||
1803 | */ | ||
1804 | static int ibmvmc_reset_task(void *data) | ||
1805 | { | ||
1806 | struct crq_server_adapter *adapter = data; | ||
1807 | int rc; | ||
1808 | |||
1809 | set_user_nice(current, -20); | ||
1810 | |||
1811 | while (!kthread_should_stop()) { | ||
1812 | wait_event_interruptible(adapter->reset_wait_queue, | ||
1813 | (ibmvmc.state == ibmvmc_state_sched_reset) || | ||
1814 | kthread_should_stop()); | ||
1815 | |||
1816 | if (kthread_should_stop()) | ||
1817 | break; | ||
1818 | |||
1819 | dev_dbg(adapter->dev, "CRQ resetting in process context"); | ||
1820 | tasklet_disable(&adapter->work_task); | ||
1821 | |||
1822 | rc = ibmvmc_reset_crq_queue(adapter); | ||
1823 | |||
1824 | if (rc != H_SUCCESS && rc != H_RESOURCE) { | ||
1825 | dev_err(adapter->dev, "Error initializing CRQ. rc = 0x%x\n", | ||
1826 | rc); | ||
1827 | ibmvmc.state = ibmvmc_state_failed; | ||
1828 | } else { | ||
1829 | ibmvmc.state = ibmvmc_state_crqinit; | ||
1830 | |||
1831 | if (ibmvmc_send_crq(adapter, 0xC001000000000000LL, 0) | ||
1832 | != 0 && rc != H_RESOURCE) | ||
1833 | dev_warn(adapter->dev, "Failed to send initialize CRQ message\n"); | ||
1834 | } | ||
1835 | |||
1836 | vio_enable_interrupts(to_vio_dev(adapter->dev)); | ||
1837 | tasklet_enable(&adapter->work_task); | ||
1838 | } | ||
1839 | |||
1840 | return 0; | ||
1841 | } | ||
1842 | |||
1843 | /** | ||
1844 | * ibmvmc_process_open_resp - Process Open Response | ||
1845 | * | ||
1846 | * @crq: ibmvmc_crq_msg struct | ||
1847 | * @adapter: crq_server_adapter struct | ||
1848 | * | ||
1849 | * This command is sent by the hypervisor in response to the Interface | ||
1850 | * Open message. When this message is received, the indicated buffer is | ||
1851 | * again available for management partition use. | ||
1852 | */ | ||
1853 | static void ibmvmc_process_open_resp(struct ibmvmc_crq_msg *crq, | ||
1854 | struct crq_server_adapter *adapter) | ||
1855 | { | ||
1856 | unsigned char hmc_index; | ||
1857 | unsigned short buffer_id; | ||
1858 | |||
1859 | hmc_index = crq->hmc_index; | ||
1860 | if (hmc_index > ibmvmc.max_hmc_index) { | ||
1861 | /* Why would PHYP give an index > max negotiated? */ | ||
1862 | ibmvmc_reset(adapter, false); | ||
1863 | return; | ||
1864 | } | ||
1865 | |||
1866 | if (crq->status) { | ||
1867 | dev_warn(adapter->dev, "open_resp: failed - status 0x%x\n", | ||
1868 | crq->status); | ||
1869 | ibmvmc_return_hmc(&hmcs[hmc_index], false); | ||
1870 | return; | ||
1871 | } | ||
1872 | |||
1873 | if (hmcs[hmc_index].state == ibmhmc_state_opening) { | ||
1874 | buffer_id = be16_to_cpu(crq->var2.buffer_id); | ||
1875 | if (buffer_id >= ibmvmc.max_buffer_pool_size) { | ||
1876 | dev_err(adapter->dev, "open_resp: invalid buffer_id = 0x%x\n", | ||
1877 | buffer_id); | ||
1878 | hmcs[hmc_index].state = ibmhmc_state_failed; | ||
1879 | } else { | ||
1880 | ibmvmc_free_hmc_buffer(&hmcs[hmc_index], | ||
1881 | &hmcs[hmc_index].buffer[buffer_id]); | ||
1882 | hmcs[hmc_index].state = ibmhmc_state_ready; | ||
1883 | dev_dbg(adapter->dev, "open_resp: set hmc state = ready\n"); | ||
1884 | } | ||
1885 | } else { | ||
1886 | dev_warn(adapter->dev, "open_resp: invalid hmc state (0x%x)\n", | ||
1887 | hmcs[hmc_index].state); | ||
1888 | } | ||
1889 | } | ||
1890 | |||
1891 | /** | ||
1892 | * ibmvmc_process_close_resp - Process Close Response | ||
1893 | * | ||
1894 | * @crq: ibmvmc_crq_msg struct | ||
1895 | * @adapter: crq_server_adapter struct | ||
1896 | * | ||
1897 | * This command is sent by the hypervisor in response to the managemant | ||
1898 | * application Interface Close message. | ||
1899 | * | ||
1900 | * If the close fails, simply reset the entire driver as the state of the VMC | ||
1901 | * must be in tough shape. | ||
1902 | */ | ||
1903 | static void ibmvmc_process_close_resp(struct ibmvmc_crq_msg *crq, | ||
1904 | struct crq_server_adapter *adapter) | ||
1905 | { | ||
1906 | unsigned char hmc_index; | ||
1907 | |||
1908 | hmc_index = crq->hmc_index; | ||
1909 | if (hmc_index > ibmvmc.max_hmc_index) { | ||
1910 | ibmvmc_reset(adapter, false); | ||
1911 | return; | ||
1912 | } | ||
1913 | |||
1914 | if (crq->status) { | ||
1915 | dev_warn(adapter->dev, "close_resp: failed - status 0x%x\n", | ||
1916 | crq->status); | ||
1917 | ibmvmc_reset(adapter, false); | ||
1918 | return; | ||
1919 | } | ||
1920 | |||
1921 | ibmvmc_return_hmc(&hmcs[hmc_index], false); | ||
1922 | } | ||
1923 | |||
1924 | /** | ||
1925 | * ibmvmc_crq_process - Process CRQ | ||
1926 | * | ||
1927 | * @adapter: crq_server_adapter struct | ||
1928 | * @crq: ibmvmc_crq_msg struct | ||
1929 | * | ||
1930 | * Process the CRQ message based upon the type of message received. | ||
1931 | * | ||
1932 | */ | ||
1933 | static void ibmvmc_crq_process(struct crq_server_adapter *adapter, | ||
1934 | struct ibmvmc_crq_msg *crq) | ||
1935 | { | ||
1936 | switch (crq->type) { | ||
1937 | case VMC_MSG_CAP_RESP: | ||
1938 | dev_dbg(adapter->dev, "CRQ recv: capabilities resp (0x%x)\n", | ||
1939 | crq->type); | ||
1940 | if (ibmvmc.state == ibmvmc_state_capabilities) | ||
1941 | ibmvmc_process_capabilities(adapter, crq); | ||
1942 | else | ||
1943 | dev_warn(adapter->dev, "caps msg invalid in state 0x%x\n", | ||
1944 | ibmvmc.state); | ||
1945 | break; | ||
1946 | case VMC_MSG_OPEN_RESP: | ||
1947 | dev_dbg(adapter->dev, "CRQ recv: open resp (0x%x)\n", | ||
1948 | crq->type); | ||
1949 | if (ibmvmc_validate_hmc_session(adapter, crq) == 0) | ||
1950 | ibmvmc_process_open_resp(crq, adapter); | ||
1951 | break; | ||
1952 | case VMC_MSG_ADD_BUF: | ||
1953 | dev_dbg(adapter->dev, "CRQ recv: add buf (0x%x)\n", | ||
1954 | crq->type); | ||
1955 | if (ibmvmc_validate_hmc_session(adapter, crq) == 0) | ||
1956 | ibmvmc_add_buffer(adapter, crq); | ||
1957 | break; | ||
1958 | case VMC_MSG_REM_BUF: | ||
1959 | dev_dbg(adapter->dev, "CRQ recv: rem buf (0x%x)\n", | ||
1960 | crq->type); | ||
1961 | if (ibmvmc_validate_hmc_session(adapter, crq) == 0) | ||
1962 | ibmvmc_rem_buffer(adapter, crq); | ||
1963 | break; | ||
1964 | case VMC_MSG_SIGNAL: | ||
1965 | dev_dbg(adapter->dev, "CRQ recv: signal msg (0x%x)\n", | ||
1966 | crq->type); | ||
1967 | if (ibmvmc_validate_hmc_session(adapter, crq) == 0) | ||
1968 | ibmvmc_recv_msg(adapter, crq); | ||
1969 | break; | ||
1970 | case VMC_MSG_CLOSE_RESP: | ||
1971 | dev_dbg(adapter->dev, "CRQ recv: close resp (0x%x)\n", | ||
1972 | crq->type); | ||
1973 | if (ibmvmc_validate_hmc_session(adapter, crq) == 0) | ||
1974 | ibmvmc_process_close_resp(crq, adapter); | ||
1975 | break; | ||
1976 | case VMC_MSG_CAP: | ||
1977 | case VMC_MSG_OPEN: | ||
1978 | case VMC_MSG_CLOSE: | ||
1979 | case VMC_MSG_ADD_BUF_RESP: | ||
1980 | case VMC_MSG_REM_BUF_RESP: | ||
1981 | dev_warn(adapter->dev, "CRQ recv: unexpected msg (0x%x)\n", | ||
1982 | crq->type); | ||
1983 | break; | ||
1984 | default: | ||
1985 | dev_warn(adapter->dev, "CRQ recv: unknown msg (0x%x)\n", | ||
1986 | crq->type); | ||
1987 | break; | ||
1988 | } | ||
1989 | } | ||
1990 | |||
1991 | /** | ||
1992 | * ibmvmc_handle_crq_init - Handle CRQ Init | ||
1993 | * | ||
1994 | * @crq: ibmvmc_crq_msg struct | ||
1995 | * @adapter: crq_server_adapter struct | ||
1996 | * | ||
1997 | * Handle the type of crq initialization based on whether | ||
1998 | * it is a message or a response. | ||
1999 | * | ||
2000 | */ | ||
2001 | static void ibmvmc_handle_crq_init(struct ibmvmc_crq_msg *crq, | ||
2002 | struct crq_server_adapter *adapter) | ||
2003 | { | ||
2004 | switch (crq->type) { | ||
2005 | case 0x01: /* Initialization message */ | ||
2006 | dev_dbg(adapter->dev, "CRQ recv: CRQ init msg - state 0x%x\n", | ||
2007 | ibmvmc.state); | ||
2008 | if (ibmvmc.state == ibmvmc_state_crqinit) { | ||
2009 | /* Send back a response */ | ||
2010 | if (ibmvmc_send_crq(adapter, 0xC002000000000000, | ||
2011 | 0) == 0) | ||
2012 | ibmvmc_send_capabilities(adapter); | ||
2013 | else | ||
2014 | dev_err(adapter->dev, " Unable to send init rsp\n"); | ||
2015 | } else { | ||
2016 | dev_err(adapter->dev, "Invalid state 0x%x mtu = 0x%x\n", | ||
2017 | ibmvmc.state, ibmvmc.max_mtu); | ||
2018 | } | ||
2019 | |||
2020 | break; | ||
2021 | case 0x02: /* Initialization response */ | ||
2022 | dev_dbg(adapter->dev, "CRQ recv: initialization resp msg - state 0x%x\n", | ||
2023 | ibmvmc.state); | ||
2024 | if (ibmvmc.state == ibmvmc_state_crqinit) | ||
2025 | ibmvmc_send_capabilities(adapter); | ||
2026 | break; | ||
2027 | default: | ||
2028 | dev_warn(adapter->dev, "Unknown crq message type 0x%lx\n", | ||
2029 | (unsigned long)crq->type); | ||
2030 | } | ||
2031 | } | ||
2032 | |||
2033 | /** | ||
2034 | * ibmvmc_handle_crq - Handle CRQ | ||
2035 | * | ||
2036 | * @crq: ibmvmc_crq_msg struct | ||
2037 | * @adapter: crq_server_adapter struct | ||
2038 | * | ||
2039 | * Read the command elements from the command queue and execute the | ||
2040 | * requests based upon the type of crq message. | ||
2041 | * | ||
2042 | */ | ||
2043 | static void ibmvmc_handle_crq(struct ibmvmc_crq_msg *crq, | ||
2044 | struct crq_server_adapter *adapter) | ||
2045 | { | ||
2046 | switch (crq->valid) { | ||
2047 | case 0xC0: /* initialization */ | ||
2048 | ibmvmc_handle_crq_init(crq, adapter); | ||
2049 | break; | ||
2050 | case 0xFF: /* Hypervisor telling us the connection is closed */ | ||
2051 | dev_warn(adapter->dev, "CRQ recv: virtual adapter failed - resetting.\n"); | ||
2052 | ibmvmc_reset(adapter, true); | ||
2053 | break; | ||
2054 | case 0x80: /* real payload */ | ||
2055 | ibmvmc_crq_process(adapter, crq); | ||
2056 | break; | ||
2057 | default: | ||
2058 | dev_warn(adapter->dev, "CRQ recv: unknown msg 0x%02x.\n", | ||
2059 | crq->valid); | ||
2060 | break; | ||
2061 | } | ||
2062 | } | ||
2063 | |||
2064 | static void ibmvmc_task(unsigned long data) | ||
2065 | { | ||
2066 | struct crq_server_adapter *adapter = | ||
2067 | (struct crq_server_adapter *)data; | ||
2068 | struct vio_dev *vdev = to_vio_dev(adapter->dev); | ||
2069 | struct ibmvmc_crq_msg *crq; | ||
2070 | int done = 0; | ||
2071 | |||
2072 | while (!done) { | ||
2073 | /* Pull all the valid messages off the CRQ */ | ||
2074 | while ((crq = crq_queue_next_crq(&adapter->queue)) != NULL) { | ||
2075 | ibmvmc_handle_crq(crq, adapter); | ||
2076 | crq->valid = 0x00; | ||
2077 | /* CRQ reset was requested, stop processing CRQs. | ||
2078 | * Interrupts will be re-enabled by the reset task. | ||
2079 | */ | ||
2080 | if (ibmvmc.state == ibmvmc_state_sched_reset) | ||
2081 | return; | ||
2082 | } | ||
2083 | |||
2084 | vio_enable_interrupts(vdev); | ||
2085 | crq = crq_queue_next_crq(&adapter->queue); | ||
2086 | if (crq) { | ||
2087 | vio_disable_interrupts(vdev); | ||
2088 | ibmvmc_handle_crq(crq, adapter); | ||
2089 | crq->valid = 0x00; | ||
2090 | /* CRQ reset was requested, stop processing CRQs. | ||
2091 | * Interrupts will be re-enabled by the reset task. | ||
2092 | */ | ||
2093 | if (ibmvmc.state == ibmvmc_state_sched_reset) | ||
2094 | return; | ||
2095 | } else { | ||
2096 | done = 1; | ||
2097 | } | ||
2098 | } | ||
2099 | } | ||
2100 | |||
2101 | /** | ||
2102 | * ibmvmc_init_crq_queue - Init CRQ Queue | ||
2103 | * | ||
2104 | * @adapter: crq_server_adapter struct | ||
2105 | * | ||
2106 | * Return: | ||
2107 | * 0 - Success | ||
2108 | * Non-zero - Failure | ||
2109 | */ | ||
2110 | static int ibmvmc_init_crq_queue(struct crq_server_adapter *adapter) | ||
2111 | { | ||
2112 | struct vio_dev *vdev = to_vio_dev(adapter->dev); | ||
2113 | struct crq_queue *queue = &adapter->queue; | ||
2114 | int rc = 0; | ||
2115 | int retrc = 0; | ||
2116 | |||
2117 | queue->msgs = (struct ibmvmc_crq_msg *)get_zeroed_page(GFP_KERNEL); | ||
2118 | |||
2119 | if (!queue->msgs) | ||
2120 | goto malloc_failed; | ||
2121 | |||
2122 | queue->size = PAGE_SIZE / sizeof(*queue->msgs); | ||
2123 | |||
2124 | queue->msg_token = dma_map_single(adapter->dev, queue->msgs, | ||
2125 | queue->size * sizeof(*queue->msgs), | ||
2126 | DMA_BIDIRECTIONAL); | ||
2127 | |||
2128 | if (dma_mapping_error(adapter->dev, queue->msg_token)) | ||
2129 | goto map_failed; | ||
2130 | |||
2131 | retrc = plpar_hcall_norets(H_REG_CRQ, | ||
2132 | vdev->unit_address, | ||
2133 | queue->msg_token, PAGE_SIZE); | ||
2134 | retrc = rc; | ||
2135 | |||
2136 | if (rc == H_RESOURCE) | ||
2137 | rc = ibmvmc_reset_crq_queue(adapter); | ||
2138 | |||
2139 | if (rc == 2) { | ||
2140 | dev_warn(adapter->dev, "Partner adapter not ready\n"); | ||
2141 | retrc = 0; | ||
2142 | } else if (rc != 0) { | ||
2143 | dev_err(adapter->dev, "Error %d opening adapter\n", rc); | ||
2144 | goto reg_crq_failed; | ||
2145 | } | ||
2146 | |||
2147 | queue->cur = 0; | ||
2148 | spin_lock_init(&queue->lock); | ||
2149 | |||
2150 | tasklet_init(&adapter->work_task, ibmvmc_task, (unsigned long)adapter); | ||
2151 | |||
2152 | if (request_irq(vdev->irq, | ||
2153 | ibmvmc_handle_event, | ||
2154 | 0, "ibmvmc", (void *)adapter) != 0) { | ||
2155 | dev_err(adapter->dev, "couldn't register irq 0x%x\n", | ||
2156 | vdev->irq); | ||
2157 | goto req_irq_failed; | ||
2158 | } | ||
2159 | |||
2160 | rc = vio_enable_interrupts(vdev); | ||
2161 | if (rc != 0) { | ||
2162 | dev_err(adapter->dev, "Error %d enabling interrupts!!!\n", rc); | ||
2163 | goto req_irq_failed; | ||
2164 | } | ||
2165 | |||
2166 | return retrc; | ||
2167 | |||
2168 | req_irq_failed: | ||
2169 | /* Cannot have any work since we either never got our IRQ registered, | ||
2170 | * or never got interrupts enabled | ||
2171 | */ | ||
2172 | tasklet_kill(&adapter->work_task); | ||
2173 | h_free_crq(vdev->unit_address); | ||
2174 | reg_crq_failed: | ||
2175 | dma_unmap_single(adapter->dev, | ||
2176 | queue->msg_token, | ||
2177 | queue->size * sizeof(*queue->msgs), DMA_BIDIRECTIONAL); | ||
2178 | map_failed: | ||
2179 | free_page((unsigned long)queue->msgs); | ||
2180 | malloc_failed: | ||
2181 | return -ENOMEM; | ||
2182 | } | ||
2183 | |||
2184 | /* Fill in the liobn and riobn fields on the adapter */ | ||
2185 | static int read_dma_window(struct vio_dev *vdev, | ||
2186 | struct crq_server_adapter *adapter) | ||
2187 | { | ||
2188 | const __be32 *dma_window; | ||
2189 | const __be32 *prop; | ||
2190 | |||
2191 | /* TODO Using of_parse_dma_window would be better, but it doesn't give | ||
2192 | * a way to read multiple windows without already knowing the size of | ||
2193 | * a window or the number of windows | ||
2194 | */ | ||
2195 | dma_window = | ||
2196 | (const __be32 *)vio_get_attribute(vdev, "ibm,my-dma-window", | ||
2197 | NULL); | ||
2198 | if (!dma_window) { | ||
2199 | dev_warn(adapter->dev, "Couldn't find ibm,my-dma-window property\n"); | ||
2200 | return -1; | ||
2201 | } | ||
2202 | |||
2203 | adapter->liobn = be32_to_cpu(*dma_window); | ||
2204 | dma_window++; | ||
2205 | |||
2206 | prop = (const __be32 *)vio_get_attribute(vdev, "ibm,#dma-address-cells", | ||
2207 | NULL); | ||
2208 | if (!prop) { | ||
2209 | dev_warn(adapter->dev, "Couldn't find ibm,#dma-address-cells property\n"); | ||
2210 | dma_window++; | ||
2211 | } else { | ||
2212 | dma_window += be32_to_cpu(*prop); | ||
2213 | } | ||
2214 | |||
2215 | prop = (const __be32 *)vio_get_attribute(vdev, "ibm,#dma-size-cells", | ||
2216 | NULL); | ||
2217 | if (!prop) { | ||
2218 | dev_warn(adapter->dev, "Couldn't find ibm,#dma-size-cells property\n"); | ||
2219 | dma_window++; | ||
2220 | } else { | ||
2221 | dma_window += be32_to_cpu(*prop); | ||
2222 | } | ||
2223 | |||
2224 | /* dma_window should point to the second window now */ | ||
2225 | adapter->riobn = be32_to_cpu(*dma_window); | ||
2226 | |||
2227 | return 0; | ||
2228 | } | ||
2229 | |||
2230 | static int ibmvmc_probe(struct vio_dev *vdev, const struct vio_device_id *id) | ||
2231 | { | ||
2232 | struct crq_server_adapter *adapter = &ibmvmc_adapter; | ||
2233 | int rc; | ||
2234 | |||
2235 | dev_set_drvdata(&vdev->dev, NULL); | ||
2236 | memset(adapter, 0, sizeof(*adapter)); | ||
2237 | adapter->dev = &vdev->dev; | ||
2238 | |||
2239 | dev_info(adapter->dev, "Probe for UA 0x%x\n", vdev->unit_address); | ||
2240 | |||
2241 | rc = read_dma_window(vdev, adapter); | ||
2242 | if (rc != 0) { | ||
2243 | ibmvmc.state = ibmvmc_state_failed; | ||
2244 | return -1; | ||
2245 | } | ||
2246 | |||
2247 | dev_dbg(adapter->dev, "Probe: liobn 0x%x, riobn 0x%x\n", | ||
2248 | adapter->liobn, adapter->riobn); | ||
2249 | |||
2250 | init_waitqueue_head(&adapter->reset_wait_queue); | ||
2251 | adapter->reset_task = kthread_run(ibmvmc_reset_task, adapter, "ibmvmc"); | ||
2252 | if (IS_ERR(adapter->reset_task)) { | ||
2253 | dev_err(adapter->dev, "Failed to start reset thread\n"); | ||
2254 | ibmvmc.state = ibmvmc_state_failed; | ||
2255 | rc = PTR_ERR(adapter->reset_task); | ||
2256 | adapter->reset_task = NULL; | ||
2257 | return rc; | ||
2258 | } | ||
2259 | |||
2260 | rc = ibmvmc_init_crq_queue(adapter); | ||
2261 | if (rc != 0 && rc != H_RESOURCE) { | ||
2262 | dev_err(adapter->dev, "Error initializing CRQ. rc = 0x%x\n", | ||
2263 | rc); | ||
2264 | ibmvmc.state = ibmvmc_state_failed; | ||
2265 | goto crq_failed; | ||
2266 | } | ||
2267 | |||
2268 | ibmvmc.state = ibmvmc_state_crqinit; | ||
2269 | |||
2270 | /* Try to send an initialization message. Note that this is allowed | ||
2271 | * to fail if the other end is not acive. In that case we just wait | ||
2272 | * for the other side to initialize. | ||
2273 | */ | ||
2274 | if (ibmvmc_send_crq(adapter, 0xC001000000000000LL, 0) != 0 && | ||
2275 | rc != H_RESOURCE) | ||
2276 | dev_warn(adapter->dev, "Failed to send initialize CRQ message\n"); | ||
2277 | |||
2278 | dev_set_drvdata(&vdev->dev, adapter); | ||
2279 | |||
2280 | return 0; | ||
2281 | |||
2282 | crq_failed: | ||
2283 | kthread_stop(adapter->reset_task); | ||
2284 | adapter->reset_task = NULL; | ||
2285 | return -EPERM; | ||
2286 | } | ||
2287 | |||
2288 | static int ibmvmc_remove(struct vio_dev *vdev) | ||
2289 | { | ||
2290 | struct crq_server_adapter *adapter = dev_get_drvdata(&vdev->dev); | ||
2291 | |||
2292 | dev_info(adapter->dev, "Entering remove for UA 0x%x\n", | ||
2293 | vdev->unit_address); | ||
2294 | ibmvmc_release_crq_queue(adapter); | ||
2295 | |||
2296 | return 0; | ||
2297 | } | ||
2298 | |||
2299 | static struct vio_device_id ibmvmc_device_table[] = { | ||
2300 | { "ibm,vmc", "IBM,vmc" }, | ||
2301 | { "", "" } | ||
2302 | }; | ||
2303 | MODULE_DEVICE_TABLE(vio, ibmvmc_device_table); | ||
2304 | |||
2305 | static struct vio_driver ibmvmc_driver = { | ||
2306 | .name = ibmvmc_driver_name, | ||
2307 | .id_table = ibmvmc_device_table, | ||
2308 | .probe = ibmvmc_probe, | ||
2309 | .remove = ibmvmc_remove, | ||
2310 | }; | ||
2311 | |||
2312 | static void __init ibmvmc_scrub_module_parms(void) | ||
2313 | { | ||
2314 | if (ibmvmc_max_mtu > MAX_MTU) { | ||
2315 | pr_warn("ibmvmc: Max MTU reduced to %d\n", MAX_MTU); | ||
2316 | ibmvmc_max_mtu = MAX_MTU; | ||
2317 | } else if (ibmvmc_max_mtu < MIN_MTU) { | ||
2318 | pr_warn("ibmvmc: Max MTU increased to %d\n", MIN_MTU); | ||
2319 | ibmvmc_max_mtu = MIN_MTU; | ||
2320 | } | ||
2321 | |||
2322 | if (ibmvmc_max_buf_pool_size > MAX_BUF_POOL_SIZE) { | ||
2323 | pr_warn("ibmvmc: Max buffer pool size reduced to %d\n", | ||
2324 | MAX_BUF_POOL_SIZE); | ||
2325 | ibmvmc_max_buf_pool_size = MAX_BUF_POOL_SIZE; | ||
2326 | } else if (ibmvmc_max_buf_pool_size < MIN_BUF_POOL_SIZE) { | ||
2327 | pr_warn("ibmvmc: Max buffer pool size increased to %d\n", | ||
2328 | MIN_BUF_POOL_SIZE); | ||
2329 | ibmvmc_max_buf_pool_size = MIN_BUF_POOL_SIZE; | ||
2330 | } | ||
2331 | |||
2332 | if (ibmvmc_max_hmcs > MAX_HMCS) { | ||
2333 | pr_warn("ibmvmc: Max HMCs reduced to %d\n", MAX_HMCS); | ||
2334 | ibmvmc_max_hmcs = MAX_HMCS; | ||
2335 | } else if (ibmvmc_max_hmcs < MIN_HMCS) { | ||
2336 | pr_warn("ibmvmc: Max HMCs increased to %d\n", MIN_HMCS); | ||
2337 | ibmvmc_max_hmcs = MIN_HMCS; | ||
2338 | } | ||
2339 | } | ||
2340 | |||
2341 | static struct miscdevice ibmvmc_miscdev = { | ||
2342 | .name = ibmvmc_driver_name, | ||
2343 | .minor = MISC_DYNAMIC_MINOR, | ||
2344 | .fops = &ibmvmc_fops, | ||
2345 | }; | ||
2346 | |||
2347 | static int __init ibmvmc_module_init(void) | ||
2348 | { | ||
2349 | int rc, i, j; | ||
2350 | |||
2351 | ibmvmc.state = ibmvmc_state_initial; | ||
2352 | pr_info("ibmvmc: version %s\n", IBMVMC_DRIVER_VERSION); | ||
2353 | |||
2354 | rc = misc_register(&ibmvmc_miscdev); | ||
2355 | if (rc) { | ||
2356 | pr_err("ibmvmc: misc registration failed\n"); | ||
2357 | goto misc_register_failed; | ||
2358 | } | ||
2359 | pr_info("ibmvmc: node %d:%d\n", MISC_MAJOR, | ||
2360 | ibmvmc_miscdev.minor); | ||
2361 | |||
2362 | /* Initialize data structures */ | ||
2363 | memset(hmcs, 0, sizeof(struct ibmvmc_hmc) * MAX_HMCS); | ||
2364 | for (i = 0; i < MAX_HMCS; i++) { | ||
2365 | spin_lock_init(&hmcs[i].lock); | ||
2366 | hmcs[i].state = ibmhmc_state_free; | ||
2367 | for (j = 0; j < MAX_BUF_POOL_SIZE; j++) | ||
2368 | hmcs[i].queue_outbound_msgs[j] = VMC_INVALID_BUFFER_ID; | ||
2369 | } | ||
2370 | |||
2371 | /* Sanity check module parms */ | ||
2372 | ibmvmc_scrub_module_parms(); | ||
2373 | |||
2374 | /* | ||
2375 | * Initialize some reasonable values. Might be negotiated smaller | ||
2376 | * values during the capabilities exchange. | ||
2377 | */ | ||
2378 | ibmvmc.max_mtu = ibmvmc_max_mtu; | ||
2379 | ibmvmc.max_buffer_pool_size = ibmvmc_max_buf_pool_size; | ||
2380 | ibmvmc.max_hmc_index = ibmvmc_max_hmcs - 1; | ||
2381 | |||
2382 | rc = vio_register_driver(&ibmvmc_driver); | ||
2383 | |||
2384 | if (rc) { | ||
2385 | pr_err("ibmvmc: rc %d from vio_register_driver\n", rc); | ||
2386 | goto vio_reg_failed; | ||
2387 | } | ||
2388 | |||
2389 | return 0; | ||
2390 | |||
2391 | vio_reg_failed: | ||
2392 | misc_deregister(&ibmvmc_miscdev); | ||
2393 | misc_register_failed: | ||
2394 | return rc; | ||
2395 | } | ||
2396 | |||
2397 | static void __exit ibmvmc_module_exit(void) | ||
2398 | { | ||
2399 | pr_info("ibmvmc: module exit\n"); | ||
2400 | vio_unregister_driver(&ibmvmc_driver); | ||
2401 | misc_deregister(&ibmvmc_miscdev); | ||
2402 | } | ||
2403 | |||
2404 | module_init(ibmvmc_module_init); | ||
2405 | module_exit(ibmvmc_module_exit); | ||
2406 | |||
2407 | module_param_named(buf_pool_size, ibmvmc_max_buf_pool_size, | ||
2408 | int, 0644); | ||
2409 | MODULE_PARM_DESC(buf_pool_size, "Buffer pool size"); | ||
2410 | module_param_named(max_hmcs, ibmvmc_max_hmcs, int, 0644); | ||
2411 | MODULE_PARM_DESC(max_hmcs, "Max HMCs"); | ||
2412 | module_param_named(max_mtu, ibmvmc_max_mtu, int, 0644); | ||
2413 | MODULE_PARM_DESC(max_mtu, "Max MTU"); | ||
2414 | |||
2415 | MODULE_AUTHOR("Steven Royer <seroyer@linux.vnet.ibm.com>"); | ||
2416 | MODULE_DESCRIPTION("IBM VMC"); | ||
2417 | MODULE_VERSION(IBMVMC_DRIVER_VERSION); | ||
2418 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/misc/ibmvmc.h b/drivers/misc/ibmvmc.h new file mode 100644 index 000000000000..e140ada8fe2c --- /dev/null +++ b/drivers/misc/ibmvmc.h | |||
@@ -0,0 +1,209 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0+ | ||
2 | * | ||
3 | * linux/drivers/misc/ibmvmc.h | ||
4 | * | ||
5 | * IBM Power Systems Virtual Management Channel Support. | ||
6 | * | ||
7 | * Copyright (c) 2004, 2018 IBM Corp. | ||
8 | * Dave Engebretsen engebret@us.ibm.com | ||
9 | * Steven Royer seroyer@linux.vnet.ibm.com | ||
10 | * Adam Reznechek adreznec@linux.vnet.ibm.com | ||
11 | * Bryant G. Ly <bryantly@linux.vnet.ibm.com> | ||
12 | */ | ||
13 | #ifndef IBMVMC_H | ||
14 | #define IBMVMC_H | ||
15 | |||
16 | #include <linux/types.h> | ||
17 | #include <linux/cdev.h> | ||
18 | |||
19 | #include <asm/vio.h> | ||
20 | |||
21 | #define IBMVMC_PROTOCOL_VERSION 0x0101 | ||
22 | |||
23 | #define MIN_BUF_POOL_SIZE 16 | ||
24 | #define MIN_HMCS 1 | ||
25 | #define MIN_MTU 4096 | ||
26 | #define MAX_BUF_POOL_SIZE 64 | ||
27 | #define MAX_HMCS 2 | ||
28 | #define MAX_MTU (4 * 4096) | ||
29 | #define DEFAULT_BUF_POOL_SIZE 32 | ||
30 | #define DEFAULT_HMCS 1 | ||
31 | #define DEFAULT_MTU 4096 | ||
32 | #define HMC_ID_LEN 32 | ||
33 | |||
34 | #define VMC_INVALID_BUFFER_ID 0xFFFF | ||
35 | |||
36 | /* ioctl numbers */ | ||
37 | #define VMC_BASE 0xCC | ||
38 | #define VMC_IOCTL_SETHMCID _IOW(VMC_BASE, 0x00, unsigned char *) | ||
39 | #define VMC_IOCTL_QUERY _IOR(VMC_BASE, 0x01, struct ibmvmc_query_struct) | ||
40 | #define VMC_IOCTL_REQUESTVMC _IOR(VMC_BASE, 0x02, u32) | ||
41 | |||
42 | #define VMC_MSG_CAP 0x01 | ||
43 | #define VMC_MSG_CAP_RESP 0x81 | ||
44 | #define VMC_MSG_OPEN 0x02 | ||
45 | #define VMC_MSG_OPEN_RESP 0x82 | ||
46 | #define VMC_MSG_CLOSE 0x03 | ||
47 | #define VMC_MSG_CLOSE_RESP 0x83 | ||
48 | #define VMC_MSG_ADD_BUF 0x04 | ||
49 | #define VMC_MSG_ADD_BUF_RESP 0x84 | ||
50 | #define VMC_MSG_REM_BUF 0x05 | ||
51 | #define VMC_MSG_REM_BUF_RESP 0x85 | ||
52 | #define VMC_MSG_SIGNAL 0x06 | ||
53 | |||
54 | #define VMC_MSG_SUCCESS 0 | ||
55 | #define VMC_MSG_INVALID_HMC_INDEX 1 | ||
56 | #define VMC_MSG_INVALID_BUFFER_ID 2 | ||
57 | #define VMC_MSG_CLOSED_HMC 3 | ||
58 | #define VMC_MSG_INTERFACE_FAILURE 4 | ||
59 | #define VMC_MSG_NO_BUFFER 5 | ||
60 | |||
61 | #define VMC_BUF_OWNER_ALPHA 0 | ||
62 | #define VMC_BUF_OWNER_HV 1 | ||
63 | |||
64 | enum ibmvmc_states { | ||
65 | ibmvmc_state_sched_reset = -1, | ||
66 | ibmvmc_state_initial = 0, | ||
67 | ibmvmc_state_crqinit = 1, | ||
68 | ibmvmc_state_capabilities = 2, | ||
69 | ibmvmc_state_ready = 3, | ||
70 | ibmvmc_state_failed = 4, | ||
71 | }; | ||
72 | |||
73 | enum ibmhmc_states { | ||
74 | /* HMC connection not established */ | ||
75 | ibmhmc_state_free = 0, | ||
76 | |||
77 | /* HMC connection established (open called) */ | ||
78 | ibmhmc_state_initial = 1, | ||
79 | |||
80 | /* open msg sent to HV, due to ioctl(1) call */ | ||
81 | ibmhmc_state_opening = 2, | ||
82 | |||
83 | /* HMC connection ready, open resp msg from HV */ | ||
84 | ibmhmc_state_ready = 3, | ||
85 | |||
86 | /* HMC connection failure */ | ||
87 | ibmhmc_state_failed = 4, | ||
88 | }; | ||
89 | |||
90 | struct ibmvmc_buffer { | ||
91 | u8 valid; /* 1 when DMA storage allocated to buffer */ | ||
92 | u8 free; /* 1 when buffer available for the Alpha Partition */ | ||
93 | u8 owner; | ||
94 | u16 id; | ||
95 | u32 size; | ||
96 | u32 msg_len; | ||
97 | dma_addr_t dma_addr_local; | ||
98 | dma_addr_t dma_addr_remote; | ||
99 | void *real_addr_local; | ||
100 | }; | ||
101 | |||
102 | struct ibmvmc_admin_crq_msg { | ||
103 | u8 valid; /* RPA Defined */ | ||
104 | u8 type; /* ibmvmc msg type */ | ||
105 | u8 status; /* Response msg status. Zero is success and on failure, | ||
106 | * either 1 - General Failure, or 2 - Invalid Version is | ||
107 | * returned. | ||
108 | */ | ||
109 | u8 rsvd[2]; | ||
110 | u8 max_hmc; /* Max # of independent HMC connections supported */ | ||
111 | __be16 pool_size; /* Maximum number of buffers supported per HMC | ||
112 | * connection | ||
113 | */ | ||
114 | __be32 max_mtu; /* Maximum message size supported (bytes) */ | ||
115 | __be16 crq_size; /* # of entries available in the CRQ for the | ||
116 | * source partition. The target partition must | ||
117 | * limit the number of outstanding messages to | ||
118 | * one half or less. | ||
119 | */ | ||
120 | __be16 version; /* Indicates the code level of the management partition | ||
121 | * or the hypervisor with the high-order byte | ||
122 | * indicating a major version and the low-order byte | ||
123 | * indicating a minor version. | ||
124 | */ | ||
125 | }; | ||
126 | |||
127 | struct ibmvmc_crq_msg { | ||
128 | u8 valid; /* RPA Defined */ | ||
129 | u8 type; /* ibmvmc msg type */ | ||
130 | u8 status; /* Response msg status */ | ||
131 | union { | ||
132 | u8 rsvd; /* Reserved */ | ||
133 | u8 owner; | ||
134 | } var1; | ||
135 | u8 hmc_session; /* Session Identifier for the current VMC connection */ | ||
136 | u8 hmc_index; /* A unique HMC Idx would be used if multiple management | ||
137 | * applications running concurrently were desired | ||
138 | */ | ||
139 | union { | ||
140 | __be16 rsvd; | ||
141 | __be16 buffer_id; | ||
142 | } var2; | ||
143 | __be32 rsvd; | ||
144 | union { | ||
145 | __be32 rsvd; | ||
146 | __be32 lioba; | ||
147 | __be32 msg_len; | ||
148 | } var3; | ||
149 | }; | ||
150 | |||
151 | /* an RPA command/response transport queue */ | ||
152 | struct crq_queue { | ||
153 | struct ibmvmc_crq_msg *msgs; | ||
154 | int size, cur; | ||
155 | dma_addr_t msg_token; | ||
156 | spinlock_t lock; | ||
157 | }; | ||
158 | |||
159 | /* VMC server adapter settings */ | ||
160 | struct crq_server_adapter { | ||
161 | struct device *dev; | ||
162 | struct crq_queue queue; | ||
163 | u32 liobn; | ||
164 | u32 riobn; | ||
165 | struct tasklet_struct work_task; | ||
166 | wait_queue_head_t reset_wait_queue; | ||
167 | struct task_struct *reset_task; | ||
168 | }; | ||
169 | |||
170 | /* Driver wide settings */ | ||
171 | struct ibmvmc_struct { | ||
172 | u32 state; | ||
173 | u32 max_mtu; | ||
174 | u32 max_buffer_pool_size; | ||
175 | u32 max_hmc_index; | ||
176 | struct crq_server_adapter *adapter; | ||
177 | struct cdev cdev; | ||
178 | u32 vmc_drc_index; | ||
179 | }; | ||
180 | |||
181 | struct ibmvmc_file_session; | ||
182 | |||
183 | /* Connection specific settings */ | ||
184 | struct ibmvmc_hmc { | ||
185 | u8 session; | ||
186 | u8 index; | ||
187 | u32 state; | ||
188 | struct crq_server_adapter *adapter; | ||
189 | spinlock_t lock; | ||
190 | unsigned char hmc_id[HMC_ID_LEN]; | ||
191 | struct ibmvmc_buffer buffer[MAX_BUF_POOL_SIZE]; | ||
192 | unsigned short queue_outbound_msgs[MAX_BUF_POOL_SIZE]; | ||
193 | int queue_head, queue_tail; | ||
194 | struct ibmvmc_file_session *file_session; | ||
195 | }; | ||
196 | |||
197 | struct ibmvmc_file_session { | ||
198 | struct file *file; | ||
199 | struct ibmvmc_hmc *hmc; | ||
200 | bool valid; | ||
201 | }; | ||
202 | |||
203 | struct ibmvmc_query_struct { | ||
204 | int have_vmc; | ||
205 | int state; | ||
206 | int vmc_drc_index; | ||
207 | }; | ||
208 | |||
209 | #endif /* __IBMVMC_H */ | ||
diff --git a/drivers/misc/sgi-gru/grumain.c b/drivers/misc/sgi-gru/grumain.c index 3641f1334cf0..ab174f28e3be 100644 --- a/drivers/misc/sgi-gru/grumain.c +++ b/drivers/misc/sgi-gru/grumain.c | |||
@@ -926,7 +926,7 @@ again: | |||
926 | * | 926 | * |
927 | * Note: gru segments alway mmaped on GRU_GSEG_PAGESIZE boundaries. | 927 | * Note: gru segments alway mmaped on GRU_GSEG_PAGESIZE boundaries. |
928 | */ | 928 | */ |
929 | int gru_fault(struct vm_fault *vmf) | 929 | vm_fault_t gru_fault(struct vm_fault *vmf) |
930 | { | 930 | { |
931 | struct vm_area_struct *vma = vmf->vma; | 931 | struct vm_area_struct *vma = vmf->vma; |
932 | struct gru_thread_state *gts; | 932 | struct gru_thread_state *gts; |
diff --git a/drivers/misc/sgi-gru/grutables.h b/drivers/misc/sgi-gru/grutables.h index b5e308b50ed1..3e041b6f7a68 100644 --- a/drivers/misc/sgi-gru/grutables.h +++ b/drivers/misc/sgi-gru/grutables.h | |||
@@ -147,6 +147,7 @@ | |||
147 | #include <linux/mutex.h> | 147 | #include <linux/mutex.h> |
148 | #include <linux/wait.h> | 148 | #include <linux/wait.h> |
149 | #include <linux/mmu_notifier.h> | 149 | #include <linux/mmu_notifier.h> |
150 | #include <linux/mm_types.h> | ||
150 | #include "gru.h" | 151 | #include "gru.h" |
151 | #include "grulib.h" | 152 | #include "grulib.h" |
152 | #include "gruhandles.h" | 153 | #include "gruhandles.h" |
@@ -665,7 +666,7 @@ extern unsigned long gru_reserve_cb_resources(struct gru_state *gru, | |||
665 | int cbr_au_count, char *cbmap); | 666 | int cbr_au_count, char *cbmap); |
666 | extern unsigned long gru_reserve_ds_resources(struct gru_state *gru, | 667 | extern unsigned long gru_reserve_ds_resources(struct gru_state *gru, |
667 | int dsr_au_count, char *dsmap); | 668 | int dsr_au_count, char *dsmap); |
668 | extern int gru_fault(struct vm_fault *vmf); | 669 | extern vm_fault_t gru_fault(struct vm_fault *vmf); |
669 | extern struct gru_mm_struct *gru_register_mmu_notifier(void); | 670 | extern struct gru_mm_struct *gru_register_mmu_notifier(void); |
670 | extern void gru_drop_mmu_notifier(struct gru_mm_struct *gms); | 671 | extern void gru_drop_mmu_notifier(struct gru_mm_struct *gms); |
671 | 672 | ||
diff --git a/drivers/misc/sgi-xp/xpnet.c b/drivers/misc/sgi-xp/xpnet.c index 0c26eaf5f62b..216d5c756236 100644 --- a/drivers/misc/sgi-xp/xpnet.c +++ b/drivers/misc/sgi-xp/xpnet.c | |||
@@ -407,7 +407,7 @@ xpnet_send(struct sk_buff *skb, struct xpnet_pending_msg *queued_msg, | |||
407 | * destination partid. If the destination partid octets are 0xffff, | 407 | * destination partid. If the destination partid octets are 0xffff, |
408 | * this packet is to be broadcast to all connected partitions. | 408 | * this packet is to be broadcast to all connected partitions. |
409 | */ | 409 | */ |
410 | static int | 410 | static netdev_tx_t |
411 | xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | 411 | xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) |
412 | { | 412 | { |
413 | struct xpnet_pending_msg *queued_msg; | 413 | struct xpnet_pending_msg *queued_msg; |
diff --git a/drivers/misc/ti-st/st_kim.c b/drivers/misc/ti-st/st_kim.c index b77aacafc3fc..5ec3f5a43718 100644 --- a/drivers/misc/ti-st/st_kim.c +++ b/drivers/misc/ti-st/st_kim.c | |||
@@ -735,7 +735,7 @@ static int kim_probe(struct platform_device *pdev) | |||
735 | st_kim_devices[0] = pdev; | 735 | st_kim_devices[0] = pdev; |
736 | } | 736 | } |
737 | 737 | ||
738 | kim_gdata = kzalloc(sizeof(struct kim_data_s), GFP_ATOMIC); | 738 | kim_gdata = kzalloc(sizeof(struct kim_data_s), GFP_KERNEL); |
739 | if (!kim_gdata) { | 739 | if (!kim_gdata) { |
740 | pr_err("no mem to allocate"); | 740 | pr_err("no mem to allocate"); |
741 | return -ENOMEM; | 741 | return -ENOMEM; |
diff --git a/drivers/misc/tifm_7xx1.c b/drivers/misc/tifm_7xx1.c index e5f108713dd8..9ac95b48ef92 100644 --- a/drivers/misc/tifm_7xx1.c +++ b/drivers/misc/tifm_7xx1.c | |||
@@ -239,9 +239,13 @@ static int tifm_7xx1_resume(struct pci_dev *dev) | |||
239 | unsigned long timeout; | 239 | unsigned long timeout; |
240 | unsigned int good_sockets = 0, bad_sockets = 0; | 240 | unsigned int good_sockets = 0, bad_sockets = 0; |
241 | unsigned long flags; | 241 | unsigned long flags; |
242 | unsigned char new_ids[fm->num_sockets]; | 242 | /* Maximum number of entries is 4 */ |
243 | unsigned char new_ids[4]; | ||
243 | DECLARE_COMPLETION_ONSTACK(finish_resume); | 244 | DECLARE_COMPLETION_ONSTACK(finish_resume); |
244 | 245 | ||
246 | if (WARN_ON(fm->num_sockets > ARRAY_SIZE(new_ids))) | ||
247 | return -ENXIO; | ||
248 | |||
245 | pci_set_power_state(dev, PCI_D0); | 249 | pci_set_power_state(dev, PCI_D0); |
246 | pci_restore_state(dev); | 250 | pci_restore_state(dev); |
247 | rc = pci_enable_device(dev); | 251 | rc = pci_enable_device(dev); |
diff --git a/drivers/misc/vmw_balloon.c b/drivers/misc/vmw_balloon.c index 9047c0a529b2..efd733472a35 100644 --- a/drivers/misc/vmw_balloon.c +++ b/drivers/misc/vmw_balloon.c | |||
@@ -576,15 +576,9 @@ static void vmballoon_pop(struct vmballoon *b) | |||
576 | } | 576 | } |
577 | } | 577 | } |
578 | 578 | ||
579 | if (b->batch_page) { | 579 | /* Clearing the batch_page unconditionally has no adverse effect */ |
580 | vunmap(b->batch_page); | 580 | free_page((unsigned long)b->batch_page); |
581 | b->batch_page = NULL; | 581 | b->batch_page = NULL; |
582 | } | ||
583 | |||
584 | if (b->page) { | ||
585 | __free_page(b->page); | ||
586 | b->page = NULL; | ||
587 | } | ||
588 | } | 582 | } |
589 | 583 | ||
590 | /* | 584 | /* |
@@ -991,16 +985,13 @@ static const struct vmballoon_ops vmballoon_batched_ops = { | |||
991 | 985 | ||
992 | static bool vmballoon_init_batching(struct vmballoon *b) | 986 | static bool vmballoon_init_batching(struct vmballoon *b) |
993 | { | 987 | { |
994 | b->page = alloc_page(VMW_PAGE_ALLOC_NOSLEEP); | 988 | struct page *page; |
995 | if (!b->page) | ||
996 | return false; | ||
997 | 989 | ||
998 | b->batch_page = vmap(&b->page, 1, VM_MAP, PAGE_KERNEL); | 990 | page = alloc_page(GFP_KERNEL | __GFP_ZERO); |
999 | if (!b->batch_page) { | 991 | if (!page) |
1000 | __free_page(b->page); | ||
1001 | return false; | 992 | return false; |
1002 | } | ||
1003 | 993 | ||
994 | b->batch_page = page_address(page); | ||
1004 | return true; | 995 | return true; |
1005 | } | 996 | } |
1006 | 997 | ||
diff --git a/drivers/mux/adg792a.c b/drivers/mux/adg792a.c index 6a8725cf3d71..e8fc2fc1ab09 100644 --- a/drivers/mux/adg792a.c +++ b/drivers/mux/adg792a.c | |||
@@ -58,8 +58,7 @@ static const struct mux_control_ops adg792a_ops = { | |||
58 | .set = adg792a_set, | 58 | .set = adg792a_set, |
59 | }; | 59 | }; |
60 | 60 | ||
61 | static int adg792a_probe(struct i2c_client *i2c, | 61 | static int adg792a_probe(struct i2c_client *i2c) |
62 | const struct i2c_device_id *id) | ||
63 | { | 62 | { |
64 | struct device *dev = &i2c->dev; | 63 | struct device *dev = &i2c->dev; |
65 | struct mux_chip *mux_chip; | 64 | struct mux_chip *mux_chip; |
@@ -144,7 +143,7 @@ static struct i2c_driver adg792a_driver = { | |||
144 | .name = "adg792a", | 143 | .name = "adg792a", |
145 | .of_match_table = of_match_ptr(adg792a_of_match), | 144 | .of_match_table = of_match_ptr(adg792a_of_match), |
146 | }, | 145 | }, |
147 | .probe = adg792a_probe, | 146 | .probe_new = adg792a_probe, |
148 | .id_table = adg792a_id, | 147 | .id_table = adg792a_id, |
149 | }; | 148 | }; |
150 | module_i2c_driver(adg792a_driver); | 149 | module_i2c_driver(adg792a_driver); |
diff --git a/drivers/nubus/bus.c b/drivers/nubus/bus.c index d306c348c857..a59b6c4bb5b8 100644 --- a/drivers/nubus/bus.c +++ b/drivers/nubus/bus.c | |||
@@ -63,20 +63,15 @@ static struct device nubus_parent = { | |||
63 | .init_name = "nubus", | 63 | .init_name = "nubus", |
64 | }; | 64 | }; |
65 | 65 | ||
66 | int __init nubus_bus_register(void) | 66 | static int __init nubus_bus_register(void) |
67 | { | 67 | { |
68 | int err; | 68 | return bus_register(&nubus_bus_type); |
69 | 69 | } | |
70 | err = device_register(&nubus_parent); | 70 | postcore_initcall(nubus_bus_register); |
71 | if (err) | ||
72 | return err; | ||
73 | |||
74 | err = bus_register(&nubus_bus_type); | ||
75 | if (!err) | ||
76 | return 0; | ||
77 | 71 | ||
78 | device_unregister(&nubus_parent); | 72 | int __init nubus_parent_device_register(void) |
79 | return err; | 73 | { |
74 | return device_register(&nubus_parent); | ||
80 | } | 75 | } |
81 | 76 | ||
82 | static void nubus_device_release(struct device *dev) | 77 | static void nubus_device_release(struct device *dev) |
diff --git a/drivers/nubus/nubus.c b/drivers/nubus/nubus.c index 4621ff98138c..bb0d63a44f41 100644 --- a/drivers/nubus/nubus.c +++ b/drivers/nubus/nubus.c | |||
@@ -875,7 +875,7 @@ static int __init nubus_init(void) | |||
875 | return 0; | 875 | return 0; |
876 | 876 | ||
877 | nubus_proc_init(); | 877 | nubus_proc_init(); |
878 | err = nubus_bus_register(); | 878 | err = nubus_parent_device_register(); |
879 | if (err) | 879 | if (err) |
880 | return err; | 880 | return err; |
881 | nubus_scan_bus(); | 881 | nubus_scan_bus(); |
diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig index 1090924efdb1..54a3c298247b 100644 --- a/drivers/nvmem/Kconfig +++ b/drivers/nvmem/Kconfig | |||
@@ -175,4 +175,10 @@ config NVMEM_SNVS_LPGPR | |||
175 | This driver can also be built as a module. If so, the module | 175 | This driver can also be built as a module. If so, the module |
176 | will be called nvmem-snvs-lpgpr. | 176 | will be called nvmem-snvs-lpgpr. |
177 | 177 | ||
178 | config RAVE_SP_EEPROM | ||
179 | tristate "Rave SP EEPROM Support" | ||
180 | depends on RAVE_SP_CORE | ||
181 | help | ||
182 | Say y here to enable Rave SP EEPROM support. | ||
183 | |||
178 | endif | 184 | endif |
diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile index e54dcfa6565a..27e96a8efd1c 100644 --- a/drivers/nvmem/Makefile +++ b/drivers/nvmem/Makefile | |||
@@ -37,3 +37,6 @@ obj-$(CONFIG_MESON_MX_EFUSE) += nvmem_meson_mx_efuse.o | |||
37 | nvmem_meson_mx_efuse-y := meson-mx-efuse.o | 37 | nvmem_meson_mx_efuse-y := meson-mx-efuse.o |
38 | obj-$(CONFIG_NVMEM_SNVS_LPGPR) += nvmem_snvs_lpgpr.o | 38 | obj-$(CONFIG_NVMEM_SNVS_LPGPR) += nvmem_snvs_lpgpr.o |
39 | nvmem_snvs_lpgpr-y := snvs_lpgpr.o | 39 | nvmem_snvs_lpgpr-y := snvs_lpgpr.o |
40 | obj-$(CONFIG_RAVE_SP_EEPROM) += nvmem-rave-sp-eeprom.o | ||
41 | nvmem-rave-sp-eeprom-y := rave-sp-eeprom.o | ||
42 | |||
diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index b05aa8e81303..b5b0cdc21d01 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c | |||
@@ -353,18 +353,27 @@ static int nvmem_cell_info_to_nvmem_cell(struct nvmem_device *nvmem, | |||
353 | return 0; | 353 | return 0; |
354 | } | 354 | } |
355 | 355 | ||
356 | static int nvmem_add_cells(struct nvmem_device *nvmem, | 356 | /** |
357 | const struct nvmem_config *cfg) | 357 | * nvmem_add_cells() - Add cell information to an nvmem device |
358 | * | ||
359 | * @nvmem: nvmem device to add cells to. | ||
360 | * @info: nvmem cell info to add to the device | ||
361 | * @ncells: number of cells in info | ||
362 | * | ||
363 | * Return: 0 or negative error code on failure. | ||
364 | */ | ||
365 | int nvmem_add_cells(struct nvmem_device *nvmem, | ||
366 | const struct nvmem_cell_info *info, | ||
367 | int ncells) | ||
358 | { | 368 | { |
359 | struct nvmem_cell **cells; | 369 | struct nvmem_cell **cells; |
360 | const struct nvmem_cell_info *info = cfg->cells; | ||
361 | int i, rval; | 370 | int i, rval; |
362 | 371 | ||
363 | cells = kcalloc(cfg->ncells, sizeof(*cells), GFP_KERNEL); | 372 | cells = kcalloc(ncells, sizeof(*cells), GFP_KERNEL); |
364 | if (!cells) | 373 | if (!cells) |
365 | return -ENOMEM; | 374 | return -ENOMEM; |
366 | 375 | ||
367 | for (i = 0; i < cfg->ncells; i++) { | 376 | for (i = 0; i < ncells; i++) { |
368 | cells[i] = kzalloc(sizeof(**cells), GFP_KERNEL); | 377 | cells[i] = kzalloc(sizeof(**cells), GFP_KERNEL); |
369 | if (!cells[i]) { | 378 | if (!cells[i]) { |
370 | rval = -ENOMEM; | 379 | rval = -ENOMEM; |
@@ -380,7 +389,7 @@ static int nvmem_add_cells(struct nvmem_device *nvmem, | |||
380 | nvmem_cell_add(cells[i]); | 389 | nvmem_cell_add(cells[i]); |
381 | } | 390 | } |
382 | 391 | ||
383 | nvmem->ncells = cfg->ncells; | 392 | nvmem->ncells = ncells; |
384 | /* remove tmp array */ | 393 | /* remove tmp array */ |
385 | kfree(cells); | 394 | kfree(cells); |
386 | 395 | ||
@@ -393,6 +402,7 @@ err: | |||
393 | 402 | ||
394 | return rval; | 403 | return rval; |
395 | } | 404 | } |
405 | EXPORT_SYMBOL_GPL(nvmem_add_cells); | ||
396 | 406 | ||
397 | /* | 407 | /* |
398 | * nvmem_setup_compat() - Create an additional binary entry in | 408 | * nvmem_setup_compat() - Create an additional binary entry in |
@@ -509,7 +519,7 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config) | |||
509 | } | 519 | } |
510 | 520 | ||
511 | if (config->cells) | 521 | if (config->cells) |
512 | nvmem_add_cells(nvmem, config); | 522 | nvmem_add_cells(nvmem, config->cells, config->ncells); |
513 | 523 | ||
514 | return nvmem; | 524 | return nvmem; |
515 | 525 | ||
@@ -559,6 +569,7 @@ static void devm_nvmem_release(struct device *dev, void *res) | |||
559 | * nvmem_config. | 569 | * nvmem_config. |
560 | * Also creates an binary entry in /sys/bus/nvmem/devices/dev-name/nvmem | 570 | * Also creates an binary entry in /sys/bus/nvmem/devices/dev-name/nvmem |
561 | * | 571 | * |
572 | * @dev: Device that uses the nvmem device. | ||
562 | * @config: nvmem device configuration with which nvmem device is created. | 573 | * @config: nvmem device configuration with which nvmem device is created. |
563 | * | 574 | * |
564 | * Return: Will be an ERR_PTR() on error or a valid pointer to nvmem_device | 575 | * Return: Will be an ERR_PTR() on error or a valid pointer to nvmem_device |
@@ -597,6 +608,7 @@ static int devm_nvmem_match(struct device *dev, void *res, void *data) | |||
597 | * devm_nvmem_unregister() - Unregister previously registered managed nvmem | 608 | * devm_nvmem_unregister() - Unregister previously registered managed nvmem |
598 | * device. | 609 | * device. |
599 | * | 610 | * |
611 | * @dev: Device that uses the nvmem device. | ||
600 | * @nvmem: Pointer to previously registered nvmem device. | 612 | * @nvmem: Pointer to previously registered nvmem device. |
601 | * | 613 | * |
602 | * Return: Will be an negative on error or a zero on success. | 614 | * Return: Will be an negative on error or a zero on success. |
@@ -1107,6 +1119,8 @@ static void *nvmem_cell_prepare_write_buffer(struct nvmem_cell *cell, | |||
1107 | 1119 | ||
1108 | /* setup the first byte with lsb bits from nvmem */ | 1120 | /* setup the first byte with lsb bits from nvmem */ |
1109 | rc = nvmem_reg_read(nvmem, cell->offset, &v, 1); | 1121 | rc = nvmem_reg_read(nvmem, cell->offset, &v, 1); |
1122 | if (rc) | ||
1123 | goto err; | ||
1110 | *b++ |= GENMASK(bit_offset - 1, 0) & v; | 1124 | *b++ |= GENMASK(bit_offset - 1, 0) & v; |
1111 | 1125 | ||
1112 | /* setup rest of the byte if any */ | 1126 | /* setup rest of the byte if any */ |
@@ -1125,11 +1139,16 @@ static void *nvmem_cell_prepare_write_buffer(struct nvmem_cell *cell, | |||
1125 | /* setup the last byte with msb bits from nvmem */ | 1139 | /* setup the last byte with msb bits from nvmem */ |
1126 | rc = nvmem_reg_read(nvmem, | 1140 | rc = nvmem_reg_read(nvmem, |
1127 | cell->offset + cell->bytes - 1, &v, 1); | 1141 | cell->offset + cell->bytes - 1, &v, 1); |
1142 | if (rc) | ||
1143 | goto err; | ||
1128 | *p |= GENMASK(7, (nbits + bit_offset) % BITS_PER_BYTE) & v; | 1144 | *p |= GENMASK(7, (nbits + bit_offset) % BITS_PER_BYTE) & v; |
1129 | 1145 | ||
1130 | } | 1146 | } |
1131 | 1147 | ||
1132 | return buf; | 1148 | return buf; |
1149 | err: | ||
1150 | kfree(buf); | ||
1151 | return ERR_PTR(rc); | ||
1133 | } | 1152 | } |
1134 | 1153 | ||
1135 | /** | 1154 | /** |
diff --git a/drivers/nvmem/meson-efuse.c b/drivers/nvmem/meson-efuse.c index 71823d1403c5..d769840d1e18 100644 --- a/drivers/nvmem/meson-efuse.c +++ b/drivers/nvmem/meson-efuse.c | |||
@@ -24,23 +24,16 @@ | |||
24 | static int meson_efuse_read(void *context, unsigned int offset, | 24 | static int meson_efuse_read(void *context, unsigned int offset, |
25 | void *val, size_t bytes) | 25 | void *val, size_t bytes) |
26 | { | 26 | { |
27 | u8 *buf = val; | 27 | return meson_sm_call_read((u8 *)val, bytes, SM_EFUSE_READ, offset, |
28 | int ret; | 28 | bytes, 0, 0, 0); |
29 | |||
30 | ret = meson_sm_call_read(buf, bytes, SM_EFUSE_READ, offset, | ||
31 | bytes, 0, 0, 0); | ||
32 | if (ret < 0) | ||
33 | return ret; | ||
34 | |||
35 | return 0; | ||
36 | } | 29 | } |
37 | 30 | ||
38 | static struct nvmem_config econfig = { | 31 | static int meson_efuse_write(void *context, unsigned int offset, |
39 | .name = "meson-efuse", | 32 | void *val, size_t bytes) |
40 | .stride = 1, | 33 | { |
41 | .word_size = 1, | 34 | return meson_sm_call_write((u8 *)val, bytes, SM_EFUSE_WRITE, offset, |
42 | .read_only = true, | 35 | bytes, 0, 0, 0); |
43 | }; | 36 | } |
44 | 37 | ||
45 | static const struct of_device_id meson_efuse_match[] = { | 38 | static const struct of_device_id meson_efuse_match[] = { |
46 | { .compatible = "amlogic,meson-gxbb-efuse", }, | 39 | { .compatible = "amlogic,meson-gxbb-efuse", }, |
@@ -50,17 +43,27 @@ MODULE_DEVICE_TABLE(of, meson_efuse_match); | |||
50 | 43 | ||
51 | static int meson_efuse_probe(struct platform_device *pdev) | 44 | static int meson_efuse_probe(struct platform_device *pdev) |
52 | { | 45 | { |
46 | struct device *dev = &pdev->dev; | ||
53 | struct nvmem_device *nvmem; | 47 | struct nvmem_device *nvmem; |
48 | struct nvmem_config *econfig; | ||
54 | unsigned int size; | 49 | unsigned int size; |
55 | 50 | ||
56 | if (meson_sm_call(SM_EFUSE_USER_MAX, &size, 0, 0, 0, 0, 0) < 0) | 51 | if (meson_sm_call(SM_EFUSE_USER_MAX, &size, 0, 0, 0, 0, 0) < 0) |
57 | return -EINVAL; | 52 | return -EINVAL; |
58 | 53 | ||
59 | econfig.dev = &pdev->dev; | 54 | econfig = devm_kzalloc(dev, sizeof(*econfig), GFP_KERNEL); |
60 | econfig.reg_read = meson_efuse_read; | 55 | if (!econfig) |
61 | econfig.size = size; | 56 | return -ENOMEM; |
57 | |||
58 | econfig->dev = dev; | ||
59 | econfig->name = dev_name(dev); | ||
60 | econfig->stride = 1; | ||
61 | econfig->word_size = 1; | ||
62 | econfig->reg_read = meson_efuse_read; | ||
63 | econfig->reg_write = meson_efuse_write; | ||
64 | econfig->size = size; | ||
62 | 65 | ||
63 | nvmem = devm_nvmem_register(&pdev->dev, &econfig); | 66 | nvmem = devm_nvmem_register(&pdev->dev, econfig); |
64 | 67 | ||
65 | return PTR_ERR_OR_ZERO(nvmem); | 68 | return PTR_ERR_OR_ZERO(nvmem); |
66 | } | 69 | } |
diff --git a/drivers/nvmem/rave-sp-eeprom.c b/drivers/nvmem/rave-sp-eeprom.c new file mode 100644 index 000000000000..50aeea6ec6cc --- /dev/null +++ b/drivers/nvmem/rave-sp-eeprom.c | |||
@@ -0,0 +1,357 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0+ | ||
2 | |||
3 | /* | ||
4 | * EEPROM driver for RAVE SP | ||
5 | * | ||
6 | * Copyright (C) 2018 Zodiac Inflight Innovations | ||
7 | * | ||
8 | */ | ||
9 | #include <linux/kernel.h> | ||
10 | #include <linux/mfd/rave-sp.h> | ||
11 | #include <linux/module.h> | ||
12 | #include <linux/nvmem-provider.h> | ||
13 | #include <linux/of_device.h> | ||
14 | #include <linux/platform_device.h> | ||
15 | #include <linux/sizes.h> | ||
16 | |||
17 | /** | ||
18 | * enum rave_sp_eeprom_access_type - Supported types of EEPROM access | ||
19 | * | ||
20 | * @RAVE_SP_EEPROM_WRITE: EEPROM write | ||
21 | * @RAVE_SP_EEPROM_READ: EEPROM read | ||
22 | */ | ||
23 | enum rave_sp_eeprom_access_type { | ||
24 | RAVE_SP_EEPROM_WRITE = 0, | ||
25 | RAVE_SP_EEPROM_READ = 1, | ||
26 | }; | ||
27 | |||
28 | /** | ||
29 | * enum rave_sp_eeprom_header_size - EEPROM command header sizes | ||
30 | * | ||
31 | * @RAVE_SP_EEPROM_HEADER_SMALL: EEPROM header size for "small" devices (< 8K) | ||
32 | * @RAVE_SP_EEPROM_HEADER_BIG: EEPROM header size for "big" devices (> 8K) | ||
33 | */ | ||
34 | enum rave_sp_eeprom_header_size { | ||
35 | RAVE_SP_EEPROM_HEADER_SMALL = 4U, | ||
36 | RAVE_SP_EEPROM_HEADER_BIG = 5U, | ||
37 | }; | ||
38 | |||
39 | #define RAVE_SP_EEPROM_PAGE_SIZE 32U | ||
40 | |||
41 | /** | ||
42 | * struct rave_sp_eeprom_page - RAVE SP EEPROM page | ||
43 | * | ||
44 | * @type: Access type (see enum rave_sp_eeprom_access_type) | ||
45 | * @success: Success flag (Success = 1, Failure = 0) | ||
46 | * @data: Read data | ||
47 | |||
48 | * Note this structure corresponds to RSP_*_EEPROM payload from RAVE | ||
49 | * SP ICD | ||
50 | */ | ||
51 | struct rave_sp_eeprom_page { | ||
52 | u8 type; | ||
53 | u8 success; | ||
54 | u8 data[RAVE_SP_EEPROM_PAGE_SIZE]; | ||
55 | } __packed; | ||
56 | |||
57 | /** | ||
58 | * struct rave_sp_eeprom - RAVE SP EEPROM device | ||
59 | * | ||
60 | * @sp: Pointer to parent RAVE SP device | ||
61 | * @mutex: Lock protecting access to EEPROM | ||
62 | * @address: EEPROM device address | ||
63 | * @header_size: Size of EEPROM command header for this device | ||
64 | * @dev: Pointer to corresponding struct device used for logging | ||
65 | */ | ||
66 | struct rave_sp_eeprom { | ||
67 | struct rave_sp *sp; | ||
68 | struct mutex mutex; | ||
69 | u8 address; | ||
70 | unsigned int header_size; | ||
71 | struct device *dev; | ||
72 | }; | ||
73 | |||
74 | /** | ||
75 | * rave_sp_eeprom_io - Low-level part of EEPROM page access | ||
76 | * | ||
77 | * @eeprom: EEPROM device to write to | ||
78 | * @type: EEPROM access type (read or write) | ||
79 | * @idx: number of the EEPROM page | ||
80 | * @page: Data to write or buffer to store result (via page->data) | ||
81 | * | ||
82 | * This function does all of the low-level work required to perform a | ||
83 | * EEPROM access. This includes formatting correct command payload, | ||
84 | * sending it and checking received results. | ||
85 | * | ||
86 | * Returns zero in case of success or negative error code in | ||
87 | * case of failure. | ||
88 | */ | ||
89 | static int rave_sp_eeprom_io(struct rave_sp_eeprom *eeprom, | ||
90 | enum rave_sp_eeprom_access_type type, | ||
91 | u16 idx, | ||
92 | struct rave_sp_eeprom_page *page) | ||
93 | { | ||
94 | const bool is_write = type == RAVE_SP_EEPROM_WRITE; | ||
95 | const unsigned int data_size = is_write ? sizeof(page->data) : 0; | ||
96 | const unsigned int cmd_size = eeprom->header_size + data_size; | ||
97 | const unsigned int rsp_size = | ||
98 | is_write ? sizeof(*page) - sizeof(page->data) : sizeof(*page); | ||
99 | unsigned int offset = 0; | ||
100 | u8 cmd[cmd_size]; | ||
101 | int ret; | ||
102 | |||
103 | cmd[offset++] = eeprom->address; | ||
104 | cmd[offset++] = 0; | ||
105 | cmd[offset++] = type; | ||
106 | cmd[offset++] = idx; | ||
107 | |||
108 | /* | ||
109 | * If there's still room in this command's header it means we | ||
110 | * are talkin to EEPROM that uses 16-bit page numbers and we | ||
111 | * have to specify index's MSB in payload as well. | ||
112 | */ | ||
113 | if (offset < eeprom->header_size) | ||
114 | cmd[offset++] = idx >> 8; | ||
115 | /* | ||
116 | * Copy our data to write to command buffer first. In case of | ||
117 | * a read data_size should be zero and memcpy would become a | ||
118 | * no-op | ||
119 | */ | ||
120 | memcpy(&cmd[offset], page->data, data_size); | ||
121 | |||
122 | ret = rave_sp_exec(eeprom->sp, cmd, cmd_size, page, rsp_size); | ||
123 | if (ret) | ||
124 | return ret; | ||
125 | |||
126 | if (page->type != type) | ||
127 | return -EPROTO; | ||
128 | |||
129 | if (!page->success) | ||
130 | return -EIO; | ||
131 | |||
132 | return 0; | ||
133 | } | ||
134 | |||
135 | /** | ||
136 | * rave_sp_eeprom_page_access - Access single EEPROM page | ||
137 | * | ||
138 | * @eeprom: EEPROM device to access | ||
139 | * @type: Access type to perform (read or write) | ||
140 | * @offset: Offset within EEPROM to access | ||
141 | * @data: Data buffer | ||
142 | * @data_len: Size of the data buffer | ||
143 | * | ||
144 | * This function performs a generic access to a single page or a | ||
145 | * portion thereof. Requested access MUST NOT cross the EEPROM page | ||
146 | * boundary. | ||
147 | * | ||
148 | * Returns zero in case of success or negative error code in | ||
149 | * case of failure. | ||
150 | */ | ||
151 | static int | ||
152 | rave_sp_eeprom_page_access(struct rave_sp_eeprom *eeprom, | ||
153 | enum rave_sp_eeprom_access_type type, | ||
154 | unsigned int offset, u8 *data, | ||
155 | size_t data_len) | ||
156 | { | ||
157 | const unsigned int page_offset = offset % RAVE_SP_EEPROM_PAGE_SIZE; | ||
158 | const unsigned int page_nr = offset / RAVE_SP_EEPROM_PAGE_SIZE; | ||
159 | struct rave_sp_eeprom_page page; | ||
160 | int ret; | ||
161 | |||
162 | /* | ||
163 | * This function will not work if data access we've been asked | ||
164 | * to do is crossing EEPROM page boundary. Normally this | ||
165 | * should never happen and getting here would indicate a bug | ||
166 | * in the code. | ||
167 | */ | ||
168 | if (WARN_ON(data_len > sizeof(page.data) - page_offset)) | ||
169 | return -EINVAL; | ||
170 | |||
171 | if (type == RAVE_SP_EEPROM_WRITE) { | ||
172 | /* | ||
173 | * If doing a partial write we need to do a read first | ||
174 | * to fill the rest of the page with correct data. | ||
175 | */ | ||
176 | if (data_len < RAVE_SP_EEPROM_PAGE_SIZE) { | ||
177 | ret = rave_sp_eeprom_io(eeprom, RAVE_SP_EEPROM_READ, | ||
178 | page_nr, &page); | ||
179 | if (ret) | ||
180 | return ret; | ||
181 | } | ||
182 | |||
183 | memcpy(&page.data[page_offset], data, data_len); | ||
184 | } | ||
185 | |||
186 | ret = rave_sp_eeprom_io(eeprom, type, page_nr, &page); | ||
187 | if (ret) | ||
188 | return ret; | ||
189 | |||
190 | /* | ||
191 | * Since we receive the result of the read via 'page.data' | ||
192 | * buffer we need to copy that to 'data' | ||
193 | */ | ||
194 | if (type == RAVE_SP_EEPROM_READ) | ||
195 | memcpy(data, &page.data[page_offset], data_len); | ||
196 | |||
197 | return 0; | ||
198 | } | ||
199 | |||
200 | /** | ||
201 | * rave_sp_eeprom_access - Access EEPROM data | ||
202 | * | ||
203 | * @eeprom: EEPROM device to access | ||
204 | * @type: Access type to perform (read or write) | ||
205 | * @offset: Offset within EEPROM to access | ||
206 | * @data: Data buffer | ||
207 | * @data_len: Size of the data buffer | ||
208 | * | ||
209 | * This function performs a generic access (either read or write) at | ||
210 | * arbitrary offset (not necessary page aligned) of arbitrary length | ||
211 | * (is not constrained by EEPROM page size). | ||
212 | * | ||
213 | * Returns zero in case of success or negative error code in case of | ||
214 | * failure. | ||
215 | */ | ||
216 | static int rave_sp_eeprom_access(struct rave_sp_eeprom *eeprom, | ||
217 | enum rave_sp_eeprom_access_type type, | ||
218 | unsigned int offset, u8 *data, | ||
219 | unsigned int data_len) | ||
220 | { | ||
221 | unsigned int residue; | ||
222 | unsigned int chunk; | ||
223 | unsigned int head; | ||
224 | int ret; | ||
225 | |||
226 | mutex_lock(&eeprom->mutex); | ||
227 | |||
228 | head = offset % RAVE_SP_EEPROM_PAGE_SIZE; | ||
229 | residue = data_len; | ||
230 | |||
231 | do { | ||
232 | /* | ||
233 | * First iteration, if we are doing an access that is | ||
234 | * not 32-byte aligned, we need to access only data up | ||
235 | * to a page boundary to avoid corssing it in | ||
236 | * rave_sp_eeprom_page_access() | ||
237 | */ | ||
238 | if (unlikely(head)) { | ||
239 | chunk = RAVE_SP_EEPROM_PAGE_SIZE - head; | ||
240 | /* | ||
241 | * This can only happen once per | ||
242 | * rave_sp_eeprom_access() call, so we set | ||
243 | * head to zero to process all the other | ||
244 | * iterations normally. | ||
245 | */ | ||
246 | head = 0; | ||
247 | } else { | ||
248 | chunk = RAVE_SP_EEPROM_PAGE_SIZE; | ||
249 | } | ||
250 | |||
251 | /* | ||
252 | * We should never read more that 'residue' bytes | ||
253 | */ | ||
254 | chunk = min(chunk, residue); | ||
255 | ret = rave_sp_eeprom_page_access(eeprom, type, offset, | ||
256 | data, chunk); | ||
257 | if (ret) | ||
258 | goto out; | ||
259 | |||
260 | residue -= chunk; | ||
261 | offset += chunk; | ||
262 | data += chunk; | ||
263 | } while (residue); | ||
264 | out: | ||
265 | mutex_unlock(&eeprom->mutex); | ||
266 | return ret; | ||
267 | } | ||
268 | |||
269 | static int rave_sp_eeprom_reg_read(void *eeprom, unsigned int offset, | ||
270 | void *val, size_t bytes) | ||
271 | { | ||
272 | return rave_sp_eeprom_access(eeprom, RAVE_SP_EEPROM_READ, | ||
273 | offset, val, bytes); | ||
274 | } | ||
275 | |||
276 | static int rave_sp_eeprom_reg_write(void *eeprom, unsigned int offset, | ||
277 | void *val, size_t bytes) | ||
278 | { | ||
279 | return rave_sp_eeprom_access(eeprom, RAVE_SP_EEPROM_WRITE, | ||
280 | offset, val, bytes); | ||
281 | } | ||
282 | |||
283 | static int rave_sp_eeprom_probe(struct platform_device *pdev) | ||
284 | { | ||
285 | struct device *dev = &pdev->dev; | ||
286 | struct rave_sp *sp = dev_get_drvdata(dev->parent); | ||
287 | struct device_node *np = dev->of_node; | ||
288 | struct nvmem_config config = { 0 }; | ||
289 | struct rave_sp_eeprom *eeprom; | ||
290 | struct nvmem_device *nvmem; | ||
291 | u32 reg[2], size; | ||
292 | |||
293 | if (of_property_read_u32_array(np, "reg", reg, ARRAY_SIZE(reg))) { | ||
294 | dev_err(dev, "Failed to parse \"reg\" property\n"); | ||
295 | return -EINVAL; | ||
296 | } | ||
297 | |||
298 | size = reg[1]; | ||
299 | /* | ||
300 | * Per ICD, we have no more than 2 bytes to specify EEPROM | ||
301 | * page. | ||
302 | */ | ||
303 | if (size > U16_MAX * RAVE_SP_EEPROM_PAGE_SIZE) { | ||
304 | dev_err(dev, "Specified size is too big\n"); | ||
305 | return -EINVAL; | ||
306 | } | ||
307 | |||
308 | eeprom = devm_kzalloc(dev, sizeof(*eeprom), GFP_KERNEL); | ||
309 | if (!eeprom) | ||
310 | return -ENOMEM; | ||
311 | |||
312 | eeprom->address = reg[0]; | ||
313 | eeprom->sp = sp; | ||
314 | eeprom->dev = dev; | ||
315 | |||
316 | if (size > SZ_8K) | ||
317 | eeprom->header_size = RAVE_SP_EEPROM_HEADER_BIG; | ||
318 | else | ||
319 | eeprom->header_size = RAVE_SP_EEPROM_HEADER_SMALL; | ||
320 | |||
321 | mutex_init(&eeprom->mutex); | ||
322 | |||
323 | config.id = -1; | ||
324 | of_property_read_string(np, "zii,eeprom-name", &config.name); | ||
325 | config.priv = eeprom; | ||
326 | config.dev = dev; | ||
327 | config.size = size; | ||
328 | config.reg_read = rave_sp_eeprom_reg_read; | ||
329 | config.reg_write = rave_sp_eeprom_reg_write; | ||
330 | config.word_size = 1; | ||
331 | config.stride = 1; | ||
332 | |||
333 | nvmem = devm_nvmem_register(dev, &config); | ||
334 | |||
335 | return PTR_ERR_OR_ZERO(nvmem); | ||
336 | } | ||
337 | |||
338 | static const struct of_device_id rave_sp_eeprom_of_match[] = { | ||
339 | { .compatible = "zii,rave-sp-eeprom" }, | ||
340 | {} | ||
341 | }; | ||
342 | MODULE_DEVICE_TABLE(of, rave_sp_eeprom_of_match); | ||
343 | |||
344 | static struct platform_driver rave_sp_eeprom_driver = { | ||
345 | .probe = rave_sp_eeprom_probe, | ||
346 | .driver = { | ||
347 | .name = KBUILD_MODNAME, | ||
348 | .of_match_table = rave_sp_eeprom_of_match, | ||
349 | }, | ||
350 | }; | ||
351 | module_platform_driver(rave_sp_eeprom_driver); | ||
352 | |||
353 | MODULE_LICENSE("GPL"); | ||
354 | MODULE_AUTHOR("Andrey Vostrikov <andrey.vostrikov@cogentembedded.com>"); | ||
355 | MODULE_AUTHOR("Nikita Yushchenko <nikita.yoush@cogentembedded.com>"); | ||
356 | MODULE_AUTHOR("Andrey Smirnov <andrew.smirnov@gmail.com>"); | ||
357 | MODULE_DESCRIPTION("RAVE SP EEPROM driver"); | ||
diff --git a/drivers/slimbus/qcom-ctrl.c b/drivers/slimbus/qcom-ctrl.c index ffb46f915334..bb36a8fbc9b1 100644 --- a/drivers/slimbus/qcom-ctrl.c +++ b/drivers/slimbus/qcom-ctrl.c | |||
@@ -439,13 +439,12 @@ static int slim_get_current_rxbuf(struct qcom_slim_ctrl *ctrl, void *buf) | |||
439 | static void qcom_slim_rxwq(struct work_struct *work) | 439 | static void qcom_slim_rxwq(struct work_struct *work) |
440 | { | 440 | { |
441 | u8 buf[SLIM_MSGQ_BUF_LEN]; | 441 | u8 buf[SLIM_MSGQ_BUF_LEN]; |
442 | u8 mc, mt, len; | 442 | u8 mc, mt; |
443 | int ret; | 443 | int ret; |
444 | struct qcom_slim_ctrl *ctrl = container_of(work, struct qcom_slim_ctrl, | 444 | struct qcom_slim_ctrl *ctrl = container_of(work, struct qcom_slim_ctrl, |
445 | wd); | 445 | wd); |
446 | 446 | ||
447 | while ((slim_get_current_rxbuf(ctrl, buf)) != -ENODATA) { | 447 | while ((slim_get_current_rxbuf(ctrl, buf)) != -ENODATA) { |
448 | len = SLIM_HEADER_GET_RL(buf[0]); | ||
449 | mt = SLIM_HEADER_GET_MT(buf[0]); | 448 | mt = SLIM_HEADER_GET_MT(buf[0]); |
450 | mc = SLIM_HEADER_GET_MC(buf[1]); | 449 | mc = SLIM_HEADER_GET_MC(buf[1]); |
451 | if (mt == SLIM_MSG_MT_CORE && | 450 | if (mt == SLIM_MSG_MT_CORE && |
diff --git a/drivers/soundwire/Kconfig b/drivers/soundwire/Kconfig index b46084b4b1f8..19c8efb9a5ee 100644 --- a/drivers/soundwire/Kconfig +++ b/drivers/soundwire/Kconfig | |||
@@ -27,7 +27,7 @@ config SOUNDWIRE_INTEL | |||
27 | tristate "Intel SoundWire Master driver" | 27 | tristate "Intel SoundWire Master driver" |
28 | select SOUNDWIRE_CADENCE | 28 | select SOUNDWIRE_CADENCE |
29 | select SOUNDWIRE_BUS | 29 | select SOUNDWIRE_BUS |
30 | depends on X86 && ACPI | 30 | depends on X86 && ACPI && SND_SOC |
31 | ---help--- | 31 | ---help--- |
32 | SoundWire Intel Master driver. | 32 | SoundWire Intel Master driver. |
33 | If you have an Intel platform which has a SoundWire Master then | 33 | If you have an Intel platform which has a SoundWire Master then |
diff --git a/drivers/soundwire/Makefile b/drivers/soundwire/Makefile index e1a74c5692aa..5817beaca0e1 100644 --- a/drivers/soundwire/Makefile +++ b/drivers/soundwire/Makefile | |||
@@ -3,7 +3,7 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | #Bus Objs | 5 | #Bus Objs |
6 | soundwire-bus-objs := bus_type.o bus.o slave.o mipi_disco.o | 6 | soundwire-bus-objs := bus_type.o bus.o slave.o mipi_disco.o stream.o |
7 | obj-$(CONFIG_SOUNDWIRE_BUS) += soundwire-bus.o | 7 | obj-$(CONFIG_SOUNDWIRE_BUS) += soundwire-bus.o |
8 | 8 | ||
9 | #Cadence Objs | 9 | #Cadence Objs |
diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index d6dc8e7a8614..dcc0ff9f0c22 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c | |||
@@ -17,6 +17,7 @@ | |||
17 | */ | 17 | */ |
18 | int sdw_add_bus_master(struct sdw_bus *bus) | 18 | int sdw_add_bus_master(struct sdw_bus *bus) |
19 | { | 19 | { |
20 | struct sdw_master_prop *prop = NULL; | ||
20 | int ret; | 21 | int ret; |
21 | 22 | ||
22 | if (!bus->dev) { | 23 | if (!bus->dev) { |
@@ -32,6 +33,7 @@ int sdw_add_bus_master(struct sdw_bus *bus) | |||
32 | mutex_init(&bus->msg_lock); | 33 | mutex_init(&bus->msg_lock); |
33 | mutex_init(&bus->bus_lock); | 34 | mutex_init(&bus->bus_lock); |
34 | INIT_LIST_HEAD(&bus->slaves); | 35 | INIT_LIST_HEAD(&bus->slaves); |
36 | INIT_LIST_HEAD(&bus->m_rt_list); | ||
35 | 37 | ||
36 | if (bus->ops->read_prop) { | 38 | if (bus->ops->read_prop) { |
37 | ret = bus->ops->read_prop(bus); | 39 | ret = bus->ops->read_prop(bus); |
@@ -77,6 +79,21 @@ int sdw_add_bus_master(struct sdw_bus *bus) | |||
77 | return ret; | 79 | return ret; |
78 | } | 80 | } |
79 | 81 | ||
82 | /* | ||
83 | * Initialize clock values based on Master properties. The max | ||
84 | * frequency is read from max_freq property. Current assumption | ||
85 | * is that the bus will start at highest clock frequency when | ||
86 | * powered on. | ||
87 | * | ||
88 | * Default active bank will be 0 as out of reset the Slaves have | ||
89 | * to start with bank 0 (Table 40 of Spec) | ||
90 | */ | ||
91 | prop = &bus->prop; | ||
92 | bus->params.max_dr_freq = prop->max_freq * SDW_DOUBLE_RATE_FACTOR; | ||
93 | bus->params.curr_dr_freq = bus->params.max_dr_freq; | ||
94 | bus->params.curr_bank = SDW_BANK0; | ||
95 | bus->params.next_bank = SDW_BANK1; | ||
96 | |||
80 | return 0; | 97 | return 0; |
81 | } | 98 | } |
82 | EXPORT_SYMBOL(sdw_add_bus_master); | 99 | EXPORT_SYMBOL(sdw_add_bus_master); |
@@ -576,6 +593,32 @@ static void sdw_modify_slave_status(struct sdw_slave *slave, | |||
576 | mutex_unlock(&slave->bus->bus_lock); | 593 | mutex_unlock(&slave->bus->bus_lock); |
577 | } | 594 | } |
578 | 595 | ||
596 | int sdw_configure_dpn_intr(struct sdw_slave *slave, | ||
597 | int port, bool enable, int mask) | ||
598 | { | ||
599 | u32 addr; | ||
600 | int ret; | ||
601 | u8 val = 0; | ||
602 | |||
603 | addr = SDW_DPN_INTMASK(port); | ||
604 | |||
605 | /* Set/Clear port ready interrupt mask */ | ||
606 | if (enable) { | ||
607 | val |= mask; | ||
608 | val |= SDW_DPN_INT_PORT_READY; | ||
609 | } else { | ||
610 | val &= ~(mask); | ||
611 | val &= ~SDW_DPN_INT_PORT_READY; | ||
612 | } | ||
613 | |||
614 | ret = sdw_update(slave, addr, (mask | SDW_DPN_INT_PORT_READY), val); | ||
615 | if (ret < 0) | ||
616 | dev_err(slave->bus->dev, | ||
617 | "SDW_DPN_INTMASK write failed:%d", val); | ||
618 | |||
619 | return ret; | ||
620 | } | ||
621 | |||
579 | static int sdw_initialize_slave(struct sdw_slave *slave) | 622 | static int sdw_initialize_slave(struct sdw_slave *slave) |
580 | { | 623 | { |
581 | struct sdw_slave_prop *prop = &slave->prop; | 624 | struct sdw_slave_prop *prop = &slave->prop; |
diff --git a/drivers/soundwire/bus.h b/drivers/soundwire/bus.h index 345c34d697e9..3b15c4e25a3a 100644 --- a/drivers/soundwire/bus.h +++ b/drivers/soundwire/bus.h | |||
@@ -45,6 +45,78 @@ struct sdw_msg { | |||
45 | bool page; | 45 | bool page; |
46 | }; | 46 | }; |
47 | 47 | ||
48 | #define SDW_DOUBLE_RATE_FACTOR 2 | ||
49 | |||
50 | extern int rows[SDW_FRAME_ROWS]; | ||
51 | extern int cols[SDW_FRAME_COLS]; | ||
52 | |||
53 | /** | ||
54 | * sdw_port_runtime: Runtime port parameters for Master or Slave | ||
55 | * | ||
56 | * @num: Port number. For audio streams, valid port number ranges from | ||
57 | * [1,14] | ||
58 | * @ch_mask: Channel mask | ||
59 | * @transport_params: Transport parameters | ||
60 | * @port_params: Port parameters | ||
61 | * @port_node: List node for Master or Slave port_list | ||
62 | * | ||
63 | * SoundWire spec has no mention of ports for Master interface but the | ||
64 | * concept is logically extended. | ||
65 | */ | ||
66 | struct sdw_port_runtime { | ||
67 | int num; | ||
68 | int ch_mask; | ||
69 | struct sdw_transport_params transport_params; | ||
70 | struct sdw_port_params port_params; | ||
71 | struct list_head port_node; | ||
72 | }; | ||
73 | |||
74 | /** | ||
75 | * sdw_slave_runtime: Runtime Stream parameters for Slave | ||
76 | * | ||
77 | * @slave: Slave handle | ||
78 | * @direction: Data direction for Slave | ||
79 | * @ch_count: Number of channels handled by the Slave for | ||
80 | * this stream | ||
81 | * @m_rt_node: sdw_master_runtime list node | ||
82 | * @port_list: List of Slave Ports configured for this stream | ||
83 | */ | ||
84 | struct sdw_slave_runtime { | ||
85 | struct sdw_slave *slave; | ||
86 | enum sdw_data_direction direction; | ||
87 | unsigned int ch_count; | ||
88 | struct list_head m_rt_node; | ||
89 | struct list_head port_list; | ||
90 | }; | ||
91 | |||
92 | /** | ||
93 | * sdw_master_runtime: Runtime stream parameters for Master | ||
94 | * | ||
95 | * @bus: Bus handle | ||
96 | * @stream: Stream runtime handle | ||
97 | * @direction: Data direction for Master | ||
98 | * @ch_count: Number of channels handled by the Master for | ||
99 | * this stream, can be zero. | ||
100 | * @slave_rt_list: Slave runtime list | ||
101 | * @port_list: List of Master Ports configured for this stream, can be zero. | ||
102 | * @bus_node: sdw_bus m_rt_list node | ||
103 | */ | ||
104 | struct sdw_master_runtime { | ||
105 | struct sdw_bus *bus; | ||
106 | struct sdw_stream_runtime *stream; | ||
107 | enum sdw_data_direction direction; | ||
108 | unsigned int ch_count; | ||
109 | struct list_head slave_rt_list; | ||
110 | struct list_head port_list; | ||
111 | struct list_head bus_node; | ||
112 | }; | ||
113 | |||
114 | struct sdw_dpn_prop *sdw_get_slave_dpn_prop(struct sdw_slave *slave, | ||
115 | enum sdw_data_direction direction, | ||
116 | unsigned int port_num); | ||
117 | int sdw_configure_dpn_intr(struct sdw_slave *slave, int port, | ||
118 | bool enable, int mask); | ||
119 | |||
48 | int sdw_transfer(struct sdw_bus *bus, struct sdw_msg *msg); | 120 | int sdw_transfer(struct sdw_bus *bus, struct sdw_msg *msg); |
49 | int sdw_transfer_defer(struct sdw_bus *bus, struct sdw_msg *msg, | 121 | int sdw_transfer_defer(struct sdw_bus *bus, struct sdw_msg *msg, |
50 | struct sdw_defer *defer); | 122 | struct sdw_defer *defer); |
diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index 3a9b1462039b..cb6a331f448a 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c | |||
@@ -13,6 +13,8 @@ | |||
13 | #include <linux/mod_devicetable.h> | 13 | #include <linux/mod_devicetable.h> |
14 | #include <linux/soundwire/sdw_registers.h> | 14 | #include <linux/soundwire/sdw_registers.h> |
15 | #include <linux/soundwire/sdw.h> | 15 | #include <linux/soundwire/sdw.h> |
16 | #include <sound/pcm_params.h> | ||
17 | #include <sound/soc.h> | ||
16 | #include "bus.h" | 18 | #include "bus.h" |
17 | #include "cadence_master.h" | 19 | #include "cadence_master.h" |
18 | 20 | ||
@@ -396,7 +398,7 @@ static int cdns_prep_msg(struct sdw_cdns *cdns, struct sdw_msg *msg, int *cmd) | |||
396 | return 0; | 398 | return 0; |
397 | } | 399 | } |
398 | 400 | ||
399 | static enum sdw_command_response | 401 | enum sdw_command_response |
400 | cdns_xfer_msg(struct sdw_bus *bus, struct sdw_msg *msg) | 402 | cdns_xfer_msg(struct sdw_bus *bus, struct sdw_msg *msg) |
401 | { | 403 | { |
402 | struct sdw_cdns *cdns = bus_to_cdns(bus); | 404 | struct sdw_cdns *cdns = bus_to_cdns(bus); |
@@ -422,8 +424,9 @@ cdns_xfer_msg(struct sdw_bus *bus, struct sdw_msg *msg) | |||
422 | exit: | 424 | exit: |
423 | return ret; | 425 | return ret; |
424 | } | 426 | } |
427 | EXPORT_SYMBOL(cdns_xfer_msg); | ||
425 | 428 | ||
426 | static enum sdw_command_response | 429 | enum sdw_command_response |
427 | cdns_xfer_msg_defer(struct sdw_bus *bus, | 430 | cdns_xfer_msg_defer(struct sdw_bus *bus, |
428 | struct sdw_msg *msg, struct sdw_defer *defer) | 431 | struct sdw_msg *msg, struct sdw_defer *defer) |
429 | { | 432 | { |
@@ -443,8 +446,9 @@ cdns_xfer_msg_defer(struct sdw_bus *bus, | |||
443 | 446 | ||
444 | return _cdns_xfer_msg(cdns, msg, cmd, 0, msg->len, true); | 447 | return _cdns_xfer_msg(cdns, msg, cmd, 0, msg->len, true); |
445 | } | 448 | } |
449 | EXPORT_SYMBOL(cdns_xfer_msg_defer); | ||
446 | 450 | ||
447 | static enum sdw_command_response | 451 | enum sdw_command_response |
448 | cdns_reset_page_addr(struct sdw_bus *bus, unsigned int dev_num) | 452 | cdns_reset_page_addr(struct sdw_bus *bus, unsigned int dev_num) |
449 | { | 453 | { |
450 | struct sdw_cdns *cdns = bus_to_cdns(bus); | 454 | struct sdw_cdns *cdns = bus_to_cdns(bus); |
@@ -456,6 +460,7 @@ cdns_reset_page_addr(struct sdw_bus *bus, unsigned int dev_num) | |||
456 | 460 | ||
457 | return cdns_program_scp_addr(cdns, &msg); | 461 | return cdns_program_scp_addr(cdns, &msg); |
458 | } | 462 | } |
463 | EXPORT_SYMBOL(cdns_reset_page_addr); | ||
459 | 464 | ||
460 | /* | 465 | /* |
461 | * IRQ handling | 466 | * IRQ handling |
@@ -666,6 +671,120 @@ int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns) | |||
666 | } | 671 | } |
667 | EXPORT_SYMBOL(sdw_cdns_enable_interrupt); | 672 | EXPORT_SYMBOL(sdw_cdns_enable_interrupt); |
668 | 673 | ||
674 | static int cdns_allocate_pdi(struct sdw_cdns *cdns, | ||
675 | struct sdw_cdns_pdi **stream, | ||
676 | u32 num, u32 pdi_offset) | ||
677 | { | ||
678 | struct sdw_cdns_pdi *pdi; | ||
679 | int i; | ||
680 | |||
681 | if (!num) | ||
682 | return 0; | ||
683 | |||
684 | pdi = devm_kcalloc(cdns->dev, num, sizeof(*pdi), GFP_KERNEL); | ||
685 | if (!pdi) | ||
686 | return -ENOMEM; | ||
687 | |||
688 | for (i = 0; i < num; i++) { | ||
689 | pdi[i].num = i + pdi_offset; | ||
690 | pdi[i].assigned = false; | ||
691 | } | ||
692 | |||
693 | *stream = pdi; | ||
694 | return 0; | ||
695 | } | ||
696 | |||
697 | /** | ||
698 | * sdw_cdns_pdi_init() - PDI initialization routine | ||
699 | * | ||
700 | * @cdns: Cadence instance | ||
701 | * @config: Stream configurations | ||
702 | */ | ||
703 | int sdw_cdns_pdi_init(struct sdw_cdns *cdns, | ||
704 | struct sdw_cdns_stream_config config) | ||
705 | { | ||
706 | struct sdw_cdns_streams *stream; | ||
707 | int offset, i, ret; | ||
708 | |||
709 | cdns->pcm.num_bd = config.pcm_bd; | ||
710 | cdns->pcm.num_in = config.pcm_in; | ||
711 | cdns->pcm.num_out = config.pcm_out; | ||
712 | cdns->pdm.num_bd = config.pdm_bd; | ||
713 | cdns->pdm.num_in = config.pdm_in; | ||
714 | cdns->pdm.num_out = config.pdm_out; | ||
715 | |||
716 | /* Allocate PDIs for PCMs */ | ||
717 | stream = &cdns->pcm; | ||
718 | |||
719 | /* First two PDIs are reserved for bulk transfers */ | ||
720 | stream->num_bd -= CDNS_PCM_PDI_OFFSET; | ||
721 | offset = CDNS_PCM_PDI_OFFSET; | ||
722 | |||
723 | ret = cdns_allocate_pdi(cdns, &stream->bd, | ||
724 | stream->num_bd, offset); | ||
725 | if (ret) | ||
726 | return ret; | ||
727 | |||
728 | offset += stream->num_bd; | ||
729 | |||
730 | ret = cdns_allocate_pdi(cdns, &stream->in, | ||
731 | stream->num_in, offset); | ||
732 | if (ret) | ||
733 | return ret; | ||
734 | |||
735 | offset += stream->num_in; | ||
736 | |||
737 | ret = cdns_allocate_pdi(cdns, &stream->out, | ||
738 | stream->num_out, offset); | ||
739 | if (ret) | ||
740 | return ret; | ||
741 | |||
742 | /* Update total number of PCM PDIs */ | ||
743 | stream->num_pdi = stream->num_bd + stream->num_in + stream->num_out; | ||
744 | cdns->num_ports = stream->num_pdi; | ||
745 | |||
746 | /* Allocate PDIs for PDMs */ | ||
747 | stream = &cdns->pdm; | ||
748 | offset = CDNS_PDM_PDI_OFFSET; | ||
749 | ret = cdns_allocate_pdi(cdns, &stream->bd, | ||
750 | stream->num_bd, offset); | ||
751 | if (ret) | ||
752 | return ret; | ||
753 | |||
754 | offset += stream->num_bd; | ||
755 | |||
756 | ret = cdns_allocate_pdi(cdns, &stream->in, | ||
757 | stream->num_in, offset); | ||
758 | if (ret) | ||
759 | return ret; | ||
760 | |||
761 | offset += stream->num_in; | ||
762 | |||
763 | ret = cdns_allocate_pdi(cdns, &stream->out, | ||
764 | stream->num_out, offset); | ||
765 | if (ret) | ||
766 | return ret; | ||
767 | |||
768 | /* Update total number of PDM PDIs */ | ||
769 | stream->num_pdi = stream->num_bd + stream->num_in + stream->num_out; | ||
770 | cdns->num_ports += stream->num_pdi; | ||
771 | |||
772 | cdns->ports = devm_kcalloc(cdns->dev, cdns->num_ports, | ||
773 | sizeof(*cdns->ports), GFP_KERNEL); | ||
774 | if (!cdns->ports) { | ||
775 | ret = -ENOMEM; | ||
776 | return ret; | ||
777 | } | ||
778 | |||
779 | for (i = 0; i < cdns->num_ports; i++) { | ||
780 | cdns->ports[i].assigned = false; | ||
781 | cdns->ports[i].num = i + 1; /* Port 0 reserved for bulk */ | ||
782 | } | ||
783 | |||
784 | return 0; | ||
785 | } | ||
786 | EXPORT_SYMBOL(sdw_cdns_pdi_init); | ||
787 | |||
669 | /** | 788 | /** |
670 | * sdw_cdns_init() - Cadence initialization | 789 | * sdw_cdns_init() - Cadence initialization |
671 | * @cdns: Cadence instance | 790 | * @cdns: Cadence instance |
@@ -727,13 +846,133 @@ int sdw_cdns_init(struct sdw_cdns *cdns) | |||
727 | } | 846 | } |
728 | EXPORT_SYMBOL(sdw_cdns_init); | 847 | EXPORT_SYMBOL(sdw_cdns_init); |
729 | 848 | ||
730 | struct sdw_master_ops sdw_cdns_master_ops = { | 849 | int cdns_bus_conf(struct sdw_bus *bus, struct sdw_bus_params *params) |
731 | .read_prop = sdw_master_read_prop, | 850 | { |
732 | .xfer_msg = cdns_xfer_msg, | 851 | struct sdw_cdns *cdns = bus_to_cdns(bus); |
733 | .xfer_msg_defer = cdns_xfer_msg_defer, | 852 | int mcp_clkctrl_off, mcp_clkctrl; |
734 | .reset_page_addr = cdns_reset_page_addr, | 853 | int divider; |
854 | |||
855 | if (!params->curr_dr_freq) { | ||
856 | dev_err(cdns->dev, "NULL curr_dr_freq"); | ||
857 | return -EINVAL; | ||
858 | } | ||
859 | |||
860 | divider = (params->max_dr_freq / params->curr_dr_freq) - 1; | ||
861 | |||
862 | if (params->next_bank) | ||
863 | mcp_clkctrl_off = CDNS_MCP_CLK_CTRL1; | ||
864 | else | ||
865 | mcp_clkctrl_off = CDNS_MCP_CLK_CTRL0; | ||
866 | |||
867 | mcp_clkctrl = cdns_readl(cdns, mcp_clkctrl_off); | ||
868 | mcp_clkctrl |= divider; | ||
869 | cdns_writel(cdns, mcp_clkctrl_off, mcp_clkctrl); | ||
870 | |||
871 | return 0; | ||
872 | } | ||
873 | EXPORT_SYMBOL(cdns_bus_conf); | ||
874 | |||
875 | static int cdns_port_params(struct sdw_bus *bus, | ||
876 | struct sdw_port_params *p_params, unsigned int bank) | ||
877 | { | ||
878 | struct sdw_cdns *cdns = bus_to_cdns(bus); | ||
879 | int dpn_config = 0, dpn_config_off; | ||
880 | |||
881 | if (bank) | ||
882 | dpn_config_off = CDNS_DPN_B1_CONFIG(p_params->num); | ||
883 | else | ||
884 | dpn_config_off = CDNS_DPN_B0_CONFIG(p_params->num); | ||
885 | |||
886 | dpn_config = cdns_readl(cdns, dpn_config_off); | ||
887 | |||
888 | dpn_config |= ((p_params->bps - 1) << | ||
889 | SDW_REG_SHIFT(CDNS_DPN_CONFIG_WL)); | ||
890 | dpn_config |= (p_params->flow_mode << | ||
891 | SDW_REG_SHIFT(CDNS_DPN_CONFIG_PORT_FLOW)); | ||
892 | dpn_config |= (p_params->data_mode << | ||
893 | SDW_REG_SHIFT(CDNS_DPN_CONFIG_PORT_DAT)); | ||
894 | |||
895 | cdns_writel(cdns, dpn_config_off, dpn_config); | ||
896 | |||
897 | return 0; | ||
898 | } | ||
899 | |||
900 | static int cdns_transport_params(struct sdw_bus *bus, | ||
901 | struct sdw_transport_params *t_params, | ||
902 | enum sdw_reg_bank bank) | ||
903 | { | ||
904 | struct sdw_cdns *cdns = bus_to_cdns(bus); | ||
905 | int dpn_offsetctrl = 0, dpn_offsetctrl_off; | ||
906 | int dpn_config = 0, dpn_config_off; | ||
907 | int dpn_hctrl = 0, dpn_hctrl_off; | ||
908 | int num = t_params->port_num; | ||
909 | int dpn_samplectrl_off; | ||
910 | |||
911 | /* | ||
912 | * Note: Only full data port is supported on the Master side for | ||
913 | * both PCM and PDM ports. | ||
914 | */ | ||
915 | |||
916 | if (bank) { | ||
917 | dpn_config_off = CDNS_DPN_B1_CONFIG(num); | ||
918 | dpn_samplectrl_off = CDNS_DPN_B1_SAMPLE_CTRL(num); | ||
919 | dpn_hctrl_off = CDNS_DPN_B1_HCTRL(num); | ||
920 | dpn_offsetctrl_off = CDNS_DPN_B1_OFFSET_CTRL(num); | ||
921 | } else { | ||
922 | dpn_config_off = CDNS_DPN_B0_CONFIG(num); | ||
923 | dpn_samplectrl_off = CDNS_DPN_B0_SAMPLE_CTRL(num); | ||
924 | dpn_hctrl_off = CDNS_DPN_B0_HCTRL(num); | ||
925 | dpn_offsetctrl_off = CDNS_DPN_B0_OFFSET_CTRL(num); | ||
926 | } | ||
927 | |||
928 | dpn_config = cdns_readl(cdns, dpn_config_off); | ||
929 | |||
930 | dpn_config |= (t_params->blk_grp_ctrl << | ||
931 | SDW_REG_SHIFT(CDNS_DPN_CONFIG_BGC)); | ||
932 | dpn_config |= (t_params->blk_pkg_mode << | ||
933 | SDW_REG_SHIFT(CDNS_DPN_CONFIG_BPM)); | ||
934 | cdns_writel(cdns, dpn_config_off, dpn_config); | ||
935 | |||
936 | dpn_offsetctrl |= (t_params->offset1 << | ||
937 | SDW_REG_SHIFT(CDNS_DPN_OFFSET_CTRL_1)); | ||
938 | dpn_offsetctrl |= (t_params->offset2 << | ||
939 | SDW_REG_SHIFT(CDNS_DPN_OFFSET_CTRL_2)); | ||
940 | cdns_writel(cdns, dpn_offsetctrl_off, dpn_offsetctrl); | ||
941 | |||
942 | dpn_hctrl |= (t_params->hstart << | ||
943 | SDW_REG_SHIFT(CDNS_DPN_HCTRL_HSTART)); | ||
944 | dpn_hctrl |= (t_params->hstop << SDW_REG_SHIFT(CDNS_DPN_HCTRL_HSTOP)); | ||
945 | dpn_hctrl |= (t_params->lane_ctrl << | ||
946 | SDW_REG_SHIFT(CDNS_DPN_HCTRL_LCTRL)); | ||
947 | |||
948 | cdns_writel(cdns, dpn_hctrl_off, dpn_hctrl); | ||
949 | cdns_writel(cdns, dpn_samplectrl_off, (t_params->sample_interval - 1)); | ||
950 | |||
951 | return 0; | ||
952 | } | ||
953 | |||
954 | static int cdns_port_enable(struct sdw_bus *bus, | ||
955 | struct sdw_enable_ch *enable_ch, unsigned int bank) | ||
956 | { | ||
957 | struct sdw_cdns *cdns = bus_to_cdns(bus); | ||
958 | int dpn_chnen_off, ch_mask; | ||
959 | |||
960 | if (bank) | ||
961 | dpn_chnen_off = CDNS_DPN_B1_CH_EN(enable_ch->port_num); | ||
962 | else | ||
963 | dpn_chnen_off = CDNS_DPN_B0_CH_EN(enable_ch->port_num); | ||
964 | |||
965 | ch_mask = enable_ch->ch_mask * enable_ch->enable; | ||
966 | cdns_writel(cdns, dpn_chnen_off, ch_mask); | ||
967 | |||
968 | return 0; | ||
969 | } | ||
970 | |||
971 | static const struct sdw_master_port_ops cdns_port_ops = { | ||
972 | .dpn_set_port_params = cdns_port_params, | ||
973 | .dpn_set_port_transport_params = cdns_transport_params, | ||
974 | .dpn_port_enable_ch = cdns_port_enable, | ||
735 | }; | 975 | }; |
736 | EXPORT_SYMBOL(sdw_cdns_master_ops); | ||
737 | 976 | ||
738 | /** | 977 | /** |
739 | * sdw_cdns_probe() - Cadence probe routine | 978 | * sdw_cdns_probe() - Cadence probe routine |
@@ -742,10 +981,204 @@ EXPORT_SYMBOL(sdw_cdns_master_ops); | |||
742 | int sdw_cdns_probe(struct sdw_cdns *cdns) | 981 | int sdw_cdns_probe(struct sdw_cdns *cdns) |
743 | { | 982 | { |
744 | init_completion(&cdns->tx_complete); | 983 | init_completion(&cdns->tx_complete); |
984 | cdns->bus.port_ops = &cdns_port_ops; | ||
745 | 985 | ||
746 | return 0; | 986 | return 0; |
747 | } | 987 | } |
748 | EXPORT_SYMBOL(sdw_cdns_probe); | 988 | EXPORT_SYMBOL(sdw_cdns_probe); |
749 | 989 | ||
990 | int cdns_set_sdw_stream(struct snd_soc_dai *dai, | ||
991 | void *stream, bool pcm, int direction) | ||
992 | { | ||
993 | struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai); | ||
994 | struct sdw_cdns_dma_data *dma; | ||
995 | |||
996 | dma = kzalloc(sizeof(*dma), GFP_KERNEL); | ||
997 | if (!dma) | ||
998 | return -ENOMEM; | ||
999 | |||
1000 | if (pcm) | ||
1001 | dma->stream_type = SDW_STREAM_PCM; | ||
1002 | else | ||
1003 | dma->stream_type = SDW_STREAM_PDM; | ||
1004 | |||
1005 | dma->bus = &cdns->bus; | ||
1006 | dma->link_id = cdns->instance; | ||
1007 | |||
1008 | dma->stream = stream; | ||
1009 | |||
1010 | if (direction == SNDRV_PCM_STREAM_PLAYBACK) | ||
1011 | dai->playback_dma_data = dma; | ||
1012 | else | ||
1013 | dai->capture_dma_data = dma; | ||
1014 | |||
1015 | return 0; | ||
1016 | } | ||
1017 | EXPORT_SYMBOL(cdns_set_sdw_stream); | ||
1018 | |||
1019 | /** | ||
1020 | * cdns_find_pdi() - Find a free PDI | ||
1021 | * | ||
1022 | * @cdns: Cadence instance | ||
1023 | * @num: Number of PDIs | ||
1024 | * @pdi: PDI instances | ||
1025 | * | ||
1026 | * Find and return a free PDI for a given PDI array | ||
1027 | */ | ||
1028 | static struct sdw_cdns_pdi *cdns_find_pdi(struct sdw_cdns *cdns, | ||
1029 | unsigned int num, struct sdw_cdns_pdi *pdi) | ||
1030 | { | ||
1031 | int i; | ||
1032 | |||
1033 | for (i = 0; i < num; i++) { | ||
1034 | if (pdi[i].assigned == true) | ||
1035 | continue; | ||
1036 | pdi[i].assigned = true; | ||
1037 | return &pdi[i]; | ||
1038 | } | ||
1039 | |||
1040 | return NULL; | ||
1041 | } | ||
1042 | |||
1043 | /** | ||
1044 | * sdw_cdns_config_stream: Configure a stream | ||
1045 | * | ||
1046 | * @cdns: Cadence instance | ||
1047 | * @port: Cadence data port | ||
1048 | * @ch: Channel count | ||
1049 | * @dir: Data direction | ||
1050 | * @pdi: PDI to be used | ||
1051 | */ | ||
1052 | void sdw_cdns_config_stream(struct sdw_cdns *cdns, | ||
1053 | struct sdw_cdns_port *port, | ||
1054 | u32 ch, u32 dir, struct sdw_cdns_pdi *pdi) | ||
1055 | { | ||
1056 | u32 offset, val = 0; | ||
1057 | |||
1058 | if (dir == SDW_DATA_DIR_RX) | ||
1059 | val = CDNS_PORTCTRL_DIRN; | ||
1060 | |||
1061 | offset = CDNS_PORTCTRL + port->num * CDNS_PORT_OFFSET; | ||
1062 | cdns_updatel(cdns, offset, CDNS_PORTCTRL_DIRN, val); | ||
1063 | |||
1064 | val = port->num; | ||
1065 | val |= ((1 << ch) - 1) << SDW_REG_SHIFT(CDNS_PDI_CONFIG_CHANNEL); | ||
1066 | cdns_writel(cdns, CDNS_PDI_CONFIG(pdi->num), val); | ||
1067 | } | ||
1068 | EXPORT_SYMBOL(sdw_cdns_config_stream); | ||
1069 | |||
1070 | /** | ||
1071 | * cdns_get_num_pdi() - Get number of PDIs required | ||
1072 | * | ||
1073 | * @cdns: Cadence instance | ||
1074 | * @pdi: PDI to be used | ||
1075 | * @num: Number of PDIs | ||
1076 | * @ch_count: Channel count | ||
1077 | */ | ||
1078 | static int cdns_get_num_pdi(struct sdw_cdns *cdns, | ||
1079 | struct sdw_cdns_pdi *pdi, | ||
1080 | unsigned int num, u32 ch_count) | ||
1081 | { | ||
1082 | int i, pdis = 0; | ||
1083 | |||
1084 | for (i = 0; i < num; i++) { | ||
1085 | if (pdi[i].assigned == true) | ||
1086 | continue; | ||
1087 | |||
1088 | if (pdi[i].ch_count < ch_count) | ||
1089 | ch_count -= pdi[i].ch_count; | ||
1090 | else | ||
1091 | ch_count = 0; | ||
1092 | |||
1093 | pdis++; | ||
1094 | |||
1095 | if (!ch_count) | ||
1096 | break; | ||
1097 | } | ||
1098 | |||
1099 | if (ch_count) | ||
1100 | return 0; | ||
1101 | |||
1102 | return pdis; | ||
1103 | } | ||
1104 | |||
1105 | /** | ||
1106 | * sdw_cdns_get_stream() - Get stream information | ||
1107 | * | ||
1108 | * @cdns: Cadence instance | ||
1109 | * @stream: Stream to be allocated | ||
1110 | * @ch: Channel count | ||
1111 | * @dir: Data direction | ||
1112 | */ | ||
1113 | int sdw_cdns_get_stream(struct sdw_cdns *cdns, | ||
1114 | struct sdw_cdns_streams *stream, | ||
1115 | u32 ch, u32 dir) | ||
1116 | { | ||
1117 | int pdis = 0; | ||
1118 | |||
1119 | if (dir == SDW_DATA_DIR_RX) | ||
1120 | pdis = cdns_get_num_pdi(cdns, stream->in, stream->num_in, ch); | ||
1121 | else | ||
1122 | pdis = cdns_get_num_pdi(cdns, stream->out, stream->num_out, ch); | ||
1123 | |||
1124 | /* check if we found PDI, else find in bi-directional */ | ||
1125 | if (!pdis) | ||
1126 | pdis = cdns_get_num_pdi(cdns, stream->bd, stream->num_bd, ch); | ||
1127 | |||
1128 | return pdis; | ||
1129 | } | ||
1130 | EXPORT_SYMBOL(sdw_cdns_get_stream); | ||
1131 | |||
1132 | /** | ||
1133 | * sdw_cdns_alloc_stream() - Allocate a stream | ||
1134 | * | ||
1135 | * @cdns: Cadence instance | ||
1136 | * @stream: Stream to be allocated | ||
1137 | * @port: Cadence data port | ||
1138 | * @ch: Channel count | ||
1139 | * @dir: Data direction | ||
1140 | */ | ||
1141 | int sdw_cdns_alloc_stream(struct sdw_cdns *cdns, | ||
1142 | struct sdw_cdns_streams *stream, | ||
1143 | struct sdw_cdns_port *port, u32 ch, u32 dir) | ||
1144 | { | ||
1145 | struct sdw_cdns_pdi *pdi = NULL; | ||
1146 | |||
1147 | if (dir == SDW_DATA_DIR_RX) | ||
1148 | pdi = cdns_find_pdi(cdns, stream->num_in, stream->in); | ||
1149 | else | ||
1150 | pdi = cdns_find_pdi(cdns, stream->num_out, stream->out); | ||
1151 | |||
1152 | /* check if we found a PDI, else find in bi-directional */ | ||
1153 | if (!pdi) | ||
1154 | pdi = cdns_find_pdi(cdns, stream->num_bd, stream->bd); | ||
1155 | |||
1156 | if (!pdi) | ||
1157 | return -EIO; | ||
1158 | |||
1159 | port->pdi = pdi; | ||
1160 | pdi->l_ch_num = 0; | ||
1161 | pdi->h_ch_num = ch - 1; | ||
1162 | pdi->dir = dir; | ||
1163 | pdi->ch_count = ch; | ||
1164 | |||
1165 | return 0; | ||
1166 | } | ||
1167 | EXPORT_SYMBOL(sdw_cdns_alloc_stream); | ||
1168 | |||
1169 | void sdw_cdns_shutdown(struct snd_pcm_substream *substream, | ||
1170 | struct snd_soc_dai *dai) | ||
1171 | { | ||
1172 | struct sdw_cdns_dma_data *dma; | ||
1173 | |||
1174 | dma = snd_soc_dai_get_dma_data(dai, substream); | ||
1175 | if (!dma) | ||
1176 | return; | ||
1177 | |||
1178 | snd_soc_dai_set_dma_data(dai, substream, NULL); | ||
1179 | kfree(dma); | ||
1180 | } | ||
1181 | EXPORT_SYMBOL(sdw_cdns_shutdown); | ||
1182 | |||
750 | MODULE_LICENSE("Dual BSD/GPL"); | 1183 | MODULE_LICENSE("Dual BSD/GPL"); |
751 | MODULE_DESCRIPTION("Cadence Soundwire Library"); | 1184 | MODULE_DESCRIPTION("Cadence Soundwire Library"); |
diff --git a/drivers/soundwire/cadence_master.h b/drivers/soundwire/cadence_master.h index beaf6c9804eb..eb902b19c5a4 100644 --- a/drivers/soundwire/cadence_master.h +++ b/drivers/soundwire/cadence_master.h | |||
@@ -1,10 +1,117 @@ | |||
1 | // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) | 1 | // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) |
2 | // Copyright(c) 2015-17 Intel Corporation. | 2 | // Copyright(c) 2015-17 Intel Corporation. |
3 | #include <sound/soc.h> | ||
3 | 4 | ||
4 | #ifndef __SDW_CADENCE_H | 5 | #ifndef __SDW_CADENCE_H |
5 | #define __SDW_CADENCE_H | 6 | #define __SDW_CADENCE_H |
6 | 7 | ||
7 | /** | 8 | /** |
9 | * struct sdw_cdns_pdi: PDI (Physical Data Interface) instance | ||
10 | * | ||
11 | * @assigned: pdi assigned | ||
12 | * @num: pdi number | ||
13 | * @intel_alh_id: link identifier | ||
14 | * @l_ch_num: low channel for PDI | ||
15 | * @h_ch_num: high channel for PDI | ||
16 | * @ch_count: total channel count for PDI | ||
17 | * @dir: data direction | ||
18 | * @type: stream type, PDM or PCM | ||
19 | */ | ||
20 | struct sdw_cdns_pdi { | ||
21 | bool assigned; | ||
22 | int num; | ||
23 | int intel_alh_id; | ||
24 | int l_ch_num; | ||
25 | int h_ch_num; | ||
26 | int ch_count; | ||
27 | enum sdw_data_direction dir; | ||
28 | enum sdw_stream_type type; | ||
29 | }; | ||
30 | |||
31 | /** | ||
32 | * struct sdw_cdns_port: Cadence port structure | ||
33 | * | ||
34 | * @num: port number | ||
35 | * @assigned: port assigned | ||
36 | * @ch: channel count | ||
37 | * @direction: data port direction | ||
38 | * @pdi: pdi for this port | ||
39 | */ | ||
40 | struct sdw_cdns_port { | ||
41 | unsigned int num; | ||
42 | bool assigned; | ||
43 | unsigned int ch; | ||
44 | enum sdw_data_direction direction; | ||
45 | struct sdw_cdns_pdi *pdi; | ||
46 | }; | ||
47 | |||
48 | /** | ||
49 | * struct sdw_cdns_streams: Cadence stream data structure | ||
50 | * | ||
51 | * @num_bd: number of bidirectional streams | ||
52 | * @num_in: number of input streams | ||
53 | * @num_out: number of output streams | ||
54 | * @num_ch_bd: number of bidirectional stream channels | ||
55 | * @num_ch_bd: number of input stream channels | ||
56 | * @num_ch_bd: number of output stream channels | ||
57 | * @num_pdi: total number of PDIs | ||
58 | * @bd: bidirectional streams | ||
59 | * @in: input streams | ||
60 | * @out: output streams | ||
61 | */ | ||
62 | struct sdw_cdns_streams { | ||
63 | unsigned int num_bd; | ||
64 | unsigned int num_in; | ||
65 | unsigned int num_out; | ||
66 | unsigned int num_ch_bd; | ||
67 | unsigned int num_ch_in; | ||
68 | unsigned int num_ch_out; | ||
69 | unsigned int num_pdi; | ||
70 | struct sdw_cdns_pdi *bd; | ||
71 | struct sdw_cdns_pdi *in; | ||
72 | struct sdw_cdns_pdi *out; | ||
73 | }; | ||
74 | |||
75 | /** | ||
76 | * struct sdw_cdns_stream_config: stream configuration | ||
77 | * | ||
78 | * @pcm_bd: number of bidirectional PCM streams supported | ||
79 | * @pcm_in: number of input PCM streams supported | ||
80 | * @pcm_out: number of output PCM streams supported | ||
81 | * @pdm_bd: number of bidirectional PDM streams supported | ||
82 | * @pdm_in: number of input PDM streams supported | ||
83 | * @pdm_out: number of output PDM streams supported | ||
84 | */ | ||
85 | struct sdw_cdns_stream_config { | ||
86 | unsigned int pcm_bd; | ||
87 | unsigned int pcm_in; | ||
88 | unsigned int pcm_out; | ||
89 | unsigned int pdm_bd; | ||
90 | unsigned int pdm_in; | ||
91 | unsigned int pdm_out; | ||
92 | }; | ||
93 | |||
94 | /** | ||
95 | * struct sdw_cdns_dma_data: Cadence DMA data | ||
96 | * | ||
97 | * @name: SoundWire stream name | ||
98 | * @nr_ports: Number of ports | ||
99 | * @port: Ports | ||
100 | * @bus: Bus handle | ||
101 | * @stream_type: Stream type | ||
102 | * @link_id: Master link id | ||
103 | */ | ||
104 | struct sdw_cdns_dma_data { | ||
105 | char *name; | ||
106 | struct sdw_stream_runtime *stream; | ||
107 | int nr_ports; | ||
108 | struct sdw_cdns_port **port; | ||
109 | struct sdw_bus *bus; | ||
110 | enum sdw_stream_type stream_type; | ||
111 | int link_id; | ||
112 | }; | ||
113 | |||
114 | /** | ||
8 | * struct sdw_cdns - Cadence driver context | 115 | * struct sdw_cdns - Cadence driver context |
9 | * @dev: Linux device | 116 | * @dev: Linux device |
10 | * @bus: Bus handle | 117 | * @bus: Bus handle |
@@ -12,6 +119,10 @@ | |||
12 | * @response_buf: SoundWire response buffer | 119 | * @response_buf: SoundWire response buffer |
13 | * @tx_complete: Tx completion | 120 | * @tx_complete: Tx completion |
14 | * @defer: Defer pointer | 121 | * @defer: Defer pointer |
122 | * @ports: Data ports | ||
123 | * @num_ports: Total number of data ports | ||
124 | * @pcm: PCM streams | ||
125 | * @pdm: PDM streams | ||
15 | * @registers: Cadence registers | 126 | * @registers: Cadence registers |
16 | * @link_up: Link status | 127 | * @link_up: Link status |
17 | * @msg_count: Messages sent on bus | 128 | * @msg_count: Messages sent on bus |
@@ -25,6 +136,12 @@ struct sdw_cdns { | |||
25 | struct completion tx_complete; | 136 | struct completion tx_complete; |
26 | struct sdw_defer *defer; | 137 | struct sdw_defer *defer; |
27 | 138 | ||
139 | struct sdw_cdns_port *ports; | ||
140 | int num_ports; | ||
141 | |||
142 | struct sdw_cdns_streams pcm; | ||
143 | struct sdw_cdns_streams pdm; | ||
144 | |||
28 | void __iomem *registers; | 145 | void __iomem *registers; |
29 | 146 | ||
30 | bool link_up; | 147 | bool link_up; |
@@ -42,7 +159,41 @@ irqreturn_t sdw_cdns_irq(int irq, void *dev_id); | |||
42 | irqreturn_t sdw_cdns_thread(int irq, void *dev_id); | 159 | irqreturn_t sdw_cdns_thread(int irq, void *dev_id); |
43 | 160 | ||
44 | int sdw_cdns_init(struct sdw_cdns *cdns); | 161 | int sdw_cdns_init(struct sdw_cdns *cdns); |
162 | int sdw_cdns_pdi_init(struct sdw_cdns *cdns, | ||
163 | struct sdw_cdns_stream_config config); | ||
45 | int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns); | 164 | int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns); |
46 | 165 | ||
166 | int sdw_cdns_get_stream(struct sdw_cdns *cdns, | ||
167 | struct sdw_cdns_streams *stream, | ||
168 | u32 ch, u32 dir); | ||
169 | int sdw_cdns_alloc_stream(struct sdw_cdns *cdns, | ||
170 | struct sdw_cdns_streams *stream, | ||
171 | struct sdw_cdns_port *port, u32 ch, u32 dir); | ||
172 | void sdw_cdns_config_stream(struct sdw_cdns *cdns, struct sdw_cdns_port *port, | ||
173 | u32 ch, u32 dir, struct sdw_cdns_pdi *pdi); | ||
174 | |||
175 | void sdw_cdns_shutdown(struct snd_pcm_substream *substream, | ||
176 | struct snd_soc_dai *dai); | ||
177 | int sdw_cdns_pcm_set_stream(struct snd_soc_dai *dai, | ||
178 | void *stream, int direction); | ||
179 | int sdw_cdns_pdm_set_stream(struct snd_soc_dai *dai, | ||
180 | void *stream, int direction); | ||
181 | |||
182 | enum sdw_command_response | ||
183 | cdns_reset_page_addr(struct sdw_bus *bus, unsigned int dev_num); | ||
184 | |||
185 | enum sdw_command_response | ||
186 | cdns_xfer_msg(struct sdw_bus *bus, struct sdw_msg *msg); | ||
187 | |||
188 | enum sdw_command_response | ||
189 | cdns_xfer_msg_defer(struct sdw_bus *bus, | ||
190 | struct sdw_msg *msg, struct sdw_defer *defer); | ||
191 | |||
192 | enum sdw_command_response | ||
193 | cdns_reset_page_addr(struct sdw_bus *bus, unsigned int dev_num); | ||
194 | |||
195 | int cdns_bus_conf(struct sdw_bus *bus, struct sdw_bus_params *params); | ||
47 | 196 | ||
197 | int cdns_set_sdw_stream(struct snd_soc_dai *dai, | ||
198 | void *stream, bool pcm, int direction); | ||
48 | #endif /* __SDW_CADENCE_H */ | 199 | #endif /* __SDW_CADENCE_H */ |
diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index 86a7bd1fc912..0a8990e758f9 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c | |||
@@ -9,6 +9,8 @@ | |||
9 | #include <linux/delay.h> | 9 | #include <linux/delay.h> |
10 | #include <linux/interrupt.h> | 10 | #include <linux/interrupt.h> |
11 | #include <linux/platform_device.h> | 11 | #include <linux/platform_device.h> |
12 | #include <sound/pcm_params.h> | ||
13 | #include <sound/soc.h> | ||
12 | #include <linux/soundwire/sdw_registers.h> | 14 | #include <linux/soundwire/sdw_registers.h> |
13 | #include <linux/soundwire/sdw.h> | 15 | #include <linux/soundwire/sdw.h> |
14 | #include <linux/soundwire/sdw_intel.h> | 16 | #include <linux/soundwire/sdw_intel.h> |
@@ -85,6 +87,12 @@ | |||
85 | #define SDW_ALH_STRMZCFG_DMAT GENMASK(7, 0) | 87 | #define SDW_ALH_STRMZCFG_DMAT GENMASK(7, 0) |
86 | #define SDW_ALH_STRMZCFG_CHN GENMASK(19, 16) | 88 | #define SDW_ALH_STRMZCFG_CHN GENMASK(19, 16) |
87 | 89 | ||
90 | enum intel_pdi_type { | ||
91 | INTEL_PDI_IN = 0, | ||
92 | INTEL_PDI_OUT = 1, | ||
93 | INTEL_PDI_BD = 2, | ||
94 | }; | ||
95 | |||
88 | struct sdw_intel { | 96 | struct sdw_intel { |
89 | struct sdw_cdns cdns; | 97 | struct sdw_cdns cdns; |
90 | int instance; | 98 | int instance; |
@@ -234,6 +242,490 @@ static int intel_shim_init(struct sdw_intel *sdw) | |||
234 | return ret; | 242 | return ret; |
235 | } | 243 | } |
236 | 244 | ||
245 | /* | ||
246 | * PDI routines | ||
247 | */ | ||
248 | static void intel_pdi_init(struct sdw_intel *sdw, | ||
249 | struct sdw_cdns_stream_config *config) | ||
250 | { | ||
251 | void __iomem *shim = sdw->res->shim; | ||
252 | unsigned int link_id = sdw->instance; | ||
253 | int pcm_cap, pdm_cap; | ||
254 | |||
255 | /* PCM Stream Capability */ | ||
256 | pcm_cap = intel_readw(shim, SDW_SHIM_PCMSCAP(link_id)); | ||
257 | |||
258 | config->pcm_bd = (pcm_cap & SDW_SHIM_PCMSCAP_BSS) >> | ||
259 | SDW_REG_SHIFT(SDW_SHIM_PCMSCAP_BSS); | ||
260 | config->pcm_in = (pcm_cap & SDW_SHIM_PCMSCAP_ISS) >> | ||
261 | SDW_REG_SHIFT(SDW_SHIM_PCMSCAP_ISS); | ||
262 | config->pcm_out = (pcm_cap & SDW_SHIM_PCMSCAP_OSS) >> | ||
263 | SDW_REG_SHIFT(SDW_SHIM_PCMSCAP_OSS); | ||
264 | |||
265 | /* PDM Stream Capability */ | ||
266 | pdm_cap = intel_readw(shim, SDW_SHIM_PDMSCAP(link_id)); | ||
267 | |||
268 | config->pdm_bd = (pdm_cap & SDW_SHIM_PDMSCAP_BSS) >> | ||
269 | SDW_REG_SHIFT(SDW_SHIM_PDMSCAP_BSS); | ||
270 | config->pdm_in = (pdm_cap & SDW_SHIM_PDMSCAP_ISS) >> | ||
271 | SDW_REG_SHIFT(SDW_SHIM_PDMSCAP_ISS); | ||
272 | config->pdm_out = (pdm_cap & SDW_SHIM_PDMSCAP_OSS) >> | ||
273 | SDW_REG_SHIFT(SDW_SHIM_PDMSCAP_OSS); | ||
274 | } | ||
275 | |||
276 | static int | ||
277 | intel_pdi_get_ch_cap(struct sdw_intel *sdw, unsigned int pdi_num, bool pcm) | ||
278 | { | ||
279 | void __iomem *shim = sdw->res->shim; | ||
280 | unsigned int link_id = sdw->instance; | ||
281 | int count; | ||
282 | |||
283 | if (pcm) { | ||
284 | count = intel_readw(shim, SDW_SHIM_PCMSYCHC(link_id, pdi_num)); | ||
285 | } else { | ||
286 | count = intel_readw(shim, SDW_SHIM_PDMSCAP(link_id)); | ||
287 | count = ((count & SDW_SHIM_PDMSCAP_CPSS) >> | ||
288 | SDW_REG_SHIFT(SDW_SHIM_PDMSCAP_CPSS)); | ||
289 | } | ||
290 | |||
291 | /* zero based values for channel count in register */ | ||
292 | count++; | ||
293 | |||
294 | return count; | ||
295 | } | ||
296 | |||
297 | static int intel_pdi_get_ch_update(struct sdw_intel *sdw, | ||
298 | struct sdw_cdns_pdi *pdi, | ||
299 | unsigned int num_pdi, | ||
300 | unsigned int *num_ch, bool pcm) | ||
301 | { | ||
302 | int i, ch_count = 0; | ||
303 | |||
304 | for (i = 0; i < num_pdi; i++) { | ||
305 | pdi->ch_count = intel_pdi_get_ch_cap(sdw, pdi->num, pcm); | ||
306 | ch_count += pdi->ch_count; | ||
307 | pdi++; | ||
308 | } | ||
309 | |||
310 | *num_ch = ch_count; | ||
311 | return 0; | ||
312 | } | ||
313 | |||
314 | static int intel_pdi_stream_ch_update(struct sdw_intel *sdw, | ||
315 | struct sdw_cdns_streams *stream, bool pcm) | ||
316 | { | ||
317 | intel_pdi_get_ch_update(sdw, stream->bd, stream->num_bd, | ||
318 | &stream->num_ch_bd, pcm); | ||
319 | |||
320 | intel_pdi_get_ch_update(sdw, stream->in, stream->num_in, | ||
321 | &stream->num_ch_in, pcm); | ||
322 | |||
323 | intel_pdi_get_ch_update(sdw, stream->out, stream->num_out, | ||
324 | &stream->num_ch_out, pcm); | ||
325 | |||
326 | return 0; | ||
327 | } | ||
328 | |||
329 | static int intel_pdi_ch_update(struct sdw_intel *sdw) | ||
330 | { | ||
331 | /* First update PCM streams followed by PDM streams */ | ||
332 | intel_pdi_stream_ch_update(sdw, &sdw->cdns.pcm, true); | ||
333 | intel_pdi_stream_ch_update(sdw, &sdw->cdns.pdm, false); | ||
334 | |||
335 | return 0; | ||
336 | } | ||
337 | |||
338 | static void | ||
339 | intel_pdi_shim_configure(struct sdw_intel *sdw, struct sdw_cdns_pdi *pdi) | ||
340 | { | ||
341 | void __iomem *shim = sdw->res->shim; | ||
342 | unsigned int link_id = sdw->instance; | ||
343 | int pdi_conf = 0; | ||
344 | |||
345 | pdi->intel_alh_id = (link_id * 16) + pdi->num + 5; | ||
346 | |||
347 | /* | ||
348 | * Program stream parameters to stream SHIM register | ||
349 | * This is applicable for PCM stream only. | ||
350 | */ | ||
351 | if (pdi->type != SDW_STREAM_PCM) | ||
352 | return; | ||
353 | |||
354 | if (pdi->dir == SDW_DATA_DIR_RX) | ||
355 | pdi_conf |= SDW_SHIM_PCMSYCM_DIR; | ||
356 | else | ||
357 | pdi_conf &= ~(SDW_SHIM_PCMSYCM_DIR); | ||
358 | |||
359 | pdi_conf |= (pdi->intel_alh_id << | ||
360 | SDW_REG_SHIFT(SDW_SHIM_PCMSYCM_STREAM)); | ||
361 | pdi_conf |= (pdi->l_ch_num << SDW_REG_SHIFT(SDW_SHIM_PCMSYCM_LCHN)); | ||
362 | pdi_conf |= (pdi->h_ch_num << SDW_REG_SHIFT(SDW_SHIM_PCMSYCM_HCHN)); | ||
363 | |||
364 | intel_writew(shim, SDW_SHIM_PCMSYCHM(link_id, pdi->num), pdi_conf); | ||
365 | } | ||
366 | |||
367 | static void | ||
368 | intel_pdi_alh_configure(struct sdw_intel *sdw, struct sdw_cdns_pdi *pdi) | ||
369 | { | ||
370 | void __iomem *alh = sdw->res->alh; | ||
371 | unsigned int link_id = sdw->instance; | ||
372 | unsigned int conf; | ||
373 | |||
374 | pdi->intel_alh_id = (link_id * 16) + pdi->num + 5; | ||
375 | |||
376 | /* Program Stream config ALH register */ | ||
377 | conf = intel_readl(alh, SDW_ALH_STRMZCFG(pdi->intel_alh_id)); | ||
378 | |||
379 | conf |= (SDW_ALH_STRMZCFG_DMAT_VAL << | ||
380 | SDW_REG_SHIFT(SDW_ALH_STRMZCFG_DMAT)); | ||
381 | |||
382 | conf |= ((pdi->ch_count - 1) << | ||
383 | SDW_REG_SHIFT(SDW_ALH_STRMZCFG_CHN)); | ||
384 | |||
385 | intel_writel(alh, SDW_ALH_STRMZCFG(pdi->intel_alh_id), conf); | ||
386 | } | ||
387 | |||
388 | static int intel_config_stream(struct sdw_intel *sdw, | ||
389 | struct snd_pcm_substream *substream, | ||
390 | struct snd_soc_dai *dai, | ||
391 | struct snd_pcm_hw_params *hw_params, int link_id) | ||
392 | { | ||
393 | if (sdw->res->ops && sdw->res->ops->config_stream) | ||
394 | return sdw->res->ops->config_stream(sdw->res->arg, | ||
395 | substream, dai, hw_params, link_id); | ||
396 | |||
397 | return -EIO; | ||
398 | } | ||
399 | |||
400 | /* | ||
401 | * DAI routines | ||
402 | */ | ||
403 | |||
404 | static struct sdw_cdns_port *intel_alloc_port(struct sdw_intel *sdw, | ||
405 | u32 ch, u32 dir, bool pcm) | ||
406 | { | ||
407 | struct sdw_cdns *cdns = &sdw->cdns; | ||
408 | struct sdw_cdns_port *port = NULL; | ||
409 | int i, ret = 0; | ||
410 | |||
411 | for (i = 0; i < cdns->num_ports; i++) { | ||
412 | if (cdns->ports[i].assigned == true) | ||
413 | continue; | ||
414 | |||
415 | port = &cdns->ports[i]; | ||
416 | port->assigned = true; | ||
417 | port->direction = dir; | ||
418 | port->ch = ch; | ||
419 | break; | ||
420 | } | ||
421 | |||
422 | if (!port) { | ||
423 | dev_err(cdns->dev, "Unable to find a free port\n"); | ||
424 | return NULL; | ||
425 | } | ||
426 | |||
427 | if (pcm) { | ||
428 | ret = sdw_cdns_alloc_stream(cdns, &cdns->pcm, port, ch, dir); | ||
429 | if (ret) | ||
430 | goto out; | ||
431 | |||
432 | intel_pdi_shim_configure(sdw, port->pdi); | ||
433 | sdw_cdns_config_stream(cdns, port, ch, dir, port->pdi); | ||
434 | |||
435 | intel_pdi_alh_configure(sdw, port->pdi); | ||
436 | |||
437 | } else { | ||
438 | ret = sdw_cdns_alloc_stream(cdns, &cdns->pdm, port, ch, dir); | ||
439 | } | ||
440 | |||
441 | out: | ||
442 | if (ret) { | ||
443 | port->assigned = false; | ||
444 | port = NULL; | ||
445 | } | ||
446 | |||
447 | return port; | ||
448 | } | ||
449 | |||
450 | static void intel_port_cleanup(struct sdw_cdns_dma_data *dma) | ||
451 | { | ||
452 | int i; | ||
453 | |||
454 | for (i = 0; i < dma->nr_ports; i++) { | ||
455 | if (dma->port[i]) { | ||
456 | dma->port[i]->pdi->assigned = false; | ||
457 | dma->port[i]->pdi = NULL; | ||
458 | dma->port[i]->assigned = false; | ||
459 | dma->port[i] = NULL; | ||
460 | } | ||
461 | } | ||
462 | } | ||
463 | |||
464 | static int intel_hw_params(struct snd_pcm_substream *substream, | ||
465 | struct snd_pcm_hw_params *params, | ||
466 | struct snd_soc_dai *dai) | ||
467 | { | ||
468 | struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai); | ||
469 | struct sdw_intel *sdw = cdns_to_intel(cdns); | ||
470 | struct sdw_cdns_dma_data *dma; | ||
471 | struct sdw_stream_config sconfig; | ||
472 | struct sdw_port_config *pconfig; | ||
473 | int ret, i, ch, dir; | ||
474 | bool pcm = true; | ||
475 | |||
476 | dma = snd_soc_dai_get_dma_data(dai, substream); | ||
477 | if (!dma) | ||
478 | return -EIO; | ||
479 | |||
480 | ch = params_channels(params); | ||
481 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) | ||
482 | dir = SDW_DATA_DIR_RX; | ||
483 | else | ||
484 | dir = SDW_DATA_DIR_TX; | ||
485 | |||
486 | if (dma->stream_type == SDW_STREAM_PDM) { | ||
487 | /* TODO: Check whether PDM decimator is already in use */ | ||
488 | dma->nr_ports = sdw_cdns_get_stream(cdns, &cdns->pdm, ch, dir); | ||
489 | pcm = false; | ||
490 | } else { | ||
491 | dma->nr_ports = sdw_cdns_get_stream(cdns, &cdns->pcm, ch, dir); | ||
492 | } | ||
493 | |||
494 | if (!dma->nr_ports) { | ||
495 | dev_err(dai->dev, "ports/resources not available"); | ||
496 | return -EINVAL; | ||
497 | } | ||
498 | |||
499 | dma->port = kcalloc(dma->nr_ports, sizeof(*dma->port), GFP_KERNEL); | ||
500 | if (!dma->port) | ||
501 | return -ENOMEM; | ||
502 | |||
503 | for (i = 0; i < dma->nr_ports; i++) { | ||
504 | dma->port[i] = intel_alloc_port(sdw, ch, dir, pcm); | ||
505 | if (!dma->port[i]) { | ||
506 | ret = -EINVAL; | ||
507 | goto port_error; | ||
508 | } | ||
509 | } | ||
510 | |||
511 | /* Inform DSP about PDI stream number */ | ||
512 | for (i = 0; i < dma->nr_ports; i++) { | ||
513 | ret = intel_config_stream(sdw, substream, dai, params, | ||
514 | dma->port[i]->pdi->intel_alh_id); | ||
515 | if (ret) | ||
516 | goto port_error; | ||
517 | } | ||
518 | |||
519 | sconfig.direction = dir; | ||
520 | sconfig.ch_count = ch; | ||
521 | sconfig.frame_rate = params_rate(params); | ||
522 | sconfig.type = dma->stream_type; | ||
523 | |||
524 | if (dma->stream_type == SDW_STREAM_PDM) { | ||
525 | sconfig.frame_rate *= 50; | ||
526 | sconfig.bps = 1; | ||
527 | } else { | ||
528 | sconfig.bps = snd_pcm_format_width(params_format(params)); | ||
529 | } | ||
530 | |||
531 | /* Port configuration */ | ||
532 | pconfig = kcalloc(dma->nr_ports, sizeof(*pconfig), GFP_KERNEL); | ||
533 | if (!pconfig) { | ||
534 | ret = -ENOMEM; | ||
535 | goto port_error; | ||
536 | } | ||
537 | |||
538 | for (i = 0; i < dma->nr_ports; i++) { | ||
539 | pconfig[i].num = dma->port[i]->num; | ||
540 | pconfig[i].ch_mask = (1 << ch) - 1; | ||
541 | } | ||
542 | |||
543 | ret = sdw_stream_add_master(&cdns->bus, &sconfig, | ||
544 | pconfig, dma->nr_ports, dma->stream); | ||
545 | if (ret) { | ||
546 | dev_err(cdns->dev, "add master to stream failed:%d", ret); | ||
547 | goto stream_error; | ||
548 | } | ||
549 | |||
550 | kfree(pconfig); | ||
551 | return ret; | ||
552 | |||
553 | stream_error: | ||
554 | kfree(pconfig); | ||
555 | port_error: | ||
556 | intel_port_cleanup(dma); | ||
557 | kfree(dma->port); | ||
558 | return ret; | ||
559 | } | ||
560 | |||
561 | static int | ||
562 | intel_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) | ||
563 | { | ||
564 | struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai); | ||
565 | struct sdw_cdns_dma_data *dma; | ||
566 | int ret; | ||
567 | |||
568 | dma = snd_soc_dai_get_dma_data(dai, substream); | ||
569 | if (!dma) | ||
570 | return -EIO; | ||
571 | |||
572 | ret = sdw_stream_remove_master(&cdns->bus, dma->stream); | ||
573 | if (ret < 0) | ||
574 | dev_err(dai->dev, "remove master from stream %s failed: %d", | ||
575 | dma->stream->name, ret); | ||
576 | |||
577 | intel_port_cleanup(dma); | ||
578 | kfree(dma->port); | ||
579 | return ret; | ||
580 | } | ||
581 | |||
582 | static int intel_pcm_set_sdw_stream(struct snd_soc_dai *dai, | ||
583 | void *stream, int direction) | ||
584 | { | ||
585 | return cdns_set_sdw_stream(dai, stream, true, direction); | ||
586 | } | ||
587 | |||
588 | static int intel_pdm_set_sdw_stream(struct snd_soc_dai *dai, | ||
589 | void *stream, int direction) | ||
590 | { | ||
591 | return cdns_set_sdw_stream(dai, stream, false, direction); | ||
592 | } | ||
593 | |||
594 | static struct snd_soc_dai_ops intel_pcm_dai_ops = { | ||
595 | .hw_params = intel_hw_params, | ||
596 | .hw_free = intel_hw_free, | ||
597 | .shutdown = sdw_cdns_shutdown, | ||
598 | .set_sdw_stream = intel_pcm_set_sdw_stream, | ||
599 | }; | ||
600 | |||
601 | static struct snd_soc_dai_ops intel_pdm_dai_ops = { | ||
602 | .hw_params = intel_hw_params, | ||
603 | .hw_free = intel_hw_free, | ||
604 | .shutdown = sdw_cdns_shutdown, | ||
605 | .set_sdw_stream = intel_pdm_set_sdw_stream, | ||
606 | }; | ||
607 | |||
608 | static const struct snd_soc_component_driver dai_component = { | ||
609 | .name = "soundwire", | ||
610 | }; | ||
611 | |||
612 | static int intel_create_dai(struct sdw_cdns *cdns, | ||
613 | struct snd_soc_dai_driver *dais, | ||
614 | enum intel_pdi_type type, | ||
615 | u32 num, u32 off, u32 max_ch, bool pcm) | ||
616 | { | ||
617 | int i; | ||
618 | |||
619 | if (num == 0) | ||
620 | return 0; | ||
621 | |||
622 | /* TODO: Read supported rates/formats from hardware */ | ||
623 | for (i = off; i < (off + num); i++) { | ||
624 | dais[i].name = kasprintf(GFP_KERNEL, "SDW%d Pin%d", | ||
625 | cdns->instance, i); | ||
626 | if (!dais[i].name) | ||
627 | return -ENOMEM; | ||
628 | |||
629 | if (type == INTEL_PDI_BD || type == INTEL_PDI_OUT) { | ||
630 | dais[i].playback.stream_name = kasprintf(GFP_KERNEL, | ||
631 | "SDW%d Tx%d", | ||
632 | cdns->instance, i); | ||
633 | if (!dais[i].playback.stream_name) { | ||
634 | kfree(dais[i].name); | ||
635 | return -ENOMEM; | ||
636 | } | ||
637 | |||
638 | dais[i].playback.channels_min = 1; | ||
639 | dais[i].playback.channels_max = max_ch; | ||
640 | dais[i].playback.rates = SNDRV_PCM_RATE_48000; | ||
641 | dais[i].playback.formats = SNDRV_PCM_FMTBIT_S16_LE; | ||
642 | } | ||
643 | |||
644 | if (type == INTEL_PDI_BD || type == INTEL_PDI_IN) { | ||
645 | dais[i].capture.stream_name = kasprintf(GFP_KERNEL, | ||
646 | "SDW%d Rx%d", | ||
647 | cdns->instance, i); | ||
648 | if (!dais[i].capture.stream_name) { | ||
649 | kfree(dais[i].name); | ||
650 | kfree(dais[i].playback.stream_name); | ||
651 | return -ENOMEM; | ||
652 | } | ||
653 | |||
654 | dais[i].playback.channels_min = 1; | ||
655 | dais[i].playback.channels_max = max_ch; | ||
656 | dais[i].capture.rates = SNDRV_PCM_RATE_48000; | ||
657 | dais[i].capture.formats = SNDRV_PCM_FMTBIT_S16_LE; | ||
658 | } | ||
659 | |||
660 | dais[i].id = SDW_DAI_ID_RANGE_START + i; | ||
661 | |||
662 | if (pcm) | ||
663 | dais[i].ops = &intel_pcm_dai_ops; | ||
664 | else | ||
665 | dais[i].ops = &intel_pdm_dai_ops; | ||
666 | } | ||
667 | |||
668 | return 0; | ||
669 | } | ||
670 | |||
671 | static int intel_register_dai(struct sdw_intel *sdw) | ||
672 | { | ||
673 | struct sdw_cdns *cdns = &sdw->cdns; | ||
674 | struct sdw_cdns_streams *stream; | ||
675 | struct snd_soc_dai_driver *dais; | ||
676 | int num_dai, ret, off = 0; | ||
677 | |||
678 | /* DAIs are created based on total number of PDIs supported */ | ||
679 | num_dai = cdns->pcm.num_pdi + cdns->pdm.num_pdi; | ||
680 | |||
681 | dais = devm_kcalloc(cdns->dev, num_dai, sizeof(*dais), GFP_KERNEL); | ||
682 | if (!dais) | ||
683 | return -ENOMEM; | ||
684 | |||
685 | /* Create PCM DAIs */ | ||
686 | stream = &cdns->pcm; | ||
687 | |||
688 | ret = intel_create_dai(cdns, dais, INTEL_PDI_IN, | ||
689 | stream->num_in, off, stream->num_ch_in, true); | ||
690 | if (ret) | ||
691 | return ret; | ||
692 | |||
693 | off += cdns->pcm.num_in; | ||
694 | ret = intel_create_dai(cdns, dais, INTEL_PDI_OUT, | ||
695 | cdns->pcm.num_out, off, stream->num_ch_out, true); | ||
696 | if (ret) | ||
697 | return ret; | ||
698 | |||
699 | off += cdns->pcm.num_out; | ||
700 | ret = intel_create_dai(cdns, dais, INTEL_PDI_BD, | ||
701 | cdns->pcm.num_bd, off, stream->num_ch_bd, true); | ||
702 | if (ret) | ||
703 | return ret; | ||
704 | |||
705 | /* Create PDM DAIs */ | ||
706 | stream = &cdns->pdm; | ||
707 | off += cdns->pcm.num_bd; | ||
708 | ret = intel_create_dai(cdns, dais, INTEL_PDI_IN, | ||
709 | cdns->pdm.num_in, off, stream->num_ch_in, false); | ||
710 | if (ret) | ||
711 | return ret; | ||
712 | |||
713 | off += cdns->pdm.num_in; | ||
714 | ret = intel_create_dai(cdns, dais, INTEL_PDI_OUT, | ||
715 | cdns->pdm.num_out, off, stream->num_ch_out, false); | ||
716 | if (ret) | ||
717 | return ret; | ||
718 | |||
719 | off += cdns->pdm.num_bd; | ||
720 | ret = intel_create_dai(cdns, dais, INTEL_PDI_BD, | ||
721 | cdns->pdm.num_bd, off, stream->num_ch_bd, false); | ||
722 | if (ret) | ||
723 | return ret; | ||
724 | |||
725 | return snd_soc_register_component(cdns->dev, &dai_component, | ||
726 | dais, num_dai); | ||
727 | } | ||
728 | |||
237 | static int intel_prop_read(struct sdw_bus *bus) | 729 | static int intel_prop_read(struct sdw_bus *bus) |
238 | { | 730 | { |
239 | /* Initialize with default handler to read all DisCo properties */ | 731 | /* Initialize with default handler to read all DisCo properties */ |
@@ -252,11 +744,20 @@ static int intel_prop_read(struct sdw_bus *bus) | |||
252 | return 0; | 744 | return 0; |
253 | } | 745 | } |
254 | 746 | ||
747 | static struct sdw_master_ops sdw_intel_ops = { | ||
748 | .read_prop = sdw_master_read_prop, | ||
749 | .xfer_msg = cdns_xfer_msg, | ||
750 | .xfer_msg_defer = cdns_xfer_msg_defer, | ||
751 | .reset_page_addr = cdns_reset_page_addr, | ||
752 | .set_bus_conf = cdns_bus_conf, | ||
753 | }; | ||
754 | |||
255 | /* | 755 | /* |
256 | * probe and init | 756 | * probe and init |
257 | */ | 757 | */ |
258 | static int intel_probe(struct platform_device *pdev) | 758 | static int intel_probe(struct platform_device *pdev) |
259 | { | 759 | { |
760 | struct sdw_cdns_stream_config config; | ||
260 | struct sdw_intel *sdw; | 761 | struct sdw_intel *sdw; |
261 | int ret; | 762 | int ret; |
262 | 763 | ||
@@ -276,8 +777,11 @@ static int intel_probe(struct platform_device *pdev) | |||
276 | sdw_cdns_probe(&sdw->cdns); | 777 | sdw_cdns_probe(&sdw->cdns); |
277 | 778 | ||
278 | /* Set property read ops */ | 779 | /* Set property read ops */ |
279 | sdw_cdns_master_ops.read_prop = intel_prop_read; | 780 | sdw_intel_ops.read_prop = intel_prop_read; |
280 | sdw->cdns.bus.ops = &sdw_cdns_master_ops; | 781 | sdw->cdns.bus.ops = &sdw_intel_ops; |
782 | |||
783 | sdw_intel_ops.read_prop = intel_prop_read; | ||
784 | sdw->cdns.bus.ops = &sdw_intel_ops; | ||
281 | 785 | ||
282 | platform_set_drvdata(pdev, sdw); | 786 | platform_set_drvdata(pdev, sdw); |
283 | 787 | ||
@@ -296,9 +800,15 @@ static int intel_probe(struct platform_device *pdev) | |||
296 | goto err_init; | 800 | goto err_init; |
297 | 801 | ||
298 | ret = sdw_cdns_enable_interrupt(&sdw->cdns); | 802 | ret = sdw_cdns_enable_interrupt(&sdw->cdns); |
803 | |||
804 | /* Read the PDI config and initialize cadence PDI */ | ||
805 | intel_pdi_init(sdw, &config); | ||
806 | ret = sdw_cdns_pdi_init(&sdw->cdns, config); | ||
299 | if (ret) | 807 | if (ret) |
300 | goto err_init; | 808 | goto err_init; |
301 | 809 | ||
810 | intel_pdi_ch_update(sdw); | ||
811 | |||
302 | /* Acquire IRQ */ | 812 | /* Acquire IRQ */ |
303 | ret = request_threaded_irq(sdw->res->irq, sdw_cdns_irq, | 813 | ret = request_threaded_irq(sdw->res->irq, sdw_cdns_irq, |
304 | sdw_cdns_thread, IRQF_SHARED, KBUILD_MODNAME, | 814 | sdw_cdns_thread, IRQF_SHARED, KBUILD_MODNAME, |
@@ -309,8 +819,18 @@ static int intel_probe(struct platform_device *pdev) | |||
309 | goto err_init; | 819 | goto err_init; |
310 | } | 820 | } |
311 | 821 | ||
822 | /* Register DAIs */ | ||
823 | ret = intel_register_dai(sdw); | ||
824 | if (ret) { | ||
825 | dev_err(sdw->cdns.dev, "DAI registration failed: %d", ret); | ||
826 | snd_soc_unregister_component(sdw->cdns.dev); | ||
827 | goto err_dai; | ||
828 | } | ||
829 | |||
312 | return 0; | 830 | return 0; |
313 | 831 | ||
832 | err_dai: | ||
833 | free_irq(sdw->res->irq, sdw); | ||
314 | err_init: | 834 | err_init: |
315 | sdw_delete_bus_master(&sdw->cdns.bus); | 835 | sdw_delete_bus_master(&sdw->cdns.bus); |
316 | err_master_reg: | 836 | err_master_reg: |
@@ -324,6 +844,7 @@ static int intel_remove(struct platform_device *pdev) | |||
324 | sdw = platform_get_drvdata(pdev); | 844 | sdw = platform_get_drvdata(pdev); |
325 | 845 | ||
326 | free_irq(sdw->res->irq, sdw); | 846 | free_irq(sdw->res->irq, sdw); |
847 | snd_soc_unregister_component(sdw->cdns.dev); | ||
327 | sdw_delete_bus_master(&sdw->cdns.bus); | 848 | sdw_delete_bus_master(&sdw->cdns.bus); |
328 | 849 | ||
329 | return 0; | 850 | return 0; |
diff --git a/drivers/soundwire/intel.h b/drivers/soundwire/intel.h index ffa30d9535a2..c1a5bac6212e 100644 --- a/drivers/soundwire/intel.h +++ b/drivers/soundwire/intel.h | |||
@@ -10,6 +10,8 @@ | |||
10 | * @shim: Audio shim pointer | 10 | * @shim: Audio shim pointer |
11 | * @alh: ALH (Audio Link Hub) pointer | 11 | * @alh: ALH (Audio Link Hub) pointer |
12 | * @irq: Interrupt line | 12 | * @irq: Interrupt line |
13 | * @ops: Shim callback ops | ||
14 | * @arg: Shim callback ops argument | ||
13 | * | 15 | * |
14 | * This is set as pdata for each link instance. | 16 | * This is set as pdata for each link instance. |
15 | */ | 17 | */ |
@@ -18,6 +20,8 @@ struct sdw_intel_link_res { | |||
18 | void __iomem *shim; | 20 | void __iomem *shim; |
19 | void __iomem *alh; | 21 | void __iomem *alh; |
20 | int irq; | 22 | int irq; |
23 | const struct sdw_intel_ops *ops; | ||
24 | void *arg; | ||
21 | }; | 25 | }; |
22 | 26 | ||
23 | #endif /* __SDW_INTEL_LOCAL_H */ | 27 | #endif /* __SDW_INTEL_LOCAL_H */ |
diff --git a/drivers/soundwire/intel_init.c b/drivers/soundwire/intel_init.c index 6f2bb99526f2..d1ea6b4d0ad3 100644 --- a/drivers/soundwire/intel_init.c +++ b/drivers/soundwire/intel_init.c | |||
@@ -111,6 +111,9 @@ static struct sdw_intel_ctx | |||
111 | link->res.shim = res->mmio_base + SDW_SHIM_BASE; | 111 | link->res.shim = res->mmio_base + SDW_SHIM_BASE; |
112 | link->res.alh = res->mmio_base + SDW_ALH_BASE; | 112 | link->res.alh = res->mmio_base + SDW_ALH_BASE; |
113 | 113 | ||
114 | link->res.ops = res->ops; | ||
115 | link->res.arg = res->arg; | ||
116 | |||
114 | memset(&pdevinfo, 0, sizeof(pdevinfo)); | 117 | memset(&pdevinfo, 0, sizeof(pdevinfo)); |
115 | 118 | ||
116 | pdevinfo.parent = res->parent; | 119 | pdevinfo.parent = res->parent; |
diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c new file mode 100644 index 000000000000..8974a0fcda1b --- /dev/null +++ b/drivers/soundwire/stream.c | |||
@@ -0,0 +1,1479 @@ | |||
1 | // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) | ||
2 | // Copyright(c) 2015-18 Intel Corporation. | ||
3 | |||
4 | /* | ||
5 | * stream.c - SoundWire Bus stream operations. | ||
6 | */ | ||
7 | |||
8 | #include <linux/delay.h> | ||
9 | #include <linux/device.h> | ||
10 | #include <linux/init.h> | ||
11 | #include <linux/module.h> | ||
12 | #include <linux/mod_devicetable.h> | ||
13 | #include <linux/slab.h> | ||
14 | #include <linux/soundwire/sdw_registers.h> | ||
15 | #include <linux/soundwire/sdw.h> | ||
16 | #include "bus.h" | ||
17 | |||
18 | /* | ||
19 | * Array of supported rows and columns as per MIPI SoundWire Specification 1.1 | ||
20 | * | ||
21 | * The rows are arranged as per the array index value programmed | ||
22 | * in register. The index 15 has dummy value 0 in order to fill hole. | ||
23 | */ | ||
24 | int rows[SDW_FRAME_ROWS] = {48, 50, 60, 64, 75, 80, 125, 147, | ||
25 | 96, 100, 120, 128, 150, 160, 250, 0, | ||
26 | 192, 200, 240, 256, 72, 144, 90, 180}; | ||
27 | |||
28 | int cols[SDW_FRAME_COLS] = {2, 4, 6, 8, 10, 12, 14, 16}; | ||
29 | |||
30 | static int sdw_find_col_index(int col) | ||
31 | { | ||
32 | int i; | ||
33 | |||
34 | for (i = 0; i < SDW_FRAME_COLS; i++) { | ||
35 | if (cols[i] == col) | ||
36 | return i; | ||
37 | } | ||
38 | |||
39 | pr_warn("Requested column not found, selecting lowest column no: 2\n"); | ||
40 | return 0; | ||
41 | } | ||
42 | |||
43 | static int sdw_find_row_index(int row) | ||
44 | { | ||
45 | int i; | ||
46 | |||
47 | for (i = 0; i < SDW_FRAME_ROWS; i++) { | ||
48 | if (rows[i] == row) | ||
49 | return i; | ||
50 | } | ||
51 | |||
52 | pr_warn("Requested row not found, selecting lowest row no: 48\n"); | ||
53 | return 0; | ||
54 | } | ||
55 | static int _sdw_program_slave_port_params(struct sdw_bus *bus, | ||
56 | struct sdw_slave *slave, | ||
57 | struct sdw_transport_params *t_params, | ||
58 | enum sdw_dpn_type type) | ||
59 | { | ||
60 | u32 addr1, addr2, addr3, addr4; | ||
61 | int ret; | ||
62 | u16 wbuf; | ||
63 | |||
64 | if (bus->params.next_bank) { | ||
65 | addr1 = SDW_DPN_OFFSETCTRL2_B1(t_params->port_num); | ||
66 | addr2 = SDW_DPN_BLOCKCTRL3_B1(t_params->port_num); | ||
67 | addr3 = SDW_DPN_SAMPLECTRL2_B1(t_params->port_num); | ||
68 | addr4 = SDW_DPN_HCTRL_B1(t_params->port_num); | ||
69 | } else { | ||
70 | addr1 = SDW_DPN_OFFSETCTRL2_B0(t_params->port_num); | ||
71 | addr2 = SDW_DPN_BLOCKCTRL3_B0(t_params->port_num); | ||
72 | addr3 = SDW_DPN_SAMPLECTRL2_B0(t_params->port_num); | ||
73 | addr4 = SDW_DPN_HCTRL_B0(t_params->port_num); | ||
74 | } | ||
75 | |||
76 | /* Program DPN_OffsetCtrl2 registers */ | ||
77 | ret = sdw_write(slave, addr1, t_params->offset2); | ||
78 | if (ret < 0) { | ||
79 | dev_err(bus->dev, "DPN_OffsetCtrl2 register write failed"); | ||
80 | return ret; | ||
81 | } | ||
82 | |||
83 | /* Program DPN_BlockCtrl3 register */ | ||
84 | ret = sdw_write(slave, addr2, t_params->blk_pkg_mode); | ||
85 | if (ret < 0) { | ||
86 | dev_err(bus->dev, "DPN_BlockCtrl3 register write failed"); | ||
87 | return ret; | ||
88 | } | ||
89 | |||
90 | /* | ||
91 | * Data ports are FULL, SIMPLE and REDUCED. This function handles | ||
92 | * FULL and REDUCED only and and beyond this point only FULL is | ||
93 | * handled, so bail out if we are not FULL data port type | ||
94 | */ | ||
95 | if (type != SDW_DPN_FULL) | ||
96 | return ret; | ||
97 | |||
98 | /* Program DPN_SampleCtrl2 register */ | ||
99 | wbuf = (t_params->sample_interval - 1); | ||
100 | wbuf &= SDW_DPN_SAMPLECTRL_HIGH; | ||
101 | wbuf >>= SDW_REG_SHIFT(SDW_DPN_SAMPLECTRL_HIGH); | ||
102 | |||
103 | ret = sdw_write(slave, addr3, wbuf); | ||
104 | if (ret < 0) { | ||
105 | dev_err(bus->dev, "DPN_SampleCtrl2 register write failed"); | ||
106 | return ret; | ||
107 | } | ||
108 | |||
109 | /* Program DPN_HCtrl register */ | ||
110 | wbuf = t_params->hstart; | ||
111 | wbuf <<= SDW_REG_SHIFT(SDW_DPN_HCTRL_HSTART); | ||
112 | wbuf |= t_params->hstop; | ||
113 | |||
114 | ret = sdw_write(slave, addr4, wbuf); | ||
115 | if (ret < 0) | ||
116 | dev_err(bus->dev, "DPN_HCtrl register write failed"); | ||
117 | |||
118 | return ret; | ||
119 | } | ||
120 | |||
121 | static int sdw_program_slave_port_params(struct sdw_bus *bus, | ||
122 | struct sdw_slave_runtime *s_rt, | ||
123 | struct sdw_port_runtime *p_rt) | ||
124 | { | ||
125 | struct sdw_transport_params *t_params = &p_rt->transport_params; | ||
126 | struct sdw_port_params *p_params = &p_rt->port_params; | ||
127 | struct sdw_slave_prop *slave_prop = &s_rt->slave->prop; | ||
128 | u32 addr1, addr2, addr3, addr4, addr5, addr6; | ||
129 | struct sdw_dpn_prop *dpn_prop; | ||
130 | int ret; | ||
131 | u8 wbuf; | ||
132 | |||
133 | dpn_prop = sdw_get_slave_dpn_prop(s_rt->slave, | ||
134 | s_rt->direction, | ||
135 | t_params->port_num); | ||
136 | if (!dpn_prop) | ||
137 | return -EINVAL; | ||
138 | |||
139 | addr1 = SDW_DPN_PORTCTRL(t_params->port_num); | ||
140 | addr2 = SDW_DPN_BLOCKCTRL1(t_params->port_num); | ||
141 | |||
142 | if (bus->params.next_bank) { | ||
143 | addr3 = SDW_DPN_SAMPLECTRL1_B1(t_params->port_num); | ||
144 | addr4 = SDW_DPN_OFFSETCTRL1_B1(t_params->port_num); | ||
145 | addr5 = SDW_DPN_BLOCKCTRL2_B1(t_params->port_num); | ||
146 | addr6 = SDW_DPN_LANECTRL_B1(t_params->port_num); | ||
147 | |||
148 | } else { | ||
149 | addr3 = SDW_DPN_SAMPLECTRL1_B0(t_params->port_num); | ||
150 | addr4 = SDW_DPN_OFFSETCTRL1_B0(t_params->port_num); | ||
151 | addr5 = SDW_DPN_BLOCKCTRL2_B0(t_params->port_num); | ||
152 | addr6 = SDW_DPN_LANECTRL_B0(t_params->port_num); | ||
153 | } | ||
154 | |||
155 | /* Program DPN_PortCtrl register */ | ||
156 | wbuf = p_params->data_mode << SDW_REG_SHIFT(SDW_DPN_PORTCTRL_DATAMODE); | ||
157 | wbuf |= p_params->flow_mode; | ||
158 | |||
159 | ret = sdw_update(s_rt->slave, addr1, 0xF, wbuf); | ||
160 | if (ret < 0) { | ||
161 | dev_err(&s_rt->slave->dev, | ||
162 | "DPN_PortCtrl register write failed for port %d", | ||
163 | t_params->port_num); | ||
164 | return ret; | ||
165 | } | ||
166 | |||
167 | /* Program DPN_BlockCtrl1 register */ | ||
168 | ret = sdw_write(s_rt->slave, addr2, (p_params->bps - 1)); | ||
169 | if (ret < 0) { | ||
170 | dev_err(&s_rt->slave->dev, | ||
171 | "DPN_BlockCtrl1 register write failed for port %d", | ||
172 | t_params->port_num); | ||
173 | return ret; | ||
174 | } | ||
175 | |||
176 | /* Program DPN_SampleCtrl1 register */ | ||
177 | wbuf = (t_params->sample_interval - 1) & SDW_DPN_SAMPLECTRL_LOW; | ||
178 | ret = sdw_write(s_rt->slave, addr3, wbuf); | ||
179 | if (ret < 0) { | ||
180 | dev_err(&s_rt->slave->dev, | ||
181 | "DPN_SampleCtrl1 register write failed for port %d", | ||
182 | t_params->port_num); | ||
183 | return ret; | ||
184 | } | ||
185 | |||
186 | /* Program DPN_OffsetCtrl1 registers */ | ||
187 | ret = sdw_write(s_rt->slave, addr4, t_params->offset1); | ||
188 | if (ret < 0) { | ||
189 | dev_err(&s_rt->slave->dev, | ||
190 | "DPN_OffsetCtrl1 register write failed for port %d", | ||
191 | t_params->port_num); | ||
192 | return ret; | ||
193 | } | ||
194 | |||
195 | /* Program DPN_BlockCtrl2 register*/ | ||
196 | if (t_params->blk_grp_ctrl_valid) { | ||
197 | ret = sdw_write(s_rt->slave, addr5, t_params->blk_grp_ctrl); | ||
198 | if (ret < 0) { | ||
199 | dev_err(&s_rt->slave->dev, | ||
200 | "DPN_BlockCtrl2 reg write failed for port %d", | ||
201 | t_params->port_num); | ||
202 | return ret; | ||
203 | } | ||
204 | } | ||
205 | |||
206 | /* program DPN_LaneCtrl register */ | ||
207 | if (slave_prop->lane_control_support) { | ||
208 | ret = sdw_write(s_rt->slave, addr6, t_params->lane_ctrl); | ||
209 | if (ret < 0) { | ||
210 | dev_err(&s_rt->slave->dev, | ||
211 | "DPN_LaneCtrl register write failed for port %d", | ||
212 | t_params->port_num); | ||
213 | return ret; | ||
214 | } | ||
215 | } | ||
216 | |||
217 | if (dpn_prop->type != SDW_DPN_SIMPLE) { | ||
218 | ret = _sdw_program_slave_port_params(bus, s_rt->slave, | ||
219 | t_params, dpn_prop->type); | ||
220 | if (ret < 0) | ||
221 | dev_err(&s_rt->slave->dev, | ||
222 | "Transport reg write failed for port: %d", | ||
223 | t_params->port_num); | ||
224 | } | ||
225 | |||
226 | return ret; | ||
227 | } | ||
228 | |||
229 | static int sdw_program_master_port_params(struct sdw_bus *bus, | ||
230 | struct sdw_port_runtime *p_rt) | ||
231 | { | ||
232 | int ret; | ||
233 | |||
234 | /* | ||
235 | * we need to set transport and port parameters for the port. | ||
236 | * Transport parameters refers to the smaple interval, offsets and | ||
237 | * hstart/stop etc of the data. Port parameters refers to word | ||
238 | * length, flow mode etc of the port | ||
239 | */ | ||
240 | ret = bus->port_ops->dpn_set_port_transport_params(bus, | ||
241 | &p_rt->transport_params, | ||
242 | bus->params.next_bank); | ||
243 | if (ret < 0) | ||
244 | return ret; | ||
245 | |||
246 | return bus->port_ops->dpn_set_port_params(bus, | ||
247 | &p_rt->port_params, | ||
248 | bus->params.next_bank); | ||
249 | } | ||
250 | |||
251 | /** | ||
252 | * sdw_program_port_params() - Programs transport parameters of Master(s) | ||
253 | * and Slave(s) | ||
254 | * | ||
255 | * @m_rt: Master stream runtime | ||
256 | */ | ||
257 | static int sdw_program_port_params(struct sdw_master_runtime *m_rt) | ||
258 | { | ||
259 | struct sdw_slave_runtime *s_rt = NULL; | ||
260 | struct sdw_bus *bus = m_rt->bus; | ||
261 | struct sdw_port_runtime *p_rt; | ||
262 | int ret = 0; | ||
263 | |||
264 | /* Program transport & port parameters for Slave(s) */ | ||
265 | list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) { | ||
266 | list_for_each_entry(p_rt, &s_rt->port_list, port_node) { | ||
267 | ret = sdw_program_slave_port_params(bus, s_rt, p_rt); | ||
268 | if (ret < 0) | ||
269 | return ret; | ||
270 | } | ||
271 | } | ||
272 | |||
273 | /* Program transport & port parameters for Master(s) */ | ||
274 | list_for_each_entry(p_rt, &m_rt->port_list, port_node) { | ||
275 | ret = sdw_program_master_port_params(bus, p_rt); | ||
276 | if (ret < 0) | ||
277 | return ret; | ||
278 | } | ||
279 | |||
280 | return 0; | ||
281 | } | ||
282 | |||
283 | /** | ||
284 | * sdw_enable_disable_slave_ports: Enable/disable slave data port | ||
285 | * | ||
286 | * @bus: bus instance | ||
287 | * @s_rt: slave runtime | ||
288 | * @p_rt: port runtime | ||
289 | * @en: enable or disable operation | ||
290 | * | ||
291 | * This function only sets the enable/disable bits in the relevant bank, the | ||
292 | * actual enable/disable is done with a bank switch | ||
293 | */ | ||
294 | static int sdw_enable_disable_slave_ports(struct sdw_bus *bus, | ||
295 | struct sdw_slave_runtime *s_rt, | ||
296 | struct sdw_port_runtime *p_rt, bool en) | ||
297 | { | ||
298 | struct sdw_transport_params *t_params = &p_rt->transport_params; | ||
299 | u32 addr; | ||
300 | int ret; | ||
301 | |||
302 | if (bus->params.next_bank) | ||
303 | addr = SDW_DPN_CHANNELEN_B1(p_rt->num); | ||
304 | else | ||
305 | addr = SDW_DPN_CHANNELEN_B0(p_rt->num); | ||
306 | |||
307 | /* | ||
308 | * Since bus doesn't support sharing a port across two streams, | ||
309 | * it is safe to reset this register | ||
310 | */ | ||
311 | if (en) | ||
312 | ret = sdw_update(s_rt->slave, addr, 0xFF, p_rt->ch_mask); | ||
313 | else | ||
314 | ret = sdw_update(s_rt->slave, addr, 0xFF, 0x0); | ||
315 | |||
316 | if (ret < 0) | ||
317 | dev_err(&s_rt->slave->dev, | ||
318 | "Slave chn_en reg write failed:%d port:%d", | ||
319 | ret, t_params->port_num); | ||
320 | |||
321 | return ret; | ||
322 | } | ||
323 | |||
324 | static int sdw_enable_disable_master_ports(struct sdw_master_runtime *m_rt, | ||
325 | struct sdw_port_runtime *p_rt, bool en) | ||
326 | { | ||
327 | struct sdw_transport_params *t_params = &p_rt->transport_params; | ||
328 | struct sdw_bus *bus = m_rt->bus; | ||
329 | struct sdw_enable_ch enable_ch; | ||
330 | int ret = 0; | ||
331 | |||
332 | enable_ch.port_num = p_rt->num; | ||
333 | enable_ch.ch_mask = p_rt->ch_mask; | ||
334 | enable_ch.enable = en; | ||
335 | |||
336 | /* Perform Master port channel(s) enable/disable */ | ||
337 | if (bus->port_ops->dpn_port_enable_ch) { | ||
338 | ret = bus->port_ops->dpn_port_enable_ch(bus, | ||
339 | &enable_ch, bus->params.next_bank); | ||
340 | if (ret < 0) { | ||
341 | dev_err(bus->dev, | ||
342 | "Master chn_en write failed:%d port:%d", | ||
343 | ret, t_params->port_num); | ||
344 | return ret; | ||
345 | } | ||
346 | } else { | ||
347 | dev_err(bus->dev, | ||
348 | "dpn_port_enable_ch not supported, %s failed\n", | ||
349 | en ? "enable" : "disable"); | ||
350 | return -EINVAL; | ||
351 | } | ||
352 | |||
353 | return 0; | ||
354 | } | ||
355 | |||
356 | /** | ||
357 | * sdw_enable_disable_ports() - Enable/disable port(s) for Master and | ||
358 | * Slave(s) | ||
359 | * | ||
360 | * @m_rt: Master stream runtime | ||
361 | * @en: mode (enable/disable) | ||
362 | */ | ||
363 | static int sdw_enable_disable_ports(struct sdw_master_runtime *m_rt, bool en) | ||
364 | { | ||
365 | struct sdw_port_runtime *s_port, *m_port; | ||
366 | struct sdw_slave_runtime *s_rt = NULL; | ||
367 | int ret = 0; | ||
368 | |||
369 | /* Enable/Disable Slave port(s) */ | ||
370 | list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) { | ||
371 | list_for_each_entry(s_port, &s_rt->port_list, port_node) { | ||
372 | ret = sdw_enable_disable_slave_ports(m_rt->bus, s_rt, | ||
373 | s_port, en); | ||
374 | if (ret < 0) | ||
375 | return ret; | ||
376 | } | ||
377 | } | ||
378 | |||
379 | /* Enable/Disable Master port(s) */ | ||
380 | list_for_each_entry(m_port, &m_rt->port_list, port_node) { | ||
381 | ret = sdw_enable_disable_master_ports(m_rt, m_port, en); | ||
382 | if (ret < 0) | ||
383 | return ret; | ||
384 | } | ||
385 | |||
386 | return 0; | ||
387 | } | ||
388 | |||
389 | static int sdw_do_port_prep(struct sdw_slave_runtime *s_rt, | ||
390 | struct sdw_prepare_ch prep_ch, enum sdw_port_prep_ops cmd) | ||
391 | { | ||
392 | const struct sdw_slave_ops *ops = s_rt->slave->ops; | ||
393 | int ret; | ||
394 | |||
395 | if (ops->port_prep) { | ||
396 | ret = ops->port_prep(s_rt->slave, &prep_ch, cmd); | ||
397 | if (ret < 0) { | ||
398 | dev_err(&s_rt->slave->dev, | ||
399 | "Slave Port Prep cmd %d failed: %d", cmd, ret); | ||
400 | return ret; | ||
401 | } | ||
402 | } | ||
403 | |||
404 | return 0; | ||
405 | } | ||
406 | |||
407 | static int sdw_prep_deprep_slave_ports(struct sdw_bus *bus, | ||
408 | struct sdw_slave_runtime *s_rt, | ||
409 | struct sdw_port_runtime *p_rt, bool prep) | ||
410 | { | ||
411 | struct completion *port_ready = NULL; | ||
412 | struct sdw_dpn_prop *dpn_prop; | ||
413 | struct sdw_prepare_ch prep_ch; | ||
414 | unsigned int time_left; | ||
415 | bool intr = false; | ||
416 | int ret = 0, val; | ||
417 | u32 addr; | ||
418 | |||
419 | prep_ch.num = p_rt->num; | ||
420 | prep_ch.ch_mask = p_rt->ch_mask; | ||
421 | |||
422 | dpn_prop = sdw_get_slave_dpn_prop(s_rt->slave, | ||
423 | s_rt->direction, | ||
424 | prep_ch.num); | ||
425 | if (!dpn_prop) { | ||
426 | dev_err(bus->dev, | ||
427 | "Slave Port:%d properties not found", prep_ch.num); | ||
428 | return -EINVAL; | ||
429 | } | ||
430 | |||
431 | prep_ch.prepare = prep; | ||
432 | |||
433 | prep_ch.bank = bus->params.next_bank; | ||
434 | |||
435 | if (dpn_prop->device_interrupts || !dpn_prop->simple_ch_prep_sm) | ||
436 | intr = true; | ||
437 | |||
438 | /* | ||
439 | * Enable interrupt before Port prepare. | ||
440 | * For Port de-prepare, it is assumed that port | ||
441 | * was prepared earlier | ||
442 | */ | ||
443 | if (prep && intr) { | ||
444 | ret = sdw_configure_dpn_intr(s_rt->slave, p_rt->num, prep, | ||
445 | dpn_prop->device_interrupts); | ||
446 | if (ret < 0) | ||
447 | return ret; | ||
448 | } | ||
449 | |||
450 | /* Inform slave about the impending port prepare */ | ||
451 | sdw_do_port_prep(s_rt, prep_ch, SDW_OPS_PORT_PRE_PREP); | ||
452 | |||
453 | /* Prepare Slave port implementing CP_SM */ | ||
454 | if (!dpn_prop->simple_ch_prep_sm) { | ||
455 | addr = SDW_DPN_PREPARECTRL(p_rt->num); | ||
456 | |||
457 | if (prep) | ||
458 | ret = sdw_update(s_rt->slave, addr, | ||
459 | 0xFF, p_rt->ch_mask); | ||
460 | else | ||
461 | ret = sdw_update(s_rt->slave, addr, 0xFF, 0x0); | ||
462 | |||
463 | if (ret < 0) { | ||
464 | dev_err(&s_rt->slave->dev, | ||
465 | "Slave prep_ctrl reg write failed"); | ||
466 | return ret; | ||
467 | } | ||
468 | |||
469 | /* Wait for completion on port ready */ | ||
470 | port_ready = &s_rt->slave->port_ready[prep_ch.num]; | ||
471 | time_left = wait_for_completion_timeout(port_ready, | ||
472 | msecs_to_jiffies(dpn_prop->ch_prep_timeout)); | ||
473 | |||
474 | val = sdw_read(s_rt->slave, SDW_DPN_PREPARESTATUS(p_rt->num)); | ||
475 | val &= p_rt->ch_mask; | ||
476 | if (!time_left || val) { | ||
477 | dev_err(&s_rt->slave->dev, | ||
478 | "Chn prep failed for port:%d", prep_ch.num); | ||
479 | return -ETIMEDOUT; | ||
480 | } | ||
481 | } | ||
482 | |||
483 | /* Inform slaves about ports prepared */ | ||
484 | sdw_do_port_prep(s_rt, prep_ch, SDW_OPS_PORT_POST_PREP); | ||
485 | |||
486 | /* Disable interrupt after Port de-prepare */ | ||
487 | if (!prep && intr) | ||
488 | ret = sdw_configure_dpn_intr(s_rt->slave, p_rt->num, prep, | ||
489 | dpn_prop->device_interrupts); | ||
490 | |||
491 | return ret; | ||
492 | } | ||
493 | |||
494 | static int sdw_prep_deprep_master_ports(struct sdw_master_runtime *m_rt, | ||
495 | struct sdw_port_runtime *p_rt, bool prep) | ||
496 | { | ||
497 | struct sdw_transport_params *t_params = &p_rt->transport_params; | ||
498 | struct sdw_bus *bus = m_rt->bus; | ||
499 | const struct sdw_master_port_ops *ops = bus->port_ops; | ||
500 | struct sdw_prepare_ch prep_ch; | ||
501 | int ret = 0; | ||
502 | |||
503 | prep_ch.num = p_rt->num; | ||
504 | prep_ch.ch_mask = p_rt->ch_mask; | ||
505 | prep_ch.prepare = prep; /* Prepare/De-prepare */ | ||
506 | prep_ch.bank = bus->params.next_bank; | ||
507 | |||
508 | /* Pre-prepare/Pre-deprepare port(s) */ | ||
509 | if (ops->dpn_port_prep) { | ||
510 | ret = ops->dpn_port_prep(bus, &prep_ch); | ||
511 | if (ret < 0) { | ||
512 | dev_err(bus->dev, "Port prepare failed for port:%d", | ||
513 | t_params->port_num); | ||
514 | return ret; | ||
515 | } | ||
516 | } | ||
517 | |||
518 | return ret; | ||
519 | } | ||
520 | |||
521 | /** | ||
522 | * sdw_prep_deprep_ports() - Prepare/De-prepare port(s) for Master(s) and | ||
523 | * Slave(s) | ||
524 | * | ||
525 | * @m_rt: Master runtime handle | ||
526 | * @prep: Prepare or De-prepare | ||
527 | */ | ||
528 | static int sdw_prep_deprep_ports(struct sdw_master_runtime *m_rt, bool prep) | ||
529 | { | ||
530 | struct sdw_slave_runtime *s_rt = NULL; | ||
531 | struct sdw_port_runtime *p_rt; | ||
532 | int ret = 0; | ||
533 | |||
534 | /* Prepare/De-prepare Slave port(s) */ | ||
535 | list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) { | ||
536 | list_for_each_entry(p_rt, &s_rt->port_list, port_node) { | ||
537 | ret = sdw_prep_deprep_slave_ports(m_rt->bus, s_rt, | ||
538 | p_rt, prep); | ||
539 | if (ret < 0) | ||
540 | return ret; | ||
541 | } | ||
542 | } | ||
543 | |||
544 | /* Prepare/De-prepare Master port(s) */ | ||
545 | list_for_each_entry(p_rt, &m_rt->port_list, port_node) { | ||
546 | ret = sdw_prep_deprep_master_ports(m_rt, p_rt, prep); | ||
547 | if (ret < 0) | ||
548 | return ret; | ||
549 | } | ||
550 | |||
551 | return ret; | ||
552 | } | ||
553 | |||
554 | /** | ||
555 | * sdw_notify_config() - Notify bus configuration | ||
556 | * | ||
557 | * @m_rt: Master runtime handle | ||
558 | * | ||
559 | * This function notifies the Master(s) and Slave(s) of the | ||
560 | * new bus configuration. | ||
561 | */ | ||
562 | static int sdw_notify_config(struct sdw_master_runtime *m_rt) | ||
563 | { | ||
564 | struct sdw_slave_runtime *s_rt; | ||
565 | struct sdw_bus *bus = m_rt->bus; | ||
566 | struct sdw_slave *slave; | ||
567 | int ret = 0; | ||
568 | |||
569 | if (bus->ops->set_bus_conf) { | ||
570 | ret = bus->ops->set_bus_conf(bus, &bus->params); | ||
571 | if (ret < 0) | ||
572 | return ret; | ||
573 | } | ||
574 | |||
575 | list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) { | ||
576 | slave = s_rt->slave; | ||
577 | |||
578 | if (slave->ops->bus_config) { | ||
579 | ret = slave->ops->bus_config(slave, &bus->params); | ||
580 | if (ret < 0) | ||
581 | dev_err(bus->dev, "Notify Slave: %d failed", | ||
582 | slave->dev_num); | ||
583 | return ret; | ||
584 | } | ||
585 | } | ||
586 | |||
587 | return ret; | ||
588 | } | ||
589 | |||
590 | /** | ||
591 | * sdw_program_params() - Program transport and port parameters for Master(s) | ||
592 | * and Slave(s) | ||
593 | * | ||
594 | * @bus: SDW bus instance | ||
595 | */ | ||
596 | static int sdw_program_params(struct sdw_bus *bus) | ||
597 | { | ||
598 | struct sdw_master_runtime *m_rt = NULL; | ||
599 | int ret = 0; | ||
600 | |||
601 | list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) { | ||
602 | ret = sdw_program_port_params(m_rt); | ||
603 | if (ret < 0) { | ||
604 | dev_err(bus->dev, | ||
605 | "Program transport params failed: %d", ret); | ||
606 | return ret; | ||
607 | } | ||
608 | |||
609 | ret = sdw_notify_config(m_rt); | ||
610 | if (ret < 0) { | ||
611 | dev_err(bus->dev, "Notify bus config failed: %d", ret); | ||
612 | return ret; | ||
613 | } | ||
614 | |||
615 | /* Enable port(s) on alternate bank for all active streams */ | ||
616 | if (m_rt->stream->state != SDW_STREAM_ENABLED) | ||
617 | continue; | ||
618 | |||
619 | ret = sdw_enable_disable_ports(m_rt, true); | ||
620 | if (ret < 0) { | ||
621 | dev_err(bus->dev, "Enable channel failed: %d", ret); | ||
622 | return ret; | ||
623 | } | ||
624 | } | ||
625 | |||
626 | return ret; | ||
627 | } | ||
628 | |||
629 | static int sdw_bank_switch(struct sdw_bus *bus) | ||
630 | { | ||
631 | int col_index, row_index; | ||
632 | struct sdw_msg *wr_msg; | ||
633 | u8 *wbuf = NULL; | ||
634 | int ret = 0; | ||
635 | u16 addr; | ||
636 | |||
637 | wr_msg = kzalloc(sizeof(*wr_msg), GFP_KERNEL); | ||
638 | if (!wr_msg) | ||
639 | return -ENOMEM; | ||
640 | |||
641 | wbuf = kzalloc(sizeof(*wbuf), GFP_KERNEL); | ||
642 | if (!wbuf) { | ||
643 | ret = -ENOMEM; | ||
644 | goto error_1; | ||
645 | } | ||
646 | |||
647 | /* Get row and column index to program register */ | ||
648 | col_index = sdw_find_col_index(bus->params.col); | ||
649 | row_index = sdw_find_row_index(bus->params.row); | ||
650 | wbuf[0] = col_index | (row_index << 3); | ||
651 | |||
652 | if (bus->params.next_bank) | ||
653 | addr = SDW_SCP_FRAMECTRL_B1; | ||
654 | else | ||
655 | addr = SDW_SCP_FRAMECTRL_B0; | ||
656 | |||
657 | sdw_fill_msg(wr_msg, NULL, addr, 1, SDW_BROADCAST_DEV_NUM, | ||
658 | SDW_MSG_FLAG_WRITE, wbuf); | ||
659 | wr_msg->ssp_sync = true; | ||
660 | |||
661 | ret = sdw_transfer(bus, wr_msg); | ||
662 | if (ret < 0) { | ||
663 | dev_err(bus->dev, "Slave frame_ctrl reg write failed"); | ||
664 | goto error; | ||
665 | } | ||
666 | |||
667 | kfree(wr_msg); | ||
668 | kfree(wbuf); | ||
669 | bus->defer_msg.msg = NULL; | ||
670 | bus->params.curr_bank = !bus->params.curr_bank; | ||
671 | bus->params.next_bank = !bus->params.next_bank; | ||
672 | |||
673 | return 0; | ||
674 | |||
675 | error: | ||
676 | kfree(wbuf); | ||
677 | error_1: | ||
678 | kfree(wr_msg); | ||
679 | return ret; | ||
680 | } | ||
681 | |||
682 | static int do_bank_switch(struct sdw_stream_runtime *stream) | ||
683 | { | ||
684 | struct sdw_master_runtime *m_rt = stream->m_rt; | ||
685 | const struct sdw_master_ops *ops; | ||
686 | struct sdw_bus *bus = m_rt->bus; | ||
687 | int ret = 0; | ||
688 | |||
689 | ops = bus->ops; | ||
690 | |||
691 | /* Pre-bank switch */ | ||
692 | if (ops->pre_bank_switch) { | ||
693 | ret = ops->pre_bank_switch(bus); | ||
694 | if (ret < 0) { | ||
695 | dev_err(bus->dev, "Pre bank switch op failed: %d", ret); | ||
696 | return ret; | ||
697 | } | ||
698 | } | ||
699 | |||
700 | /* Bank switch */ | ||
701 | ret = sdw_bank_switch(bus); | ||
702 | if (ret < 0) { | ||
703 | dev_err(bus->dev, "Bank switch failed: %d", ret); | ||
704 | return ret; | ||
705 | } | ||
706 | |||
707 | /* Post-bank switch */ | ||
708 | if (ops->post_bank_switch) { | ||
709 | ret = ops->post_bank_switch(bus); | ||
710 | if (ret < 0) { | ||
711 | dev_err(bus->dev, | ||
712 | "Post bank switch op failed: %d", ret); | ||
713 | } | ||
714 | } | ||
715 | |||
716 | return ret; | ||
717 | } | ||
718 | |||
719 | /** | ||
720 | * sdw_release_stream() - Free the assigned stream runtime | ||
721 | * | ||
722 | * @stream: SoundWire stream runtime | ||
723 | * | ||
724 | * sdw_release_stream should be called only once per stream | ||
725 | */ | ||
726 | void sdw_release_stream(struct sdw_stream_runtime *stream) | ||
727 | { | ||
728 | kfree(stream); | ||
729 | } | ||
730 | EXPORT_SYMBOL(sdw_release_stream); | ||
731 | |||
732 | /** | ||
733 | * sdw_alloc_stream() - Allocate and return stream runtime | ||
734 | * | ||
735 | * @stream_name: SoundWire stream name | ||
736 | * | ||
737 | * Allocates a SoundWire stream runtime instance. | ||
738 | * sdw_alloc_stream should be called only once per stream. Typically | ||
739 | * invoked from ALSA/ASoC machine/platform driver. | ||
740 | */ | ||
741 | struct sdw_stream_runtime *sdw_alloc_stream(char *stream_name) | ||
742 | { | ||
743 | struct sdw_stream_runtime *stream; | ||
744 | |||
745 | stream = kzalloc(sizeof(*stream), GFP_KERNEL); | ||
746 | if (!stream) | ||
747 | return NULL; | ||
748 | |||
749 | stream->name = stream_name; | ||
750 | stream->state = SDW_STREAM_ALLOCATED; | ||
751 | |||
752 | return stream; | ||
753 | } | ||
754 | EXPORT_SYMBOL(sdw_alloc_stream); | ||
755 | |||
756 | /** | ||
757 | * sdw_alloc_master_rt() - Allocates and initialize Master runtime handle | ||
758 | * | ||
759 | * @bus: SDW bus instance | ||
760 | * @stream_config: Stream configuration | ||
761 | * @stream: Stream runtime handle. | ||
762 | * | ||
763 | * This function is to be called with bus_lock held. | ||
764 | */ | ||
765 | static struct sdw_master_runtime | ||
766 | *sdw_alloc_master_rt(struct sdw_bus *bus, | ||
767 | struct sdw_stream_config *stream_config, | ||
768 | struct sdw_stream_runtime *stream) | ||
769 | { | ||
770 | struct sdw_master_runtime *m_rt; | ||
771 | |||
772 | m_rt = stream->m_rt; | ||
773 | |||
774 | /* | ||
775 | * check if Master is already allocated (as a result of Slave adding | ||
776 | * it first), if so skip allocation and go to configure | ||
777 | */ | ||
778 | if (m_rt) | ||
779 | goto stream_config; | ||
780 | |||
781 | m_rt = kzalloc(sizeof(*m_rt), GFP_KERNEL); | ||
782 | if (!m_rt) | ||
783 | return NULL; | ||
784 | |||
785 | /* Initialization of Master runtime handle */ | ||
786 | INIT_LIST_HEAD(&m_rt->port_list); | ||
787 | INIT_LIST_HEAD(&m_rt->slave_rt_list); | ||
788 | stream->m_rt = m_rt; | ||
789 | |||
790 | list_add_tail(&m_rt->bus_node, &bus->m_rt_list); | ||
791 | |||
792 | stream_config: | ||
793 | m_rt->ch_count = stream_config->ch_count; | ||
794 | m_rt->bus = bus; | ||
795 | m_rt->stream = stream; | ||
796 | m_rt->direction = stream_config->direction; | ||
797 | |||
798 | return m_rt; | ||
799 | } | ||
800 | |||
801 | /** | ||
802 | * sdw_alloc_slave_rt() - Allocate and initialize Slave runtime handle. | ||
803 | * | ||
804 | * @slave: Slave handle | ||
805 | * @stream_config: Stream configuration | ||
806 | * @stream: Stream runtime handle | ||
807 | * | ||
808 | * This function is to be called with bus_lock held. | ||
809 | */ | ||
810 | static struct sdw_slave_runtime | ||
811 | *sdw_alloc_slave_rt(struct sdw_slave *slave, | ||
812 | struct sdw_stream_config *stream_config, | ||
813 | struct sdw_stream_runtime *stream) | ||
814 | { | ||
815 | struct sdw_slave_runtime *s_rt = NULL; | ||
816 | |||
817 | s_rt = kzalloc(sizeof(*s_rt), GFP_KERNEL); | ||
818 | if (!s_rt) | ||
819 | return NULL; | ||
820 | |||
821 | INIT_LIST_HEAD(&s_rt->port_list); | ||
822 | s_rt->ch_count = stream_config->ch_count; | ||
823 | s_rt->direction = stream_config->direction; | ||
824 | s_rt->slave = slave; | ||
825 | |||
826 | return s_rt; | ||
827 | } | ||
828 | |||
829 | static void sdw_master_port_release(struct sdw_bus *bus, | ||
830 | struct sdw_master_runtime *m_rt) | ||
831 | { | ||
832 | struct sdw_port_runtime *p_rt, *_p_rt; | ||
833 | |||
834 | list_for_each_entry_safe(p_rt, _p_rt, | ||
835 | &m_rt->port_list, port_node) { | ||
836 | list_del(&p_rt->port_node); | ||
837 | kfree(p_rt); | ||
838 | } | ||
839 | } | ||
840 | |||
841 | static void sdw_slave_port_release(struct sdw_bus *bus, | ||
842 | struct sdw_slave *slave, | ||
843 | struct sdw_stream_runtime *stream) | ||
844 | { | ||
845 | struct sdw_port_runtime *p_rt, *_p_rt; | ||
846 | struct sdw_master_runtime *m_rt = stream->m_rt; | ||
847 | struct sdw_slave_runtime *s_rt; | ||
848 | |||
849 | list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) { | ||
850 | if (s_rt->slave != slave) | ||
851 | continue; | ||
852 | |||
853 | list_for_each_entry_safe(p_rt, _p_rt, | ||
854 | &s_rt->port_list, port_node) { | ||
855 | list_del(&p_rt->port_node); | ||
856 | kfree(p_rt); | ||
857 | } | ||
858 | } | ||
859 | } | ||
860 | |||
861 | /** | ||
862 | * sdw_release_slave_stream() - Free Slave(s) runtime handle | ||
863 | * | ||
864 | * @slave: Slave handle. | ||
865 | * @stream: Stream runtime handle. | ||
866 | * | ||
867 | * This function is to be called with bus_lock held. | ||
868 | */ | ||
869 | static void sdw_release_slave_stream(struct sdw_slave *slave, | ||
870 | struct sdw_stream_runtime *stream) | ||
871 | { | ||
872 | struct sdw_slave_runtime *s_rt, *_s_rt; | ||
873 | struct sdw_master_runtime *m_rt = stream->m_rt; | ||
874 | |||
875 | /* Retrieve Slave runtime handle */ | ||
876 | list_for_each_entry_safe(s_rt, _s_rt, | ||
877 | &m_rt->slave_rt_list, m_rt_node) { | ||
878 | |||
879 | if (s_rt->slave == slave) { | ||
880 | list_del(&s_rt->m_rt_node); | ||
881 | kfree(s_rt); | ||
882 | return; | ||
883 | } | ||
884 | } | ||
885 | } | ||
886 | |||
887 | /** | ||
888 | * sdw_release_master_stream() - Free Master runtime handle | ||
889 | * | ||
890 | * @stream: Stream runtime handle. | ||
891 | * | ||
892 | * This function is to be called with bus_lock held | ||
893 | * It frees the Master runtime handle and associated Slave(s) runtime | ||
894 | * handle. If this is called first then sdw_release_slave_stream() will have | ||
895 | * no effect as Slave(s) runtime handle would already be freed up. | ||
896 | */ | ||
897 | static void sdw_release_master_stream(struct sdw_stream_runtime *stream) | ||
898 | { | ||
899 | struct sdw_master_runtime *m_rt = stream->m_rt; | ||
900 | struct sdw_slave_runtime *s_rt, *_s_rt; | ||
901 | |||
902 | list_for_each_entry_safe(s_rt, _s_rt, | ||
903 | &m_rt->slave_rt_list, m_rt_node) | ||
904 | sdw_stream_remove_slave(s_rt->slave, stream); | ||
905 | |||
906 | list_del(&m_rt->bus_node); | ||
907 | } | ||
908 | |||
909 | /** | ||
910 | * sdw_stream_remove_master() - Remove master from sdw_stream | ||
911 | * | ||
912 | * @bus: SDW Bus instance | ||
913 | * @stream: SoundWire stream | ||
914 | * | ||
915 | * This removes and frees port_rt and master_rt from a stream | ||
916 | */ | ||
917 | int sdw_stream_remove_master(struct sdw_bus *bus, | ||
918 | struct sdw_stream_runtime *stream) | ||
919 | { | ||
920 | mutex_lock(&bus->bus_lock); | ||
921 | |||
922 | sdw_release_master_stream(stream); | ||
923 | sdw_master_port_release(bus, stream->m_rt); | ||
924 | stream->state = SDW_STREAM_RELEASED; | ||
925 | kfree(stream->m_rt); | ||
926 | stream->m_rt = NULL; | ||
927 | |||
928 | mutex_unlock(&bus->bus_lock); | ||
929 | |||
930 | return 0; | ||
931 | } | ||
932 | EXPORT_SYMBOL(sdw_stream_remove_master); | ||
933 | |||
934 | /** | ||
935 | * sdw_stream_remove_slave() - Remove slave from sdw_stream | ||
936 | * | ||
937 | * @slave: SDW Slave instance | ||
938 | * @stream: SoundWire stream | ||
939 | * | ||
940 | * This removes and frees port_rt and slave_rt from a stream | ||
941 | */ | ||
942 | int sdw_stream_remove_slave(struct sdw_slave *slave, | ||
943 | struct sdw_stream_runtime *stream) | ||
944 | { | ||
945 | mutex_lock(&slave->bus->bus_lock); | ||
946 | |||
947 | sdw_slave_port_release(slave->bus, slave, stream); | ||
948 | sdw_release_slave_stream(slave, stream); | ||
949 | |||
950 | mutex_unlock(&slave->bus->bus_lock); | ||
951 | |||
952 | return 0; | ||
953 | } | ||
954 | EXPORT_SYMBOL(sdw_stream_remove_slave); | ||
955 | |||
956 | /** | ||
957 | * sdw_config_stream() - Configure the allocated stream | ||
958 | * | ||
959 | * @dev: SDW device | ||
960 | * @stream: SoundWire stream | ||
961 | * @stream_config: Stream configuration for audio stream | ||
962 | * @is_slave: is API called from Slave or Master | ||
963 | * | ||
964 | * This function is to be called with bus_lock held. | ||
965 | */ | ||
966 | static int sdw_config_stream(struct device *dev, | ||
967 | struct sdw_stream_runtime *stream, | ||
968 | struct sdw_stream_config *stream_config, bool is_slave) | ||
969 | { | ||
970 | /* | ||
971 | * Update the stream rate, channel and bps based on data | ||
972 | * source. For more than one data source (multilink), | ||
973 | * match the rate, bps, stream type and increment number of channels. | ||
974 | * | ||
975 | * If rate/bps is zero, it means the values are not set, so skip | ||
976 | * comparison and allow the value to be set and stored in stream | ||
977 | */ | ||
978 | if (stream->params.rate && | ||
979 | stream->params.rate != stream_config->frame_rate) { | ||
980 | dev_err(dev, "rate not matching, stream:%s", stream->name); | ||
981 | return -EINVAL; | ||
982 | } | ||
983 | |||
984 | if (stream->params.bps && | ||
985 | stream->params.bps != stream_config->bps) { | ||
986 | dev_err(dev, "bps not matching, stream:%s", stream->name); | ||
987 | return -EINVAL; | ||
988 | } | ||
989 | |||
990 | stream->type = stream_config->type; | ||
991 | stream->params.rate = stream_config->frame_rate; | ||
992 | stream->params.bps = stream_config->bps; | ||
993 | |||
994 | /* TODO: Update this check during Device-device support */ | ||
995 | if (is_slave) | ||
996 | stream->params.ch_count += stream_config->ch_count; | ||
997 | |||
998 | return 0; | ||
999 | } | ||
1000 | |||
1001 | static int sdw_is_valid_port_range(struct device *dev, | ||
1002 | struct sdw_port_runtime *p_rt) | ||
1003 | { | ||
1004 | if (!SDW_VALID_PORT_RANGE(p_rt->num)) { | ||
1005 | dev_err(dev, | ||
1006 | "SoundWire: Invalid port number :%d", p_rt->num); | ||
1007 | return -EINVAL; | ||
1008 | } | ||
1009 | |||
1010 | return 0; | ||
1011 | } | ||
1012 | |||
1013 | static struct sdw_port_runtime *sdw_port_alloc(struct device *dev, | ||
1014 | struct sdw_port_config *port_config, | ||
1015 | int port_index) | ||
1016 | { | ||
1017 | struct sdw_port_runtime *p_rt; | ||
1018 | |||
1019 | p_rt = kzalloc(sizeof(*p_rt), GFP_KERNEL); | ||
1020 | if (!p_rt) | ||
1021 | return NULL; | ||
1022 | |||
1023 | p_rt->ch_mask = port_config[port_index].ch_mask; | ||
1024 | p_rt->num = port_config[port_index].num; | ||
1025 | |||
1026 | return p_rt; | ||
1027 | } | ||
1028 | |||
1029 | static int sdw_master_port_config(struct sdw_bus *bus, | ||
1030 | struct sdw_master_runtime *m_rt, | ||
1031 | struct sdw_port_config *port_config, | ||
1032 | unsigned int num_ports) | ||
1033 | { | ||
1034 | struct sdw_port_runtime *p_rt; | ||
1035 | int i; | ||
1036 | |||
1037 | /* Iterate for number of ports to perform initialization */ | ||
1038 | for (i = 0; i < num_ports; i++) { | ||
1039 | p_rt = sdw_port_alloc(bus->dev, port_config, i); | ||
1040 | if (!p_rt) | ||
1041 | return -ENOMEM; | ||
1042 | |||
1043 | /* | ||
1044 | * TODO: Check port capabilities for requested | ||
1045 | * configuration (audio mode support) | ||
1046 | */ | ||
1047 | |||
1048 | list_add_tail(&p_rt->port_node, &m_rt->port_list); | ||
1049 | } | ||
1050 | |||
1051 | return 0; | ||
1052 | } | ||
1053 | |||
1054 | static int sdw_slave_port_config(struct sdw_slave *slave, | ||
1055 | struct sdw_slave_runtime *s_rt, | ||
1056 | struct sdw_port_config *port_config, | ||
1057 | unsigned int num_config) | ||
1058 | { | ||
1059 | struct sdw_port_runtime *p_rt; | ||
1060 | int i, ret; | ||
1061 | |||
1062 | /* Iterate for number of ports to perform initialization */ | ||
1063 | for (i = 0; i < num_config; i++) { | ||
1064 | p_rt = sdw_port_alloc(&slave->dev, port_config, i); | ||
1065 | if (!p_rt) | ||
1066 | return -ENOMEM; | ||
1067 | |||
1068 | /* | ||
1069 | * TODO: Check valid port range as defined by DisCo/ | ||
1070 | * slave | ||
1071 | */ | ||
1072 | ret = sdw_is_valid_port_range(&slave->dev, p_rt); | ||
1073 | if (ret < 0) { | ||
1074 | kfree(p_rt); | ||
1075 | return ret; | ||
1076 | } | ||
1077 | |||
1078 | /* | ||
1079 | * TODO: Check port capabilities for requested | ||
1080 | * configuration (audio mode support) | ||
1081 | */ | ||
1082 | |||
1083 | list_add_tail(&p_rt->port_node, &s_rt->port_list); | ||
1084 | } | ||
1085 | |||
1086 | return 0; | ||
1087 | } | ||
1088 | |||
1089 | /** | ||
1090 | * sdw_stream_add_master() - Allocate and add master runtime to a stream | ||
1091 | * | ||
1092 | * @bus: SDW Bus instance | ||
1093 | * @stream_config: Stream configuration for audio stream | ||
1094 | * @port_config: Port configuration for audio stream | ||
1095 | * @num_ports: Number of ports | ||
1096 | * @stream: SoundWire stream | ||
1097 | */ | ||
1098 | int sdw_stream_add_master(struct sdw_bus *bus, | ||
1099 | struct sdw_stream_config *stream_config, | ||
1100 | struct sdw_port_config *port_config, | ||
1101 | unsigned int num_ports, | ||
1102 | struct sdw_stream_runtime *stream) | ||
1103 | { | ||
1104 | struct sdw_master_runtime *m_rt = NULL; | ||
1105 | int ret; | ||
1106 | |||
1107 | mutex_lock(&bus->bus_lock); | ||
1108 | |||
1109 | m_rt = sdw_alloc_master_rt(bus, stream_config, stream); | ||
1110 | if (!m_rt) { | ||
1111 | dev_err(bus->dev, | ||
1112 | "Master runtime config failed for stream:%s", | ||
1113 | stream->name); | ||
1114 | ret = -ENOMEM; | ||
1115 | goto error; | ||
1116 | } | ||
1117 | |||
1118 | ret = sdw_config_stream(bus->dev, stream, stream_config, false); | ||
1119 | if (ret) | ||
1120 | goto stream_error; | ||
1121 | |||
1122 | ret = sdw_master_port_config(bus, m_rt, port_config, num_ports); | ||
1123 | if (ret) | ||
1124 | goto stream_error; | ||
1125 | |||
1126 | stream->state = SDW_STREAM_CONFIGURED; | ||
1127 | |||
1128 | stream_error: | ||
1129 | sdw_release_master_stream(stream); | ||
1130 | error: | ||
1131 | mutex_unlock(&bus->bus_lock); | ||
1132 | return ret; | ||
1133 | } | ||
1134 | EXPORT_SYMBOL(sdw_stream_add_master); | ||
1135 | |||
1136 | /** | ||
1137 | * sdw_stream_add_slave() - Allocate and add master/slave runtime to a stream | ||
1138 | * | ||
1139 | * @slave: SDW Slave instance | ||
1140 | * @stream_config: Stream configuration for audio stream | ||
1141 | * @stream: SoundWire stream | ||
1142 | * @port_config: Port configuration for audio stream | ||
1143 | * @num_ports: Number of ports | ||
1144 | */ | ||
1145 | int sdw_stream_add_slave(struct sdw_slave *slave, | ||
1146 | struct sdw_stream_config *stream_config, | ||
1147 | struct sdw_port_config *port_config, | ||
1148 | unsigned int num_ports, | ||
1149 | struct sdw_stream_runtime *stream) | ||
1150 | { | ||
1151 | struct sdw_slave_runtime *s_rt; | ||
1152 | struct sdw_master_runtime *m_rt; | ||
1153 | int ret; | ||
1154 | |||
1155 | mutex_lock(&slave->bus->bus_lock); | ||
1156 | |||
1157 | /* | ||
1158 | * If this API is invoked by Slave first then m_rt is not valid. | ||
1159 | * So, allocate m_rt and add Slave to it. | ||
1160 | */ | ||
1161 | m_rt = sdw_alloc_master_rt(slave->bus, stream_config, stream); | ||
1162 | if (!m_rt) { | ||
1163 | dev_err(&slave->dev, | ||
1164 | "alloc master runtime failed for stream:%s", | ||
1165 | stream->name); | ||
1166 | ret = -ENOMEM; | ||
1167 | goto error; | ||
1168 | } | ||
1169 | |||
1170 | s_rt = sdw_alloc_slave_rt(slave, stream_config, stream); | ||
1171 | if (!s_rt) { | ||
1172 | dev_err(&slave->dev, | ||
1173 | "Slave runtime config failed for stream:%s", | ||
1174 | stream->name); | ||
1175 | ret = -ENOMEM; | ||
1176 | goto stream_error; | ||
1177 | } | ||
1178 | |||
1179 | ret = sdw_config_stream(&slave->dev, stream, stream_config, true); | ||
1180 | if (ret) | ||
1181 | goto stream_error; | ||
1182 | |||
1183 | list_add_tail(&s_rt->m_rt_node, &m_rt->slave_rt_list); | ||
1184 | |||
1185 | ret = sdw_slave_port_config(slave, s_rt, port_config, num_ports); | ||
1186 | if (ret) | ||
1187 | goto stream_error; | ||
1188 | |||
1189 | stream->state = SDW_STREAM_CONFIGURED; | ||
1190 | goto error; | ||
1191 | |||
1192 | stream_error: | ||
1193 | /* | ||
1194 | * we hit error so cleanup the stream, release all Slave(s) and | ||
1195 | * Master runtime | ||
1196 | */ | ||
1197 | sdw_release_master_stream(stream); | ||
1198 | error: | ||
1199 | mutex_unlock(&slave->bus->bus_lock); | ||
1200 | return ret; | ||
1201 | } | ||
1202 | EXPORT_SYMBOL(sdw_stream_add_slave); | ||
1203 | |||
1204 | /** | ||
1205 | * sdw_get_slave_dpn_prop() - Get Slave port capabilities | ||
1206 | * | ||
1207 | * @slave: Slave handle | ||
1208 | * @direction: Data direction. | ||
1209 | * @port_num: Port number | ||
1210 | */ | ||
1211 | struct sdw_dpn_prop *sdw_get_slave_dpn_prop(struct sdw_slave *slave, | ||
1212 | enum sdw_data_direction direction, | ||
1213 | unsigned int port_num) | ||
1214 | { | ||
1215 | struct sdw_dpn_prop *dpn_prop; | ||
1216 | u8 num_ports; | ||
1217 | int i; | ||
1218 | |||
1219 | if (direction == SDW_DATA_DIR_TX) { | ||
1220 | num_ports = hweight32(slave->prop.source_ports); | ||
1221 | dpn_prop = slave->prop.src_dpn_prop; | ||
1222 | } else { | ||
1223 | num_ports = hweight32(slave->prop.sink_ports); | ||
1224 | dpn_prop = slave->prop.sink_dpn_prop; | ||
1225 | } | ||
1226 | |||
1227 | for (i = 0; i < num_ports; i++) { | ||
1228 | dpn_prop = &dpn_prop[i]; | ||
1229 | |||
1230 | if (dpn_prop->num == port_num) | ||
1231 | return &dpn_prop[i]; | ||
1232 | } | ||
1233 | |||
1234 | return NULL; | ||
1235 | } | ||
1236 | |||
1237 | static int _sdw_prepare_stream(struct sdw_stream_runtime *stream) | ||
1238 | { | ||
1239 | struct sdw_master_runtime *m_rt = stream->m_rt; | ||
1240 | struct sdw_bus *bus = m_rt->bus; | ||
1241 | struct sdw_master_prop *prop = NULL; | ||
1242 | struct sdw_bus_params params; | ||
1243 | int ret; | ||
1244 | |||
1245 | prop = &bus->prop; | ||
1246 | memcpy(¶ms, &bus->params, sizeof(params)); | ||
1247 | |||
1248 | /* TODO: Support Asynchronous mode */ | ||
1249 | if ((prop->max_freq % stream->params.rate) != 0) { | ||
1250 | dev_err(bus->dev, "Async mode not supported"); | ||
1251 | return -EINVAL; | ||
1252 | } | ||
1253 | |||
1254 | /* Increment cumulative bus bandwidth */ | ||
1255 | /* TODO: Update this during Device-Device support */ | ||
1256 | bus->params.bandwidth += m_rt->stream->params.rate * | ||
1257 | m_rt->ch_count * m_rt->stream->params.bps; | ||
1258 | |||
1259 | /* Program params */ | ||
1260 | ret = sdw_program_params(bus); | ||
1261 | if (ret < 0) { | ||
1262 | dev_err(bus->dev, "Program params failed: %d", ret); | ||
1263 | goto restore_params; | ||
1264 | } | ||
1265 | |||
1266 | ret = do_bank_switch(stream); | ||
1267 | if (ret < 0) { | ||
1268 | dev_err(bus->dev, "Bank switch failed: %d", ret); | ||
1269 | goto restore_params; | ||
1270 | } | ||
1271 | |||
1272 | /* Prepare port(s) on the new clock configuration */ | ||
1273 | ret = sdw_prep_deprep_ports(m_rt, true); | ||
1274 | if (ret < 0) { | ||
1275 | dev_err(bus->dev, "Prepare port(s) failed ret = %d", | ||
1276 | ret); | ||
1277 | return ret; | ||
1278 | } | ||
1279 | |||
1280 | stream->state = SDW_STREAM_PREPARED; | ||
1281 | |||
1282 | return ret; | ||
1283 | |||
1284 | restore_params: | ||
1285 | memcpy(&bus->params, ¶ms, sizeof(params)); | ||
1286 | return ret; | ||
1287 | } | ||
1288 | |||
1289 | /** | ||
1290 | * sdw_prepare_stream() - Prepare SoundWire stream | ||
1291 | * | ||
1292 | * @stream: Soundwire stream | ||
1293 | * | ||
1294 | * Documentation/soundwire/stream.txt explains this API in detail | ||
1295 | */ | ||
1296 | int sdw_prepare_stream(struct sdw_stream_runtime *stream) | ||
1297 | { | ||
1298 | int ret = 0; | ||
1299 | |||
1300 | if (!stream) { | ||
1301 | pr_err("SoundWire: Handle not found for stream"); | ||
1302 | return -EINVAL; | ||
1303 | } | ||
1304 | |||
1305 | mutex_lock(&stream->m_rt->bus->bus_lock); | ||
1306 | |||
1307 | ret = _sdw_prepare_stream(stream); | ||
1308 | if (ret < 0) | ||
1309 | pr_err("Prepare for stream:%s failed: %d", stream->name, ret); | ||
1310 | |||
1311 | mutex_unlock(&stream->m_rt->bus->bus_lock); | ||
1312 | return ret; | ||
1313 | } | ||
1314 | EXPORT_SYMBOL(sdw_prepare_stream); | ||
1315 | |||
1316 | static int _sdw_enable_stream(struct sdw_stream_runtime *stream) | ||
1317 | { | ||
1318 | struct sdw_master_runtime *m_rt = stream->m_rt; | ||
1319 | struct sdw_bus *bus = m_rt->bus; | ||
1320 | int ret; | ||
1321 | |||
1322 | /* Program params */ | ||
1323 | ret = sdw_program_params(bus); | ||
1324 | if (ret < 0) { | ||
1325 | dev_err(bus->dev, "Program params failed: %d", ret); | ||
1326 | return ret; | ||
1327 | } | ||
1328 | |||
1329 | /* Enable port(s) */ | ||
1330 | ret = sdw_enable_disable_ports(m_rt, true); | ||
1331 | if (ret < 0) { | ||
1332 | dev_err(bus->dev, "Enable port(s) failed ret: %d", ret); | ||
1333 | return ret; | ||
1334 | } | ||
1335 | |||
1336 | ret = do_bank_switch(stream); | ||
1337 | if (ret < 0) { | ||
1338 | dev_err(bus->dev, "Bank switch failed: %d", ret); | ||
1339 | return ret; | ||
1340 | } | ||
1341 | |||
1342 | stream->state = SDW_STREAM_ENABLED; | ||
1343 | return 0; | ||
1344 | } | ||
1345 | |||
1346 | /** | ||
1347 | * sdw_enable_stream() - Enable SoundWire stream | ||
1348 | * | ||
1349 | * @stream: Soundwire stream | ||
1350 | * | ||
1351 | * Documentation/soundwire/stream.txt explains this API in detail | ||
1352 | */ | ||
1353 | int sdw_enable_stream(struct sdw_stream_runtime *stream) | ||
1354 | { | ||
1355 | int ret = 0; | ||
1356 | |||
1357 | if (!stream) { | ||
1358 | pr_err("SoundWire: Handle not found for stream"); | ||
1359 | return -EINVAL; | ||
1360 | } | ||
1361 | |||
1362 | mutex_lock(&stream->m_rt->bus->bus_lock); | ||
1363 | |||
1364 | ret = _sdw_enable_stream(stream); | ||
1365 | if (ret < 0) | ||
1366 | pr_err("Enable for stream:%s failed: %d", stream->name, ret); | ||
1367 | |||
1368 | mutex_unlock(&stream->m_rt->bus->bus_lock); | ||
1369 | return ret; | ||
1370 | } | ||
1371 | EXPORT_SYMBOL(sdw_enable_stream); | ||
1372 | |||
1373 | static int _sdw_disable_stream(struct sdw_stream_runtime *stream) | ||
1374 | { | ||
1375 | struct sdw_master_runtime *m_rt = stream->m_rt; | ||
1376 | struct sdw_bus *bus = m_rt->bus; | ||
1377 | int ret; | ||
1378 | |||
1379 | /* Disable port(s) */ | ||
1380 | ret = sdw_enable_disable_ports(m_rt, false); | ||
1381 | if (ret < 0) { | ||
1382 | dev_err(bus->dev, "Disable port(s) failed: %d", ret); | ||
1383 | return ret; | ||
1384 | } | ||
1385 | |||
1386 | stream->state = SDW_STREAM_DISABLED; | ||
1387 | |||
1388 | /* Program params */ | ||
1389 | ret = sdw_program_params(bus); | ||
1390 | if (ret < 0) { | ||
1391 | dev_err(bus->dev, "Program params failed: %d", ret); | ||
1392 | return ret; | ||
1393 | } | ||
1394 | |||
1395 | return do_bank_switch(stream); | ||
1396 | } | ||
1397 | |||
1398 | /** | ||
1399 | * sdw_disable_stream() - Disable SoundWire stream | ||
1400 | * | ||
1401 | * @stream: Soundwire stream | ||
1402 | * | ||
1403 | * Documentation/soundwire/stream.txt explains this API in detail | ||
1404 | */ | ||
1405 | int sdw_disable_stream(struct sdw_stream_runtime *stream) | ||
1406 | { | ||
1407 | int ret = 0; | ||
1408 | |||
1409 | if (!stream) { | ||
1410 | pr_err("SoundWire: Handle not found for stream"); | ||
1411 | return -EINVAL; | ||
1412 | } | ||
1413 | |||
1414 | mutex_lock(&stream->m_rt->bus->bus_lock); | ||
1415 | |||
1416 | ret = _sdw_disable_stream(stream); | ||
1417 | if (ret < 0) | ||
1418 | pr_err("Disable for stream:%s failed: %d", stream->name, ret); | ||
1419 | |||
1420 | mutex_unlock(&stream->m_rt->bus->bus_lock); | ||
1421 | return ret; | ||
1422 | } | ||
1423 | EXPORT_SYMBOL(sdw_disable_stream); | ||
1424 | |||
1425 | static int _sdw_deprepare_stream(struct sdw_stream_runtime *stream) | ||
1426 | { | ||
1427 | struct sdw_master_runtime *m_rt = stream->m_rt; | ||
1428 | struct sdw_bus *bus = m_rt->bus; | ||
1429 | int ret = 0; | ||
1430 | |||
1431 | /* De-prepare port(s) */ | ||
1432 | ret = sdw_prep_deprep_ports(m_rt, false); | ||
1433 | if (ret < 0) { | ||
1434 | dev_err(bus->dev, "De-prepare port(s) failed: %d", ret); | ||
1435 | return ret; | ||
1436 | } | ||
1437 | |||
1438 | stream->state = SDW_STREAM_DEPREPARED; | ||
1439 | |||
1440 | /* TODO: Update this during Device-Device support */ | ||
1441 | bus->params.bandwidth -= m_rt->stream->params.rate * | ||
1442 | m_rt->ch_count * m_rt->stream->params.bps; | ||
1443 | |||
1444 | /* Program params */ | ||
1445 | ret = sdw_program_params(bus); | ||
1446 | if (ret < 0) { | ||
1447 | dev_err(bus->dev, "Program params failed: %d", ret); | ||
1448 | return ret; | ||
1449 | } | ||
1450 | |||
1451 | return do_bank_switch(stream); | ||
1452 | } | ||
1453 | |||
1454 | /** | ||
1455 | * sdw_deprepare_stream() - Deprepare SoundWire stream | ||
1456 | * | ||
1457 | * @stream: Soundwire stream | ||
1458 | * | ||
1459 | * Documentation/soundwire/stream.txt explains this API in detail | ||
1460 | */ | ||
1461 | int sdw_deprepare_stream(struct sdw_stream_runtime *stream) | ||
1462 | { | ||
1463 | int ret = 0; | ||
1464 | |||
1465 | if (!stream) { | ||
1466 | pr_err("SoundWire: Handle not found for stream"); | ||
1467 | return -EINVAL; | ||
1468 | } | ||
1469 | |||
1470 | mutex_lock(&stream->m_rt->bus->bus_lock); | ||
1471 | |||
1472 | ret = _sdw_deprepare_stream(stream); | ||
1473 | if (ret < 0) | ||
1474 | pr_err("De-prepare for stream:%d failed: %d", ret, ret); | ||
1475 | |||
1476 | mutex_unlock(&stream->m_rt->bus->bus_lock); | ||
1477 | return ret; | ||
1478 | } | ||
1479 | EXPORT_SYMBOL(sdw_deprepare_stream); | ||
diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c index fd4848392e0d..e8f4ac9400ea 100644 --- a/drivers/uio/uio.c +++ b/drivers/uio/uio.c | |||
@@ -270,7 +270,7 @@ static int uio_dev_add_attributes(struct uio_device *idev) | |||
270 | if (!map_found) { | 270 | if (!map_found) { |
271 | map_found = 1; | 271 | map_found = 1; |
272 | idev->map_dir = kobject_create_and_add("maps", | 272 | idev->map_dir = kobject_create_and_add("maps", |
273 | &idev->dev->kobj); | 273 | &idev->dev.kobj); |
274 | if (!idev->map_dir) { | 274 | if (!idev->map_dir) { |
275 | ret = -ENOMEM; | 275 | ret = -ENOMEM; |
276 | goto err_map; | 276 | goto err_map; |
@@ -299,7 +299,7 @@ static int uio_dev_add_attributes(struct uio_device *idev) | |||
299 | if (!portio_found) { | 299 | if (!portio_found) { |
300 | portio_found = 1; | 300 | portio_found = 1; |
301 | idev->portio_dir = kobject_create_and_add("portio", | 301 | idev->portio_dir = kobject_create_and_add("portio", |
302 | &idev->dev->kobj); | 302 | &idev->dev.kobj); |
303 | if (!idev->portio_dir) { | 303 | if (!idev->portio_dir) { |
304 | ret = -ENOMEM; | 304 | ret = -ENOMEM; |
305 | goto err_portio; | 305 | goto err_portio; |
@@ -342,7 +342,7 @@ err_map_kobj: | |||
342 | kobject_put(&map->kobj); | 342 | kobject_put(&map->kobj); |
343 | } | 343 | } |
344 | kobject_put(idev->map_dir); | 344 | kobject_put(idev->map_dir); |
345 | dev_err(idev->dev, "error creating sysfs files (%d)\n", ret); | 345 | dev_err(&idev->dev, "error creating sysfs files (%d)\n", ret); |
346 | return ret; | 346 | return ret; |
347 | } | 347 | } |
348 | 348 | ||
@@ -379,7 +379,7 @@ static int uio_get_minor(struct uio_device *idev) | |||
379 | idev->minor = retval; | 379 | idev->minor = retval; |
380 | retval = 0; | 380 | retval = 0; |
381 | } else if (retval == -ENOSPC) { | 381 | } else if (retval == -ENOSPC) { |
382 | dev_err(idev->dev, "too many uio devices\n"); | 382 | dev_err(&idev->dev, "too many uio devices\n"); |
383 | retval = -EINVAL; | 383 | retval = -EINVAL; |
384 | } | 384 | } |
385 | mutex_unlock(&minor_lock); | 385 | mutex_unlock(&minor_lock); |
@@ -433,6 +433,7 @@ static int uio_open(struct inode *inode, struct file *filep) | |||
433 | struct uio_device *idev; | 433 | struct uio_device *idev; |
434 | struct uio_listener *listener; | 434 | struct uio_listener *listener; |
435 | int ret = 0; | 435 | int ret = 0; |
436 | unsigned long flags; | ||
436 | 437 | ||
437 | mutex_lock(&minor_lock); | 438 | mutex_lock(&minor_lock); |
438 | idev = idr_find(&uio_idr, iminor(inode)); | 439 | idev = idr_find(&uio_idr, iminor(inode)); |
@@ -442,9 +443,11 @@ static int uio_open(struct inode *inode, struct file *filep) | |||
442 | goto out; | 443 | goto out; |
443 | } | 444 | } |
444 | 445 | ||
446 | get_device(&idev->dev); | ||
447 | |||
445 | if (!try_module_get(idev->owner)) { | 448 | if (!try_module_get(idev->owner)) { |
446 | ret = -ENODEV; | 449 | ret = -ENODEV; |
447 | goto out; | 450 | goto err_module_get; |
448 | } | 451 | } |
449 | 452 | ||
450 | listener = kmalloc(sizeof(*listener), GFP_KERNEL); | 453 | listener = kmalloc(sizeof(*listener), GFP_KERNEL); |
@@ -457,11 +460,13 @@ static int uio_open(struct inode *inode, struct file *filep) | |||
457 | listener->event_count = atomic_read(&idev->event); | 460 | listener->event_count = atomic_read(&idev->event); |
458 | filep->private_data = listener; | 461 | filep->private_data = listener; |
459 | 462 | ||
460 | if (idev->info->open) { | 463 | spin_lock_irqsave(&idev->info_lock, flags); |
464 | if (idev->info && idev->info->open) | ||
461 | ret = idev->info->open(idev->info, inode); | 465 | ret = idev->info->open(idev->info, inode); |
462 | if (ret) | 466 | spin_unlock_irqrestore(&idev->info_lock, flags); |
463 | goto err_infoopen; | 467 | if (ret) |
464 | } | 468 | goto err_infoopen; |
469 | |||
465 | return 0; | 470 | return 0; |
466 | 471 | ||
467 | err_infoopen: | 472 | err_infoopen: |
@@ -470,6 +475,9 @@ err_infoopen: | |||
470 | err_alloc_listener: | 475 | err_alloc_listener: |
471 | module_put(idev->owner); | 476 | module_put(idev->owner); |
472 | 477 | ||
478 | err_module_get: | ||
479 | put_device(&idev->dev); | ||
480 | |||
473 | out: | 481 | out: |
474 | return ret; | 482 | return ret; |
475 | } | 483 | } |
@@ -487,12 +495,16 @@ static int uio_release(struct inode *inode, struct file *filep) | |||
487 | int ret = 0; | 495 | int ret = 0; |
488 | struct uio_listener *listener = filep->private_data; | 496 | struct uio_listener *listener = filep->private_data; |
489 | struct uio_device *idev = listener->dev; | 497 | struct uio_device *idev = listener->dev; |
498 | unsigned long flags; | ||
490 | 499 | ||
491 | if (idev->info->release) | 500 | spin_lock_irqsave(&idev->info_lock, flags); |
501 | if (idev->info && idev->info->release) | ||
492 | ret = idev->info->release(idev->info, inode); | 502 | ret = idev->info->release(idev->info, inode); |
503 | spin_unlock_irqrestore(&idev->info_lock, flags); | ||
493 | 504 | ||
494 | module_put(idev->owner); | 505 | module_put(idev->owner); |
495 | kfree(listener); | 506 | kfree(listener); |
507 | put_device(&idev->dev); | ||
496 | return ret; | 508 | return ret; |
497 | } | 509 | } |
498 | 510 | ||
@@ -500,9 +512,16 @@ static __poll_t uio_poll(struct file *filep, poll_table *wait) | |||
500 | { | 512 | { |
501 | struct uio_listener *listener = filep->private_data; | 513 | struct uio_listener *listener = filep->private_data; |
502 | struct uio_device *idev = listener->dev; | 514 | struct uio_device *idev = listener->dev; |
515 | __poll_t ret = 0; | ||
516 | unsigned long flags; | ||
503 | 517 | ||
504 | if (!idev->info->irq) | 518 | spin_lock_irqsave(&idev->info_lock, flags); |
505 | return -EIO; | 519 | if (!idev->info || !idev->info->irq) |
520 | ret = -EIO; | ||
521 | spin_unlock_irqrestore(&idev->info_lock, flags); | ||
522 | |||
523 | if (ret) | ||
524 | return ret; | ||
506 | 525 | ||
507 | poll_wait(filep, &idev->wait, wait); | 526 | poll_wait(filep, &idev->wait, wait); |
508 | if (listener->event_count != atomic_read(&idev->event)) | 527 | if (listener->event_count != atomic_read(&idev->event)) |
@@ -516,11 +535,17 @@ static ssize_t uio_read(struct file *filep, char __user *buf, | |||
516 | struct uio_listener *listener = filep->private_data; | 535 | struct uio_listener *listener = filep->private_data; |
517 | struct uio_device *idev = listener->dev; | 536 | struct uio_device *idev = listener->dev; |
518 | DECLARE_WAITQUEUE(wait, current); | 537 | DECLARE_WAITQUEUE(wait, current); |
519 | ssize_t retval; | 538 | ssize_t retval = 0; |
520 | s32 event_count; | 539 | s32 event_count; |
540 | unsigned long flags; | ||
521 | 541 | ||
522 | if (!idev->info->irq) | 542 | spin_lock_irqsave(&idev->info_lock, flags); |
523 | return -EIO; | 543 | if (!idev->info || !idev->info->irq) |
544 | retval = -EIO; | ||
545 | spin_unlock_irqrestore(&idev->info_lock, flags); | ||
546 | |||
547 | if (retval) | ||
548 | return retval; | ||
524 | 549 | ||
525 | if (count != sizeof(s32)) | 550 | if (count != sizeof(s32)) |
526 | return -EINVAL; | 551 | return -EINVAL; |
@@ -567,21 +592,33 @@ static ssize_t uio_write(struct file *filep, const char __user *buf, | |||
567 | struct uio_device *idev = listener->dev; | 592 | struct uio_device *idev = listener->dev; |
568 | ssize_t retval; | 593 | ssize_t retval; |
569 | s32 irq_on; | 594 | s32 irq_on; |
595 | unsigned long flags; | ||
570 | 596 | ||
571 | if (!idev->info->irq) | 597 | spin_lock_irqsave(&idev->info_lock, flags); |
572 | return -EIO; | 598 | if (!idev->info || !idev->info->irq) { |
599 | retval = -EIO; | ||
600 | goto out; | ||
601 | } | ||
573 | 602 | ||
574 | if (count != sizeof(s32)) | 603 | if (count != sizeof(s32)) { |
575 | return -EINVAL; | 604 | retval = -EINVAL; |
605 | goto out; | ||
606 | } | ||
576 | 607 | ||
577 | if (!idev->info->irqcontrol) | 608 | if (!idev->info->irqcontrol) { |
578 | return -ENOSYS; | 609 | retval = -ENOSYS; |
610 | goto out; | ||
611 | } | ||
579 | 612 | ||
580 | if (copy_from_user(&irq_on, buf, count)) | 613 | if (copy_from_user(&irq_on, buf, count)) { |
581 | return -EFAULT; | 614 | retval = -EFAULT; |
615 | goto out; | ||
616 | } | ||
582 | 617 | ||
583 | retval = idev->info->irqcontrol(idev->info, irq_on); | 618 | retval = idev->info->irqcontrol(idev->info, irq_on); |
584 | 619 | ||
620 | out: | ||
621 | spin_unlock_irqrestore(&idev->info_lock, flags); | ||
585 | return retval ? retval : sizeof(s32); | 622 | return retval ? retval : sizeof(s32); |
586 | } | 623 | } |
587 | 624 | ||
@@ -597,7 +634,7 @@ static int uio_find_mem_index(struct vm_area_struct *vma) | |||
597 | return -1; | 634 | return -1; |
598 | } | 635 | } |
599 | 636 | ||
600 | static int uio_vma_fault(struct vm_fault *vmf) | 637 | static vm_fault_t uio_vma_fault(struct vm_fault *vmf) |
601 | { | 638 | { |
602 | struct uio_device *idev = vmf->vma->vm_private_data; | 639 | struct uio_device *idev = vmf->vma->vm_private_data; |
603 | struct page *page; | 640 | struct page *page; |
@@ -794,6 +831,13 @@ static void release_uio_class(void) | |||
794 | uio_major_cleanup(); | 831 | uio_major_cleanup(); |
795 | } | 832 | } |
796 | 833 | ||
834 | static void uio_device_release(struct device *dev) | ||
835 | { | ||
836 | struct uio_device *idev = dev_get_drvdata(dev); | ||
837 | |||
838 | kfree(idev); | ||
839 | } | ||
840 | |||
797 | /** | 841 | /** |
798 | * uio_register_device - register a new userspace IO device | 842 | * uio_register_device - register a new userspace IO device |
799 | * @owner: module that creates the new device | 843 | * @owner: module that creates the new device |
@@ -814,13 +858,14 @@ int __uio_register_device(struct module *owner, | |||
814 | 858 | ||
815 | info->uio_dev = NULL; | 859 | info->uio_dev = NULL; |
816 | 860 | ||
817 | idev = devm_kzalloc(parent, sizeof(*idev), GFP_KERNEL); | 861 | idev = kzalloc(sizeof(*idev), GFP_KERNEL); |
818 | if (!idev) { | 862 | if (!idev) { |
819 | return -ENOMEM; | 863 | return -ENOMEM; |
820 | } | 864 | } |
821 | 865 | ||
822 | idev->owner = owner; | 866 | idev->owner = owner; |
823 | idev->info = info; | 867 | idev->info = info; |
868 | spin_lock_init(&idev->info_lock); | ||
824 | init_waitqueue_head(&idev->wait); | 869 | init_waitqueue_head(&idev->wait); |
825 | atomic_set(&idev->event, 0); | 870 | atomic_set(&idev->event, 0); |
826 | 871 | ||
@@ -828,14 +873,19 @@ int __uio_register_device(struct module *owner, | |||
828 | if (ret) | 873 | if (ret) |
829 | return ret; | 874 | return ret; |
830 | 875 | ||
831 | idev->dev = device_create(&uio_class, parent, | 876 | idev->dev.devt = MKDEV(uio_major, idev->minor); |
832 | MKDEV(uio_major, idev->minor), idev, | 877 | idev->dev.class = &uio_class; |
833 | "uio%d", idev->minor); | 878 | idev->dev.parent = parent; |
834 | if (IS_ERR(idev->dev)) { | 879 | idev->dev.release = uio_device_release; |
835 | printk(KERN_ERR "UIO: device register failed\n"); | 880 | dev_set_drvdata(&idev->dev, idev); |
836 | ret = PTR_ERR(idev->dev); | 881 | |
882 | ret = dev_set_name(&idev->dev, "uio%d", idev->minor); | ||
883 | if (ret) | ||
884 | goto err_device_create; | ||
885 | |||
886 | ret = device_register(&idev->dev); | ||
887 | if (ret) | ||
837 | goto err_device_create; | 888 | goto err_device_create; |
838 | } | ||
839 | 889 | ||
840 | ret = uio_dev_add_attributes(idev); | 890 | ret = uio_dev_add_attributes(idev); |
841 | if (ret) | 891 | if (ret) |
@@ -863,7 +913,7 @@ int __uio_register_device(struct module *owner, | |||
863 | err_request_irq: | 913 | err_request_irq: |
864 | uio_dev_del_attributes(idev); | 914 | uio_dev_del_attributes(idev); |
865 | err_uio_dev_add_attributes: | 915 | err_uio_dev_add_attributes: |
866 | device_destroy(&uio_class, MKDEV(uio_major, idev->minor)); | 916 | device_unregister(&idev->dev); |
867 | err_device_create: | 917 | err_device_create: |
868 | uio_free_minor(idev); | 918 | uio_free_minor(idev); |
869 | return ret; | 919 | return ret; |
@@ -878,6 +928,7 @@ EXPORT_SYMBOL_GPL(__uio_register_device); | |||
878 | void uio_unregister_device(struct uio_info *info) | 928 | void uio_unregister_device(struct uio_info *info) |
879 | { | 929 | { |
880 | struct uio_device *idev; | 930 | struct uio_device *idev; |
931 | unsigned long flags; | ||
881 | 932 | ||
882 | if (!info || !info->uio_dev) | 933 | if (!info || !info->uio_dev) |
883 | return; | 934 | return; |
@@ -891,7 +942,11 @@ void uio_unregister_device(struct uio_info *info) | |||
891 | if (info->irq && info->irq != UIO_IRQ_CUSTOM) | 942 | if (info->irq && info->irq != UIO_IRQ_CUSTOM) |
892 | free_irq(info->irq, idev); | 943 | free_irq(info->irq, idev); |
893 | 944 | ||
894 | device_destroy(&uio_class, MKDEV(uio_major, idev->minor)); | 945 | spin_lock_irqsave(&idev->info_lock, flags); |
946 | idev->info = NULL; | ||
947 | spin_unlock_irqrestore(&idev->info_lock, flags); | ||
948 | |||
949 | device_unregister(&idev->dev); | ||
895 | 950 | ||
896 | return; | 951 | return; |
897 | } | 952 | } |
diff --git a/drivers/uio/uio_fsl_elbc_gpcm.c b/drivers/uio/uio_fsl_elbc_gpcm.c index b46323d9dc18..b55191335d90 100644 --- a/drivers/uio/uio_fsl_elbc_gpcm.c +++ b/drivers/uio/uio_fsl_elbc_gpcm.c | |||
@@ -475,7 +475,6 @@ MODULE_DEVICE_TABLE(of, uio_fsl_elbc_gpcm_match); | |||
475 | static struct platform_driver uio_fsl_elbc_gpcm_driver = { | 475 | static struct platform_driver uio_fsl_elbc_gpcm_driver = { |
476 | .driver = { | 476 | .driver = { |
477 | .name = "fsl,elbc-gpcm-uio", | 477 | .name = "fsl,elbc-gpcm-uio", |
478 | .owner = THIS_MODULE, | ||
479 | .of_match_table = uio_fsl_elbc_gpcm_match, | 478 | .of_match_table = uio_fsl_elbc_gpcm_match, |
480 | }, | 479 | }, |
481 | .probe = uio_fsl_elbc_gpcm_probe, | 480 | .probe = uio_fsl_elbc_gpcm_probe, |
diff --git a/drivers/virt/vboxguest/vboxguest_linux.c b/drivers/virt/vboxguest/vboxguest_linux.c index 398d22693234..6e2a9619192d 100644 --- a/drivers/virt/vboxguest/vboxguest_linux.c +++ b/drivers/virt/vboxguest/vboxguest_linux.c | |||
@@ -121,7 +121,9 @@ static long vbg_misc_device_ioctl(struct file *filp, unsigned int req, | |||
121 | if (!buf) | 121 | if (!buf) |
122 | return -ENOMEM; | 122 | return -ENOMEM; |
123 | 123 | ||
124 | if (copy_from_user(buf, (void *)arg, hdr.size_in)) { | 124 | *((struct vbg_ioctl_hdr *)buf) = hdr; |
125 | if (copy_from_user(buf + sizeof(hdr), (void *)arg + sizeof(hdr), | ||
126 | hdr.size_in - sizeof(hdr))) { | ||
125 | ret = -EFAULT; | 127 | ret = -EFAULT; |
126 | goto out; | 128 | goto out; |
127 | } | 129 | } |
diff --git a/drivers/w1/masters/mxc_w1.c b/drivers/w1/masters/mxc_w1.c index 74f2e6e6202a..8851d441e5fd 100644 --- a/drivers/w1/masters/mxc_w1.c +++ b/drivers/w1/masters/mxc_w1.c | |||
@@ -112,6 +112,10 @@ static int mxc_w1_probe(struct platform_device *pdev) | |||
112 | if (IS_ERR(mdev->clk)) | 112 | if (IS_ERR(mdev->clk)) |
113 | return PTR_ERR(mdev->clk); | 113 | return PTR_ERR(mdev->clk); |
114 | 114 | ||
115 | err = clk_prepare_enable(mdev->clk); | ||
116 | if (err) | ||
117 | return err; | ||
118 | |||
115 | clkrate = clk_get_rate(mdev->clk); | 119 | clkrate = clk_get_rate(mdev->clk); |
116 | if (clkrate < 10000000) | 120 | if (clkrate < 10000000) |
117 | dev_warn(&pdev->dev, | 121 | dev_warn(&pdev->dev, |
@@ -125,12 +129,10 @@ static int mxc_w1_probe(struct platform_device *pdev) | |||
125 | 129 | ||
126 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 130 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
127 | mdev->regs = devm_ioremap_resource(&pdev->dev, res); | 131 | mdev->regs = devm_ioremap_resource(&pdev->dev, res); |
128 | if (IS_ERR(mdev->regs)) | 132 | if (IS_ERR(mdev->regs)) { |
129 | return PTR_ERR(mdev->regs); | 133 | err = PTR_ERR(mdev->regs); |
130 | 134 | goto out_disable_clk; | |
131 | err = clk_prepare_enable(mdev->clk); | 135 | } |
132 | if (err) | ||
133 | return err; | ||
134 | 136 | ||
135 | /* Software reset 1-Wire module */ | 137 | /* Software reset 1-Wire module */ |
136 | writeb(MXC_W1_RESET_RST, mdev->regs + MXC_W1_RESET); | 138 | writeb(MXC_W1_RESET_RST, mdev->regs + MXC_W1_RESET); |
@@ -146,8 +148,12 @@ static int mxc_w1_probe(struct platform_device *pdev) | |||
146 | 148 | ||
147 | err = w1_add_master_device(&mdev->bus_master); | 149 | err = w1_add_master_device(&mdev->bus_master); |
148 | if (err) | 150 | if (err) |
149 | clk_disable_unprepare(mdev->clk); | 151 | goto out_disable_clk; |
150 | 152 | ||
153 | return 0; | ||
154 | |||
155 | out_disable_clk: | ||
156 | clk_disable_unprepare(mdev->clk); | ||
151 | return err; | 157 | return err; |
152 | } | 158 | } |
153 | 159 | ||
diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c index 80a778b02f28..caef0e0fd817 100644 --- a/drivers/w1/w1.c +++ b/drivers/w1/w1.c | |||
@@ -751,7 +751,7 @@ int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn) | |||
751 | 751 | ||
752 | /* slave modules need to be loaded in a context with unlocked mutex */ | 752 | /* slave modules need to be loaded in a context with unlocked mutex */ |
753 | mutex_unlock(&dev->mutex); | 753 | mutex_unlock(&dev->mutex); |
754 | request_module("w1-family-0x%02x", rn->family); | 754 | request_module("w1-family-0x%02X", rn->family); |
755 | mutex_lock(&dev->mutex); | 755 | mutex_lock(&dev->mutex); |
756 | 756 | ||
757 | spin_lock(&w1_flock); | 757 | spin_lock(&w1_flock); |
diff --git a/include/linux/coresight.h b/include/linux/coresight.h index d950dad5056a..c265e0468414 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h | |||
@@ -1,13 +1,6 @@ | |||
1 | /* Copyright (c) 2012, The Linux Foundation. All rights reserved. | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
2 | * | 2 | /* |
3 | * This program is free software; you can redistribute it and/or modify | 3 | * Copyright (c) 2012, The Linux Foundation. All rights reserved. |
4 | * it under the terms of the GNU General Public License version 2 and | ||
5 | * only version 2 as published by the Free Software Foundation. | ||
6 | * | ||
7 | * This program is distributed in the hope that it will be useful, | ||
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
10 | * GNU General Public License for more details. | ||
11 | */ | 4 | */ |
12 | 5 | ||
13 | #ifndef _LINUX_CORESIGHT_H | 6 | #ifndef _LINUX_CORESIGHT_H |
diff --git a/include/linux/fpga/altera-pr-ip-core.h b/include/linux/fpga/altera-pr-ip-core.h index 3810a9033f49..7d4664730d60 100644 --- a/include/linux/fpga/altera-pr-ip-core.h +++ b/include/linux/fpga/altera-pr-ip-core.h | |||
@@ -1,3 +1,4 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
1 | /* | 2 | /* |
2 | * Driver for Altera Partial Reconfiguration IP Core | 3 | * Driver for Altera Partial Reconfiguration IP Core |
3 | * | 4 | * |
@@ -5,18 +6,6 @@ | |||
5 | * | 6 | * |
6 | * Based on socfpga-a10.c Copyright (C) 2015-2016 Altera Corporation | 7 | * Based on socfpga-a10.c Copyright (C) 2015-2016 Altera Corporation |
7 | * by Alan Tull <atull@opensource.altera.com> | 8 | * by Alan Tull <atull@opensource.altera.com> |
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms and conditions of the GNU General Public License, | ||
11 | * version 2, as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
14 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
15 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
16 | * more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License along with | ||
19 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
20 | */ | 9 | */ |
21 | 10 | ||
22 | #ifndef _ALT_PR_IP_CORE_H | 11 | #ifndef _ALT_PR_IP_CORE_H |
diff --git a/include/linux/fpga/fpga-bridge.h b/include/linux/fpga/fpga-bridge.h index 3694821a6d2d..ce550fcf6360 100644 --- a/include/linux/fpga/fpga-bridge.h +++ b/include/linux/fpga/fpga-bridge.h | |||
@@ -62,8 +62,11 @@ int of_fpga_bridge_get_to_list(struct device_node *np, | |||
62 | struct fpga_image_info *info, | 62 | struct fpga_image_info *info, |
63 | struct list_head *bridge_list); | 63 | struct list_head *bridge_list); |
64 | 64 | ||
65 | int fpga_bridge_register(struct device *dev, const char *name, | 65 | struct fpga_bridge *fpga_bridge_create(struct device *dev, const char *name, |
66 | const struct fpga_bridge_ops *br_ops, void *priv); | 66 | const struct fpga_bridge_ops *br_ops, |
67 | void fpga_bridge_unregister(struct device *dev); | 67 | void *priv); |
68 | void fpga_bridge_free(struct fpga_bridge *br); | ||
69 | int fpga_bridge_register(struct fpga_bridge *br); | ||
70 | void fpga_bridge_unregister(struct fpga_bridge *br); | ||
68 | 71 | ||
69 | #endif /* _LINUX_FPGA_BRIDGE_H */ | 72 | #endif /* _LINUX_FPGA_BRIDGE_H */ |
diff --git a/include/linux/fpga/fpga-mgr.h b/include/linux/fpga/fpga-mgr.h index 3c6de23aabdf..eec7c2478b0d 100644 --- a/include/linux/fpga/fpga-mgr.h +++ b/include/linux/fpga/fpga-mgr.h | |||
@@ -1,20 +1,9 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
1 | /* | 2 | /* |
2 | * FPGA Framework | 3 | * FPGA Framework |
3 | * | 4 | * |
4 | * Copyright (C) 2013-2016 Altera Corporation | 5 | * Copyright (C) 2013-2016 Altera Corporation |
5 | * Copyright (C) 2017 Intel Corporation | 6 | * Copyright (C) 2017 Intel Corporation |
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms and conditions of the GNU General Public License, | ||
9 | * version 2, as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
14 | * more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along with | ||
17 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
18 | */ | 7 | */ |
19 | #ifndef _LINUX_FPGA_MGR_H | 8 | #ifndef _LINUX_FPGA_MGR_H |
20 | #define _LINUX_FPGA_MGR_H | 9 | #define _LINUX_FPGA_MGR_H |
@@ -170,9 +159,11 @@ struct fpga_manager *fpga_mgr_get(struct device *dev); | |||
170 | 159 | ||
171 | void fpga_mgr_put(struct fpga_manager *mgr); | 160 | void fpga_mgr_put(struct fpga_manager *mgr); |
172 | 161 | ||
173 | int fpga_mgr_register(struct device *dev, const char *name, | 162 | struct fpga_manager *fpga_mgr_create(struct device *dev, const char *name, |
174 | const struct fpga_manager_ops *mops, void *priv); | 163 | const struct fpga_manager_ops *mops, |
175 | 164 | void *priv); | |
176 | void fpga_mgr_unregister(struct device *dev); | 165 | void fpga_mgr_free(struct fpga_manager *mgr); |
166 | int fpga_mgr_register(struct fpga_manager *mgr); | ||
167 | void fpga_mgr_unregister(struct fpga_manager *mgr); | ||
177 | 168 | ||
178 | #endif /*_LINUX_FPGA_MGR_H */ | 169 | #endif /*_LINUX_FPGA_MGR_H */ |
diff --git a/include/linux/fpga/fpga-region.h b/include/linux/fpga/fpga-region.h index b6520318ab9c..d7071cddd727 100644 --- a/include/linux/fpga/fpga-region.h +++ b/include/linux/fpga/fpga-region.h | |||
@@ -1,3 +1,5 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
2 | |||
1 | #ifndef _FPGA_REGION_H | 3 | #ifndef _FPGA_REGION_H |
2 | #define _FPGA_REGION_H | 4 | #define _FPGA_REGION_H |
3 | 5 | ||
@@ -14,7 +16,6 @@ | |||
14 | * @info: FPGA image info | 16 | * @info: FPGA image info |
15 | * @priv: private data | 17 | * @priv: private data |
16 | * @get_bridges: optional function to get bridges to a list | 18 | * @get_bridges: optional function to get bridges to a list |
17 | * @groups: optional attribute groups. | ||
18 | */ | 19 | */ |
19 | struct fpga_region { | 20 | struct fpga_region { |
20 | struct device dev; | 21 | struct device dev; |
@@ -24,7 +25,6 @@ struct fpga_region { | |||
24 | struct fpga_image_info *info; | 25 | struct fpga_image_info *info; |
25 | void *priv; | 26 | void *priv; |
26 | int (*get_bridges)(struct fpga_region *region); | 27 | int (*get_bridges)(struct fpga_region *region); |
27 | const struct attribute_group **groups; | ||
28 | }; | 28 | }; |
29 | 29 | ||
30 | #define to_fpga_region(d) container_of(d, struct fpga_region, dev) | 30 | #define to_fpga_region(d) container_of(d, struct fpga_region, dev) |
@@ -34,7 +34,12 @@ struct fpga_region *fpga_region_class_find( | |||
34 | int (*match)(struct device *, const void *)); | 34 | int (*match)(struct device *, const void *)); |
35 | 35 | ||
36 | int fpga_region_program_fpga(struct fpga_region *region); | 36 | int fpga_region_program_fpga(struct fpga_region *region); |
37 | int fpga_region_register(struct device *dev, struct fpga_region *region); | 37 | |
38 | int fpga_region_unregister(struct fpga_region *region); | 38 | struct fpga_region |
39 | *fpga_region_create(struct device *dev, struct fpga_manager *mgr, | ||
40 | int (*get_bridges)(struct fpga_region *)); | ||
41 | void fpga_region_free(struct fpga_region *region); | ||
42 | int fpga_region_register(struct fpga_region *region); | ||
43 | void fpga_region_unregister(struct fpga_region *region); | ||
39 | 44 | ||
40 | #endif /* _FPGA_REGION_H */ | 45 | #endif /* _FPGA_REGION_H */ |
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index 192ed8fbc403..11b5612dc066 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h | |||
@@ -163,6 +163,7 @@ static inline u32 hv_get_bytes_to_write(const struct hv_ring_buffer_info *rbi) | |||
163 | * 2 . 4 (Windows 8) | 163 | * 2 . 4 (Windows 8) |
164 | * 3 . 0 (Windows 8 R2) | 164 | * 3 . 0 (Windows 8 R2) |
165 | * 4 . 0 (Windows 10) | 165 | * 4 . 0 (Windows 10) |
166 | * 5 . 0 (Newer Windows 10) | ||
166 | */ | 167 | */ |
167 | 168 | ||
168 | #define VERSION_WS2008 ((0 << 16) | (13)) | 169 | #define VERSION_WS2008 ((0 << 16) | (13)) |
@@ -170,10 +171,11 @@ static inline u32 hv_get_bytes_to_write(const struct hv_ring_buffer_info *rbi) | |||
170 | #define VERSION_WIN8 ((2 << 16) | (4)) | 171 | #define VERSION_WIN8 ((2 << 16) | (4)) |
171 | #define VERSION_WIN8_1 ((3 << 16) | (0)) | 172 | #define VERSION_WIN8_1 ((3 << 16) | (0)) |
172 | #define VERSION_WIN10 ((4 << 16) | (0)) | 173 | #define VERSION_WIN10 ((4 << 16) | (0)) |
174 | #define VERSION_WIN10_V5 ((5 << 16) | (0)) | ||
173 | 175 | ||
174 | #define VERSION_INVAL -1 | 176 | #define VERSION_INVAL -1 |
175 | 177 | ||
176 | #define VERSION_CURRENT VERSION_WIN10 | 178 | #define VERSION_CURRENT VERSION_WIN10_V5 |
177 | 179 | ||
178 | /* Make maximum size of pipe payload of 16K */ | 180 | /* Make maximum size of pipe payload of 16K */ |
179 | #define MAX_PIPE_DATA_PAYLOAD (sizeof(u8) * 16384) | 181 | #define MAX_PIPE_DATA_PAYLOAD (sizeof(u8) * 16384) |
@@ -570,7 +572,14 @@ struct vmbus_channel_initiate_contact { | |||
570 | struct vmbus_channel_message_header header; | 572 | struct vmbus_channel_message_header header; |
571 | u32 vmbus_version_requested; | 573 | u32 vmbus_version_requested; |
572 | u32 target_vcpu; /* The VCPU the host should respond to */ | 574 | u32 target_vcpu; /* The VCPU the host should respond to */ |
573 | u64 interrupt_page; | 575 | union { |
576 | u64 interrupt_page; | ||
577 | struct { | ||
578 | u8 msg_sint; | ||
579 | u8 padding1[3]; | ||
580 | u32 padding2; | ||
581 | }; | ||
582 | }; | ||
574 | u64 monitor_page1; | 583 | u64 monitor_page1; |
575 | u64 monitor_page2; | 584 | u64 monitor_page2; |
576 | } __packed; | 585 | } __packed; |
@@ -585,6 +594,19 @@ struct vmbus_channel_tl_connect_request { | |||
585 | struct vmbus_channel_version_response { | 594 | struct vmbus_channel_version_response { |
586 | struct vmbus_channel_message_header header; | 595 | struct vmbus_channel_message_header header; |
587 | u8 version_supported; | 596 | u8 version_supported; |
597 | |||
598 | u8 connection_state; | ||
599 | u16 padding; | ||
600 | |||
601 | /* | ||
602 | * On new hosts that support VMBus protocol 5.0, we must use | ||
603 | * VMBUS_MESSAGE_CONNECTION_ID_4 for the Initiate Contact Message, | ||
604 | * and for subsequent messages, we must use the Message Connection ID | ||
605 | * field in the host-returned Version Response Message. | ||
606 | * | ||
607 | * On old hosts, we should always use VMBUS_MESSAGE_CONNECTION_ID (1). | ||
608 | */ | ||
609 | u32 msg_conn_id; | ||
588 | } __packed; | 610 | } __packed; |
589 | 611 | ||
590 | enum vmbus_channel_state { | 612 | enum vmbus_channel_state { |
diff --git a/include/linux/nubus.h b/include/linux/nubus.h index 6e8200215321..eba50b057f6f 100644 --- a/include/linux/nubus.h +++ b/include/linux/nubus.h | |||
@@ -163,7 +163,7 @@ void nubus_seq_write_rsrc_mem(struct seq_file *m, | |||
163 | unsigned char *nubus_dirptr(const struct nubus_dirent *nd); | 163 | unsigned char *nubus_dirptr(const struct nubus_dirent *nd); |
164 | 164 | ||
165 | /* Declarations relating to driver model objects */ | 165 | /* Declarations relating to driver model objects */ |
166 | int nubus_bus_register(void); | 166 | int nubus_parent_device_register(void); |
167 | int nubus_device_register(struct nubus_board *board); | 167 | int nubus_device_register(struct nubus_board *board); |
168 | int nubus_driver_register(struct nubus_driver *ndrv); | 168 | int nubus_driver_register(struct nubus_driver *ndrv); |
169 | void nubus_driver_unregister(struct nubus_driver *ndrv); | 169 | void nubus_driver_unregister(struct nubus_driver *ndrv); |
diff --git a/include/linux/nvmem-provider.h b/include/linux/nvmem-provider.h index f89598bc4e1c..24def6ad09bb 100644 --- a/include/linux/nvmem-provider.h +++ b/include/linux/nvmem-provider.h | |||
@@ -77,6 +77,9 @@ struct nvmem_device *devm_nvmem_register(struct device *dev, | |||
77 | 77 | ||
78 | int devm_nvmem_unregister(struct device *dev, struct nvmem_device *nvmem); | 78 | int devm_nvmem_unregister(struct device *dev, struct nvmem_device *nvmem); |
79 | 79 | ||
80 | int nvmem_add_cells(struct nvmem_device *nvmem, | ||
81 | const struct nvmem_cell_info *info, | ||
82 | int ncells); | ||
80 | #else | 83 | #else |
81 | 84 | ||
82 | static inline struct nvmem_device *nvmem_register(const struct nvmem_config *c) | 85 | static inline struct nvmem_device *nvmem_register(const struct nvmem_config *c) |
@@ -99,6 +102,14 @@ static inline int | |||
99 | devm_nvmem_unregister(struct device *dev, struct nvmem_device *nvmem) | 102 | devm_nvmem_unregister(struct device *dev, struct nvmem_device *nvmem) |
100 | { | 103 | { |
101 | return nvmem_unregister(nvmem); | 104 | return nvmem_unregister(nvmem); |
105 | |||
106 | } | ||
107 | |||
108 | static inline int nvmem_add_cells(struct nvmem_device *nvmem, | ||
109 | const struct nvmem_cell_info *info, | ||
110 | int ncells) | ||
111 | { | ||
112 | return -ENOSYS; | ||
102 | } | 113 | } |
103 | 114 | ||
104 | #endif /* CONFIG_NVMEM */ | 115 | #endif /* CONFIG_NVMEM */ |
diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index e91fdcf41049..962971e6a9c7 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h | |||
@@ -23,9 +23,24 @@ struct sdw_slave; | |||
23 | #define SDW_MASTER_DEV_NUM 14 | 23 | #define SDW_MASTER_DEV_NUM 14 |
24 | 24 | ||
25 | #define SDW_NUM_DEV_ID_REGISTERS 6 | 25 | #define SDW_NUM_DEV_ID_REGISTERS 6 |
26 | /* frame shape defines */ | ||
26 | 27 | ||
28 | /* | ||
29 | * Note: The maximum row define in SoundWire spec 1.1 is 23. In order to | ||
30 | * fill hole with 0, one more dummy entry is added | ||
31 | */ | ||
32 | #define SDW_FRAME_ROWS 24 | ||
33 | #define SDW_FRAME_COLS 8 | ||
34 | #define SDW_FRAME_ROW_COLS (SDW_FRAME_ROWS * SDW_FRAME_COLS) | ||
35 | |||
36 | #define SDW_FRAME_CTRL_BITS 48 | ||
27 | #define SDW_MAX_DEVICES 11 | 37 | #define SDW_MAX_DEVICES 11 |
28 | 38 | ||
39 | #define SDW_VALID_PORT_RANGE(n) (n <= 14 && n >= 1) | ||
40 | |||
41 | #define SDW_DAI_ID_RANGE_START 100 | ||
42 | #define SDW_DAI_ID_RANGE_END 200 | ||
43 | |||
29 | /** | 44 | /** |
30 | * enum sdw_slave_status - Slave status | 45 | * enum sdw_slave_status - Slave status |
31 | * @SDW_SLAVE_UNATTACHED: Slave is not attached with the bus. | 46 | * @SDW_SLAVE_UNATTACHED: Slave is not attached with the bus. |
@@ -61,6 +76,30 @@ enum sdw_command_response { | |||
61 | SDW_CMD_FAIL_OTHER = 4, | 76 | SDW_CMD_FAIL_OTHER = 4, |
62 | }; | 77 | }; |
63 | 78 | ||
79 | /** | ||
80 | * enum sdw_stream_type: data stream type | ||
81 | * | ||
82 | * @SDW_STREAM_PCM: PCM data stream | ||
83 | * @SDW_STREAM_PDM: PDM data stream | ||
84 | * | ||
85 | * spec doesn't define this, but is used in implementation | ||
86 | */ | ||
87 | enum sdw_stream_type { | ||
88 | SDW_STREAM_PCM = 0, | ||
89 | SDW_STREAM_PDM = 1, | ||
90 | }; | ||
91 | |||
92 | /** | ||
93 | * enum sdw_data_direction: Data direction | ||
94 | * | ||
95 | * @SDW_DATA_DIR_RX: Data into Port | ||
96 | * @SDW_DATA_DIR_TX: Data out of Port | ||
97 | */ | ||
98 | enum sdw_data_direction { | ||
99 | SDW_DATA_DIR_RX = 0, | ||
100 | SDW_DATA_DIR_TX = 1, | ||
101 | }; | ||
102 | |||
64 | /* | 103 | /* |
65 | * SDW properties, defined in MIPI DisCo spec v1.0 | 104 | * SDW properties, defined in MIPI DisCo spec v1.0 |
66 | */ | 105 | */ |
@@ -341,11 +380,92 @@ struct sdw_slave_intr_status { | |||
341 | }; | 380 | }; |
342 | 381 | ||
343 | /** | 382 | /** |
344 | * struct sdw_slave_ops - Slave driver callback ops | 383 | * sdw_reg_bank - SoundWire register banks |
384 | * @SDW_BANK0: Soundwire register bank 0 | ||
385 | * @SDW_BANK1: Soundwire register bank 1 | ||
386 | */ | ||
387 | enum sdw_reg_bank { | ||
388 | SDW_BANK0, | ||
389 | SDW_BANK1, | ||
390 | }; | ||
391 | |||
392 | /** | ||
393 | * struct sdw_bus_conf: Bus configuration | ||
394 | * | ||
395 | * @clk_freq: Clock frequency, in Hz | ||
396 | * @num_rows: Number of rows in frame | ||
397 | * @num_cols: Number of columns in frame | ||
398 | * @bank: Next register bank | ||
399 | */ | ||
400 | struct sdw_bus_conf { | ||
401 | unsigned int clk_freq; | ||
402 | unsigned int num_rows; | ||
403 | unsigned int num_cols; | ||
404 | unsigned int bank; | ||
405 | }; | ||
406 | |||
407 | /** | ||
408 | * struct sdw_prepare_ch: Prepare/De-prepare Data Port channel | ||
409 | * | ||
410 | * @num: Port number | ||
411 | * @ch_mask: Active channel mask | ||
412 | * @prepare: Prepare (true) /de-prepare (false) channel | ||
413 | * @bank: Register bank, which bank Slave/Master driver should program for | ||
414 | * implementation defined registers. This is always updated to next_bank | ||
415 | * value read from bus params. | ||
416 | * | ||
417 | */ | ||
418 | struct sdw_prepare_ch { | ||
419 | unsigned int num; | ||
420 | unsigned int ch_mask; | ||
421 | bool prepare; | ||
422 | unsigned int bank; | ||
423 | }; | ||
424 | |||
425 | /** | ||
426 | * enum sdw_port_prep_ops: Prepare operations for Data Port | ||
427 | * | ||
428 | * @SDW_OPS_PORT_PRE_PREP: Pre prepare operation for the Port | ||
429 | * @SDW_OPS_PORT_PREP: Prepare operation for the Port | ||
430 | * @SDW_OPS_PORT_POST_PREP: Post prepare operation for the Port | ||
431 | */ | ||
432 | enum sdw_port_prep_ops { | ||
433 | SDW_OPS_PORT_PRE_PREP = 0, | ||
434 | SDW_OPS_PORT_PREP = 1, | ||
435 | SDW_OPS_PORT_POST_PREP = 2, | ||
436 | }; | ||
437 | |||
438 | /** | ||
439 | * struct sdw_bus_params: Structure holding bus configuration | ||
440 | * | ||
441 | * @curr_bank: Current bank in use (BANK0/BANK1) | ||
442 | * @next_bank: Next bank to use (BANK0/BANK1). next_bank will always be | ||
443 | * set to !curr_bank | ||
444 | * @max_dr_freq: Maximum double rate clock frequency supported, in Hz | ||
445 | * @curr_dr_freq: Current double rate clock frequency, in Hz | ||
446 | * @bandwidth: Current bandwidth | ||
447 | * @col: Active columns | ||
448 | * @row: Active rows | ||
449 | */ | ||
450 | struct sdw_bus_params { | ||
451 | enum sdw_reg_bank curr_bank; | ||
452 | enum sdw_reg_bank next_bank; | ||
453 | unsigned int max_dr_freq; | ||
454 | unsigned int curr_dr_freq; | ||
455 | unsigned int bandwidth; | ||
456 | unsigned int col; | ||
457 | unsigned int row; | ||
458 | }; | ||
459 | |||
460 | /** | ||
461 | * struct sdw_slave_ops: Slave driver callback ops | ||
462 | * | ||
345 | * @read_prop: Read Slave properties | 463 | * @read_prop: Read Slave properties |
346 | * @interrupt_callback: Device interrupt notification (invoked in thread | 464 | * @interrupt_callback: Device interrupt notification (invoked in thread |
347 | * context) | 465 | * context) |
348 | * @update_status: Update Slave status | 466 | * @update_status: Update Slave status |
467 | * @bus_config: Update the bus config for Slave | ||
468 | * @port_prep: Prepare the port with parameters | ||
349 | */ | 469 | */ |
350 | struct sdw_slave_ops { | 470 | struct sdw_slave_ops { |
351 | int (*read_prop)(struct sdw_slave *sdw); | 471 | int (*read_prop)(struct sdw_slave *sdw); |
@@ -353,6 +473,11 @@ struct sdw_slave_ops { | |||
353 | struct sdw_slave_intr_status *status); | 473 | struct sdw_slave_intr_status *status); |
354 | int (*update_status)(struct sdw_slave *slave, | 474 | int (*update_status)(struct sdw_slave *slave, |
355 | enum sdw_slave_status status); | 475 | enum sdw_slave_status status); |
476 | int (*bus_config)(struct sdw_slave *slave, | ||
477 | struct sdw_bus_params *params); | ||
478 | int (*port_prep)(struct sdw_slave *slave, | ||
479 | struct sdw_prepare_ch *prepare_ch, | ||
480 | enum sdw_port_prep_ops pre_ops); | ||
356 | }; | 481 | }; |
357 | 482 | ||
358 | /** | 483 | /** |
@@ -406,6 +531,93 @@ int sdw_handle_slave_status(struct sdw_bus *bus, | |||
406 | * SDW master structures and APIs | 531 | * SDW master structures and APIs |
407 | */ | 532 | */ |
408 | 533 | ||
534 | /** | ||
535 | * struct sdw_port_params: Data Port parameters | ||
536 | * | ||
537 | * @num: Port number | ||
538 | * @bps: Word length of the Port | ||
539 | * @flow_mode: Port Data flow mode | ||
540 | * @data_mode: Test modes or normal mode | ||
541 | * | ||
542 | * This is used to program the Data Port based on Data Port stream | ||
543 | * parameters. | ||
544 | */ | ||
545 | struct sdw_port_params { | ||
546 | unsigned int num; | ||
547 | unsigned int bps; | ||
548 | unsigned int flow_mode; | ||
549 | unsigned int data_mode; | ||
550 | }; | ||
551 | |||
552 | /** | ||
553 | * struct sdw_transport_params: Data Port Transport Parameters | ||
554 | * | ||
555 | * @blk_grp_ctrl_valid: Port implements block group control | ||
556 | * @num: Port number | ||
557 | * @blk_grp_ctrl: Block group control value | ||
558 | * @sample_interval: Sample interval | ||
559 | * @offset1: Blockoffset of the payload data | ||
560 | * @offset2: Blockoffset of the payload data | ||
561 | * @hstart: Horizontal start of the payload data | ||
562 | * @hstop: Horizontal stop of the payload data | ||
563 | * @blk_pkg_mode: Block per channel or block per port | ||
564 | * @lane_ctrl: Data lane Port uses for Data transfer. Currently only single | ||
565 | * data lane is supported in bus | ||
566 | * | ||
567 | * This is used to program the Data Port based on Data Port transport | ||
568 | * parameters. All these parameters are banked and can be modified | ||
569 | * during a bank switch without any artifacts in audio stream. | ||
570 | */ | ||
571 | struct sdw_transport_params { | ||
572 | bool blk_grp_ctrl_valid; | ||
573 | unsigned int port_num; | ||
574 | unsigned int blk_grp_ctrl; | ||
575 | unsigned int sample_interval; | ||
576 | unsigned int offset1; | ||
577 | unsigned int offset2; | ||
578 | unsigned int hstart; | ||
579 | unsigned int hstop; | ||
580 | unsigned int blk_pkg_mode; | ||
581 | unsigned int lane_ctrl; | ||
582 | }; | ||
583 | |||
584 | /** | ||
585 | * struct sdw_enable_ch: Enable/disable Data Port channel | ||
586 | * | ||
587 | * @num: Port number | ||
588 | * @ch_mask: Active channel mask | ||
589 | * @enable: Enable (true) /disable (false) channel | ||
590 | */ | ||
591 | struct sdw_enable_ch { | ||
592 | unsigned int port_num; | ||
593 | unsigned int ch_mask; | ||
594 | bool enable; | ||
595 | }; | ||
596 | |||
597 | /** | ||
598 | * struct sdw_master_port_ops: Callback functions from bus to Master | ||
599 | * driver to set Master Data ports. | ||
600 | * | ||
601 | * @dpn_set_port_params: Set the Port parameters for the Master Port. | ||
602 | * Mandatory callback | ||
603 | * @dpn_set_port_transport_params: Set transport parameters for the Master | ||
604 | * Port. Mandatory callback | ||
605 | * @dpn_port_prep: Port prepare operations for the Master Data Port. | ||
606 | * @dpn_port_enable_ch: Enable the channels of Master Port. | ||
607 | */ | ||
608 | struct sdw_master_port_ops { | ||
609 | int (*dpn_set_port_params)(struct sdw_bus *bus, | ||
610 | struct sdw_port_params *port_params, | ||
611 | unsigned int bank); | ||
612 | int (*dpn_set_port_transport_params)(struct sdw_bus *bus, | ||
613 | struct sdw_transport_params *transport_params, | ||
614 | enum sdw_reg_bank bank); | ||
615 | int (*dpn_port_prep)(struct sdw_bus *bus, | ||
616 | struct sdw_prepare_ch *prepare_ch); | ||
617 | int (*dpn_port_enable_ch)(struct sdw_bus *bus, | ||
618 | struct sdw_enable_ch *enable_ch, unsigned int bank); | ||
619 | }; | ||
620 | |||
409 | struct sdw_msg; | 621 | struct sdw_msg; |
410 | 622 | ||
411 | /** | 623 | /** |
@@ -426,6 +638,9 @@ struct sdw_defer { | |||
426 | * @xfer_msg: Transfer message callback | 638 | * @xfer_msg: Transfer message callback |
427 | * @xfer_msg_defer: Defer version of transfer message callback | 639 | * @xfer_msg_defer: Defer version of transfer message callback |
428 | * @reset_page_addr: Reset the SCP page address registers | 640 | * @reset_page_addr: Reset the SCP page address registers |
641 | * @set_bus_conf: Set the bus configuration | ||
642 | * @pre_bank_switch: Callback for pre bank switch | ||
643 | * @post_bank_switch: Callback for post bank switch | ||
429 | */ | 644 | */ |
430 | struct sdw_master_ops { | 645 | struct sdw_master_ops { |
431 | int (*read_prop)(struct sdw_bus *bus); | 646 | int (*read_prop)(struct sdw_bus *bus); |
@@ -437,6 +652,11 @@ struct sdw_master_ops { | |||
437 | struct sdw_defer *defer); | 652 | struct sdw_defer *defer); |
438 | enum sdw_command_response (*reset_page_addr) | 653 | enum sdw_command_response (*reset_page_addr) |
439 | (struct sdw_bus *bus, unsigned int dev_num); | 654 | (struct sdw_bus *bus, unsigned int dev_num); |
655 | int (*set_bus_conf)(struct sdw_bus *bus, | ||
656 | struct sdw_bus_params *params); | ||
657 | int (*pre_bank_switch)(struct sdw_bus *bus); | ||
658 | int (*post_bank_switch)(struct sdw_bus *bus); | ||
659 | |||
440 | }; | 660 | }; |
441 | 661 | ||
442 | /** | 662 | /** |
@@ -449,9 +669,15 @@ struct sdw_master_ops { | |||
449 | * @bus_lock: bus lock | 669 | * @bus_lock: bus lock |
450 | * @msg_lock: message lock | 670 | * @msg_lock: message lock |
451 | * @ops: Master callback ops | 671 | * @ops: Master callback ops |
672 | * @port_ops: Master port callback ops | ||
673 | * @params: Current bus parameters | ||
452 | * @prop: Master properties | 674 | * @prop: Master properties |
675 | * @m_rt_list: List of Master instance of all stream(s) running on Bus. This | ||
676 | * is used to compute and program bus bandwidth, clock, frame shape, | ||
677 | * transport and port parameters | ||
453 | * @defer_msg: Defer message | 678 | * @defer_msg: Defer message |
454 | * @clk_stop_timeout: Clock stop timeout computed | 679 | * @clk_stop_timeout: Clock stop timeout computed |
680 | * @bank_switch_timeout: Bank switch timeout computed | ||
455 | */ | 681 | */ |
456 | struct sdw_bus { | 682 | struct sdw_bus { |
457 | struct device *dev; | 683 | struct device *dev; |
@@ -461,14 +687,118 @@ struct sdw_bus { | |||
461 | struct mutex bus_lock; | 687 | struct mutex bus_lock; |
462 | struct mutex msg_lock; | 688 | struct mutex msg_lock; |
463 | const struct sdw_master_ops *ops; | 689 | const struct sdw_master_ops *ops; |
690 | const struct sdw_master_port_ops *port_ops; | ||
691 | struct sdw_bus_params params; | ||
464 | struct sdw_master_prop prop; | 692 | struct sdw_master_prop prop; |
693 | struct list_head m_rt_list; | ||
465 | struct sdw_defer defer_msg; | 694 | struct sdw_defer defer_msg; |
466 | unsigned int clk_stop_timeout; | 695 | unsigned int clk_stop_timeout; |
696 | u32 bank_switch_timeout; | ||
467 | }; | 697 | }; |
468 | 698 | ||
469 | int sdw_add_bus_master(struct sdw_bus *bus); | 699 | int sdw_add_bus_master(struct sdw_bus *bus); |
470 | void sdw_delete_bus_master(struct sdw_bus *bus); | 700 | void sdw_delete_bus_master(struct sdw_bus *bus); |
471 | 701 | ||
702 | /** | ||
703 | * sdw_port_config: Master or Slave Port configuration | ||
704 | * | ||
705 | * @num: Port number | ||
706 | * @ch_mask: channels mask for port | ||
707 | */ | ||
708 | struct sdw_port_config { | ||
709 | unsigned int num; | ||
710 | unsigned int ch_mask; | ||
711 | }; | ||
712 | |||
713 | /** | ||
714 | * sdw_stream_config: Master or Slave stream configuration | ||
715 | * | ||
716 | * @frame_rate: Audio frame rate of the stream, in Hz | ||
717 | * @ch_count: Channel count of the stream | ||
718 | * @bps: Number of bits per audio sample | ||
719 | * @direction: Data direction | ||
720 | * @type: Stream type PCM or PDM | ||
721 | */ | ||
722 | struct sdw_stream_config { | ||
723 | unsigned int frame_rate; | ||
724 | unsigned int ch_count; | ||
725 | unsigned int bps; | ||
726 | enum sdw_data_direction direction; | ||
727 | enum sdw_stream_type type; | ||
728 | }; | ||
729 | |||
730 | /** | ||
731 | * sdw_stream_state: Stream states | ||
732 | * | ||
733 | * @SDW_STREAM_ALLOCATED: New stream allocated. | ||
734 | * @SDW_STREAM_CONFIGURED: Stream configured | ||
735 | * @SDW_STREAM_PREPARED: Stream prepared | ||
736 | * @SDW_STREAM_ENABLED: Stream enabled | ||
737 | * @SDW_STREAM_DISABLED: Stream disabled | ||
738 | * @SDW_STREAM_DEPREPARED: Stream de-prepared | ||
739 | * @SDW_STREAM_RELEASED: Stream released | ||
740 | */ | ||
741 | enum sdw_stream_state { | ||
742 | SDW_STREAM_ALLOCATED = 0, | ||
743 | SDW_STREAM_CONFIGURED = 1, | ||
744 | SDW_STREAM_PREPARED = 2, | ||
745 | SDW_STREAM_ENABLED = 3, | ||
746 | SDW_STREAM_DISABLED = 4, | ||
747 | SDW_STREAM_DEPREPARED = 5, | ||
748 | SDW_STREAM_RELEASED = 6, | ||
749 | }; | ||
750 | |||
751 | /** | ||
752 | * sdw_stream_params: Stream parameters | ||
753 | * | ||
754 | * @rate: Sampling frequency, in Hz | ||
755 | * @ch_count: Number of channels | ||
756 | * @bps: bits per channel sample | ||
757 | */ | ||
758 | struct sdw_stream_params { | ||
759 | unsigned int rate; | ||
760 | unsigned int ch_count; | ||
761 | unsigned int bps; | ||
762 | }; | ||
763 | |||
764 | /** | ||
765 | * sdw_stream_runtime: Runtime stream parameters | ||
766 | * | ||
767 | * @name: SoundWire stream name | ||
768 | * @params: Stream parameters | ||
769 | * @state: Current state of the stream | ||
770 | * @type: Stream type PCM or PDM | ||
771 | * @m_rt: Master runtime | ||
772 | */ | ||
773 | struct sdw_stream_runtime { | ||
774 | char *name; | ||
775 | struct sdw_stream_params params; | ||
776 | enum sdw_stream_state state; | ||
777 | enum sdw_stream_type type; | ||
778 | struct sdw_master_runtime *m_rt; | ||
779 | }; | ||
780 | |||
781 | struct sdw_stream_runtime *sdw_alloc_stream(char *stream_name); | ||
782 | void sdw_release_stream(struct sdw_stream_runtime *stream); | ||
783 | int sdw_stream_add_master(struct sdw_bus *bus, | ||
784 | struct sdw_stream_config *stream_config, | ||
785 | struct sdw_port_config *port_config, | ||
786 | unsigned int num_ports, | ||
787 | struct sdw_stream_runtime *stream); | ||
788 | int sdw_stream_add_slave(struct sdw_slave *slave, | ||
789 | struct sdw_stream_config *stream_config, | ||
790 | struct sdw_port_config *port_config, | ||
791 | unsigned int num_ports, | ||
792 | struct sdw_stream_runtime *stream); | ||
793 | int sdw_stream_remove_master(struct sdw_bus *bus, | ||
794 | struct sdw_stream_runtime *stream); | ||
795 | int sdw_stream_remove_slave(struct sdw_slave *slave, | ||
796 | struct sdw_stream_runtime *stream); | ||
797 | int sdw_prepare_stream(struct sdw_stream_runtime *stream); | ||
798 | int sdw_enable_stream(struct sdw_stream_runtime *stream); | ||
799 | int sdw_disable_stream(struct sdw_stream_runtime *stream); | ||
800 | int sdw_deprepare_stream(struct sdw_stream_runtime *stream); | ||
801 | |||
472 | /* messaging and data APIs */ | 802 | /* messaging and data APIs */ |
473 | 803 | ||
474 | int sdw_read(struct sdw_slave *slave, u32 addr); | 804 | int sdw_read(struct sdw_slave *slave, u32 addr); |
diff --git a/include/linux/soundwire/sdw_intel.h b/include/linux/soundwire/sdw_intel.h index 4b37528f592d..2b9573b8aedd 100644 --- a/include/linux/soundwire/sdw_intel.h +++ b/include/linux/soundwire/sdw_intel.h | |||
@@ -5,17 +5,31 @@ | |||
5 | #define __SDW_INTEL_H | 5 | #define __SDW_INTEL_H |
6 | 6 | ||
7 | /** | 7 | /** |
8 | * struct sdw_intel_ops: Intel audio driver callback ops | ||
9 | * | ||
10 | * @config_stream: configure the stream with the hw_params | ||
11 | */ | ||
12 | struct sdw_intel_ops { | ||
13 | int (*config_stream)(void *arg, void *substream, | ||
14 | void *dai, void *hw_params, int stream_num); | ||
15 | }; | ||
16 | |||
17 | /** | ||
8 | * struct sdw_intel_res - Soundwire Intel resource structure | 18 | * struct sdw_intel_res - Soundwire Intel resource structure |
9 | * @mmio_base: mmio base of SoundWire registers | 19 | * @mmio_base: mmio base of SoundWire registers |
10 | * @irq: interrupt number | 20 | * @irq: interrupt number |
11 | * @handle: ACPI parent handle | 21 | * @handle: ACPI parent handle |
12 | * @parent: parent device | 22 | * @parent: parent device |
23 | * @ops: callback ops | ||
24 | * @arg: callback arg | ||
13 | */ | 25 | */ |
14 | struct sdw_intel_res { | 26 | struct sdw_intel_res { |
15 | void __iomem *mmio_base; | 27 | void __iomem *mmio_base; |
16 | int irq; | 28 | int irq; |
17 | acpi_handle handle; | 29 | acpi_handle handle; |
18 | struct device *parent; | 30 | struct device *parent; |
31 | const struct sdw_intel_ops *ops; | ||
32 | void *arg; | ||
19 | }; | 33 | }; |
20 | 34 | ||
21 | void *sdw_intel_init(acpi_handle *parent_handle, struct sdw_intel_res *res); | 35 | void *sdw_intel_init(acpi_handle *parent_handle, struct sdw_intel_res *res); |
diff --git a/include/linux/uio_driver.h b/include/linux/uio_driver.h index 3c85c81b0027..6c5f2074e14f 100644 --- a/include/linux/uio_driver.h +++ b/include/linux/uio_driver.h | |||
@@ -14,6 +14,7 @@ | |||
14 | #ifndef _UIO_DRIVER_H_ | 14 | #ifndef _UIO_DRIVER_H_ |
15 | #define _UIO_DRIVER_H_ | 15 | #define _UIO_DRIVER_H_ |
16 | 16 | ||
17 | #include <linux/device.h> | ||
17 | #include <linux/fs.h> | 18 | #include <linux/fs.h> |
18 | #include <linux/interrupt.h> | 19 | #include <linux/interrupt.h> |
19 | 20 | ||
@@ -68,12 +69,13 @@ struct uio_port { | |||
68 | 69 | ||
69 | struct uio_device { | 70 | struct uio_device { |
70 | struct module *owner; | 71 | struct module *owner; |
71 | struct device *dev; | 72 | struct device dev; |
72 | int minor; | 73 | int minor; |
73 | atomic_t event; | 74 | atomic_t event; |
74 | struct fasync_struct *async_queue; | 75 | struct fasync_struct *async_queue; |
75 | wait_queue_head_t wait; | 76 | wait_queue_head_t wait; |
76 | struct uio_info *info; | 77 | struct uio_info *info; |
78 | spinlock_t info_lock; | ||
77 | struct kobject *map_dir; | 79 | struct kobject *map_dir; |
78 | struct kobject *portio_dir; | 80 | struct kobject *portio_dir; |
79 | }; | 81 | }; |
diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index 8ad11669e4d8..3ddb575eed54 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h | |||
@@ -170,6 +170,8 @@ struct snd_soc_dai_ops { | |||
170 | unsigned int rx_num, unsigned int *rx_slot); | 170 | unsigned int rx_num, unsigned int *rx_slot); |
171 | int (*set_tristate)(struct snd_soc_dai *dai, int tristate); | 171 | int (*set_tristate)(struct snd_soc_dai *dai, int tristate); |
172 | 172 | ||
173 | int (*set_sdw_stream)(struct snd_soc_dai *dai, | ||
174 | void *stream, int direction); | ||
173 | /* | 175 | /* |
174 | * DAI digital mute - optional. | 176 | * DAI digital mute - optional. |
175 | * Called by soc-core to minimise any pops. | 177 | * Called by soc-core to minimise any pops. |
@@ -358,4 +360,25 @@ static inline void *snd_soc_dai_get_drvdata(struct snd_soc_dai *dai) | |||
358 | return dev_get_drvdata(dai->dev); | 360 | return dev_get_drvdata(dai->dev); |
359 | } | 361 | } |
360 | 362 | ||
363 | /** | ||
364 | * snd_soc_dai_set_sdw_stream() - Configures a DAI for SDW stream operation | ||
365 | * @dai: DAI | ||
366 | * @stream: STREAM | ||
367 | * @direction: Stream direction(Playback/Capture) | ||
368 | * SoundWire subsystem doesn't have a notion of direction and we reuse | ||
369 | * the ASoC stream direction to configure sink/source ports. | ||
370 | * Playback maps to source ports and Capture for sink ports. | ||
371 | * | ||
372 | * This should be invoked with NULL to clear the stream set previously. | ||
373 | * Returns 0 on success, a negative error code otherwise. | ||
374 | */ | ||
375 | static inline int snd_soc_dai_set_sdw_stream(struct snd_soc_dai *dai, | ||
376 | void *stream, int direction) | ||
377 | { | ||
378 | if (dai->driver->ops->set_sdw_stream) | ||
379 | return dai->driver->ops->set_sdw_stream(dai, stream, direction); | ||
380 | else | ||
381 | return -ENOTSUPP; | ||
382 | } | ||
383 | |||
361 | #endif | 384 | #endif |
diff --git a/scripts/mod/devicetable-offsets.c b/scripts/mod/devicetable-offsets.c index 9fad6afe4c41..6667f7b491d6 100644 --- a/scripts/mod/devicetable-offsets.c +++ b/scripts/mod/devicetable-offsets.c | |||
@@ -139,6 +139,9 @@ int main(void) | |||
139 | DEVID(hv_vmbus_device_id); | 139 | DEVID(hv_vmbus_device_id); |
140 | DEVID_FIELD(hv_vmbus_device_id, guid); | 140 | DEVID_FIELD(hv_vmbus_device_id, guid); |
141 | 141 | ||
142 | DEVID(rpmsg_device_id); | ||
143 | DEVID_FIELD(rpmsg_device_id, name); | ||
144 | |||
142 | DEVID(i2c_device_id); | 145 | DEVID(i2c_device_id); |
143 | DEVID_FIELD(i2c_device_id, name); | 146 | DEVID_FIELD(i2c_device_id, name); |
144 | 147 | ||
diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index b9beeaa4695b..52fd54a8fe39 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c | |||
@@ -944,6 +944,17 @@ static int do_vmbus_entry(const char *filename, void *symval, | |||
944 | } | 944 | } |
945 | ADD_TO_DEVTABLE("vmbus", hv_vmbus_device_id, do_vmbus_entry); | 945 | ADD_TO_DEVTABLE("vmbus", hv_vmbus_device_id, do_vmbus_entry); |
946 | 946 | ||
947 | /* Looks like: rpmsg:S */ | ||
948 | static int do_rpmsg_entry(const char *filename, void *symval, | ||
949 | char *alias) | ||
950 | { | ||
951 | DEF_FIELD_ADDR(symval, rpmsg_device_id, name); | ||
952 | sprintf(alias, RPMSG_DEVICE_MODALIAS_FMT, *name); | ||
953 | |||
954 | return 1; | ||
955 | } | ||
956 | ADD_TO_DEVTABLE("rpmsg", rpmsg_device_id, do_rpmsg_entry); | ||
957 | |||
947 | /* Looks like: i2c:S */ | 958 | /* Looks like: i2c:S */ |
948 | static int do_i2c_entry(const char *filename, void *symval, | 959 | static int do_i2c_entry(const char *filename, void *symval, |
949 | char *alias) | 960 | char *alias) |
diff --git a/scripts/ver_linux b/scripts/ver_linux index 545ec7388eb7..7227994ccf63 100755 --- a/scripts/ver_linux +++ b/scripts/ver_linux | |||
@@ -13,36 +13,34 @@ BEGIN { | |||
13 | system("uname -a") | 13 | system("uname -a") |
14 | printf("\n") | 14 | printf("\n") |
15 | 15 | ||
16 | printversion("GNU C", version("gcc -dumpversion 2>&1")) | 16 | printversion("GNU C", version("gcc -dumpversion")) |
17 | printversion("GNU Make", version("make --version 2>&1")) | 17 | printversion("GNU Make", version("make --version")) |
18 | printversion("Binutils", version("ld -v 2>&1")) | 18 | printversion("Binutils", version("ld -v")) |
19 | printversion("Util-linux", version("mount --version 2>&1")) | 19 | printversion("Util-linux", version("mount --version")) |
20 | printversion("Mount", version("mount --version 2>&1")) | 20 | printversion("Mount", version("mount --version")) |
21 | printversion("Module-init-tools", version("depmod -V 2>&1")) | 21 | printversion("Module-init-tools", version("depmod -V")) |
22 | printversion("E2fsprogs", version("tune2fs 2>&1")) | 22 | printversion("E2fsprogs", version("tune2fs")) |
23 | printversion("Jfsutils", version("fsck.jfs -V 2>&1")) | 23 | printversion("Jfsutils", version("fsck.jfs -V")) |
24 | printversion("Reiserfsprogs", version("reiserfsck -V 2>&1")) | 24 | printversion("Reiserfsprogs", version("reiserfsck -V")) |
25 | printversion("Reiser4fsprogs", version("fsck.reiser4 -V 2>&1")) | 25 | printversion("Reiser4fsprogs", version("fsck.reiser4 -V")) |
26 | printversion("Xfsprogs", version("xfs_db -V 2>&1")) | 26 | printversion("Xfsprogs", version("xfs_db -V")) |
27 | printversion("Pcmciautils", version("pccardctl -V 2>&1")) | 27 | printversion("Pcmciautils", version("pccardctl -V")) |
28 | printversion("Pcmcia-cs", version("cardmgr -V 2>&1")) | 28 | printversion("Pcmcia-cs", version("cardmgr -V")) |
29 | printversion("Quota-tools", version("quota -V 2>&1")) | 29 | printversion("Quota-tools", version("quota -V")) |
30 | printversion("PPP", version("pppd --version 2>&1")) | 30 | printversion("PPP", version("pppd --version")) |
31 | printversion("Isdn4k-utils", version("isdnctrl 2>&1")) | 31 | printversion("Isdn4k-utils", version("isdnctrl")) |
32 | printversion("Nfs-utils", version("showmount --version 2>&1")) | 32 | printversion("Nfs-utils", version("showmount --version")) |
33 | 33 | ||
34 | if (system("test -r /proc/self/maps") == 0) { | 34 | while (getline <"/proc/self/maps" > 0) { |
35 | while (getline <"/proc/self/maps" > 0) { | 35 | n = split($0, procmaps, "/") |
36 | n = split($0, procmaps, "/") | 36 | if (/libc.*so$/ && match(procmaps[n], /[0-9]+([.]?[0-9]+)+/)) { |
37 | if (/libc.*so$/ && match(procmaps[n], /[0-9]+([.]?[0-9]+)+/)) { | 37 | ver = substr(procmaps[n], RSTART, RLENGTH) |
38 | ver = substr(procmaps[n], RSTART, RLENGTH) | 38 | printversion("Linux C Library", ver) |
39 | printversion("Linux C Library", ver) | 39 | break |
40 | break | ||
41 | } | ||
42 | } | 40 | } |
43 | } | 41 | } |
44 | 42 | ||
45 | printversion("Dynamic linker (ldd)", version("ldd --version 2>&1")) | 43 | printversion("Dynamic linker (ldd)", version("ldd --version")) |
46 | 44 | ||
47 | while ("ldconfig -p 2>/dev/null" | getline > 0) { | 45 | while ("ldconfig -p 2>/dev/null" | getline > 0) { |
48 | if (/(libg|stdc)[+]+\.so/) { | 46 | if (/(libg|stdc)[+]+\.so/) { |
@@ -50,28 +48,25 @@ BEGIN { | |||
50 | break | 48 | break |
51 | } | 49 | } |
52 | } | 50 | } |
53 | if (system("test -r " libcpp) == 0) | 51 | printversion("Linux C++ Library", version("readlink " libcpp)) |
54 | printversion("Linux C++ Library", version("readlink " libcpp)) | 52 | printversion("Procps", version("ps --version")) |
55 | 53 | printversion("Net-tools", version("ifconfig --version")) | |
56 | printversion("Procps", version("ps --version 2>&1")) | 54 | printversion("Kbd", version("loadkeys -V")) |
57 | printversion("Net-tools", version("ifconfig --version 2>&1")) | 55 | printversion("Console-tools", version("loadkeys -V")) |
58 | printversion("Kbd", version("loadkeys -V 2>&1")) | 56 | printversion("Oprofile", version("oprofiled --version")) |
59 | printversion("Console-tools", version("loadkeys -V 2>&1")) | 57 | printversion("Sh-utils", version("expr --v")) |
60 | printversion("Oprofile", version("oprofiled --version 2>&1")) | 58 | printversion("Udev", version("udevadm --version")) |
61 | printversion("Sh-utils", version("expr --v 2>&1")) | 59 | printversion("Wireless-tools", version("iwconfig --version")) |
62 | printversion("Udev", version("udevadm --version 2>&1")) | ||
63 | printversion("Wireless-tools", version("iwconfig --version 2>&1")) | ||
64 | 60 | ||
65 | if (system("test -r /proc/modules") == 0) { | 61 | while ("sort /proc/modules" | getline > 0) { |
66 | while ("sort /proc/modules" | getline > 0) { | 62 | mods = mods sep $1 |
67 | mods = mods sep $1 | 63 | sep = " " |
68 | sep = " " | ||
69 | } | ||
70 | printversion("Modules Loaded", mods) | ||
71 | } | 64 | } |
65 | printversion("Modules Loaded", mods) | ||
72 | } | 66 | } |
73 | 67 | ||
74 | function version(cmd, ver) { | 68 | function version(cmd, ver) { |
69 | cmd = cmd " 2>&1" | ||
75 | while (cmd | getline > 0) { | 70 | while (cmd | getline > 0) { |
76 | if (!/ver_linux/ && match($0, /[0-9]+([.]?[0-9]+)+/)) { | 71 | if (!/ver_linux/ && match($0, /[0-9]+([.]?[0-9]+)+/)) { |
77 | ver = substr($0, RSTART, RLENGTH) | 72 | ver = substr($0, RSTART, RLENGTH) |