diff options
author | Bjorn Helgaas <bhelgaas@google.com> | 2017-04-28 11:32:33 -0400 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2017-04-28 11:32:33 -0400 |
commit | 9b2707ca56f98d1184857384ebecd23e1f06c807 (patch) | |
tree | bed29b8550b6e10eec99f726062ac7b94e1f669e | |
parent | c1ae3cfa0e89fa1a7ecc4c99031f5e9ae99d9201 (diff) | |
parent | 2c949ce38f4e81d7487f165fa3b8f77d74a2a6c4 (diff) |
Merge branch 'pci/host-designware' into next
* pci/host-designware:
ARM: DRA7: clockdomain: Change the CLKTRCTRL of CM_PCIE_CLKSTCTRL to SW_WKUP
MAINTAINERS: Add PCI Endpoint maintainer
Documentation: PCI: Add userguide for PCI endpoint test function
tools: PCI: Add sample test script to invoke pcitest
tools: PCI: Add a userspace tool to test PCI endpoint
Documentation: misc-devices: Add Documentation for pci-endpoint-test driver
misc: Add host side PCI driver for PCI test function device
PCI: Add device IDs for DRA74x and DRA72x
dt-bindings: PCI: dra7xx: Add DT bindings to enable unaligned access
PCI: dwc: dra7xx: Workaround for errata id i870
dt-bindings: PCI: dra7xx: Add DT bindings for PCI dra7xx EP mode
PCI: dwc: dra7xx: Add EP mode support
PCI: dwc: dra7xx: Facilitate wrapper and MSI interrupts to be enabled independently
dt-bindings: PCI: Add DT bindings for PCI designware EP mode
PCI: dwc: designware: Add EP mode support
Documentation: PCI: Add binding documentation for pci-test endpoint function
PCI: endpoint: functions: Add an EP function to test PCI
Documentation: PCI: Add specification for the *PCI test* function device
PCI: endpoint: Create configfs entry for EPC device and EPF driver
Documentation: PCI: Guide to use PCI endpoint configfs
PCI: endpoint: Introduce configfs entry for configuring EP functions
Documentation: PCI: Guide to use PCI Endpoint Core Layer
PCI: endpoint: Add EP core layer to enable EP controller and EP functions
PCI: dwc: dra7xx: Push request_irq() call to the bottom of probe
PCI: dwc: designware: Move _unroll configurations to a separate function
PCI: dwc: all: Modify dbi accessors to access data of 4/2/1 bytes
PCI: dwc: all: Modify dbi accessors to take dbi_base as argument
PCI: dwc: artpec6: Populate cpu_addr_fixup ops
PCI: dwc: dra7xx: Populate cpu_addr_fixup ops
PCI: dwc: designware: Add new *ops* for CPU addr fixup
PCI: dwc: Fix uninitialized variable in dw_handle_msi_irq()
PCI: dwc: Unindent dw_handle_msi_irq() loop
PCI: dwc: Fix dw_pcie_ops NULL pointer dereference
PCI: dwc: Select PCI_HOST_COMMON for hisi
PCI: thunder-pem: Fix legacy firmware PEM-specific resources
PCI: thunder-pem: Add legacy firmware support for Cavium ThunderX host controller
PCI: thunder-pem: Use Cavium assigned hardware ID for ThunderX host controller
PCI: iproc: Save host bridge window resource in struct iproc_pcie
PCI/ASPM: Always set link->downstream to avoid NULL dereference on remove
PCI: Prevent VPD access for QLogic ISP2722
PCI: exynos: Initialize elbi_base even when using PHY framework
50 files changed, 5122 insertions, 158 deletions
diff --git a/Documentation/PCI/00-INDEX b/Documentation/PCI/00-INDEX index 147231f1613e..00c9a90b6f38 100644 --- a/Documentation/PCI/00-INDEX +++ b/Documentation/PCI/00-INDEX | |||
@@ -12,3 +12,13 @@ pci.txt | |||
12 | - info on the PCI subsystem for device driver authors | 12 | - info on the PCI subsystem for device driver authors |
13 | pcieaer-howto.txt | 13 | pcieaer-howto.txt |
14 | - the PCI Express Advanced Error Reporting Driver Guide HOWTO | 14 | - the PCI Express Advanced Error Reporting Driver Guide HOWTO |
15 | endpoint/pci-endpoint.txt | ||
16 | - guide to add endpoint controller driver and endpoint function driver. | ||
17 | endpoint/pci-endpoint-cfs.txt | ||
18 | - guide to use configfs to configure the PCI endpoint function. | ||
19 | endpoint/pci-test-function.txt | ||
20 | - specification of *PCI test* function device. | ||
21 | endpoint/pci-test-howto.txt | ||
22 | - userguide for PCI endpoint test function. | ||
23 | endpoint/function/binding/ | ||
24 | - binding documentation for PCI endpoint function | ||
diff --git a/Documentation/PCI/endpoint/function/binding/pci-test.txt b/Documentation/PCI/endpoint/function/binding/pci-test.txt new file mode 100644 index 000000000000..3b68b955fb50 --- /dev/null +++ b/Documentation/PCI/endpoint/function/binding/pci-test.txt | |||
@@ -0,0 +1,17 @@ | |||
1 | PCI TEST ENDPOINT FUNCTION | ||
2 | |||
3 | name: Should be "pci_epf_test" to bind to the pci_epf_test driver. | ||
4 | |||
5 | Configurable Fields: | ||
6 | vendorid : should be 0x104c | ||
7 | deviceid : should be 0xb500 for DRA74x and 0xb501 for DRA72x | ||
8 | revid : don't care | ||
9 | progif_code : don't care | ||
10 | subclass_code : don't care | ||
11 | baseclass_code : should be 0xff | ||
12 | cache_line_size : don't care | ||
13 | subsys_vendor_id : don't care | ||
14 | subsys_id : don't care | ||
15 | interrupt_pin : Should be 1 - INTA, 2 - INTB, 3 - INTC, 4 -INTD | ||
16 | msi_interrupts : Should be 1 to 32 depending on the number of MSI interrupts | ||
17 | to test | ||
diff --git a/Documentation/PCI/endpoint/pci-endpoint-cfs.txt b/Documentation/PCI/endpoint/pci-endpoint-cfs.txt new file mode 100644 index 000000000000..d740f29960a4 --- /dev/null +++ b/Documentation/PCI/endpoint/pci-endpoint-cfs.txt | |||
@@ -0,0 +1,105 @@ | |||
1 | CONFIGURING PCI ENDPOINT USING CONFIGFS | ||
2 | Kishon Vijay Abraham I <kishon@ti.com> | ||
3 | |||
4 | The PCI Endpoint Core exposes configfs entry (pci_ep) to configure the | ||
5 | PCI endpoint function and to bind the endpoint function | ||
6 | with the endpoint controller. (For introducing other mechanisms to | ||
7 | configure the PCI Endpoint Function refer to [1]). | ||
8 | |||
9 | *) Mounting configfs | ||
10 | |||
11 | The PCI Endpoint Core layer creates pci_ep directory in the mounted configfs | ||
12 | directory. configfs can be mounted using the following command. | ||
13 | |||
14 | mount -t configfs none /sys/kernel/config | ||
15 | |||
16 | *) Directory Structure | ||
17 | |||
18 | The pci_ep configfs has two directories at its root: controllers and | ||
19 | functions. Every EPC device present in the system will have an entry in | ||
20 | the *controllers* directory and and every EPF driver present in the system | ||
21 | will have an entry in the *functions* directory. | ||
22 | |||
23 | /sys/kernel/config/pci_ep/ | ||
24 | .. controllers/ | ||
25 | .. functions/ | ||
26 | |||
27 | *) Creating EPF Device | ||
28 | |||
29 | Every registered EPF driver will be listed in controllers directory. The | ||
30 | entries corresponding to EPF driver will be created by the EPF core. | ||
31 | |||
32 | /sys/kernel/config/pci_ep/functions/ | ||
33 | .. <EPF Driver1>/ | ||
34 | ... <EPF Device 11>/ | ||
35 | ... <EPF Device 21>/ | ||
36 | .. <EPF Driver2>/ | ||
37 | ... <EPF Device 12>/ | ||
38 | ... <EPF Device 22>/ | ||
39 | |||
40 | In order to create a <EPF device> of the type probed by <EPF Driver>, the | ||
41 | user has to create a directory inside <EPF DriverN>. | ||
42 | |||
43 | Every <EPF device> directory consists of the following entries that can be | ||
44 | used to configure the standard configuration header of the endpoint function. | ||
45 | (These entries are created by the framework when any new <EPF Device> is | ||
46 | created) | ||
47 | |||
48 | .. <EPF Driver1>/ | ||
49 | ... <EPF Device 11>/ | ||
50 | ... vendorid | ||
51 | ... deviceid | ||
52 | ... revid | ||
53 | ... progif_code | ||
54 | ... subclass_code | ||
55 | ... baseclass_code | ||
56 | ... cache_line_size | ||
57 | ... subsys_vendor_id | ||
58 | ... subsys_id | ||
59 | ... interrupt_pin | ||
60 | |||
61 | *) EPC Device | ||
62 | |||
63 | Every registered EPC device will be listed in controllers directory. The | ||
64 | entries corresponding to EPC device will be created by the EPC core. | ||
65 | |||
66 | /sys/kernel/config/pci_ep/controllers/ | ||
67 | .. <EPC Device1>/ | ||
68 | ... <Symlink EPF Device11>/ | ||
69 | ... <Symlink EPF Device12>/ | ||
70 | ... start | ||
71 | .. <EPC Device2>/ | ||
72 | ... <Symlink EPF Device21>/ | ||
73 | ... <Symlink EPF Device22>/ | ||
74 | ... start | ||
75 | |||
76 | The <EPC Device> directory will have a list of symbolic links to | ||
77 | <EPF Device>. These symbolic links should be created by the user to | ||
78 | represent the functions present in the endpoint device. | ||
79 | |||
80 | The <EPC Device> directory will also have a *start* field. Once | ||
81 | "1" is written to this field, the endpoint device will be ready to | ||
82 | establish the link with the host. This is usually done after | ||
83 | all the EPF devices are created and linked with the EPC device. | ||
84 | |||
85 | |||
86 | | controllers/ | ||
87 | | <Directory: EPC name>/ | ||
88 | | <Symbolic Link: Function> | ||
89 | | start | ||
90 | | functions/ | ||
91 | | <Directory: EPF driver>/ | ||
92 | | <Directory: EPF device>/ | ||
93 | | vendorid | ||
94 | | deviceid | ||
95 | | revid | ||
96 | | progif_code | ||
97 | | subclass_code | ||
98 | | baseclass_code | ||
99 | | cache_line_size | ||
100 | | subsys_vendor_id | ||
101 | | subsys_id | ||
102 | | interrupt_pin | ||
103 | | function | ||
104 | |||
105 | [1] -> Documentation/PCI/endpoint/pci-endpoint.txt | ||
diff --git a/Documentation/PCI/endpoint/pci-endpoint.txt b/Documentation/PCI/endpoint/pci-endpoint.txt new file mode 100644 index 000000000000..9b1d66829290 --- /dev/null +++ b/Documentation/PCI/endpoint/pci-endpoint.txt | |||
@@ -0,0 +1,215 @@ | |||
1 | PCI ENDPOINT FRAMEWORK | ||
2 | Kishon Vijay Abraham I <kishon@ti.com> | ||
3 | |||
4 | This document is a guide to use the PCI Endpoint Framework in order to create | ||
5 | endpoint controller driver, endpoint function driver, and using configfs | ||
6 | interface to bind the function driver to the controller driver. | ||
7 | |||
8 | 1. Introduction | ||
9 | |||
10 | Linux has a comprehensive PCI subsystem to support PCI controllers that | ||
11 | operates in Root Complex mode. The subsystem has capability to scan PCI bus, | ||
12 | assign memory resources and IRQ resources, load PCI driver (based on | ||
13 | vendor ID, device ID), support other services like hot-plug, power management, | ||
14 | advanced error reporting and virtual channels. | ||
15 | |||
16 | However the PCI controller IP integrated in some SoCs is capable of operating | ||
17 | either in Root Complex mode or Endpoint mode. PCI Endpoint Framework will | ||
18 | add endpoint mode support in Linux. This will help to run Linux in an | ||
19 | EP system which can have a wide variety of use cases from testing or | ||
20 | validation, co-processor accelerator, etc. | ||
21 | |||
22 | 2. PCI Endpoint Core | ||
23 | |||
24 | The PCI Endpoint Core layer comprises 3 components: the Endpoint Controller | ||
25 | library, the Endpoint Function library, and the configfs layer to bind the | ||
26 | endpoint function with the endpoint controller. | ||
27 | |||
28 | 2.1 PCI Endpoint Controller(EPC) Library | ||
29 | |||
30 | The EPC library provides APIs to be used by the controller that can operate | ||
31 | in endpoint mode. It also provides APIs to be used by function driver/library | ||
32 | in order to implement a particular endpoint function. | ||
33 | |||
34 | 2.1.1 APIs for the PCI controller Driver | ||
35 | |||
36 | This section lists the APIs that the PCI Endpoint core provides to be used | ||
37 | by the PCI controller driver. | ||
38 | |||
39 | *) devm_pci_epc_create()/pci_epc_create() | ||
40 | |||
41 | The PCI controller driver should implement the following ops: | ||
42 | * write_header: ops to populate configuration space header | ||
43 | * set_bar: ops to configure the BAR | ||
44 | * clear_bar: ops to reset the BAR | ||
45 | * alloc_addr_space: ops to allocate in PCI controller address space | ||
46 | * free_addr_space: ops to free the allocated address space | ||
47 | * raise_irq: ops to raise a legacy or MSI interrupt | ||
48 | * start: ops to start the PCI link | ||
49 | * stop: ops to stop the PCI link | ||
50 | |||
51 | The PCI controller driver can then create a new EPC device by invoking | ||
52 | devm_pci_epc_create()/pci_epc_create(). | ||
53 | |||
54 | *) devm_pci_epc_destroy()/pci_epc_destroy() | ||
55 | |||
56 | The PCI controller driver can destroy the EPC device created by either | ||
57 | devm_pci_epc_create() or pci_epc_create() using devm_pci_epc_destroy() or | ||
58 | pci_epc_destroy(). | ||
59 | |||
60 | *) pci_epc_linkup() | ||
61 | |||
62 | In order to notify all the function devices that the EPC device to which | ||
63 | they are linked has established a link with the host, the PCI controller | ||
64 | driver should invoke pci_epc_linkup(). | ||
65 | |||
66 | *) pci_epc_mem_init() | ||
67 | |||
68 | Initialize the pci_epc_mem structure used for allocating EPC addr space. | ||
69 | |||
70 | *) pci_epc_mem_exit() | ||
71 | |||
72 | Cleanup the pci_epc_mem structure allocated during pci_epc_mem_init(). | ||
73 | |||
74 | 2.1.2 APIs for the PCI Endpoint Function Driver | ||
75 | |||
76 | This section lists the APIs that the PCI Endpoint core provides to be used | ||
77 | by the PCI endpoint function driver. | ||
78 | |||
79 | *) pci_epc_write_header() | ||
80 | |||
81 | The PCI endpoint function driver should use pci_epc_write_header() to | ||
82 | write the standard configuration header to the endpoint controller. | ||
83 | |||
84 | *) pci_epc_set_bar() | ||
85 | |||
86 | The PCI endpoint function driver should use pci_epc_set_bar() to configure | ||
87 | the Base Address Register in order for the host to assign PCI addr space. | ||
88 | Register space of the function driver is usually configured | ||
89 | using this API. | ||
90 | |||
91 | *) pci_epc_clear_bar() | ||
92 | |||
93 | The PCI endpoint function driver should use pci_epc_clear_bar() to reset | ||
94 | the BAR. | ||
95 | |||
96 | *) pci_epc_raise_irq() | ||
97 | |||
98 | The PCI endpoint function driver should use pci_epc_raise_irq() to raise | ||
99 | Legacy Interrupt or MSI Interrupt. | ||
100 | |||
101 | *) pci_epc_mem_alloc_addr() | ||
102 | |||
103 | The PCI endpoint function driver should use pci_epc_mem_alloc_addr(), to | ||
104 | allocate memory address from EPC addr space which is required to access | ||
105 | RC's buffer | ||
106 | |||
107 | *) pci_epc_mem_free_addr() | ||
108 | |||
109 | The PCI endpoint function driver should use pci_epc_mem_free_addr() to | ||
110 | free the memory space allocated using pci_epc_mem_alloc_addr(). | ||
111 | |||
112 | 2.1.3 Other APIs | ||
113 | |||
114 | There are other APIs provided by the EPC library. These are used for binding | ||
115 | the EPF device with EPC device. pci-ep-cfs.c can be used as reference for | ||
116 | using these APIs. | ||
117 | |||
118 | *) pci_epc_get() | ||
119 | |||
120 | Get a reference to the PCI endpoint controller based on the device name of | ||
121 | the controller. | ||
122 | |||
123 | *) pci_epc_put() | ||
124 | |||
125 | Release the reference to the PCI endpoint controller obtained using | ||
126 | pci_epc_get() | ||
127 | |||
128 | *) pci_epc_add_epf() | ||
129 | |||
130 | Add a PCI endpoint function to a PCI endpoint controller. A PCIe device | ||
131 | can have up to 8 functions according to the specification. | ||
132 | |||
133 | *) pci_epc_remove_epf() | ||
134 | |||
135 | Remove the PCI endpoint function from PCI endpoint controller. | ||
136 | |||
137 | *) pci_epc_start() | ||
138 | |||
139 | The PCI endpoint function driver should invoke pci_epc_start() once it | ||
140 | has configured the endpoint function and wants to start the PCI link. | ||
141 | |||
142 | *) pci_epc_stop() | ||
143 | |||
144 | The PCI endpoint function driver should invoke pci_epc_stop() to stop | ||
145 | the PCI LINK. | ||
146 | |||
147 | 2.2 PCI Endpoint Function(EPF) Library | ||
148 | |||
149 | The EPF library provides APIs to be used by the function driver and the EPC | ||
150 | library to provide endpoint mode functionality. | ||
151 | |||
152 | 2.2.1 APIs for the PCI Endpoint Function Driver | ||
153 | |||
154 | This section lists the APIs that the PCI Endpoint core provides to be used | ||
155 | by the PCI endpoint function driver. | ||
156 | |||
157 | *) pci_epf_register_driver() | ||
158 | |||
159 | The PCI Endpoint Function driver should implement the following ops: | ||
160 | * bind: ops to perform when a EPC device has been bound to EPF device | ||
161 | * unbind: ops to perform when a binding has been lost between a EPC | ||
162 | device and EPF device | ||
163 | * linkup: ops to perform when the EPC device has established a | ||
164 | connection with a host system | ||
165 | |||
166 | The PCI Function driver can then register the PCI EPF driver by using | ||
167 | pci_epf_register_driver(). | ||
168 | |||
169 | *) pci_epf_unregister_driver() | ||
170 | |||
171 | The PCI Function driver can unregister the PCI EPF driver by using | ||
172 | pci_epf_unregister_driver(). | ||
173 | |||
174 | *) pci_epf_alloc_space() | ||
175 | |||
176 | The PCI Function driver can allocate space for a particular BAR using | ||
177 | pci_epf_alloc_space(). | ||
178 | |||
179 | *) pci_epf_free_space() | ||
180 | |||
181 | The PCI Function driver can free the allocated space | ||
182 | (using pci_epf_alloc_space) by invoking pci_epf_free_space(). | ||
183 | |||
184 | 2.2.2 APIs for the PCI Endpoint Controller Library | ||
185 | This section lists the APIs that the PCI Endpoint core provides to be used | ||
186 | by the PCI endpoint controller library. | ||
187 | |||
188 | *) pci_epf_linkup() | ||
189 | |||
190 | The PCI endpoint controller library invokes pci_epf_linkup() when the | ||
191 | EPC device has established the connection to the host. | ||
192 | |||
193 | 2.2.2 Other APIs | ||
194 | There are other APIs provided by the EPF library. These are used to notify | ||
195 | the function driver when the EPF device is bound to the EPC device. | ||
196 | pci-ep-cfs.c can be used as reference for using these APIs. | ||
197 | |||
198 | *) pci_epf_create() | ||
199 | |||
200 | Create a new PCI EPF device by passing the name of the PCI EPF device. | ||
201 | This name will be used to bind the the EPF device to a EPF driver. | ||
202 | |||
203 | *) pci_epf_destroy() | ||
204 | |||
205 | Destroy the created PCI EPF device. | ||
206 | |||
207 | *) pci_epf_bind() | ||
208 | |||
209 | pci_epf_bind() should be invoked when the EPF device has been bound to | ||
210 | a EPC device. | ||
211 | |||
212 | *) pci_epf_unbind() | ||
213 | |||
214 | pci_epf_unbind() should be invoked when the binding between EPC device | ||
215 | and EPF device is lost. | ||
diff --git a/Documentation/PCI/endpoint/pci-test-function.txt b/Documentation/PCI/endpoint/pci-test-function.txt new file mode 100644 index 000000000000..0c519c9bf94a --- /dev/null +++ b/Documentation/PCI/endpoint/pci-test-function.txt | |||
@@ -0,0 +1,66 @@ | |||
1 | PCI TEST | ||
2 | Kishon Vijay Abraham I <kishon@ti.com> | ||
3 | |||
4 | Traditionally PCI RC has always been validated by using standard | ||
5 | PCI cards like ethernet PCI cards or USB PCI cards or SATA PCI cards. | ||
6 | However with the addition of EP-core in linux kernel, it is possible | ||
7 | to configure a PCI controller that can operate in EP mode to work as | ||
8 | a test device. | ||
9 | |||
10 | The PCI endpoint test device is a virtual device (defined in software) | ||
11 | used to test the endpoint functionality and serve as a sample driver | ||
12 | for other PCI endpoint devices (to use the EP framework). | ||
13 | |||
14 | The PCI endpoint test device has the following registers: | ||
15 | |||
16 | 1) PCI_ENDPOINT_TEST_MAGIC | ||
17 | 2) PCI_ENDPOINT_TEST_COMMAND | ||
18 | 3) PCI_ENDPOINT_TEST_STATUS | ||
19 | 4) PCI_ENDPOINT_TEST_SRC_ADDR | ||
20 | 5) PCI_ENDPOINT_TEST_DST_ADDR | ||
21 | 6) PCI_ENDPOINT_TEST_SIZE | ||
22 | 7) PCI_ENDPOINT_TEST_CHECKSUM | ||
23 | |||
24 | *) PCI_ENDPOINT_TEST_MAGIC | ||
25 | |||
26 | This register will be used to test BAR0. A known pattern will be written | ||
27 | and read back from MAGIC register to verify BAR0. | ||
28 | |||
29 | *) PCI_ENDPOINT_TEST_COMMAND: | ||
30 | |||
31 | This register will be used by the host driver to indicate the function | ||
32 | that the endpoint device must perform. | ||
33 | |||
34 | Bitfield Description: | ||
35 | Bit 0 : raise legacy IRQ | ||
36 | Bit 1 : raise MSI IRQ | ||
37 | Bit 2 - 7 : MSI interrupt number | ||
38 | Bit 8 : read command (read data from RC buffer) | ||
39 | Bit 9 : write command (write data to RC buffer) | ||
40 | Bit 10 : copy command (copy data from one RC buffer to another | ||
41 | RC buffer) | ||
42 | |||
43 | *) PCI_ENDPOINT_TEST_STATUS | ||
44 | |||
45 | This register reflects the status of the PCI endpoint device. | ||
46 | |||
47 | Bitfield Description: | ||
48 | Bit 0 : read success | ||
49 | Bit 1 : read fail | ||
50 | Bit 2 : write success | ||
51 | Bit 3 : write fail | ||
52 | Bit 4 : copy success | ||
53 | Bit 5 : copy fail | ||
54 | Bit 6 : IRQ raised | ||
55 | Bit 7 : source address is invalid | ||
56 | Bit 8 : destination address is invalid | ||
57 | |||
58 | *) PCI_ENDPOINT_TEST_SRC_ADDR | ||
59 | |||
60 | This register contains the source address (RC buffer address) for the | ||
61 | COPY/READ command. | ||
62 | |||
63 | *) PCI_ENDPOINT_TEST_DST_ADDR | ||
64 | |||
65 | This register contains the destination address (RC buffer address) for | ||
66 | the COPY/WRITE command. | ||
diff --git a/Documentation/PCI/endpoint/pci-test-howto.txt b/Documentation/PCI/endpoint/pci-test-howto.txt new file mode 100644 index 000000000000..75f48c3bb191 --- /dev/null +++ b/Documentation/PCI/endpoint/pci-test-howto.txt | |||
@@ -0,0 +1,179 @@ | |||
1 | PCI TEST USERGUIDE | ||
2 | Kishon Vijay Abraham I <kishon@ti.com> | ||
3 | |||
4 | This document is a guide to help users use pci-epf-test function driver | ||
5 | and pci_endpoint_test host driver for testing PCI. The list of steps to | ||
6 | be followed in the host side and EP side is given below. | ||
7 | |||
8 | 1. Endpoint Device | ||
9 | |||
10 | 1.1 Endpoint Controller Devices | ||
11 | |||
12 | To find the list of endpoint controller devices in the system: | ||
13 | |||
14 | # ls /sys/class/pci_epc/ | ||
15 | 51000000.pcie_ep | ||
16 | |||
17 | If PCI_ENDPOINT_CONFIGFS is enabled | ||
18 | # ls /sys/kernel/config/pci_ep/controllers | ||
19 | 51000000.pcie_ep | ||
20 | |||
21 | 1.2 Endpoint Function Drivers | ||
22 | |||
23 | To find the list of endpoint function drivers in the system: | ||
24 | |||
25 | # ls /sys/bus/pci-epf/drivers | ||
26 | pci_epf_test | ||
27 | |||
28 | If PCI_ENDPOINT_CONFIGFS is enabled | ||
29 | # ls /sys/kernel/config/pci_ep/functions | ||
30 | pci_epf_test | ||
31 | |||
32 | 1.3 Creating pci-epf-test Device | ||
33 | |||
34 | PCI endpoint function device can be created using the configfs. To create | ||
35 | pci-epf-test device, the following commands can be used | ||
36 | |||
37 | # mount -t configfs none /sys/kernel/config | ||
38 | # cd /sys/kernel/config/pci_ep/ | ||
39 | # mkdir functions/pci_epf_test/func1 | ||
40 | |||
41 | The "mkdir func1" above creates the pci-epf-test function device that will | ||
42 | be probed by pci_epf_test driver. | ||
43 | |||
44 | The PCI endpoint framework populates the directory with the following | ||
45 | configurable fields. | ||
46 | |||
47 | # ls functions/pci_epf_test/func1 | ||
48 | baseclass_code interrupt_pin revid subsys_vendor_id | ||
49 | cache_line_size msi_interrupts subclass_code vendorid | ||
50 | deviceid progif_code subsys_id | ||
51 | |||
52 | The PCI endpoint function driver populates these entries with default values | ||
53 | when the device is bound to the driver. The pci-epf-test driver populates | ||
54 | vendorid with 0xffff and interrupt_pin with 0x0001 | ||
55 | |||
56 | # cat functions/pci_epf_test/func1/vendorid | ||
57 | 0xffff | ||
58 | # cat functions/pci_epf_test/func1/interrupt_pin | ||
59 | 0x0001 | ||
60 | |||
61 | 1.4 Configuring pci-epf-test Device | ||
62 | |||
63 | The user can configure the pci-epf-test device using configfs entry. In order | ||
64 | to change the vendorid and the number of MSI interrupts used by the function | ||
65 | device, the following commands can be used. | ||
66 | |||
67 | # echo 0x104c > functions/pci_epf_test/func1/vendorid | ||
68 | # echo 0xb500 > functions/pci_epf_test/func1/deviceid | ||
69 | # echo 16 > functions/pci_epf_test/func1/msi_interrupts | ||
70 | |||
71 | 1.5 Binding pci-epf-test Device to EP Controller | ||
72 | |||
73 | In order for the endpoint function device to be useful, it has to be bound to | ||
74 | a PCI endpoint controller driver. Use the configfs to bind the function | ||
75 | device to one of the controller driver present in the system. | ||
76 | |||
77 | # ln -s functions/pci_epf_test/func1 controllers/51000000.pcie_ep/ | ||
78 | |||
79 | Once the above step is completed, the PCI endpoint is ready to establish a link | ||
80 | with the host. | ||
81 | |||
82 | 1.6 Start the Link | ||
83 | |||
84 | In order for the endpoint device to establish a link with the host, the _start_ | ||
85 | field should be populated with '1'. | ||
86 | |||
87 | # echo 1 > controllers/51000000.pcie_ep/start | ||
88 | |||
89 | 2. RootComplex Device | ||
90 | |||
91 | 2.1 lspci Output | ||
92 | |||
93 | Note that the devices listed here correspond to the value populated in 1.4 above | ||
94 | |||
95 | 00:00.0 PCI bridge: Texas Instruments Device 8888 (rev 01) | ||
96 | 01:00.0 Unassigned class [ff00]: Texas Instruments Device b500 | ||
97 | |||
98 | 2.2 Using Endpoint Test function Device | ||
99 | |||
100 | pcitest.sh added in tools/pci/ can be used to run all the default PCI endpoint | ||
101 | tests. Before pcitest.sh can be used pcitest.c should be compiled using the | ||
102 | following commands. | ||
103 | |||
104 | cd <kernel-dir> | ||
105 | make headers_install ARCH=arm | ||
106 | arm-linux-gnueabihf-gcc -Iusr/include tools/pci/pcitest.c -o pcitest | ||
107 | cp pcitest <rootfs>/usr/sbin/ | ||
108 | cp tools/pci/pcitest.sh <rootfs> | ||
109 | |||
110 | 2.2.1 pcitest.sh Output | ||
111 | # ./pcitest.sh | ||
112 | BAR tests | ||
113 | |||
114 | BAR0: OKAY | ||
115 | BAR1: OKAY | ||
116 | BAR2: OKAY | ||
117 | BAR3: OKAY | ||
118 | BAR4: NOT OKAY | ||
119 | BAR5: NOT OKAY | ||
120 | |||
121 | Interrupt tests | ||
122 | |||
123 | LEGACY IRQ: NOT OKAY | ||
124 | MSI1: OKAY | ||
125 | MSI2: OKAY | ||
126 | MSI3: OKAY | ||
127 | MSI4: OKAY | ||
128 | MSI5: OKAY | ||
129 | MSI6: OKAY | ||
130 | MSI7: OKAY | ||
131 | MSI8: OKAY | ||
132 | MSI9: OKAY | ||
133 | MSI10: OKAY | ||
134 | MSI11: OKAY | ||
135 | MSI12: OKAY | ||
136 | MSI13: OKAY | ||
137 | MSI14: OKAY | ||
138 | MSI15: OKAY | ||
139 | MSI16: OKAY | ||
140 | MSI17: NOT OKAY | ||
141 | MSI18: NOT OKAY | ||
142 | MSI19: NOT OKAY | ||
143 | MSI20: NOT OKAY | ||
144 | MSI21: NOT OKAY | ||
145 | MSI22: NOT OKAY | ||
146 | MSI23: NOT OKAY | ||
147 | MSI24: NOT OKAY | ||
148 | MSI25: NOT OKAY | ||
149 | MSI26: NOT OKAY | ||
150 | MSI27: NOT OKAY | ||
151 | MSI28: NOT OKAY | ||
152 | MSI29: NOT OKAY | ||
153 | MSI30: NOT OKAY | ||
154 | MSI31: NOT OKAY | ||
155 | MSI32: NOT OKAY | ||
156 | |||
157 | Read Tests | ||
158 | |||
159 | READ ( 1 bytes): OKAY | ||
160 | READ ( 1024 bytes): OKAY | ||
161 | READ ( 1025 bytes): OKAY | ||
162 | READ (1024000 bytes): OKAY | ||
163 | READ (1024001 bytes): OKAY | ||
164 | |||
165 | Write Tests | ||
166 | |||
167 | WRITE ( 1 bytes): OKAY | ||
168 | WRITE ( 1024 bytes): OKAY | ||
169 | WRITE ( 1025 bytes): OKAY | ||
170 | WRITE (1024000 bytes): OKAY | ||
171 | WRITE (1024001 bytes): OKAY | ||
172 | |||
173 | Copy Tests | ||
174 | |||
175 | COPY ( 1 bytes): OKAY | ||
176 | COPY ( 1024 bytes): OKAY | ||
177 | COPY ( 1025 bytes): OKAY | ||
178 | COPY (1024000 bytes): OKAY | ||
179 | COPY (1024001 bytes): OKAY | ||
diff --git a/Documentation/devicetree/bindings/pci/designware-pcie.txt b/Documentation/devicetree/bindings/pci/designware-pcie.txt index 1392c705ceca..b2480dd38c11 100644 --- a/Documentation/devicetree/bindings/pci/designware-pcie.txt +++ b/Documentation/devicetree/bindings/pci/designware-pcie.txt | |||
@@ -6,30 +6,40 @@ Required properties: | |||
6 | - reg-names: Must be "config" for the PCIe configuration space. | 6 | - reg-names: Must be "config" for the PCIe configuration space. |
7 | (The old way of getting the configuration address space from "ranges" | 7 | (The old way of getting the configuration address space from "ranges" |
8 | is deprecated and should be avoided.) | 8 | is deprecated and should be avoided.) |
9 | - num-lanes: number of lanes to use | ||
10 | RC mode: | ||
9 | - #address-cells: set to <3> | 11 | - #address-cells: set to <3> |
10 | - #size-cells: set to <2> | 12 | - #size-cells: set to <2> |
11 | - device_type: set to "pci" | 13 | - device_type: set to "pci" |
12 | - ranges: ranges for the PCI memory and I/O regions | 14 | - ranges: ranges for the PCI memory and I/O regions |
13 | - #interrupt-cells: set to <1> | 15 | - #interrupt-cells: set to <1> |
14 | - interrupt-map-mask and interrupt-map: standard PCI properties | 16 | - interrupt-map-mask and interrupt-map: standard PCI |
15 | to define the mapping of the PCIe interface to interrupt | 17 | properties to define the mapping of the PCIe interface to interrupt |
16 | numbers. | 18 | numbers. |
17 | - num-lanes: number of lanes to use | 19 | EP mode: |
20 | - num-ib-windows: number of inbound address translation | ||
21 | windows | ||
22 | - num-ob-windows: number of outbound address translation | ||
23 | windows | ||
18 | 24 | ||
19 | Optional properties: | 25 | Optional properties: |
20 | - num-viewport: number of view ports configured in hardware. If a platform | ||
21 | does not specify it, the driver assumes 2. | ||
22 | - num-lanes: number of lanes to use (this property should be specified unless | 26 | - num-lanes: number of lanes to use (this property should be specified unless |
23 | the link is brought already up in BIOS) | 27 | the link is brought already up in BIOS) |
24 | - reset-gpio: gpio pin number of power good signal | 28 | - reset-gpio: gpio pin number of power good signal |
25 | - bus-range: PCI bus numbers covered (it is recommended for new devicetrees to | ||
26 | specify this property, to keep backwards compatibility a range of 0x00-0xff | ||
27 | is assumed if not present) | ||
28 | - clocks: Must contain an entry for each entry in clock-names. | 29 | - clocks: Must contain an entry for each entry in clock-names. |
29 | See ../clocks/clock-bindings.txt for details. | 30 | See ../clocks/clock-bindings.txt for details. |
30 | - clock-names: Must include the following entries: | 31 | - clock-names: Must include the following entries: |
31 | - "pcie" | 32 | - "pcie" |
32 | - "pcie_bus" | 33 | - "pcie_bus" |
34 | RC mode: | ||
35 | - num-viewport: number of view ports configured in | ||
36 | hardware. If a platform does not specify it, the driver assumes 2. | ||
37 | - bus-range: PCI bus numbers covered (it is recommended | ||
38 | for new devicetrees to specify this property, to keep backwards | ||
39 | compatibility a range of 0x00-0xff is assumed if not present) | ||
40 | EP mode: | ||
41 | - max-functions: maximum number of functions that can be | ||
42 | configured | ||
33 | 43 | ||
34 | Example configuration: | 44 | Example configuration: |
35 | 45 | ||
diff --git a/Documentation/devicetree/bindings/pci/ti-pci.txt b/Documentation/devicetree/bindings/pci/ti-pci.txt index 60e25161f351..6a07c96227e0 100644 --- a/Documentation/devicetree/bindings/pci/ti-pci.txt +++ b/Documentation/devicetree/bindings/pci/ti-pci.txt | |||
@@ -1,17 +1,22 @@ | |||
1 | TI PCI Controllers | 1 | TI PCI Controllers |
2 | 2 | ||
3 | PCIe Designware Controller | 3 | PCIe Designware Controller |
4 | - compatible: Should be "ti,dra7-pcie"" | 4 | - compatible: Should be "ti,dra7-pcie" for RC |
5 | - reg : Two register ranges as listed in the reg-names property | 5 | Should be "ti,dra7-pcie-ep" for EP |
6 | - reg-names : The first entry must be "ti-conf" for the TI specific registers | ||
7 | The second entry must be "rc-dbics" for the designware pcie | ||
8 | registers | ||
9 | The third entry must be "config" for the PCIe configuration space | ||
10 | - phys : list of PHY specifiers (used by generic PHY framework) | 6 | - phys : list of PHY specifiers (used by generic PHY framework) |
11 | - phy-names : must be "pcie-phy0", "pcie-phy1", "pcie-phyN".. based on the | 7 | - phy-names : must be "pcie-phy0", "pcie-phy1", "pcie-phyN".. based on the |
12 | number of PHYs as specified in *phys* property. | 8 | number of PHYs as specified in *phys* property. |
13 | - ti,hwmods : Name of the hwmod associated to the pcie, "pcie<X>", | 9 | - ti,hwmods : Name of the hwmod associated to the pcie, "pcie<X>", |
14 | where <X> is the instance number of the pcie from the HW spec. | 10 | where <X> is the instance number of the pcie from the HW spec. |
11 | - num-lanes as specified in ../designware-pcie.txt | ||
12 | |||
13 | HOST MODE | ||
14 | ========= | ||
15 | - reg : Two register ranges as listed in the reg-names property | ||
16 | - reg-names : The first entry must be "ti-conf" for the TI specific registers | ||
17 | The second entry must be "rc-dbics" for the DesignWare PCIe | ||
18 | registers | ||
19 | The third entry must be "config" for the PCIe configuration space | ||
15 | - interrupts : Two interrupt entries must be specified. The first one is for | 20 | - interrupts : Two interrupt entries must be specified. The first one is for |
16 | main interrupt line and the second for MSI interrupt line. | 21 | main interrupt line and the second for MSI interrupt line. |
17 | - #address-cells, | 22 | - #address-cells, |
@@ -19,13 +24,36 @@ PCIe Designware Controller | |||
19 | #interrupt-cells, | 24 | #interrupt-cells, |
20 | device_type, | 25 | device_type, |
21 | ranges, | 26 | ranges, |
22 | num-lanes, | ||
23 | interrupt-map-mask, | 27 | interrupt-map-mask, |
24 | interrupt-map : as specified in ../designware-pcie.txt | 28 | interrupt-map : as specified in ../designware-pcie.txt |
25 | 29 | ||
30 | DEVICE MODE | ||
31 | =========== | ||
32 | - reg : Four register ranges as listed in the reg-names property | ||
33 | - reg-names : "ti-conf" for the TI specific registers | ||
34 | "ep_dbics" for the standard configuration registers as | ||
35 | they are locally accessed within the DIF CS space | ||
36 | "ep_dbics2" for the standard configuration registers as | ||
37 | they are locally accessed within the DIF CS2 space | ||
38 | "addr_space" used to map remote RC address space | ||
39 | - interrupts : one interrupt entries must be specified for main interrupt. | ||
40 | - num-ib-windows : number of inbound address translation windows | ||
41 | - num-ob-windows : number of outbound address translation windows | ||
42 | - ti,syscon-unaligned-access: phandle to the syscon DT node. The 1st argument | ||
43 | should contain the register offset within syscon | ||
44 | and the 2nd argument should contain the bit field | ||
45 | for setting the bit to enable unaligned | ||
46 | access. | ||
47 | |||
26 | Optional Property: | 48 | Optional Property: |
27 | - gpios : Should be added if a gpio line is required to drive PERST# line | 49 | - gpios : Should be added if a gpio line is required to drive PERST# line |
28 | 50 | ||
51 | NOTE: Two DT nodes may be added for each PCI controller; one for host | ||
52 | mode and another for device mode. So in order for PCI to | ||
53 | work in host mode, EP mode DT node should be disabled and in order to PCI to | ||
54 | work in EP mode, host mode DT node should be disabled. Host mode and EP | ||
55 | mode are mutually exclusive. | ||
56 | |||
29 | Example: | 57 | Example: |
30 | axi { | 58 | axi { |
31 | compatible = "simple-bus"; | 59 | compatible = "simple-bus"; |
diff --git a/Documentation/misc-devices/pci-endpoint-test.txt b/Documentation/misc-devices/pci-endpoint-test.txt new file mode 100644 index 000000000000..4ebc3594b32c --- /dev/null +++ b/Documentation/misc-devices/pci-endpoint-test.txt | |||
@@ -0,0 +1,35 @@ | |||
1 | Driver for PCI Endpoint Test Function | ||
2 | |||
3 | This driver should be used as a host side driver if the root complex is | ||
4 | connected to a configurable PCI endpoint running *pci_epf_test* function | ||
5 | driver configured according to [1]. | ||
6 | |||
7 | The "pci_endpoint_test" driver can be used to perform the following tests. | ||
8 | |||
9 | The PCI driver for the test device performs the following tests | ||
10 | *) verifying addresses programmed in BAR | ||
11 | *) raise legacy IRQ | ||
12 | *) raise MSI IRQ | ||
13 | *) read data | ||
14 | *) write data | ||
15 | *) copy data | ||
16 | |||
17 | This misc driver creates /dev/pci-endpoint-test.<num> for every | ||
18 | *pci_epf_test* function connected to the root complex and "ioctls" | ||
19 | should be used to perform the above tests. | ||
20 | |||
21 | ioctl | ||
22 | ----- | ||
23 | PCITEST_BAR: Tests the BAR. The number of the BAR to be tested | ||
24 | should be passed as argument. | ||
25 | PCITEST_LEGACY_IRQ: Tests legacy IRQ | ||
26 | PCITEST_MSI: Tests message signalled interrupts. The MSI number | ||
27 | to be tested should be passed as argument. | ||
28 | PCITEST_WRITE: Perform write tests. The size of the buffer should be passed | ||
29 | as argument. | ||
30 | PCITEST_READ: Perform read tests. The size of the buffer should be passed | ||
31 | as argument. | ||
32 | PCITEST_COPY: Perform read tests. The size of the buffer should be passed | ||
33 | as argument. | ||
34 | |||
35 | [1] -> Documentation/PCI/endpoint/function/binding/pci-test.txt | ||
diff --git a/MAINTAINERS b/MAINTAINERS index c265a5fe4848..15ed84389092 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -9581,6 +9581,15 @@ F: include/linux/pci* | |||
9581 | F: arch/x86/pci/ | 9581 | F: arch/x86/pci/ |
9582 | F: arch/x86/kernel/quirks.c | 9582 | F: arch/x86/kernel/quirks.c |
9583 | 9583 | ||
9584 | PCI ENDPOINT SUBSYSTEM | ||
9585 | M: Kishon Vijay Abraham I <kishon@ti.com> | ||
9586 | L: linux-pci@vger.kernel.org | ||
9587 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/kishon/pci-endpoint.git | ||
9588 | S: Supported | ||
9589 | F: drivers/pci/endpoint/ | ||
9590 | F: drivers/misc/pci_endpoint_test.c | ||
9591 | F: tools/pci/ | ||
9592 | |||
9584 | PCI DRIVER FOR ALTERA PCIE IP | 9593 | PCI DRIVER FOR ALTERA PCIE IP |
9585 | M: Ley Foon Tan <lftan@altera.com> | 9594 | M: Ley Foon Tan <lftan@altera.com> |
9586 | L: rfi@lists.rocketboards.org (moderated for non-subscribers) | 9595 | L: rfi@lists.rocketboards.org (moderated for non-subscribers) |
diff --git a/arch/arm/mach-omap2/clockdomains7xx_data.c b/arch/arm/mach-omap2/clockdomains7xx_data.c index 6c679659cda5..67ebff829cf2 100644 --- a/arch/arm/mach-omap2/clockdomains7xx_data.c +++ b/arch/arm/mach-omap2/clockdomains7xx_data.c | |||
@@ -524,7 +524,7 @@ static struct clockdomain pcie_7xx_clkdm = { | |||
524 | .dep_bit = DRA7XX_PCIE_STATDEP_SHIFT, | 524 | .dep_bit = DRA7XX_PCIE_STATDEP_SHIFT, |
525 | .wkdep_srcs = pcie_wkup_sleep_deps, | 525 | .wkdep_srcs = pcie_wkup_sleep_deps, |
526 | .sleepdep_srcs = pcie_wkup_sleep_deps, | 526 | .sleepdep_srcs = pcie_wkup_sleep_deps, |
527 | .flags = CLKDM_CAN_HWSUP_SWSUP, | 527 | .flags = CLKDM_CAN_SWSUP, |
528 | }; | 528 | }; |
529 | 529 | ||
530 | static struct clockdomain atl_7xx_clkdm = { | 530 | static struct clockdomain atl_7xx_clkdm = { |
diff --git a/drivers/Makefile b/drivers/Makefile index 2eced9afba53..a5f8e43b2c4d 100644 --- a/drivers/Makefile +++ b/drivers/Makefile | |||
@@ -14,7 +14,9 @@ obj-$(CONFIG_GENERIC_PHY) += phy/ | |||
14 | obj-$(CONFIG_PINCTRL) += pinctrl/ | 14 | obj-$(CONFIG_PINCTRL) += pinctrl/ |
15 | obj-$(CONFIG_GPIOLIB) += gpio/ | 15 | obj-$(CONFIG_GPIOLIB) += gpio/ |
16 | obj-y += pwm/ | 16 | obj-y += pwm/ |
17 | |||
17 | obj-$(CONFIG_PCI) += pci/ | 18 | obj-$(CONFIG_PCI) += pci/ |
19 | obj-$(CONFIG_PCI_ENDPOINT) += pci/endpoint/ | ||
18 | # PCI dwc controller drivers | 20 | # PCI dwc controller drivers |
19 | obj-y += pci/dwc/ | 21 | obj-y += pci/dwc/ |
20 | 22 | ||
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index c290990d73ed..527b115c4e23 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig | |||
@@ -771,6 +771,13 @@ config PANEL_BOOT_MESSAGE | |||
771 | 771 | ||
772 | endif # PANEL | 772 | endif # PANEL |
773 | 773 | ||
774 | config PCI_ENDPOINT_TEST | ||
775 | depends on PCI | ||
776 | tristate "PCI Endpoint Test driver" | ||
777 | ---help--- | ||
778 | Enable this configuration option to enable the host side test driver | ||
779 | for PCI Endpoint. | ||
780 | |||
774 | source "drivers/misc/c2port/Kconfig" | 781 | source "drivers/misc/c2port/Kconfig" |
775 | source "drivers/misc/eeprom/Kconfig" | 782 | source "drivers/misc/eeprom/Kconfig" |
776 | source "drivers/misc/cb710/Kconfig" | 783 | source "drivers/misc/cb710/Kconfig" |
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 7a3ea89339b4..6e139cd70421 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile | |||
@@ -54,6 +54,7 @@ obj-$(CONFIG_ECHO) += echo/ | |||
54 | obj-$(CONFIG_VEXPRESS_SYSCFG) += vexpress-syscfg.o | 54 | obj-$(CONFIG_VEXPRESS_SYSCFG) += vexpress-syscfg.o |
55 | obj-$(CONFIG_CXL_BASE) += cxl/ | 55 | obj-$(CONFIG_CXL_BASE) += cxl/ |
56 | obj-$(CONFIG_PANEL) += panel.o | 56 | obj-$(CONFIG_PANEL) += panel.o |
57 | obj-$(CONFIG_PCI_ENDPOINT_TEST) += pci_endpoint_test.o | ||
57 | 58 | ||
58 | lkdtm-$(CONFIG_LKDTM) += lkdtm_core.o | 59 | lkdtm-$(CONFIG_LKDTM) += lkdtm_core.o |
59 | lkdtm-$(CONFIG_LKDTM) += lkdtm_bugs.o | 60 | lkdtm-$(CONFIG_LKDTM) += lkdtm_bugs.o |
diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c new file mode 100644 index 000000000000..09c10f426b64 --- /dev/null +++ b/drivers/misc/pci_endpoint_test.c | |||
@@ -0,0 +1,534 @@ | |||
1 | /** | ||
2 | * Host side test driver to test endpoint functionality | ||
3 | * | ||
4 | * Copyright (C) 2017 Texas Instruments | ||
5 | * Author: Kishon Vijay Abraham I <kishon@ti.com> | ||
6 | * | ||
7 | * This program is free software: you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 of | ||
9 | * the License as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
18 | */ | ||
19 | |||
20 | #include <linux/crc32.h> | ||
21 | #include <linux/delay.h> | ||
22 | #include <linux/fs.h> | ||
23 | #include <linux/io.h> | ||
24 | #include <linux/interrupt.h> | ||
25 | #include <linux/irq.h> | ||
26 | #include <linux/miscdevice.h> | ||
27 | #include <linux/module.h> | ||
28 | #include <linux/mutex.h> | ||
29 | #include <linux/random.h> | ||
30 | #include <linux/slab.h> | ||
31 | #include <linux/pci.h> | ||
32 | #include <linux/pci_ids.h> | ||
33 | |||
34 | #include <linux/pci_regs.h> | ||
35 | |||
36 | #include <uapi/linux/pcitest.h> | ||
37 | |||
38 | #define DRV_MODULE_NAME "pci-endpoint-test" | ||
39 | |||
40 | #define PCI_ENDPOINT_TEST_MAGIC 0x0 | ||
41 | |||
42 | #define PCI_ENDPOINT_TEST_COMMAND 0x4 | ||
43 | #define COMMAND_RAISE_LEGACY_IRQ BIT(0) | ||
44 | #define COMMAND_RAISE_MSI_IRQ BIT(1) | ||
45 | #define MSI_NUMBER_SHIFT 2 | ||
46 | /* 6 bits for MSI number */ | ||
47 | #define COMMAND_READ BIT(8) | ||
48 | #define COMMAND_WRITE BIT(9) | ||
49 | #define COMMAND_COPY BIT(10) | ||
50 | |||
51 | #define PCI_ENDPOINT_TEST_STATUS 0x8 | ||
52 | #define STATUS_READ_SUCCESS BIT(0) | ||
53 | #define STATUS_READ_FAIL BIT(1) | ||
54 | #define STATUS_WRITE_SUCCESS BIT(2) | ||
55 | #define STATUS_WRITE_FAIL BIT(3) | ||
56 | #define STATUS_COPY_SUCCESS BIT(4) | ||
57 | #define STATUS_COPY_FAIL BIT(5) | ||
58 | #define STATUS_IRQ_RAISED BIT(6) | ||
59 | #define STATUS_SRC_ADDR_INVALID BIT(7) | ||
60 | #define STATUS_DST_ADDR_INVALID BIT(8) | ||
61 | |||
62 | #define PCI_ENDPOINT_TEST_LOWER_SRC_ADDR 0xc | ||
63 | #define PCI_ENDPOINT_TEST_UPPER_SRC_ADDR 0x10 | ||
64 | |||
65 | #define PCI_ENDPOINT_TEST_LOWER_DST_ADDR 0x14 | ||
66 | #define PCI_ENDPOINT_TEST_UPPER_DST_ADDR 0x18 | ||
67 | |||
68 | #define PCI_ENDPOINT_TEST_SIZE 0x1c | ||
69 | #define PCI_ENDPOINT_TEST_CHECKSUM 0x20 | ||
70 | |||
71 | static DEFINE_IDA(pci_endpoint_test_ida); | ||
72 | |||
73 | #define to_endpoint_test(priv) container_of((priv), struct pci_endpoint_test, \ | ||
74 | miscdev) | ||
75 | enum pci_barno { | ||
76 | BAR_0, | ||
77 | BAR_1, | ||
78 | BAR_2, | ||
79 | BAR_3, | ||
80 | BAR_4, | ||
81 | BAR_5, | ||
82 | }; | ||
83 | |||
84 | struct pci_endpoint_test { | ||
85 | struct pci_dev *pdev; | ||
86 | void __iomem *base; | ||
87 | void __iomem *bar[6]; | ||
88 | struct completion irq_raised; | ||
89 | int last_irq; | ||
90 | /* mutex to protect the ioctls */ | ||
91 | struct mutex mutex; | ||
92 | struct miscdevice miscdev; | ||
93 | }; | ||
94 | |||
95 | static int bar_size[] = { 4, 512, 1024, 16384, 131072, 1048576 }; | ||
96 | |||
97 | static inline u32 pci_endpoint_test_readl(struct pci_endpoint_test *test, | ||
98 | u32 offset) | ||
99 | { | ||
100 | return readl(test->base + offset); | ||
101 | } | ||
102 | |||
103 | static inline void pci_endpoint_test_writel(struct pci_endpoint_test *test, | ||
104 | u32 offset, u32 value) | ||
105 | { | ||
106 | writel(value, test->base + offset); | ||
107 | } | ||
108 | |||
109 | static inline u32 pci_endpoint_test_bar_readl(struct pci_endpoint_test *test, | ||
110 | int bar, int offset) | ||
111 | { | ||
112 | return readl(test->bar[bar] + offset); | ||
113 | } | ||
114 | |||
115 | static inline void pci_endpoint_test_bar_writel(struct pci_endpoint_test *test, | ||
116 | int bar, u32 offset, u32 value) | ||
117 | { | ||
118 | writel(value, test->bar[bar] + offset); | ||
119 | } | ||
120 | |||
121 | static irqreturn_t pci_endpoint_test_irqhandler(int irq, void *dev_id) | ||
122 | { | ||
123 | struct pci_endpoint_test *test = dev_id; | ||
124 | u32 reg; | ||
125 | |||
126 | reg = pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_STATUS); | ||
127 | if (reg & STATUS_IRQ_RAISED) { | ||
128 | test->last_irq = irq; | ||
129 | complete(&test->irq_raised); | ||
130 | reg &= ~STATUS_IRQ_RAISED; | ||
131 | } | ||
132 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_STATUS, | ||
133 | reg); | ||
134 | |||
135 | return IRQ_HANDLED; | ||
136 | } | ||
137 | |||
138 | static bool pci_endpoint_test_bar(struct pci_endpoint_test *test, | ||
139 | enum pci_barno barno) | ||
140 | { | ||
141 | int j; | ||
142 | u32 val; | ||
143 | int size; | ||
144 | |||
145 | if (!test->bar[barno]) | ||
146 | return false; | ||
147 | |||
148 | size = bar_size[barno]; | ||
149 | |||
150 | for (j = 0; j < size; j += 4) | ||
151 | pci_endpoint_test_bar_writel(test, barno, j, 0xA0A0A0A0); | ||
152 | |||
153 | for (j = 0; j < size; j += 4) { | ||
154 | val = pci_endpoint_test_bar_readl(test, barno, j); | ||
155 | if (val != 0xA0A0A0A0) | ||
156 | return false; | ||
157 | } | ||
158 | |||
159 | return true; | ||
160 | } | ||
161 | |||
162 | static bool pci_endpoint_test_legacy_irq(struct pci_endpoint_test *test) | ||
163 | { | ||
164 | u32 val; | ||
165 | |||
166 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND, | ||
167 | COMMAND_RAISE_LEGACY_IRQ); | ||
168 | val = wait_for_completion_timeout(&test->irq_raised, | ||
169 | msecs_to_jiffies(1000)); | ||
170 | if (!val) | ||
171 | return false; | ||
172 | |||
173 | return true; | ||
174 | } | ||
175 | |||
176 | static bool pci_endpoint_test_msi_irq(struct pci_endpoint_test *test, | ||
177 | u8 msi_num) | ||
178 | { | ||
179 | u32 val; | ||
180 | struct pci_dev *pdev = test->pdev; | ||
181 | |||
182 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND, | ||
183 | msi_num << MSI_NUMBER_SHIFT | | ||
184 | COMMAND_RAISE_MSI_IRQ); | ||
185 | val = wait_for_completion_timeout(&test->irq_raised, | ||
186 | msecs_to_jiffies(1000)); | ||
187 | if (!val) | ||
188 | return false; | ||
189 | |||
190 | if (test->last_irq - pdev->irq == msi_num - 1) | ||
191 | return true; | ||
192 | |||
193 | return false; | ||
194 | } | ||
195 | |||
196 | static bool pci_endpoint_test_copy(struct pci_endpoint_test *test, size_t size) | ||
197 | { | ||
198 | bool ret = false; | ||
199 | void *src_addr; | ||
200 | void *dst_addr; | ||
201 | dma_addr_t src_phys_addr; | ||
202 | dma_addr_t dst_phys_addr; | ||
203 | struct pci_dev *pdev = test->pdev; | ||
204 | struct device *dev = &pdev->dev; | ||
205 | u32 src_crc32; | ||
206 | u32 dst_crc32; | ||
207 | |||
208 | src_addr = dma_alloc_coherent(dev, size, &src_phys_addr, GFP_KERNEL); | ||
209 | if (!src_addr) { | ||
210 | dev_err(dev, "failed to allocate source buffer\n"); | ||
211 | ret = false; | ||
212 | goto err; | ||
213 | } | ||
214 | |||
215 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_LOWER_SRC_ADDR, | ||
216 | lower_32_bits(src_phys_addr)); | ||
217 | |||
218 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_UPPER_SRC_ADDR, | ||
219 | upper_32_bits(src_phys_addr)); | ||
220 | |||
221 | get_random_bytes(src_addr, size); | ||
222 | src_crc32 = crc32_le(~0, src_addr, size); | ||
223 | |||
224 | dst_addr = dma_alloc_coherent(dev, size, &dst_phys_addr, GFP_KERNEL); | ||
225 | if (!dst_addr) { | ||
226 | dev_err(dev, "failed to allocate destination address\n"); | ||
227 | ret = false; | ||
228 | goto err_src_addr; | ||
229 | } | ||
230 | |||
231 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_LOWER_DST_ADDR, | ||
232 | lower_32_bits(dst_phys_addr)); | ||
233 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_UPPER_DST_ADDR, | ||
234 | upper_32_bits(dst_phys_addr)); | ||
235 | |||
236 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_SIZE, | ||
237 | size); | ||
238 | |||
239 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND, | ||
240 | 1 << MSI_NUMBER_SHIFT | COMMAND_COPY); | ||
241 | |||
242 | wait_for_completion(&test->irq_raised); | ||
243 | |||
244 | dst_crc32 = crc32_le(~0, dst_addr, size); | ||
245 | if (dst_crc32 == src_crc32) | ||
246 | ret = true; | ||
247 | |||
248 | dma_free_coherent(dev, size, dst_addr, dst_phys_addr); | ||
249 | |||
250 | err_src_addr: | ||
251 | dma_free_coherent(dev, size, src_addr, src_phys_addr); | ||
252 | |||
253 | err: | ||
254 | return ret; | ||
255 | } | ||
256 | |||
257 | static bool pci_endpoint_test_write(struct pci_endpoint_test *test, size_t size) | ||
258 | { | ||
259 | bool ret = false; | ||
260 | u32 reg; | ||
261 | void *addr; | ||
262 | dma_addr_t phys_addr; | ||
263 | struct pci_dev *pdev = test->pdev; | ||
264 | struct device *dev = &pdev->dev; | ||
265 | u32 crc32; | ||
266 | |||
267 | addr = dma_alloc_coherent(dev, size, &phys_addr, GFP_KERNEL); | ||
268 | if (!addr) { | ||
269 | dev_err(dev, "failed to allocate address\n"); | ||
270 | ret = false; | ||
271 | goto err; | ||
272 | } | ||
273 | |||
274 | get_random_bytes(addr, size); | ||
275 | |||
276 | crc32 = crc32_le(~0, addr, size); | ||
277 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_CHECKSUM, | ||
278 | crc32); | ||
279 | |||
280 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_LOWER_SRC_ADDR, | ||
281 | lower_32_bits(phys_addr)); | ||
282 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_UPPER_SRC_ADDR, | ||
283 | upper_32_bits(phys_addr)); | ||
284 | |||
285 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_SIZE, size); | ||
286 | |||
287 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND, | ||
288 | 1 << MSI_NUMBER_SHIFT | COMMAND_READ); | ||
289 | |||
290 | wait_for_completion(&test->irq_raised); | ||
291 | |||
292 | reg = pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_STATUS); | ||
293 | if (reg & STATUS_READ_SUCCESS) | ||
294 | ret = true; | ||
295 | |||
296 | dma_free_coherent(dev, size, addr, phys_addr); | ||
297 | |||
298 | err: | ||
299 | return ret; | ||
300 | } | ||
301 | |||
302 | static bool pci_endpoint_test_read(struct pci_endpoint_test *test, size_t size) | ||
303 | { | ||
304 | bool ret = false; | ||
305 | void *addr; | ||
306 | dma_addr_t phys_addr; | ||
307 | struct pci_dev *pdev = test->pdev; | ||
308 | struct device *dev = &pdev->dev; | ||
309 | u32 crc32; | ||
310 | |||
311 | addr = dma_alloc_coherent(dev, size, &phys_addr, GFP_KERNEL); | ||
312 | if (!addr) { | ||
313 | dev_err(dev, "failed to allocate destination address\n"); | ||
314 | ret = false; | ||
315 | goto err; | ||
316 | } | ||
317 | |||
318 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_LOWER_DST_ADDR, | ||
319 | lower_32_bits(phys_addr)); | ||
320 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_UPPER_DST_ADDR, | ||
321 | upper_32_bits(phys_addr)); | ||
322 | |||
323 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_SIZE, size); | ||
324 | |||
325 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND, | ||
326 | 1 << MSI_NUMBER_SHIFT | COMMAND_WRITE); | ||
327 | |||
328 | wait_for_completion(&test->irq_raised); | ||
329 | |||
330 | crc32 = crc32_le(~0, addr, size); | ||
331 | if (crc32 == pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_CHECKSUM)) | ||
332 | ret = true; | ||
333 | |||
334 | dma_free_coherent(dev, size, addr, phys_addr); | ||
335 | err: | ||
336 | return ret; | ||
337 | } | ||
338 | |||
339 | static long pci_endpoint_test_ioctl(struct file *file, unsigned int cmd, | ||
340 | unsigned long arg) | ||
341 | { | ||
342 | int ret = -EINVAL; | ||
343 | enum pci_barno bar; | ||
344 | struct pci_endpoint_test *test = to_endpoint_test(file->private_data); | ||
345 | |||
346 | mutex_lock(&test->mutex); | ||
347 | switch (cmd) { | ||
348 | case PCITEST_BAR: | ||
349 | bar = arg; | ||
350 | if (bar < 0 || bar > 5) | ||
351 | goto ret; | ||
352 | ret = pci_endpoint_test_bar(test, bar); | ||
353 | break; | ||
354 | case PCITEST_LEGACY_IRQ: | ||
355 | ret = pci_endpoint_test_legacy_irq(test); | ||
356 | break; | ||
357 | case PCITEST_MSI: | ||
358 | ret = pci_endpoint_test_msi_irq(test, arg); | ||
359 | break; | ||
360 | case PCITEST_WRITE: | ||
361 | ret = pci_endpoint_test_write(test, arg); | ||
362 | break; | ||
363 | case PCITEST_READ: | ||
364 | ret = pci_endpoint_test_read(test, arg); | ||
365 | break; | ||
366 | case PCITEST_COPY: | ||
367 | ret = pci_endpoint_test_copy(test, arg); | ||
368 | break; | ||
369 | } | ||
370 | |||
371 | ret: | ||
372 | mutex_unlock(&test->mutex); | ||
373 | return ret; | ||
374 | } | ||
375 | |||
376 | static const struct file_operations pci_endpoint_test_fops = { | ||
377 | .owner = THIS_MODULE, | ||
378 | .unlocked_ioctl = pci_endpoint_test_ioctl, | ||
379 | }; | ||
380 | |||
381 | static int pci_endpoint_test_probe(struct pci_dev *pdev, | ||
382 | const struct pci_device_id *ent) | ||
383 | { | ||
384 | int i; | ||
385 | int err; | ||
386 | int irq; | ||
387 | int id; | ||
388 | char name[20]; | ||
389 | enum pci_barno bar; | ||
390 | void __iomem *base; | ||
391 | struct device *dev = &pdev->dev; | ||
392 | struct pci_endpoint_test *test; | ||
393 | struct miscdevice *misc_device; | ||
394 | |||
395 | if (pci_is_bridge(pdev)) | ||
396 | return -ENODEV; | ||
397 | |||
398 | test = devm_kzalloc(dev, sizeof(*test), GFP_KERNEL); | ||
399 | if (!test) | ||
400 | return -ENOMEM; | ||
401 | |||
402 | test->pdev = pdev; | ||
403 | init_completion(&test->irq_raised); | ||
404 | mutex_init(&test->mutex); | ||
405 | |||
406 | err = pci_enable_device(pdev); | ||
407 | if (err) { | ||
408 | dev_err(dev, "Cannot enable PCI device\n"); | ||
409 | return err; | ||
410 | } | ||
411 | |||
412 | err = pci_request_regions(pdev, DRV_MODULE_NAME); | ||
413 | if (err) { | ||
414 | dev_err(dev, "Cannot obtain PCI resources\n"); | ||
415 | goto err_disable_pdev; | ||
416 | } | ||
417 | |||
418 | pci_set_master(pdev); | ||
419 | |||
420 | irq = pci_alloc_irq_vectors(pdev, 1, 32, PCI_IRQ_MSI); | ||
421 | if (irq < 0) | ||
422 | dev_err(dev, "failed to get MSI interrupts\n"); | ||
423 | |||
424 | err = devm_request_irq(dev, pdev->irq, pci_endpoint_test_irqhandler, | ||
425 | IRQF_SHARED, DRV_MODULE_NAME, test); | ||
426 | if (err) { | ||
427 | dev_err(dev, "failed to request IRQ %d\n", pdev->irq); | ||
428 | goto err_disable_msi; | ||
429 | } | ||
430 | |||
431 | for (i = 1; i < irq; i++) { | ||
432 | err = devm_request_irq(dev, pdev->irq + i, | ||
433 | pci_endpoint_test_irqhandler, | ||
434 | IRQF_SHARED, DRV_MODULE_NAME, test); | ||
435 | if (err) | ||
436 | dev_err(dev, "failed to request IRQ %d for MSI %d\n", | ||
437 | pdev->irq + i, i + 1); | ||
438 | } | ||
439 | |||
440 | for (bar = BAR_0; bar <= BAR_5; bar++) { | ||
441 | base = pci_ioremap_bar(pdev, bar); | ||
442 | if (!base) { | ||
443 | dev_err(dev, "failed to read BAR%d\n", bar); | ||
444 | WARN_ON(bar == BAR_0); | ||
445 | } | ||
446 | test->bar[bar] = base; | ||
447 | } | ||
448 | |||
449 | test->base = test->bar[0]; | ||
450 | if (!test->base) { | ||
451 | dev_err(dev, "Cannot perform PCI test without BAR0\n"); | ||
452 | goto err_iounmap; | ||
453 | } | ||
454 | |||
455 | pci_set_drvdata(pdev, test); | ||
456 | |||
457 | id = ida_simple_get(&pci_endpoint_test_ida, 0, 0, GFP_KERNEL); | ||
458 | if (id < 0) { | ||
459 | dev_err(dev, "unable to get id\n"); | ||
460 | goto err_iounmap; | ||
461 | } | ||
462 | |||
463 | snprintf(name, sizeof(name), DRV_MODULE_NAME ".%d", id); | ||
464 | misc_device = &test->miscdev; | ||
465 | misc_device->minor = MISC_DYNAMIC_MINOR; | ||
466 | misc_device->name = name; | ||
467 | misc_device->fops = &pci_endpoint_test_fops, | ||
468 | |||
469 | err = misc_register(misc_device); | ||
470 | if (err) { | ||
471 | dev_err(dev, "failed to register device\n"); | ||
472 | goto err_ida_remove; | ||
473 | } | ||
474 | |||
475 | return 0; | ||
476 | |||
477 | err_ida_remove: | ||
478 | ida_simple_remove(&pci_endpoint_test_ida, id); | ||
479 | |||
480 | err_iounmap: | ||
481 | for (bar = BAR_0; bar <= BAR_5; bar++) { | ||
482 | if (test->bar[bar]) | ||
483 | pci_iounmap(pdev, test->bar[bar]); | ||
484 | } | ||
485 | |||
486 | err_disable_msi: | ||
487 | pci_disable_msi(pdev); | ||
488 | pci_release_regions(pdev); | ||
489 | |||
490 | err_disable_pdev: | ||
491 | pci_disable_device(pdev); | ||
492 | |||
493 | return err; | ||
494 | } | ||
495 | |||
496 | static void pci_endpoint_test_remove(struct pci_dev *pdev) | ||
497 | { | ||
498 | int id; | ||
499 | enum pci_barno bar; | ||
500 | struct pci_endpoint_test *test = pci_get_drvdata(pdev); | ||
501 | struct miscdevice *misc_device = &test->miscdev; | ||
502 | |||
503 | if (sscanf(misc_device->name, DRV_MODULE_NAME ".%d", &id) != 1) | ||
504 | return; | ||
505 | |||
506 | misc_deregister(&test->miscdev); | ||
507 | ida_simple_remove(&pci_endpoint_test_ida, id); | ||
508 | for (bar = BAR_0; bar <= BAR_5; bar++) { | ||
509 | if (test->bar[bar]) | ||
510 | pci_iounmap(pdev, test->bar[bar]); | ||
511 | } | ||
512 | pci_disable_msi(pdev); | ||
513 | pci_release_regions(pdev); | ||
514 | pci_disable_device(pdev); | ||
515 | } | ||
516 | |||
517 | static const struct pci_device_id pci_endpoint_test_tbl[] = { | ||
518 | { PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_DRA74x) }, | ||
519 | { PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_DRA72x) }, | ||
520 | { } | ||
521 | }; | ||
522 | MODULE_DEVICE_TABLE(pci, pci_endpoint_test_tbl); | ||
523 | |||
524 | static struct pci_driver pci_endpoint_test_driver = { | ||
525 | .name = DRV_MODULE_NAME, | ||
526 | .id_table = pci_endpoint_test_tbl, | ||
527 | .probe = pci_endpoint_test_probe, | ||
528 | .remove = pci_endpoint_test_remove, | ||
529 | }; | ||
530 | module_pci_driver(pci_endpoint_test_driver); | ||
531 | |||
532 | MODULE_DESCRIPTION("PCI ENDPOINT TEST HOST DRIVER"); | ||
533 | MODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>"); | ||
534 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index df141420c902..9747c1ec8c74 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig | |||
@@ -134,3 +134,4 @@ config PCI_HYPERV | |||
134 | source "drivers/pci/hotplug/Kconfig" | 134 | source "drivers/pci/hotplug/Kconfig" |
135 | source "drivers/pci/dwc/Kconfig" | 135 | source "drivers/pci/dwc/Kconfig" |
136 | source "drivers/pci/host/Kconfig" | 136 | source "drivers/pci/host/Kconfig" |
137 | source "drivers/pci/endpoint/Kconfig" | ||
diff --git a/drivers/pci/dwc/Kconfig b/drivers/pci/dwc/Kconfig index dfb8a69afc28..b7e15526d676 100644 --- a/drivers/pci/dwc/Kconfig +++ b/drivers/pci/dwc/Kconfig | |||
@@ -9,16 +9,44 @@ config PCIE_DW_HOST | |||
9 | depends on PCI_MSI_IRQ_DOMAIN | 9 | depends on PCI_MSI_IRQ_DOMAIN |
10 | select PCIE_DW | 10 | select PCIE_DW |
11 | 11 | ||
12 | config PCIE_DW_EP | ||
13 | bool | ||
14 | depends on PCI_ENDPOINT | ||
15 | select PCIE_DW | ||
16 | |||
12 | config PCI_DRA7XX | 17 | config PCI_DRA7XX |
13 | bool "TI DRA7xx PCIe controller" | 18 | bool "TI DRA7xx PCIe controller" |
14 | depends on PCI | 19 | depends on (PCI && PCI_MSI_IRQ_DOMAIN) || PCI_ENDPOINT |
15 | depends on OF && HAS_IOMEM && TI_PIPE3 | 20 | depends on OF && HAS_IOMEM && TI_PIPE3 |
21 | help | ||
22 | Enables support for the PCIe controller in the DRA7xx SoC. There | ||
23 | are two instances of PCIe controller in DRA7xx. This controller can | ||
24 | work either as EP or RC. In order to enable host-specific features | ||
25 | PCI_DRA7XX_HOST must be selected and in order to enable device- | ||
26 | specific features PCI_DRA7XX_EP must be selected. This uses | ||
27 | the Designware core. | ||
28 | |||
29 | if PCI_DRA7XX | ||
30 | |||
31 | config PCI_DRA7XX_HOST | ||
32 | bool "PCI DRA7xx Host Mode" | ||
33 | depends on PCI | ||
16 | depends on PCI_MSI_IRQ_DOMAIN | 34 | depends on PCI_MSI_IRQ_DOMAIN |
17 | select PCIE_DW_HOST | 35 | select PCIE_DW_HOST |
36 | default y | ||
18 | help | 37 | help |
19 | Enables support for the PCIe controller in the DRA7xx SoC. There | 38 | Enables support for the PCIe controller in the DRA7xx SoC to work in |
20 | are two instances of PCIe controller in DRA7xx. This controller can | 39 | host mode. |
21 | act both as EP and RC. This reuses the Designware core. | 40 | |
41 | config PCI_DRA7XX_EP | ||
42 | bool "PCI DRA7xx Endpoint Mode" | ||
43 | depends on PCI_ENDPOINT | ||
44 | select PCIE_DW_EP | ||
45 | help | ||
46 | Enables support for the PCIe controller in the DRA7xx SoC to work in | ||
47 | endpoint mode. | ||
48 | |||
49 | endif | ||
22 | 50 | ||
23 | config PCIE_DW_PLAT | 51 | config PCIE_DW_PLAT |
24 | bool "Platform bus based DesignWare PCIe Controller" | 52 | bool "Platform bus based DesignWare PCIe Controller" |
@@ -89,6 +117,7 @@ config PCI_HISI | |||
89 | depends on PCI_MSI_IRQ_DOMAIN | 117 | depends on PCI_MSI_IRQ_DOMAIN |
90 | select PCIEPORTBUS | 118 | select PCIEPORTBUS |
91 | select PCIE_DW_HOST | 119 | select PCIE_DW_HOST |
120 | select PCI_HOST_COMMON | ||
92 | help | 121 | help |
93 | Say Y here if you want PCIe controller support on HiSilicon | 122 | Say Y here if you want PCIe controller support on HiSilicon |
94 | Hip05 and Hip06 SoCs | 123 | Hip05 and Hip06 SoCs |
diff --git a/drivers/pci/dwc/Makefile b/drivers/pci/dwc/Makefile index a2df13c28798..f31a8596442a 100644 --- a/drivers/pci/dwc/Makefile +++ b/drivers/pci/dwc/Makefile | |||
@@ -1,7 +1,10 @@ | |||
1 | obj-$(CONFIG_PCIE_DW) += pcie-designware.o | 1 | obj-$(CONFIG_PCIE_DW) += pcie-designware.o |
2 | obj-$(CONFIG_PCIE_DW_HOST) += pcie-designware-host.o | 2 | obj-$(CONFIG_PCIE_DW_HOST) += pcie-designware-host.o |
3 | obj-$(CONFIG_PCIE_DW_EP) += pcie-designware-ep.o | ||
3 | obj-$(CONFIG_PCIE_DW_PLAT) += pcie-designware-plat.o | 4 | obj-$(CONFIG_PCIE_DW_PLAT) += pcie-designware-plat.o |
4 | obj-$(CONFIG_PCI_DRA7XX) += pci-dra7xx.o | 5 | ifneq ($(filter y,$(CONFIG_PCI_DRA7XX_HOST) $(CONFIG_PCI_DRA7XX_EP)),) |
6 | obj-$(CONFIG_PCI_DRA7XX) += pci-dra7xx.o | ||
7 | endif | ||
5 | obj-$(CONFIG_PCI_EXYNOS) += pci-exynos.o | 8 | obj-$(CONFIG_PCI_EXYNOS) += pci-exynos.o |
6 | obj-$(CONFIG_PCI_IMX6) += pci-imx6.o | 9 | obj-$(CONFIG_PCI_IMX6) += pci-imx6.o |
7 | obj-$(CONFIG_PCIE_SPEAR13XX) += pcie-spear13xx.o | 10 | obj-$(CONFIG_PCIE_SPEAR13XX) += pcie-spear13xx.o |
diff --git a/drivers/pci/dwc/pci-dra7xx.c b/drivers/pci/dwc/pci-dra7xx.c index 0984baff07e3..8decf46cf525 100644 --- a/drivers/pci/dwc/pci-dra7xx.c +++ b/drivers/pci/dwc/pci-dra7xx.c | |||
@@ -10,12 +10,14 @@ | |||
10 | * published by the Free Software Foundation. | 10 | * published by the Free Software Foundation. |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <linux/delay.h> | ||
13 | #include <linux/err.h> | 14 | #include <linux/err.h> |
14 | #include <linux/interrupt.h> | 15 | #include <linux/interrupt.h> |
15 | #include <linux/irq.h> | 16 | #include <linux/irq.h> |
16 | #include <linux/irqdomain.h> | 17 | #include <linux/irqdomain.h> |
17 | #include <linux/kernel.h> | 18 | #include <linux/kernel.h> |
18 | #include <linux/init.h> | 19 | #include <linux/init.h> |
20 | #include <linux/of_device.h> | ||
19 | #include <linux/of_gpio.h> | 21 | #include <linux/of_gpio.h> |
20 | #include <linux/of_pci.h> | 22 | #include <linux/of_pci.h> |
21 | #include <linux/pci.h> | 23 | #include <linux/pci.h> |
@@ -24,6 +26,8 @@ | |||
24 | #include <linux/pm_runtime.h> | 26 | #include <linux/pm_runtime.h> |
25 | #include <linux/resource.h> | 27 | #include <linux/resource.h> |
26 | #include <linux/types.h> | 28 | #include <linux/types.h> |
29 | #include <linux/mfd/syscon.h> | ||
30 | #include <linux/regmap.h> | ||
27 | 31 | ||
28 | #include "pcie-designware.h" | 32 | #include "pcie-designware.h" |
29 | 33 | ||
@@ -57,6 +61,11 @@ | |||
57 | #define MSI BIT(4) | 61 | #define MSI BIT(4) |
58 | #define LEG_EP_INTERRUPTS (INTA | INTB | INTC | INTD) | 62 | #define LEG_EP_INTERRUPTS (INTA | INTB | INTC | INTD) |
59 | 63 | ||
64 | #define PCIECTRL_TI_CONF_DEVICE_TYPE 0x0100 | ||
65 | #define DEVICE_TYPE_EP 0x0 | ||
66 | #define DEVICE_TYPE_LEG_EP 0x1 | ||
67 | #define DEVICE_TYPE_RC 0x4 | ||
68 | |||
60 | #define PCIECTRL_DRA7XX_CONF_DEVICE_CMD 0x0104 | 69 | #define PCIECTRL_DRA7XX_CONF_DEVICE_CMD 0x0104 |
61 | #define LTSSM_EN 0x1 | 70 | #define LTSSM_EN 0x1 |
62 | 71 | ||
@@ -66,6 +75,13 @@ | |||
66 | 75 | ||
67 | #define EXP_CAP_ID_OFFSET 0x70 | 76 | #define EXP_CAP_ID_OFFSET 0x70 |
68 | 77 | ||
78 | #define PCIECTRL_TI_CONF_INTX_ASSERT 0x0124 | ||
79 | #define PCIECTRL_TI_CONF_INTX_DEASSERT 0x0128 | ||
80 | |||
81 | #define PCIECTRL_TI_CONF_MSI_XMT 0x012c | ||
82 | #define MSI_REQ_GRANT BIT(0) | ||
83 | #define MSI_VECTOR_SHIFT 7 | ||
84 | |||
69 | struct dra7xx_pcie { | 85 | struct dra7xx_pcie { |
70 | struct dw_pcie *pci; | 86 | struct dw_pcie *pci; |
71 | void __iomem *base; /* DT ti_conf */ | 87 | void __iomem *base; /* DT ti_conf */ |
@@ -73,6 +89,11 @@ struct dra7xx_pcie { | |||
73 | struct phy **phy; | 89 | struct phy **phy; |
74 | int link_gen; | 90 | int link_gen; |
75 | struct irq_domain *irq_domain; | 91 | struct irq_domain *irq_domain; |
92 | enum dw_pcie_device_mode mode; | ||
93 | }; | ||
94 | |||
95 | struct dra7xx_pcie_of_data { | ||
96 | enum dw_pcie_device_mode mode; | ||
76 | }; | 97 | }; |
77 | 98 | ||
78 | #define to_dra7xx_pcie(x) dev_get_drvdata((x)->dev) | 99 | #define to_dra7xx_pcie(x) dev_get_drvdata((x)->dev) |
@@ -88,6 +109,11 @@ static inline void dra7xx_pcie_writel(struct dra7xx_pcie *pcie, u32 offset, | |||
88 | writel(value, pcie->base + offset); | 109 | writel(value, pcie->base + offset); |
89 | } | 110 | } |
90 | 111 | ||
112 | static u64 dra7xx_pcie_cpu_addr_fixup(u64 pci_addr) | ||
113 | { | ||
114 | return pci_addr & DRA7XX_CPU_TO_BUS_ADDR; | ||
115 | } | ||
116 | |||
91 | static int dra7xx_pcie_link_up(struct dw_pcie *pci) | 117 | static int dra7xx_pcie_link_up(struct dw_pcie *pci) |
92 | { | 118 | { |
93 | struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pci); | 119 | struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pci); |
@@ -96,9 +122,19 @@ static int dra7xx_pcie_link_up(struct dw_pcie *pci) | |||
96 | return !!(reg & LINK_UP); | 122 | return !!(reg & LINK_UP); |
97 | } | 123 | } |
98 | 124 | ||
99 | static int dra7xx_pcie_establish_link(struct dra7xx_pcie *dra7xx) | 125 | static void dra7xx_pcie_stop_link(struct dw_pcie *pci) |
100 | { | 126 | { |
101 | struct dw_pcie *pci = dra7xx->pci; | 127 | struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pci); |
128 | u32 reg; | ||
129 | |||
130 | reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD); | ||
131 | reg &= ~LTSSM_EN; | ||
132 | dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD, reg); | ||
133 | } | ||
134 | |||
135 | static int dra7xx_pcie_establish_link(struct dw_pcie *pci) | ||
136 | { | ||
137 | struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pci); | ||
102 | struct device *dev = pci->dev; | 138 | struct device *dev = pci->dev; |
103 | u32 reg; | 139 | u32 reg; |
104 | u32 exp_cap_off = EXP_CAP_ID_OFFSET; | 140 | u32 exp_cap_off = EXP_CAP_ID_OFFSET; |
@@ -132,34 +168,42 @@ static int dra7xx_pcie_establish_link(struct dra7xx_pcie *dra7xx) | |||
132 | reg |= LTSSM_EN; | 168 | reg |= LTSSM_EN; |
133 | dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD, reg); | 169 | dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD, reg); |
134 | 170 | ||
135 | return dw_pcie_wait_for_link(pci); | 171 | return 0; |
136 | } | 172 | } |
137 | 173 | ||
138 | static void dra7xx_pcie_enable_interrupts(struct dra7xx_pcie *dra7xx) | 174 | static void dra7xx_pcie_enable_msi_interrupts(struct dra7xx_pcie *dra7xx) |
139 | { | 175 | { |
140 | dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_IRQSTATUS_MAIN, | ||
141 | ~INTERRUPTS); | ||
142 | dra7xx_pcie_writel(dra7xx, | ||
143 | PCIECTRL_DRA7XX_CONF_IRQENABLE_SET_MAIN, INTERRUPTS); | ||
144 | dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_IRQSTATUS_MSI, | 176 | dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_IRQSTATUS_MSI, |
145 | ~LEG_EP_INTERRUPTS & ~MSI); | 177 | ~LEG_EP_INTERRUPTS & ~MSI); |
146 | dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_IRQENABLE_SET_MSI, | 178 | |
179 | dra7xx_pcie_writel(dra7xx, | ||
180 | PCIECTRL_DRA7XX_CONF_IRQENABLE_SET_MSI, | ||
147 | MSI | LEG_EP_INTERRUPTS); | 181 | MSI | LEG_EP_INTERRUPTS); |
148 | } | 182 | } |
149 | 183 | ||
184 | static void dra7xx_pcie_enable_wrapper_interrupts(struct dra7xx_pcie *dra7xx) | ||
185 | { | ||
186 | dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_IRQSTATUS_MAIN, | ||
187 | ~INTERRUPTS); | ||
188 | dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_IRQENABLE_SET_MAIN, | ||
189 | INTERRUPTS); | ||
190 | } | ||
191 | |||
192 | static void dra7xx_pcie_enable_interrupts(struct dra7xx_pcie *dra7xx) | ||
193 | { | ||
194 | dra7xx_pcie_enable_wrapper_interrupts(dra7xx); | ||
195 | dra7xx_pcie_enable_msi_interrupts(dra7xx); | ||
196 | } | ||
197 | |||
150 | static void dra7xx_pcie_host_init(struct pcie_port *pp) | 198 | static void dra7xx_pcie_host_init(struct pcie_port *pp) |
151 | { | 199 | { |
152 | struct dw_pcie *pci = to_dw_pcie_from_pp(pp); | 200 | struct dw_pcie *pci = to_dw_pcie_from_pp(pp); |
153 | struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pci); | 201 | struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pci); |
154 | 202 | ||
155 | pp->io_base &= DRA7XX_CPU_TO_BUS_ADDR; | ||
156 | pp->mem_base &= DRA7XX_CPU_TO_BUS_ADDR; | ||
157 | pp->cfg0_base &= DRA7XX_CPU_TO_BUS_ADDR; | ||
158 | pp->cfg1_base &= DRA7XX_CPU_TO_BUS_ADDR; | ||
159 | |||
160 | dw_pcie_setup_rc(pp); | 203 | dw_pcie_setup_rc(pp); |
161 | 204 | ||
162 | dra7xx_pcie_establish_link(dra7xx); | 205 | dra7xx_pcie_establish_link(pci); |
206 | dw_pcie_wait_for_link(pci); | ||
163 | dw_pcie_msi_init(pp); | 207 | dw_pcie_msi_init(pp); |
164 | dra7xx_pcie_enable_interrupts(dra7xx); | 208 | dra7xx_pcie_enable_interrupts(dra7xx); |
165 | } | 209 | } |
@@ -237,6 +281,7 @@ static irqreturn_t dra7xx_pcie_irq_handler(int irq, void *arg) | |||
237 | struct dra7xx_pcie *dra7xx = arg; | 281 | struct dra7xx_pcie *dra7xx = arg; |
238 | struct dw_pcie *pci = dra7xx->pci; | 282 | struct dw_pcie *pci = dra7xx->pci; |
239 | struct device *dev = pci->dev; | 283 | struct device *dev = pci->dev; |
284 | struct dw_pcie_ep *ep = &pci->ep; | ||
240 | u32 reg; | 285 | u32 reg; |
241 | 286 | ||
242 | reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_IRQSTATUS_MAIN); | 287 | reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_IRQSTATUS_MAIN); |
@@ -273,8 +318,11 @@ static irqreturn_t dra7xx_pcie_irq_handler(int irq, void *arg) | |||
273 | if (reg & LINK_REQ_RST) | 318 | if (reg & LINK_REQ_RST) |
274 | dev_dbg(dev, "Link Request Reset\n"); | 319 | dev_dbg(dev, "Link Request Reset\n"); |
275 | 320 | ||
276 | if (reg & LINK_UP_EVT) | 321 | if (reg & LINK_UP_EVT) { |
322 | if (dra7xx->mode == DW_PCIE_EP_TYPE) | ||
323 | dw_pcie_ep_linkup(ep); | ||
277 | dev_dbg(dev, "Link-up state change\n"); | 324 | dev_dbg(dev, "Link-up state change\n"); |
325 | } | ||
278 | 326 | ||
279 | if (reg & CFG_BME_EVT) | 327 | if (reg & CFG_BME_EVT) |
280 | dev_dbg(dev, "CFG 'Bus Master Enable' change\n"); | 328 | dev_dbg(dev, "CFG 'Bus Master Enable' change\n"); |
@@ -287,6 +335,94 @@ static irqreturn_t dra7xx_pcie_irq_handler(int irq, void *arg) | |||
287 | return IRQ_HANDLED; | 335 | return IRQ_HANDLED; |
288 | } | 336 | } |
289 | 337 | ||
338 | static void dra7xx_pcie_ep_init(struct dw_pcie_ep *ep) | ||
339 | { | ||
340 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); | ||
341 | struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pci); | ||
342 | |||
343 | dra7xx_pcie_enable_wrapper_interrupts(dra7xx); | ||
344 | } | ||
345 | |||
346 | static void dra7xx_pcie_raise_legacy_irq(struct dra7xx_pcie *dra7xx) | ||
347 | { | ||
348 | dra7xx_pcie_writel(dra7xx, PCIECTRL_TI_CONF_INTX_ASSERT, 0x1); | ||
349 | mdelay(1); | ||
350 | dra7xx_pcie_writel(dra7xx, PCIECTRL_TI_CONF_INTX_DEASSERT, 0x1); | ||
351 | } | ||
352 | |||
353 | static void dra7xx_pcie_raise_msi_irq(struct dra7xx_pcie *dra7xx, | ||
354 | u8 interrupt_num) | ||
355 | { | ||
356 | u32 reg; | ||
357 | |||
358 | reg = (interrupt_num - 1) << MSI_VECTOR_SHIFT; | ||
359 | reg |= MSI_REQ_GRANT; | ||
360 | dra7xx_pcie_writel(dra7xx, PCIECTRL_TI_CONF_MSI_XMT, reg); | ||
361 | } | ||
362 | |||
363 | static int dra7xx_pcie_raise_irq(struct dw_pcie_ep *ep, | ||
364 | enum pci_epc_irq_type type, u8 interrupt_num) | ||
365 | { | ||
366 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); | ||
367 | struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pci); | ||
368 | |||
369 | switch (type) { | ||
370 | case PCI_EPC_IRQ_LEGACY: | ||
371 | dra7xx_pcie_raise_legacy_irq(dra7xx); | ||
372 | break; | ||
373 | case PCI_EPC_IRQ_MSI: | ||
374 | dra7xx_pcie_raise_msi_irq(dra7xx, interrupt_num); | ||
375 | break; | ||
376 | default: | ||
377 | dev_err(pci->dev, "UNKNOWN IRQ type\n"); | ||
378 | } | ||
379 | |||
380 | return 0; | ||
381 | } | ||
382 | |||
383 | static struct dw_pcie_ep_ops pcie_ep_ops = { | ||
384 | .ep_init = dra7xx_pcie_ep_init, | ||
385 | .raise_irq = dra7xx_pcie_raise_irq, | ||
386 | }; | ||
387 | |||
388 | static int __init dra7xx_add_pcie_ep(struct dra7xx_pcie *dra7xx, | ||
389 | struct platform_device *pdev) | ||
390 | { | ||
391 | int ret; | ||
392 | struct dw_pcie_ep *ep; | ||
393 | struct resource *res; | ||
394 | struct device *dev = &pdev->dev; | ||
395 | struct dw_pcie *pci = dra7xx->pci; | ||
396 | |||
397 | ep = &pci->ep; | ||
398 | ep->ops = &pcie_ep_ops; | ||
399 | |||
400 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ep_dbics"); | ||
401 | pci->dbi_base = devm_ioremap(dev, res->start, resource_size(res)); | ||
402 | if (!pci->dbi_base) | ||
403 | return -ENOMEM; | ||
404 | |||
405 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ep_dbics2"); | ||
406 | pci->dbi_base2 = devm_ioremap(dev, res->start, resource_size(res)); | ||
407 | if (!pci->dbi_base2) | ||
408 | return -ENOMEM; | ||
409 | |||
410 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space"); | ||
411 | if (!res) | ||
412 | return -EINVAL; | ||
413 | |||
414 | ep->phys_base = res->start; | ||
415 | ep->addr_size = resource_size(res); | ||
416 | |||
417 | ret = dw_pcie_ep_init(ep); | ||
418 | if (ret) { | ||
419 | dev_err(dev, "failed to initialize endpoint\n"); | ||
420 | return ret; | ||
421 | } | ||
422 | |||
423 | return 0; | ||
424 | } | ||
425 | |||
290 | static int __init dra7xx_add_pcie_port(struct dra7xx_pcie *dra7xx, | 426 | static int __init dra7xx_add_pcie_port(struct dra7xx_pcie *dra7xx, |
291 | struct platform_device *pdev) | 427 | struct platform_device *pdev) |
292 | { | 428 | { |
@@ -329,6 +465,9 @@ static int __init dra7xx_add_pcie_port(struct dra7xx_pcie *dra7xx, | |||
329 | } | 465 | } |
330 | 466 | ||
331 | static const struct dw_pcie_ops dw_pcie_ops = { | 467 | static const struct dw_pcie_ops dw_pcie_ops = { |
468 | .cpu_addr_fixup = dra7xx_pcie_cpu_addr_fixup, | ||
469 | .start_link = dra7xx_pcie_establish_link, | ||
470 | .stop_link = dra7xx_pcie_stop_link, | ||
332 | .link_up = dra7xx_pcie_link_up, | 471 | .link_up = dra7xx_pcie_link_up, |
333 | }; | 472 | }; |
334 | 473 | ||
@@ -371,6 +510,68 @@ err_phy: | |||
371 | return ret; | 510 | return ret; |
372 | } | 511 | } |
373 | 512 | ||
513 | static const struct dra7xx_pcie_of_data dra7xx_pcie_rc_of_data = { | ||
514 | .mode = DW_PCIE_RC_TYPE, | ||
515 | }; | ||
516 | |||
517 | static const struct dra7xx_pcie_of_data dra7xx_pcie_ep_of_data = { | ||
518 | .mode = DW_PCIE_EP_TYPE, | ||
519 | }; | ||
520 | |||
521 | static const struct of_device_id of_dra7xx_pcie_match[] = { | ||
522 | { | ||
523 | .compatible = "ti,dra7-pcie", | ||
524 | .data = &dra7xx_pcie_rc_of_data, | ||
525 | }, | ||
526 | { | ||
527 | .compatible = "ti,dra7-pcie-ep", | ||
528 | .data = &dra7xx_pcie_ep_of_data, | ||
529 | }, | ||
530 | {}, | ||
531 | }; | ||
532 | |||
533 | /* | ||
534 | * dra7xx_pcie_ep_unaligned_memaccess: workaround for AM572x/AM571x Errata i870 | ||
535 | * @dra7xx: the dra7xx device where the workaround should be applied | ||
536 | * | ||
537 | * Access to the PCIe slave port that are not 32-bit aligned will result | ||
538 | * in incorrect mapping to TLP Address and Byte enable fields. Therefore, | ||
539 | * byte and half-word accesses are not possible to byte offset 0x1, 0x2, or | ||
540 | * 0x3. | ||
541 | * | ||
542 | * To avoid this issue set PCIE_SS1_AXI2OCP_LEGACY_MODE_ENABLE to 1. | ||
543 | */ | ||
544 | static int dra7xx_pcie_ep_unaligned_memaccess(struct device *dev) | ||
545 | { | ||
546 | int ret; | ||
547 | struct device_node *np = dev->of_node; | ||
548 | struct of_phandle_args args; | ||
549 | struct regmap *regmap; | ||
550 | |||
551 | regmap = syscon_regmap_lookup_by_phandle(np, | ||
552 | "ti,syscon-unaligned-access"); | ||
553 | if (IS_ERR(regmap)) { | ||
554 | dev_dbg(dev, "can't get ti,syscon-unaligned-access\n"); | ||
555 | return -EINVAL; | ||
556 | } | ||
557 | |||
558 | ret = of_parse_phandle_with_fixed_args(np, "ti,syscon-unaligned-access", | ||
559 | 2, 0, &args); | ||
560 | if (ret) { | ||
561 | dev_err(dev, "failed to parse ti,syscon-unaligned-access\n"); | ||
562 | return ret; | ||
563 | } | ||
564 | |||
565 | ret = regmap_update_bits(regmap, args.args[0], args.args[1], | ||
566 | args.args[1]); | ||
567 | if (ret) | ||
568 | dev_err(dev, "failed to enable unaligned access\n"); | ||
569 | |||
570 | of_node_put(args.np); | ||
571 | |||
572 | return ret; | ||
573 | } | ||
574 | |||
374 | static int __init dra7xx_pcie_probe(struct platform_device *pdev) | 575 | static int __init dra7xx_pcie_probe(struct platform_device *pdev) |
375 | { | 576 | { |
376 | u32 reg; | 577 | u32 reg; |
@@ -388,6 +589,16 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev) | |||
388 | struct device_node *np = dev->of_node; | 589 | struct device_node *np = dev->of_node; |
389 | char name[10]; | 590 | char name[10]; |
390 | struct gpio_desc *reset; | 591 | struct gpio_desc *reset; |
592 | const struct of_device_id *match; | ||
593 | const struct dra7xx_pcie_of_data *data; | ||
594 | enum dw_pcie_device_mode mode; | ||
595 | |||
596 | match = of_match_device(of_match_ptr(of_dra7xx_pcie_match), dev); | ||
597 | if (!match) | ||
598 | return -EINVAL; | ||
599 | |||
600 | data = (struct dra7xx_pcie_of_data *)match->data; | ||
601 | mode = (enum dw_pcie_device_mode)data->mode; | ||
391 | 602 | ||
392 | dra7xx = devm_kzalloc(dev, sizeof(*dra7xx), GFP_KERNEL); | 603 | dra7xx = devm_kzalloc(dev, sizeof(*dra7xx), GFP_KERNEL); |
393 | if (!dra7xx) | 604 | if (!dra7xx) |
@@ -409,13 +620,6 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev) | |||
409 | return -EINVAL; | 620 | return -EINVAL; |
410 | } | 621 | } |
411 | 622 | ||
412 | ret = devm_request_irq(dev, irq, dra7xx_pcie_irq_handler, | ||
413 | IRQF_SHARED, "dra7xx-pcie-main", dra7xx); | ||
414 | if (ret) { | ||
415 | dev_err(dev, "failed to request irq\n"); | ||
416 | return ret; | ||
417 | } | ||
418 | |||
419 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ti_conf"); | 623 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ti_conf"); |
420 | base = devm_ioremap_nocache(dev, res->start, resource_size(res)); | 624 | base = devm_ioremap_nocache(dev, res->start, resource_size(res)); |
421 | if (!base) | 625 | if (!base) |
@@ -473,9 +677,37 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev) | |||
473 | if (dra7xx->link_gen < 0 || dra7xx->link_gen > 2) | 677 | if (dra7xx->link_gen < 0 || dra7xx->link_gen > 2) |
474 | dra7xx->link_gen = 2; | 678 | dra7xx->link_gen = 2; |
475 | 679 | ||
476 | ret = dra7xx_add_pcie_port(dra7xx, pdev); | 680 | switch (mode) { |
477 | if (ret < 0) | 681 | case DW_PCIE_RC_TYPE: |
682 | dra7xx_pcie_writel(dra7xx, PCIECTRL_TI_CONF_DEVICE_TYPE, | ||
683 | DEVICE_TYPE_RC); | ||
684 | ret = dra7xx_add_pcie_port(dra7xx, pdev); | ||
685 | if (ret < 0) | ||
686 | goto err_gpio; | ||
687 | break; | ||
688 | case DW_PCIE_EP_TYPE: | ||
689 | dra7xx_pcie_writel(dra7xx, PCIECTRL_TI_CONF_DEVICE_TYPE, | ||
690 | DEVICE_TYPE_EP); | ||
691 | |||
692 | ret = dra7xx_pcie_ep_unaligned_memaccess(dev); | ||
693 | if (ret) | ||
694 | goto err_gpio; | ||
695 | |||
696 | ret = dra7xx_add_pcie_ep(dra7xx, pdev); | ||
697 | if (ret < 0) | ||
698 | goto err_gpio; | ||
699 | break; | ||
700 | default: | ||
701 | dev_err(dev, "INVALID device type %d\n", mode); | ||
702 | } | ||
703 | dra7xx->mode = mode; | ||
704 | |||
705 | ret = devm_request_irq(dev, irq, dra7xx_pcie_irq_handler, | ||
706 | IRQF_SHARED, "dra7xx-pcie-main", dra7xx); | ||
707 | if (ret) { | ||
708 | dev_err(dev, "failed to request irq\n"); | ||
478 | goto err_gpio; | 709 | goto err_gpio; |
710 | } | ||
479 | 711 | ||
480 | return 0; | 712 | return 0; |
481 | 713 | ||
@@ -496,6 +728,9 @@ static int dra7xx_pcie_suspend(struct device *dev) | |||
496 | struct dw_pcie *pci = dra7xx->pci; | 728 | struct dw_pcie *pci = dra7xx->pci; |
497 | u32 val; | 729 | u32 val; |
498 | 730 | ||
731 | if (dra7xx->mode != DW_PCIE_RC_TYPE) | ||
732 | return 0; | ||
733 | |||
499 | /* clear MSE */ | 734 | /* clear MSE */ |
500 | val = dw_pcie_readl_dbi(pci, PCI_COMMAND); | 735 | val = dw_pcie_readl_dbi(pci, PCI_COMMAND); |
501 | val &= ~PCI_COMMAND_MEMORY; | 736 | val &= ~PCI_COMMAND_MEMORY; |
@@ -510,6 +745,9 @@ static int dra7xx_pcie_resume(struct device *dev) | |||
510 | struct dw_pcie *pci = dra7xx->pci; | 745 | struct dw_pcie *pci = dra7xx->pci; |
511 | u32 val; | 746 | u32 val; |
512 | 747 | ||
748 | if (dra7xx->mode != DW_PCIE_RC_TYPE) | ||
749 | return 0; | ||
750 | |||
513 | /* set MSE */ | 751 | /* set MSE */ |
514 | val = dw_pcie_readl_dbi(pci, PCI_COMMAND); | 752 | val = dw_pcie_readl_dbi(pci, PCI_COMMAND); |
515 | val |= PCI_COMMAND_MEMORY; | 753 | val |= PCI_COMMAND_MEMORY; |
@@ -548,11 +786,6 @@ static const struct dev_pm_ops dra7xx_pcie_pm_ops = { | |||
548 | dra7xx_pcie_resume_noirq) | 786 | dra7xx_pcie_resume_noirq) |
549 | }; | 787 | }; |
550 | 788 | ||
551 | static const struct of_device_id of_dra7xx_pcie_match[] = { | ||
552 | { .compatible = "ti,dra7-pcie", }, | ||
553 | {}, | ||
554 | }; | ||
555 | |||
556 | static struct platform_driver dra7xx_pcie_driver = { | 789 | static struct platform_driver dra7xx_pcie_driver = { |
557 | .driver = { | 790 | .driver = { |
558 | .name = "dra7-pcie", | 791 | .name = "dra7-pcie", |
diff --git a/drivers/pci/dwc/pci-exynos.c b/drivers/pci/dwc/pci-exynos.c index 993b650ef275..546082ad5a3f 100644 --- a/drivers/pci/dwc/pci-exynos.c +++ b/drivers/pci/dwc/pci-exynos.c | |||
@@ -132,10 +132,6 @@ static int exynos5440_pcie_get_mem_resources(struct platform_device *pdev, | |||
132 | struct device *dev = pci->dev; | 132 | struct device *dev = pci->dev; |
133 | struct resource *res; | 133 | struct resource *res; |
134 | 134 | ||
135 | /* If using the PHY framework, doesn't need to get other resource */ | ||
136 | if (ep->using_phy) | ||
137 | return 0; | ||
138 | |||
139 | ep->mem_res = devm_kzalloc(dev, sizeof(*ep->mem_res), GFP_KERNEL); | 135 | ep->mem_res = devm_kzalloc(dev, sizeof(*ep->mem_res), GFP_KERNEL); |
140 | if (!ep->mem_res) | 136 | if (!ep->mem_res) |
141 | return -ENOMEM; | 137 | return -ENOMEM; |
@@ -145,6 +141,10 @@ static int exynos5440_pcie_get_mem_resources(struct platform_device *pdev, | |||
145 | if (IS_ERR(ep->mem_res->elbi_base)) | 141 | if (IS_ERR(ep->mem_res->elbi_base)) |
146 | return PTR_ERR(ep->mem_res->elbi_base); | 142 | return PTR_ERR(ep->mem_res->elbi_base); |
147 | 143 | ||
144 | /* If using the PHY framework, doesn't need to get other resource */ | ||
145 | if (ep->using_phy) | ||
146 | return 0; | ||
147 | |||
148 | res = platform_get_resource(pdev, IORESOURCE_MEM, 1); | 148 | res = platform_get_resource(pdev, IORESOURCE_MEM, 1); |
149 | ep->mem_res->phy_base = devm_ioremap_resource(dev, res); | 149 | ep->mem_res->phy_base = devm_ioremap_resource(dev, res); |
150 | if (IS_ERR(ep->mem_res->phy_base)) | 150 | if (IS_ERR(ep->mem_res->phy_base)) |
@@ -521,23 +521,25 @@ static void exynos_pcie_enable_interrupts(struct exynos_pcie *ep) | |||
521 | exynos_pcie_msi_init(ep); | 521 | exynos_pcie_msi_init(ep); |
522 | } | 522 | } |
523 | 523 | ||
524 | static u32 exynos_pcie_readl_dbi(struct dw_pcie *pci, u32 reg) | 524 | static u32 exynos_pcie_read_dbi(struct dw_pcie *pci, void __iomem *base, |
525 | u32 reg, size_t size) | ||
525 | { | 526 | { |
526 | struct exynos_pcie *ep = to_exynos_pcie(pci); | 527 | struct exynos_pcie *ep = to_exynos_pcie(pci); |
527 | u32 val; | 528 | u32 val; |
528 | 529 | ||
529 | exynos_pcie_sideband_dbi_r_mode(ep, true); | 530 | exynos_pcie_sideband_dbi_r_mode(ep, true); |
530 | val = readl(pci->dbi_base + reg); | 531 | dw_pcie_read(base + reg, size, &val); |
531 | exynos_pcie_sideband_dbi_r_mode(ep, false); | 532 | exynos_pcie_sideband_dbi_r_mode(ep, false); |
532 | return val; | 533 | return val; |
533 | } | 534 | } |
534 | 535 | ||
535 | static void exynos_pcie_writel_dbi(struct dw_pcie *pci, u32 reg, u32 val) | 536 | static void exynos_pcie_write_dbi(struct dw_pcie *pci, void __iomem *base, |
537 | u32 reg, size_t size, u32 val) | ||
536 | { | 538 | { |
537 | struct exynos_pcie *ep = to_exynos_pcie(pci); | 539 | struct exynos_pcie *ep = to_exynos_pcie(pci); |
538 | 540 | ||
539 | exynos_pcie_sideband_dbi_w_mode(ep, true); | 541 | exynos_pcie_sideband_dbi_w_mode(ep, true); |
540 | writel(val, pci->dbi_base + reg); | 542 | dw_pcie_write(base + reg, size, val); |
541 | exynos_pcie_sideband_dbi_w_mode(ep, false); | 543 | exynos_pcie_sideband_dbi_w_mode(ep, false); |
542 | } | 544 | } |
543 | 545 | ||
@@ -644,8 +646,8 @@ static int __init exynos_add_pcie_port(struct exynos_pcie *ep, | |||
644 | } | 646 | } |
645 | 647 | ||
646 | static const struct dw_pcie_ops dw_pcie_ops = { | 648 | static const struct dw_pcie_ops dw_pcie_ops = { |
647 | .readl_dbi = exynos_pcie_readl_dbi, | 649 | .read_dbi = exynos_pcie_read_dbi, |
648 | .writel_dbi = exynos_pcie_writel_dbi, | 650 | .write_dbi = exynos_pcie_write_dbi, |
649 | .link_up = exynos_pcie_link_up, | 651 | .link_up = exynos_pcie_link_up, |
650 | }; | 652 | }; |
651 | 653 | ||
diff --git a/drivers/pci/dwc/pcie-artpec6.c b/drivers/pci/dwc/pcie-artpec6.c index fcd3ef845883..5b3b3afc0edb 100644 --- a/drivers/pci/dwc/pcie-artpec6.c +++ b/drivers/pci/dwc/pcie-artpec6.c | |||
@@ -78,6 +78,11 @@ static void artpec6_pcie_writel(struct artpec6_pcie *artpec6_pcie, u32 offset, u | |||
78 | regmap_write(artpec6_pcie->regmap, offset, val); | 78 | regmap_write(artpec6_pcie->regmap, offset, val); |
79 | } | 79 | } |
80 | 80 | ||
81 | static u64 artpec6_pcie_cpu_addr_fixup(u64 pci_addr) | ||
82 | { | ||
83 | return pci_addr & ARTPEC6_CPU_TO_BUS_ADDR; | ||
84 | } | ||
85 | |||
81 | static int artpec6_pcie_establish_link(struct artpec6_pcie *artpec6_pcie) | 86 | static int artpec6_pcie_establish_link(struct artpec6_pcie *artpec6_pcie) |
82 | { | 87 | { |
83 | struct dw_pcie *pci = artpec6_pcie->pci; | 88 | struct dw_pcie *pci = artpec6_pcie->pci; |
@@ -142,11 +147,6 @@ static int artpec6_pcie_establish_link(struct artpec6_pcie *artpec6_pcie) | |||
142 | */ | 147 | */ |
143 | dw_pcie_writel_dbi(pci, MISC_CONTROL_1_OFF, DBI_RO_WR_EN); | 148 | dw_pcie_writel_dbi(pci, MISC_CONTROL_1_OFF, DBI_RO_WR_EN); |
144 | 149 | ||
145 | pp->io_base &= ARTPEC6_CPU_TO_BUS_ADDR; | ||
146 | pp->mem_base &= ARTPEC6_CPU_TO_BUS_ADDR; | ||
147 | pp->cfg0_base &= ARTPEC6_CPU_TO_BUS_ADDR; | ||
148 | pp->cfg1_base &= ARTPEC6_CPU_TO_BUS_ADDR; | ||
149 | |||
150 | /* setup root complex */ | 150 | /* setup root complex */ |
151 | dw_pcie_setup_rc(pp); | 151 | dw_pcie_setup_rc(pp); |
152 | 152 | ||
@@ -234,6 +234,10 @@ static int artpec6_add_pcie_port(struct artpec6_pcie *artpec6_pcie, | |||
234 | return 0; | 234 | return 0; |
235 | } | 235 | } |
236 | 236 | ||
237 | static const struct dw_pcie_ops dw_pcie_ops = { | ||
238 | .cpu_addr_fixup = artpec6_pcie_cpu_addr_fixup, | ||
239 | }; | ||
240 | |||
237 | static int artpec6_pcie_probe(struct platform_device *pdev) | 241 | static int artpec6_pcie_probe(struct platform_device *pdev) |
238 | { | 242 | { |
239 | struct device *dev = &pdev->dev; | 243 | struct device *dev = &pdev->dev; |
@@ -252,6 +256,7 @@ static int artpec6_pcie_probe(struct platform_device *pdev) | |||
252 | return -ENOMEM; | 256 | return -ENOMEM; |
253 | 257 | ||
254 | pci->dev = dev; | 258 | pci->dev = dev; |
259 | pci->ops = &dw_pcie_ops; | ||
255 | 260 | ||
256 | artpec6_pcie->pci = pci; | 261 | artpec6_pcie->pci = pci; |
257 | 262 | ||
diff --git a/drivers/pci/dwc/pcie-designware-ep.c b/drivers/pci/dwc/pcie-designware-ep.c new file mode 100644 index 000000000000..398406393f37 --- /dev/null +++ b/drivers/pci/dwc/pcie-designware-ep.c | |||
@@ -0,0 +1,342 @@ | |||
1 | /** | ||
2 | * Synopsys Designware PCIe Endpoint controller driver | ||
3 | * | ||
4 | * Copyright (C) 2017 Texas Instruments | ||
5 | * Author: Kishon Vijay Abraham I <kishon@ti.com> | ||
6 | * | ||
7 | * This program is free software: you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 of | ||
9 | * the License as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
18 | */ | ||
19 | |||
20 | #include <linux/of.h> | ||
21 | |||
22 | #include "pcie-designware.h" | ||
23 | #include <linux/pci-epc.h> | ||
24 | #include <linux/pci-epf.h> | ||
25 | |||
26 | void dw_pcie_ep_linkup(struct dw_pcie_ep *ep) | ||
27 | { | ||
28 | struct pci_epc *epc = ep->epc; | ||
29 | |||
30 | pci_epc_linkup(epc); | ||
31 | } | ||
32 | |||
33 | static void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar) | ||
34 | { | ||
35 | u32 reg; | ||
36 | |||
37 | reg = PCI_BASE_ADDRESS_0 + (4 * bar); | ||
38 | dw_pcie_writel_dbi2(pci, reg, 0x0); | ||
39 | dw_pcie_writel_dbi(pci, reg, 0x0); | ||
40 | } | ||
41 | |||
42 | static int dw_pcie_ep_write_header(struct pci_epc *epc, | ||
43 | struct pci_epf_header *hdr) | ||
44 | { | ||
45 | struct dw_pcie_ep *ep = epc_get_drvdata(epc); | ||
46 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); | ||
47 | |||
48 | dw_pcie_writew_dbi(pci, PCI_VENDOR_ID, hdr->vendorid); | ||
49 | dw_pcie_writew_dbi(pci, PCI_DEVICE_ID, hdr->deviceid); | ||
50 | dw_pcie_writeb_dbi(pci, PCI_REVISION_ID, hdr->revid); | ||
51 | dw_pcie_writeb_dbi(pci, PCI_CLASS_PROG, hdr->progif_code); | ||
52 | dw_pcie_writew_dbi(pci, PCI_CLASS_DEVICE, | ||
53 | hdr->subclass_code | hdr->baseclass_code << 8); | ||
54 | dw_pcie_writeb_dbi(pci, PCI_CACHE_LINE_SIZE, | ||
55 | hdr->cache_line_size); | ||
56 | dw_pcie_writew_dbi(pci, PCI_SUBSYSTEM_VENDOR_ID, | ||
57 | hdr->subsys_vendor_id); | ||
58 | dw_pcie_writew_dbi(pci, PCI_SUBSYSTEM_ID, hdr->subsys_id); | ||
59 | dw_pcie_writeb_dbi(pci, PCI_INTERRUPT_PIN, | ||
60 | hdr->interrupt_pin); | ||
61 | |||
62 | return 0; | ||
63 | } | ||
64 | |||
65 | static int dw_pcie_ep_inbound_atu(struct dw_pcie_ep *ep, enum pci_barno bar, | ||
66 | dma_addr_t cpu_addr, | ||
67 | enum dw_pcie_as_type as_type) | ||
68 | { | ||
69 | int ret; | ||
70 | u32 free_win; | ||
71 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); | ||
72 | |||
73 | free_win = find_first_zero_bit(&ep->ib_window_map, | ||
74 | sizeof(ep->ib_window_map)); | ||
75 | if (free_win >= ep->num_ib_windows) { | ||
76 | dev_err(pci->dev, "no free inbound window\n"); | ||
77 | return -EINVAL; | ||
78 | } | ||
79 | |||
80 | ret = dw_pcie_prog_inbound_atu(pci, free_win, bar, cpu_addr, | ||
81 | as_type); | ||
82 | if (ret < 0) { | ||
83 | dev_err(pci->dev, "Failed to program IB window\n"); | ||
84 | return ret; | ||
85 | } | ||
86 | |||
87 | ep->bar_to_atu[bar] = free_win; | ||
88 | set_bit(free_win, &ep->ib_window_map); | ||
89 | |||
90 | return 0; | ||
91 | } | ||
92 | |||
93 | static int dw_pcie_ep_outbound_atu(struct dw_pcie_ep *ep, phys_addr_t phys_addr, | ||
94 | u64 pci_addr, size_t size) | ||
95 | { | ||
96 | u32 free_win; | ||
97 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); | ||
98 | |||
99 | free_win = find_first_zero_bit(&ep->ob_window_map, | ||
100 | sizeof(ep->ob_window_map)); | ||
101 | if (free_win >= ep->num_ob_windows) { | ||
102 | dev_err(pci->dev, "no free outbound window\n"); | ||
103 | return -EINVAL; | ||
104 | } | ||
105 | |||
106 | dw_pcie_prog_outbound_atu(pci, free_win, PCIE_ATU_TYPE_MEM, | ||
107 | phys_addr, pci_addr, size); | ||
108 | |||
109 | set_bit(free_win, &ep->ob_window_map); | ||
110 | ep->outbound_addr[free_win] = phys_addr; | ||
111 | |||
112 | return 0; | ||
113 | } | ||
114 | |||
115 | static void dw_pcie_ep_clear_bar(struct pci_epc *epc, enum pci_barno bar) | ||
116 | { | ||
117 | struct dw_pcie_ep *ep = epc_get_drvdata(epc); | ||
118 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); | ||
119 | u32 atu_index = ep->bar_to_atu[bar]; | ||
120 | |||
121 | dw_pcie_ep_reset_bar(pci, bar); | ||
122 | |||
123 | dw_pcie_disable_atu(pci, atu_index, DW_PCIE_REGION_INBOUND); | ||
124 | clear_bit(atu_index, &ep->ib_window_map); | ||
125 | } | ||
126 | |||
127 | static int dw_pcie_ep_set_bar(struct pci_epc *epc, enum pci_barno bar, | ||
128 | dma_addr_t bar_phys, size_t size, int flags) | ||
129 | { | ||
130 | int ret; | ||
131 | struct dw_pcie_ep *ep = epc_get_drvdata(epc); | ||
132 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); | ||
133 | enum dw_pcie_as_type as_type; | ||
134 | u32 reg = PCI_BASE_ADDRESS_0 + (4 * bar); | ||
135 | |||
136 | if (!(flags & PCI_BASE_ADDRESS_SPACE)) | ||
137 | as_type = DW_PCIE_AS_MEM; | ||
138 | else | ||
139 | as_type = DW_PCIE_AS_IO; | ||
140 | |||
141 | ret = dw_pcie_ep_inbound_atu(ep, bar, bar_phys, as_type); | ||
142 | if (ret) | ||
143 | return ret; | ||
144 | |||
145 | dw_pcie_writel_dbi2(pci, reg, size - 1); | ||
146 | dw_pcie_writel_dbi(pci, reg, flags); | ||
147 | |||
148 | return 0; | ||
149 | } | ||
150 | |||
151 | static int dw_pcie_find_index(struct dw_pcie_ep *ep, phys_addr_t addr, | ||
152 | u32 *atu_index) | ||
153 | { | ||
154 | u32 index; | ||
155 | |||
156 | for (index = 0; index < ep->num_ob_windows; index++) { | ||
157 | if (ep->outbound_addr[index] != addr) | ||
158 | continue; | ||
159 | *atu_index = index; | ||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | return -EINVAL; | ||
164 | } | ||
165 | |||
166 | static void dw_pcie_ep_unmap_addr(struct pci_epc *epc, phys_addr_t addr) | ||
167 | { | ||
168 | int ret; | ||
169 | u32 atu_index; | ||
170 | struct dw_pcie_ep *ep = epc_get_drvdata(epc); | ||
171 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); | ||
172 | |||
173 | ret = dw_pcie_find_index(ep, addr, &atu_index); | ||
174 | if (ret < 0) | ||
175 | return; | ||
176 | |||
177 | dw_pcie_disable_atu(pci, atu_index, DW_PCIE_REGION_OUTBOUND); | ||
178 | clear_bit(atu_index, &ep->ob_window_map); | ||
179 | } | ||
180 | |||
181 | static int dw_pcie_ep_map_addr(struct pci_epc *epc, phys_addr_t addr, | ||
182 | u64 pci_addr, size_t size) | ||
183 | { | ||
184 | int ret; | ||
185 | struct dw_pcie_ep *ep = epc_get_drvdata(epc); | ||
186 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); | ||
187 | |||
188 | ret = dw_pcie_ep_outbound_atu(ep, addr, pci_addr, size); | ||
189 | if (ret) { | ||
190 | dev_err(pci->dev, "failed to enable address\n"); | ||
191 | return ret; | ||
192 | } | ||
193 | |||
194 | return 0; | ||
195 | } | ||
196 | |||
197 | static int dw_pcie_ep_get_msi(struct pci_epc *epc) | ||
198 | { | ||
199 | int val; | ||
200 | u32 lower_addr; | ||
201 | u32 upper_addr; | ||
202 | struct dw_pcie_ep *ep = epc_get_drvdata(epc); | ||
203 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); | ||
204 | |||
205 | val = dw_pcie_readb_dbi(pci, MSI_MESSAGE_CONTROL); | ||
206 | val = (val & MSI_CAP_MME_MASK) >> MSI_CAP_MME_SHIFT; | ||
207 | |||
208 | lower_addr = dw_pcie_readl_dbi(pci, MSI_MESSAGE_ADDR_L32); | ||
209 | upper_addr = dw_pcie_readl_dbi(pci, MSI_MESSAGE_ADDR_U32); | ||
210 | |||
211 | if (!(lower_addr || upper_addr)) | ||
212 | return -EINVAL; | ||
213 | |||
214 | return val; | ||
215 | } | ||
216 | |||
217 | static int dw_pcie_ep_set_msi(struct pci_epc *epc, u8 encode_int) | ||
218 | { | ||
219 | int val; | ||
220 | struct dw_pcie_ep *ep = epc_get_drvdata(epc); | ||
221 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); | ||
222 | |||
223 | val = (encode_int << MSI_CAP_MMC_SHIFT); | ||
224 | dw_pcie_writew_dbi(pci, MSI_MESSAGE_CONTROL, val); | ||
225 | |||
226 | return 0; | ||
227 | } | ||
228 | |||
229 | static int dw_pcie_ep_raise_irq(struct pci_epc *epc, | ||
230 | enum pci_epc_irq_type type, u8 interrupt_num) | ||
231 | { | ||
232 | struct dw_pcie_ep *ep = epc_get_drvdata(epc); | ||
233 | |||
234 | if (!ep->ops->raise_irq) | ||
235 | return -EINVAL; | ||
236 | |||
237 | return ep->ops->raise_irq(ep, type, interrupt_num); | ||
238 | } | ||
239 | |||
240 | static void dw_pcie_ep_stop(struct pci_epc *epc) | ||
241 | { | ||
242 | struct dw_pcie_ep *ep = epc_get_drvdata(epc); | ||
243 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); | ||
244 | |||
245 | if (!pci->ops->stop_link) | ||
246 | return; | ||
247 | |||
248 | pci->ops->stop_link(pci); | ||
249 | } | ||
250 | |||
251 | static int dw_pcie_ep_start(struct pci_epc *epc) | ||
252 | { | ||
253 | struct dw_pcie_ep *ep = epc_get_drvdata(epc); | ||
254 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); | ||
255 | |||
256 | if (!pci->ops->start_link) | ||
257 | return -EINVAL; | ||
258 | |||
259 | return pci->ops->start_link(pci); | ||
260 | } | ||
261 | |||
262 | static const struct pci_epc_ops epc_ops = { | ||
263 | .write_header = dw_pcie_ep_write_header, | ||
264 | .set_bar = dw_pcie_ep_set_bar, | ||
265 | .clear_bar = dw_pcie_ep_clear_bar, | ||
266 | .map_addr = dw_pcie_ep_map_addr, | ||
267 | .unmap_addr = dw_pcie_ep_unmap_addr, | ||
268 | .set_msi = dw_pcie_ep_set_msi, | ||
269 | .get_msi = dw_pcie_ep_get_msi, | ||
270 | .raise_irq = dw_pcie_ep_raise_irq, | ||
271 | .start = dw_pcie_ep_start, | ||
272 | .stop = dw_pcie_ep_stop, | ||
273 | }; | ||
274 | |||
275 | void dw_pcie_ep_exit(struct dw_pcie_ep *ep) | ||
276 | { | ||
277 | struct pci_epc *epc = ep->epc; | ||
278 | |||
279 | pci_epc_mem_exit(epc); | ||
280 | } | ||
281 | |||
282 | int dw_pcie_ep_init(struct dw_pcie_ep *ep) | ||
283 | { | ||
284 | int ret; | ||
285 | void *addr; | ||
286 | enum pci_barno bar; | ||
287 | struct pci_epc *epc; | ||
288 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); | ||
289 | struct device *dev = pci->dev; | ||
290 | struct device_node *np = dev->of_node; | ||
291 | |||
292 | if (!pci->dbi_base || !pci->dbi_base2) { | ||
293 | dev_err(dev, "dbi_base/deb_base2 is not populated\n"); | ||
294 | return -EINVAL; | ||
295 | } | ||
296 | |||
297 | ret = of_property_read_u32(np, "num-ib-windows", &ep->num_ib_windows); | ||
298 | if (ret < 0) { | ||
299 | dev_err(dev, "unable to read *num-ib-windows* property\n"); | ||
300 | return ret; | ||
301 | } | ||
302 | |||
303 | ret = of_property_read_u32(np, "num-ob-windows", &ep->num_ob_windows); | ||
304 | if (ret < 0) { | ||
305 | dev_err(dev, "unable to read *num-ob-windows* property\n"); | ||
306 | return ret; | ||
307 | } | ||
308 | |||
309 | addr = devm_kzalloc(dev, sizeof(phys_addr_t) * ep->num_ob_windows, | ||
310 | GFP_KERNEL); | ||
311 | if (!addr) | ||
312 | return -ENOMEM; | ||
313 | ep->outbound_addr = addr; | ||
314 | |||
315 | for (bar = BAR_0; bar <= BAR_5; bar++) | ||
316 | dw_pcie_ep_reset_bar(pci, bar); | ||
317 | |||
318 | if (ep->ops->ep_init) | ||
319 | ep->ops->ep_init(ep); | ||
320 | |||
321 | epc = devm_pci_epc_create(dev, &epc_ops); | ||
322 | if (IS_ERR(epc)) { | ||
323 | dev_err(dev, "failed to create epc device\n"); | ||
324 | return PTR_ERR(epc); | ||
325 | } | ||
326 | |||
327 | ret = of_property_read_u8(np, "max-functions", &epc->max_functions); | ||
328 | if (ret < 0) | ||
329 | epc->max_functions = 1; | ||
330 | |||
331 | ret = pci_epc_mem_init(epc, ep->phys_base, ep->addr_size); | ||
332 | if (ret < 0) { | ||
333 | dev_err(dev, "Failed to initialize address space\n"); | ||
334 | return ret; | ||
335 | } | ||
336 | |||
337 | ep->epc = epc; | ||
338 | epc_set_drvdata(epc, ep); | ||
339 | dw_pcie_setup(pci); | ||
340 | |||
341 | return 0; | ||
342 | } | ||
diff --git a/drivers/pci/dwc/pcie-designware-host.c b/drivers/pci/dwc/pcie-designware-host.c index 5ba334938b52..aece2962defc 100644 --- a/drivers/pci/dwc/pcie-designware-host.c +++ b/drivers/pci/dwc/pcie-designware-host.c | |||
@@ -56,24 +56,25 @@ static struct irq_chip dw_msi_irq_chip = { | |||
56 | /* MSI int handler */ | 56 | /* MSI int handler */ |
57 | irqreturn_t dw_handle_msi_irq(struct pcie_port *pp) | 57 | irqreturn_t dw_handle_msi_irq(struct pcie_port *pp) |
58 | { | 58 | { |
59 | unsigned long val; | 59 | u32 val; |
60 | int i, pos, irq; | 60 | int i, pos, irq; |
61 | irqreturn_t ret = IRQ_NONE; | 61 | irqreturn_t ret = IRQ_NONE; |
62 | 62 | ||
63 | for (i = 0; i < MAX_MSI_CTRLS; i++) { | 63 | for (i = 0; i < MAX_MSI_CTRLS; i++) { |
64 | dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_STATUS + i * 12, 4, | 64 | dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_STATUS + i * 12, 4, |
65 | (u32 *)&val); | 65 | &val); |
66 | if (val) { | 66 | if (!val) |
67 | ret = IRQ_HANDLED; | 67 | continue; |
68 | pos = 0; | 68 | |
69 | while ((pos = find_next_bit(&val, 32, pos)) != 32) { | 69 | ret = IRQ_HANDLED; |
70 | irq = irq_find_mapping(pp->irq_domain, | 70 | pos = 0; |
71 | i * 32 + pos); | 71 | while ((pos = find_next_bit((unsigned long *) &val, 32, |
72 | dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_STATUS + | 72 | pos)) != 32) { |
73 | i * 12, 4, 1 << pos); | 73 | irq = irq_find_mapping(pp->irq_domain, i * 32 + pos); |
74 | generic_handle_irq(irq); | 74 | dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_STATUS + i * 12, |
75 | pos++; | 75 | 4, 1 << pos); |
76 | } | 76 | generic_handle_irq(irq); |
77 | pos++; | ||
77 | } | 78 | } |
78 | } | 79 | } |
79 | 80 | ||
diff --git a/drivers/pci/dwc/pcie-designware-plat.c b/drivers/pci/dwc/pcie-designware-plat.c index b6c832ba39dd..f20d494922ab 100644 --- a/drivers/pci/dwc/pcie-designware-plat.c +++ b/drivers/pci/dwc/pcie-designware-plat.c | |||
@@ -86,6 +86,9 @@ static int dw_plat_add_pcie_port(struct pcie_port *pp, | |||
86 | return 0; | 86 | return 0; |
87 | } | 87 | } |
88 | 88 | ||
89 | static const struct dw_pcie_ops dw_pcie_ops = { | ||
90 | }; | ||
91 | |||
89 | static int dw_plat_pcie_probe(struct platform_device *pdev) | 92 | static int dw_plat_pcie_probe(struct platform_device *pdev) |
90 | { | 93 | { |
91 | struct device *dev = &pdev->dev; | 94 | struct device *dev = &pdev->dev; |
@@ -103,6 +106,7 @@ static int dw_plat_pcie_probe(struct platform_device *pdev) | |||
103 | return -ENOMEM; | 106 | return -ENOMEM; |
104 | 107 | ||
105 | pci->dev = dev; | 108 | pci->dev = dev; |
109 | pci->ops = &dw_pcie_ops; | ||
106 | 110 | ||
107 | dw_plat_pcie->pci = pci; | 111 | dw_plat_pcie->pci = pci; |
108 | 112 | ||
diff --git a/drivers/pci/dwc/pcie-designware.c b/drivers/pci/dwc/pcie-designware.c index 7e1fb7d6643c..0e03af279259 100644 --- a/drivers/pci/dwc/pcie-designware.c +++ b/drivers/pci/dwc/pcie-designware.c | |||
@@ -61,91 +61,253 @@ int dw_pcie_write(void __iomem *addr, int size, u32 val) | |||
61 | return PCIBIOS_SUCCESSFUL; | 61 | return PCIBIOS_SUCCESSFUL; |
62 | } | 62 | } |
63 | 63 | ||
64 | u32 dw_pcie_readl_dbi(struct dw_pcie *pci, u32 reg) | 64 | u32 __dw_pcie_read_dbi(struct dw_pcie *pci, void __iomem *base, u32 reg, |
65 | size_t size) | ||
65 | { | 66 | { |
66 | if (pci->ops->readl_dbi) | 67 | int ret; |
67 | return pci->ops->readl_dbi(pci, reg); | 68 | u32 val; |
68 | 69 | ||
69 | return readl(pci->dbi_base + reg); | 70 | if (pci->ops->read_dbi) |
71 | return pci->ops->read_dbi(pci, base, reg, size); | ||
72 | |||
73 | ret = dw_pcie_read(base + reg, size, &val); | ||
74 | if (ret) | ||
75 | dev_err(pci->dev, "read DBI address failed\n"); | ||
76 | |||
77 | return val; | ||
70 | } | 78 | } |
71 | 79 | ||
72 | void dw_pcie_writel_dbi(struct dw_pcie *pci, u32 reg, u32 val) | 80 | void __dw_pcie_write_dbi(struct dw_pcie *pci, void __iomem *base, u32 reg, |
81 | size_t size, u32 val) | ||
73 | { | 82 | { |
74 | if (pci->ops->writel_dbi) | 83 | int ret; |
75 | pci->ops->writel_dbi(pci, reg, val); | 84 | |
76 | else | 85 | if (pci->ops->write_dbi) { |
77 | writel(val, pci->dbi_base + reg); | 86 | pci->ops->write_dbi(pci, base, reg, size, val); |
87 | return; | ||
88 | } | ||
89 | |||
90 | ret = dw_pcie_write(base + reg, size, val); | ||
91 | if (ret) | ||
92 | dev_err(pci->dev, "write DBI address failed\n"); | ||
78 | } | 93 | } |
79 | 94 | ||
80 | static u32 dw_pcie_readl_unroll(struct dw_pcie *pci, u32 index, u32 reg) | 95 | static u32 dw_pcie_readl_ob_unroll(struct dw_pcie *pci, u32 index, u32 reg) |
81 | { | 96 | { |
82 | u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index); | 97 | u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index); |
83 | 98 | ||
84 | return dw_pcie_readl_dbi(pci, offset + reg); | 99 | return dw_pcie_readl_dbi(pci, offset + reg); |
85 | } | 100 | } |
86 | 101 | ||
87 | static void dw_pcie_writel_unroll(struct dw_pcie *pci, u32 index, u32 reg, | 102 | static void dw_pcie_writel_ob_unroll(struct dw_pcie *pci, u32 index, u32 reg, |
88 | u32 val) | 103 | u32 val) |
89 | { | 104 | { |
90 | u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index); | 105 | u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index); |
91 | 106 | ||
92 | dw_pcie_writel_dbi(pci, offset + reg, val); | 107 | dw_pcie_writel_dbi(pci, offset + reg, val); |
93 | } | 108 | } |
94 | 109 | ||
110 | void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, int index, int type, | ||
111 | u64 cpu_addr, u64 pci_addr, u32 size) | ||
112 | { | ||
113 | u32 retries, val; | ||
114 | |||
115 | dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_BASE, | ||
116 | lower_32_bits(cpu_addr)); | ||
117 | dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_BASE, | ||
118 | upper_32_bits(cpu_addr)); | ||
119 | dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LIMIT, | ||
120 | lower_32_bits(cpu_addr + size - 1)); | ||
121 | dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_TARGET, | ||
122 | lower_32_bits(pci_addr)); | ||
123 | dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET, | ||
124 | upper_32_bits(pci_addr)); | ||
125 | dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, | ||
126 | type); | ||
127 | dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2, | ||
128 | PCIE_ATU_ENABLE); | ||
129 | |||
130 | /* | ||
131 | * Make sure ATU enable takes effect before any subsequent config | ||
132 | * and I/O accesses. | ||
133 | */ | ||
134 | for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) { | ||
135 | val = dw_pcie_readl_ob_unroll(pci, index, | ||
136 | PCIE_ATU_UNR_REGION_CTRL2); | ||
137 | if (val & PCIE_ATU_ENABLE) | ||
138 | return; | ||
139 | |||
140 | usleep_range(LINK_WAIT_IATU_MIN, LINK_WAIT_IATU_MAX); | ||
141 | } | ||
142 | dev_err(pci->dev, "outbound iATU is not being enabled\n"); | ||
143 | } | ||
144 | |||
95 | void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type, | 145 | void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type, |
96 | u64 cpu_addr, u64 pci_addr, u32 size) | 146 | u64 cpu_addr, u64 pci_addr, u32 size) |
97 | { | 147 | { |
98 | u32 retries, val; | 148 | u32 retries, val; |
99 | 149 | ||
150 | if (pci->ops->cpu_addr_fixup) | ||
151 | cpu_addr = pci->ops->cpu_addr_fixup(cpu_addr); | ||
152 | |||
100 | if (pci->iatu_unroll_enabled) { | 153 | if (pci->iatu_unroll_enabled) { |
101 | dw_pcie_writel_unroll(pci, index, PCIE_ATU_UNR_LOWER_BASE, | 154 | dw_pcie_prog_outbound_atu_unroll(pci, index, type, cpu_addr, |
102 | lower_32_bits(cpu_addr)); | 155 | pci_addr, size); |
103 | dw_pcie_writel_unroll(pci, index, PCIE_ATU_UNR_UPPER_BASE, | 156 | return; |
104 | upper_32_bits(cpu_addr)); | ||
105 | dw_pcie_writel_unroll(pci, index, PCIE_ATU_UNR_LIMIT, | ||
106 | lower_32_bits(cpu_addr + size - 1)); | ||
107 | dw_pcie_writel_unroll(pci, index, PCIE_ATU_UNR_LOWER_TARGET, | ||
108 | lower_32_bits(pci_addr)); | ||
109 | dw_pcie_writel_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET, | ||
110 | upper_32_bits(pci_addr)); | ||
111 | dw_pcie_writel_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, | ||
112 | type); | ||
113 | dw_pcie_writel_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2, | ||
114 | PCIE_ATU_ENABLE); | ||
115 | } else { | ||
116 | dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, | ||
117 | PCIE_ATU_REGION_OUTBOUND | index); | ||
118 | dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_BASE, | ||
119 | lower_32_bits(cpu_addr)); | ||
120 | dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_BASE, | ||
121 | upper_32_bits(cpu_addr)); | ||
122 | dw_pcie_writel_dbi(pci, PCIE_ATU_LIMIT, | ||
123 | lower_32_bits(cpu_addr + size - 1)); | ||
124 | dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_TARGET, | ||
125 | lower_32_bits(pci_addr)); | ||
126 | dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_TARGET, | ||
127 | upper_32_bits(pci_addr)); | ||
128 | dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, type); | ||
129 | dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, PCIE_ATU_ENABLE); | ||
130 | } | 157 | } |
131 | 158 | ||
159 | dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, | ||
160 | PCIE_ATU_REGION_OUTBOUND | index); | ||
161 | dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_BASE, | ||
162 | lower_32_bits(cpu_addr)); | ||
163 | dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_BASE, | ||
164 | upper_32_bits(cpu_addr)); | ||
165 | dw_pcie_writel_dbi(pci, PCIE_ATU_LIMIT, | ||
166 | lower_32_bits(cpu_addr + size - 1)); | ||
167 | dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_TARGET, | ||
168 | lower_32_bits(pci_addr)); | ||
169 | dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_TARGET, | ||
170 | upper_32_bits(pci_addr)); | ||
171 | dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, type); | ||
172 | dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, PCIE_ATU_ENABLE); | ||
173 | |||
132 | /* | 174 | /* |
133 | * Make sure ATU enable takes effect before any subsequent config | 175 | * Make sure ATU enable takes effect before any subsequent config |
134 | * and I/O accesses. | 176 | * and I/O accesses. |
135 | */ | 177 | */ |
136 | for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) { | 178 | for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) { |
137 | if (pci->iatu_unroll_enabled) | 179 | val = dw_pcie_readl_dbi(pci, PCIE_ATU_CR2); |
138 | val = dw_pcie_readl_unroll(pci, index, | ||
139 | PCIE_ATU_UNR_REGION_CTRL2); | ||
140 | else | ||
141 | val = dw_pcie_readl_dbi(pci, PCIE_ATU_CR2); | ||
142 | |||
143 | if (val == PCIE_ATU_ENABLE) | 180 | if (val == PCIE_ATU_ENABLE) |
144 | return; | 181 | return; |
145 | 182 | ||
146 | usleep_range(LINK_WAIT_IATU_MIN, LINK_WAIT_IATU_MAX); | 183 | usleep_range(LINK_WAIT_IATU_MIN, LINK_WAIT_IATU_MAX); |
147 | } | 184 | } |
148 | dev_err(pci->dev, "iATU is not being enabled\n"); | 185 | dev_err(pci->dev, "outbound iATU is not being enabled\n"); |
186 | } | ||
187 | |||
188 | static u32 dw_pcie_readl_ib_unroll(struct dw_pcie *pci, u32 index, u32 reg) | ||
189 | { | ||
190 | u32 offset = PCIE_GET_ATU_INB_UNR_REG_OFFSET(index); | ||
191 | |||
192 | return dw_pcie_readl_dbi(pci, offset + reg); | ||
193 | } | ||
194 | |||
195 | static void dw_pcie_writel_ib_unroll(struct dw_pcie *pci, u32 index, u32 reg, | ||
196 | u32 val) | ||
197 | { | ||
198 | u32 offset = PCIE_GET_ATU_INB_UNR_REG_OFFSET(index); | ||
199 | |||
200 | dw_pcie_writel_dbi(pci, offset + reg, val); | ||
201 | } | ||
202 | |||
203 | int dw_pcie_prog_inbound_atu_unroll(struct dw_pcie *pci, int index, int bar, | ||
204 | u64 cpu_addr, enum dw_pcie_as_type as_type) | ||
205 | { | ||
206 | int type; | ||
207 | u32 retries, val; | ||
208 | |||
209 | dw_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_LOWER_TARGET, | ||
210 | lower_32_bits(cpu_addr)); | ||
211 | dw_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET, | ||
212 | upper_32_bits(cpu_addr)); | ||
213 | |||
214 | switch (as_type) { | ||
215 | case DW_PCIE_AS_MEM: | ||
216 | type = PCIE_ATU_TYPE_MEM; | ||
217 | break; | ||
218 | case DW_PCIE_AS_IO: | ||
219 | type = PCIE_ATU_TYPE_IO; | ||
220 | break; | ||
221 | default: | ||
222 | return -EINVAL; | ||
223 | } | ||
224 | |||
225 | dw_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, type); | ||
226 | dw_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2, | ||
227 | PCIE_ATU_ENABLE | | ||
228 | PCIE_ATU_BAR_MODE_ENABLE | (bar << 8)); | ||
229 | |||
230 | /* | ||
231 | * Make sure ATU enable takes effect before any subsequent config | ||
232 | * and I/O accesses. | ||
233 | */ | ||
234 | for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) { | ||
235 | val = dw_pcie_readl_ib_unroll(pci, index, | ||
236 | PCIE_ATU_UNR_REGION_CTRL2); | ||
237 | if (val & PCIE_ATU_ENABLE) | ||
238 | return 0; | ||
239 | |||
240 | usleep_range(LINK_WAIT_IATU_MIN, LINK_WAIT_IATU_MAX); | ||
241 | } | ||
242 | dev_err(pci->dev, "inbound iATU is not being enabled\n"); | ||
243 | |||
244 | return -EBUSY; | ||
245 | } | ||
246 | |||
247 | int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, int index, int bar, | ||
248 | u64 cpu_addr, enum dw_pcie_as_type as_type) | ||
249 | { | ||
250 | int type; | ||
251 | u32 retries, val; | ||
252 | |||
253 | if (pci->iatu_unroll_enabled) | ||
254 | return dw_pcie_prog_inbound_atu_unroll(pci, index, bar, | ||
255 | cpu_addr, as_type); | ||
256 | |||
257 | dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, PCIE_ATU_REGION_INBOUND | | ||
258 | index); | ||
259 | dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_TARGET, lower_32_bits(cpu_addr)); | ||
260 | dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_TARGET, upper_32_bits(cpu_addr)); | ||
261 | |||
262 | switch (as_type) { | ||
263 | case DW_PCIE_AS_MEM: | ||
264 | type = PCIE_ATU_TYPE_MEM; | ||
265 | break; | ||
266 | case DW_PCIE_AS_IO: | ||
267 | type = PCIE_ATU_TYPE_IO; | ||
268 | break; | ||
269 | default: | ||
270 | return -EINVAL; | ||
271 | } | ||
272 | |||
273 | dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, type); | ||
274 | dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, PCIE_ATU_ENABLE | ||
275 | | PCIE_ATU_BAR_MODE_ENABLE | (bar << 8)); | ||
276 | |||
277 | /* | ||
278 | * Make sure ATU enable takes effect before any subsequent config | ||
279 | * and I/O accesses. | ||
280 | */ | ||
281 | for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) { | ||
282 | val = dw_pcie_readl_dbi(pci, PCIE_ATU_CR2); | ||
283 | if (val & PCIE_ATU_ENABLE) | ||
284 | return 0; | ||
285 | |||
286 | usleep_range(LINK_WAIT_IATU_MIN, LINK_WAIT_IATU_MAX); | ||
287 | } | ||
288 | dev_err(pci->dev, "inbound iATU is not being enabled\n"); | ||
289 | |||
290 | return -EBUSY; | ||
291 | } | ||
292 | |||
293 | void dw_pcie_disable_atu(struct dw_pcie *pci, int index, | ||
294 | enum dw_pcie_region_type type) | ||
295 | { | ||
296 | int region; | ||
297 | |||
298 | switch (type) { | ||
299 | case DW_PCIE_REGION_INBOUND: | ||
300 | region = PCIE_ATU_REGION_INBOUND; | ||
301 | break; | ||
302 | case DW_PCIE_REGION_OUTBOUND: | ||
303 | region = PCIE_ATU_REGION_OUTBOUND; | ||
304 | break; | ||
305 | default: | ||
306 | return; | ||
307 | } | ||
308 | |||
309 | dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, region | index); | ||
310 | dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, ~PCIE_ATU_ENABLE); | ||
149 | } | 311 | } |
150 | 312 | ||
151 | int dw_pcie_wait_for_link(struct dw_pcie *pci) | 313 | int dw_pcie_wait_for_link(struct dw_pcie *pci) |
diff --git a/drivers/pci/dwc/pcie-designware.h b/drivers/pci/dwc/pcie-designware.h index cd3b8713fe50..c6a840575796 100644 --- a/drivers/pci/dwc/pcie-designware.h +++ b/drivers/pci/dwc/pcie-designware.h | |||
@@ -18,6 +18,9 @@ | |||
18 | #include <linux/msi.h> | 18 | #include <linux/msi.h> |
19 | #include <linux/pci.h> | 19 | #include <linux/pci.h> |
20 | 20 | ||
21 | #include <linux/pci-epc.h> | ||
22 | #include <linux/pci-epf.h> | ||
23 | |||
21 | /* Parameters for the waiting for link up routine */ | 24 | /* Parameters for the waiting for link up routine */ |
22 | #define LINK_WAIT_MAX_RETRIES 10 | 25 | #define LINK_WAIT_MAX_RETRIES 10 |
23 | #define LINK_WAIT_USLEEP_MIN 90000 | 26 | #define LINK_WAIT_USLEEP_MIN 90000 |
@@ -89,6 +92,16 @@ | |||
89 | #define PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(region) \ | 92 | #define PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(region) \ |
90 | ((0x3 << 20) | ((region) << 9)) | 93 | ((0x3 << 20) | ((region) << 9)) |
91 | 94 | ||
95 | #define PCIE_GET_ATU_INB_UNR_REG_OFFSET(region) \ | ||
96 | ((0x3 << 20) | ((region) << 9) | (0x1 << 8)) | ||
97 | |||
98 | #define MSI_MESSAGE_CONTROL 0x52 | ||
99 | #define MSI_CAP_MMC_SHIFT 1 | ||
100 | #define MSI_CAP_MME_SHIFT 4 | ||
101 | #define MSI_CAP_MME_MASK (7 << MSI_CAP_MME_SHIFT) | ||
102 | #define MSI_MESSAGE_ADDR_L32 0x54 | ||
103 | #define MSI_MESSAGE_ADDR_U32 0x58 | ||
104 | |||
92 | /* | 105 | /* |
93 | * Maximum number of MSI IRQs can be 256 per controller. But keep | 106 | * Maximum number of MSI IRQs can be 256 per controller. But keep |
94 | * it 32 as of now. Probably we will never need more than 32. If needed, | 107 | * it 32 as of now. Probably we will never need more than 32. If needed, |
@@ -99,6 +112,20 @@ | |||
99 | 112 | ||
100 | struct pcie_port; | 113 | struct pcie_port; |
101 | struct dw_pcie; | 114 | struct dw_pcie; |
115 | struct dw_pcie_ep; | ||
116 | |||
117 | enum dw_pcie_region_type { | ||
118 | DW_PCIE_REGION_UNKNOWN, | ||
119 | DW_PCIE_REGION_INBOUND, | ||
120 | DW_PCIE_REGION_OUTBOUND, | ||
121 | }; | ||
122 | |||
123 | enum dw_pcie_device_mode { | ||
124 | DW_PCIE_UNKNOWN_TYPE, | ||
125 | DW_PCIE_EP_TYPE, | ||
126 | DW_PCIE_LEG_EP_TYPE, | ||
127 | DW_PCIE_RC_TYPE, | ||
128 | }; | ||
102 | 129 | ||
103 | struct dw_pcie_host_ops { | 130 | struct dw_pcie_host_ops { |
104 | int (*rd_own_conf)(struct pcie_port *pp, int where, int size, u32 *val); | 131 | int (*rd_own_conf)(struct pcie_port *pp, int where, int size, u32 *val); |
@@ -142,35 +169,116 @@ struct pcie_port { | |||
142 | DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_IRQS); | 169 | DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_IRQS); |
143 | }; | 170 | }; |
144 | 171 | ||
172 | enum dw_pcie_as_type { | ||
173 | DW_PCIE_AS_UNKNOWN, | ||
174 | DW_PCIE_AS_MEM, | ||
175 | DW_PCIE_AS_IO, | ||
176 | }; | ||
177 | |||
178 | struct dw_pcie_ep_ops { | ||
179 | void (*ep_init)(struct dw_pcie_ep *ep); | ||
180 | int (*raise_irq)(struct dw_pcie_ep *ep, enum pci_epc_irq_type type, | ||
181 | u8 interrupt_num); | ||
182 | }; | ||
183 | |||
184 | struct dw_pcie_ep { | ||
185 | struct pci_epc *epc; | ||
186 | struct dw_pcie_ep_ops *ops; | ||
187 | phys_addr_t phys_base; | ||
188 | size_t addr_size; | ||
189 | u8 bar_to_atu[6]; | ||
190 | phys_addr_t *outbound_addr; | ||
191 | unsigned long ib_window_map; | ||
192 | unsigned long ob_window_map; | ||
193 | u32 num_ib_windows; | ||
194 | u32 num_ob_windows; | ||
195 | }; | ||
196 | |||
145 | struct dw_pcie_ops { | 197 | struct dw_pcie_ops { |
146 | u32 (*readl_dbi)(struct dw_pcie *pcie, u32 reg); | 198 | u64 (*cpu_addr_fixup)(u64 cpu_addr); |
147 | void (*writel_dbi)(struct dw_pcie *pcie, u32 reg, u32 val); | 199 | u32 (*read_dbi)(struct dw_pcie *pcie, void __iomem *base, u32 reg, |
200 | size_t size); | ||
201 | void (*write_dbi)(struct dw_pcie *pcie, void __iomem *base, u32 reg, | ||
202 | size_t size, u32 val); | ||
148 | int (*link_up)(struct dw_pcie *pcie); | 203 | int (*link_up)(struct dw_pcie *pcie); |
204 | int (*start_link)(struct dw_pcie *pcie); | ||
205 | void (*stop_link)(struct dw_pcie *pcie); | ||
149 | }; | 206 | }; |
150 | 207 | ||
151 | struct dw_pcie { | 208 | struct dw_pcie { |
152 | struct device *dev; | 209 | struct device *dev; |
153 | void __iomem *dbi_base; | 210 | void __iomem *dbi_base; |
211 | void __iomem *dbi_base2; | ||
154 | u32 num_viewport; | 212 | u32 num_viewport; |
155 | u8 iatu_unroll_enabled; | 213 | u8 iatu_unroll_enabled; |
156 | struct pcie_port pp; | 214 | struct pcie_port pp; |
215 | struct dw_pcie_ep ep; | ||
157 | const struct dw_pcie_ops *ops; | 216 | const struct dw_pcie_ops *ops; |
158 | }; | 217 | }; |
159 | 218 | ||
160 | #define to_dw_pcie_from_pp(port) container_of((port), struct dw_pcie, pp) | 219 | #define to_dw_pcie_from_pp(port) container_of((port), struct dw_pcie, pp) |
161 | 220 | ||
221 | #define to_dw_pcie_from_ep(endpoint) \ | ||
222 | container_of((endpoint), struct dw_pcie, ep) | ||
223 | |||
162 | int dw_pcie_read(void __iomem *addr, int size, u32 *val); | 224 | int dw_pcie_read(void __iomem *addr, int size, u32 *val); |
163 | int dw_pcie_write(void __iomem *addr, int size, u32 val); | 225 | int dw_pcie_write(void __iomem *addr, int size, u32 val); |
164 | 226 | ||
165 | u32 dw_pcie_readl_dbi(struct dw_pcie *pci, u32 reg); | 227 | u32 __dw_pcie_read_dbi(struct dw_pcie *pci, void __iomem *base, u32 reg, |
166 | void dw_pcie_writel_dbi(struct dw_pcie *pci, u32 reg, u32 val); | 228 | size_t size); |
229 | void __dw_pcie_write_dbi(struct dw_pcie *pci, void __iomem *base, u32 reg, | ||
230 | size_t size, u32 val); | ||
167 | int dw_pcie_link_up(struct dw_pcie *pci); | 231 | int dw_pcie_link_up(struct dw_pcie *pci); |
168 | int dw_pcie_wait_for_link(struct dw_pcie *pci); | 232 | int dw_pcie_wait_for_link(struct dw_pcie *pci); |
169 | void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, | 233 | void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, |
170 | int type, u64 cpu_addr, u64 pci_addr, | 234 | int type, u64 cpu_addr, u64 pci_addr, |
171 | u32 size); | 235 | u32 size); |
236 | int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, int index, int bar, | ||
237 | u64 cpu_addr, enum dw_pcie_as_type as_type); | ||
238 | void dw_pcie_disable_atu(struct dw_pcie *pci, int index, | ||
239 | enum dw_pcie_region_type type); | ||
172 | void dw_pcie_setup(struct dw_pcie *pci); | 240 | void dw_pcie_setup(struct dw_pcie *pci); |
173 | 241 | ||
242 | static inline void dw_pcie_writel_dbi(struct dw_pcie *pci, u32 reg, u32 val) | ||
243 | { | ||
244 | __dw_pcie_write_dbi(pci, pci->dbi_base, reg, 0x4, val); | ||
245 | } | ||
246 | |||
247 | static inline u32 dw_pcie_readl_dbi(struct dw_pcie *pci, u32 reg) | ||
248 | { | ||
249 | return __dw_pcie_read_dbi(pci, pci->dbi_base, reg, 0x4); | ||
250 | } | ||
251 | |||
252 | static inline void dw_pcie_writew_dbi(struct dw_pcie *pci, u32 reg, u16 val) | ||
253 | { | ||
254 | __dw_pcie_write_dbi(pci, pci->dbi_base, reg, 0x2, val); | ||
255 | } | ||
256 | |||
257 | static inline u16 dw_pcie_readw_dbi(struct dw_pcie *pci, u32 reg) | ||
258 | { | ||
259 | return __dw_pcie_read_dbi(pci, pci->dbi_base, reg, 0x2); | ||
260 | } | ||
261 | |||
262 | static inline void dw_pcie_writeb_dbi(struct dw_pcie *pci, u32 reg, u8 val) | ||
263 | { | ||
264 | __dw_pcie_write_dbi(pci, pci->dbi_base, reg, 0x1, val); | ||
265 | } | ||
266 | |||
267 | static inline u8 dw_pcie_readb_dbi(struct dw_pcie *pci, u32 reg) | ||
268 | { | ||
269 | return __dw_pcie_read_dbi(pci, pci->dbi_base, reg, 0x1); | ||
270 | } | ||
271 | |||
272 | static inline void dw_pcie_writel_dbi2(struct dw_pcie *pci, u32 reg, u32 val) | ||
273 | { | ||
274 | __dw_pcie_write_dbi(pci, pci->dbi_base2, reg, 0x4, val); | ||
275 | } | ||
276 | |||
277 | static inline u32 dw_pcie_readl_dbi2(struct dw_pcie *pci, u32 reg) | ||
278 | { | ||
279 | return __dw_pcie_read_dbi(pci, pci->dbi_base2, reg, 0x4); | ||
280 | } | ||
281 | |||
174 | #ifdef CONFIG_PCIE_DW_HOST | 282 | #ifdef CONFIG_PCIE_DW_HOST |
175 | irqreturn_t dw_handle_msi_irq(struct pcie_port *pp); | 283 | irqreturn_t dw_handle_msi_irq(struct pcie_port *pp); |
176 | void dw_pcie_msi_init(struct pcie_port *pp); | 284 | void dw_pcie_msi_init(struct pcie_port *pp); |
@@ -195,4 +303,23 @@ static inline int dw_pcie_host_init(struct pcie_port *pp) | |||
195 | return 0; | 303 | return 0; |
196 | } | 304 | } |
197 | #endif | 305 | #endif |
306 | |||
307 | #ifdef CONFIG_PCIE_DW_EP | ||
308 | void dw_pcie_ep_linkup(struct dw_pcie_ep *ep); | ||
309 | int dw_pcie_ep_init(struct dw_pcie_ep *ep); | ||
310 | void dw_pcie_ep_exit(struct dw_pcie_ep *ep); | ||
311 | #else | ||
312 | static inline void dw_pcie_ep_linkup(struct dw_pcie_ep *ep) | ||
313 | { | ||
314 | } | ||
315 | |||
316 | static inline int dw_pcie_ep_init(struct dw_pcie_ep *ep) | ||
317 | { | ||
318 | return 0; | ||
319 | } | ||
320 | |||
321 | static inline void dw_pcie_ep_exit(struct dw_pcie_ep *ep) | ||
322 | { | ||
323 | } | ||
324 | #endif | ||
198 | #endif /* _PCIE_DESIGNWARE_H */ | 325 | #endif /* _PCIE_DESIGNWARE_H */ |
diff --git a/drivers/pci/endpoint/Kconfig b/drivers/pci/endpoint/Kconfig new file mode 100644 index 000000000000..c23f146fb5a6 --- /dev/null +++ b/drivers/pci/endpoint/Kconfig | |||
@@ -0,0 +1,31 @@ | |||
1 | # | ||
2 | # PCI Endpoint Support | ||
3 | # | ||
4 | |||
5 | menu "PCI Endpoint" | ||
6 | |||
7 | config PCI_ENDPOINT | ||
8 | bool "PCI Endpoint Support" | ||
9 | help | ||
10 | Enable this configuration option to support configurable PCI | ||
11 | endpoint. This should be enabled if the platform has a PCI | ||
12 | controller that can operate in endpoint mode. | ||
13 | |||
14 | Enabling this option will build the endpoint library, which | ||
15 | includes endpoint controller library and endpoint function | ||
16 | library. | ||
17 | |||
18 | If in doubt, say "N" to disable Endpoint support. | ||
19 | |||
20 | config PCI_ENDPOINT_CONFIGFS | ||
21 | bool "PCI Endpoint Configfs Support" | ||
22 | depends on PCI_ENDPOINT | ||
23 | select CONFIGFS_FS | ||
24 | help | ||
25 | This will enable the configfs entry that can be used to | ||
26 | configure the endpoint function and used to bind the | ||
27 | function with a endpoint controller. | ||
28 | |||
29 | source "drivers/pci/endpoint/functions/Kconfig" | ||
30 | |||
31 | endmenu | ||
diff --git a/drivers/pci/endpoint/Makefile b/drivers/pci/endpoint/Makefile new file mode 100644 index 000000000000..1041f80a4645 --- /dev/null +++ b/drivers/pci/endpoint/Makefile | |||
@@ -0,0 +1,7 @@ | |||
1 | # | ||
2 | # Makefile for PCI Endpoint Support | ||
3 | # | ||
4 | |||
5 | obj-$(CONFIG_PCI_ENDPOINT_CONFIGFS) += pci-ep-cfs.o | ||
6 | obj-$(CONFIG_PCI_ENDPOINT) += pci-epc-core.o pci-epf-core.o\ | ||
7 | pci-epc-mem.o functions/ | ||
diff --git a/drivers/pci/endpoint/functions/Kconfig b/drivers/pci/endpoint/functions/Kconfig new file mode 100644 index 000000000000..175edad42d2f --- /dev/null +++ b/drivers/pci/endpoint/functions/Kconfig | |||
@@ -0,0 +1,12 @@ | |||
1 | # | ||
2 | # PCI Endpoint Functions | ||
3 | # | ||
4 | |||
5 | config PCI_EPF_TEST | ||
6 | tristate "PCI Endpoint Test driver" | ||
7 | depends on PCI_ENDPOINT | ||
8 | help | ||
9 | Enable this configuration option to enable the test driver | ||
10 | for PCI Endpoint. | ||
11 | |||
12 | If in doubt, say "N" to disable Endpoint test driver. | ||
diff --git a/drivers/pci/endpoint/functions/Makefile b/drivers/pci/endpoint/functions/Makefile new file mode 100644 index 000000000000..6d94a4801838 --- /dev/null +++ b/drivers/pci/endpoint/functions/Makefile | |||
@@ -0,0 +1,5 @@ | |||
1 | # | ||
2 | # Makefile for PCI Endpoint Functions | ||
3 | # | ||
4 | |||
5 | obj-$(CONFIG_PCI_EPF_TEST) += pci-epf-test.o | ||
diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c new file mode 100644 index 000000000000..53fff8030337 --- /dev/null +++ b/drivers/pci/endpoint/functions/pci-epf-test.c | |||
@@ -0,0 +1,510 @@ | |||
1 | /** | ||
2 | * Test driver to test endpoint functionality | ||
3 | * | ||
4 | * Copyright (C) 2017 Texas Instruments | ||
5 | * Author: Kishon Vijay Abraham I <kishon@ti.com> | ||
6 | * | ||
7 | * This program is free software: you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 of | ||
9 | * the License as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
18 | */ | ||
19 | |||
20 | #include <linux/crc32.h> | ||
21 | #include <linux/delay.h> | ||
22 | #include <linux/io.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include <linux/pci_ids.h> | ||
26 | #include <linux/random.h> | ||
27 | |||
28 | #include <linux/pci-epc.h> | ||
29 | #include <linux/pci-epf.h> | ||
30 | #include <linux/pci_regs.h> | ||
31 | |||
32 | #define COMMAND_RAISE_LEGACY_IRQ BIT(0) | ||
33 | #define COMMAND_RAISE_MSI_IRQ BIT(1) | ||
34 | #define MSI_NUMBER_SHIFT 2 | ||
35 | #define MSI_NUMBER_MASK (0x3f << MSI_NUMBER_SHIFT) | ||
36 | #define COMMAND_READ BIT(8) | ||
37 | #define COMMAND_WRITE BIT(9) | ||
38 | #define COMMAND_COPY BIT(10) | ||
39 | |||
40 | #define STATUS_READ_SUCCESS BIT(0) | ||
41 | #define STATUS_READ_FAIL BIT(1) | ||
42 | #define STATUS_WRITE_SUCCESS BIT(2) | ||
43 | #define STATUS_WRITE_FAIL BIT(3) | ||
44 | #define STATUS_COPY_SUCCESS BIT(4) | ||
45 | #define STATUS_COPY_FAIL BIT(5) | ||
46 | #define STATUS_IRQ_RAISED BIT(6) | ||
47 | #define STATUS_SRC_ADDR_INVALID BIT(7) | ||
48 | #define STATUS_DST_ADDR_INVALID BIT(8) | ||
49 | |||
50 | #define TIMER_RESOLUTION 1 | ||
51 | |||
52 | static struct workqueue_struct *kpcitest_workqueue; | ||
53 | |||
54 | struct pci_epf_test { | ||
55 | void *reg[6]; | ||
56 | struct pci_epf *epf; | ||
57 | struct delayed_work cmd_handler; | ||
58 | }; | ||
59 | |||
60 | struct pci_epf_test_reg { | ||
61 | u32 magic; | ||
62 | u32 command; | ||
63 | u32 status; | ||
64 | u64 src_addr; | ||
65 | u64 dst_addr; | ||
66 | u32 size; | ||
67 | u32 checksum; | ||
68 | } __packed; | ||
69 | |||
70 | static struct pci_epf_header test_header = { | ||
71 | .vendorid = PCI_ANY_ID, | ||
72 | .deviceid = PCI_ANY_ID, | ||
73 | .baseclass_code = PCI_CLASS_OTHERS, | ||
74 | .interrupt_pin = PCI_INTERRUPT_INTA, | ||
75 | }; | ||
76 | |||
77 | static int bar_size[] = { 512, 1024, 16384, 131072, 1048576 }; | ||
78 | |||
79 | static int pci_epf_test_copy(struct pci_epf_test *epf_test) | ||
80 | { | ||
81 | int ret; | ||
82 | void __iomem *src_addr; | ||
83 | void __iomem *dst_addr; | ||
84 | phys_addr_t src_phys_addr; | ||
85 | phys_addr_t dst_phys_addr; | ||
86 | struct pci_epf *epf = epf_test->epf; | ||
87 | struct device *dev = &epf->dev; | ||
88 | struct pci_epc *epc = epf->epc; | ||
89 | struct pci_epf_test_reg *reg = epf_test->reg[0]; | ||
90 | |||
91 | src_addr = pci_epc_mem_alloc_addr(epc, &src_phys_addr, reg->size); | ||
92 | if (!src_addr) { | ||
93 | dev_err(dev, "failed to allocate source address\n"); | ||
94 | reg->status = STATUS_SRC_ADDR_INVALID; | ||
95 | ret = -ENOMEM; | ||
96 | goto err; | ||
97 | } | ||
98 | |||
99 | ret = pci_epc_map_addr(epc, src_phys_addr, reg->src_addr, reg->size); | ||
100 | if (ret) { | ||
101 | dev_err(dev, "failed to map source address\n"); | ||
102 | reg->status = STATUS_SRC_ADDR_INVALID; | ||
103 | goto err_src_addr; | ||
104 | } | ||
105 | |||
106 | dst_addr = pci_epc_mem_alloc_addr(epc, &dst_phys_addr, reg->size); | ||
107 | if (!dst_addr) { | ||
108 | dev_err(dev, "failed to allocate destination address\n"); | ||
109 | reg->status = STATUS_DST_ADDR_INVALID; | ||
110 | ret = -ENOMEM; | ||
111 | goto err_src_map_addr; | ||
112 | } | ||
113 | |||
114 | ret = pci_epc_map_addr(epc, dst_phys_addr, reg->dst_addr, reg->size); | ||
115 | if (ret) { | ||
116 | dev_err(dev, "failed to map destination address\n"); | ||
117 | reg->status = STATUS_DST_ADDR_INVALID; | ||
118 | goto err_dst_addr; | ||
119 | } | ||
120 | |||
121 | memcpy(dst_addr, src_addr, reg->size); | ||
122 | |||
123 | pci_epc_unmap_addr(epc, dst_phys_addr); | ||
124 | |||
125 | err_dst_addr: | ||
126 | pci_epc_mem_free_addr(epc, dst_phys_addr, dst_addr, reg->size); | ||
127 | |||
128 | err_src_map_addr: | ||
129 | pci_epc_unmap_addr(epc, src_phys_addr); | ||
130 | |||
131 | err_src_addr: | ||
132 | pci_epc_mem_free_addr(epc, src_phys_addr, src_addr, reg->size); | ||
133 | |||
134 | err: | ||
135 | return ret; | ||
136 | } | ||
137 | |||
138 | static int pci_epf_test_read(struct pci_epf_test *epf_test) | ||
139 | { | ||
140 | int ret; | ||
141 | void __iomem *src_addr; | ||
142 | void *buf; | ||
143 | u32 crc32; | ||
144 | phys_addr_t phys_addr; | ||
145 | struct pci_epf *epf = epf_test->epf; | ||
146 | struct device *dev = &epf->dev; | ||
147 | struct pci_epc *epc = epf->epc; | ||
148 | struct pci_epf_test_reg *reg = epf_test->reg[0]; | ||
149 | |||
150 | src_addr = pci_epc_mem_alloc_addr(epc, &phys_addr, reg->size); | ||
151 | if (!src_addr) { | ||
152 | dev_err(dev, "failed to allocate address\n"); | ||
153 | reg->status = STATUS_SRC_ADDR_INVALID; | ||
154 | ret = -ENOMEM; | ||
155 | goto err; | ||
156 | } | ||
157 | |||
158 | ret = pci_epc_map_addr(epc, phys_addr, reg->src_addr, reg->size); | ||
159 | if (ret) { | ||
160 | dev_err(dev, "failed to map address\n"); | ||
161 | reg->status = STATUS_SRC_ADDR_INVALID; | ||
162 | goto err_addr; | ||
163 | } | ||
164 | |||
165 | buf = kzalloc(reg->size, GFP_KERNEL); | ||
166 | if (!buf) { | ||
167 | ret = -ENOMEM; | ||
168 | goto err_map_addr; | ||
169 | } | ||
170 | |||
171 | memcpy(buf, src_addr, reg->size); | ||
172 | |||
173 | crc32 = crc32_le(~0, buf, reg->size); | ||
174 | if (crc32 != reg->checksum) | ||
175 | ret = -EIO; | ||
176 | |||
177 | kfree(buf); | ||
178 | |||
179 | err_map_addr: | ||
180 | pci_epc_unmap_addr(epc, phys_addr); | ||
181 | |||
182 | err_addr: | ||
183 | pci_epc_mem_free_addr(epc, phys_addr, src_addr, reg->size); | ||
184 | |||
185 | err: | ||
186 | return ret; | ||
187 | } | ||
188 | |||
189 | static int pci_epf_test_write(struct pci_epf_test *epf_test) | ||
190 | { | ||
191 | int ret; | ||
192 | void __iomem *dst_addr; | ||
193 | void *buf; | ||
194 | phys_addr_t phys_addr; | ||
195 | struct pci_epf *epf = epf_test->epf; | ||
196 | struct device *dev = &epf->dev; | ||
197 | struct pci_epc *epc = epf->epc; | ||
198 | struct pci_epf_test_reg *reg = epf_test->reg[0]; | ||
199 | |||
200 | dst_addr = pci_epc_mem_alloc_addr(epc, &phys_addr, reg->size); | ||
201 | if (!dst_addr) { | ||
202 | dev_err(dev, "failed to allocate address\n"); | ||
203 | reg->status = STATUS_DST_ADDR_INVALID; | ||
204 | ret = -ENOMEM; | ||
205 | goto err; | ||
206 | } | ||
207 | |||
208 | ret = pci_epc_map_addr(epc, phys_addr, reg->dst_addr, reg->size); | ||
209 | if (ret) { | ||
210 | dev_err(dev, "failed to map address\n"); | ||
211 | reg->status = STATUS_DST_ADDR_INVALID; | ||
212 | goto err_addr; | ||
213 | } | ||
214 | |||
215 | buf = kzalloc(reg->size, GFP_KERNEL); | ||
216 | if (!buf) { | ||
217 | ret = -ENOMEM; | ||
218 | goto err_map_addr; | ||
219 | } | ||
220 | |||
221 | get_random_bytes(buf, reg->size); | ||
222 | reg->checksum = crc32_le(~0, buf, reg->size); | ||
223 | |||
224 | memcpy(dst_addr, buf, reg->size); | ||
225 | |||
226 | /* | ||
227 | * wait 1ms inorder for the write to complete. Without this delay L3 | ||
228 | * error in observed in the host system. | ||
229 | */ | ||
230 | mdelay(1); | ||
231 | |||
232 | kfree(buf); | ||
233 | |||
234 | err_map_addr: | ||
235 | pci_epc_unmap_addr(epc, phys_addr); | ||
236 | |||
237 | err_addr: | ||
238 | pci_epc_mem_free_addr(epc, phys_addr, dst_addr, reg->size); | ||
239 | |||
240 | err: | ||
241 | return ret; | ||
242 | } | ||
243 | |||
244 | static void pci_epf_test_raise_irq(struct pci_epf_test *epf_test) | ||
245 | { | ||
246 | u8 irq; | ||
247 | u8 msi_count; | ||
248 | struct pci_epf *epf = epf_test->epf; | ||
249 | struct pci_epc *epc = epf->epc; | ||
250 | struct pci_epf_test_reg *reg = epf_test->reg[0]; | ||
251 | |||
252 | reg->status |= STATUS_IRQ_RAISED; | ||
253 | msi_count = pci_epc_get_msi(epc); | ||
254 | irq = (reg->command & MSI_NUMBER_MASK) >> MSI_NUMBER_SHIFT; | ||
255 | if (irq > msi_count || msi_count <= 0) | ||
256 | pci_epc_raise_irq(epc, PCI_EPC_IRQ_LEGACY, 0); | ||
257 | else | ||
258 | pci_epc_raise_irq(epc, PCI_EPC_IRQ_MSI, irq); | ||
259 | } | ||
260 | |||
261 | static void pci_epf_test_cmd_handler(struct work_struct *work) | ||
262 | { | ||
263 | int ret; | ||
264 | u8 irq; | ||
265 | u8 msi_count; | ||
266 | struct pci_epf_test *epf_test = container_of(work, struct pci_epf_test, | ||
267 | cmd_handler.work); | ||
268 | struct pci_epf *epf = epf_test->epf; | ||
269 | struct pci_epc *epc = epf->epc; | ||
270 | struct pci_epf_test_reg *reg = epf_test->reg[0]; | ||
271 | |||
272 | if (!reg->command) | ||
273 | goto reset_handler; | ||
274 | |||
275 | if (reg->command & COMMAND_RAISE_LEGACY_IRQ) { | ||
276 | reg->status = STATUS_IRQ_RAISED; | ||
277 | pci_epc_raise_irq(epc, PCI_EPC_IRQ_LEGACY, 0); | ||
278 | goto reset_handler; | ||
279 | } | ||
280 | |||
281 | if (reg->command & COMMAND_WRITE) { | ||
282 | ret = pci_epf_test_write(epf_test); | ||
283 | if (ret) | ||
284 | reg->status |= STATUS_WRITE_FAIL; | ||
285 | else | ||
286 | reg->status |= STATUS_WRITE_SUCCESS; | ||
287 | pci_epf_test_raise_irq(epf_test); | ||
288 | goto reset_handler; | ||
289 | } | ||
290 | |||
291 | if (reg->command & COMMAND_READ) { | ||
292 | ret = pci_epf_test_read(epf_test); | ||
293 | if (!ret) | ||
294 | reg->status |= STATUS_READ_SUCCESS; | ||
295 | else | ||
296 | reg->status |= STATUS_READ_FAIL; | ||
297 | pci_epf_test_raise_irq(epf_test); | ||
298 | goto reset_handler; | ||
299 | } | ||
300 | |||
301 | if (reg->command & COMMAND_COPY) { | ||
302 | ret = pci_epf_test_copy(epf_test); | ||
303 | if (!ret) | ||
304 | reg->status |= STATUS_COPY_SUCCESS; | ||
305 | else | ||
306 | reg->status |= STATUS_COPY_FAIL; | ||
307 | pci_epf_test_raise_irq(epf_test); | ||
308 | goto reset_handler; | ||
309 | } | ||
310 | |||
311 | if (reg->command & COMMAND_RAISE_MSI_IRQ) { | ||
312 | msi_count = pci_epc_get_msi(epc); | ||
313 | irq = (reg->command & MSI_NUMBER_MASK) >> MSI_NUMBER_SHIFT; | ||
314 | if (irq > msi_count || msi_count <= 0) | ||
315 | goto reset_handler; | ||
316 | reg->status = STATUS_IRQ_RAISED; | ||
317 | pci_epc_raise_irq(epc, PCI_EPC_IRQ_MSI, irq); | ||
318 | goto reset_handler; | ||
319 | } | ||
320 | |||
321 | reset_handler: | ||
322 | reg->command = 0; | ||
323 | |||
324 | queue_delayed_work(kpcitest_workqueue, &epf_test->cmd_handler, | ||
325 | msecs_to_jiffies(1)); | ||
326 | } | ||
327 | |||
328 | static void pci_epf_test_linkup(struct pci_epf *epf) | ||
329 | { | ||
330 | struct pci_epf_test *epf_test = epf_get_drvdata(epf); | ||
331 | |||
332 | queue_delayed_work(kpcitest_workqueue, &epf_test->cmd_handler, | ||
333 | msecs_to_jiffies(1)); | ||
334 | } | ||
335 | |||
336 | static void pci_epf_test_unbind(struct pci_epf *epf) | ||
337 | { | ||
338 | struct pci_epf_test *epf_test = epf_get_drvdata(epf); | ||
339 | struct pci_epc *epc = epf->epc; | ||
340 | int bar; | ||
341 | |||
342 | cancel_delayed_work(&epf_test->cmd_handler); | ||
343 | pci_epc_stop(epc); | ||
344 | for (bar = BAR_0; bar <= BAR_5; bar++) { | ||
345 | if (epf_test->reg[bar]) { | ||
346 | pci_epf_free_space(epf, epf_test->reg[bar], bar); | ||
347 | pci_epc_clear_bar(epc, bar); | ||
348 | } | ||
349 | } | ||
350 | } | ||
351 | |||
352 | static int pci_epf_test_set_bar(struct pci_epf *epf) | ||
353 | { | ||
354 | int flags; | ||
355 | int bar; | ||
356 | int ret; | ||
357 | struct pci_epf_bar *epf_bar; | ||
358 | struct pci_epc *epc = epf->epc; | ||
359 | struct device *dev = &epf->dev; | ||
360 | struct pci_epf_test *epf_test = epf_get_drvdata(epf); | ||
361 | |||
362 | flags = PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_32; | ||
363 | if (sizeof(dma_addr_t) == 0x8) | ||
364 | flags |= PCI_BASE_ADDRESS_MEM_TYPE_64; | ||
365 | |||
366 | for (bar = BAR_0; bar <= BAR_5; bar++) { | ||
367 | epf_bar = &epf->bar[bar]; | ||
368 | ret = pci_epc_set_bar(epc, bar, epf_bar->phys_addr, | ||
369 | epf_bar->size, flags); | ||
370 | if (ret) { | ||
371 | pci_epf_free_space(epf, epf_test->reg[bar], bar); | ||
372 | dev_err(dev, "failed to set BAR%d\n", bar); | ||
373 | if (bar == BAR_0) | ||
374 | return ret; | ||
375 | } | ||
376 | } | ||
377 | |||
378 | return 0; | ||
379 | } | ||
380 | |||
381 | static int pci_epf_test_alloc_space(struct pci_epf *epf) | ||
382 | { | ||
383 | struct pci_epf_test *epf_test = epf_get_drvdata(epf); | ||
384 | struct device *dev = &epf->dev; | ||
385 | void *base; | ||
386 | int bar; | ||
387 | |||
388 | base = pci_epf_alloc_space(epf, sizeof(struct pci_epf_test_reg), | ||
389 | BAR_0); | ||
390 | if (!base) { | ||
391 | dev_err(dev, "failed to allocated register space\n"); | ||
392 | return -ENOMEM; | ||
393 | } | ||
394 | epf_test->reg[0] = base; | ||
395 | |||
396 | for (bar = BAR_1; bar <= BAR_5; bar++) { | ||
397 | base = pci_epf_alloc_space(epf, bar_size[bar - 1], bar); | ||
398 | if (!base) | ||
399 | dev_err(dev, "failed to allocate space for BAR%d\n", | ||
400 | bar); | ||
401 | epf_test->reg[bar] = base; | ||
402 | } | ||
403 | |||
404 | return 0; | ||
405 | } | ||
406 | |||
407 | static int pci_epf_test_bind(struct pci_epf *epf) | ||
408 | { | ||
409 | int ret; | ||
410 | struct pci_epf_header *header = epf->header; | ||
411 | struct pci_epc *epc = epf->epc; | ||
412 | struct device *dev = &epf->dev; | ||
413 | |||
414 | if (WARN_ON_ONCE(!epc)) | ||
415 | return -EINVAL; | ||
416 | |||
417 | ret = pci_epc_write_header(epc, header); | ||
418 | if (ret) { | ||
419 | dev_err(dev, "configuration header write failed\n"); | ||
420 | return ret; | ||
421 | } | ||
422 | |||
423 | ret = pci_epf_test_alloc_space(epf); | ||
424 | if (ret) | ||
425 | return ret; | ||
426 | |||
427 | ret = pci_epf_test_set_bar(epf); | ||
428 | if (ret) | ||
429 | return ret; | ||
430 | |||
431 | ret = pci_epc_set_msi(epc, epf->msi_interrupts); | ||
432 | if (ret) | ||
433 | return ret; | ||
434 | |||
435 | return 0; | ||
436 | } | ||
437 | |||
438 | static int pci_epf_test_probe(struct pci_epf *epf) | ||
439 | { | ||
440 | struct pci_epf_test *epf_test; | ||
441 | struct device *dev = &epf->dev; | ||
442 | |||
443 | epf_test = devm_kzalloc(dev, sizeof(*epf_test), GFP_KERNEL); | ||
444 | if (!epf_test) | ||
445 | return -ENOMEM; | ||
446 | |||
447 | epf->header = &test_header; | ||
448 | epf_test->epf = epf; | ||
449 | |||
450 | INIT_DELAYED_WORK(&epf_test->cmd_handler, pci_epf_test_cmd_handler); | ||
451 | |||
452 | epf_set_drvdata(epf, epf_test); | ||
453 | return 0; | ||
454 | } | ||
455 | |||
456 | static int pci_epf_test_remove(struct pci_epf *epf) | ||
457 | { | ||
458 | struct pci_epf_test *epf_test = epf_get_drvdata(epf); | ||
459 | |||
460 | kfree(epf_test); | ||
461 | return 0; | ||
462 | } | ||
463 | |||
464 | static struct pci_epf_ops ops = { | ||
465 | .unbind = pci_epf_test_unbind, | ||
466 | .bind = pci_epf_test_bind, | ||
467 | .linkup = pci_epf_test_linkup, | ||
468 | }; | ||
469 | |||
470 | static const struct pci_epf_device_id pci_epf_test_ids[] = { | ||
471 | { | ||
472 | .name = "pci_epf_test", | ||
473 | }, | ||
474 | {}, | ||
475 | }; | ||
476 | |||
477 | static struct pci_epf_driver test_driver = { | ||
478 | .driver.name = "pci_epf_test", | ||
479 | .probe = pci_epf_test_probe, | ||
480 | .remove = pci_epf_test_remove, | ||
481 | .id_table = pci_epf_test_ids, | ||
482 | .ops = &ops, | ||
483 | .owner = THIS_MODULE, | ||
484 | }; | ||
485 | |||
486 | static int __init pci_epf_test_init(void) | ||
487 | { | ||
488 | int ret; | ||
489 | |||
490 | kpcitest_workqueue = alloc_workqueue("kpcitest", | ||
491 | WQ_MEM_RECLAIM | WQ_HIGHPRI, 0); | ||
492 | ret = pci_epf_register_driver(&test_driver); | ||
493 | if (ret) { | ||
494 | pr_err("failed to register pci epf test driver --> %d\n", ret); | ||
495 | return ret; | ||
496 | } | ||
497 | |||
498 | return 0; | ||
499 | } | ||
500 | module_init(pci_epf_test_init); | ||
501 | |||
502 | static void __exit pci_epf_test_exit(void) | ||
503 | { | ||
504 | pci_epf_unregister_driver(&test_driver); | ||
505 | } | ||
506 | module_exit(pci_epf_test_exit); | ||
507 | |||
508 | MODULE_DESCRIPTION("PCI EPF TEST DRIVER"); | ||
509 | MODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>"); | ||
510 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/pci/endpoint/pci-ep-cfs.c b/drivers/pci/endpoint/pci-ep-cfs.c new file mode 100644 index 000000000000..424fdd6ed1ca --- /dev/null +++ b/drivers/pci/endpoint/pci-ep-cfs.c | |||
@@ -0,0 +1,509 @@ | |||
1 | /** | ||
2 | * configfs to configure the PCI endpoint | ||
3 | * | ||
4 | * Copyright (C) 2017 Texas Instruments | ||
5 | * Author: Kishon Vijay Abraham I <kishon@ti.com> | ||
6 | * | ||
7 | * This program is free software: you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 of | ||
9 | * the License as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
18 | */ | ||
19 | |||
20 | #include <linux/module.h> | ||
21 | #include <linux/slab.h> | ||
22 | |||
23 | #include <linux/pci-epc.h> | ||
24 | #include <linux/pci-epf.h> | ||
25 | #include <linux/pci-ep-cfs.h> | ||
26 | |||
27 | static struct config_group *functions_group; | ||
28 | static struct config_group *controllers_group; | ||
29 | |||
30 | struct pci_epf_group { | ||
31 | struct config_group group; | ||
32 | struct pci_epf *epf; | ||
33 | }; | ||
34 | |||
35 | struct pci_epc_group { | ||
36 | struct config_group group; | ||
37 | struct pci_epc *epc; | ||
38 | bool start; | ||
39 | unsigned long function_num_map; | ||
40 | }; | ||
41 | |||
42 | static inline struct pci_epf_group *to_pci_epf_group(struct config_item *item) | ||
43 | { | ||
44 | return container_of(to_config_group(item), struct pci_epf_group, group); | ||
45 | } | ||
46 | |||
47 | static inline struct pci_epc_group *to_pci_epc_group(struct config_item *item) | ||
48 | { | ||
49 | return container_of(to_config_group(item), struct pci_epc_group, group); | ||
50 | } | ||
51 | |||
52 | static ssize_t pci_epc_start_store(struct config_item *item, const char *page, | ||
53 | size_t len) | ||
54 | { | ||
55 | int ret; | ||
56 | bool start; | ||
57 | struct pci_epc *epc; | ||
58 | struct pci_epc_group *epc_group = to_pci_epc_group(item); | ||
59 | |||
60 | epc = epc_group->epc; | ||
61 | |||
62 | ret = kstrtobool(page, &start); | ||
63 | if (ret) | ||
64 | return ret; | ||
65 | |||
66 | if (!start) { | ||
67 | pci_epc_stop(epc); | ||
68 | return len; | ||
69 | } | ||
70 | |||
71 | ret = pci_epc_start(epc); | ||
72 | if (ret) { | ||
73 | dev_err(&epc->dev, "failed to start endpoint controller\n"); | ||
74 | return -EINVAL; | ||
75 | } | ||
76 | |||
77 | epc_group->start = start; | ||
78 | |||
79 | return len; | ||
80 | } | ||
81 | |||
82 | static ssize_t pci_epc_start_show(struct config_item *item, char *page) | ||
83 | { | ||
84 | return sprintf(page, "%d\n", | ||
85 | to_pci_epc_group(item)->start); | ||
86 | } | ||
87 | |||
88 | CONFIGFS_ATTR(pci_epc_, start); | ||
89 | |||
90 | static struct configfs_attribute *pci_epc_attrs[] = { | ||
91 | &pci_epc_attr_start, | ||
92 | NULL, | ||
93 | }; | ||
94 | |||
95 | static int pci_epc_epf_link(struct config_item *epc_item, | ||
96 | struct config_item *epf_item) | ||
97 | { | ||
98 | int ret; | ||
99 | u32 func_no = 0; | ||
100 | struct pci_epc *epc; | ||
101 | struct pci_epf *epf; | ||
102 | struct pci_epf_group *epf_group = to_pci_epf_group(epf_item); | ||
103 | struct pci_epc_group *epc_group = to_pci_epc_group(epc_item); | ||
104 | |||
105 | epc = epc_group->epc; | ||
106 | epf = epf_group->epf; | ||
107 | ret = pci_epc_add_epf(epc, epf); | ||
108 | if (ret) | ||
109 | goto err_add_epf; | ||
110 | |||
111 | func_no = find_first_zero_bit(&epc_group->function_num_map, | ||
112 | sizeof(epc_group->function_num_map)); | ||
113 | set_bit(func_no, &epc_group->function_num_map); | ||
114 | epf->func_no = func_no; | ||
115 | |||
116 | ret = pci_epf_bind(epf); | ||
117 | if (ret) | ||
118 | goto err_epf_bind; | ||
119 | |||
120 | return 0; | ||
121 | |||
122 | err_epf_bind: | ||
123 | pci_epc_remove_epf(epc, epf); | ||
124 | |||
125 | err_add_epf: | ||
126 | clear_bit(func_no, &epc_group->function_num_map); | ||
127 | |||
128 | return ret; | ||
129 | } | ||
130 | |||
131 | static void pci_epc_epf_unlink(struct config_item *epc_item, | ||
132 | struct config_item *epf_item) | ||
133 | { | ||
134 | struct pci_epc *epc; | ||
135 | struct pci_epf *epf; | ||
136 | struct pci_epf_group *epf_group = to_pci_epf_group(epf_item); | ||
137 | struct pci_epc_group *epc_group = to_pci_epc_group(epc_item); | ||
138 | |||
139 | WARN_ON_ONCE(epc_group->start); | ||
140 | |||
141 | epc = epc_group->epc; | ||
142 | epf = epf_group->epf; | ||
143 | clear_bit(epf->func_no, &epc_group->function_num_map); | ||
144 | pci_epf_unbind(epf); | ||
145 | pci_epc_remove_epf(epc, epf); | ||
146 | } | ||
147 | |||
148 | static struct configfs_item_operations pci_epc_item_ops = { | ||
149 | .allow_link = pci_epc_epf_link, | ||
150 | .drop_link = pci_epc_epf_unlink, | ||
151 | }; | ||
152 | |||
153 | static struct config_item_type pci_epc_type = { | ||
154 | .ct_item_ops = &pci_epc_item_ops, | ||
155 | .ct_attrs = pci_epc_attrs, | ||
156 | .ct_owner = THIS_MODULE, | ||
157 | }; | ||
158 | |||
159 | struct config_group *pci_ep_cfs_add_epc_group(const char *name) | ||
160 | { | ||
161 | int ret; | ||
162 | struct pci_epc *epc; | ||
163 | struct config_group *group; | ||
164 | struct pci_epc_group *epc_group; | ||
165 | |||
166 | epc_group = kzalloc(sizeof(*epc_group), GFP_KERNEL); | ||
167 | if (!epc_group) { | ||
168 | ret = -ENOMEM; | ||
169 | goto err; | ||
170 | } | ||
171 | |||
172 | group = &epc_group->group; | ||
173 | |||
174 | config_group_init_type_name(group, name, &pci_epc_type); | ||
175 | ret = configfs_register_group(controllers_group, group); | ||
176 | if (ret) { | ||
177 | pr_err("failed to register configfs group for %s\n", name); | ||
178 | goto err_register_group; | ||
179 | } | ||
180 | |||
181 | epc = pci_epc_get(name); | ||
182 | if (IS_ERR(epc)) { | ||
183 | ret = PTR_ERR(epc); | ||
184 | goto err_epc_get; | ||
185 | } | ||
186 | |||
187 | epc_group->epc = epc; | ||
188 | |||
189 | return group; | ||
190 | |||
191 | err_epc_get: | ||
192 | configfs_unregister_group(group); | ||
193 | |||
194 | err_register_group: | ||
195 | kfree(epc_group); | ||
196 | |||
197 | err: | ||
198 | return ERR_PTR(ret); | ||
199 | } | ||
200 | EXPORT_SYMBOL(pci_ep_cfs_add_epc_group); | ||
201 | |||
202 | void pci_ep_cfs_remove_epc_group(struct config_group *group) | ||
203 | { | ||
204 | struct pci_epc_group *epc_group; | ||
205 | |||
206 | if (!group) | ||
207 | return; | ||
208 | |||
209 | epc_group = container_of(group, struct pci_epc_group, group); | ||
210 | pci_epc_put(epc_group->epc); | ||
211 | configfs_unregister_group(&epc_group->group); | ||
212 | kfree(epc_group); | ||
213 | } | ||
214 | EXPORT_SYMBOL(pci_ep_cfs_remove_epc_group); | ||
215 | |||
216 | #define PCI_EPF_HEADER_R(_name) \ | ||
217 | static ssize_t pci_epf_##_name##_show(struct config_item *item, char *page) \ | ||
218 | { \ | ||
219 | struct pci_epf *epf = to_pci_epf_group(item)->epf; \ | ||
220 | if (WARN_ON_ONCE(!epf->header)) \ | ||
221 | return -EINVAL; \ | ||
222 | return sprintf(page, "0x%04x\n", epf->header->_name); \ | ||
223 | } | ||
224 | |||
225 | #define PCI_EPF_HEADER_W_u32(_name) \ | ||
226 | static ssize_t pci_epf_##_name##_store(struct config_item *item, \ | ||
227 | const char *page, size_t len) \ | ||
228 | { \ | ||
229 | u32 val; \ | ||
230 | int ret; \ | ||
231 | struct pci_epf *epf = to_pci_epf_group(item)->epf; \ | ||
232 | if (WARN_ON_ONCE(!epf->header)) \ | ||
233 | return -EINVAL; \ | ||
234 | ret = kstrtou32(page, 0, &val); \ | ||
235 | if (ret) \ | ||
236 | return ret; \ | ||
237 | epf->header->_name = val; \ | ||
238 | return len; \ | ||
239 | } | ||
240 | |||
241 | #define PCI_EPF_HEADER_W_u16(_name) \ | ||
242 | static ssize_t pci_epf_##_name##_store(struct config_item *item, \ | ||
243 | const char *page, size_t len) \ | ||
244 | { \ | ||
245 | u16 val; \ | ||
246 | int ret; \ | ||
247 | struct pci_epf *epf = to_pci_epf_group(item)->epf; \ | ||
248 | if (WARN_ON_ONCE(!epf->header)) \ | ||
249 | return -EINVAL; \ | ||
250 | ret = kstrtou16(page, 0, &val); \ | ||
251 | if (ret) \ | ||
252 | return ret; \ | ||
253 | epf->header->_name = val; \ | ||
254 | return len; \ | ||
255 | } | ||
256 | |||
257 | #define PCI_EPF_HEADER_W_u8(_name) \ | ||
258 | static ssize_t pci_epf_##_name##_store(struct config_item *item, \ | ||
259 | const char *page, size_t len) \ | ||
260 | { \ | ||
261 | u8 val; \ | ||
262 | int ret; \ | ||
263 | struct pci_epf *epf = to_pci_epf_group(item)->epf; \ | ||
264 | if (WARN_ON_ONCE(!epf->header)) \ | ||
265 | return -EINVAL; \ | ||
266 | ret = kstrtou8(page, 0, &val); \ | ||
267 | if (ret) \ | ||
268 | return ret; \ | ||
269 | epf->header->_name = val; \ | ||
270 | return len; \ | ||
271 | } | ||
272 | |||
273 | static ssize_t pci_epf_msi_interrupts_store(struct config_item *item, | ||
274 | const char *page, size_t len) | ||
275 | { | ||
276 | u8 val; | ||
277 | int ret; | ||
278 | |||
279 | ret = kstrtou8(page, 0, &val); | ||
280 | if (ret) | ||
281 | return ret; | ||
282 | |||
283 | to_pci_epf_group(item)->epf->msi_interrupts = val; | ||
284 | |||
285 | return len; | ||
286 | } | ||
287 | |||
288 | static ssize_t pci_epf_msi_interrupts_show(struct config_item *item, | ||
289 | char *page) | ||
290 | { | ||
291 | return sprintf(page, "%d\n", | ||
292 | to_pci_epf_group(item)->epf->msi_interrupts); | ||
293 | } | ||
294 | |||
295 | PCI_EPF_HEADER_R(vendorid) | ||
296 | PCI_EPF_HEADER_W_u16(vendorid) | ||
297 | |||
298 | PCI_EPF_HEADER_R(deviceid) | ||
299 | PCI_EPF_HEADER_W_u16(deviceid) | ||
300 | |||
301 | PCI_EPF_HEADER_R(revid) | ||
302 | PCI_EPF_HEADER_W_u8(revid) | ||
303 | |||
304 | PCI_EPF_HEADER_R(progif_code) | ||
305 | PCI_EPF_HEADER_W_u8(progif_code) | ||
306 | |||
307 | PCI_EPF_HEADER_R(subclass_code) | ||
308 | PCI_EPF_HEADER_W_u8(subclass_code) | ||
309 | |||
310 | PCI_EPF_HEADER_R(baseclass_code) | ||
311 | PCI_EPF_HEADER_W_u8(baseclass_code) | ||
312 | |||
313 | PCI_EPF_HEADER_R(cache_line_size) | ||
314 | PCI_EPF_HEADER_W_u8(cache_line_size) | ||
315 | |||
316 | PCI_EPF_HEADER_R(subsys_vendor_id) | ||
317 | PCI_EPF_HEADER_W_u16(subsys_vendor_id) | ||
318 | |||
319 | PCI_EPF_HEADER_R(subsys_id) | ||
320 | PCI_EPF_HEADER_W_u16(subsys_id) | ||
321 | |||
322 | PCI_EPF_HEADER_R(interrupt_pin) | ||
323 | PCI_EPF_HEADER_W_u8(interrupt_pin) | ||
324 | |||
325 | CONFIGFS_ATTR(pci_epf_, vendorid); | ||
326 | CONFIGFS_ATTR(pci_epf_, deviceid); | ||
327 | CONFIGFS_ATTR(pci_epf_, revid); | ||
328 | CONFIGFS_ATTR(pci_epf_, progif_code); | ||
329 | CONFIGFS_ATTR(pci_epf_, subclass_code); | ||
330 | CONFIGFS_ATTR(pci_epf_, baseclass_code); | ||
331 | CONFIGFS_ATTR(pci_epf_, cache_line_size); | ||
332 | CONFIGFS_ATTR(pci_epf_, subsys_vendor_id); | ||
333 | CONFIGFS_ATTR(pci_epf_, subsys_id); | ||
334 | CONFIGFS_ATTR(pci_epf_, interrupt_pin); | ||
335 | CONFIGFS_ATTR(pci_epf_, msi_interrupts); | ||
336 | |||
337 | static struct configfs_attribute *pci_epf_attrs[] = { | ||
338 | &pci_epf_attr_vendorid, | ||
339 | &pci_epf_attr_deviceid, | ||
340 | &pci_epf_attr_revid, | ||
341 | &pci_epf_attr_progif_code, | ||
342 | &pci_epf_attr_subclass_code, | ||
343 | &pci_epf_attr_baseclass_code, | ||
344 | &pci_epf_attr_cache_line_size, | ||
345 | &pci_epf_attr_subsys_vendor_id, | ||
346 | &pci_epf_attr_subsys_id, | ||
347 | &pci_epf_attr_interrupt_pin, | ||
348 | &pci_epf_attr_msi_interrupts, | ||
349 | NULL, | ||
350 | }; | ||
351 | |||
352 | static void pci_epf_release(struct config_item *item) | ||
353 | { | ||
354 | struct pci_epf_group *epf_group = to_pci_epf_group(item); | ||
355 | |||
356 | pci_epf_destroy(epf_group->epf); | ||
357 | kfree(epf_group); | ||
358 | } | ||
359 | |||
360 | static struct configfs_item_operations pci_epf_ops = { | ||
361 | .release = pci_epf_release, | ||
362 | }; | ||
363 | |||
364 | static struct config_item_type pci_epf_type = { | ||
365 | .ct_item_ops = &pci_epf_ops, | ||
366 | .ct_attrs = pci_epf_attrs, | ||
367 | .ct_owner = THIS_MODULE, | ||
368 | }; | ||
369 | |||
370 | static struct config_group *pci_epf_make(struct config_group *group, | ||
371 | const char *name) | ||
372 | { | ||
373 | struct pci_epf_group *epf_group; | ||
374 | struct pci_epf *epf; | ||
375 | |||
376 | epf_group = kzalloc(sizeof(*epf_group), GFP_KERNEL); | ||
377 | if (!epf_group) | ||
378 | return ERR_PTR(-ENOMEM); | ||
379 | |||
380 | config_group_init_type_name(&epf_group->group, name, &pci_epf_type); | ||
381 | |||
382 | epf = pci_epf_create(group->cg_item.ci_name); | ||
383 | if (IS_ERR(epf)) { | ||
384 | pr_err("failed to create endpoint function device\n"); | ||
385 | return ERR_PTR(-EINVAL); | ||
386 | } | ||
387 | |||
388 | epf_group->epf = epf; | ||
389 | |||
390 | return &epf_group->group; | ||
391 | } | ||
392 | |||
393 | static void pci_epf_drop(struct config_group *group, struct config_item *item) | ||
394 | { | ||
395 | config_item_put(item); | ||
396 | } | ||
397 | |||
398 | static struct configfs_group_operations pci_epf_group_ops = { | ||
399 | .make_group = &pci_epf_make, | ||
400 | .drop_item = &pci_epf_drop, | ||
401 | }; | ||
402 | |||
403 | static struct config_item_type pci_epf_group_type = { | ||
404 | .ct_group_ops = &pci_epf_group_ops, | ||
405 | .ct_owner = THIS_MODULE, | ||
406 | }; | ||
407 | |||
408 | struct config_group *pci_ep_cfs_add_epf_group(const char *name) | ||
409 | { | ||
410 | struct config_group *group; | ||
411 | |||
412 | group = configfs_register_default_group(functions_group, name, | ||
413 | &pci_epf_group_type); | ||
414 | if (IS_ERR(group)) | ||
415 | pr_err("failed to register configfs group for %s function\n", | ||
416 | name); | ||
417 | |||
418 | return group; | ||
419 | } | ||
420 | EXPORT_SYMBOL(pci_ep_cfs_add_epf_group); | ||
421 | |||
422 | void pci_ep_cfs_remove_epf_group(struct config_group *group) | ||
423 | { | ||
424 | if (IS_ERR_OR_NULL(group)) | ||
425 | return; | ||
426 | |||
427 | configfs_unregister_default_group(group); | ||
428 | } | ||
429 | EXPORT_SYMBOL(pci_ep_cfs_remove_epf_group); | ||
430 | |||
431 | static struct config_item_type pci_functions_type = { | ||
432 | .ct_owner = THIS_MODULE, | ||
433 | }; | ||
434 | |||
435 | static struct config_item_type pci_controllers_type = { | ||
436 | .ct_owner = THIS_MODULE, | ||
437 | }; | ||
438 | |||
439 | static struct config_item_type pci_ep_type = { | ||
440 | .ct_owner = THIS_MODULE, | ||
441 | }; | ||
442 | |||
443 | static struct configfs_subsystem pci_ep_cfs_subsys = { | ||
444 | .su_group = { | ||
445 | .cg_item = { | ||
446 | .ci_namebuf = "pci_ep", | ||
447 | .ci_type = &pci_ep_type, | ||
448 | }, | ||
449 | }, | ||
450 | .su_mutex = __MUTEX_INITIALIZER(pci_ep_cfs_subsys.su_mutex), | ||
451 | }; | ||
452 | |||
453 | static int __init pci_ep_cfs_init(void) | ||
454 | { | ||
455 | int ret; | ||
456 | struct config_group *root = &pci_ep_cfs_subsys.su_group; | ||
457 | |||
458 | config_group_init(root); | ||
459 | |||
460 | ret = configfs_register_subsystem(&pci_ep_cfs_subsys); | ||
461 | if (ret) { | ||
462 | pr_err("Error %d while registering subsystem %s\n", | ||
463 | ret, root->cg_item.ci_namebuf); | ||
464 | goto err; | ||
465 | } | ||
466 | |||
467 | functions_group = configfs_register_default_group(root, "functions", | ||
468 | &pci_functions_type); | ||
469 | if (IS_ERR(functions_group)) { | ||
470 | ret = PTR_ERR(functions_group); | ||
471 | pr_err("Error %d while registering functions group\n", | ||
472 | ret); | ||
473 | goto err_functions_group; | ||
474 | } | ||
475 | |||
476 | controllers_group = | ||
477 | configfs_register_default_group(root, "controllers", | ||
478 | &pci_controllers_type); | ||
479 | if (IS_ERR(controllers_group)) { | ||
480 | ret = PTR_ERR(controllers_group); | ||
481 | pr_err("Error %d while registering controllers group\n", | ||
482 | ret); | ||
483 | goto err_controllers_group; | ||
484 | } | ||
485 | |||
486 | return 0; | ||
487 | |||
488 | err_controllers_group: | ||
489 | configfs_unregister_default_group(functions_group); | ||
490 | |||
491 | err_functions_group: | ||
492 | configfs_unregister_subsystem(&pci_ep_cfs_subsys); | ||
493 | |||
494 | err: | ||
495 | return ret; | ||
496 | } | ||
497 | module_init(pci_ep_cfs_init); | ||
498 | |||
499 | static void __exit pci_ep_cfs_exit(void) | ||
500 | { | ||
501 | configfs_unregister_default_group(controllers_group); | ||
502 | configfs_unregister_default_group(functions_group); | ||
503 | configfs_unregister_subsystem(&pci_ep_cfs_subsys); | ||
504 | } | ||
505 | module_exit(pci_ep_cfs_exit); | ||
506 | |||
507 | MODULE_DESCRIPTION("PCI EP CONFIGFS"); | ||
508 | MODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>"); | ||
509 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/pci/endpoint/pci-epc-core.c b/drivers/pci/endpoint/pci-epc-core.c new file mode 100644 index 000000000000..caa7be10e473 --- /dev/null +++ b/drivers/pci/endpoint/pci-epc-core.c | |||
@@ -0,0 +1,580 @@ | |||
1 | /** | ||
2 | * PCI Endpoint *Controller* (EPC) library | ||
3 | * | ||
4 | * Copyright (C) 2017 Texas Instruments | ||
5 | * Author: Kishon Vijay Abraham I <kishon@ti.com> | ||
6 | * | ||
7 | * This program is free software: you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 of | ||
9 | * the License as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
18 | */ | ||
19 | |||
20 | #include <linux/device.h> | ||
21 | #include <linux/dma-mapping.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/module.h> | ||
24 | |||
25 | #include <linux/pci-epc.h> | ||
26 | #include <linux/pci-epf.h> | ||
27 | #include <linux/pci-ep-cfs.h> | ||
28 | |||
29 | static struct class *pci_epc_class; | ||
30 | |||
31 | static void devm_pci_epc_release(struct device *dev, void *res) | ||
32 | { | ||
33 | struct pci_epc *epc = *(struct pci_epc **)res; | ||
34 | |||
35 | pci_epc_destroy(epc); | ||
36 | } | ||
37 | |||
38 | static int devm_pci_epc_match(struct device *dev, void *res, void *match_data) | ||
39 | { | ||
40 | struct pci_epc **epc = res; | ||
41 | |||
42 | return *epc == match_data; | ||
43 | } | ||
44 | |||
45 | /** | ||
46 | * pci_epc_put() - release the PCI endpoint controller | ||
47 | * @epc: epc returned by pci_epc_get() | ||
48 | * | ||
49 | * release the refcount the caller obtained by invoking pci_epc_get() | ||
50 | */ | ||
51 | void pci_epc_put(struct pci_epc *epc) | ||
52 | { | ||
53 | if (!epc || IS_ERR(epc)) | ||
54 | return; | ||
55 | |||
56 | module_put(epc->ops->owner); | ||
57 | put_device(&epc->dev); | ||
58 | } | ||
59 | EXPORT_SYMBOL_GPL(pci_epc_put); | ||
60 | |||
61 | /** | ||
62 | * pci_epc_get() - get the PCI endpoint controller | ||
63 | * @epc_name: device name of the endpoint controller | ||
64 | * | ||
65 | * Invoke to get struct pci_epc * corresponding to the device name of the | ||
66 | * endpoint controller | ||
67 | */ | ||
68 | struct pci_epc *pci_epc_get(const char *epc_name) | ||
69 | { | ||
70 | int ret = -EINVAL; | ||
71 | struct pci_epc *epc; | ||
72 | struct device *dev; | ||
73 | struct class_dev_iter iter; | ||
74 | |||
75 | class_dev_iter_init(&iter, pci_epc_class, NULL, NULL); | ||
76 | while ((dev = class_dev_iter_next(&iter))) { | ||
77 | if (strcmp(epc_name, dev_name(dev))) | ||
78 | continue; | ||
79 | |||
80 | epc = to_pci_epc(dev); | ||
81 | if (!try_module_get(epc->ops->owner)) { | ||
82 | ret = -EINVAL; | ||
83 | goto err; | ||
84 | } | ||
85 | |||
86 | class_dev_iter_exit(&iter); | ||
87 | get_device(&epc->dev); | ||
88 | return epc; | ||
89 | } | ||
90 | |||
91 | err: | ||
92 | class_dev_iter_exit(&iter); | ||
93 | return ERR_PTR(ret); | ||
94 | } | ||
95 | EXPORT_SYMBOL_GPL(pci_epc_get); | ||
96 | |||
97 | /** | ||
98 | * pci_epc_stop() - stop the PCI link | ||
99 | * @epc: the link of the EPC device that has to be stopped | ||
100 | * | ||
101 | * Invoke to stop the PCI link | ||
102 | */ | ||
103 | void pci_epc_stop(struct pci_epc *epc) | ||
104 | { | ||
105 | unsigned long flags; | ||
106 | |||
107 | if (IS_ERR(epc) || !epc->ops->stop) | ||
108 | return; | ||
109 | |||
110 | spin_lock_irqsave(&epc->lock, flags); | ||
111 | epc->ops->stop(epc); | ||
112 | spin_unlock_irqrestore(&epc->lock, flags); | ||
113 | } | ||
114 | EXPORT_SYMBOL_GPL(pci_epc_stop); | ||
115 | |||
116 | /** | ||
117 | * pci_epc_start() - start the PCI link | ||
118 | * @epc: the link of *this* EPC device has to be started | ||
119 | * | ||
120 | * Invoke to start the PCI link | ||
121 | */ | ||
122 | int pci_epc_start(struct pci_epc *epc) | ||
123 | { | ||
124 | int ret; | ||
125 | unsigned long flags; | ||
126 | |||
127 | if (IS_ERR(epc)) | ||
128 | return -EINVAL; | ||
129 | |||
130 | if (!epc->ops->start) | ||
131 | return 0; | ||
132 | |||
133 | spin_lock_irqsave(&epc->lock, flags); | ||
134 | ret = epc->ops->start(epc); | ||
135 | spin_unlock_irqrestore(&epc->lock, flags); | ||
136 | |||
137 | return ret; | ||
138 | } | ||
139 | EXPORT_SYMBOL_GPL(pci_epc_start); | ||
140 | |||
141 | /** | ||
142 | * pci_epc_raise_irq() - interrupt the host system | ||
143 | * @epc: the EPC device which has to interrupt the host | ||
144 | * @type: specify the type of interrupt; legacy or MSI | ||
145 | * @interrupt_num: the MSI interrupt number | ||
146 | * | ||
147 | * Invoke to raise an MSI or legacy interrupt | ||
148 | */ | ||
149 | int pci_epc_raise_irq(struct pci_epc *epc, enum pci_epc_irq_type type, | ||
150 | u8 interrupt_num) | ||
151 | { | ||
152 | int ret; | ||
153 | unsigned long flags; | ||
154 | |||
155 | if (IS_ERR(epc)) | ||
156 | return -EINVAL; | ||
157 | |||
158 | if (!epc->ops->raise_irq) | ||
159 | return 0; | ||
160 | |||
161 | spin_lock_irqsave(&epc->lock, flags); | ||
162 | ret = epc->ops->raise_irq(epc, type, interrupt_num); | ||
163 | spin_unlock_irqrestore(&epc->lock, flags); | ||
164 | |||
165 | return ret; | ||
166 | } | ||
167 | EXPORT_SYMBOL_GPL(pci_epc_raise_irq); | ||
168 | |||
169 | /** | ||
170 | * pci_epc_get_msi() - get the number of MSI interrupt numbers allocated | ||
171 | * @epc: the EPC device to which MSI interrupts was requested | ||
172 | * | ||
173 | * Invoke to get the number of MSI interrupts allocated by the RC | ||
174 | */ | ||
175 | int pci_epc_get_msi(struct pci_epc *epc) | ||
176 | { | ||
177 | int interrupt; | ||
178 | unsigned long flags; | ||
179 | |||
180 | if (IS_ERR(epc)) | ||
181 | return 0; | ||
182 | |||
183 | if (!epc->ops->get_msi) | ||
184 | return 0; | ||
185 | |||
186 | spin_lock_irqsave(&epc->lock, flags); | ||
187 | interrupt = epc->ops->get_msi(epc); | ||
188 | spin_unlock_irqrestore(&epc->lock, flags); | ||
189 | |||
190 | if (interrupt < 0) | ||
191 | return 0; | ||
192 | |||
193 | interrupt = 1 << interrupt; | ||
194 | |||
195 | return interrupt; | ||
196 | } | ||
197 | EXPORT_SYMBOL_GPL(pci_epc_get_msi); | ||
198 | |||
199 | /** | ||
200 | * pci_epc_set_msi() - set the number of MSI interrupt numbers required | ||
201 | * @epc: the EPC device on which MSI has to be configured | ||
202 | * @interrupts: number of MSI interrupts required by the EPF | ||
203 | * | ||
204 | * Invoke to set the required number of MSI interrupts. | ||
205 | */ | ||
206 | int pci_epc_set_msi(struct pci_epc *epc, u8 interrupts) | ||
207 | { | ||
208 | int ret; | ||
209 | u8 encode_int; | ||
210 | unsigned long flags; | ||
211 | |||
212 | if (IS_ERR(epc)) | ||
213 | return -EINVAL; | ||
214 | |||
215 | if (!epc->ops->set_msi) | ||
216 | return 0; | ||
217 | |||
218 | encode_int = order_base_2(interrupts); | ||
219 | |||
220 | spin_lock_irqsave(&epc->lock, flags); | ||
221 | ret = epc->ops->set_msi(epc, encode_int); | ||
222 | spin_unlock_irqrestore(&epc->lock, flags); | ||
223 | |||
224 | return ret; | ||
225 | } | ||
226 | EXPORT_SYMBOL_GPL(pci_epc_set_msi); | ||
227 | |||
228 | /** | ||
229 | * pci_epc_unmap_addr() - unmap CPU address from PCI address | ||
230 | * @epc: the EPC device on which address is allocated | ||
231 | * @phys_addr: physical address of the local system | ||
232 | * | ||
233 | * Invoke to unmap the CPU address from PCI address. | ||
234 | */ | ||
235 | void pci_epc_unmap_addr(struct pci_epc *epc, phys_addr_t phys_addr) | ||
236 | { | ||
237 | unsigned long flags; | ||
238 | |||
239 | if (IS_ERR(epc)) | ||
240 | return; | ||
241 | |||
242 | if (!epc->ops->unmap_addr) | ||
243 | return; | ||
244 | |||
245 | spin_lock_irqsave(&epc->lock, flags); | ||
246 | epc->ops->unmap_addr(epc, phys_addr); | ||
247 | spin_unlock_irqrestore(&epc->lock, flags); | ||
248 | } | ||
249 | EXPORT_SYMBOL_GPL(pci_epc_unmap_addr); | ||
250 | |||
251 | /** | ||
252 | * pci_epc_map_addr() - map CPU address to PCI address | ||
253 | * @epc: the EPC device on which address is allocated | ||
254 | * @phys_addr: physical address of the local system | ||
255 | * @pci_addr: PCI address to which the physical address should be mapped | ||
256 | * @size: the size of the allocation | ||
257 | * | ||
258 | * Invoke to map CPU address with PCI address. | ||
259 | */ | ||
260 | int pci_epc_map_addr(struct pci_epc *epc, phys_addr_t phys_addr, | ||
261 | u64 pci_addr, size_t size) | ||
262 | { | ||
263 | int ret; | ||
264 | unsigned long flags; | ||
265 | |||
266 | if (IS_ERR(epc)) | ||
267 | return -EINVAL; | ||
268 | |||
269 | if (!epc->ops->map_addr) | ||
270 | return 0; | ||
271 | |||
272 | spin_lock_irqsave(&epc->lock, flags); | ||
273 | ret = epc->ops->map_addr(epc, phys_addr, pci_addr, size); | ||
274 | spin_unlock_irqrestore(&epc->lock, flags); | ||
275 | |||
276 | return ret; | ||
277 | } | ||
278 | EXPORT_SYMBOL_GPL(pci_epc_map_addr); | ||
279 | |||
280 | /** | ||
281 | * pci_epc_clear_bar() - reset the BAR | ||
282 | * @epc: the EPC device for which the BAR has to be cleared | ||
283 | * @bar: the BAR number that has to be reset | ||
284 | * | ||
285 | * Invoke to reset the BAR of the endpoint device. | ||
286 | */ | ||
287 | void pci_epc_clear_bar(struct pci_epc *epc, int bar) | ||
288 | { | ||
289 | unsigned long flags; | ||
290 | |||
291 | if (IS_ERR(epc)) | ||
292 | return; | ||
293 | |||
294 | if (!epc->ops->clear_bar) | ||
295 | return; | ||
296 | |||
297 | spin_lock_irqsave(&epc->lock, flags); | ||
298 | epc->ops->clear_bar(epc, bar); | ||
299 | spin_unlock_irqrestore(&epc->lock, flags); | ||
300 | } | ||
301 | EXPORT_SYMBOL_GPL(pci_epc_clear_bar); | ||
302 | |||
303 | /** | ||
304 | * pci_epc_set_bar() - configure BAR in order for host to assign PCI addr space | ||
305 | * @epc: the EPC device on which BAR has to be configured | ||
306 | * @bar: the BAR number that has to be configured | ||
307 | * @size: the size of the addr space | ||
308 | * @flags: specify memory allocation/io allocation/32bit address/64 bit address | ||
309 | * | ||
310 | * Invoke to configure the BAR of the endpoint device. | ||
311 | */ | ||
312 | int pci_epc_set_bar(struct pci_epc *epc, enum pci_barno bar, | ||
313 | dma_addr_t bar_phys, size_t size, int flags) | ||
314 | { | ||
315 | int ret; | ||
316 | unsigned long irq_flags; | ||
317 | |||
318 | if (IS_ERR(epc)) | ||
319 | return -EINVAL; | ||
320 | |||
321 | if (!epc->ops->set_bar) | ||
322 | return 0; | ||
323 | |||
324 | spin_lock_irqsave(&epc->lock, irq_flags); | ||
325 | ret = epc->ops->set_bar(epc, bar, bar_phys, size, flags); | ||
326 | spin_unlock_irqrestore(&epc->lock, irq_flags); | ||
327 | |||
328 | return ret; | ||
329 | } | ||
330 | EXPORT_SYMBOL_GPL(pci_epc_set_bar); | ||
331 | |||
332 | /** | ||
333 | * pci_epc_write_header() - write standard configuration header | ||
334 | * @epc: the EPC device to which the configuration header should be written | ||
335 | * @header: standard configuration header fields | ||
336 | * | ||
337 | * Invoke to write the configuration header to the endpoint controller. Every | ||
338 | * endpoint controller will have a dedicated location to which the standard | ||
339 | * configuration header would be written. The callback function should write | ||
340 | * the header fields to this dedicated location. | ||
341 | */ | ||
342 | int pci_epc_write_header(struct pci_epc *epc, struct pci_epf_header *header) | ||
343 | { | ||
344 | int ret; | ||
345 | unsigned long flags; | ||
346 | |||
347 | if (IS_ERR(epc)) | ||
348 | return -EINVAL; | ||
349 | |||
350 | if (!epc->ops->write_header) | ||
351 | return 0; | ||
352 | |||
353 | spin_lock_irqsave(&epc->lock, flags); | ||
354 | ret = epc->ops->write_header(epc, header); | ||
355 | spin_unlock_irqrestore(&epc->lock, flags); | ||
356 | |||
357 | return ret; | ||
358 | } | ||
359 | EXPORT_SYMBOL_GPL(pci_epc_write_header); | ||
360 | |||
361 | /** | ||
362 | * pci_epc_add_epf() - bind PCI endpoint function to an endpoint controller | ||
363 | * @epc: the EPC device to which the endpoint function should be added | ||
364 | * @epf: the endpoint function to be added | ||
365 | * | ||
366 | * A PCI endpoint device can have one or more functions. In the case of PCIe, | ||
367 | * the specification allows up to 8 PCIe endpoint functions. Invoke | ||
368 | * pci_epc_add_epf() to add a PCI endpoint function to an endpoint controller. | ||
369 | */ | ||
370 | int pci_epc_add_epf(struct pci_epc *epc, struct pci_epf *epf) | ||
371 | { | ||
372 | unsigned long flags; | ||
373 | |||
374 | if (epf->epc) | ||
375 | return -EBUSY; | ||
376 | |||
377 | if (IS_ERR(epc)) | ||
378 | return -EINVAL; | ||
379 | |||
380 | if (epf->func_no > epc->max_functions - 1) | ||
381 | return -EINVAL; | ||
382 | |||
383 | epf->epc = epc; | ||
384 | dma_set_coherent_mask(&epf->dev, epc->dev.coherent_dma_mask); | ||
385 | epf->dev.dma_mask = epc->dev.dma_mask; | ||
386 | |||
387 | spin_lock_irqsave(&epc->lock, flags); | ||
388 | list_add_tail(&epf->list, &epc->pci_epf); | ||
389 | spin_unlock_irqrestore(&epc->lock, flags); | ||
390 | |||
391 | return 0; | ||
392 | } | ||
393 | EXPORT_SYMBOL_GPL(pci_epc_add_epf); | ||
394 | |||
395 | /** | ||
396 | * pci_epc_remove_epf() - remove PCI endpoint function from endpoint controller | ||
397 | * @epc: the EPC device from which the endpoint function should be removed | ||
398 | * @epf: the endpoint function to be removed | ||
399 | * | ||
400 | * Invoke to remove PCI endpoint function from the endpoint controller. | ||
401 | */ | ||
402 | void pci_epc_remove_epf(struct pci_epc *epc, struct pci_epf *epf) | ||
403 | { | ||
404 | unsigned long flags; | ||
405 | |||
406 | if (!epc || IS_ERR(epc)) | ||
407 | return; | ||
408 | |||
409 | spin_lock_irqsave(&epc->lock, flags); | ||
410 | list_del(&epf->list); | ||
411 | spin_unlock_irqrestore(&epc->lock, flags); | ||
412 | } | ||
413 | EXPORT_SYMBOL_GPL(pci_epc_remove_epf); | ||
414 | |||
415 | /** | ||
416 | * pci_epc_linkup() - Notify the EPF device that EPC device has established a | ||
417 | * connection with the Root Complex. | ||
418 | * @epc: the EPC device which has established link with the host | ||
419 | * | ||
420 | * Invoke to Notify the EPF device that the EPC device has established a | ||
421 | * connection with the Root Complex. | ||
422 | */ | ||
423 | void pci_epc_linkup(struct pci_epc *epc) | ||
424 | { | ||
425 | unsigned long flags; | ||
426 | struct pci_epf *epf; | ||
427 | |||
428 | if (!epc || IS_ERR(epc)) | ||
429 | return; | ||
430 | |||
431 | spin_lock_irqsave(&epc->lock, flags); | ||
432 | list_for_each_entry(epf, &epc->pci_epf, list) | ||
433 | pci_epf_linkup(epf); | ||
434 | spin_unlock_irqrestore(&epc->lock, flags); | ||
435 | } | ||
436 | EXPORT_SYMBOL_GPL(pci_epc_linkup); | ||
437 | |||
438 | /** | ||
439 | * pci_epc_destroy() - destroy the EPC device | ||
440 | * @epc: the EPC device that has to be destroyed | ||
441 | * | ||
442 | * Invoke to destroy the PCI EPC device | ||
443 | */ | ||
444 | void pci_epc_destroy(struct pci_epc *epc) | ||
445 | { | ||
446 | pci_ep_cfs_remove_epc_group(epc->group); | ||
447 | device_unregister(&epc->dev); | ||
448 | kfree(epc); | ||
449 | } | ||
450 | EXPORT_SYMBOL_GPL(pci_epc_destroy); | ||
451 | |||
452 | /** | ||
453 | * devm_pci_epc_destroy() - destroy the EPC device | ||
454 | * @dev: device that wants to destroy the EPC | ||
455 | * @epc: the EPC device that has to be destroyed | ||
456 | * | ||
457 | * Invoke to destroy the devres associated with this | ||
458 | * pci_epc and destroy the EPC device. | ||
459 | */ | ||
460 | void devm_pci_epc_destroy(struct device *dev, struct pci_epc *epc) | ||
461 | { | ||
462 | int r; | ||
463 | |||
464 | r = devres_destroy(dev, devm_pci_epc_release, devm_pci_epc_match, | ||
465 | epc); | ||
466 | dev_WARN_ONCE(dev, r, "couldn't find PCI EPC resource\n"); | ||
467 | } | ||
468 | EXPORT_SYMBOL_GPL(devm_pci_epc_destroy); | ||
469 | |||
470 | /** | ||
471 | * __pci_epc_create() - create a new endpoint controller (EPC) device | ||
472 | * @dev: device that is creating the new EPC | ||
473 | * @ops: function pointers for performing EPC operations | ||
474 | * @owner: the owner of the module that creates the EPC device | ||
475 | * | ||
476 | * Invoke to create a new EPC device and add it to pci_epc class. | ||
477 | */ | ||
478 | struct pci_epc * | ||
479 | __pci_epc_create(struct device *dev, const struct pci_epc_ops *ops, | ||
480 | struct module *owner) | ||
481 | { | ||
482 | int ret; | ||
483 | struct pci_epc *epc; | ||
484 | |||
485 | if (WARN_ON(!dev)) { | ||
486 | ret = -EINVAL; | ||
487 | goto err_ret; | ||
488 | } | ||
489 | |||
490 | epc = kzalloc(sizeof(*epc), GFP_KERNEL); | ||
491 | if (!epc) { | ||
492 | ret = -ENOMEM; | ||
493 | goto err_ret; | ||
494 | } | ||
495 | |||
496 | spin_lock_init(&epc->lock); | ||
497 | INIT_LIST_HEAD(&epc->pci_epf); | ||
498 | |||
499 | device_initialize(&epc->dev); | ||
500 | dma_set_coherent_mask(&epc->dev, dev->coherent_dma_mask); | ||
501 | epc->dev.class = pci_epc_class; | ||
502 | epc->dev.dma_mask = dev->dma_mask; | ||
503 | epc->ops = ops; | ||
504 | |||
505 | ret = dev_set_name(&epc->dev, "%s", dev_name(dev)); | ||
506 | if (ret) | ||
507 | goto put_dev; | ||
508 | |||
509 | ret = device_add(&epc->dev); | ||
510 | if (ret) | ||
511 | goto put_dev; | ||
512 | |||
513 | epc->group = pci_ep_cfs_add_epc_group(dev_name(dev)); | ||
514 | |||
515 | return epc; | ||
516 | |||
517 | put_dev: | ||
518 | put_device(&epc->dev); | ||
519 | kfree(epc); | ||
520 | |||
521 | err_ret: | ||
522 | return ERR_PTR(ret); | ||
523 | } | ||
524 | EXPORT_SYMBOL_GPL(__pci_epc_create); | ||
525 | |||
526 | /** | ||
527 | * __devm_pci_epc_create() - create a new endpoint controller (EPC) device | ||
528 | * @dev: device that is creating the new EPC | ||
529 | * @ops: function pointers for performing EPC operations | ||
530 | * @owner: the owner of the module that creates the EPC device | ||
531 | * | ||
532 | * Invoke to create a new EPC device and add it to pci_epc class. | ||
533 | * While at that, it also associates the device with the pci_epc using devres. | ||
534 | * On driver detach, release function is invoked on the devres data, | ||
535 | * then, devres data is freed. | ||
536 | */ | ||
537 | struct pci_epc * | ||
538 | __devm_pci_epc_create(struct device *dev, const struct pci_epc_ops *ops, | ||
539 | struct module *owner) | ||
540 | { | ||
541 | struct pci_epc **ptr, *epc; | ||
542 | |||
543 | ptr = devres_alloc(devm_pci_epc_release, sizeof(*ptr), GFP_KERNEL); | ||
544 | if (!ptr) | ||
545 | return ERR_PTR(-ENOMEM); | ||
546 | |||
547 | epc = __pci_epc_create(dev, ops, owner); | ||
548 | if (!IS_ERR(epc)) { | ||
549 | *ptr = epc; | ||
550 | devres_add(dev, ptr); | ||
551 | } else { | ||
552 | devres_free(ptr); | ||
553 | } | ||
554 | |||
555 | return epc; | ||
556 | } | ||
557 | EXPORT_SYMBOL_GPL(__devm_pci_epc_create); | ||
558 | |||
559 | static int __init pci_epc_init(void) | ||
560 | { | ||
561 | pci_epc_class = class_create(THIS_MODULE, "pci_epc"); | ||
562 | if (IS_ERR(pci_epc_class)) { | ||
563 | pr_err("failed to create pci epc class --> %ld\n", | ||
564 | PTR_ERR(pci_epc_class)); | ||
565 | return PTR_ERR(pci_epc_class); | ||
566 | } | ||
567 | |||
568 | return 0; | ||
569 | } | ||
570 | module_init(pci_epc_init); | ||
571 | |||
572 | static void __exit pci_epc_exit(void) | ||
573 | { | ||
574 | class_destroy(pci_epc_class); | ||
575 | } | ||
576 | module_exit(pci_epc_exit); | ||
577 | |||
578 | MODULE_DESCRIPTION("PCI EPC Library"); | ||
579 | MODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>"); | ||
580 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/pci/endpoint/pci-epc-mem.c b/drivers/pci/endpoint/pci-epc-mem.c new file mode 100644 index 000000000000..3a94cc1caf22 --- /dev/null +++ b/drivers/pci/endpoint/pci-epc-mem.c | |||
@@ -0,0 +1,143 @@ | |||
1 | /** | ||
2 | * PCI Endpoint *Controller* Address Space Management | ||
3 | * | ||
4 | * Copyright (C) 2017 Texas Instruments | ||
5 | * Author: Kishon Vijay Abraham I <kishon@ti.com> | ||
6 | * | ||
7 | * This program is free software: you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 of | ||
9 | * the License as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
18 | */ | ||
19 | |||
20 | #include <linux/io.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/slab.h> | ||
23 | |||
24 | #include <linux/pci-epc.h> | ||
25 | |||
26 | /** | ||
27 | * pci_epc_mem_init() - initialize the pci_epc_mem structure | ||
28 | * @epc: the EPC device that invoked pci_epc_mem_init | ||
29 | * @phys_base: the physical address of the base | ||
30 | * @size: the size of the address space | ||
31 | * | ||
32 | * Invoke to initialize the pci_epc_mem structure used by the | ||
33 | * endpoint functions to allocate mapped PCI address. | ||
34 | */ | ||
35 | int pci_epc_mem_init(struct pci_epc *epc, phys_addr_t phys_base, size_t size) | ||
36 | { | ||
37 | int ret; | ||
38 | struct pci_epc_mem *mem; | ||
39 | unsigned long *bitmap; | ||
40 | int pages = size >> PAGE_SHIFT; | ||
41 | int bitmap_size = BITS_TO_LONGS(pages) * sizeof(long); | ||
42 | |||
43 | mem = kzalloc(sizeof(*mem), GFP_KERNEL); | ||
44 | if (!mem) { | ||
45 | ret = -ENOMEM; | ||
46 | goto err; | ||
47 | } | ||
48 | |||
49 | bitmap = kzalloc(bitmap_size, GFP_KERNEL); | ||
50 | if (!bitmap) { | ||
51 | ret = -ENOMEM; | ||
52 | goto err_mem; | ||
53 | } | ||
54 | |||
55 | mem->bitmap = bitmap; | ||
56 | mem->phys_base = phys_base; | ||
57 | mem->pages = pages; | ||
58 | mem->size = size; | ||
59 | |||
60 | epc->mem = mem; | ||
61 | |||
62 | return 0; | ||
63 | |||
64 | err_mem: | ||
65 | kfree(mem); | ||
66 | |||
67 | err: | ||
68 | return ret; | ||
69 | } | ||
70 | EXPORT_SYMBOL_GPL(pci_epc_mem_init); | ||
71 | |||
72 | /** | ||
73 | * pci_epc_mem_exit() - cleanup the pci_epc_mem structure | ||
74 | * @epc: the EPC device that invoked pci_epc_mem_exit | ||
75 | * | ||
76 | * Invoke to cleanup the pci_epc_mem structure allocated in | ||
77 | * pci_epc_mem_init(). | ||
78 | */ | ||
79 | void pci_epc_mem_exit(struct pci_epc *epc) | ||
80 | { | ||
81 | struct pci_epc_mem *mem = epc->mem; | ||
82 | |||
83 | epc->mem = NULL; | ||
84 | kfree(mem->bitmap); | ||
85 | kfree(mem); | ||
86 | } | ||
87 | EXPORT_SYMBOL_GPL(pci_epc_mem_exit); | ||
88 | |||
89 | /** | ||
90 | * pci_epc_mem_alloc_addr() - allocate memory address from EPC addr space | ||
91 | * @epc: the EPC device on which memory has to be allocated | ||
92 | * @phys_addr: populate the allocated physical address here | ||
93 | * @size: the size of the address space that has to be allocated | ||
94 | * | ||
95 | * Invoke to allocate memory address from the EPC address space. This | ||
96 | * is usually done to map the remote RC address into the local system. | ||
97 | */ | ||
98 | void __iomem *pci_epc_mem_alloc_addr(struct pci_epc *epc, | ||
99 | phys_addr_t *phys_addr, size_t size) | ||
100 | { | ||
101 | int pageno; | ||
102 | void __iomem *virt_addr; | ||
103 | struct pci_epc_mem *mem = epc->mem; | ||
104 | int order = get_order(size); | ||
105 | |||
106 | pageno = bitmap_find_free_region(mem->bitmap, mem->pages, order); | ||
107 | if (pageno < 0) | ||
108 | return NULL; | ||
109 | |||
110 | *phys_addr = mem->phys_base + (pageno << PAGE_SHIFT); | ||
111 | virt_addr = ioremap(*phys_addr, size); | ||
112 | if (!virt_addr) | ||
113 | bitmap_release_region(mem->bitmap, pageno, order); | ||
114 | |||
115 | return virt_addr; | ||
116 | } | ||
117 | EXPORT_SYMBOL_GPL(pci_epc_mem_alloc_addr); | ||
118 | |||
119 | /** | ||
120 | * pci_epc_mem_free_addr() - free the allocated memory address | ||
121 | * @epc: the EPC device on which memory was allocated | ||
122 | * @phys_addr: the allocated physical address | ||
123 | * @virt_addr: virtual address of the allocated mem space | ||
124 | * @size: the size of the allocated address space | ||
125 | * | ||
126 | * Invoke to free the memory allocated using pci_epc_mem_alloc_addr. | ||
127 | */ | ||
128 | void pci_epc_mem_free_addr(struct pci_epc *epc, phys_addr_t phys_addr, | ||
129 | void __iomem *virt_addr, size_t size) | ||
130 | { | ||
131 | int pageno; | ||
132 | int order = get_order(size); | ||
133 | struct pci_epc_mem *mem = epc->mem; | ||
134 | |||
135 | iounmap(virt_addr); | ||
136 | pageno = (phys_addr - mem->phys_base) >> PAGE_SHIFT; | ||
137 | bitmap_release_region(mem->bitmap, pageno, order); | ||
138 | } | ||
139 | EXPORT_SYMBOL_GPL(pci_epc_mem_free_addr); | ||
140 | |||
141 | MODULE_DESCRIPTION("PCI EPC Address Space Management"); | ||
142 | MODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>"); | ||
143 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/pci/endpoint/pci-epf-core.c b/drivers/pci/endpoint/pci-epf-core.c new file mode 100644 index 000000000000..6877d6a5bcc9 --- /dev/null +++ b/drivers/pci/endpoint/pci-epf-core.c | |||
@@ -0,0 +1,359 @@ | |||
1 | /** | ||
2 | * PCI Endpoint *Function* (EPF) library | ||
3 | * | ||
4 | * Copyright (C) 2017 Texas Instruments | ||
5 | * Author: Kishon Vijay Abraham I <kishon@ti.com> | ||
6 | * | ||
7 | * This program is free software: you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 of | ||
9 | * the License as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
18 | */ | ||
19 | |||
20 | #include <linux/device.h> | ||
21 | #include <linux/dma-mapping.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/module.h> | ||
24 | |||
25 | #include <linux/pci-epc.h> | ||
26 | #include <linux/pci-epf.h> | ||
27 | #include <linux/pci-ep-cfs.h> | ||
28 | |||
29 | static struct bus_type pci_epf_bus_type; | ||
30 | static struct device_type pci_epf_type; | ||
31 | |||
32 | /** | ||
33 | * pci_epf_linkup() - Notify the function driver that EPC device has | ||
34 | * established a connection with the Root Complex. | ||
35 | * @epf: the EPF device bound to the EPC device which has established | ||
36 | * the connection with the host | ||
37 | * | ||
38 | * Invoke to notify the function driver that EPC device has established | ||
39 | * a connection with the Root Complex. | ||
40 | */ | ||
41 | void pci_epf_linkup(struct pci_epf *epf) | ||
42 | { | ||
43 | if (!epf->driver) { | ||
44 | dev_WARN(&epf->dev, "epf device not bound to driver\n"); | ||
45 | return; | ||
46 | } | ||
47 | |||
48 | epf->driver->ops->linkup(epf); | ||
49 | } | ||
50 | EXPORT_SYMBOL_GPL(pci_epf_linkup); | ||
51 | |||
52 | /** | ||
53 | * pci_epf_unbind() - Notify the function driver that the binding between the | ||
54 | * EPF device and EPC device has been lost | ||
55 | * @epf: the EPF device which has lost the binding with the EPC device | ||
56 | * | ||
57 | * Invoke to notify the function driver that the binding between the EPF device | ||
58 | * and EPC device has been lost. | ||
59 | */ | ||
60 | void pci_epf_unbind(struct pci_epf *epf) | ||
61 | { | ||
62 | if (!epf->driver) { | ||
63 | dev_WARN(&epf->dev, "epf device not bound to driver\n"); | ||
64 | return; | ||
65 | } | ||
66 | |||
67 | epf->driver->ops->unbind(epf); | ||
68 | module_put(epf->driver->owner); | ||
69 | } | ||
70 | EXPORT_SYMBOL_GPL(pci_epf_unbind); | ||
71 | |||
72 | /** | ||
73 | * pci_epf_bind() - Notify the function driver that the EPF device has been | ||
74 | * bound to a EPC device | ||
75 | * @epf: the EPF device which has been bound to the EPC device | ||
76 | * | ||
77 | * Invoke to notify the function driver that it has been bound to a EPC device | ||
78 | */ | ||
79 | int pci_epf_bind(struct pci_epf *epf) | ||
80 | { | ||
81 | if (!epf->driver) { | ||
82 | dev_WARN(&epf->dev, "epf device not bound to driver\n"); | ||
83 | return -EINVAL; | ||
84 | } | ||
85 | |||
86 | if (!try_module_get(epf->driver->owner)) | ||
87 | return -EAGAIN; | ||
88 | |||
89 | return epf->driver->ops->bind(epf); | ||
90 | } | ||
91 | EXPORT_SYMBOL_GPL(pci_epf_bind); | ||
92 | |||
93 | /** | ||
94 | * pci_epf_free_space() - free the allocated PCI EPF register space | ||
95 | * @addr: the virtual address of the PCI EPF register space | ||
96 | * @bar: the BAR number corresponding to the register space | ||
97 | * | ||
98 | * Invoke to free the allocated PCI EPF register space. | ||
99 | */ | ||
100 | void pci_epf_free_space(struct pci_epf *epf, void *addr, enum pci_barno bar) | ||
101 | { | ||
102 | struct device *dev = &epf->dev; | ||
103 | |||
104 | if (!addr) | ||
105 | return; | ||
106 | |||
107 | dma_free_coherent(dev, epf->bar[bar].size, addr, | ||
108 | epf->bar[bar].phys_addr); | ||
109 | |||
110 | epf->bar[bar].phys_addr = 0; | ||
111 | epf->bar[bar].size = 0; | ||
112 | } | ||
113 | EXPORT_SYMBOL_GPL(pci_epf_free_space); | ||
114 | |||
115 | /** | ||
116 | * pci_epf_alloc_space() - allocate memory for the PCI EPF register space | ||
117 | * @size: the size of the memory that has to be allocated | ||
118 | * @bar: the BAR number corresponding to the allocated register space | ||
119 | * | ||
120 | * Invoke to allocate memory for the PCI EPF register space. | ||
121 | */ | ||
122 | void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar) | ||
123 | { | ||
124 | void *space; | ||
125 | struct device *dev = &epf->dev; | ||
126 | dma_addr_t phys_addr; | ||
127 | |||
128 | if (size < 128) | ||
129 | size = 128; | ||
130 | size = roundup_pow_of_two(size); | ||
131 | |||
132 | space = dma_alloc_coherent(dev, size, &phys_addr, GFP_KERNEL); | ||
133 | if (!space) { | ||
134 | dev_err(dev, "failed to allocate mem space\n"); | ||
135 | return NULL; | ||
136 | } | ||
137 | |||
138 | epf->bar[bar].phys_addr = phys_addr; | ||
139 | epf->bar[bar].size = size; | ||
140 | |||
141 | return space; | ||
142 | } | ||
143 | EXPORT_SYMBOL_GPL(pci_epf_alloc_space); | ||
144 | |||
145 | /** | ||
146 | * pci_epf_unregister_driver() - unregister the PCI EPF driver | ||
147 | * @driver: the PCI EPF driver that has to be unregistered | ||
148 | * | ||
149 | * Invoke to unregister the PCI EPF driver. | ||
150 | */ | ||
151 | void pci_epf_unregister_driver(struct pci_epf_driver *driver) | ||
152 | { | ||
153 | pci_ep_cfs_remove_epf_group(driver->group); | ||
154 | driver_unregister(&driver->driver); | ||
155 | } | ||
156 | EXPORT_SYMBOL_GPL(pci_epf_unregister_driver); | ||
157 | |||
158 | /** | ||
159 | * __pci_epf_register_driver() - register a new PCI EPF driver | ||
160 | * @driver: structure representing PCI EPF driver | ||
161 | * @owner: the owner of the module that registers the PCI EPF driver | ||
162 | * | ||
163 | * Invoke to register a new PCI EPF driver. | ||
164 | */ | ||
165 | int __pci_epf_register_driver(struct pci_epf_driver *driver, | ||
166 | struct module *owner) | ||
167 | { | ||
168 | int ret; | ||
169 | |||
170 | if (!driver->ops) | ||
171 | return -EINVAL; | ||
172 | |||
173 | if (!driver->ops->bind || !driver->ops->unbind || !driver->ops->linkup) | ||
174 | return -EINVAL; | ||
175 | |||
176 | driver->driver.bus = &pci_epf_bus_type; | ||
177 | driver->driver.owner = owner; | ||
178 | |||
179 | ret = driver_register(&driver->driver); | ||
180 | if (ret) | ||
181 | return ret; | ||
182 | |||
183 | driver->group = pci_ep_cfs_add_epf_group(driver->driver.name); | ||
184 | |||
185 | return 0; | ||
186 | } | ||
187 | EXPORT_SYMBOL_GPL(__pci_epf_register_driver); | ||
188 | |||
189 | /** | ||
190 | * pci_epf_destroy() - destroy the created PCI EPF device | ||
191 | * @epf: the PCI EPF device that has to be destroyed. | ||
192 | * | ||
193 | * Invoke to destroy the PCI EPF device created by invoking pci_epf_create(). | ||
194 | */ | ||
195 | void pci_epf_destroy(struct pci_epf *epf) | ||
196 | { | ||
197 | device_unregister(&epf->dev); | ||
198 | } | ||
199 | EXPORT_SYMBOL_GPL(pci_epf_destroy); | ||
200 | |||
201 | /** | ||
202 | * pci_epf_create() - create a new PCI EPF device | ||
203 | * @name: the name of the PCI EPF device. This name will be used to bind the | ||
204 | * the EPF device to a EPF driver | ||
205 | * | ||
206 | * Invoke to create a new PCI EPF device by providing the name of the function | ||
207 | * device. | ||
208 | */ | ||
209 | struct pci_epf *pci_epf_create(const char *name) | ||
210 | { | ||
211 | int ret; | ||
212 | struct pci_epf *epf; | ||
213 | struct device *dev; | ||
214 | char *func_name; | ||
215 | char *buf; | ||
216 | |||
217 | epf = kzalloc(sizeof(*epf), GFP_KERNEL); | ||
218 | if (!epf) { | ||
219 | ret = -ENOMEM; | ||
220 | goto err_ret; | ||
221 | } | ||
222 | |||
223 | buf = kstrdup(name, GFP_KERNEL); | ||
224 | if (!buf) { | ||
225 | ret = -ENOMEM; | ||
226 | goto free_epf; | ||
227 | } | ||
228 | |||
229 | func_name = buf; | ||
230 | buf = strchrnul(buf, '.'); | ||
231 | *buf = '\0'; | ||
232 | |||
233 | epf->name = kstrdup(func_name, GFP_KERNEL); | ||
234 | if (!epf->name) { | ||
235 | ret = -ENOMEM; | ||
236 | goto free_func_name; | ||
237 | } | ||
238 | |||
239 | dev = &epf->dev; | ||
240 | device_initialize(dev); | ||
241 | dev->bus = &pci_epf_bus_type; | ||
242 | dev->type = &pci_epf_type; | ||
243 | |||
244 | ret = dev_set_name(dev, "%s", name); | ||
245 | if (ret) | ||
246 | goto put_dev; | ||
247 | |||
248 | ret = device_add(dev); | ||
249 | if (ret) | ||
250 | goto put_dev; | ||
251 | |||
252 | kfree(func_name); | ||
253 | return epf; | ||
254 | |||
255 | put_dev: | ||
256 | put_device(dev); | ||
257 | kfree(epf->name); | ||
258 | |||
259 | free_func_name: | ||
260 | kfree(func_name); | ||
261 | |||
262 | free_epf: | ||
263 | kfree(epf); | ||
264 | |||
265 | err_ret: | ||
266 | return ERR_PTR(ret); | ||
267 | } | ||
268 | EXPORT_SYMBOL_GPL(pci_epf_create); | ||
269 | |||
270 | static void pci_epf_dev_release(struct device *dev) | ||
271 | { | ||
272 | struct pci_epf *epf = to_pci_epf(dev); | ||
273 | |||
274 | kfree(epf->name); | ||
275 | kfree(epf); | ||
276 | } | ||
277 | |||
278 | static struct device_type pci_epf_type = { | ||
279 | .release = pci_epf_dev_release, | ||
280 | }; | ||
281 | |||
282 | static int | ||
283 | pci_epf_match_id(const struct pci_epf_device_id *id, const struct pci_epf *epf) | ||
284 | { | ||
285 | while (id->name[0]) { | ||
286 | if (strcmp(epf->name, id->name) == 0) | ||
287 | return true; | ||
288 | id++; | ||
289 | } | ||
290 | |||
291 | return false; | ||
292 | } | ||
293 | |||
294 | static int pci_epf_device_match(struct device *dev, struct device_driver *drv) | ||
295 | { | ||
296 | struct pci_epf *epf = to_pci_epf(dev); | ||
297 | struct pci_epf_driver *driver = to_pci_epf_driver(drv); | ||
298 | |||
299 | if (driver->id_table) | ||
300 | return pci_epf_match_id(driver->id_table, epf); | ||
301 | |||
302 | return !strcmp(epf->name, drv->name); | ||
303 | } | ||
304 | |||
305 | static int pci_epf_device_probe(struct device *dev) | ||
306 | { | ||
307 | struct pci_epf *epf = to_pci_epf(dev); | ||
308 | struct pci_epf_driver *driver = to_pci_epf_driver(dev->driver); | ||
309 | |||
310 | if (!driver->probe) | ||
311 | return -ENODEV; | ||
312 | |||
313 | epf->driver = driver; | ||
314 | |||
315 | return driver->probe(epf); | ||
316 | } | ||
317 | |||
318 | static int pci_epf_device_remove(struct device *dev) | ||
319 | { | ||
320 | int ret; | ||
321 | struct pci_epf *epf = to_pci_epf(dev); | ||
322 | struct pci_epf_driver *driver = to_pci_epf_driver(dev->driver); | ||
323 | |||
324 | ret = driver->remove(epf); | ||
325 | epf->driver = NULL; | ||
326 | |||
327 | return ret; | ||
328 | } | ||
329 | |||
330 | static struct bus_type pci_epf_bus_type = { | ||
331 | .name = "pci-epf", | ||
332 | .match = pci_epf_device_match, | ||
333 | .probe = pci_epf_device_probe, | ||
334 | .remove = pci_epf_device_remove, | ||
335 | }; | ||
336 | |||
337 | static int __init pci_epf_init(void) | ||
338 | { | ||
339 | int ret; | ||
340 | |||
341 | ret = bus_register(&pci_epf_bus_type); | ||
342 | if (ret) { | ||
343 | pr_err("failed to register pci epf bus --> %d\n", ret); | ||
344 | return ret; | ||
345 | } | ||
346 | |||
347 | return 0; | ||
348 | } | ||
349 | module_init(pci_epf_init); | ||
350 | |||
351 | static void __exit pci_epf_exit(void) | ||
352 | { | ||
353 | bus_unregister(&pci_epf_bus_type); | ||
354 | } | ||
355 | module_exit(pci_epf_exit); | ||
356 | |||
357 | MODULE_DESCRIPTION("PCI EPF Library"); | ||
358 | MODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>"); | ||
359 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/pci/host/pci-thunder-pem.c b/drivers/pci/host/pci-thunder-pem.c index 52b5bdccf5f0..6e031b522529 100644 --- a/drivers/pci/host/pci-thunder-pem.c +++ b/drivers/pci/host/pci-thunder-pem.c | |||
@@ -14,6 +14,7 @@ | |||
14 | * Copyright (C) 2015 - 2016 Cavium, Inc. | 14 | * Copyright (C) 2015 - 2016 Cavium, Inc. |
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include <linux/bitfield.h> | ||
17 | #include <linux/kernel.h> | 18 | #include <linux/kernel.h> |
18 | #include <linux/init.h> | 19 | #include <linux/init.h> |
19 | #include <linux/of_address.h> | 20 | #include <linux/of_address.h> |
@@ -334,6 +335,49 @@ static int thunder_pem_init(struct device *dev, struct pci_config_window *cfg, | |||
334 | 335 | ||
335 | #if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS) | 336 | #if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS) |
336 | 337 | ||
338 | #define PEM_RES_BASE 0x87e0c0000000UL | ||
339 | #define PEM_NODE_MASK GENMASK(45, 44) | ||
340 | #define PEM_INDX_MASK GENMASK(26, 24) | ||
341 | #define PEM_MIN_DOM_IN_NODE 4 | ||
342 | #define PEM_MAX_DOM_IN_NODE 10 | ||
343 | |||
344 | static void thunder_pem_reserve_range(struct device *dev, int seg, | ||
345 | struct resource *r) | ||
346 | { | ||
347 | resource_size_t start = r->start, end = r->end; | ||
348 | struct resource *res; | ||
349 | const char *regionid; | ||
350 | |||
351 | regionid = kasprintf(GFP_KERNEL, "PEM RC:%d", seg); | ||
352 | if (!regionid) | ||
353 | return; | ||
354 | |||
355 | res = request_mem_region(start, end - start + 1, regionid); | ||
356 | if (res) | ||
357 | res->flags &= ~IORESOURCE_BUSY; | ||
358 | else | ||
359 | kfree(regionid); | ||
360 | |||
361 | dev_info(dev, "%pR %s reserved\n", r, | ||
362 | res ? "has been" : "could not be"); | ||
363 | } | ||
364 | |||
365 | static void thunder_pem_legacy_fw(struct acpi_pci_root *root, | ||
366 | struct resource *res_pem) | ||
367 | { | ||
368 | int node = acpi_get_node(root->device->handle); | ||
369 | int index; | ||
370 | |||
371 | if (node == NUMA_NO_NODE) | ||
372 | node = 0; | ||
373 | |||
374 | index = root->segment - PEM_MIN_DOM_IN_NODE; | ||
375 | index -= node * PEM_MAX_DOM_IN_NODE; | ||
376 | res_pem->start = PEM_RES_BASE | FIELD_PREP(PEM_NODE_MASK, node) | | ||
377 | FIELD_PREP(PEM_INDX_MASK, index); | ||
378 | res_pem->flags = IORESOURCE_MEM; | ||
379 | } | ||
380 | |||
337 | static int thunder_pem_acpi_init(struct pci_config_window *cfg) | 381 | static int thunder_pem_acpi_init(struct pci_config_window *cfg) |
338 | { | 382 | { |
339 | struct device *dev = cfg->parent; | 383 | struct device *dev = cfg->parent; |
@@ -346,10 +390,24 @@ static int thunder_pem_acpi_init(struct pci_config_window *cfg) | |||
346 | if (!res_pem) | 390 | if (!res_pem) |
347 | return -ENOMEM; | 391 | return -ENOMEM; |
348 | 392 | ||
349 | ret = acpi_get_rc_resources(dev, "THRX0002", root->segment, res_pem); | 393 | ret = acpi_get_rc_resources(dev, "CAVA02B", root->segment, res_pem); |
394 | |||
395 | /* | ||
396 | * If we fail to gather resources it means that we run with old | ||
397 | * FW where we need to calculate PEM-specific resources manually. | ||
398 | */ | ||
350 | if (ret) { | 399 | if (ret) { |
351 | dev_err(dev, "can't get rc base address\n"); | 400 | thunder_pem_legacy_fw(root, res_pem); |
352 | return ret; | 401 | /* |
402 | * Reserve 64K size PEM specific resources. The full 16M range | ||
403 | * size is required for thunder_pem_init() call. | ||
404 | */ | ||
405 | res_pem->end = res_pem->start + SZ_64K - 1; | ||
406 | thunder_pem_reserve_range(dev, root->segment, res_pem); | ||
407 | res_pem->end = res_pem->start + SZ_16M - 1; | ||
408 | |||
409 | /* Reserve PCI configuration space as well. */ | ||
410 | thunder_pem_reserve_range(dev, root->segment, &cfg->res); | ||
353 | } | 411 | } |
354 | 412 | ||
355 | return thunder_pem_init(dev, cfg, res_pem); | 413 | return thunder_pem_init(dev, cfg, res_pem); |
diff --git a/drivers/pci/host/pcie-iproc-bcma.c b/drivers/pci/host/pcie-iproc-bcma.c index bd4c9ec25edc..384c27e664fe 100644 --- a/drivers/pci/host/pcie-iproc-bcma.c +++ b/drivers/pci/host/pcie-iproc-bcma.c | |||
@@ -44,8 +44,7 @@ static int iproc_pcie_bcma_probe(struct bcma_device *bdev) | |||
44 | { | 44 | { |
45 | struct device *dev = &bdev->dev; | 45 | struct device *dev = &bdev->dev; |
46 | struct iproc_pcie *pcie; | 46 | struct iproc_pcie *pcie; |
47 | LIST_HEAD(res); | 47 | LIST_HEAD(resources); |
48 | struct resource res_mem; | ||
49 | int ret; | 48 | int ret; |
50 | 49 | ||
51 | pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL); | 50 | pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL); |
@@ -63,22 +62,23 @@ static int iproc_pcie_bcma_probe(struct bcma_device *bdev) | |||
63 | 62 | ||
64 | pcie->base_addr = bdev->addr; | 63 | pcie->base_addr = bdev->addr; |
65 | 64 | ||
66 | res_mem.start = bdev->addr_s[0]; | 65 | pcie->mem.start = bdev->addr_s[0]; |
67 | res_mem.end = bdev->addr_s[0] + SZ_128M - 1; | 66 | pcie->mem.end = bdev->addr_s[0] + SZ_128M - 1; |
68 | res_mem.name = "PCIe MEM space"; | 67 | pcie->mem.name = "PCIe MEM space"; |
69 | res_mem.flags = IORESOURCE_MEM; | 68 | pcie->mem.flags = IORESOURCE_MEM; |
70 | pci_add_resource(&res, &res_mem); | 69 | pci_add_resource(&resources, &pcie->mem); |
71 | 70 | ||
72 | pcie->map_irq = iproc_pcie_bcma_map_irq; | 71 | pcie->map_irq = iproc_pcie_bcma_map_irq; |
73 | 72 | ||
74 | ret = iproc_pcie_setup(pcie, &res); | 73 | ret = iproc_pcie_setup(pcie, &resources); |
75 | if (ret) | 74 | if (ret) { |
76 | dev_err(dev, "PCIe controller setup failed\n"); | 75 | dev_err(dev, "PCIe controller setup failed\n"); |
77 | 76 | pci_free_resource_list(&resources); | |
78 | pci_free_resource_list(&res); | 77 | return ret; |
78 | } | ||
79 | 79 | ||
80 | bcma_set_drvdata(bdev, pcie); | 80 | bcma_set_drvdata(bdev, pcie); |
81 | return ret; | 81 | return 0; |
82 | } | 82 | } |
83 | 83 | ||
84 | static void iproc_pcie_bcma_remove(struct bcma_device *bdev) | 84 | static void iproc_pcie_bcma_remove(struct bcma_device *bdev) |
diff --git a/drivers/pci/host/pcie-iproc-platform.c b/drivers/pci/host/pcie-iproc-platform.c index f4909bb0b2ad..8c6a327ca6cd 100644 --- a/drivers/pci/host/pcie-iproc-platform.c +++ b/drivers/pci/host/pcie-iproc-platform.c | |||
@@ -51,7 +51,7 @@ static int iproc_pcie_pltfm_probe(struct platform_device *pdev) | |||
51 | struct device_node *np = dev->of_node; | 51 | struct device_node *np = dev->of_node; |
52 | struct resource reg; | 52 | struct resource reg; |
53 | resource_size_t iobase = 0; | 53 | resource_size_t iobase = 0; |
54 | LIST_HEAD(res); | 54 | LIST_HEAD(resources); |
55 | int ret; | 55 | int ret; |
56 | 56 | ||
57 | pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL); | 57 | pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL); |
@@ -96,10 +96,10 @@ static int iproc_pcie_pltfm_probe(struct platform_device *pdev) | |||
96 | pcie->phy = NULL; | 96 | pcie->phy = NULL; |
97 | } | 97 | } |
98 | 98 | ||
99 | ret = of_pci_get_host_bridge_resources(np, 0, 0xff, &res, &iobase); | 99 | ret = of_pci_get_host_bridge_resources(np, 0, 0xff, &resources, |
100 | &iobase); | ||
100 | if (ret) { | 101 | if (ret) { |
101 | dev_err(dev, | 102 | dev_err(dev, "unable to get PCI host bridge resources\n"); |
102 | "unable to get PCI host bridge resources\n"); | ||
103 | return ret; | 103 | return ret; |
104 | } | 104 | } |
105 | 105 | ||
@@ -112,14 +112,15 @@ static int iproc_pcie_pltfm_probe(struct platform_device *pdev) | |||
112 | pcie->map_irq = of_irq_parse_and_map_pci; | 112 | pcie->map_irq = of_irq_parse_and_map_pci; |
113 | } | 113 | } |
114 | 114 | ||
115 | ret = iproc_pcie_setup(pcie, &res); | 115 | ret = iproc_pcie_setup(pcie, &resources); |
116 | if (ret) | 116 | if (ret) { |
117 | dev_err(dev, "PCIe controller setup failed\n"); | 117 | dev_err(dev, "PCIe controller setup failed\n"); |
118 | 118 | pci_free_resource_list(&resources); | |
119 | pci_free_resource_list(&res); | 119 | return ret; |
120 | } | ||
120 | 121 | ||
121 | platform_set_drvdata(pdev, pcie); | 122 | platform_set_drvdata(pdev, pcie); |
122 | return ret; | 123 | return 0; |
123 | } | 124 | } |
124 | 125 | ||
125 | static int iproc_pcie_pltfm_remove(struct platform_device *pdev) | 126 | static int iproc_pcie_pltfm_remove(struct platform_device *pdev) |
diff --git a/drivers/pci/host/pcie-iproc.h b/drivers/pci/host/pcie-iproc.h index 04fed8e907f1..0bbe2ea44f3e 100644 --- a/drivers/pci/host/pcie-iproc.h +++ b/drivers/pci/host/pcie-iproc.h | |||
@@ -90,6 +90,7 @@ struct iproc_pcie { | |||
90 | #ifdef CONFIG_ARM | 90 | #ifdef CONFIG_ARM |
91 | struct pci_sys_data sysdata; | 91 | struct pci_sys_data sysdata; |
92 | #endif | 92 | #endif |
93 | struct resource mem; | ||
93 | struct pci_bus *root_bus; | 94 | struct pci_bus *root_bus; |
94 | struct phy *phy; | 95 | struct phy *phy; |
95 | int (*map_irq)(const struct pci_dev *, u8, u8); | 96 | int (*map_irq)(const struct pci_dev *, u8, u8); |
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 973472c23d89..1dfa10cc566b 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c | |||
@@ -478,7 +478,7 @@ static void aspm_calc_l1ss_info(struct pcie_link_state *link, | |||
478 | 478 | ||
479 | static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist) | 479 | static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist) |
480 | { | 480 | { |
481 | struct pci_dev *child, *parent = link->pdev; | 481 | struct pci_dev *child = link->downstream, *parent = link->pdev; |
482 | struct pci_bus *linkbus = parent->subordinate; | 482 | struct pci_bus *linkbus = parent->subordinate; |
483 | struct aspm_register_info upreg, dwreg; | 483 | struct aspm_register_info upreg, dwreg; |
484 | 484 | ||
@@ -491,9 +491,7 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist) | |||
491 | 491 | ||
492 | /* Get upstream/downstream components' register state */ | 492 | /* Get upstream/downstream components' register state */ |
493 | pcie_get_aspm_reg(parent, &upreg); | 493 | pcie_get_aspm_reg(parent, &upreg); |
494 | child = pci_function_0(linkbus); | ||
495 | pcie_get_aspm_reg(child, &dwreg); | 494 | pcie_get_aspm_reg(child, &dwreg); |
496 | link->downstream = child; | ||
497 | 495 | ||
498 | /* | 496 | /* |
499 | * If ASPM not supported, don't mess with the clocks and link, | 497 | * If ASPM not supported, don't mess with the clocks and link, |
@@ -800,6 +798,7 @@ static struct pcie_link_state *alloc_pcie_link_state(struct pci_dev *pdev) | |||
800 | INIT_LIST_HEAD(&link->children); | 798 | INIT_LIST_HEAD(&link->children); |
801 | INIT_LIST_HEAD(&link->link); | 799 | INIT_LIST_HEAD(&link->link); |
802 | link->pdev = pdev; | 800 | link->pdev = pdev; |
801 | link->downstream = pci_function_0(pdev->subordinate); | ||
803 | 802 | ||
804 | /* | 803 | /* |
805 | * Root Ports and PCI/PCI-X to PCIe Bridges are roots of PCIe | 804 | * Root Ports and PCI/PCI-X to PCIe Bridges are roots of PCIe |
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index f754453fe754..673683660b5c 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c | |||
@@ -2174,6 +2174,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x005d, quirk_blacklist_vpd); | |||
2174 | DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x005f, quirk_blacklist_vpd); | 2174 | DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x005f, quirk_blacklist_vpd); |
2175 | DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATTANSIC, PCI_ANY_ID, | 2175 | DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATTANSIC, PCI_ANY_ID, |
2176 | quirk_blacklist_vpd); | 2176 | quirk_blacklist_vpd); |
2177 | DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_QLOGIC, 0x2261, quirk_blacklist_vpd); | ||
2177 | 2178 | ||
2178 | /* | 2179 | /* |
2179 | * For Broadcom 5706, 5708, 5709 rev. A nics, any read beyond the | 2180 | * For Broadcom 5706, 5708, 5709 rev. A nics, any read beyond the |
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h index 8850fcaf50db..566fda587fcf 100644 --- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h | |||
@@ -428,6 +428,16 @@ struct i2c_device_id { | |||
428 | kernel_ulong_t driver_data; /* Data private to the driver */ | 428 | kernel_ulong_t driver_data; /* Data private to the driver */ |
429 | }; | 429 | }; |
430 | 430 | ||
431 | /* pci_epf */ | ||
432 | |||
433 | #define PCI_EPF_NAME_SIZE 20 | ||
434 | #define PCI_EPF_MODULE_PREFIX "pci_epf:" | ||
435 | |||
436 | struct pci_epf_device_id { | ||
437 | char name[PCI_EPF_NAME_SIZE]; | ||
438 | kernel_ulong_t driver_data; | ||
439 | }; | ||
440 | |||
431 | /* spi */ | 441 | /* spi */ |
432 | 442 | ||
433 | #define SPI_NAME_SIZE 32 | 443 | #define SPI_NAME_SIZE 32 |
diff --git a/include/linux/pci-ep-cfs.h b/include/linux/pci-ep-cfs.h new file mode 100644 index 000000000000..263b89ea5705 --- /dev/null +++ b/include/linux/pci-ep-cfs.h | |||
@@ -0,0 +1,41 @@ | |||
1 | /** | ||
2 | * PCI Endpoint ConfigFS header file | ||
3 | * | ||
4 | * Copyright (C) 2017 Texas Instruments | ||
5 | * Author: Kishon Vijay Abraham I <kishon@ti.com> | ||
6 | * | ||
7 | * This program is free software: you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 of | ||
9 | * the License as published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #ifndef __LINUX_PCI_EP_CFS_H | ||
13 | #define __LINUX_PCI_EP_CFS_H | ||
14 | |||
15 | #include <linux/configfs.h> | ||
16 | |||
17 | #ifdef CONFIG_PCI_ENDPOINT_CONFIGFS | ||
18 | struct config_group *pci_ep_cfs_add_epc_group(const char *name); | ||
19 | void pci_ep_cfs_remove_epc_group(struct config_group *group); | ||
20 | struct config_group *pci_ep_cfs_add_epf_group(const char *name); | ||
21 | void pci_ep_cfs_remove_epf_group(struct config_group *group); | ||
22 | #else | ||
23 | static inline struct config_group *pci_ep_cfs_add_epc_group(const char *name) | ||
24 | { | ||
25 | return 0; | ||
26 | } | ||
27 | |||
28 | static inline void pci_ep_cfs_remove_epc_group(struct config_group *group) | ||
29 | { | ||
30 | } | ||
31 | |||
32 | static inline struct config_group *pci_ep_cfs_add_epf_group(const char *name) | ||
33 | { | ||
34 | return 0; | ||
35 | } | ||
36 | |||
37 | static inline void pci_ep_cfs_remove_epf_group(struct config_group *group) | ||
38 | { | ||
39 | } | ||
40 | #endif | ||
41 | #endif /* __LINUX_PCI_EP_CFS_H */ | ||
diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h new file mode 100644 index 000000000000..af5edbf3eea3 --- /dev/null +++ b/include/linux/pci-epc.h | |||
@@ -0,0 +1,144 @@ | |||
1 | /** | ||
2 | * PCI Endpoint *Controller* (EPC) header file | ||
3 | * | ||
4 | * Copyright (C) 2017 Texas Instruments | ||
5 | * Author: Kishon Vijay Abraham I <kishon@ti.com> | ||
6 | * | ||
7 | * This program is free software: you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 of | ||
9 | * the License as published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #ifndef __LINUX_PCI_EPC_H | ||
13 | #define __LINUX_PCI_EPC_H | ||
14 | |||
15 | #include <linux/pci-epf.h> | ||
16 | |||
17 | struct pci_epc; | ||
18 | |||
19 | enum pci_epc_irq_type { | ||
20 | PCI_EPC_IRQ_UNKNOWN, | ||
21 | PCI_EPC_IRQ_LEGACY, | ||
22 | PCI_EPC_IRQ_MSI, | ||
23 | }; | ||
24 | |||
25 | /** | ||
26 | * struct pci_epc_ops - set of function pointers for performing EPC operations | ||
27 | * @write_header: ops to populate configuration space header | ||
28 | * @set_bar: ops to configure the BAR | ||
29 | * @clear_bar: ops to reset the BAR | ||
30 | * @map_addr: ops to map CPU address to PCI address | ||
31 | * @unmap_addr: ops to unmap CPU address and PCI address | ||
32 | * @set_msi: ops to set the requested number of MSI interrupts in the MSI | ||
33 | * capability register | ||
34 | * @get_msi: ops to get the number of MSI interrupts allocated by the RC from | ||
35 | * the MSI capability register | ||
36 | * @raise_irq: ops to raise a legacy or MSI interrupt | ||
37 | * @start: ops to start the PCI link | ||
38 | * @stop: ops to stop the PCI link | ||
39 | * @owner: the module owner containing the ops | ||
40 | */ | ||
41 | struct pci_epc_ops { | ||
42 | int (*write_header)(struct pci_epc *pci_epc, | ||
43 | struct pci_epf_header *hdr); | ||
44 | int (*set_bar)(struct pci_epc *epc, enum pci_barno bar, | ||
45 | dma_addr_t bar_phys, size_t size, int flags); | ||
46 | void (*clear_bar)(struct pci_epc *epc, enum pci_barno bar); | ||
47 | int (*map_addr)(struct pci_epc *epc, phys_addr_t addr, | ||
48 | u64 pci_addr, size_t size); | ||
49 | void (*unmap_addr)(struct pci_epc *epc, phys_addr_t addr); | ||
50 | int (*set_msi)(struct pci_epc *epc, u8 interrupts); | ||
51 | int (*get_msi)(struct pci_epc *epc); | ||
52 | int (*raise_irq)(struct pci_epc *pci_epc, | ||
53 | enum pci_epc_irq_type type, u8 interrupt_num); | ||
54 | int (*start)(struct pci_epc *epc); | ||
55 | void (*stop)(struct pci_epc *epc); | ||
56 | struct module *owner; | ||
57 | }; | ||
58 | |||
59 | /** | ||
60 | * struct pci_epc_mem - address space of the endpoint controller | ||
61 | * @phys_base: physical base address of the PCI address space | ||
62 | * @size: the size of the PCI address space | ||
63 | * @bitmap: bitmap to manage the PCI address space | ||
64 | * @pages: number of bits representing the address region | ||
65 | */ | ||
66 | struct pci_epc_mem { | ||
67 | phys_addr_t phys_base; | ||
68 | size_t size; | ||
69 | unsigned long *bitmap; | ||
70 | int pages; | ||
71 | }; | ||
72 | |||
73 | /** | ||
74 | * struct pci_epc - represents the PCI EPC device | ||
75 | * @dev: PCI EPC device | ||
76 | * @pci_epf: list of endpoint functions present in this EPC device | ||
77 | * @ops: function pointers for performing endpoint operations | ||
78 | * @mem: address space of the endpoint controller | ||
79 | * @max_functions: max number of functions that can be configured in this EPC | ||
80 | * @group: configfs group representing the PCI EPC device | ||
81 | * @lock: spinlock to protect pci_epc ops | ||
82 | */ | ||
83 | struct pci_epc { | ||
84 | struct device dev; | ||
85 | struct list_head pci_epf; | ||
86 | const struct pci_epc_ops *ops; | ||
87 | struct pci_epc_mem *mem; | ||
88 | u8 max_functions; | ||
89 | struct config_group *group; | ||
90 | /* spinlock to protect against concurrent access of EP controller */ | ||
91 | spinlock_t lock; | ||
92 | }; | ||
93 | |||
94 | #define to_pci_epc(device) container_of((device), struct pci_epc, dev) | ||
95 | |||
96 | #define pci_epc_create(dev, ops) \ | ||
97 | __pci_epc_create((dev), (ops), THIS_MODULE) | ||
98 | #define devm_pci_epc_create(dev, ops) \ | ||
99 | __devm_pci_epc_create((dev), (ops), THIS_MODULE) | ||
100 | |||
101 | static inline void epc_set_drvdata(struct pci_epc *epc, void *data) | ||
102 | { | ||
103 | dev_set_drvdata(&epc->dev, data); | ||
104 | } | ||
105 | |||
106 | static inline void *epc_get_drvdata(struct pci_epc *epc) | ||
107 | { | ||
108 | return dev_get_drvdata(&epc->dev); | ||
109 | } | ||
110 | |||
111 | struct pci_epc * | ||
112 | __devm_pci_epc_create(struct device *dev, const struct pci_epc_ops *ops, | ||
113 | struct module *owner); | ||
114 | struct pci_epc * | ||
115 | __pci_epc_create(struct device *dev, const struct pci_epc_ops *ops, | ||
116 | struct module *owner); | ||
117 | void devm_pci_epc_destroy(struct device *dev, struct pci_epc *epc); | ||
118 | void pci_epc_destroy(struct pci_epc *epc); | ||
119 | int pci_epc_add_epf(struct pci_epc *epc, struct pci_epf *epf); | ||
120 | void pci_epc_linkup(struct pci_epc *epc); | ||
121 | void pci_epc_remove_epf(struct pci_epc *epc, struct pci_epf *epf); | ||
122 | int pci_epc_write_header(struct pci_epc *epc, struct pci_epf_header *hdr); | ||
123 | int pci_epc_set_bar(struct pci_epc *epc, enum pci_barno bar, | ||
124 | dma_addr_t bar_phys, size_t size, int flags); | ||
125 | void pci_epc_clear_bar(struct pci_epc *epc, int bar); | ||
126 | int pci_epc_map_addr(struct pci_epc *epc, phys_addr_t phys_addr, | ||
127 | u64 pci_addr, size_t size); | ||
128 | void pci_epc_unmap_addr(struct pci_epc *epc, phys_addr_t phys_addr); | ||
129 | int pci_epc_set_msi(struct pci_epc *epc, u8 interrupts); | ||
130 | int pci_epc_get_msi(struct pci_epc *epc); | ||
131 | int pci_epc_raise_irq(struct pci_epc *epc, enum pci_epc_irq_type type, | ||
132 | u8 interrupt_num); | ||
133 | int pci_epc_start(struct pci_epc *epc); | ||
134 | void pci_epc_stop(struct pci_epc *epc); | ||
135 | struct pci_epc *pci_epc_get(const char *epc_name); | ||
136 | void pci_epc_put(struct pci_epc *epc); | ||
137 | |||
138 | int pci_epc_mem_init(struct pci_epc *epc, phys_addr_t phys_addr, size_t size); | ||
139 | void pci_epc_mem_exit(struct pci_epc *epc); | ||
140 | void __iomem *pci_epc_mem_alloc_addr(struct pci_epc *epc, | ||
141 | phys_addr_t *phys_addr, size_t size); | ||
142 | void pci_epc_mem_free_addr(struct pci_epc *epc, phys_addr_t phys_addr, | ||
143 | void __iomem *virt_addr, size_t size); | ||
144 | #endif /* __LINUX_PCI_EPC_H */ | ||
diff --git a/include/linux/pci-epf.h b/include/linux/pci-epf.h new file mode 100644 index 000000000000..0d529cb90143 --- /dev/null +++ b/include/linux/pci-epf.h | |||
@@ -0,0 +1,162 @@ | |||
1 | /** | ||
2 | * PCI Endpoint *Function* (EPF) header file | ||
3 | * | ||
4 | * Copyright (C) 2017 Texas Instruments | ||
5 | * Author: Kishon Vijay Abraham I <kishon@ti.com> | ||
6 | * | ||
7 | * This program is free software: you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 of | ||
9 | * the License as published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #ifndef __LINUX_PCI_EPF_H | ||
13 | #define __LINUX_PCI_EPF_H | ||
14 | |||
15 | #include <linux/device.h> | ||
16 | #include <linux/mod_devicetable.h> | ||
17 | |||
18 | struct pci_epf; | ||
19 | |||
20 | enum pci_interrupt_pin { | ||
21 | PCI_INTERRUPT_UNKNOWN, | ||
22 | PCI_INTERRUPT_INTA, | ||
23 | PCI_INTERRUPT_INTB, | ||
24 | PCI_INTERRUPT_INTC, | ||
25 | PCI_INTERRUPT_INTD, | ||
26 | }; | ||
27 | |||
28 | enum pci_barno { | ||
29 | BAR_0, | ||
30 | BAR_1, | ||
31 | BAR_2, | ||
32 | BAR_3, | ||
33 | BAR_4, | ||
34 | BAR_5, | ||
35 | }; | ||
36 | |||
37 | /** | ||
38 | * struct pci_epf_header - represents standard configuration header | ||
39 | * @vendorid: identifies device manufacturer | ||
40 | * @deviceid: identifies a particular device | ||
41 | * @revid: specifies a device-specific revision identifier | ||
42 | * @progif_code: identifies a specific register-level programming interface | ||
43 | * @subclass_code: identifies more specifically the function of the device | ||
44 | * @baseclass_code: broadly classifies the type of function the device performs | ||
45 | * @cache_line_size: specifies the system cacheline size in units of DWORDs | ||
46 | * @subsys_vendor_id: vendor of the add-in card or subsystem | ||
47 | * @subsys_id: id specific to vendor | ||
48 | * @interrupt_pin: interrupt pin the device (or device function) uses | ||
49 | */ | ||
50 | struct pci_epf_header { | ||
51 | u16 vendorid; | ||
52 | u16 deviceid; | ||
53 | u8 revid; | ||
54 | u8 progif_code; | ||
55 | u8 subclass_code; | ||
56 | u8 baseclass_code; | ||
57 | u8 cache_line_size; | ||
58 | u16 subsys_vendor_id; | ||
59 | u16 subsys_id; | ||
60 | enum pci_interrupt_pin interrupt_pin; | ||
61 | }; | ||
62 | |||
63 | /** | ||
64 | * struct pci_epf_ops - set of function pointers for performing EPF operations | ||
65 | * @bind: ops to perform when a EPC device has been bound to EPF device | ||
66 | * @unbind: ops to perform when a binding has been lost between a EPC device | ||
67 | * and EPF device | ||
68 | * @linkup: ops to perform when the EPC device has established a connection with | ||
69 | * a host system | ||
70 | */ | ||
71 | struct pci_epf_ops { | ||
72 | int (*bind)(struct pci_epf *epf); | ||
73 | void (*unbind)(struct pci_epf *epf); | ||
74 | void (*linkup)(struct pci_epf *epf); | ||
75 | }; | ||
76 | |||
77 | /** | ||
78 | * struct pci_epf_driver - represents the PCI EPF driver | ||
79 | * @probe: ops to perform when a new EPF device has been bound to the EPF driver | ||
80 | * @remove: ops to perform when the binding between the EPF device and EPF | ||
81 | * driver is broken | ||
82 | * @driver: PCI EPF driver | ||
83 | * @ops: set of function pointers for performing EPF operations | ||
84 | * @owner: the owner of the module that registers the PCI EPF driver | ||
85 | * @group: configfs group corresponding to the PCI EPF driver | ||
86 | * @id_table: identifies EPF devices for probing | ||
87 | */ | ||
88 | struct pci_epf_driver { | ||
89 | int (*probe)(struct pci_epf *epf); | ||
90 | int (*remove)(struct pci_epf *epf); | ||
91 | |||
92 | struct device_driver driver; | ||
93 | struct pci_epf_ops *ops; | ||
94 | struct module *owner; | ||
95 | struct config_group *group; | ||
96 | const struct pci_epf_device_id *id_table; | ||
97 | }; | ||
98 | |||
99 | #define to_pci_epf_driver(drv) (container_of((drv), struct pci_epf_driver, \ | ||
100 | driver)) | ||
101 | |||
102 | /** | ||
103 | * struct pci_epf_bar - represents the BAR of EPF device | ||
104 | * @phys_addr: physical address that should be mapped to the BAR | ||
105 | * @size: the size of the address space present in BAR | ||
106 | */ | ||
107 | struct pci_epf_bar { | ||
108 | dma_addr_t phys_addr; | ||
109 | size_t size; | ||
110 | }; | ||
111 | |||
112 | /** | ||
113 | * struct pci_epf - represents the PCI EPF device | ||
114 | * @dev: the PCI EPF device | ||
115 | * @name: the name of the PCI EPF device | ||
116 | * @header: represents standard configuration header | ||
117 | * @bar: represents the BAR of EPF device | ||
118 | * @msi_interrupts: number of MSI interrupts required by this function | ||
119 | * @func_no: unique function number within this endpoint device | ||
120 | * @epc: the EPC device to which this EPF device is bound | ||
121 | * @driver: the EPF driver to which this EPF device is bound | ||
122 | * @list: to add pci_epf as a list of PCI endpoint functions to pci_epc | ||
123 | */ | ||
124 | struct pci_epf { | ||
125 | struct device dev; | ||
126 | const char *name; | ||
127 | struct pci_epf_header *header; | ||
128 | struct pci_epf_bar bar[6]; | ||
129 | u8 msi_interrupts; | ||
130 | u8 func_no; | ||
131 | |||
132 | struct pci_epc *epc; | ||
133 | struct pci_epf_driver *driver; | ||
134 | struct list_head list; | ||
135 | }; | ||
136 | |||
137 | #define to_pci_epf(epf_dev) container_of((epf_dev), struct pci_epf, dev) | ||
138 | |||
139 | #define pci_epf_register_driver(driver) \ | ||
140 | __pci_epf_register_driver((driver), THIS_MODULE) | ||
141 | |||
142 | static inline void epf_set_drvdata(struct pci_epf *epf, void *data) | ||
143 | { | ||
144 | dev_set_drvdata(&epf->dev, data); | ||
145 | } | ||
146 | |||
147 | static inline void *epf_get_drvdata(struct pci_epf *epf) | ||
148 | { | ||
149 | return dev_get_drvdata(&epf->dev); | ||
150 | } | ||
151 | |||
152 | struct pci_epf *pci_epf_create(const char *name); | ||
153 | void pci_epf_destroy(struct pci_epf *epf); | ||
154 | int __pci_epf_register_driver(struct pci_epf_driver *driver, | ||
155 | struct module *owner); | ||
156 | void pci_epf_unregister_driver(struct pci_epf_driver *driver); | ||
157 | void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar); | ||
158 | void pci_epf_free_space(struct pci_epf *epf, void *addr, enum pci_barno bar); | ||
159 | int pci_epf_bind(struct pci_epf *epf); | ||
160 | void pci_epf_unbind(struct pci_epf *epf); | ||
161 | void pci_epf_linkup(struct pci_epf *epf); | ||
162 | #endif /* __LINUX_PCI_EPF_H */ | ||
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index a4f77feecbb0..5f6b71d15393 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h | |||
@@ -862,6 +862,8 @@ | |||
862 | #define PCI_DEVICE_ID_TI_X620 0xac8d | 862 | #define PCI_DEVICE_ID_TI_X620 0xac8d |
863 | #define PCI_DEVICE_ID_TI_X420 0xac8e | 863 | #define PCI_DEVICE_ID_TI_X420 0xac8e |
864 | #define PCI_DEVICE_ID_TI_XX20_FM 0xac8f | 864 | #define PCI_DEVICE_ID_TI_XX20_FM 0xac8f |
865 | #define PCI_DEVICE_ID_TI_DRA74x 0xb500 | ||
866 | #define PCI_DEVICE_ID_TI_DRA72x 0xb501 | ||
865 | 867 | ||
866 | #define PCI_VENDOR_ID_SONY 0x104d | 868 | #define PCI_VENDOR_ID_SONY 0x104d |
867 | 869 | ||
diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild index dd9820b1c779..baee6db08287 100644 --- a/include/uapi/linux/Kbuild +++ b/include/uapi/linux/Kbuild | |||
@@ -333,6 +333,7 @@ header-y += parport.h | |||
333 | header-y += patchkey.h | 333 | header-y += patchkey.h |
334 | header-y += pci.h | 334 | header-y += pci.h |
335 | header-y += pci_regs.h | 335 | header-y += pci_regs.h |
336 | header-y += pcitest.h | ||
336 | header-y += perf_event.h | 337 | header-y += perf_event.h |
337 | header-y += personality.h | 338 | header-y += personality.h |
338 | header-y += pfkeyv2.h | 339 | header-y += pfkeyv2.h |
diff --git a/include/uapi/linux/pcitest.h b/include/uapi/linux/pcitest.h new file mode 100644 index 000000000000..a6aa10c45ad1 --- /dev/null +++ b/include/uapi/linux/pcitest.h | |||
@@ -0,0 +1,19 @@ | |||
1 | /** | ||
2 | * pcitest.h - PCI test uapi defines | ||
3 | * | ||
4 | * Copyright (C) 2017 Texas Instruments | ||
5 | * Author: Kishon Vijay Abraham I <kishon@ti.com> | ||
6 | * | ||
7 | */ | ||
8 | |||
9 | #ifndef __UAPI_LINUX_PCITEST_H | ||
10 | #define __UAPI_LINUX_PCITEST_H | ||
11 | |||
12 | #define PCITEST_BAR _IO('P', 0x1) | ||
13 | #define PCITEST_LEGACY_IRQ _IO('P', 0x2) | ||
14 | #define PCITEST_MSI _IOW('P', 0x3, int) | ||
15 | #define PCITEST_WRITE _IOW('P', 0x4, unsigned long) | ||
16 | #define PCITEST_READ _IOW('P', 0x5, unsigned long) | ||
17 | #define PCITEST_COPY _IOW('P', 0x6, unsigned long) | ||
18 | |||
19 | #endif /* __UAPI_LINUX_PCITEST_H */ | ||
diff --git a/tools/pci/pcitest.c b/tools/pci/pcitest.c new file mode 100644 index 000000000000..ad54a58d7dda --- /dev/null +++ b/tools/pci/pcitest.c | |||
@@ -0,0 +1,186 @@ | |||
1 | /** | ||
2 | * Userspace PCI Endpoint Test Module | ||
3 | * | ||
4 | * Copyright (C) 2017 Texas Instruments | ||
5 | * Author: Kishon Vijay Abraham I <kishon@ti.com> | ||
6 | * | ||
7 | * This program is free software: you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 of | ||
9 | * the License as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
18 | */ | ||
19 | |||
20 | #include <errno.h> | ||
21 | #include <fcntl.h> | ||
22 | #include <stdbool.h> | ||
23 | #include <stdio.h> | ||
24 | #include <stdlib.h> | ||
25 | #include <sys/ioctl.h> | ||
26 | #include <time.h> | ||
27 | #include <unistd.h> | ||
28 | |||
29 | #include <linux/pcitest.h> | ||
30 | |||
31 | #define BILLION 1E9 | ||
32 | |||
33 | static char *result[] = { "NOT OKAY", "OKAY" }; | ||
34 | |||
35 | struct pci_test { | ||
36 | char *device; | ||
37 | char barnum; | ||
38 | bool legacyirq; | ||
39 | unsigned int msinum; | ||
40 | bool read; | ||
41 | bool write; | ||
42 | bool copy; | ||
43 | unsigned long size; | ||
44 | }; | ||
45 | |||
46 | static int run_test(struct pci_test *test) | ||
47 | { | ||
48 | long ret; | ||
49 | int fd; | ||
50 | struct timespec start, end; | ||
51 | double time; | ||
52 | |||
53 | fd = open(test->device, O_RDWR); | ||
54 | if (fd < 0) { | ||
55 | perror("can't open PCI Endpoint Test device"); | ||
56 | return fd; | ||
57 | } | ||
58 | |||
59 | if (test->barnum >= 0 && test->barnum <= 5) { | ||
60 | ret = ioctl(fd, PCITEST_BAR, test->barnum); | ||
61 | fprintf(stdout, "BAR%d:\t\t", test->barnum); | ||
62 | if (ret < 0) | ||
63 | fprintf(stdout, "TEST FAILED\n"); | ||
64 | else | ||
65 | fprintf(stdout, "%s\n", result[ret]); | ||
66 | } | ||
67 | |||
68 | if (test->legacyirq) { | ||
69 | ret = ioctl(fd, PCITEST_LEGACY_IRQ, 0); | ||
70 | fprintf(stdout, "LEGACY IRQ:\t"); | ||
71 | if (ret < 0) | ||
72 | fprintf(stdout, "TEST FAILED\n"); | ||
73 | else | ||
74 | fprintf(stdout, "%s\n", result[ret]); | ||
75 | } | ||
76 | |||
77 | if (test->msinum > 0 && test->msinum <= 32) { | ||
78 | ret = ioctl(fd, PCITEST_MSI, test->msinum); | ||
79 | fprintf(stdout, "MSI%d:\t\t", test->msinum); | ||
80 | if (ret < 0) | ||
81 | fprintf(stdout, "TEST FAILED\n"); | ||
82 | else | ||
83 | fprintf(stdout, "%s\n", result[ret]); | ||
84 | } | ||
85 | |||
86 | if (test->write) { | ||
87 | ret = ioctl(fd, PCITEST_WRITE, test->size); | ||
88 | fprintf(stdout, "WRITE (%7ld bytes):\t\t", test->size); | ||
89 | if (ret < 0) | ||
90 | fprintf(stdout, "TEST FAILED\n"); | ||
91 | else | ||
92 | fprintf(stdout, "%s\n", result[ret]); | ||
93 | } | ||
94 | |||
95 | if (test->read) { | ||
96 | ret = ioctl(fd, PCITEST_READ, test->size); | ||
97 | fprintf(stdout, "READ (%7ld bytes):\t\t", test->size); | ||
98 | if (ret < 0) | ||
99 | fprintf(stdout, "TEST FAILED\n"); | ||
100 | else | ||
101 | fprintf(stdout, "%s\n", result[ret]); | ||
102 | } | ||
103 | |||
104 | if (test->copy) { | ||
105 | ret = ioctl(fd, PCITEST_COPY, test->size); | ||
106 | fprintf(stdout, "COPY (%7ld bytes):\t\t", test->size); | ||
107 | if (ret < 0) | ||
108 | fprintf(stdout, "TEST FAILED\n"); | ||
109 | else | ||
110 | fprintf(stdout, "%s\n", result[ret]); | ||
111 | } | ||
112 | |||
113 | fflush(stdout); | ||
114 | } | ||
115 | |||
116 | int main(int argc, char **argv) | ||
117 | { | ||
118 | int c; | ||
119 | struct pci_test *test; | ||
120 | |||
121 | test = calloc(1, sizeof(*test)); | ||
122 | if (!test) { | ||
123 | perror("Fail to allocate memory for pci_test\n"); | ||
124 | return -ENOMEM; | ||
125 | } | ||
126 | |||
127 | /* since '0' is a valid BAR number, initialize it to -1 */ | ||
128 | test->barnum = -1; | ||
129 | |||
130 | /* set default size as 100KB */ | ||
131 | test->size = 0x19000; | ||
132 | |||
133 | /* set default endpoint device */ | ||
134 | test->device = "/dev/pci-endpoint-test.0"; | ||
135 | |||
136 | while ((c = getopt(argc, argv, "D:b:m:lrwcs:")) != EOF) | ||
137 | switch (c) { | ||
138 | case 'D': | ||
139 | test->device = optarg; | ||
140 | continue; | ||
141 | case 'b': | ||
142 | test->barnum = atoi(optarg); | ||
143 | if (test->barnum < 0 || test->barnum > 5) | ||
144 | goto usage; | ||
145 | continue; | ||
146 | case 'l': | ||
147 | test->legacyirq = true; | ||
148 | continue; | ||
149 | case 'm': | ||
150 | test->msinum = atoi(optarg); | ||
151 | if (test->msinum < 1 || test->msinum > 32) | ||
152 | goto usage; | ||
153 | continue; | ||
154 | case 'r': | ||
155 | test->read = true; | ||
156 | continue; | ||
157 | case 'w': | ||
158 | test->write = true; | ||
159 | continue; | ||
160 | case 'c': | ||
161 | test->copy = true; | ||
162 | continue; | ||
163 | case 's': | ||
164 | test->size = strtoul(optarg, NULL, 0); | ||
165 | continue; | ||
166 | case '?': | ||
167 | case 'h': | ||
168 | default: | ||
169 | usage: | ||
170 | fprintf(stderr, | ||
171 | "usage: %s [options]\n" | ||
172 | "Options:\n" | ||
173 | "\t-D <dev> PCI endpoint test device {default: /dev/pci-endpoint-test.0}\n" | ||
174 | "\t-b <bar num> BAR test (bar number between 0..5)\n" | ||
175 | "\t-m <msi num> MSI test (msi number between 1..32)\n" | ||
176 | "\t-r Read buffer test\n" | ||
177 | "\t-w Write buffer test\n" | ||
178 | "\t-c Copy buffer test\n" | ||
179 | "\t-s <size> Size of buffer {default: 100KB}\n", | ||
180 | argv[0]); | ||
181 | return -EINVAL; | ||
182 | } | ||
183 | |||
184 | run_test(test); | ||
185 | return 0; | ||
186 | } | ||
diff --git a/tools/pci/pcitest.sh b/tools/pci/pcitest.sh new file mode 100644 index 000000000000..5442bbea4c22 --- /dev/null +++ b/tools/pci/pcitest.sh | |||
@@ -0,0 +1,56 @@ | |||
1 | #!/bin/sh | ||
2 | |||
3 | echo "BAR tests" | ||
4 | echo | ||
5 | |||
6 | bar=0 | ||
7 | |||
8 | while [ $bar -lt 6 ] | ||
9 | do | ||
10 | pcitest -b $bar | ||
11 | bar=`expr $bar + 1` | ||
12 | done | ||
13 | echo | ||
14 | |||
15 | echo "Interrupt tests" | ||
16 | echo | ||
17 | |||
18 | pcitest -l | ||
19 | msi=1 | ||
20 | |||
21 | while [ $msi -lt 33 ] | ||
22 | do | ||
23 | pcitest -m $msi | ||
24 | msi=`expr $msi + 1` | ||
25 | done | ||
26 | echo | ||
27 | |||
28 | echo "Read Tests" | ||
29 | echo | ||
30 | |||
31 | pcitest -r -s 1 | ||
32 | pcitest -r -s 1024 | ||
33 | pcitest -r -s 1025 | ||
34 | pcitest -r -s 1024000 | ||
35 | pcitest -r -s 1024001 | ||
36 | echo | ||
37 | |||
38 | echo "Write Tests" | ||
39 | echo | ||
40 | |||
41 | pcitest -w -s 1 | ||
42 | pcitest -w -s 1024 | ||
43 | pcitest -w -s 1025 | ||
44 | pcitest -w -s 1024000 | ||
45 | pcitest -w -s 1024001 | ||
46 | echo | ||
47 | |||
48 | echo "Copy Tests" | ||
49 | echo | ||
50 | |||
51 | pcitest -c -s 1 | ||
52 | pcitest -c -s 1024 | ||
53 | pcitest -c -s 1025 | ||
54 | pcitest -c -s 1024000 | ||
55 | pcitest -c -s 1024001 | ||
56 | echo | ||