瀏覽代碼

PCI: endpoint: Add callbacks for EPF initialization and data transfer

Add a callback to initialize EPF that is specific to EPC and a callback
to perfrom data transfer between EPC and remote PCIe RC. The endpoint
controller driver can use the dmaengine helper functions for data
transfer or have its own implementation of the internal DMA controller
present in PCIe EP.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
Signed-off-by: Sekhar Nori <nsekhar@ti.com>
Kishon Vijay Abraham I 6 年之前
父節點
當前提交
c584dcc1ba
共有 4 個文件被更改,包括 92 次插入0 次删除
  1. 47 0
      drivers/pci/endpoint/pci-epc-core.c
  2. 33 0
      drivers/pci/endpoint/pci-epf-core.c
  3. 10 0
      include/linux/pci-epc.h
  4. 2 0
      include/linux/pci-epf.h

+ 47 - 0
drivers/pci/endpoint/pci-epc-core.c

@@ -135,6 +135,53 @@ const struct pci_epc_features *pci_epc_get_features(struct pci_epc *epc,
 }
 EXPORT_SYMBOL_GPL(pci_epc_get_features);
 
+/**
+ * pci_epc_epf_init() - EPC specific EPF initialization
+ * @epc: the EPC device that initializes the EPF
+ * @epf: the EPF device that has to be initialized
+ *
+ * Invoke to initialize EPF that is specific to a EPC and varies from
+ * platform to platform
+ */
+int pci_epc_epf_init(struct pci_epc *epc, struct pci_epf *epf)
+{
+	int ret;
+
+	if (IS_ERR_OR_NULL(epc) || IS_ERR_OR_NULL(epf))
+		return -EINVAL;
+
+	if (!epc->ops->epf_init)
+		return 0;
+
+	mutex_lock(&epc->lock);
+	ret = epc->ops->epf_init(epc, epf);
+	mutex_unlock(&epc->lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(pci_epc_epf_init);
+
+/**
+ * pci_epc_epf_exit() - Cleanup the EPF initialization
+ * @epc: the EPC device that initialized the EPF
+ * @epf: the EPF device that has to be reset
+ *
+ * Invoke to cleanup the EPF initialization done as part fo pci_epc_epf_init.
+ */
+void pci_epc_epf_exit(struct pci_epc *epc, struct pci_epf *epf)
+{
+	if (IS_ERR_OR_NULL(epc) || IS_ERR_OR_NULL(epf))
+		return;
+
+	if (!epc->ops->epf_exit)
+		return;
+
+	mutex_lock(&epc->lock);
+	epc->ops->epf_exit(epc, epf);
+	mutex_unlock(&epc->lock);
+}
+EXPORT_SYMBOL_GPL(pci_epc_epf_exit);
+
 /**
  * pci_epc_stop() - stop the PCI link
  * @epc: the link of the EPC device that has to be stopped

+ 33 - 0
drivers/pci/endpoint/pci-epf-core.c

@@ -148,6 +148,39 @@ void pci_epf_clean_dma_chan(struct pci_epf *epf)
 }
 EXPORT_SYMBOL_GPL(pci_epf_clean_dma_chan);
 
+/**
+ * pci_epf_tx() - transfer data between EPC and remote PCIe RC
+ * @epf: the EPF device that performs the data transfer operation
+ * @dma_dst: The destination address of the data transfer. It can be a physical
+ *	     address given by pci_epc_mem_alloc_addr or DMA mapping APIs.
+ * @dma_src: The source address of the data transfer. It can be a physical
+ *	     address given by pci_epc_mem_alloc_addr or DMA mapping APIs.
+ * @len: The size of the data transfer
+ *
+ * Invoke to transfer data between EPC and remote PCIe RC. The source and
+ * destination address can be a physical address given by pci_epc_mem_alloc_addr
+ * or the one obtained using DMA mapping APIs.
+ */
+int pci_epf_tx(struct pci_epf *epf, dma_addr_t dma_dst,
+	       dma_addr_t dma_src, size_t len)
+{
+	int ret;
+	struct pci_epc *epc = epf->epc;
+
+	if (IS_ERR_OR_NULL(epc) || IS_ERR_OR_NULL(epf))
+		return -EINVAL;
+
+	if (!epc->ops->data_transfer)
+		return -EINVAL;
+
+	mutex_lock(&epf->lock);
+	ret = epc->ops->data_transfer(epc, epf, dma_dst, dma_src, len);
+	mutex_unlock(&epf->lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(pci_epf_tx);
+
 /**
  * pci_epf_unbind() - Notify the function driver that the binding between the
  *		      EPF device and EPC device has been lost

+ 10 - 0
include/linux/pci-epc.h

@@ -22,6 +22,9 @@ enum pci_epc_irq_type {
 
 /**
  * struct pci_epc_ops - set of function pointers for performing EPC operations
+ * @epf_init: ops to perform EPC specific initialization
+ * @epf_exit: ops to cleanup EPF
+ * @data_transfer: ops to transfer data with the remote RC
  * @write_header: ops to populate configuration space header
  * @set_bar: ops to configure the BAR
  * @clear_bar: ops to reset the BAR
@@ -41,6 +44,11 @@ enum pci_epc_irq_type {
  * @owner: the module owner containing the ops
  */
 struct pci_epc_ops {
+	int	(*epf_init)(struct pci_epc *epc, struct pci_epf *epf);
+	void	(*epf_exit)(struct pci_epc *epc, struct pci_epf *epf);
+	int	(*data_transfer)(struct pci_epc *epc, struct pci_epf *epf,
+				 dma_addr_t dma_dst, dma_addr_t dma_src,
+				 size_t len);
 	int	(*write_header)(struct pci_epc *epc, u8 func_no,
 				struct pci_epf_header *hdr);
 	int	(*set_bar)(struct pci_epc *epc, u8 func_no,
@@ -196,4 +204,6 @@ void __iomem *pci_epc_mem_alloc_addr(struct pci_epc *epc,
 				     phys_addr_t *phys_addr, size_t size);
 void pci_epc_mem_free_addr(struct pci_epc *epc, phys_addr_t phys_addr,
 			   void __iomem *virt_addr, size_t size);
+int pci_epc_epf_init(struct pci_epc *epc, struct pci_epf *epf);
+void pci_epc_epf_exit(struct pci_epc *epc, struct pci_epf *epf);
 #endif /* __LINUX_PCI_EPC_H */

+ 2 - 0
include/linux/pci-epf.h

@@ -165,4 +165,6 @@ int pci_epf_init_dma_chan(struct pci_epf *epf);
 void pci_epf_clean_dma_chan(struct pci_epf *epf);
 int pci_epf_data_transfer(struct pci_epf *epf, dma_addr_t dma_dst,
 			  dma_addr_t dma_src, size_t len);
+int pci_epf_tx(struct pci_epf *epf, dma_addr_t dma_dst, dma_addr_t dma_src,
+	       size_t len);
 #endif /* __LINUX_PCI_EPF_H */