// SPDX-License-Identifier: GPL-2.0-or-later /* * RapidIO mport driver for Tsi721 PCIExpress-to-SRIO bridge * * Copyright 2011 Integrated Device Technology, Inc. * Alexandre Bounine <[email protected]> * Chul Kim <[email protected]> */ #include <linux/io.h> #include <linux/errno.h> #include <linux/init.h> #include <linux/ioport.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> #include <linux/rio.h> #include <linux/rio_drv.h> #include <linux/dma-mapping.h> #include <linux/interrupt.h> #include <linux/kfifo.h> #include <linux/delay.h> #include "tsi721.h" #ifdef DEBUG u32 tsi_dbg_level; module_param_named(dbg_level, tsi_dbg_level, uint, S_IWUSR | S_IRUGO); MODULE_PARM_DESC(…) …; #endif static int pcie_mrrs = …; module_param(pcie_mrrs, int, S_IRUGO); MODULE_PARM_DESC(…) …; static u8 mbox_sel = …; module_param(mbox_sel, byte, S_IRUGO); MODULE_PARM_DESC(…) …; static DEFINE_SPINLOCK(tsi721_maint_lock); static void tsi721_omsg_handler(struct tsi721_device *priv, int ch); static void tsi721_imsg_handler(struct tsi721_device *priv, int ch); /** * tsi721_lcread - read from local SREP config space * @mport: RapidIO master port info * @index: ID of RapdiIO interface * @offset: Offset into configuration space * @len: Length (in bytes) of the maintenance transaction * @data: Value to be read into * * Generates a local SREP space read. * * Returns: %0 on success or %-EINVAL on failure. */ static int tsi721_lcread(struct rio_mport *mport, int index, u32 offset, int len, u32 *data) { … } /** * tsi721_lcwrite - write into local SREP config space * @mport: RapidIO master port info * @index: ID of RapdiIO interface * @offset: Offset into configuration space * @len: Length (in bytes) of the maintenance transaction * @data: Value to be written * * Generates a local write into SREP configuration space. * * Returns: %0 on success or %-EINVAL on failure. */ static int tsi721_lcwrite(struct rio_mport *mport, int index, u32 offset, int len, u32 data) { … } /** * tsi721_maint_dma - Helper function to generate RapidIO maintenance * transactions using designated Tsi721 DMA channel. * @priv: pointer to tsi721 private data * @sys_size: RapdiIO transport system size * @destid: Destination ID of transaction * @hopcount: Number of hops to target device * @offset: Offset into configuration space * @len: Length (in bytes) of the maintenance transaction * @data: Location to be read from or write into * @do_wr: Operation flag (1 == MAINT_WR) * * Generates a RapidIO maintenance transaction (Read or Write). * Returns: %0 on success and %-EINVAL or %-EFAULT on failure. */ static int tsi721_maint_dma(struct tsi721_device *priv, u32 sys_size, u16 destid, u8 hopcount, u32 offset, int len, u32 *data, int do_wr) { … } /** * tsi721_cread_dma - Generate a RapidIO maintenance read transaction * using Tsi721 BDMA engine. * @mport: RapidIO master port control structure * @index: ID of RapdiIO interface * @destid: Destination ID of transaction * @hopcount: Number of hops to target device * @offset: Offset into configuration space * @len: Length (in bytes) of the maintenance transaction * @data: Location to be read into * * Generates a RapidIO maintenance read transaction. * Returns: %0 on success and %-EINVAL or %-EFAULT on failure. */ static int tsi721_cread_dma(struct rio_mport *mport, int index, u16 destid, u8 hopcount, u32 offset, int len, u32 *data) { … } /** * tsi721_cwrite_dma - Generate a RapidIO maintenance write transaction * using Tsi721 BDMA engine * @mport: RapidIO master port control structure * @index: ID of RapdiIO interface * @destid: Destination ID of transaction * @hopcount: Number of hops to target device * @offset: Offset into configuration space * @len: Length (in bytes) of the maintenance transaction * @data: Value to be written * * Generates a RapidIO maintenance write transaction. * Returns: %0 on success and %-EINVAL or %-EFAULT on failure. */ static int tsi721_cwrite_dma(struct rio_mport *mport, int index, u16 destid, u8 hopcount, u32 offset, int len, u32 data) { … } /** * tsi721_pw_handler - Tsi721 inbound port-write interrupt handler * @priv: tsi721 device private structure * * Handles inbound port-write interrupts. Copies PW message from an internal * buffer into PW message FIFO and schedules deferred routine to process * queued messages. * * Returns: %0 */ static int tsi721_pw_handler(struct tsi721_device *priv) { … } static void tsi721_pw_dpc(struct work_struct *work) { … } /** * tsi721_pw_enable - enable/disable port-write interface init * @mport: Master port implementing the port write unit * @enable: 1=enable; 0=disable port-write message handling * * Returns: %0 */ static int tsi721_pw_enable(struct rio_mport *mport, int enable) { … } /** * tsi721_dsend - Send a RapidIO doorbell * @mport: RapidIO master port info * @index: ID of RapidIO interface * @destid: Destination ID of target device * @data: 16-bit info field of RapidIO doorbell * * Sends a RapidIO doorbell message. * * Returns: %0 */ static int tsi721_dsend(struct rio_mport *mport, int index, u16 destid, u16 data) { … } /** * tsi721_dbell_handler - Tsi721 doorbell interrupt handler * @priv: tsi721 device-specific data structure * * Handles inbound doorbell interrupts. Copies doorbell entry from an internal * buffer into DB message FIFO and schedules deferred routine to process * queued DBs. * * Returns: %0 */ static int tsi721_dbell_handler(struct tsi721_device *priv) { … } static void tsi721_db_dpc(struct work_struct *work) { … } /** * tsi721_irqhandler - Tsi721 interrupt handler * @irq: Linux interrupt number * @ptr: Pointer to interrupt-specific data (tsi721_device structure) * * Handles Tsi721 interrupts signaled using MSI and INTA. Checks reported * interrupt events and calls an event-specific handler(s). * * Returns: %IRQ_HANDLED or %IRQ_NONE */ static irqreturn_t tsi721_irqhandler(int irq, void *ptr) { … } static void tsi721_interrupts_init(struct tsi721_device *priv) { … } #ifdef CONFIG_PCI_MSI /** * tsi721_omsg_msix - MSI-X interrupt handler for outbound messaging * @irq: Linux interrupt number * @ptr: Pointer to interrupt-specific data (tsi721_device structure) * * Handles outbound messaging interrupts signaled using MSI-X. * * Returns: %IRQ_HANDLED */ static irqreturn_t tsi721_omsg_msix(int irq, void *ptr) { … } /** * tsi721_imsg_msix - MSI-X interrupt handler for inbound messaging * @irq: Linux interrupt number * @ptr: Pointer to interrupt-specific data (tsi721_device structure) * * Handles inbound messaging interrupts signaled using MSI-X. * * Returns: %IRQ_HANDLED */ static irqreturn_t tsi721_imsg_msix(int irq, void *ptr) { … } /** * tsi721_srio_msix - Tsi721 MSI-X SRIO MAC interrupt handler * @irq: Linux interrupt number * @ptr: Pointer to interrupt-specific data (tsi721_device structure) * * Handles Tsi721 interrupts from SRIO MAC. * * Returns: %IRQ_HANDLED */ static irqreturn_t tsi721_srio_msix(int irq, void *ptr) { … } /** * tsi721_sr2pc_ch_msix - Tsi721 MSI-X SR2PC Channel interrupt handler * @irq: Linux interrupt number * @ptr: Pointer to interrupt-specific data (tsi721_device structure) * * Handles Tsi721 interrupts from SR2PC Channel. * NOTE: At this moment services only one SR2PC channel associated with inbound * doorbells. * * Returns: %IRQ_HANDLED */ static irqreturn_t tsi721_sr2pc_ch_msix(int irq, void *ptr) { … } /** * tsi721_request_msix - register interrupt service for MSI-X mode. * @priv: tsi721 device-specific data structure * * Registers MSI-X interrupt service routines for interrupts that are active * immediately after mport initialization. Messaging interrupt service routines * should be registered during corresponding open requests. * * Returns: %0 on success or -errno value on failure. */ static int tsi721_request_msix(struct tsi721_device *priv) { … } /** * tsi721_enable_msix - Attempts to enable MSI-X support for Tsi721. * @priv: pointer to tsi721 private data * * Configures MSI-X support for Tsi721. Supports only an exact number * of requested vectors. * * Returns: %0 on success or -errno value on failure. */ static int tsi721_enable_msix(struct tsi721_device *priv) { … } #endif /* CONFIG_PCI_MSI */ static int tsi721_request_irq(struct tsi721_device *priv) { … } static void tsi721_free_irq(struct tsi721_device *priv) { … } static int tsi721_obw_alloc(struct tsi721_device *priv, struct tsi721_obw_bar *pbar, u32 size, int *win_id) { … } static int tsi721_map_outb_win(struct rio_mport *mport, u16 destid, u64 rstart, u32 size, u32 flags, dma_addr_t *laddr) { … } static void tsi721_unmap_outb_win(struct rio_mport *mport, u16 destid, u64 rstart) { … } /** * tsi721_init_pc2sr_mapping - initializes outbound (PCIe->SRIO) * translation regions. * @priv: pointer to tsi721 private data * * Disables SREP translation regions. */ static void tsi721_init_pc2sr_mapping(struct tsi721_device *priv) { … } /** * tsi721_rio_map_inb_mem -- Mapping inbound memory region. * @mport: RapidIO master port * @lstart: Local memory space start address. * @rstart: RapidIO space start address. * @size: The mapping region size. * @flags: Flags for mapping. 0 for using default flags. * * Return: 0 -- Success. * * This function will create the inbound mapping * from rstart to lstart. */ static int tsi721_rio_map_inb_mem(struct rio_mport *mport, dma_addr_t lstart, u64 rstart, u64 size, u32 flags) { … } /** * tsi721_rio_unmap_inb_mem -- Unmapping inbound memory region. * @mport: RapidIO master port * @lstart: Local memory space start address. */ static void tsi721_rio_unmap_inb_mem(struct rio_mport *mport, dma_addr_t lstart) { … } /** * tsi721_init_sr2pc_mapping - initializes inbound (SRIO->PCIe) * translation regions. * @priv: pointer to tsi721 private data * * Disables inbound windows. */ static void tsi721_init_sr2pc_mapping(struct tsi721_device *priv) { … } /* * tsi721_close_sr2pc_mapping - closes all active inbound (SRIO->PCIe) * translation regions. * @priv: pointer to tsi721 device private data */ static void tsi721_close_sr2pc_mapping(struct tsi721_device *priv) { … } /** * tsi721_port_write_init - Inbound port write interface init * @priv: pointer to tsi721 private data * * Initializes inbound port write handler. * Returns: %0 on success or %-ENOMEM on failure. */ static int tsi721_port_write_init(struct tsi721_device *priv) { … } static void tsi721_port_write_free(struct tsi721_device *priv) { … } static int tsi721_doorbell_init(struct tsi721_device *priv) { … } static void tsi721_doorbell_free(struct tsi721_device *priv) { … } /** * tsi721_bdma_maint_init - Initialize maintenance request BDMA channel. * @priv: pointer to tsi721 private data * * Initialize BDMA channel allocated for RapidIO maintenance read/write * request generation * * Returns: %0 on success or %-ENOMEM on failure. */ static int tsi721_bdma_maint_init(struct tsi721_device *priv) { … } static int tsi721_bdma_maint_free(struct tsi721_device *priv) { … } /* Enable Inbound Messaging Interrupts */ static void tsi721_imsg_interrupt_enable(struct tsi721_device *priv, int ch, u32 inte_mask) { … } /* Disable Inbound Messaging Interrupts */ static void tsi721_imsg_interrupt_disable(struct tsi721_device *priv, int ch, u32 inte_mask) { … } /* Enable Outbound Messaging interrupts */ static void tsi721_omsg_interrupt_enable(struct tsi721_device *priv, int ch, u32 inte_mask) { … } /* Disable Outbound Messaging interrupts */ static void tsi721_omsg_interrupt_disable(struct tsi721_device *priv, int ch, u32 inte_mask) { … } /** * tsi721_add_outb_message - Add message to the Tsi721 outbound message queue * @mport: Master port with outbound message queue * @rdev: Target of outbound message * @mbox: Outbound mailbox * @buffer: Message to add to outbound queue * @len: Length of message * * Returns: %0 on success or -errno value on failure. */ static int tsi721_add_outb_message(struct rio_mport *mport, struct rio_dev *rdev, int mbox, void *buffer, size_t len) { … } /** * tsi721_omsg_handler - Outbound Message Interrupt Handler * @priv: pointer to tsi721 private data * @ch: number of OB MSG channel to service * * Services channel interrupts from outbound messaging engine. */ static void tsi721_omsg_handler(struct tsi721_device *priv, int ch) { … } /** * tsi721_open_outb_mbox - Initialize Tsi721 outbound mailbox * @mport: Master port implementing Outbound Messaging Engine * @dev_id: Device specific pointer to pass on event * @mbox: Mailbox to open * @entries: Number of entries in the outbound mailbox ring * * Returns: %0 on success or -errno value on failure. */ static int tsi721_open_outb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entries) { … } /** * tsi721_close_outb_mbox - Close Tsi721 outbound mailbox * @mport: Master port implementing the outbound message unit * @mbox: Mailbox to close */ static void tsi721_close_outb_mbox(struct rio_mport *mport, int mbox) { … } /** * tsi721_imsg_handler - Inbound Message Interrupt Handler * @priv: pointer to tsi721 private data * @ch: inbound message channel number to service * * Services channel interrupts from inbound messaging engine. */ static void tsi721_imsg_handler(struct tsi721_device *priv, int ch) { … } /** * tsi721_open_inb_mbox - Initialize Tsi721 inbound mailbox * @mport: Master port implementing the Inbound Messaging Engine * @dev_id: Device specific pointer to pass on event * @mbox: Mailbox to open * @entries: Number of entries in the inbound mailbox ring * * Returns: %0 on success or -errno value on failure. */ static int tsi721_open_inb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entries) { … } /** * tsi721_close_inb_mbox - Shut down Tsi721 inbound mailbox * @mport: Master port implementing the Inbound Messaging Engine * @mbox: Mailbox to close */ static void tsi721_close_inb_mbox(struct rio_mport *mport, int mbox) { … } /** * tsi721_add_inb_buffer - Add buffer to the Tsi721 inbound message queue * @mport: Master port implementing the Inbound Messaging Engine * @mbox: Inbound mailbox number * @buf: Buffer to add to inbound queue * * Returns: %0 on success or -errno value on failure. */ static int tsi721_add_inb_buffer(struct rio_mport *mport, int mbox, void *buf) { … } /** * tsi721_get_inb_message - Fetch inbound message from the Tsi721 MSG Queue * @mport: Master port implementing the Inbound Messaging Engine * @mbox: Inbound mailbox number * * Returns: pointer to the message on success or %NULL on failure. */ static void *tsi721_get_inb_message(struct rio_mport *mport, int mbox) { … } /** * tsi721_messages_init - Initialization of Messaging Engine * @priv: pointer to tsi721 private data * * Configures Tsi721 messaging engine. * * Returns: %0 */ static int tsi721_messages_init(struct tsi721_device *priv) { … } /** * tsi721_query_mport - Fetch inbound message from the Tsi721 MSG Queue * @mport: Master port implementing the Inbound Messaging Engine * @attr: mport device attributes * * Returns: pointer to the message on success or %NULL on failure. */ static int tsi721_query_mport(struct rio_mport *mport, struct rio_mport_attr *attr) { … } /** * tsi721_disable_ints - disables all device interrupts * @priv: pointer to tsi721 private data */ static void tsi721_disable_ints(struct tsi721_device *priv) { … } static struct rio_ops tsi721_rio_ops = …; static void tsi721_mport_release(struct device *dev) { … } /** * tsi721_setup_mport - Setup Tsi721 as RapidIO subsystem master port * @priv: pointer to tsi721 private data * * Configures Tsi721 as RapidIO master port. * * Returns: %0 on success or -errno value on failure. */ static int tsi721_setup_mport(struct tsi721_device *priv) { … } static int tsi721_probe(struct pci_dev *pdev, const struct pci_device_id *id) { … } static void tsi721_remove(struct pci_dev *pdev) { … } static void tsi721_shutdown(struct pci_dev *pdev) { … } static const struct pci_device_id tsi721_pci_tbl[] = …; MODULE_DEVICE_TABLE(pci, tsi721_pci_tbl); static struct pci_driver tsi721_driver = …; module_pci_driver(…) …; MODULE_DESCRIPTION(…) …; MODULE_AUTHOR(…) …; MODULE_LICENSE(…) …;