/*
* Microsemi Switchtec(tm) PCIe Management Driver
* Copyright (c) 2017, Microsemi Corporation
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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.
*
*/
#include <linux/switchtec_ioctl.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/poll.h>
#include <linux/pci.h>
#include <linux/cdev.h>
#include <linux/wait.h>
#include <linux/io-64-nonatomic-lo-hi.h>
#include <linux/nospec.h>
MODULE_DESCRIPTION("Microsemi Switchtec(tm) PCIe Management Driver");
MODULE_VERSION("0.1");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Microsemi Corporation");
static int max_devices = 16;
module_param(max_devices, int, 0644);
MODULE_PARM_DESC(max_devices, "max number of switchtec device instances");
static dev_t switchtec_devt;
static struct class *switchtec_class;
static DEFINE_IDA(switchtec_minor_ida);
#define MICROSEMI_VENDOR_ID 0x11f8
#define MICROSEMI_NTB_CLASSCODE 0x068000
#define MICROSEMI_MGMT_CLASSCODE 0x058000
#define SWITCHTEC_MRPC_PAYLOAD_SIZE 1024
#define SWITCHTEC_MAX_PFF_CSR 48
#define SWITCHTEC_EVENT_OCCURRED BIT(0)
#define SWITCHTEC_EVENT_CLEAR BIT(0)
#define SWITCHTEC_EVENT_EN_LOG BIT(1)
#define SWITCHTEC_EVENT_EN_CLI BIT(2)
#define SWITCHTEC_EVENT_EN_IRQ BIT(3)
#define SWITCHTEC_EVENT_FATAL BIT(4)
enum {
SWITCHTEC_GAS_MRPC_OFFSET = 0x0000,
SWITCHTEC_GAS_TOP_CFG_OFFSET = 0x1000,
SWITCHTEC_GAS_SW_EVENT_OFFSET = 0x1800,
SWITCHTEC_GAS_SYS_INFO_OFFSET = 0x2000,
SWITCHTEC_GAS_FLASH_INFO_OFFSET = 0x2200,
SWITCHTEC_GAS_PART_CFG_OFFSET = 0x4000,
SWITCHTEC_GAS_NTB_OFFSET = 0x10000,
SWITCHTEC_GAS_PFF_CSR_OFFSET = 0x134000,
};
struct mrpc_regs {
u8 input_data[SWITCHTEC_MRPC_PAYLOAD_SIZE];
u8 output_data[SWITCHTEC_MRPC_PAYLOAD_SIZE];
u32 cmd;
u32 status;
u32 ret_value;
} __packed;
enum mrpc_status {
SWITCHTEC_MRPC_STATUS_INPROGRESS = 1,
SWITCHTEC_MRPC_STATUS_DONE = 2,
SWITCHTEC_MRPC_STATUS_ERROR = 0xFF,
SWITCHTEC_MRPC_STATUS_INTERRUPTED = 0x100,
};
struct sw_event_regs {
u64 event_report_ctrl;
u64 reserved1;
u64 part_event_bitmap;
u64 reserved2;
u32 global_summary;
u32 reserved3[3];
u32 stack_error_event_hdr;
u32 stack_error_event_data;
u32 reserved4[4];
u32 ppu_error_event_hdr;
u32 ppu_error_event_data;
u32 reserved5[4];
u32 isp_error_event_hdr;
u32 isp_error_event_data;
u32 reserved6[4];
u32 sys_reset_event_hdr;
u32 reserved7[5];
u32 fw_exception_hdr;
u32 reserved8[5];
u32 fw_nmi_hdr;
u32 reserved9[5];
u32 fw_non_fatal_hdr;
u32 reserved10[5];
u32 fw_fatal_hdr;
u32 reserved11[5];
u32 twi_mrpc_comp_hdr;
u32 twi_mrpc_comp_data;
u32 reserved12[4];
u32 twi_mrpc_comp_async_hdr;
u32 twi_mrpc_comp_async_data;
u32 reserved13[4];
u32 cli_mrpc_comp_hdr;
u32 cli_mrpc_comp_data;
u32 reserved14[4];
u32 cli_mrpc_comp_async_hdr;
u32 cli_mrpc_comp_async_data;
u32 reserved15[4];
u32 gpio_interrupt_hdr;
u32 gpio_interrupt_data;
u32 reserved16[4];
} __packed;
enum {
SWITCHTEC_CFG0_RUNNING = 0x04,
SWITCHTEC_CFG1_RUNNING = 0x05,
SWITCHTEC_IMG0_RUNNING = 0x03,
SWITCHTEC_IMG1_RUNNING = 0x07,
};
struct sys_info_regs {
u32 device_id;
u32 device_version;
u32 firmware_version;
u32 reserved1;
u32 vendor_table_revision;
u32 table_format_version;
u32 partition_id;
u32 cfg_file_fmt_version;
u16 cfg_running;
u16 img_running;
u32 reserved2[57];
char vendor_id[8];
char product_id[16];
char product_revision[4];
char component_vendor[8];
u16 component_id;
u8 component_revision;
} __packed;
struct flash_info_regs {
u32 flash_part_map_upd_
|