Commit b16f2ab2 authored by Bjorn Helgaas's avatar Bjorn Helgaas
Browse files

Merge branch 'remotes/lorenzo/pci/endpoint'

  - Use notification chain instead of EPF linkup ops for EPC events (Kishon
    Vijay Abraham I)

  - Protect concurrent allocation in endpoint outbound address region
    (Kishon Vijay Abraham I)

  - Protect concurrent access to pci_epf_ops (Kishon Vijay Abraham I)

  - Assign function number for each PF in endpoint core (Kishon Vijay
    Abraham I)

  - Refactor endpoint mode core initialization (Vidya Sagar)

  - Add API to notify when core initialization completes (Vidya Sagar)

  - Add test framework support to defer core initialization (Vidya Sagar)

  - Update Tegra SoC ABI header to support uninitialization of UPHY PLL
    when in endpoint mode without reference clock (Vidya Sagar)

  - Add DT and driver support for Tegra194 PCIe endpoint nodes (Vidya
    Sagar)

  - Add endpoint test support for DMA data transfer (Kishon Vijay
    Abraham I)

  - Print throughput information in endpoint test (Kishon Vijay Abraham I)

  - Use streaming DMA APIs for endpoint test buffer allocation (Kishon
    Vijay Abraham I)

  - Add endpoint test command line option for DMA (Kishon Vijay Abraham I)

  - When stopping a controller via configfs, clear endpoint "start" entry
    to prevent WARN_ON (Kunihiko Hayashi)

  - Update endpoint ->set_msix() to pay attention to MSI-X BAR Indicator
    and offset when finding MSI-X tables (Kishon Vijay Abraham I)

  - MSI-X tables are in local memory, not in the PCI address space.  Update
    pcie-designware-ep to account for this (Kishon Vijay Abraham I)

  - Allow AM654 PCIe Endpoint to raise MSI-X interrupts (Kishon Vijay
    Abraham I)

  - Avoid using module parameter to determine irqtype for endpoint test
    (Kishon Vijay Abraham I)

  - Add ioctl to clear IRQ for endpoint test (Kishon Vijay Abraham I)

  - Add endpoint test 'e' option to clear IRQ (Kishon Vijay Abraham I)

  - Bump limit on number of endpoint test devices from 10 to 10,000 (Kishon
    Vijay Abraham I)

  - Use full pci-endpoint-test name in request_irq() for easier profiling
    (Kishon Vijay Abraham I)

  - Reduce log level of -EPROBE_DEFER error messages to debug (Thierry
    Reding)

* remotes/lorenzo/pci/endpoint:
  misc: pci_endpoint_test: remove duplicate macro PCI_ENDPOINT_TEST_STATUS
  PCI: tegra: Print -EPROBE_DEFER error message at debug level
  misc: pci_endpoint_test: Use full pci-endpoint-test name in request_irq()
  misc: pci_endpoint_test: Fix to support > 10 pci-endpoint-test devices
  tools: PCI: Add 'e' to clear IRQ
  misc: pci_endpoint_test: Add ioctl to clear IRQ
  misc: pci_endpoint_test: Avoid using module parameter to determine irqtype
  PCI: keystone: Allow AM654 PCIe Endpoint to raise MSI-X interrupt
  PCI: dwc: Fix dw_pcie_ep_raise_msix_irq() to get correct MSI-X table address
  PCI: endpoint: Fix ->set_msix() to take BIR and offset as arguments
  misc: pci_endpoint_test: Add support to get DMA option from userspace
  tools: PCI: Add 'd' command line option to support DMA
  misc: pci_endpoint_test: Use streaming DMA APIs for buffer allocation
  PCI: endpoint: functions/pci-epf-test: Print throughput information
  PCI: endpoint: functions/pci-epf-test: Add DMA support to transfer data
  PCI: endpoint: Fix clearing start entry in configfs
  PCI: tegra: Add support for PCIe endpoint mode in Tegra194
  dt-bindings: PCI: tegra: Add DT support for PCIe EP nodes in Tegra194
  soc/tegra: bpmp: Update ABI header
  PCI: pci-epf-test: Add support to defer core initialization
  PCI: dwc: Add API to notify core initialization completion
  PCI: endpoint: Add notification for core init completion
  PCI: dwc: Refactor core initialization code for EP mode
  PCI: endpoint: Add core init notifying feature
  PCI: endpoint: Assign function number for each PF in EPC core
  PCI: endpoint: Protect concurrent access to pci_epf_ops with mutex
  PCI: endpoint: Fix for concurrent memory allocation in OB address region
  PCI: endpoint: Replace spinlock with mutex
  PCI: endpoint: Use notification chain mechanism to notify EPC events to EPF
parents cc36a451 e48ba3eb
Loading
Loading
Loading
Loading
+99 −26
Original line number Diff line number Diff line
NVIDIA Tegra PCIe controller (Synopsys DesignWare Core based)

This PCIe host controller is based on the Synopsis Designware PCIe IP
This PCIe controller is based on the Synopsis Designware PCIe IP
and thus inherits all the common properties defined in designware-pcie.txt.
Some of the controller instances are dual mode where in they can work either
in root port mode or endpoint mode but one at a time.

Required properties:
- compatible: For Tegra19x, must contain "nvidia,tegra194-pcie".
- device_type: Must be "pci"
- power-domains: A phandle to the node that controls power to the respective
  PCIe controller and a specifier name for the PCIe controller. Following are
  the specifiers for the different PCIe controllers
@@ -32,6 +32,32 @@ Required properties:
  entry for each entry in the interrupt-names property.
- interrupt-names: Must include the following entries:
  "intr": The Tegra interrupt that is asserted for controller interrupts
- clocks: Must contain an entry for each entry in clock-names.
  See ../clocks/clock-bindings.txt for details.
- clock-names: Must include the following entries:
  - core
- resets: Must contain an entry for each entry in reset-names.
  See ../reset/reset.txt for details.
- reset-names: Must include the following entries:
  - apb
  - core
- phys: Must contain a phandle to P2U PHY for each entry in phy-names.
- phy-names: Must include an entry for each active lane.
  "p2u-N": where N ranges from 0 to one less than the total number of lanes
- nvidia,bpmp: Must contain a pair of phandle to BPMP controller node followed
  by controller-id. Following are the controller ids for each controller.
    0: C0
    1: C1
    2: C2
    3: C3
    4: C4
    5: C5
- vddio-pex-ctl-supply: Regulator supply for PCIe side band signals

RC mode:
- compatible: Tegra19x must contain  "nvidia,tegra194-pcie"
- device_type: Must be "pci" for RC mode
- interrupt-names: Must include the following entries:
  "msi": The Tegra interrupt that is asserted when an MSI is received
- bus-range: Range of bus numbers associated with this controller
- #address-cells: Address representation for root ports (must be 3)
@@ -60,27 +86,15 @@ Required properties:
- interrupt-map-mask and interrupt-map: Standard PCI IRQ mapping properties
  Please refer to the standard PCI bus binding document for a more detailed
  explanation.
- clocks: Must contain an entry for each entry in clock-names.
  See ../clocks/clock-bindings.txt for details.
- clock-names: Must include the following entries:
  - core
- resets: Must contain an entry for each entry in reset-names.
  See ../reset/reset.txt for details.
- reset-names: Must include the following entries:
  - apb
  - core
- phys: Must contain a phandle to P2U PHY for each entry in phy-names.
- phy-names: Must include an entry for each active lane.
  "p2u-N": where N ranges from 0 to one less than the total number of lanes
- nvidia,bpmp: Must contain a pair of phandle to BPMP controller node followed
  by controller-id. Following are the controller ids for each controller.
    0: C0
    1: C1
    2: C2
    3: C3
    4: C4
    5: C5
- vddio-pex-ctl-supply: Regulator supply for PCIe side band signals

EP mode:
In Tegra194, Only controllers C0, C4 & C5 support EP mode.
- compatible: Tegra19x must contain "nvidia,tegra194-pcie-ep"
- reg-names: Must include the following entries:
  "addr_space": Used to map remote RC address space
- reset-gpios: Must contain a phandle to a GPIO controller followed by
  GPIO that is being used as PERST input signal. Please refer to pci.txt
  document.

Optional properties:
- pinctrl-names: A list of pinctrl state names.
@@ -104,6 +118,8 @@ Optional properties:
   specified in microseconds
- nvidia,aspm-l0s-entrance-latency-us: ASPM L0s entrance latency to be
   specified in microseconds

RC mode:
- vpcie3v3-supply: A phandle to the regulator node that supplies 3.3V to the slot
  if the platform has one such slot. (Ex:- x16 slot owned by C5 controller
  in p2972-0000 platform).
@@ -111,11 +127,18 @@ Optional properties:
  if the platform has one such slot. (Ex:- x16 slot owned by C5 controller
  in p2972-0000 platform).

EP mode:
- nvidia,refclk-select-gpios: Must contain a phandle to a GPIO controller
  followed by GPIO that is being used to enable REFCLK to controller from host

NOTE:- On Tegra194's P2972-0000 platform, only C5 controller can be enabled to
operate in the endpoint mode because of the way the platform is designed.

Examples:
=========

Tegra194:
--------
Tegra194 RC mode:
-----------------

	pcie@14180000 {
		compatible = "nvidia,tegra194-pcie", "snps,dw-pcie";
@@ -169,3 +192,53 @@ Tegra194:
		       <&p2u_hsio_5>;
		phy-names = "p2u-0", "p2u-1", "p2u-2", "p2u-3";
	};

Tegra194 EP mode:
-----------------

	pcie_ep@141a0000 {
		compatible = "nvidia,tegra194-pcie-ep", "snps,dw-pcie-ep";
		power-domains = <&bpmp TEGRA194_POWER_DOMAIN_PCIEX8A>;
		reg = <0x00 0x141a0000 0x0 0x00020000   /* appl registers (128K)      */
		       0x00 0x3a040000 0x0 0x00040000   /* iATU_DMA reg space (256K)  */
		       0x00 0x3a080000 0x0 0x00040000   /* DBI reg space (256K)       */
		       0x1c 0x00000000 0x4 0x00000000>; /* Address Space (16G)        */
		reg-names = "appl", "atu_dma", "dbi", "addr_space";

		num-lanes = <8>;
		num-ib-windows = <2>;
		num-ob-windows = <8>;

		pinctrl-names = "default";
		pinctrl-0 = <&clkreq_c5_bi_dir_state>;

		clocks = <&bpmp TEGRA194_CLK_PEX1_CORE_5>;
		clock-names = "core";

		resets = <&bpmp TEGRA194_RESET_PEX1_CORE_5_APB>,
			 <&bpmp TEGRA194_RESET_PEX1_CORE_5>;
		reset-names = "apb", "core";

		interrupts = <GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>;	/* controller interrupt */
		interrupt-names = "intr";

		nvidia,bpmp = <&bpmp 5>;

		nvidia,aspm-cmrt-us = <60>;
		nvidia,aspm-pwr-on-t-us = <20>;
		nvidia,aspm-l0s-entrance-latency-us = <3>;

		vddio-pex-ctl-supply = <&vdd_1v8ao>;

		reset-gpios = <&gpio TEGRA194_MAIN_GPIO(GG, 1) GPIO_ACTIVE_LOW>;

		nvidia,refclk-select-gpios = <&gpio_aon TEGRA194_AON_GPIO(AA, 5)
					      GPIO_ACTIVE_HIGH>;

		phys = <&p2u_nvhs_0>, <&p2u_nvhs_1>, <&p2u_nvhs_2>,
		       <&p2u_nvhs_3>, <&p2u_nvhs_4>, <&p2u_nvhs_5>,
		       <&p2u_nvhs_6>, <&p2u_nvhs_7>;

		phy-names = "p2u-0", "p2u-1", "p2u-2", "p2u-3", "p2u-4",
			    "p2u-5", "p2u-6", "p2u-7";
	};
+179 −34
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#include <linux/mutex.h>
#include <linux/random.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/pci.h>
#include <linux/pci_ids.h>

@@ -64,6 +65,9 @@
#define PCI_ENDPOINT_TEST_IRQ_TYPE		0x24
#define PCI_ENDPOINT_TEST_IRQ_NUMBER		0x28

#define PCI_ENDPOINT_TEST_FLAGS			0x2c
#define FLAG_USE_DMA				BIT(0)

#define PCI_DEVICE_ID_TI_AM654			0xb00c

#define is_am654_pci_dev(pdev)		\
@@ -98,11 +102,13 @@ struct pci_endpoint_test {
	struct completion irq_raised;
	int		last_irq;
	int		num_irqs;
	int		irq_type;
	/* mutex to protect the ioctls */
	struct mutex	mutex;
	struct miscdevice miscdev;
	enum pci_barno test_reg_bar;
	size_t alignment;
	const char *name;
};

struct pci_endpoint_test_data {
@@ -157,6 +163,7 @@ static void pci_endpoint_test_free_irq_vectors(struct pci_endpoint_test *test)
	struct pci_dev *pdev = test->pdev;

	pci_free_irq_vectors(pdev);
	test->irq_type = IRQ_TYPE_UNDEFINED;
}

static bool pci_endpoint_test_alloc_irq_vectors(struct pci_endpoint_test *test,
@@ -191,6 +198,8 @@ static bool pci_endpoint_test_alloc_irq_vectors(struct pci_endpoint_test *test,
		irq = 0;
		res = false;
	}

	test->irq_type = type;
	test->num_irqs = irq;

	return res;
@@ -218,7 +227,7 @@ static bool pci_endpoint_test_request_irq(struct pci_endpoint_test *test)
	for (i = 0; i < test->num_irqs; i++) {
		err = devm_request_irq(dev, pci_irq_vector(pdev, i),
				       pci_endpoint_test_irqhandler,
				       IRQF_SHARED, DRV_MODULE_NAME, test);
				       IRQF_SHARED, test->name, test);
		if (err)
			goto fail;
	}
@@ -315,11 +324,16 @@ static bool pci_endpoint_test_msi_irq(struct pci_endpoint_test *test,
	return false;
}

static bool pci_endpoint_test_copy(struct pci_endpoint_test *test, size_t size)
static bool pci_endpoint_test_copy(struct pci_endpoint_test *test,
				   unsigned long arg)
{
	struct pci_endpoint_test_xfer_param param;
	bool ret = false;
	void *src_addr;
	void *dst_addr;
	u32 flags = 0;
	bool use_dma;
	size_t size;
	dma_addr_t src_phys_addr;
	dma_addr_t dst_phys_addr;
	struct pci_dev *pdev = test->pdev;
@@ -330,25 +344,46 @@ static bool pci_endpoint_test_copy(struct pci_endpoint_test *test, size_t size)
	dma_addr_t orig_dst_phys_addr;
	size_t offset;
	size_t alignment = test->alignment;
	int irq_type = test->irq_type;
	u32 src_crc32;
	u32 dst_crc32;
	int err;

	err = copy_from_user(&param, (void __user *)arg, sizeof(param));
	if (err) {
		dev_err(dev, "Failed to get transfer param\n");
		return false;
	}

	size = param.size;
	if (size > SIZE_MAX - alignment)
		goto err;

	use_dma = !!(param.flags & PCITEST_FLAGS_USE_DMA);
	if (use_dma)
		flags |= FLAG_USE_DMA;

	if (irq_type < IRQ_TYPE_LEGACY || irq_type > IRQ_TYPE_MSIX) {
		dev_err(dev, "Invalid IRQ type option\n");
		goto err;
	}

	orig_src_addr = dma_alloc_coherent(dev, size + alignment,
					   &orig_src_phys_addr, GFP_KERNEL);
	orig_src_addr = kzalloc(size + alignment, GFP_KERNEL);
	if (!orig_src_addr) {
		dev_err(dev, "Failed to allocate source buffer\n");
		ret = false;
		goto err;
	}

	get_random_bytes(orig_src_addr, size + alignment);
	orig_src_phys_addr = dma_map_single(dev, orig_src_addr,
					    size + alignment, DMA_TO_DEVICE);
	if (dma_mapping_error(dev, orig_src_phys_addr)) {
		dev_err(dev, "failed to map source buffer address\n");
		ret = false;
		goto err_src_phys_addr;
	}

	if (alignment && !IS_ALIGNED(orig_src_phys_addr, alignment)) {
		src_phys_addr = PTR_ALIGN(orig_src_phys_addr, alignment);
		offset = src_phys_addr - orig_src_phys_addr;
@@ -364,15 +399,21 @@ static bool pci_endpoint_test_copy(struct pci_endpoint_test *test, size_t size)
	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_UPPER_SRC_ADDR,
				 upper_32_bits(src_phys_addr));

	get_random_bytes(src_addr, size);
	src_crc32 = crc32_le(~0, src_addr, size);

	orig_dst_addr = dma_alloc_coherent(dev, size + alignment,
					   &orig_dst_phys_addr, GFP_KERNEL);
	orig_dst_addr = kzalloc(size + alignment, GFP_KERNEL);
	if (!orig_dst_addr) {
		dev_err(dev, "Failed to allocate destination address\n");
		ret = false;
		goto err_orig_src_addr;
		goto err_dst_addr;
	}

	orig_dst_phys_addr = dma_map_single(dev, orig_dst_addr,
					    size + alignment, DMA_FROM_DEVICE);
	if (dma_mapping_error(dev, orig_dst_phys_addr)) {
		dev_err(dev, "failed to map destination buffer address\n");
		ret = false;
		goto err_dst_phys_addr;
	}

	if (alignment && !IS_ALIGNED(orig_dst_phys_addr, alignment)) {
@@ -392,6 +433,7 @@ static bool pci_endpoint_test_copy(struct pci_endpoint_test *test, size_t size)
	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_SIZE,
				 size);

	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_FLAGS, flags);
	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE, irq_type);
	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, 1);
	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND,
@@ -399,24 +441,34 @@ static bool pci_endpoint_test_copy(struct pci_endpoint_test *test, size_t size)

	wait_for_completion(&test->irq_raised);

	dma_unmap_single(dev, orig_dst_phys_addr, size + alignment,
			 DMA_FROM_DEVICE);

	dst_crc32 = crc32_le(~0, dst_addr, size);
	if (dst_crc32 == src_crc32)
		ret = true;

	dma_free_coherent(dev, size + alignment, orig_dst_addr,
			  orig_dst_phys_addr);
err_dst_phys_addr:
	kfree(orig_dst_addr);

err_dst_addr:
	dma_unmap_single(dev, orig_src_phys_addr, size + alignment,
			 DMA_TO_DEVICE);

err_orig_src_addr:
	dma_free_coherent(dev, size + alignment, orig_src_addr,
			  orig_src_phys_addr);
err_src_phys_addr:
	kfree(orig_src_addr);

err:
	return ret;
}

static bool pci_endpoint_test_write(struct pci_endpoint_test *test, size_t size)
static bool pci_endpoint_test_write(struct pci_endpoint_test *test,
				    unsigned long arg)
{
	struct pci_endpoint_test_xfer_param param;
	bool ret = false;
	u32 flags = 0;
	bool use_dma;
	u32 reg;
	void *addr;
	dma_addr_t phys_addr;
@@ -426,24 +478,47 @@ static bool pci_endpoint_test_write(struct pci_endpoint_test *test, size_t size)
	dma_addr_t orig_phys_addr;
	size_t offset;
	size_t alignment = test->alignment;
	int irq_type = test->irq_type;
	size_t size;
	u32 crc32;
	int err;

	err = copy_from_user(&param, (void __user *)arg, sizeof(param));
	if (err != 0) {
		dev_err(dev, "Failed to get transfer param\n");
		return false;
	}

	size = param.size;
	if (size > SIZE_MAX - alignment)
		goto err;

	use_dma = !!(param.flags & PCITEST_FLAGS_USE_DMA);
	if (use_dma)
		flags |= FLAG_USE_DMA;

	if (irq_type < IRQ_TYPE_LEGACY || irq_type > IRQ_TYPE_MSIX) {
		dev_err(dev, "Invalid IRQ type option\n");
		goto err;
	}

	orig_addr = dma_alloc_coherent(dev, size + alignment, &orig_phys_addr,
				       GFP_KERNEL);
	orig_addr = kzalloc(size + alignment, GFP_KERNEL);
	if (!orig_addr) {
		dev_err(dev, "Failed to allocate address\n");
		ret = false;
		goto err;
	}

	get_random_bytes(orig_addr, size + alignment);

	orig_phys_addr = dma_map_single(dev, orig_addr, size + alignment,
					DMA_TO_DEVICE);
	if (dma_mapping_error(dev, orig_phys_addr)) {
		dev_err(dev, "failed to map source buffer address\n");
		ret = false;
		goto err_phys_addr;
	}

	if (alignment && !IS_ALIGNED(orig_phys_addr, alignment)) {
		phys_addr =  PTR_ALIGN(orig_phys_addr, alignment);
		offset = phys_addr - orig_phys_addr;
@@ -453,8 +528,6 @@ static bool pci_endpoint_test_write(struct pci_endpoint_test *test, size_t size)
		addr = orig_addr;
	}

	get_random_bytes(addr, size);

	crc32 = crc32_le(~0, addr, size);
	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_CHECKSUM,
				 crc32);
@@ -466,6 +539,7 @@ static bool pci_endpoint_test_write(struct pci_endpoint_test *test, size_t size)

	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_SIZE, size);

	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_FLAGS, flags);
	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE, irq_type);
	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, 1);
	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND,
@@ -477,15 +551,24 @@ static bool pci_endpoint_test_write(struct pci_endpoint_test *test, size_t size)
	if (reg & STATUS_READ_SUCCESS)
		ret = true;

	dma_free_coherent(dev, size + alignment, orig_addr, orig_phys_addr);
	dma_unmap_single(dev, orig_phys_addr, size + alignment,
			 DMA_TO_DEVICE);

err_phys_addr:
	kfree(orig_addr);

err:
	return ret;
}

static bool pci_endpoint_test_read(struct pci_endpoint_test *test, size_t size)
static bool pci_endpoint_test_read(struct pci_endpoint_test *test,
				   unsigned long arg)
{
	struct pci_endpoint_test_xfer_param param;
	bool ret = false;
	u32 flags = 0;
	bool use_dma;
	size_t size;
	void *addr;
	dma_addr_t phys_addr;
	struct pci_dev *pdev = test->pdev;
@@ -494,24 +577,44 @@ static bool pci_endpoint_test_read(struct pci_endpoint_test *test, size_t size)
	dma_addr_t orig_phys_addr;
	size_t offset;
	size_t alignment = test->alignment;
	int irq_type = test->irq_type;
	u32 crc32;
	int err;

	err = copy_from_user(&param, (void __user *)arg, sizeof(param));
	if (err) {
		dev_err(dev, "Failed to get transfer param\n");
		return false;
	}

	size = param.size;
	if (size > SIZE_MAX - alignment)
		goto err;

	use_dma = !!(param.flags & PCITEST_FLAGS_USE_DMA);
	if (use_dma)
		flags |= FLAG_USE_DMA;

	if (irq_type < IRQ_TYPE_LEGACY || irq_type > IRQ_TYPE_MSIX) {
		dev_err(dev, "Invalid IRQ type option\n");
		goto err;
	}

	orig_addr = dma_alloc_coherent(dev, size + alignment, &orig_phys_addr,
				       GFP_KERNEL);
	orig_addr = kzalloc(size + alignment, GFP_KERNEL);
	if (!orig_addr) {
		dev_err(dev, "Failed to allocate destination address\n");
		ret = false;
		goto err;
	}

	orig_phys_addr = dma_map_single(dev, orig_addr, size + alignment,
					DMA_FROM_DEVICE);
	if (dma_mapping_error(dev, orig_phys_addr)) {
		dev_err(dev, "failed to map source buffer address\n");
		ret = false;
		goto err_phys_addr;
	}

	if (alignment && !IS_ALIGNED(orig_phys_addr, alignment)) {
		phys_addr = PTR_ALIGN(orig_phys_addr, alignment);
		offset = phys_addr - orig_phys_addr;
@@ -528,6 +631,7 @@ static bool pci_endpoint_test_read(struct pci_endpoint_test *test, size_t size)

	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_SIZE, size);

	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_FLAGS, flags);
	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE, irq_type);
	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, 1);
	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND,
@@ -535,15 +639,26 @@ static bool pci_endpoint_test_read(struct pci_endpoint_test *test, size_t size)

	wait_for_completion(&test->irq_raised);

	dma_unmap_single(dev, orig_phys_addr, size + alignment,
			 DMA_FROM_DEVICE);

	crc32 = crc32_le(~0, addr, size);
	if (crc32 == pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_CHECKSUM))
		ret = true;

	dma_free_coherent(dev, size + alignment, orig_addr, orig_phys_addr);
err_phys_addr:
	kfree(orig_addr);
err:
	return ret;
}

static bool pci_endpoint_test_clear_irq(struct pci_endpoint_test *test)
{
	pci_endpoint_test_release_irq(test);
	pci_endpoint_test_free_irq_vectors(test);
	return true;
}

static bool pci_endpoint_test_set_irq(struct pci_endpoint_test *test,
				      int req_irq_type)
{
@@ -555,7 +670,7 @@ static bool pci_endpoint_test_set_irq(struct pci_endpoint_test *test,
		return false;
	}

	if (irq_type == req_irq_type)
	if (test->irq_type == req_irq_type)
		return true;

	pci_endpoint_test_release_irq(test);
@@ -567,12 +682,10 @@ static bool pci_endpoint_test_set_irq(struct pci_endpoint_test *test,
	if (!pci_endpoint_test_request_irq(test))
		goto err;

	irq_type = req_irq_type;
	return true;

err:
	pci_endpoint_test_free_irq_vectors(test);
	irq_type = IRQ_TYPE_UNDEFINED;
	return false;
}

@@ -616,6 +729,9 @@ static long pci_endpoint_test_ioctl(struct file *file, unsigned int cmd,
	case PCITEST_GET_IRQTYPE:
		ret = irq_type;
		break;
	case PCITEST_CLEAR_IRQ:
		ret = pci_endpoint_test_clear_irq(test);
		break;
	}

ret:
@@ -633,7 +749,7 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,
{
	int err;
	int id;
	char name[20];
	char name[24];
	enum pci_barno bar;
	void __iomem *base;
	struct device *dev = &pdev->dev;
@@ -652,6 +768,7 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,
	test->test_reg_bar = 0;
	test->alignment = 0;
	test->pdev = pdev;
	test->irq_type = IRQ_TYPE_UNDEFINED;

	if (no_msi)
		irq_type = IRQ_TYPE_LEGACY;
@@ -667,6 +784,12 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,
	init_completion(&test->irq_raised);
	mutex_init(&test->mutex);

	if ((dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(48)) != 0) &&
	    dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)) != 0) {
		dev_err(dev, "Cannot set DMA mask\n");
		return -EINVAL;
	}

	err = pci_enable_device(pdev);
	if (err) {
		dev_err(dev, "Cannot enable PCI device\n");
@@ -684,9 +807,6 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,
	if (!pci_endpoint_test_alloc_irq_vectors(test, irq_type))
		goto err_disable_irq;

	if (!pci_endpoint_test_request_irq(test))
		goto err_disable_irq;

	for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
		if (pci_resource_flags(pdev, bar) & IORESOURCE_MEM) {
			base = pci_ioremap_bar(pdev, bar);
@@ -716,12 +836,21 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,
	}

	snprintf(name, sizeof(name), DRV_MODULE_NAME ".%d", id);
	test->name = kstrdup(name, GFP_KERNEL);
	if (!test->name) {
		err = -ENOMEM;
		goto err_ida_remove;
	}

	if (!pci_endpoint_test_request_irq(test))
		goto err_kfree_test_name;

	misc_device = &test->miscdev;
	misc_device->minor = MISC_DYNAMIC_MINOR;
	misc_device->name = kstrdup(name, GFP_KERNEL);
	if (!misc_device->name) {
		err = -ENOMEM;
		goto err_ida_remove;
		goto err_release_irq;
	}
	misc_device->fops = &pci_endpoint_test_fops,

@@ -736,6 +865,12 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,
err_kfree_name:
	kfree(misc_device->name);

err_release_irq:
	pci_endpoint_test_release_irq(test);

err_kfree_test_name:
	kfree(test->name);

err_ida_remove:
	ida_simple_remove(&pci_endpoint_test_ida, id);

@@ -744,7 +879,6 @@ err_iounmap:
		if (test->bar[bar])
			pci_iounmap(pdev, test->bar[bar]);
	}
	pci_endpoint_test_release_irq(test);

err_disable_irq:
	pci_endpoint_test_free_irq_vectors(test);
@@ -770,6 +904,7 @@ static void pci_endpoint_test_remove(struct pci_dev *pdev)

	misc_deregister(&test->miscdev);
	kfree(misc_device->name);
	kfree(test->name);
	ida_simple_remove(&pci_endpoint_test_ida, id);
	for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
		if (test->bar[bar])
@@ -783,6 +918,12 @@ static void pci_endpoint_test_remove(struct pci_dev *pdev)
	pci_disable_device(pdev);
}

static const struct pci_endpoint_test_data default_data = {
	.test_reg_bar = BAR_0,
	.alignment = SZ_4K,
	.irq_type = IRQ_TYPE_MSI,
};

static const struct pci_endpoint_test_data am654_data = {
	.test_reg_bar = BAR_2,
	.alignment = SZ_64K,
@@ -790,8 +931,12 @@ static const struct pci_endpoint_test_data am654_data = {
};

static const struct pci_device_id pci_endpoint_test_tbl[] = {
	{ PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_DRA74x) },
	{ PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_DRA72x) },
	{ PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_DRA74x),
	  .driver_data = (kernel_ulong_t)&default_data,
	},
	{ PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_DRA72x),
	  .driver_data = (kernel_ulong_t)&default_data,
	},
	{ PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, 0x81c0) },
	{ PCI_DEVICE_DATA(SYNOPSYS, EDDA, NULL) },
	{ PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_AM654),
+26 −3
Original line number Diff line number Diff line
@@ -248,14 +248,37 @@ config PCI_MESON
	  implement the driver.

config PCIE_TEGRA194
	tristate "NVIDIA Tegra194 (and later) PCIe controller"
	tristate

config PCIE_TEGRA194_HOST
	tristate "NVIDIA Tegra194 (and later) PCIe controller - Host Mode"
	depends on ARCH_TEGRA_194_SOC || COMPILE_TEST
	depends on PCI_MSI_IRQ_DOMAIN
	select PCIE_DW_HOST
	select PHY_TEGRA194_P2U
	select PCIE_TEGRA194
	help
	  Enables support for the PCIe controller in the NVIDIA Tegra194 SoC to
	  work in host mode. There are two instances of PCIe controllers in
	  Tegra194. This controller can work either as EP or RC. In order to
	  enable host-specific features PCIE_TEGRA194_HOST must be selected and
	  in order to enable device-specific features PCIE_TEGRA194_EP must be
	  selected. This uses the DesignWare core.

config PCIE_TEGRA194_EP
	tristate "NVIDIA Tegra194 (and later) PCIe controller - Endpoint Mode"
	depends on ARCH_TEGRA_194_SOC || COMPILE_TEST
	depends on PCI_ENDPOINT
	select PCIE_DW_EP
	select PHY_TEGRA194_P2U
	select PCIE_TEGRA194
	help
	  Say Y here if you want support for DesignWare core based PCIe host
	  controller found in NVIDIA Tegra194 SoC.
	  Enables support for the PCIe controller in the NVIDIA Tegra194 SoC to
	  work in host mode. There are two instances of PCIe controllers in
	  Tegra194. This controller can work either as EP or RC. In order to
	  enable host-specific features PCIE_TEGRA194_HOST must be selected and
	  in order to enable device-specific features PCIE_TEGRA194_EP must be
	  selected. This uses the DesignWare core.

config PCIE_UNIPHIER
	bool "Socionext UniPhier PCIe controllers"
+4 −1
Original line number Diff line number Diff line
@@ -959,6 +959,9 @@ static int ks_pcie_am654_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
	case PCI_EPC_IRQ_MSI:
		dw_pcie_ep_raise_msi_irq(ep, func_no, interrupt_num);
		break;
	case PCI_EPC_IRQ_MSIX:
		dw_pcie_ep_raise_msix_irq(ep, func_no, interrupt_num);
		break;
	default:
		dev_err(pci->dev, "UNKNOWN IRQ type\n");
		return -EINVAL;
@@ -970,7 +973,7 @@ static int ks_pcie_am654_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
static const struct pci_epc_features ks_pcie_am654_epc_features = {
	.linkup_notifier = false,
	.msi_capable = true,
	.msix_capable = false,
	.msix_capable = true,
	.reserved_bar = 1 << BAR_0 | 1 << BAR_1,
	.bar_fixed_64bit = 1 << BAR_0,
	.bar_fixed_size[2] = SZ_1M,
+85 −59

File changed.

Preview size limit exceeded, changes collapsed.

Loading