sonic-buildimage/platform/broadcom/saibcm-modules/sdklt/linux/bde/ngbde.h
Mahesh Maddikayala bc2a13136a [BCMSAI] Update BCMSAI debian to 4.3.0.10 with 6.5.21 SDK, and opennsl module to 6.5.21 (#6526)
BCMSAI 4.3.0.10, 6.5.21 SDK release with enhancements and fixes for vxlan, TD3 MMU, TD4-X9 EA support, etc.
2021-02-05 16:08:04 -08:00

837 lines
21 KiB
C

/*! \file ngbde.h
*
* Shared definitions and APIs for NGBDE kernel module.
*
*/
/*
* $Copyright: Copyright 2018-2020 Broadcom. All rights reserved.
* The term 'Broadcom' refers to Broadcom Inc. and/or its subsidiaries.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* A copy of the GNU General Public License version 2 (GPLv2) can
* be found in the LICENSES folder.$
*/
#ifndef NGBDE_H
#define NGBDE_H
#include <lkm/lkm.h>
#include <lkm/ngbde_kapi.h>
/*! Module name. */
#define MOD_NAME "linux_ngbde"
/*! Major number for associated charcter device file. */
#define MOD_MAJOR 120
/*! Read memory-mapped device register without byte-swap. */
#define NGBDE_IOREAD32(_a) __raw_readl(_a)
/*! Write memory-mapped device register without byte-swap. */
#define NGBDE_IOWRITE32(_v, _a) __raw_writel(_v, _a)
/*! Maximum number of I/O windows supported per device. */
#define NGBDE_NUM_IOWIN_MAX 3
/*! Maximum number of DMA memory pools supported per device. */
#define NGBDE_NUM_DMAPOOL_MAX 2
/*! Maximum number of IRQ status registers per interrupt source. */
#define NGBDE_NUM_IRQ_REGS_MAX 16
/*! Maximum number of IRQ lines (MSI vectors) per device. */
#define NGBDE_NUM_IRQS_MAX 1
/*!
* Maximum number of interrupt controller registers which may be
* written from both a user mode driver and a kernel mode driver.
*
* This feature is used when the kernel mode driver owns a subset of
* bits within a register, which is also used by the user mode driver.
*
* Both drivers must access such registers through a lock-protected
* access function.
*/
#define NGBDE_NUM_INTR_SHR_REGS_MAX 1
/*! I/O memory window definition. */
struct ngbde_memwin_s {
/*! Physical address of I/O window. */
phys_addr_t addr;
/*! Size of I/O window (in bytes). */
phys_addr_t size;
};
/*!
* \brief Shared register value.
*
* This structure contains the current value of a register where user
* mode and kernel mode owns different bits within the same
* register. In this case access must be carefully controlled to avoid
* that one context overwrites the bits owned by the other context.
*
* The structure also contains the offset of the shared register in
* order to identify the register (in case there is more than one
* shared register).
*/
typedef struct ngbde_shr_reg_s {
/*! Offset of the shared register. */
uint32_t reg_offs;
/*! Current value of the shared register. */
uint32_t cur_val;
} ngbde_shr_reg_t;
/*!
* \brief Shared interrupt mask register control.
*
* This defines which bits of an interrupt mask register are owned by
* user mode context, and which are owned by kernel context.
*
* The structure contains the corresponding interrupt status register
* in order to allow identification of the interrupt mask register
* irrespective of the host CPU being used.
*
* For example, if the host CPU is connected via PCI, then we use one
* mask register, but if the host CPU is an embedded ARM CPU, then we
* use a different mask register (for the same interrupt status
* register). By using the status register to identify the shared mask
* register, the kernel mode driver does not need to know which host
* CPU it is running off.
*/
typedef struct ngbde_irq_reg_s {
/*! Interrupt status register corresponding to the mask register. */
uint32_t status_reg;
/*! Shared interrupt mask register. */
uint32_t mask_reg;
/*! Mask identifying the register bits owned by the kernel mode driver. */
uint32_t kmask;
} ngbde_irq_reg_t;
/*!
* \name Interrupt ACK register access flags.
* \anchor NGBDE_INTR_ACK_F_xxx
*/
/*! \{ */
/*! ACK registers resides in PCI bridge I/O window. */
#define NGBDE_INTR_ACK_F_PAXB (1 << 0)
/*! \} */
/*!
* \brief Interrupt ACK register control.
*
* The structure contains the corresponding register offset
* and value in order to acknowledge interrupt in kernel driver.
*
* For example, if the host CPU is connected via PCI, then we use one
* ACK register, but if the host CPU is an embedded ARM CPU, then we
* use a different ACK register.
*/
typedef struct ngbde_intr_ack_reg_s {
/*! Ack register offset. */
uint32_t ack_reg;
/*! Ack value. */
uint32_t ack_val;
/*! Flags to indicate ack_reg resides in PCI bridge window. */
uint32_t flags;
} ngbde_intr_ack_reg_t;
/*!
* \brief BDE interrupt handler.
*
* The BDE will use a function of this type to register an interrupt
* handler with the Linux kernel.
*
* \param [in] data Interrupt handler context.
*
* \retval 0 Interrupt not recognized.
* \retval 1 Interrupt recognized and handled.
*/
typedef int (*ngbde_isr_f)(void *data);
/*!
* \brief Kernel interrupt control.
*
* This structure controls the sharing of interrupt processing between
* a user mode thread and a kernel mode interrupt handler.
*/
typedef struct ngbde_intr_ctrl_s {
/*! Handle for device I/O (for writing interrupt registers). */
uint8_t *iomem;
/*! Kernel device number (similar to user mode unit number). */
int kdev;
/*! Indicates that our interrupt handler is connected to the kernel. */
int irq_active;
/*! Interrupt number (IRQ# or MSI vector). */
int irq_vect;
/*! Number of interrupt status/mask register pairs. */
int num_regs;
/*! Interrupt status/mask register pairs for this device. */
ngbde_irq_reg_t regs[NGBDE_NUM_IRQ_REGS_MAX];
/*! Interrupt ACK register/value for this device. */
ngbde_intr_ack_reg_t intr_ack;
/*! Wait queue for user mode interrupt thread. */
wait_queue_head_t user_thread_wq;
/*! Flag to wake up user mode interrupt thread. */
atomic_t run_user_thread;
/*! Primary interrupt handler. */
ngbde_isr_f isr_func;
/*! Context for primary interrupt handler. */
void *isr_data;
} ngbde_intr_ctrl_t;
/*! Convenience macro for 1 kilobyte. */
#define ONE_KB 1024
/*! Convenience macro for 1 megabyte. */
#define ONE_MB (1024*1024)
/*!
* \name DMA allocation types.
* \anchor NGBDE_DMA_T_xxx
*/
/*! \{ */
/*!
* Do not allocate any DMA memory.
*/
#define NGBDE_DMA_T_NONE 0
/*!
* Try different allocation methods until DMA memory is successfully
* allocated.
*/
#define NGBDE_DMA_T_AUTO 1
/*! Use kernel DMA API (dma_alloc_coherent). */
#define NGBDE_DMA_T_KAPI 2
/*! Use page allocator and map to physical address manually. */
#define NGBDE_DMA_T_PGMEM 3
/*! \} */
/*! DMA memory allocation control structure. */
typedef struct ngbde_dmactrl_s {
/*! Requested size of DMA memory block (in bytes). */
size_t size;
/*! Kernel flags for memory allocation. */
gfp_t flags;
/*! Preferred DMA memory type (NGBDE_DMA_T_xxx). */
int pref_type;
/*! Kernel device for DMA memory management. */
struct device *dev;
} ngbde_dmactrl_t;
/*! DMA memory descriptor. */
typedef struct ngbde_dmamem_s {
/*! Logical address of DMA memory block. */
void *vaddr;
/*! Physical address of DMA memory block. */
dma_addr_t paddr;
/*! Bus address of DMA memory block. */
dma_addr_t baddr;
/*! Actual size of DMA memory block (in bytes). */
size_t size;
/*! Actual DMA memory type (NGBDE_DMA_T_xxx). */
int type;
/*! Kernel device for DMA memory management. */
struct device *dev;
} ngbde_dmamem_t;
/*! DMA memory pool. */
typedef struct ngbde_dmapool_s {
/*! DMA control parameters. */
struct ngbde_dmactrl_s dmactrl;
/*! DMA memory resources. */
struct ngbde_dmamem_s dmamem;
} ngbde_dmapool_t;
/*! Switch device descriptor. */
struct ngbde_dev_s {
/*! Vendor ID (typically PCI vendor ID). */
uint16_t vendor_id;
/*! Device ID (typically PCI device ID). */
uint16_t device_id;
/*! Device revision (typically PCI revision). */
uint16_t revision;
/*! Additional device identification when primary ID is not unique. */
uint16_t model;
/*! Bus number (typically PCI bus number). */
int bus_no;
/*! Slot number (typically PCI slot number). */
int slot_no;
/*! Interrupt line associated with this device. */
int irq_line;
/*! Use MSI interrupts with this device. */
int use_msi;
/*! Non-zero if device was removed. */
int inactive;
/*! Physical I/O window for kernel driver device access. */
struct ngbde_memwin_s pio_win;
/*! Memory mapped I/O window for kernel driver device access. */
uint8_t *pio_mem;
/*! Physical I/O window for interrupt controller access. */
struct ngbde_memwin_s iio_win;
/*! Memory mapped I/O window for interrupt controller access. */
uint8_t *iio_mem;
/*! Physical I/O window for device PCI bridge access. */
struct ngbde_memwin_s paxb_win;
/*! Memory mapped I/O window for device PCI bridge access. */
uint8_t *paxb_mem;
/*! Current value of shared register (typically an IRQ mask register). */
struct ngbde_shr_reg_s intr_shr_reg[NGBDE_NUM_INTR_SHR_REGS_MAX];
/*! Lock for shared register synchronization. */
spinlock_t lock;
/*! Interrupt control information. */
struct ngbde_intr_ctrl_s intr_ctrl[NGBDE_NUM_IRQS_MAX];
/*! Linux PCI handle. */
struct pci_dev *pci_dev;
/*! Kernel device for DMA memory management. */
struct device *dma_dev;
/*! Physical device I/O. */
struct ngbde_memwin_s iowin[NGBDE_NUM_IOWIN_MAX];
/*! DMA memory pools. */
struct ngbde_dmapool_s dmapool[NGBDE_NUM_DMAPOOL_MAX];
};
/*!
* \brief Linux IOCTL handler.
*
* This function handles communication between user mode and kernel
* mode.
*
* \param [in] file Device file handle.
* \param [in] cmd IOCTL command.
* \param [in] arg IOCTL command argument.
*
* \retval 0 No errors
*/
extern long
ngbde_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
/*!
* \brief Initialize procfs for BDE driver.
*
* Create procfs read interface for dumping probe information.
*
* \return 0 if no errors, otherwise -1.
*/
extern int
ngbde_procfs_init(void);
/*!
* \brief Clean up procfs for BDE driver.
*
* Clean up resources allocated by \ref ngbde_procfs_init.
*
* \return 0 if no errors, otherwise -1.
*/
extern int
ngbde_procfs_cleanup(void);
/*!
* \brief Allocate DMA memory pools for all probed devices.
*
* \return 0 if no errors, otherwise -1.
*/
extern int
ngbde_dma_init(void);
/*!
* \brief Free DMA memory pools for all probed devices.
*
* \return Nothing.
*/
extern void
ngbde_dma_cleanup(void);
/*!
* \brief Connect to hardware interrupt handler.
*
* \param [in] kdev Device number.
* \param [in] irq_num Interrupt number (MSI vector).
*
* \retval 0 No errors
* \retval -1 Something went wrong.
*/
extern int
ngbde_intr_connect(int kdev, unsigned int irq_num);
/*!
* \brief Disconnect from hardware interrupt handler.
*
* \param [in] kdev Device number.
* \param [in] irq_num Interrupt number (MSI vector).
*
* \retval 0 No errors
* \retval -1 Something went wrong.
*/
extern int
ngbde_intr_disconnect(int kdev, unsigned int irq_num);
/*!
* \brief Disconnect from all hardware interrupt handlers.
*/
void
ngbde_intr_cleanup(void);
/*!
* \brief Wait for hardware interrupt.
*
* A user mode thread will call this function and sleep until a
* hardware interrupt occurs.
*
* \param [in] kdev Device number.
* \param [in] irq_num Interrupt number (MSI vector).
*
* \retval 0 No errors
* \retval -1 Something went wrong.
*/
extern int
ngbde_intr_wait(int kdev, unsigned int irq_num);
/*!
* \brief Wake up sleeping interrupt thread.
*
* Wake up interrupt thread even if no interrupt has occurred.
*
* Intended for graceful shut-down procedure.
*
* \param [in] kdev Device number.
* \param [in] irq_num Interrupt number (MSI vector).
*
* \retval 0 No errors
* \retval -1 Something went wrong.
*/
extern int
ngbde_intr_stop(int kdev, unsigned int irq_num);
/*!
* \brief Clear list of interrupt status/mask registers.
*
* This function is typically called before new interrupt register
* information is added.
*
* \param [in] kdev Device number.
* \param [in] irq_num Interrupt number (MSI vector).
*
* \retval 0 No errors
* \retval -1 Something went wrong.
*/
extern int
ngbde_intr_regs_clr(int kdev, unsigned int irq_num);
/*!
* \brief Add interrupt status/mask register to monitor.
*
* This function adds a new interrupt status/mask register set to the
* list of registers monitored by the user-mode interrupt handler.
*
* The register list is used to determine whether a user-mode
* interrupt has occurred.
*
* See also \ref ngbde_intr_regs_clr.
*
* \param [in] kdev Device number.
* \param [in] irq_num Interrupt number (MSI vector).
* \param [in] ireg Interrupt status/mask register information.
*
* \retval 0 No errors
* \retval -1 Something went wrong.
*/
extern int
ngbde_intr_reg_add(int kdev, unsigned int irq_num,
struct ngbde_irq_reg_s *ireg);
/*!
* \brief Add interrupt ack register to monitor.
*
* This function adds a interrupt register and mask value
* to acknowledge corresponding irq_num.
*
* \param [in] kdev Device number.
* \param [in] irq_num Interrupt number (MSI vector).
* \param [in] ackreg Interrupt ack register information.
*
* \retval 0 No errors
* \retval -1 Something went wrong.
*/
extern int
ngbde_intr_ack_reg_add(int kdev, unsigned int irq_num,
struct ngbde_intr_ack_reg_s *ackreg);
/*!
* \brief Write shared interrupt mask register.
*
* This function is used by an interrupt handler when a shared
* interrupt mask register needs to be updated.
*
* Since the register is shared between multiple interrupt handlers,
* access must be protected by a lock.
*
* The register information provided via \ref ngbde_intr_reg_add is
* used to detemine which bits of the mask register belong to the user
* mode driver.
*
* Note that the mask register to access is referenced by the
* corresponding status register. This is because the mask register
* may be different depending on the host CPU interface being used
* (e.g. PCI vs. AXI). On the other hand, the status register is the
* same irrespective of the host CPU interface.
*
* \param [in] kdev Device number.
* \param [in] irq_num Interrupt number (MSI vector).
* \param [in] kapi Must be set to 1 if called from kernel API.
* \param [in] status_reg Corresponding interrupt status register offset.
* \param [in] mask_val New value to write to mask register.
*
* \retval 0 No errors
* \retval -1 Something went wrong.
*/
extern int
ngbde_intr_mask_write(int kdev, unsigned int irq_num, int kapi,
uint32_t status_reg, uint32_t mask_val);
/*!
* \brief Probe for PCI-attached Broadcom switch devices.
*
* \return 0 if no errors, otherwise -1.
*/
extern int
ngbde_pci_probe(void);
/*!
* \brief Clean up resources for PCI-attached Broadcom switch devices.
*
* \return 0 if no errors, otherwise -1.
*/
extern int
ngbde_pci_cleanup(void);
/*!
* \brief Add new switch device to BDE database.
*
* Add device information for probed or fixed switch device.
*
* \param [in] nd Switch device information.
*
* \return 0 if no errors, otherwise -1.
*/
extern int
ngbde_swdev_add(struct ngbde_dev_s *nd);
/*!
* \brief Get device information for a BDE switch device.
*
* \param [in] kdev Switch device number.
*
* \return Pointer to switch device structure or NULL on error.
*/
struct ngbde_dev_s *
ngbde_swdev_get(int kdev);
/*!
* \brief Get list of all probed switch devices.
*
* Return a pointer to the array of registered switch devices.
*
* \param [out] nd Pointer to array of switch devices.
* \param [in] num_nd number of valid entries in switch device array.
*
* \retval 0 No errors
*/
extern int
ngbde_swdev_get_all(struct ngbde_dev_s **nd, unsigned int *num_nd);
/*!
* \brief Allocate memory using page allocator
*
* For any sizes less than MEM_CHUNK_SIZE, we ask the page allocator
* for the entire memory block, otherwise we try to assemble a
* contiguous cmblock ourselves.
*
* Upon successful allocation, the memory block will be added to the
* global list of allocated memory blocks.
*
* \param [in] size Number of bytes to allocate.
* \param [in] flags Kernel flags (GFP_xxx) for memory allocation.
*
* \return Pointer to allocated memory or NULL if failure.
*/
void *
ngbde_pgmem_alloc(size_t size, gfp_t flags);
/*!
* \brief Free memory block allocated by ngbde_pgmem_alloc.
*
* \param [in] ptr Pointer returned by ngbde_pgmem_alloc.
*
* \return 0 if succesfully freed, otherwise -1.
*/
extern int
ngbde_pgmem_free(void *ptr);
/*!
* \brief Free all memory blocks allocated by ngbde_pgmem_alloc.
*
* This function will walk the global list of allocated memory blocks
* and free all associated resources.
*
* Intended for a full clean up before the module is unloaded.
*
* \return Nothing.
*/
extern void
ngbde_pgmem_free_all(void);
/*!
* \brief Map I/O memory in kernel driver.
*
* This function is used to provide device I/O access to a kernel mode
* driver.
*
* \param [in] devh Device handle (\ref ngbde_dev_s).
* \param [in] addr Physical address to map.
* \param [in] size Size of I/O window to map.
*
* \return Pointer to mapped I/O memory, or NULL on error.
*/
extern void *
ngbde_pio_map(void *devh, phys_addr_t addr, phys_addr_t size);
/*!
* \brief Unmap I/O memory in kernel driver.
*
* Unmap I/O memory previously mapped via \ref ngbde_pio_map.
*
* \param [in] devh Device handle (\ref ngbde_dev_s).
*
* \return Nothing.
*/
extern void
ngbde_pio_unmap(void *devh);
/*!
* \brief Unmap all I/O windows.
*/
extern void
ngbde_pio_cleanup(void);
/*!
* \brief Write a memory-mapped register from kernel driver.
*
* Write a 32-bit register using I/O memory previously mapped via \ref
* ngbde_pio_map.
*
* \param [in] devh Device handle (\ref ngbde_dev_s).
* \param [in] offs Register address offset.
* \param [in] val Value to write to register.
*
* \return Nothing.
*/
extern void
ngbde_pio_write32(void *devh, uint32_t offs, uint32_t val);
/*!
* \brief Read a memory-mapped register from kernel driver.
*
* Read a 32-bit register using I/O memory previously mapped via \ref
* ngbde_pio_map.
*
* \param [in] devh Device handle (\ref ngbde_dev_s).
* \param [in] offs Register address offset.
*
* \return Value read from register.
*/
extern uint32_t
ngbde_pio_read32(void *devh, uint32_t offs);
/*!
* \brief Map interrupt controller I/O memory.
*
* On some devices the interrupt controller is a device separate from
* the main switch device. This function is used to provide interrupt
* controller I/O access to a kernel mode driver.
*
* \param [in] devh Device handle (\ref ngbde_dev_s).
* \param [in] addr Physical address to map.
* \param [in] size Size of I/O window to map.
*
* \return Pointer to mapped I/O memory, or NULL on error.
*/
extern void *
ngbde_iio_map(void *devh, phys_addr_t addr, phys_addr_t size);
/*!
* \brief Unmap interrupt controller I/O memory.
*
* Unmap I/O memory previously mapped via \ref ngbde_iio_map.
*
* \param [in] devh Device handle (\ref ngbde_dev_s).
*
* \return Nothing.
*/
extern void
ngbde_iio_unmap(void *devh);
/*!
* \brief Unmap all interrupt controller I/O windows.
*/
extern void
ngbde_iio_cleanup(void);
/*!
* \brief Write a memory-mapped interrupt controller register.
*
* Write a 32-bit register using I/O memory previously mapped via \ref
* ngbde_iio_map.
*
* \param [in] devh Device handle (\ref ngbde_dev_s).
* \param [in] offs Register address offset.
* \param [in] val Value to write to register.
*
* \return Nothing.
*/
extern void
ngbde_iio_write32(void *devh, uint32_t offs, uint32_t val);
/*!
* \brief Read a memory-mapped interrupt controller register.
*
* Read a 32-bit register using I/O memory previously mapped via \ref
* ngbde_iio_map.
*
* \param [in] devh Device handle (\ref ngbde_dev_s).
* \param [in] offs Register address offset.
*
* \return Value read from register.
*/
extern uint32_t
ngbde_iio_read32(void *devh, uint32_t offs);
/*!
* \brief Map PCI bridge I/O memory.
*
* On some devices the interrupt controller is a device separate from
* the main switch device. This function is used to provide interrupt
* controller I/O access to a kernel mode driver.
*
* \param [in] devh Device handle (\ref ngbde_dev_s).
* \param [in] addr Physical address to map.
* \param [in] size Size of I/O window to map.
*
* \return Pointer to mapped I/O memory, or NULL on error.
*/
extern void *
ngbde_paxb_map(void *devh, phys_addr_t addr, phys_addr_t size);
/*!
* \brief Unmap PCI bridge I/O memory.
*
* Unmap I/O memory previously mapped via \ref ngbde_paxb_map.
*
* \param [in] devh Device handle (\ref ngbde_dev_s).
*
* \return Nothing.
*/
extern void
ngbde_paxb_unmap(void *devh);
/*!
* \brief Unmap all PCI bridge I/O windows.
*/
extern void
ngbde_paxb_cleanup(void);
/*!
* \brief Probe for Broadcom switch devices on IPROC internal bus.
*
* \return 0 if no errors, otherwise -1.
*/
extern int
ngbde_iproc_probe(void);
/*!
* \brief Clean up resources for Broadcom switch devices on IPROC internal bus.
*
* \return 0 if no errors, otherwise -1.
*/
extern int
ngbde_iproc_cleanup(void);
#endif /* NGBDE_H */