pcie: endpoint: Add public APIs for PCIe endpoint driver

Add public APIs for PCIe endpoint driver:
- EP configuration space read/write
- Mapping/Unmapping of Host buffer and PCIe outbound region
- Raise interrupt to Host
These are minimal base APIs to make PCIe EP functional.

Also, add a Kconfig and an empty CMakeLists.txt for drivers to extend.

Signed-off-by: Abhishek Shah <abhishek.shah@broadcom.com>
This commit is contained in:
Abhishek Shah 2020-05-04 12:37:34 +05:30 committed by Andrew Boie
commit ca17315d7f
5 changed files with 177 additions and 0 deletions

View file

@ -1,3 +1,5 @@
zephyr_sources(pcie.c)
zephyr_sources_ifdef(CONFIG_PCIE_MSI msi.c)
zephyr_sources_ifdef(CONFIG_PCIE_SHELL shell.c)
add_subdirectory_ifdef(CONFIG_PCIE_ENDPOINT endpoint)

View file

@ -24,4 +24,6 @@ config PCIE_SHELL
help
Enable commands for debugging PCI(e) using the built-in shell.
source "drivers/pcie/endpoint/Kconfig"
endif # PCIE

View file

@ -0,0 +1 @@
# SPDX-License-Identifier: Apache-2.0

View file

@ -0,0 +1,9 @@
# PCIe Endpoint configuration options
# Copyright 2020 Broadcom
# SPDX-License-Identifier: Apache-2.0
menuconfig PCIE_ENDPOINT
bool "Enable PCIe Endpoint support"
help
This option enables PCIe Endpoint support.

View file

@ -0,0 +1,163 @@
/**
* @file
*
* @brief Public APIs for the PCIe EP drivers.
*/
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright 2020 Broadcom
*
*/
#ifndef ZEPHYR_INCLUDE_DRIVERS_PCIE_EP_H_
#define ZEPHYR_INCLUDE_DRIVERS_PCIE_EP_H_
#include <device.h>
#include <init.h>
#include <kernel.h>
#include <stdint.h>
enum pcie_ob_mem_type {
PCIE_OB_ANYMEM, /**< PCIe OB window within any address range */
PCIE_OB_LOWMEM, /**< PCIe OB window within 32-bit address range */
PCIE_OB_HIGHMEM, /**< PCIe OB window above 32-bit address range */
};
enum pci_ep_irq_type {
PCIE_EP_IRQ_LEGACY, /**< Raise Legacy interrupt */
PCIE_EP_IRQ_MSI, /**< Raise MSI interrupt */
PCIE_EP_IRQ_MSIX, /**< Raise MSIX interrupt */
};
struct pcie_ep_driver_api {
int (*conf_read)(struct device *dev, uint32_t offset, uint32_t *data);
void (*conf_write)(struct device *dev, uint32_t offset, uint32_t data);
int (*map_addr)(struct device *dev, uint64_t pcie_addr,
uint64_t *mapped_addr, uint32_t size,
enum pcie_ob_mem_type ob_mem_type);
void (*unmap_addr)(struct device *dev, uint64_t mapped_addr);
int (*raise_irq)(struct device *dev, enum pci_ep_irq_type irq_type,
uint32_t irq_num);
};
/**
* @brief Read PCIe EP configuration space
*
* @details This API reads EP's own configuration space
*
* @param dev Pointer to the device structure for the driver instance
* @param offset Offset within configuration space
* @param data Pointer to data read from the offset
*
* @return 0 if successful, negative errno code if failure.
*/
static inline int pcie_ep_conf_read(struct device *dev,
uint32_t offset, uint32_t *data)
{
const struct pcie_ep_driver_api *api =
(const struct pcie_ep_driver_api *)dev->driver_api;
return api->conf_read(dev, offset, data);
}
/**
* @brief Write PCIe EP configuration space
*
* @details This API writes EP's own configuration space
*
* @param dev Pointer to the device structure for the driver instance
* @param offset Offset within configuration space
* @param data Data to be written at the offset
*
* @return N/A
*/
static inline void pcie_ep_conf_write(struct device *dev,
uint32_t offset, uint32_t data)
{
const struct pcie_ep_driver_api *api =
(const struct pcie_ep_driver_api *)dev->driver_api;
api->conf_write(dev, offset, data);
}
/**
* @brief Map a host memory buffer to PCIe outbound region
*
* @details This API maps a host memory buffer to PCIe outbound region,
* It is left to EP driver to manage multiple mappings through
* multiple PCIe outbound regions if supported by SoC
*
* @param dev Pointer to the device structure for the driver instance
* @param pcie_addr Host memory buffer address to be mapped
* @param mapped_addr Mapped PCIe outbound region address
* @param size Host memory buffer size (bytes)
* @param ob_mem_type Hint if lowmem/highmem outbound region has to be used,
* this is useful in cases where bus master cannot generate
* more than 32-bit address; it becomes essential to use
* lowmem outbound region
*
* @return Mapped size : If mapped size is less than requested size,
* then requestor has to call the same API again to map
* the unmapped host buffer after data transfer is done with
* mapped size. This situation may arise because of the
* mapping alignment requirements.
*
* @return Negative errno code if failure.
*/
static inline int pcie_ep_map_addr(struct device *dev, uint64_t pcie_addr,
uint64_t *mapped_addr, uint32_t size,
enum pcie_ob_mem_type ob_mem_type)
{
const struct pcie_ep_driver_api *api =
(const struct pcie_ep_driver_api *)dev->driver_api;
return api->map_addr(dev, pcie_addr, mapped_addr, size, ob_mem_type);
}
/**
* @brief Remove mapping to PCIe outbound region
*
* @details This API removes mapping to PCIe outbound region.
* Mapped PCIe outbound region address is given as argument
* to figure out the outbound region to be unmapped
*
* @param dev Pointer to the device structure for the driver instance
* @param mapped_addr PCIe outbound region address
*
* @return N/A
*/
static inline void pcie_ep_unmap_addr(struct device *dev, uint64_t mapped_addr)
{
const struct pcie_ep_driver_api *api =
(const struct pcie_ep_driver_api *)dev->driver_api;
api->unmap_addr(dev, mapped_addr);
}
/**
* @brief Raise interrupt to Host
*
* @details This API raises interrupt to Host
*
* @param dev Pointer to the device structure for the driver instance
* @param irq_type Type of Interrupt be raised (legacy, MSI or MSI-X)
* @param irq_num MSI or MSI-X interrupt number
*
* @return 0 if successful, negative errno code if failure.
*/
static inline int pcie_ep_raise_irq(struct device *dev,
enum pci_ep_irq_type irq_type,
uint32_t irq_num)
{
const struct pcie_ep_driver_api *api =
(const struct pcie_ep_driver_api *)dev->driver_api;
return api->raise_irq(dev, irq_type, irq_num);
}
#endif /* ZEPHYR_INCLUDE_DRIVERS_PCIE_EP_H_ */