1*080b47deSLogan Gunthorpe /* 2*080b47deSLogan Gunthorpe * Microsemi Switchtec(tm) PCIe Management Driver 3*080b47deSLogan Gunthorpe * Copyright (c) 2017, Microsemi Corporation 4*080b47deSLogan Gunthorpe * 5*080b47deSLogan Gunthorpe * This program is free software; you can redistribute it and/or modify it 6*080b47deSLogan Gunthorpe * under the terms and conditions of the GNU General Public License, 7*080b47deSLogan Gunthorpe * version 2, as published by the Free Software Foundation. 8*080b47deSLogan Gunthorpe * 9*080b47deSLogan Gunthorpe * This program is distributed in the hope it will be useful, but WITHOUT 10*080b47deSLogan Gunthorpe * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11*080b47deSLogan Gunthorpe * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12*080b47deSLogan Gunthorpe * more details. 13*080b47deSLogan Gunthorpe * 14*080b47deSLogan Gunthorpe */ 15*080b47deSLogan Gunthorpe 16*080b47deSLogan Gunthorpe #include <linux/interrupt.h> 17*080b47deSLogan Gunthorpe #include <linux/module.h> 18*080b47deSLogan Gunthorpe #include <linux/fs.h> 19*080b47deSLogan Gunthorpe #include <linux/uaccess.h> 20*080b47deSLogan Gunthorpe #include <linux/poll.h> 21*080b47deSLogan Gunthorpe #include <linux/pci.h> 22*080b47deSLogan Gunthorpe #include <linux/cdev.h> 23*080b47deSLogan Gunthorpe #include <linux/wait.h> 24*080b47deSLogan Gunthorpe 25*080b47deSLogan Gunthorpe MODULE_DESCRIPTION("Microsemi Switchtec(tm) PCIe Management Driver"); 26*080b47deSLogan Gunthorpe MODULE_VERSION("0.1"); 27*080b47deSLogan Gunthorpe MODULE_LICENSE("GPL"); 28*080b47deSLogan Gunthorpe MODULE_AUTHOR("Microsemi Corporation"); 29*080b47deSLogan Gunthorpe 30*080b47deSLogan Gunthorpe static int max_devices = 16; 31*080b47deSLogan Gunthorpe module_param(max_devices, int, 0644); 32*080b47deSLogan Gunthorpe MODULE_PARM_DESC(max_devices, "max number of switchtec device instances"); 33*080b47deSLogan Gunthorpe 34*080b47deSLogan Gunthorpe static dev_t switchtec_devt; 35*080b47deSLogan Gunthorpe static struct class *switchtec_class; 36*080b47deSLogan Gunthorpe static DEFINE_IDA(switchtec_minor_ida); 37*080b47deSLogan Gunthorpe 38*080b47deSLogan Gunthorpe #define MICROSEMI_VENDOR_ID 0x11f8 39*080b47deSLogan Gunthorpe #define MICROSEMI_NTB_CLASSCODE 0x068000 40*080b47deSLogan Gunthorpe #define MICROSEMI_MGMT_CLASSCODE 0x058000 41*080b47deSLogan Gunthorpe 42*080b47deSLogan Gunthorpe #define SWITCHTEC_MRPC_PAYLOAD_SIZE 1024 43*080b47deSLogan Gunthorpe #define SWITCHTEC_MAX_PFF_CSR 48 44*080b47deSLogan Gunthorpe 45*080b47deSLogan Gunthorpe #define SWITCHTEC_EVENT_OCCURRED BIT(0) 46*080b47deSLogan Gunthorpe #define SWITCHTEC_EVENT_CLEAR BIT(0) 47*080b47deSLogan Gunthorpe #define SWITCHTEC_EVENT_EN_LOG BIT(1) 48*080b47deSLogan Gunthorpe #define SWITCHTEC_EVENT_EN_CLI BIT(2) 49*080b47deSLogan Gunthorpe #define SWITCHTEC_EVENT_EN_IRQ BIT(3) 50*080b47deSLogan Gunthorpe #define SWITCHTEC_EVENT_FATAL BIT(4) 51*080b47deSLogan Gunthorpe 52*080b47deSLogan Gunthorpe enum { 53*080b47deSLogan Gunthorpe SWITCHTEC_GAS_MRPC_OFFSET = 0x0000, 54*080b47deSLogan Gunthorpe SWITCHTEC_GAS_TOP_CFG_OFFSET = 0x1000, 55*080b47deSLogan Gunthorpe SWITCHTEC_GAS_SW_EVENT_OFFSET = 0x1800, 56*080b47deSLogan Gunthorpe SWITCHTEC_GAS_SYS_INFO_OFFSET = 0x2000, 57*080b47deSLogan Gunthorpe SWITCHTEC_GAS_FLASH_INFO_OFFSET = 0x2200, 58*080b47deSLogan Gunthorpe SWITCHTEC_GAS_PART_CFG_OFFSET = 0x4000, 59*080b47deSLogan Gunthorpe SWITCHTEC_GAS_NTB_OFFSET = 0x10000, 60*080b47deSLogan Gunthorpe SWITCHTEC_GAS_PFF_CSR_OFFSET = 0x134000, 61*080b47deSLogan Gunthorpe }; 62*080b47deSLogan Gunthorpe 63*080b47deSLogan Gunthorpe struct mrpc_regs { 64*080b47deSLogan Gunthorpe u8 input_data[SWITCHTEC_MRPC_PAYLOAD_SIZE]; 65*080b47deSLogan Gunthorpe u8 output_data[SWITCHTEC_MRPC_PAYLOAD_SIZE]; 66*080b47deSLogan Gunthorpe u32 cmd; 67*080b47deSLogan Gunthorpe u32 status; 68*080b47deSLogan Gunthorpe u32 ret_value; 69*080b47deSLogan Gunthorpe } __packed; 70*080b47deSLogan Gunthorpe 71*080b47deSLogan Gunthorpe enum mrpc_status { 72*080b47deSLogan Gunthorpe SWITCHTEC_MRPC_STATUS_INPROGRESS = 1, 73*080b47deSLogan Gunthorpe SWITCHTEC_MRPC_STATUS_DONE = 2, 74*080b47deSLogan Gunthorpe SWITCHTEC_MRPC_STATUS_ERROR = 0xFF, 75*080b47deSLogan Gunthorpe SWITCHTEC_MRPC_STATUS_INTERRUPTED = 0x100, 76*080b47deSLogan Gunthorpe }; 77*080b47deSLogan Gunthorpe 78*080b47deSLogan Gunthorpe struct sw_event_regs { 79*080b47deSLogan Gunthorpe u64 event_report_ctrl; 80*080b47deSLogan Gunthorpe u64 reserved1; 81*080b47deSLogan Gunthorpe u64 part_event_bitmap; 82*080b47deSLogan Gunthorpe u64 reserved2; 83*080b47deSLogan Gunthorpe u32 global_summary; 84*080b47deSLogan Gunthorpe u32 reserved3[3]; 85*080b47deSLogan Gunthorpe u32 stack_error_event_hdr; 86*080b47deSLogan Gunthorpe u32 stack_error_event_data; 87*080b47deSLogan Gunthorpe u32 reserved4[4]; 88*080b47deSLogan Gunthorpe u32 ppu_error_event_hdr; 89*080b47deSLogan Gunthorpe u32 ppu_error_event_data; 90*080b47deSLogan Gunthorpe u32 reserved5[4]; 91*080b47deSLogan Gunthorpe u32 isp_error_event_hdr; 92*080b47deSLogan Gunthorpe u32 isp_error_event_data; 93*080b47deSLogan Gunthorpe u32 reserved6[4]; 94*080b47deSLogan Gunthorpe u32 sys_reset_event_hdr; 95*080b47deSLogan Gunthorpe u32 reserved7[5]; 96*080b47deSLogan Gunthorpe u32 fw_exception_hdr; 97*080b47deSLogan Gunthorpe u32 reserved8[5]; 98*080b47deSLogan Gunthorpe u32 fw_nmi_hdr; 99*080b47deSLogan Gunthorpe u32 reserved9[5]; 100*080b47deSLogan Gunthorpe u32 fw_non_fatal_hdr; 101*080b47deSLogan Gunthorpe u32 reserved10[5]; 102*080b47deSLogan Gunthorpe u32 fw_fatal_hdr; 103*080b47deSLogan Gunthorpe u32 reserved11[5]; 104*080b47deSLogan Gunthorpe u32 twi_mrpc_comp_hdr; 105*080b47deSLogan Gunthorpe u32 twi_mrpc_comp_data; 106*080b47deSLogan Gunthorpe u32 reserved12[4]; 107*080b47deSLogan Gunthorpe u32 twi_mrpc_comp_async_hdr; 108*080b47deSLogan Gunthorpe u32 twi_mrpc_comp_async_data; 109*080b47deSLogan Gunthorpe u32 reserved13[4]; 110*080b47deSLogan Gunthorpe u32 cli_mrpc_comp_hdr; 111*080b47deSLogan Gunthorpe u32 cli_mrpc_comp_data; 112*080b47deSLogan Gunthorpe u32 reserved14[4]; 113*080b47deSLogan Gunthorpe u32 cli_mrpc_comp_async_hdr; 114*080b47deSLogan Gunthorpe u32 cli_mrpc_comp_async_data; 115*080b47deSLogan Gunthorpe u32 reserved15[4]; 116*080b47deSLogan Gunthorpe u32 gpio_interrupt_hdr; 117*080b47deSLogan Gunthorpe u32 gpio_interrupt_data; 118*080b47deSLogan Gunthorpe u32 reserved16[4]; 119*080b47deSLogan Gunthorpe } __packed; 120*080b47deSLogan Gunthorpe 121*080b47deSLogan Gunthorpe struct sys_info_regs { 122*080b47deSLogan Gunthorpe u32 device_id; 123*080b47deSLogan Gunthorpe u32 device_version; 124*080b47deSLogan Gunthorpe u32 firmware_version; 125*080b47deSLogan Gunthorpe u32 reserved1; 126*080b47deSLogan Gunthorpe u32 vendor_table_revision; 127*080b47deSLogan Gunthorpe u32 table_format_version; 128*080b47deSLogan Gunthorpe u32 partition_id; 129*080b47deSLogan Gunthorpe u32 cfg_file_fmt_version; 130*080b47deSLogan Gunthorpe u32 reserved2[58]; 131*080b47deSLogan Gunthorpe char vendor_id[8]; 132*080b47deSLogan Gunthorpe char product_id[16]; 133*080b47deSLogan Gunthorpe char product_revision[4]; 134*080b47deSLogan Gunthorpe char component_vendor[8]; 135*080b47deSLogan Gunthorpe u16 component_id; 136*080b47deSLogan Gunthorpe u8 component_revision; 137*080b47deSLogan Gunthorpe } __packed; 138*080b47deSLogan Gunthorpe 139*080b47deSLogan Gunthorpe struct flash_info_regs { 140*080b47deSLogan Gunthorpe u32 flash_part_map_upd_idx; 141*080b47deSLogan Gunthorpe 142*080b47deSLogan Gunthorpe struct active_partition_info { 143*080b47deSLogan Gunthorpe u32 address; 144*080b47deSLogan Gunthorpe u32 build_version; 145*080b47deSLogan Gunthorpe u32 build_string; 146*080b47deSLogan Gunthorpe } active_img; 147*080b47deSLogan Gunthorpe 148*080b47deSLogan Gunthorpe struct active_partition_info active_cfg; 149*080b47deSLogan Gunthorpe struct active_partition_info inactive_img; 150*080b47deSLogan Gunthorpe struct active_partition_info inactive_cfg; 151*080b47deSLogan Gunthorpe 152*080b47deSLogan Gunthorpe u32 flash_length; 153*080b47deSLogan Gunthorpe 154*080b47deSLogan Gunthorpe struct partition_info { 155*080b47deSLogan Gunthorpe u32 address; 156*080b47deSLogan Gunthorpe u32 length; 157*080b47deSLogan Gunthorpe } cfg0; 158*080b47deSLogan Gunthorpe 159*080b47deSLogan Gunthorpe struct partition_info cfg1; 160*080b47deSLogan Gunthorpe struct partition_info img0; 161*080b47deSLogan Gunthorpe struct partition_info img1; 162*080b47deSLogan Gunthorpe struct partition_info nvlog; 163*080b47deSLogan Gunthorpe struct partition_info vendor[8]; 164*080b47deSLogan Gunthorpe }; 165*080b47deSLogan Gunthorpe 166*080b47deSLogan Gunthorpe struct ntb_info_regs { 167*080b47deSLogan Gunthorpe u8 partition_count; 168*080b47deSLogan Gunthorpe u8 partition_id; 169*080b47deSLogan Gunthorpe u16 reserved1; 170*080b47deSLogan Gunthorpe u64 ep_map; 171*080b47deSLogan Gunthorpe u16 requester_id; 172*080b47deSLogan Gunthorpe } __packed; 173*080b47deSLogan Gunthorpe 174*080b47deSLogan Gunthorpe struct part_cfg_regs { 175*080b47deSLogan Gunthorpe u32 status; 176*080b47deSLogan Gunthorpe u32 state; 177*080b47deSLogan Gunthorpe u32 port_cnt; 178*080b47deSLogan Gunthorpe u32 usp_port_mode; 179*080b47deSLogan Gunthorpe u32 usp_pff_inst_id; 180*080b47deSLogan Gunthorpe u32 vep_pff_inst_id; 181*080b47deSLogan Gunthorpe u32 dsp_pff_inst_id[47]; 182*080b47deSLogan Gunthorpe u32 reserved1[11]; 183*080b47deSLogan Gunthorpe u16 vep_vector_number; 184*080b47deSLogan Gunthorpe u16 usp_vector_number; 185*080b47deSLogan Gunthorpe u32 port_event_bitmap; 186*080b47deSLogan Gunthorpe u32 reserved2[3]; 187*080b47deSLogan Gunthorpe u32 part_event_summary; 188*080b47deSLogan Gunthorpe u32 reserved3[3]; 189*080b47deSLogan Gunthorpe u32 part_reset_hdr; 190*080b47deSLogan Gunthorpe u32 part_reset_data[5]; 191*080b47deSLogan Gunthorpe u32 mrpc_comp_hdr; 192*080b47deSLogan Gunthorpe u32 mrpc_comp_data[5]; 193*080b47deSLogan Gunthorpe u32 mrpc_comp_async_hdr; 194*080b47deSLogan Gunthorpe u32 mrpc_comp_async_data[5]; 195*080b47deSLogan Gunthorpe u32 dyn_binding_hdr; 196*080b47deSLogan Gunthorpe u32 dyn_binding_data[5]; 197*080b47deSLogan Gunthorpe u32 reserved4[159]; 198*080b47deSLogan Gunthorpe } __packed; 199*080b47deSLogan Gunthorpe 200*080b47deSLogan Gunthorpe enum { 201*080b47deSLogan Gunthorpe SWITCHTEC_PART_CFG_EVENT_RESET = 1 << 0, 202*080b47deSLogan Gunthorpe SWITCHTEC_PART_CFG_EVENT_MRPC_CMP = 1 << 1, 203*080b47deSLogan Gunthorpe SWITCHTEC_PART_CFG_EVENT_MRPC_ASYNC_CMP = 1 << 2, 204*080b47deSLogan Gunthorpe SWITCHTEC_PART_CFG_EVENT_DYN_PART_CMP = 1 << 3, 205*080b47deSLogan Gunthorpe }; 206*080b47deSLogan Gunthorpe 207*080b47deSLogan Gunthorpe struct pff_csr_regs { 208*080b47deSLogan Gunthorpe u16 vendor_id; 209*080b47deSLogan Gunthorpe u16 device_id; 210*080b47deSLogan Gunthorpe u32 pci_cfg_header[15]; 211*080b47deSLogan Gunthorpe u32 pci_cap_region[48]; 212*080b47deSLogan Gunthorpe u32 pcie_cap_region[448]; 213*080b47deSLogan Gunthorpe u32 indirect_gas_window[128]; 214*080b47deSLogan Gunthorpe u32 indirect_gas_window_off; 215*080b47deSLogan Gunthorpe u32 reserved[127]; 216*080b47deSLogan Gunthorpe u32 pff_event_summary; 217*080b47deSLogan Gunthorpe u32 reserved2[3]; 218*080b47deSLogan Gunthorpe u32 aer_in_p2p_hdr; 219*080b47deSLogan Gunthorpe u32 aer_in_p2p_data[5]; 220*080b47deSLogan Gunthorpe u32 aer_in_vep_hdr; 221*080b47deSLogan Gunthorpe u32 aer_in_vep_data[5]; 222*080b47deSLogan Gunthorpe u32 dpc_hdr; 223*080b47deSLogan Gunthorpe u32 dpc_data[5]; 224*080b47deSLogan Gunthorpe u32 cts_hdr; 225*080b47deSLogan Gunthorpe u32 cts_data[5]; 226*080b47deSLogan Gunthorpe u32 reserved3[6]; 227*080b47deSLogan Gunthorpe u32 hotplug_hdr; 228*080b47deSLogan Gunthorpe u32 hotplug_data[5]; 229*080b47deSLogan Gunthorpe u32 ier_hdr; 230*080b47deSLogan Gunthorpe u32 ier_data[5]; 231*080b47deSLogan Gunthorpe u32 threshold_hdr; 232*080b47deSLogan Gunthorpe u32 threshold_data[5]; 233*080b47deSLogan Gunthorpe u32 power_mgmt_hdr; 234*080b47deSLogan Gunthorpe u32 power_mgmt_data[5]; 235*080b47deSLogan Gunthorpe u32 tlp_throttling_hdr; 236*080b47deSLogan Gunthorpe u32 tlp_throttling_data[5]; 237*080b47deSLogan Gunthorpe u32 force_speed_hdr; 238*080b47deSLogan Gunthorpe u32 force_speed_data[5]; 239*080b47deSLogan Gunthorpe u32 credit_timeout_hdr; 240*080b47deSLogan Gunthorpe u32 credit_timeout_data[5]; 241*080b47deSLogan Gunthorpe u32 link_state_hdr; 242*080b47deSLogan Gunthorpe u32 link_state_data[5]; 243*080b47deSLogan Gunthorpe u32 reserved4[174]; 244*080b47deSLogan Gunthorpe } __packed; 245*080b47deSLogan Gunthorpe 246*080b47deSLogan Gunthorpe struct switchtec_dev { 247*080b47deSLogan Gunthorpe struct pci_dev *pdev; 248*080b47deSLogan Gunthorpe struct device dev; 249*080b47deSLogan Gunthorpe struct cdev cdev; 250*080b47deSLogan Gunthorpe 251*080b47deSLogan Gunthorpe int partition; 252*080b47deSLogan Gunthorpe int partition_count; 253*080b47deSLogan Gunthorpe int pff_csr_count; 254*080b47deSLogan Gunthorpe char pff_local[SWITCHTEC_MAX_PFF_CSR]; 255*080b47deSLogan Gunthorpe 256*080b47deSLogan Gunthorpe void __iomem *mmio; 257*080b47deSLogan Gunthorpe struct mrpc_regs __iomem *mmio_mrpc; 258*080b47deSLogan Gunthorpe struct sw_event_regs __iomem *mmio_sw_event; 259*080b47deSLogan Gunthorpe struct sys_info_regs __iomem *mmio_sys_info; 260*080b47deSLogan Gunthorpe struct flash_info_regs __iomem *mmio_flash_info; 261*080b47deSLogan Gunthorpe struct ntb_info_regs __iomem *mmio_ntb; 262*080b47deSLogan Gunthorpe struct part_cfg_regs __iomem *mmio_part_cfg; 263*080b47deSLogan Gunthorpe struct part_cfg_regs __iomem *mmio_part_cfg_all; 264*080b47deSLogan Gunthorpe struct pff_csr_regs __iomem *mmio_pff_csr; 265*080b47deSLogan Gunthorpe 266*080b47deSLogan Gunthorpe /* 267*080b47deSLogan Gunthorpe * The mrpc mutex must be held when accessing the other 268*080b47deSLogan Gunthorpe * mrpc_ fields, alive flag and stuser->state field 269*080b47deSLogan Gunthorpe */ 270*080b47deSLogan Gunthorpe struct mutex mrpc_mutex; 271*080b47deSLogan Gunthorpe struct list_head mrpc_queue; 272*080b47deSLogan Gunthorpe int mrpc_busy; 273*080b47deSLogan Gunthorpe struct work_struct mrpc_work; 274*080b47deSLogan Gunthorpe struct delayed_work mrpc_timeout; 275*080b47deSLogan Gunthorpe bool alive; 276*080b47deSLogan Gunthorpe 277*080b47deSLogan Gunthorpe wait_queue_head_t event_wq; 278*080b47deSLogan Gunthorpe atomic_t event_cnt; 279*080b47deSLogan Gunthorpe }; 280*080b47deSLogan Gunthorpe 281*080b47deSLogan Gunthorpe static struct switchtec_dev *to_stdev(struct device *dev) 282*080b47deSLogan Gunthorpe { 283*080b47deSLogan Gunthorpe return container_of(dev, struct switchtec_dev, dev); 284*080b47deSLogan Gunthorpe } 285*080b47deSLogan Gunthorpe 286*080b47deSLogan Gunthorpe enum mrpc_state { 287*080b47deSLogan Gunthorpe MRPC_IDLE = 0, 288*080b47deSLogan Gunthorpe MRPC_QUEUED, 289*080b47deSLogan Gunthorpe MRPC_RUNNING, 290*080b47deSLogan Gunthorpe MRPC_DONE, 291*080b47deSLogan Gunthorpe }; 292*080b47deSLogan Gunthorpe 293*080b47deSLogan Gunthorpe struct switchtec_user { 294*080b47deSLogan Gunthorpe struct switchtec_dev *stdev; 295*080b47deSLogan Gunthorpe 296*080b47deSLogan Gunthorpe enum mrpc_state state; 297*080b47deSLogan Gunthorpe 298*080b47deSLogan Gunthorpe struct completion comp; 299*080b47deSLogan Gunthorpe struct kref kref; 300*080b47deSLogan Gunthorpe struct list_head list; 301*080b47deSLogan Gunthorpe 302*080b47deSLogan Gunthorpe u32 cmd; 303*080b47deSLogan Gunthorpe u32 status; 304*080b47deSLogan Gunthorpe u32 return_code; 305*080b47deSLogan Gunthorpe size_t data_len; 306*080b47deSLogan Gunthorpe size_t read_len; 307*080b47deSLogan Gunthorpe unsigned char data[SWITCHTEC_MRPC_PAYLOAD_SIZE]; 308*080b47deSLogan Gunthorpe int event_cnt; 309*080b47deSLogan Gunthorpe }; 310*080b47deSLogan Gunthorpe 311*080b47deSLogan Gunthorpe static struct switchtec_user *stuser_create(struct switchtec_dev *stdev) 312*080b47deSLogan Gunthorpe { 313*080b47deSLogan Gunthorpe struct switchtec_user *stuser; 314*080b47deSLogan Gunthorpe 315*080b47deSLogan Gunthorpe stuser = kzalloc(sizeof(*stuser), GFP_KERNEL); 316*080b47deSLogan Gunthorpe if (!stuser) 317*080b47deSLogan Gunthorpe return ERR_PTR(-ENOMEM); 318*080b47deSLogan Gunthorpe 319*080b47deSLogan Gunthorpe get_device(&stdev->dev); 320*080b47deSLogan Gunthorpe stuser->stdev = stdev; 321*080b47deSLogan Gunthorpe kref_init(&stuser->kref); 322*080b47deSLogan Gunthorpe INIT_LIST_HEAD(&stuser->list); 323*080b47deSLogan Gunthorpe init_completion(&stuser->comp); 324*080b47deSLogan Gunthorpe stuser->event_cnt = atomic_read(&stdev->event_cnt); 325*080b47deSLogan Gunthorpe 326*080b47deSLogan Gunthorpe dev_dbg(&stdev->dev, "%s: %p\n", __func__, stuser); 327*080b47deSLogan Gunthorpe 328*080b47deSLogan Gunthorpe return stuser; 329*080b47deSLogan Gunthorpe } 330*080b47deSLogan Gunthorpe 331*080b47deSLogan Gunthorpe static void stuser_free(struct kref *kref) 332*080b47deSLogan Gunthorpe { 333*080b47deSLogan Gunthorpe struct switchtec_user *stuser; 334*080b47deSLogan Gunthorpe 335*080b47deSLogan Gunthorpe stuser = container_of(kref, struct switchtec_user, kref); 336*080b47deSLogan Gunthorpe 337*080b47deSLogan Gunthorpe dev_dbg(&stuser->stdev->dev, "%s: %p\n", __func__, stuser); 338*080b47deSLogan Gunthorpe 339*080b47deSLogan Gunthorpe put_device(&stuser->stdev->dev); 340*080b47deSLogan Gunthorpe kfree(stuser); 341*080b47deSLogan Gunthorpe } 342*080b47deSLogan Gunthorpe 343*080b47deSLogan Gunthorpe static void stuser_put(struct switchtec_user *stuser) 344*080b47deSLogan Gunthorpe { 345*080b47deSLogan Gunthorpe kref_put(&stuser->kref, stuser_free); 346*080b47deSLogan Gunthorpe } 347*080b47deSLogan Gunthorpe 348*080b47deSLogan Gunthorpe static void stuser_set_state(struct switchtec_user *stuser, 349*080b47deSLogan Gunthorpe enum mrpc_state state) 350*080b47deSLogan Gunthorpe { 351*080b47deSLogan Gunthorpe /* requires the mrpc_mutex to already be held when called */ 352*080b47deSLogan Gunthorpe 353*080b47deSLogan Gunthorpe const char * const state_names[] = { 354*080b47deSLogan Gunthorpe [MRPC_IDLE] = "IDLE", 355*080b47deSLogan Gunthorpe [MRPC_QUEUED] = "QUEUED", 356*080b47deSLogan Gunthorpe [MRPC_RUNNING] = "RUNNING", 357*080b47deSLogan Gunthorpe [MRPC_DONE] = "DONE", 358*080b47deSLogan Gunthorpe }; 359*080b47deSLogan Gunthorpe 360*080b47deSLogan Gunthorpe stuser->state = state; 361*080b47deSLogan Gunthorpe 362*080b47deSLogan Gunthorpe dev_dbg(&stuser->stdev->dev, "stuser state %p -> %s", 363*080b47deSLogan Gunthorpe stuser, state_names[state]); 364*080b47deSLogan Gunthorpe } 365*080b47deSLogan Gunthorpe 366*080b47deSLogan Gunthorpe static void mrpc_complete_cmd(struct switchtec_dev *stdev); 367*080b47deSLogan Gunthorpe 368*080b47deSLogan Gunthorpe static void mrpc_cmd_submit(struct switchtec_dev *stdev) 369*080b47deSLogan Gunthorpe { 370*080b47deSLogan Gunthorpe /* requires the mrpc_mutex to already be held when called */ 371*080b47deSLogan Gunthorpe 372*080b47deSLogan Gunthorpe struct switchtec_user *stuser; 373*080b47deSLogan Gunthorpe 374*080b47deSLogan Gunthorpe if (stdev->mrpc_busy) 375*080b47deSLogan Gunthorpe return; 376*080b47deSLogan Gunthorpe 377*080b47deSLogan Gunthorpe if (list_empty(&stdev->mrpc_queue)) 378*080b47deSLogan Gunthorpe return; 379*080b47deSLogan Gunthorpe 380*080b47deSLogan Gunthorpe stuser = list_entry(stdev->mrpc_queue.next, struct switchtec_user, 381*080b47deSLogan Gunthorpe list); 382*080b47deSLogan Gunthorpe 383*080b47deSLogan Gunthorpe stuser_set_state(stuser, MRPC_RUNNING); 384*080b47deSLogan Gunthorpe stdev->mrpc_busy = 1; 385*080b47deSLogan Gunthorpe memcpy_toio(&stdev->mmio_mrpc->input_data, 386*080b47deSLogan Gunthorpe stuser->data, stuser->data_len); 387*080b47deSLogan Gunthorpe iowrite32(stuser->cmd, &stdev->mmio_mrpc->cmd); 388*080b47deSLogan Gunthorpe 389*080b47deSLogan Gunthorpe stuser->status = ioread32(&stdev->mmio_mrpc->status); 390*080b47deSLogan Gunthorpe if (stuser->status != SWITCHTEC_MRPC_STATUS_INPROGRESS) 391*080b47deSLogan Gunthorpe mrpc_complete_cmd(stdev); 392*080b47deSLogan Gunthorpe 393*080b47deSLogan Gunthorpe schedule_delayed_work(&stdev->mrpc_timeout, 394*080b47deSLogan Gunthorpe msecs_to_jiffies(500)); 395*080b47deSLogan Gunthorpe } 396*080b47deSLogan Gunthorpe 397*080b47deSLogan Gunthorpe static int mrpc_queue_cmd(struct switchtec_user *stuser) 398*080b47deSLogan Gunthorpe { 399*080b47deSLogan Gunthorpe /* requires the mrpc_mutex to already be held when called */ 400*080b47deSLogan Gunthorpe 401*080b47deSLogan Gunthorpe struct switchtec_dev *stdev = stuser->stdev; 402*080b47deSLogan Gunthorpe 403*080b47deSLogan Gunthorpe kref_get(&stuser->kref); 404*080b47deSLogan Gunthorpe stuser->read_len = sizeof(stuser->data); 405*080b47deSLogan Gunthorpe stuser_set_state(stuser, MRPC_QUEUED); 406*080b47deSLogan Gunthorpe init_completion(&stuser->comp); 407*080b47deSLogan Gunthorpe list_add_tail(&stuser->list, &stdev->mrpc_queue); 408*080b47deSLogan Gunthorpe 409*080b47deSLogan Gunthorpe mrpc_cmd_submit(stdev); 410*080b47deSLogan Gunthorpe 411*080b47deSLogan Gunthorpe return 0; 412*080b47deSLogan Gunthorpe } 413*080b47deSLogan Gunthorpe 414*080b47deSLogan Gunthorpe static void mrpc_complete_cmd(struct switchtec_dev *stdev) 415*080b47deSLogan Gunthorpe { 416*080b47deSLogan Gunthorpe /* requires the mrpc_mutex to already be held when called */ 417*080b47deSLogan Gunthorpe struct switchtec_user *stuser; 418*080b47deSLogan Gunthorpe 419*080b47deSLogan Gunthorpe if (list_empty(&stdev->mrpc_queue)) 420*080b47deSLogan Gunthorpe return; 421*080b47deSLogan Gunthorpe 422*080b47deSLogan Gunthorpe stuser = list_entry(stdev->mrpc_queue.next, struct switchtec_user, 423*080b47deSLogan Gunthorpe list); 424*080b47deSLogan Gunthorpe 425*080b47deSLogan Gunthorpe stuser->status = ioread32(&stdev->mmio_mrpc->status); 426*080b47deSLogan Gunthorpe if (stuser->status == SWITCHTEC_MRPC_STATUS_INPROGRESS) 427*080b47deSLogan Gunthorpe return; 428*080b47deSLogan Gunthorpe 429*080b47deSLogan Gunthorpe stuser_set_state(stuser, MRPC_DONE); 430*080b47deSLogan Gunthorpe stuser->return_code = 0; 431*080b47deSLogan Gunthorpe 432*080b47deSLogan Gunthorpe if (stuser->status != SWITCHTEC_MRPC_STATUS_DONE) 433*080b47deSLogan Gunthorpe goto out; 434*080b47deSLogan Gunthorpe 435*080b47deSLogan Gunthorpe stuser->return_code = ioread32(&stdev->mmio_mrpc->ret_value); 436*080b47deSLogan Gunthorpe if (stuser->return_code != 0) 437*080b47deSLogan Gunthorpe goto out; 438*080b47deSLogan Gunthorpe 439*080b47deSLogan Gunthorpe memcpy_fromio(stuser->data, &stdev->mmio_mrpc->output_data, 440*080b47deSLogan Gunthorpe stuser->read_len); 441*080b47deSLogan Gunthorpe 442*080b47deSLogan Gunthorpe out: 443*080b47deSLogan Gunthorpe complete_all(&stuser->comp); 444*080b47deSLogan Gunthorpe list_del_init(&stuser->list); 445*080b47deSLogan Gunthorpe stuser_put(stuser); 446*080b47deSLogan Gunthorpe stdev->mrpc_busy = 0; 447*080b47deSLogan Gunthorpe 448*080b47deSLogan Gunthorpe mrpc_cmd_submit(stdev); 449*080b47deSLogan Gunthorpe } 450*080b47deSLogan Gunthorpe 451*080b47deSLogan Gunthorpe static void mrpc_event_work(struct work_struct *work) 452*080b47deSLogan Gunthorpe { 453*080b47deSLogan Gunthorpe struct switchtec_dev *stdev; 454*080b47deSLogan Gunthorpe 455*080b47deSLogan Gunthorpe stdev = container_of(work, struct switchtec_dev, mrpc_work); 456*080b47deSLogan Gunthorpe 457*080b47deSLogan Gunthorpe dev_dbg(&stdev->dev, "%s\n", __func__); 458*080b47deSLogan Gunthorpe 459*080b47deSLogan Gunthorpe mutex_lock(&stdev->mrpc_mutex); 460*080b47deSLogan Gunthorpe cancel_delayed_work(&stdev->mrpc_timeout); 461*080b47deSLogan Gunthorpe mrpc_complete_cmd(stdev); 462*080b47deSLogan Gunthorpe mutex_unlock(&stdev->mrpc_mutex); 463*080b47deSLogan Gunthorpe } 464*080b47deSLogan Gunthorpe 465*080b47deSLogan Gunthorpe static void mrpc_timeout_work(struct work_struct *work) 466*080b47deSLogan Gunthorpe { 467*080b47deSLogan Gunthorpe struct switchtec_dev *stdev; 468*080b47deSLogan Gunthorpe u32 status; 469*080b47deSLogan Gunthorpe 470*080b47deSLogan Gunthorpe stdev = container_of(work, struct switchtec_dev, mrpc_timeout.work); 471*080b47deSLogan Gunthorpe 472*080b47deSLogan Gunthorpe dev_dbg(&stdev->dev, "%s\n", __func__); 473*080b47deSLogan Gunthorpe 474*080b47deSLogan Gunthorpe mutex_lock(&stdev->mrpc_mutex); 475*080b47deSLogan Gunthorpe 476*080b47deSLogan Gunthorpe status = ioread32(&stdev->mmio_mrpc->status); 477*080b47deSLogan Gunthorpe if (status == SWITCHTEC_MRPC_STATUS_INPROGRESS) { 478*080b47deSLogan Gunthorpe schedule_delayed_work(&stdev->mrpc_timeout, 479*080b47deSLogan Gunthorpe msecs_to_jiffies(500)); 480*080b47deSLogan Gunthorpe goto out; 481*080b47deSLogan Gunthorpe } 482*080b47deSLogan Gunthorpe 483*080b47deSLogan Gunthorpe mrpc_complete_cmd(stdev); 484*080b47deSLogan Gunthorpe 485*080b47deSLogan Gunthorpe out: 486*080b47deSLogan Gunthorpe mutex_unlock(&stdev->mrpc_mutex); 487*080b47deSLogan Gunthorpe } 488*080b47deSLogan Gunthorpe 489*080b47deSLogan Gunthorpe static int switchtec_dev_open(struct inode *inode, struct file *filp) 490*080b47deSLogan Gunthorpe { 491*080b47deSLogan Gunthorpe struct switchtec_dev *stdev; 492*080b47deSLogan Gunthorpe struct switchtec_user *stuser; 493*080b47deSLogan Gunthorpe 494*080b47deSLogan Gunthorpe stdev = container_of(inode->i_cdev, struct switchtec_dev, cdev); 495*080b47deSLogan Gunthorpe 496*080b47deSLogan Gunthorpe stuser = stuser_create(stdev); 497*080b47deSLogan Gunthorpe if (IS_ERR(stuser)) 498*080b47deSLogan Gunthorpe return PTR_ERR(stuser); 499*080b47deSLogan Gunthorpe 500*080b47deSLogan Gunthorpe filp->private_data = stuser; 501*080b47deSLogan Gunthorpe nonseekable_open(inode, filp); 502*080b47deSLogan Gunthorpe 503*080b47deSLogan Gunthorpe dev_dbg(&stdev->dev, "%s: %p\n", __func__, stuser); 504*080b47deSLogan Gunthorpe 505*080b47deSLogan Gunthorpe return 0; 506*080b47deSLogan Gunthorpe } 507*080b47deSLogan Gunthorpe 508*080b47deSLogan Gunthorpe static int switchtec_dev_release(struct inode *inode, struct file *filp) 509*080b47deSLogan Gunthorpe { 510*080b47deSLogan Gunthorpe struct switchtec_user *stuser = filp->private_data; 511*080b47deSLogan Gunthorpe 512*080b47deSLogan Gunthorpe stuser_put(stuser); 513*080b47deSLogan Gunthorpe 514*080b47deSLogan Gunthorpe return 0; 515*080b47deSLogan Gunthorpe } 516*080b47deSLogan Gunthorpe 517*080b47deSLogan Gunthorpe static int lock_mutex_and_test_alive(struct switchtec_dev *stdev) 518*080b47deSLogan Gunthorpe { 519*080b47deSLogan Gunthorpe if (mutex_lock_interruptible(&stdev->mrpc_mutex)) 520*080b47deSLogan Gunthorpe return -EINTR; 521*080b47deSLogan Gunthorpe 522*080b47deSLogan Gunthorpe if (!stdev->alive) { 523*080b47deSLogan Gunthorpe mutex_unlock(&stdev->mrpc_mutex); 524*080b47deSLogan Gunthorpe return -ENODEV; 525*080b47deSLogan Gunthorpe } 526*080b47deSLogan Gunthorpe 527*080b47deSLogan Gunthorpe return 0; 528*080b47deSLogan Gunthorpe } 529*080b47deSLogan Gunthorpe 530*080b47deSLogan Gunthorpe static ssize_t switchtec_dev_write(struct file *filp, const char __user *data, 531*080b47deSLogan Gunthorpe size_t size, loff_t *off) 532*080b47deSLogan Gunthorpe { 533*080b47deSLogan Gunthorpe struct switchtec_user *stuser = filp->private_data; 534*080b47deSLogan Gunthorpe struct switchtec_dev *stdev = stuser->stdev; 535*080b47deSLogan Gunthorpe int rc; 536*080b47deSLogan Gunthorpe 537*080b47deSLogan Gunthorpe if (size < sizeof(stuser->cmd) || 538*080b47deSLogan Gunthorpe size > sizeof(stuser->cmd) + sizeof(stuser->data)) 539*080b47deSLogan Gunthorpe return -EINVAL; 540*080b47deSLogan Gunthorpe 541*080b47deSLogan Gunthorpe stuser->data_len = size - sizeof(stuser->cmd); 542*080b47deSLogan Gunthorpe 543*080b47deSLogan Gunthorpe rc = lock_mutex_and_test_alive(stdev); 544*080b47deSLogan Gunthorpe if (rc) 545*080b47deSLogan Gunthorpe return rc; 546*080b47deSLogan Gunthorpe 547*080b47deSLogan Gunthorpe if (stuser->state != MRPC_IDLE) { 548*080b47deSLogan Gunthorpe rc = -EBADE; 549*080b47deSLogan Gunthorpe goto out; 550*080b47deSLogan Gunthorpe } 551*080b47deSLogan Gunthorpe 552*080b47deSLogan Gunthorpe rc = copy_from_user(&stuser->cmd, data, sizeof(stuser->cmd)); 553*080b47deSLogan Gunthorpe if (rc) { 554*080b47deSLogan Gunthorpe rc = -EFAULT; 555*080b47deSLogan Gunthorpe goto out; 556*080b47deSLogan Gunthorpe } 557*080b47deSLogan Gunthorpe 558*080b47deSLogan Gunthorpe data += sizeof(stuser->cmd); 559*080b47deSLogan Gunthorpe rc = copy_from_user(&stuser->data, data, size - sizeof(stuser->cmd)); 560*080b47deSLogan Gunthorpe if (rc) { 561*080b47deSLogan Gunthorpe rc = -EFAULT; 562*080b47deSLogan Gunthorpe goto out; 563*080b47deSLogan Gunthorpe } 564*080b47deSLogan Gunthorpe 565*080b47deSLogan Gunthorpe rc = mrpc_queue_cmd(stuser); 566*080b47deSLogan Gunthorpe 567*080b47deSLogan Gunthorpe out: 568*080b47deSLogan Gunthorpe mutex_unlock(&stdev->mrpc_mutex); 569*080b47deSLogan Gunthorpe 570*080b47deSLogan Gunthorpe if (rc) 571*080b47deSLogan Gunthorpe return rc; 572*080b47deSLogan Gunthorpe 573*080b47deSLogan Gunthorpe return size; 574*080b47deSLogan Gunthorpe } 575*080b47deSLogan Gunthorpe 576*080b47deSLogan Gunthorpe static ssize_t switchtec_dev_read(struct file *filp, char __user *data, 577*080b47deSLogan Gunthorpe size_t size, loff_t *off) 578*080b47deSLogan Gunthorpe { 579*080b47deSLogan Gunthorpe struct switchtec_user *stuser = filp->private_data; 580*080b47deSLogan Gunthorpe struct switchtec_dev *stdev = stuser->stdev; 581*080b47deSLogan Gunthorpe int rc; 582*080b47deSLogan Gunthorpe 583*080b47deSLogan Gunthorpe if (size < sizeof(stuser->cmd) || 584*080b47deSLogan Gunthorpe size > sizeof(stuser->cmd) + sizeof(stuser->data)) 585*080b47deSLogan Gunthorpe return -EINVAL; 586*080b47deSLogan Gunthorpe 587*080b47deSLogan Gunthorpe rc = lock_mutex_and_test_alive(stdev); 588*080b47deSLogan Gunthorpe if (rc) 589*080b47deSLogan Gunthorpe return rc; 590*080b47deSLogan Gunthorpe 591*080b47deSLogan Gunthorpe if (stuser->state == MRPC_IDLE) { 592*080b47deSLogan Gunthorpe mutex_unlock(&stdev->mrpc_mutex); 593*080b47deSLogan Gunthorpe return -EBADE; 594*080b47deSLogan Gunthorpe } 595*080b47deSLogan Gunthorpe 596*080b47deSLogan Gunthorpe stuser->read_len = size - sizeof(stuser->return_code); 597*080b47deSLogan Gunthorpe 598*080b47deSLogan Gunthorpe mutex_unlock(&stdev->mrpc_mutex); 599*080b47deSLogan Gunthorpe 600*080b47deSLogan Gunthorpe if (filp->f_flags & O_NONBLOCK) { 601*080b47deSLogan Gunthorpe if (!try_wait_for_completion(&stuser->comp)) 602*080b47deSLogan Gunthorpe return -EAGAIN; 603*080b47deSLogan Gunthorpe } else { 604*080b47deSLogan Gunthorpe rc = wait_for_completion_interruptible(&stuser->comp); 605*080b47deSLogan Gunthorpe if (rc < 0) 606*080b47deSLogan Gunthorpe return rc; 607*080b47deSLogan Gunthorpe } 608*080b47deSLogan Gunthorpe 609*080b47deSLogan Gunthorpe rc = lock_mutex_and_test_alive(stdev); 610*080b47deSLogan Gunthorpe if (rc) 611*080b47deSLogan Gunthorpe return rc; 612*080b47deSLogan Gunthorpe 613*080b47deSLogan Gunthorpe if (stuser->state != MRPC_DONE) { 614*080b47deSLogan Gunthorpe mutex_unlock(&stdev->mrpc_mutex); 615*080b47deSLogan Gunthorpe return -EBADE; 616*080b47deSLogan Gunthorpe } 617*080b47deSLogan Gunthorpe 618*080b47deSLogan Gunthorpe rc = copy_to_user(data, &stuser->return_code, 619*080b47deSLogan Gunthorpe sizeof(stuser->return_code)); 620*080b47deSLogan Gunthorpe if (rc) { 621*080b47deSLogan Gunthorpe rc = -EFAULT; 622*080b47deSLogan Gunthorpe goto out; 623*080b47deSLogan Gunthorpe } 624*080b47deSLogan Gunthorpe 625*080b47deSLogan Gunthorpe data += sizeof(stuser->return_code); 626*080b47deSLogan Gunthorpe rc = copy_to_user(data, &stuser->data, 627*080b47deSLogan Gunthorpe size - sizeof(stuser->return_code)); 628*080b47deSLogan Gunthorpe if (rc) { 629*080b47deSLogan Gunthorpe rc = -EFAULT; 630*080b47deSLogan Gunthorpe goto out; 631*080b47deSLogan Gunthorpe } 632*080b47deSLogan Gunthorpe 633*080b47deSLogan Gunthorpe stuser_set_state(stuser, MRPC_IDLE); 634*080b47deSLogan Gunthorpe 635*080b47deSLogan Gunthorpe out: 636*080b47deSLogan Gunthorpe mutex_unlock(&stdev->mrpc_mutex); 637*080b47deSLogan Gunthorpe 638*080b47deSLogan Gunthorpe if (stuser->status == SWITCHTEC_MRPC_STATUS_DONE) 639*080b47deSLogan Gunthorpe return size; 640*080b47deSLogan Gunthorpe else if (stuser->status == SWITCHTEC_MRPC_STATUS_INTERRUPTED) 641*080b47deSLogan Gunthorpe return -ENXIO; 642*080b47deSLogan Gunthorpe else 643*080b47deSLogan Gunthorpe return -EBADMSG; 644*080b47deSLogan Gunthorpe } 645*080b47deSLogan Gunthorpe 646*080b47deSLogan Gunthorpe static unsigned int switchtec_dev_poll(struct file *filp, poll_table *wait) 647*080b47deSLogan Gunthorpe { 648*080b47deSLogan Gunthorpe struct switchtec_user *stuser = filp->private_data; 649*080b47deSLogan Gunthorpe struct switchtec_dev *stdev = stuser->stdev; 650*080b47deSLogan Gunthorpe int ret = 0; 651*080b47deSLogan Gunthorpe 652*080b47deSLogan Gunthorpe poll_wait(filp, &stuser->comp.wait, wait); 653*080b47deSLogan Gunthorpe poll_wait(filp, &stdev->event_wq, wait); 654*080b47deSLogan Gunthorpe 655*080b47deSLogan Gunthorpe if (lock_mutex_and_test_alive(stdev)) 656*080b47deSLogan Gunthorpe return POLLIN | POLLRDHUP | POLLOUT | POLLERR | POLLHUP; 657*080b47deSLogan Gunthorpe 658*080b47deSLogan Gunthorpe mutex_unlock(&stdev->mrpc_mutex); 659*080b47deSLogan Gunthorpe 660*080b47deSLogan Gunthorpe if (try_wait_for_completion(&stuser->comp)) 661*080b47deSLogan Gunthorpe ret |= POLLIN | POLLRDNORM; 662*080b47deSLogan Gunthorpe 663*080b47deSLogan Gunthorpe if (stuser->event_cnt != atomic_read(&stdev->event_cnt)) 664*080b47deSLogan Gunthorpe ret |= POLLPRI | POLLRDBAND; 665*080b47deSLogan Gunthorpe 666*080b47deSLogan Gunthorpe return ret; 667*080b47deSLogan Gunthorpe } 668*080b47deSLogan Gunthorpe 669*080b47deSLogan Gunthorpe static const struct file_operations switchtec_fops = { 670*080b47deSLogan Gunthorpe .owner = THIS_MODULE, 671*080b47deSLogan Gunthorpe .open = switchtec_dev_open, 672*080b47deSLogan Gunthorpe .release = switchtec_dev_release, 673*080b47deSLogan Gunthorpe .write = switchtec_dev_write, 674*080b47deSLogan Gunthorpe .read = switchtec_dev_read, 675*080b47deSLogan Gunthorpe .poll = switchtec_dev_poll, 676*080b47deSLogan Gunthorpe }; 677*080b47deSLogan Gunthorpe 678*080b47deSLogan Gunthorpe static void stdev_release(struct device *dev) 679*080b47deSLogan Gunthorpe { 680*080b47deSLogan Gunthorpe struct switchtec_dev *stdev = to_stdev(dev); 681*080b47deSLogan Gunthorpe 682*080b47deSLogan Gunthorpe kfree(stdev); 683*080b47deSLogan Gunthorpe } 684*080b47deSLogan Gunthorpe 685*080b47deSLogan Gunthorpe static void stdev_kill(struct switchtec_dev *stdev) 686*080b47deSLogan Gunthorpe { 687*080b47deSLogan Gunthorpe struct switchtec_user *stuser, *tmpuser; 688*080b47deSLogan Gunthorpe 689*080b47deSLogan Gunthorpe pci_clear_master(stdev->pdev); 690*080b47deSLogan Gunthorpe 691*080b47deSLogan Gunthorpe cancel_delayed_work_sync(&stdev->mrpc_timeout); 692*080b47deSLogan Gunthorpe 693*080b47deSLogan Gunthorpe /* Mark the hardware as unavailable and complete all completions */ 694*080b47deSLogan Gunthorpe mutex_lock(&stdev->mrpc_mutex); 695*080b47deSLogan Gunthorpe stdev->alive = false; 696*080b47deSLogan Gunthorpe 697*080b47deSLogan Gunthorpe /* Wake up and kill any users waiting on an MRPC request */ 698*080b47deSLogan Gunthorpe list_for_each_entry_safe(stuser, tmpuser, &stdev->mrpc_queue, list) { 699*080b47deSLogan Gunthorpe complete_all(&stuser->comp); 700*080b47deSLogan Gunthorpe list_del_init(&stuser->list); 701*080b47deSLogan Gunthorpe stuser_put(stuser); 702*080b47deSLogan Gunthorpe } 703*080b47deSLogan Gunthorpe 704*080b47deSLogan Gunthorpe mutex_unlock(&stdev->mrpc_mutex); 705*080b47deSLogan Gunthorpe 706*080b47deSLogan Gunthorpe /* Wake up any users waiting on event_wq */ 707*080b47deSLogan Gunthorpe wake_up_interruptible(&stdev->event_wq); 708*080b47deSLogan Gunthorpe } 709*080b47deSLogan Gunthorpe 710*080b47deSLogan Gunthorpe static struct switchtec_dev *stdev_create(struct pci_dev *pdev) 711*080b47deSLogan Gunthorpe { 712*080b47deSLogan Gunthorpe struct switchtec_dev *stdev; 713*080b47deSLogan Gunthorpe int minor; 714*080b47deSLogan Gunthorpe struct device *dev; 715*080b47deSLogan Gunthorpe struct cdev *cdev; 716*080b47deSLogan Gunthorpe int rc; 717*080b47deSLogan Gunthorpe 718*080b47deSLogan Gunthorpe stdev = kzalloc_node(sizeof(*stdev), GFP_KERNEL, 719*080b47deSLogan Gunthorpe dev_to_node(&pdev->dev)); 720*080b47deSLogan Gunthorpe if (!stdev) 721*080b47deSLogan Gunthorpe return ERR_PTR(-ENOMEM); 722*080b47deSLogan Gunthorpe 723*080b47deSLogan Gunthorpe stdev->alive = true; 724*080b47deSLogan Gunthorpe stdev->pdev = pdev; 725*080b47deSLogan Gunthorpe INIT_LIST_HEAD(&stdev->mrpc_queue); 726*080b47deSLogan Gunthorpe mutex_init(&stdev->mrpc_mutex); 727*080b47deSLogan Gunthorpe stdev->mrpc_busy = 0; 728*080b47deSLogan Gunthorpe INIT_WORK(&stdev->mrpc_work, mrpc_event_work); 729*080b47deSLogan Gunthorpe INIT_DELAYED_WORK(&stdev->mrpc_timeout, mrpc_timeout_work); 730*080b47deSLogan Gunthorpe init_waitqueue_head(&stdev->event_wq); 731*080b47deSLogan Gunthorpe atomic_set(&stdev->event_cnt, 0); 732*080b47deSLogan Gunthorpe 733*080b47deSLogan Gunthorpe dev = &stdev->dev; 734*080b47deSLogan Gunthorpe device_initialize(dev); 735*080b47deSLogan Gunthorpe dev->class = switchtec_class; 736*080b47deSLogan Gunthorpe dev->parent = &pdev->dev; 737*080b47deSLogan Gunthorpe dev->release = stdev_release; 738*080b47deSLogan Gunthorpe 739*080b47deSLogan Gunthorpe minor = ida_simple_get(&switchtec_minor_ida, 0, 0, 740*080b47deSLogan Gunthorpe GFP_KERNEL); 741*080b47deSLogan Gunthorpe if (minor < 0) { 742*080b47deSLogan Gunthorpe rc = minor; 743*080b47deSLogan Gunthorpe goto err_put; 744*080b47deSLogan Gunthorpe } 745*080b47deSLogan Gunthorpe 746*080b47deSLogan Gunthorpe dev->devt = MKDEV(MAJOR(switchtec_devt), minor); 747*080b47deSLogan Gunthorpe dev_set_name(dev, "switchtec%d", minor); 748*080b47deSLogan Gunthorpe 749*080b47deSLogan Gunthorpe cdev = &stdev->cdev; 750*080b47deSLogan Gunthorpe cdev_init(cdev, &switchtec_fops); 751*080b47deSLogan Gunthorpe cdev->owner = THIS_MODULE; 752*080b47deSLogan Gunthorpe cdev->kobj.parent = &dev->kobj; 753*080b47deSLogan Gunthorpe 754*080b47deSLogan Gunthorpe return stdev; 755*080b47deSLogan Gunthorpe 756*080b47deSLogan Gunthorpe err_put: 757*080b47deSLogan Gunthorpe put_device(&stdev->dev); 758*080b47deSLogan Gunthorpe return ERR_PTR(rc); 759*080b47deSLogan Gunthorpe } 760*080b47deSLogan Gunthorpe 761*080b47deSLogan Gunthorpe static irqreturn_t switchtec_event_isr(int irq, void *dev) 762*080b47deSLogan Gunthorpe { 763*080b47deSLogan Gunthorpe struct switchtec_dev *stdev = dev; 764*080b47deSLogan Gunthorpe u32 reg; 765*080b47deSLogan Gunthorpe irqreturn_t ret = IRQ_NONE; 766*080b47deSLogan Gunthorpe 767*080b47deSLogan Gunthorpe reg = ioread32(&stdev->mmio_part_cfg->mrpc_comp_hdr); 768*080b47deSLogan Gunthorpe if (reg & SWITCHTEC_EVENT_OCCURRED) { 769*080b47deSLogan Gunthorpe dev_dbg(&stdev->dev, "%s: mrpc comp\n", __func__); 770*080b47deSLogan Gunthorpe ret = IRQ_HANDLED; 771*080b47deSLogan Gunthorpe schedule_work(&stdev->mrpc_work); 772*080b47deSLogan Gunthorpe iowrite32(reg, &stdev->mmio_part_cfg->mrpc_comp_hdr); 773*080b47deSLogan Gunthorpe } 774*080b47deSLogan Gunthorpe 775*080b47deSLogan Gunthorpe return ret; 776*080b47deSLogan Gunthorpe } 777*080b47deSLogan Gunthorpe 778*080b47deSLogan Gunthorpe static int switchtec_init_isr(struct switchtec_dev *stdev) 779*080b47deSLogan Gunthorpe { 780*080b47deSLogan Gunthorpe int nvecs; 781*080b47deSLogan Gunthorpe int event_irq; 782*080b47deSLogan Gunthorpe 783*080b47deSLogan Gunthorpe nvecs = pci_alloc_irq_vectors(stdev->pdev, 1, 4, 784*080b47deSLogan Gunthorpe PCI_IRQ_MSIX | PCI_IRQ_MSI); 785*080b47deSLogan Gunthorpe if (nvecs < 0) 786*080b47deSLogan Gunthorpe return nvecs; 787*080b47deSLogan Gunthorpe 788*080b47deSLogan Gunthorpe event_irq = ioread32(&stdev->mmio_part_cfg->vep_vector_number); 789*080b47deSLogan Gunthorpe if (event_irq < 0 || event_irq >= nvecs) 790*080b47deSLogan Gunthorpe return -EFAULT; 791*080b47deSLogan Gunthorpe 792*080b47deSLogan Gunthorpe event_irq = pci_irq_vector(stdev->pdev, event_irq); 793*080b47deSLogan Gunthorpe if (event_irq < 0) 794*080b47deSLogan Gunthorpe return event_irq; 795*080b47deSLogan Gunthorpe 796*080b47deSLogan Gunthorpe return devm_request_irq(&stdev->pdev->dev, event_irq, 797*080b47deSLogan Gunthorpe switchtec_event_isr, 0, 798*080b47deSLogan Gunthorpe KBUILD_MODNAME, stdev); 799*080b47deSLogan Gunthorpe } 800*080b47deSLogan Gunthorpe 801*080b47deSLogan Gunthorpe static void init_pff(struct switchtec_dev *stdev) 802*080b47deSLogan Gunthorpe { 803*080b47deSLogan Gunthorpe int i; 804*080b47deSLogan Gunthorpe u32 reg; 805*080b47deSLogan Gunthorpe struct part_cfg_regs *pcfg = stdev->mmio_part_cfg; 806*080b47deSLogan Gunthorpe 807*080b47deSLogan Gunthorpe for (i = 0; i < SWITCHTEC_MAX_PFF_CSR; i++) { 808*080b47deSLogan Gunthorpe reg = ioread16(&stdev->mmio_pff_csr[i].vendor_id); 809*080b47deSLogan Gunthorpe if (reg != MICROSEMI_VENDOR_ID) 810*080b47deSLogan Gunthorpe break; 811*080b47deSLogan Gunthorpe } 812*080b47deSLogan Gunthorpe 813*080b47deSLogan Gunthorpe stdev->pff_csr_count = i; 814*080b47deSLogan Gunthorpe 815*080b47deSLogan Gunthorpe reg = ioread32(&pcfg->usp_pff_inst_id); 816*080b47deSLogan Gunthorpe if (reg < SWITCHTEC_MAX_PFF_CSR) 817*080b47deSLogan Gunthorpe stdev->pff_local[reg] = 1; 818*080b47deSLogan Gunthorpe 819*080b47deSLogan Gunthorpe reg = ioread32(&pcfg->vep_pff_inst_id); 820*080b47deSLogan Gunthorpe if (reg < SWITCHTEC_MAX_PFF_CSR) 821*080b47deSLogan Gunthorpe stdev->pff_local[reg] = 1; 822*080b47deSLogan Gunthorpe 823*080b47deSLogan Gunthorpe for (i = 0; i < ARRAY_SIZE(pcfg->dsp_pff_inst_id); i++) { 824*080b47deSLogan Gunthorpe reg = ioread32(&pcfg->dsp_pff_inst_id[i]); 825*080b47deSLogan Gunthorpe if (reg < SWITCHTEC_MAX_PFF_CSR) 826*080b47deSLogan Gunthorpe stdev->pff_local[reg] = 1; 827*080b47deSLogan Gunthorpe } 828*080b47deSLogan Gunthorpe } 829*080b47deSLogan Gunthorpe 830*080b47deSLogan Gunthorpe static int switchtec_init_pci(struct switchtec_dev *stdev, 831*080b47deSLogan Gunthorpe struct pci_dev *pdev) 832*080b47deSLogan Gunthorpe { 833*080b47deSLogan Gunthorpe int rc; 834*080b47deSLogan Gunthorpe 835*080b47deSLogan Gunthorpe rc = pcim_enable_device(pdev); 836*080b47deSLogan Gunthorpe if (rc) 837*080b47deSLogan Gunthorpe return rc; 838*080b47deSLogan Gunthorpe 839*080b47deSLogan Gunthorpe rc = pcim_iomap_regions(pdev, 0x1, KBUILD_MODNAME); 840*080b47deSLogan Gunthorpe if (rc) 841*080b47deSLogan Gunthorpe return rc; 842*080b47deSLogan Gunthorpe 843*080b47deSLogan Gunthorpe pci_set_master(pdev); 844*080b47deSLogan Gunthorpe 845*080b47deSLogan Gunthorpe stdev->mmio = pcim_iomap_table(pdev)[0]; 846*080b47deSLogan Gunthorpe stdev->mmio_mrpc = stdev->mmio + SWITCHTEC_GAS_MRPC_OFFSET; 847*080b47deSLogan Gunthorpe stdev->mmio_sw_event = stdev->mmio + SWITCHTEC_GAS_SW_EVENT_OFFSET; 848*080b47deSLogan Gunthorpe stdev->mmio_sys_info = stdev->mmio + SWITCHTEC_GAS_SYS_INFO_OFFSET; 849*080b47deSLogan Gunthorpe stdev->mmio_flash_info = stdev->mmio + SWITCHTEC_GAS_FLASH_INFO_OFFSET; 850*080b47deSLogan Gunthorpe stdev->mmio_ntb = stdev->mmio + SWITCHTEC_GAS_NTB_OFFSET; 851*080b47deSLogan Gunthorpe stdev->partition = ioread8(&stdev->mmio_ntb->partition_id); 852*080b47deSLogan Gunthorpe stdev->partition_count = ioread8(&stdev->mmio_ntb->partition_count); 853*080b47deSLogan Gunthorpe stdev->mmio_part_cfg_all = stdev->mmio + SWITCHTEC_GAS_PART_CFG_OFFSET; 854*080b47deSLogan Gunthorpe stdev->mmio_part_cfg = &stdev->mmio_part_cfg_all[stdev->partition]; 855*080b47deSLogan Gunthorpe stdev->mmio_pff_csr = stdev->mmio + SWITCHTEC_GAS_PFF_CSR_OFFSET; 856*080b47deSLogan Gunthorpe 857*080b47deSLogan Gunthorpe init_pff(stdev); 858*080b47deSLogan Gunthorpe 859*080b47deSLogan Gunthorpe pci_set_drvdata(pdev, stdev); 860*080b47deSLogan Gunthorpe 861*080b47deSLogan Gunthorpe return 0; 862*080b47deSLogan Gunthorpe } 863*080b47deSLogan Gunthorpe 864*080b47deSLogan Gunthorpe static int switchtec_pci_probe(struct pci_dev *pdev, 865*080b47deSLogan Gunthorpe const struct pci_device_id *id) 866*080b47deSLogan Gunthorpe { 867*080b47deSLogan Gunthorpe struct switchtec_dev *stdev; 868*080b47deSLogan Gunthorpe int rc; 869*080b47deSLogan Gunthorpe 870*080b47deSLogan Gunthorpe stdev = stdev_create(pdev); 871*080b47deSLogan Gunthorpe if (IS_ERR(stdev)) 872*080b47deSLogan Gunthorpe return PTR_ERR(stdev); 873*080b47deSLogan Gunthorpe 874*080b47deSLogan Gunthorpe rc = switchtec_init_pci(stdev, pdev); 875*080b47deSLogan Gunthorpe if (rc) 876*080b47deSLogan Gunthorpe goto err_put; 877*080b47deSLogan Gunthorpe 878*080b47deSLogan Gunthorpe rc = switchtec_init_isr(stdev); 879*080b47deSLogan Gunthorpe if (rc) { 880*080b47deSLogan Gunthorpe dev_err(&stdev->dev, "failed to init isr.\n"); 881*080b47deSLogan Gunthorpe goto err_put; 882*080b47deSLogan Gunthorpe } 883*080b47deSLogan Gunthorpe 884*080b47deSLogan Gunthorpe iowrite32(SWITCHTEC_EVENT_CLEAR | 885*080b47deSLogan Gunthorpe SWITCHTEC_EVENT_EN_IRQ, 886*080b47deSLogan Gunthorpe &stdev->mmio_part_cfg->mrpc_comp_hdr); 887*080b47deSLogan Gunthorpe 888*080b47deSLogan Gunthorpe rc = cdev_add(&stdev->cdev, stdev->dev.devt, 1); 889*080b47deSLogan Gunthorpe if (rc) 890*080b47deSLogan Gunthorpe goto err_put; 891*080b47deSLogan Gunthorpe 892*080b47deSLogan Gunthorpe rc = device_add(&stdev->dev); 893*080b47deSLogan Gunthorpe if (rc) 894*080b47deSLogan Gunthorpe goto err_devadd; 895*080b47deSLogan Gunthorpe 896*080b47deSLogan Gunthorpe dev_info(&stdev->dev, "Management device registered.\n"); 897*080b47deSLogan Gunthorpe 898*080b47deSLogan Gunthorpe return 0; 899*080b47deSLogan Gunthorpe 900*080b47deSLogan Gunthorpe err_devadd: 901*080b47deSLogan Gunthorpe cdev_del(&stdev->cdev); 902*080b47deSLogan Gunthorpe stdev_kill(stdev); 903*080b47deSLogan Gunthorpe err_put: 904*080b47deSLogan Gunthorpe ida_simple_remove(&switchtec_minor_ida, MINOR(stdev->dev.devt)); 905*080b47deSLogan Gunthorpe put_device(&stdev->dev); 906*080b47deSLogan Gunthorpe return rc; 907*080b47deSLogan Gunthorpe } 908*080b47deSLogan Gunthorpe 909*080b47deSLogan Gunthorpe static void switchtec_pci_remove(struct pci_dev *pdev) 910*080b47deSLogan Gunthorpe { 911*080b47deSLogan Gunthorpe struct switchtec_dev *stdev = pci_get_drvdata(pdev); 912*080b47deSLogan Gunthorpe 913*080b47deSLogan Gunthorpe pci_set_drvdata(pdev, NULL); 914*080b47deSLogan Gunthorpe 915*080b47deSLogan Gunthorpe device_del(&stdev->dev); 916*080b47deSLogan Gunthorpe cdev_del(&stdev->cdev); 917*080b47deSLogan Gunthorpe ida_simple_remove(&switchtec_minor_ida, MINOR(stdev->dev.devt)); 918*080b47deSLogan Gunthorpe dev_info(&stdev->dev, "unregistered.\n"); 919*080b47deSLogan Gunthorpe 920*080b47deSLogan Gunthorpe stdev_kill(stdev); 921*080b47deSLogan Gunthorpe put_device(&stdev->dev); 922*080b47deSLogan Gunthorpe } 923*080b47deSLogan Gunthorpe 924*080b47deSLogan Gunthorpe #define SWITCHTEC_PCI_DEVICE(device_id) \ 925*080b47deSLogan Gunthorpe { \ 926*080b47deSLogan Gunthorpe .vendor = MICROSEMI_VENDOR_ID, \ 927*080b47deSLogan Gunthorpe .device = device_id, \ 928*080b47deSLogan Gunthorpe .subvendor = PCI_ANY_ID, \ 929*080b47deSLogan Gunthorpe .subdevice = PCI_ANY_ID, \ 930*080b47deSLogan Gunthorpe .class = MICROSEMI_MGMT_CLASSCODE, \ 931*080b47deSLogan Gunthorpe .class_mask = 0xFFFFFFFF, \ 932*080b47deSLogan Gunthorpe }, \ 933*080b47deSLogan Gunthorpe { \ 934*080b47deSLogan Gunthorpe .vendor = MICROSEMI_VENDOR_ID, \ 935*080b47deSLogan Gunthorpe .device = device_id, \ 936*080b47deSLogan Gunthorpe .subvendor = PCI_ANY_ID, \ 937*080b47deSLogan Gunthorpe .subdevice = PCI_ANY_ID, \ 938*080b47deSLogan Gunthorpe .class = MICROSEMI_NTB_CLASSCODE, \ 939*080b47deSLogan Gunthorpe .class_mask = 0xFFFFFFFF, \ 940*080b47deSLogan Gunthorpe } 941*080b47deSLogan Gunthorpe 942*080b47deSLogan Gunthorpe static const struct pci_device_id switchtec_pci_tbl[] = { 943*080b47deSLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8531), //PFX 24xG3 944*080b47deSLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8532), //PFX 32xG3 945*080b47deSLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8533), //PFX 48xG3 946*080b47deSLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8534), //PFX 64xG3 947*080b47deSLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8535), //PFX 80xG3 948*080b47deSLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8536), //PFX 96xG3 949*080b47deSLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8543), //PSX 48xG3 950*080b47deSLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8544), //PSX 64xG3 951*080b47deSLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8545), //PSX 80xG3 952*080b47deSLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8546), //PSX 96xG3 953*080b47deSLogan Gunthorpe {0} 954*080b47deSLogan Gunthorpe }; 955*080b47deSLogan Gunthorpe MODULE_DEVICE_TABLE(pci, switchtec_pci_tbl); 956*080b47deSLogan Gunthorpe 957*080b47deSLogan Gunthorpe static struct pci_driver switchtec_pci_driver = { 958*080b47deSLogan Gunthorpe .name = KBUILD_MODNAME, 959*080b47deSLogan Gunthorpe .id_table = switchtec_pci_tbl, 960*080b47deSLogan Gunthorpe .probe = switchtec_pci_probe, 961*080b47deSLogan Gunthorpe .remove = switchtec_pci_remove, 962*080b47deSLogan Gunthorpe }; 963*080b47deSLogan Gunthorpe 964*080b47deSLogan Gunthorpe static int __init switchtec_init(void) 965*080b47deSLogan Gunthorpe { 966*080b47deSLogan Gunthorpe int rc; 967*080b47deSLogan Gunthorpe 968*080b47deSLogan Gunthorpe rc = alloc_chrdev_region(&switchtec_devt, 0, max_devices, 969*080b47deSLogan Gunthorpe "switchtec"); 970*080b47deSLogan Gunthorpe if (rc) 971*080b47deSLogan Gunthorpe return rc; 972*080b47deSLogan Gunthorpe 973*080b47deSLogan Gunthorpe switchtec_class = class_create(THIS_MODULE, "switchtec"); 974*080b47deSLogan Gunthorpe if (IS_ERR(switchtec_class)) { 975*080b47deSLogan Gunthorpe rc = PTR_ERR(switchtec_class); 976*080b47deSLogan Gunthorpe goto err_create_class; 977*080b47deSLogan Gunthorpe } 978*080b47deSLogan Gunthorpe 979*080b47deSLogan Gunthorpe rc = pci_register_driver(&switchtec_pci_driver); 980*080b47deSLogan Gunthorpe if (rc) 981*080b47deSLogan Gunthorpe goto err_pci_register; 982*080b47deSLogan Gunthorpe 983*080b47deSLogan Gunthorpe pr_info(KBUILD_MODNAME ": loaded.\n"); 984*080b47deSLogan Gunthorpe 985*080b47deSLogan Gunthorpe return 0; 986*080b47deSLogan Gunthorpe 987*080b47deSLogan Gunthorpe err_pci_register: 988*080b47deSLogan Gunthorpe class_destroy(switchtec_class); 989*080b47deSLogan Gunthorpe 990*080b47deSLogan Gunthorpe err_create_class: 991*080b47deSLogan Gunthorpe unregister_chrdev_region(switchtec_devt, max_devices); 992*080b47deSLogan Gunthorpe 993*080b47deSLogan Gunthorpe return rc; 994*080b47deSLogan Gunthorpe } 995*080b47deSLogan Gunthorpe module_init(switchtec_init); 996*080b47deSLogan Gunthorpe 997*080b47deSLogan Gunthorpe static void __exit switchtec_exit(void) 998*080b47deSLogan Gunthorpe { 999*080b47deSLogan Gunthorpe pci_unregister_driver(&switchtec_pci_driver); 1000*080b47deSLogan Gunthorpe class_destroy(switchtec_class); 1001*080b47deSLogan Gunthorpe unregister_chrdev_region(switchtec_devt, max_devices); 1002*080b47deSLogan Gunthorpe ida_destroy(&switchtec_minor_ida); 1003*080b47deSLogan Gunthorpe 1004*080b47deSLogan Gunthorpe pr_info(KBUILD_MODNAME ": unloaded.\n"); 1005*080b47deSLogan Gunthorpe } 1006*080b47deSLogan Gunthorpe module_exit(switchtec_exit); 1007