1080b47deSLogan Gunthorpe /* 2080b47deSLogan Gunthorpe * Microsemi Switchtec(tm) PCIe Management Driver 3080b47deSLogan Gunthorpe * Copyright (c) 2017, Microsemi Corporation 4080b47deSLogan Gunthorpe * 5080b47deSLogan Gunthorpe * This program is free software; you can redistribute it and/or modify it 6080b47deSLogan Gunthorpe * under the terms and conditions of the GNU General Public License, 7080b47deSLogan Gunthorpe * version 2, as published by the Free Software Foundation. 8080b47deSLogan Gunthorpe * 9080b47deSLogan Gunthorpe * This program is distributed in the hope it will be useful, but WITHOUT 10080b47deSLogan Gunthorpe * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11080b47deSLogan Gunthorpe * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12080b47deSLogan Gunthorpe * more details. 13080b47deSLogan Gunthorpe * 14080b47deSLogan Gunthorpe */ 15080b47deSLogan Gunthorpe 16080b47deSLogan Gunthorpe #include <linux/interrupt.h> 17080b47deSLogan Gunthorpe #include <linux/module.h> 18080b47deSLogan Gunthorpe #include <linux/fs.h> 19080b47deSLogan Gunthorpe #include <linux/uaccess.h> 20080b47deSLogan Gunthorpe #include <linux/poll.h> 21080b47deSLogan Gunthorpe #include <linux/pci.h> 22080b47deSLogan Gunthorpe #include <linux/cdev.h> 23080b47deSLogan Gunthorpe #include <linux/wait.h> 24080b47deSLogan Gunthorpe 25080b47deSLogan Gunthorpe MODULE_DESCRIPTION("Microsemi Switchtec(tm) PCIe Management Driver"); 26080b47deSLogan Gunthorpe MODULE_VERSION("0.1"); 27080b47deSLogan Gunthorpe MODULE_LICENSE("GPL"); 28080b47deSLogan Gunthorpe MODULE_AUTHOR("Microsemi Corporation"); 29080b47deSLogan Gunthorpe 30080b47deSLogan Gunthorpe static int max_devices = 16; 31080b47deSLogan Gunthorpe module_param(max_devices, int, 0644); 32080b47deSLogan Gunthorpe MODULE_PARM_DESC(max_devices, "max number of switchtec device instances"); 33080b47deSLogan Gunthorpe 34080b47deSLogan Gunthorpe static dev_t switchtec_devt; 35080b47deSLogan Gunthorpe static struct class *switchtec_class; 36080b47deSLogan Gunthorpe static DEFINE_IDA(switchtec_minor_ida); 37080b47deSLogan Gunthorpe 38080b47deSLogan Gunthorpe #define MICROSEMI_VENDOR_ID 0x11f8 39080b47deSLogan Gunthorpe #define MICROSEMI_NTB_CLASSCODE 0x068000 40080b47deSLogan Gunthorpe #define MICROSEMI_MGMT_CLASSCODE 0x058000 41080b47deSLogan Gunthorpe 42080b47deSLogan Gunthorpe #define SWITCHTEC_MRPC_PAYLOAD_SIZE 1024 43080b47deSLogan Gunthorpe #define SWITCHTEC_MAX_PFF_CSR 48 44080b47deSLogan Gunthorpe 45080b47deSLogan Gunthorpe #define SWITCHTEC_EVENT_OCCURRED BIT(0) 46080b47deSLogan Gunthorpe #define SWITCHTEC_EVENT_CLEAR BIT(0) 47080b47deSLogan Gunthorpe #define SWITCHTEC_EVENT_EN_LOG BIT(1) 48080b47deSLogan Gunthorpe #define SWITCHTEC_EVENT_EN_CLI BIT(2) 49080b47deSLogan Gunthorpe #define SWITCHTEC_EVENT_EN_IRQ BIT(3) 50080b47deSLogan Gunthorpe #define SWITCHTEC_EVENT_FATAL BIT(4) 51080b47deSLogan Gunthorpe 52080b47deSLogan Gunthorpe enum { 53080b47deSLogan Gunthorpe SWITCHTEC_GAS_MRPC_OFFSET = 0x0000, 54080b47deSLogan Gunthorpe SWITCHTEC_GAS_TOP_CFG_OFFSET = 0x1000, 55080b47deSLogan Gunthorpe SWITCHTEC_GAS_SW_EVENT_OFFSET = 0x1800, 56080b47deSLogan Gunthorpe SWITCHTEC_GAS_SYS_INFO_OFFSET = 0x2000, 57080b47deSLogan Gunthorpe SWITCHTEC_GAS_FLASH_INFO_OFFSET = 0x2200, 58080b47deSLogan Gunthorpe SWITCHTEC_GAS_PART_CFG_OFFSET = 0x4000, 59080b47deSLogan Gunthorpe SWITCHTEC_GAS_NTB_OFFSET = 0x10000, 60080b47deSLogan Gunthorpe SWITCHTEC_GAS_PFF_CSR_OFFSET = 0x134000, 61080b47deSLogan Gunthorpe }; 62080b47deSLogan Gunthorpe 63080b47deSLogan Gunthorpe struct mrpc_regs { 64080b47deSLogan Gunthorpe u8 input_data[SWITCHTEC_MRPC_PAYLOAD_SIZE]; 65080b47deSLogan Gunthorpe u8 output_data[SWITCHTEC_MRPC_PAYLOAD_SIZE]; 66080b47deSLogan Gunthorpe u32 cmd; 67080b47deSLogan Gunthorpe u32 status; 68080b47deSLogan Gunthorpe u32 ret_value; 69080b47deSLogan Gunthorpe } __packed; 70080b47deSLogan Gunthorpe 71080b47deSLogan Gunthorpe enum mrpc_status { 72080b47deSLogan Gunthorpe SWITCHTEC_MRPC_STATUS_INPROGRESS = 1, 73080b47deSLogan Gunthorpe SWITCHTEC_MRPC_STATUS_DONE = 2, 74080b47deSLogan Gunthorpe SWITCHTEC_MRPC_STATUS_ERROR = 0xFF, 75080b47deSLogan Gunthorpe SWITCHTEC_MRPC_STATUS_INTERRUPTED = 0x100, 76080b47deSLogan Gunthorpe }; 77080b47deSLogan Gunthorpe 78080b47deSLogan Gunthorpe struct sw_event_regs { 79080b47deSLogan Gunthorpe u64 event_report_ctrl; 80080b47deSLogan Gunthorpe u64 reserved1; 81080b47deSLogan Gunthorpe u64 part_event_bitmap; 82080b47deSLogan Gunthorpe u64 reserved2; 83080b47deSLogan Gunthorpe u32 global_summary; 84080b47deSLogan Gunthorpe u32 reserved3[3]; 85080b47deSLogan Gunthorpe u32 stack_error_event_hdr; 86080b47deSLogan Gunthorpe u32 stack_error_event_data; 87080b47deSLogan Gunthorpe u32 reserved4[4]; 88080b47deSLogan Gunthorpe u32 ppu_error_event_hdr; 89080b47deSLogan Gunthorpe u32 ppu_error_event_data; 90080b47deSLogan Gunthorpe u32 reserved5[4]; 91080b47deSLogan Gunthorpe u32 isp_error_event_hdr; 92080b47deSLogan Gunthorpe u32 isp_error_event_data; 93080b47deSLogan Gunthorpe u32 reserved6[4]; 94080b47deSLogan Gunthorpe u32 sys_reset_event_hdr; 95080b47deSLogan Gunthorpe u32 reserved7[5]; 96080b47deSLogan Gunthorpe u32 fw_exception_hdr; 97080b47deSLogan Gunthorpe u32 reserved8[5]; 98080b47deSLogan Gunthorpe u32 fw_nmi_hdr; 99080b47deSLogan Gunthorpe u32 reserved9[5]; 100080b47deSLogan Gunthorpe u32 fw_non_fatal_hdr; 101080b47deSLogan Gunthorpe u32 reserved10[5]; 102080b47deSLogan Gunthorpe u32 fw_fatal_hdr; 103080b47deSLogan Gunthorpe u32 reserved11[5]; 104080b47deSLogan Gunthorpe u32 twi_mrpc_comp_hdr; 105080b47deSLogan Gunthorpe u32 twi_mrpc_comp_data; 106080b47deSLogan Gunthorpe u32 reserved12[4]; 107080b47deSLogan Gunthorpe u32 twi_mrpc_comp_async_hdr; 108080b47deSLogan Gunthorpe u32 twi_mrpc_comp_async_data; 109080b47deSLogan Gunthorpe u32 reserved13[4]; 110080b47deSLogan Gunthorpe u32 cli_mrpc_comp_hdr; 111080b47deSLogan Gunthorpe u32 cli_mrpc_comp_data; 112080b47deSLogan Gunthorpe u32 reserved14[4]; 113080b47deSLogan Gunthorpe u32 cli_mrpc_comp_async_hdr; 114080b47deSLogan Gunthorpe u32 cli_mrpc_comp_async_data; 115080b47deSLogan Gunthorpe u32 reserved15[4]; 116080b47deSLogan Gunthorpe u32 gpio_interrupt_hdr; 117080b47deSLogan Gunthorpe u32 gpio_interrupt_data; 118080b47deSLogan Gunthorpe u32 reserved16[4]; 119080b47deSLogan Gunthorpe } __packed; 120080b47deSLogan Gunthorpe 121080b47deSLogan Gunthorpe struct sys_info_regs { 122080b47deSLogan Gunthorpe u32 device_id; 123080b47deSLogan Gunthorpe u32 device_version; 124080b47deSLogan Gunthorpe u32 firmware_version; 125080b47deSLogan Gunthorpe u32 reserved1; 126080b47deSLogan Gunthorpe u32 vendor_table_revision; 127080b47deSLogan Gunthorpe u32 table_format_version; 128080b47deSLogan Gunthorpe u32 partition_id; 129080b47deSLogan Gunthorpe u32 cfg_file_fmt_version; 130080b47deSLogan Gunthorpe u32 reserved2[58]; 131080b47deSLogan Gunthorpe char vendor_id[8]; 132080b47deSLogan Gunthorpe char product_id[16]; 133080b47deSLogan Gunthorpe char product_revision[4]; 134080b47deSLogan Gunthorpe char component_vendor[8]; 135080b47deSLogan Gunthorpe u16 component_id; 136080b47deSLogan Gunthorpe u8 component_revision; 137080b47deSLogan Gunthorpe } __packed; 138080b47deSLogan Gunthorpe 139080b47deSLogan Gunthorpe struct flash_info_regs { 140080b47deSLogan Gunthorpe u32 flash_part_map_upd_idx; 141080b47deSLogan Gunthorpe 142080b47deSLogan Gunthorpe struct active_partition_info { 143080b47deSLogan Gunthorpe u32 address; 144080b47deSLogan Gunthorpe u32 build_version; 145080b47deSLogan Gunthorpe u32 build_string; 146080b47deSLogan Gunthorpe } active_img; 147080b47deSLogan Gunthorpe 148080b47deSLogan Gunthorpe struct active_partition_info active_cfg; 149080b47deSLogan Gunthorpe struct active_partition_info inactive_img; 150080b47deSLogan Gunthorpe struct active_partition_info inactive_cfg; 151080b47deSLogan Gunthorpe 152080b47deSLogan Gunthorpe u32 flash_length; 153080b47deSLogan Gunthorpe 154080b47deSLogan Gunthorpe struct partition_info { 155080b47deSLogan Gunthorpe u32 address; 156080b47deSLogan Gunthorpe u32 length; 157080b47deSLogan Gunthorpe } cfg0; 158080b47deSLogan Gunthorpe 159080b47deSLogan Gunthorpe struct partition_info cfg1; 160080b47deSLogan Gunthorpe struct partition_info img0; 161080b47deSLogan Gunthorpe struct partition_info img1; 162080b47deSLogan Gunthorpe struct partition_info nvlog; 163080b47deSLogan Gunthorpe struct partition_info vendor[8]; 164080b47deSLogan Gunthorpe }; 165080b47deSLogan Gunthorpe 166080b47deSLogan Gunthorpe struct ntb_info_regs { 167080b47deSLogan Gunthorpe u8 partition_count; 168080b47deSLogan Gunthorpe u8 partition_id; 169080b47deSLogan Gunthorpe u16 reserved1; 170080b47deSLogan Gunthorpe u64 ep_map; 171080b47deSLogan Gunthorpe u16 requester_id; 172080b47deSLogan Gunthorpe } __packed; 173080b47deSLogan Gunthorpe 174080b47deSLogan Gunthorpe struct part_cfg_regs { 175080b47deSLogan Gunthorpe u32 status; 176080b47deSLogan Gunthorpe u32 state; 177080b47deSLogan Gunthorpe u32 port_cnt; 178080b47deSLogan Gunthorpe u32 usp_port_mode; 179080b47deSLogan Gunthorpe u32 usp_pff_inst_id; 180080b47deSLogan Gunthorpe u32 vep_pff_inst_id; 181080b47deSLogan Gunthorpe u32 dsp_pff_inst_id[47]; 182080b47deSLogan Gunthorpe u32 reserved1[11]; 183080b47deSLogan Gunthorpe u16 vep_vector_number; 184080b47deSLogan Gunthorpe u16 usp_vector_number; 185080b47deSLogan Gunthorpe u32 port_event_bitmap; 186080b47deSLogan Gunthorpe u32 reserved2[3]; 187080b47deSLogan Gunthorpe u32 part_event_summary; 188080b47deSLogan Gunthorpe u32 reserved3[3]; 189080b47deSLogan Gunthorpe u32 part_reset_hdr; 190080b47deSLogan Gunthorpe u32 part_reset_data[5]; 191080b47deSLogan Gunthorpe u32 mrpc_comp_hdr; 192080b47deSLogan Gunthorpe u32 mrpc_comp_data[5]; 193080b47deSLogan Gunthorpe u32 mrpc_comp_async_hdr; 194080b47deSLogan Gunthorpe u32 mrpc_comp_async_data[5]; 195080b47deSLogan Gunthorpe u32 dyn_binding_hdr; 196080b47deSLogan Gunthorpe u32 dyn_binding_data[5]; 197080b47deSLogan Gunthorpe u32 reserved4[159]; 198080b47deSLogan Gunthorpe } __packed; 199080b47deSLogan Gunthorpe 200080b47deSLogan Gunthorpe enum { 201080b47deSLogan Gunthorpe SWITCHTEC_PART_CFG_EVENT_RESET = 1 << 0, 202080b47deSLogan Gunthorpe SWITCHTEC_PART_CFG_EVENT_MRPC_CMP = 1 << 1, 203080b47deSLogan Gunthorpe SWITCHTEC_PART_CFG_EVENT_MRPC_ASYNC_CMP = 1 << 2, 204080b47deSLogan Gunthorpe SWITCHTEC_PART_CFG_EVENT_DYN_PART_CMP = 1 << 3, 205080b47deSLogan Gunthorpe }; 206080b47deSLogan Gunthorpe 207080b47deSLogan Gunthorpe struct pff_csr_regs { 208080b47deSLogan Gunthorpe u16 vendor_id; 209080b47deSLogan Gunthorpe u16 device_id; 210080b47deSLogan Gunthorpe u32 pci_cfg_header[15]; 211080b47deSLogan Gunthorpe u32 pci_cap_region[48]; 212080b47deSLogan Gunthorpe u32 pcie_cap_region[448]; 213080b47deSLogan Gunthorpe u32 indirect_gas_window[128]; 214080b47deSLogan Gunthorpe u32 indirect_gas_window_off; 215080b47deSLogan Gunthorpe u32 reserved[127]; 216080b47deSLogan Gunthorpe u32 pff_event_summary; 217080b47deSLogan Gunthorpe u32 reserved2[3]; 218080b47deSLogan Gunthorpe u32 aer_in_p2p_hdr; 219080b47deSLogan Gunthorpe u32 aer_in_p2p_data[5]; 220080b47deSLogan Gunthorpe u32 aer_in_vep_hdr; 221080b47deSLogan Gunthorpe u32 aer_in_vep_data[5]; 222080b47deSLogan Gunthorpe u32 dpc_hdr; 223080b47deSLogan Gunthorpe u32 dpc_data[5]; 224080b47deSLogan Gunthorpe u32 cts_hdr; 225080b47deSLogan Gunthorpe u32 cts_data[5]; 226080b47deSLogan Gunthorpe u32 reserved3[6]; 227080b47deSLogan Gunthorpe u32 hotplug_hdr; 228080b47deSLogan Gunthorpe u32 hotplug_data[5]; 229080b47deSLogan Gunthorpe u32 ier_hdr; 230080b47deSLogan Gunthorpe u32 ier_data[5]; 231080b47deSLogan Gunthorpe u32 threshold_hdr; 232080b47deSLogan Gunthorpe u32 threshold_data[5]; 233080b47deSLogan Gunthorpe u32 power_mgmt_hdr; 234080b47deSLogan Gunthorpe u32 power_mgmt_data[5]; 235080b47deSLogan Gunthorpe u32 tlp_throttling_hdr; 236080b47deSLogan Gunthorpe u32 tlp_throttling_data[5]; 237080b47deSLogan Gunthorpe u32 force_speed_hdr; 238080b47deSLogan Gunthorpe u32 force_speed_data[5]; 239080b47deSLogan Gunthorpe u32 credit_timeout_hdr; 240080b47deSLogan Gunthorpe u32 credit_timeout_data[5]; 241080b47deSLogan Gunthorpe u32 link_state_hdr; 242080b47deSLogan Gunthorpe u32 link_state_data[5]; 243080b47deSLogan Gunthorpe u32 reserved4[174]; 244080b47deSLogan Gunthorpe } __packed; 245080b47deSLogan Gunthorpe 246080b47deSLogan Gunthorpe struct switchtec_dev { 247080b47deSLogan Gunthorpe struct pci_dev *pdev; 248080b47deSLogan Gunthorpe struct device dev; 249080b47deSLogan Gunthorpe struct cdev cdev; 250080b47deSLogan Gunthorpe 251080b47deSLogan Gunthorpe int partition; 252080b47deSLogan Gunthorpe int partition_count; 253080b47deSLogan Gunthorpe int pff_csr_count; 254080b47deSLogan Gunthorpe char pff_local[SWITCHTEC_MAX_PFF_CSR]; 255080b47deSLogan Gunthorpe 256080b47deSLogan Gunthorpe void __iomem *mmio; 257080b47deSLogan Gunthorpe struct mrpc_regs __iomem *mmio_mrpc; 258080b47deSLogan Gunthorpe struct sw_event_regs __iomem *mmio_sw_event; 259080b47deSLogan Gunthorpe struct sys_info_regs __iomem *mmio_sys_info; 260080b47deSLogan Gunthorpe struct flash_info_regs __iomem *mmio_flash_info; 261080b47deSLogan Gunthorpe struct ntb_info_regs __iomem *mmio_ntb; 262080b47deSLogan Gunthorpe struct part_cfg_regs __iomem *mmio_part_cfg; 263080b47deSLogan Gunthorpe struct part_cfg_regs __iomem *mmio_part_cfg_all; 264080b47deSLogan Gunthorpe struct pff_csr_regs __iomem *mmio_pff_csr; 265080b47deSLogan Gunthorpe 266080b47deSLogan Gunthorpe /* 267080b47deSLogan Gunthorpe * The mrpc mutex must be held when accessing the other 268080b47deSLogan Gunthorpe * mrpc_ fields, alive flag and stuser->state field 269080b47deSLogan Gunthorpe */ 270080b47deSLogan Gunthorpe struct mutex mrpc_mutex; 271080b47deSLogan Gunthorpe struct list_head mrpc_queue; 272080b47deSLogan Gunthorpe int mrpc_busy; 273080b47deSLogan Gunthorpe struct work_struct mrpc_work; 274080b47deSLogan Gunthorpe struct delayed_work mrpc_timeout; 275080b47deSLogan Gunthorpe bool alive; 276080b47deSLogan Gunthorpe 277080b47deSLogan Gunthorpe wait_queue_head_t event_wq; 278080b47deSLogan Gunthorpe atomic_t event_cnt; 279080b47deSLogan Gunthorpe }; 280080b47deSLogan Gunthorpe 281080b47deSLogan Gunthorpe static struct switchtec_dev *to_stdev(struct device *dev) 282080b47deSLogan Gunthorpe { 283080b47deSLogan Gunthorpe return container_of(dev, struct switchtec_dev, dev); 284080b47deSLogan Gunthorpe } 285080b47deSLogan Gunthorpe 286080b47deSLogan Gunthorpe enum mrpc_state { 287080b47deSLogan Gunthorpe MRPC_IDLE = 0, 288080b47deSLogan Gunthorpe MRPC_QUEUED, 289080b47deSLogan Gunthorpe MRPC_RUNNING, 290080b47deSLogan Gunthorpe MRPC_DONE, 291080b47deSLogan Gunthorpe }; 292080b47deSLogan Gunthorpe 293080b47deSLogan Gunthorpe struct switchtec_user { 294080b47deSLogan Gunthorpe struct switchtec_dev *stdev; 295080b47deSLogan Gunthorpe 296080b47deSLogan Gunthorpe enum mrpc_state state; 297080b47deSLogan Gunthorpe 298080b47deSLogan Gunthorpe struct completion comp; 299080b47deSLogan Gunthorpe struct kref kref; 300080b47deSLogan Gunthorpe struct list_head list; 301080b47deSLogan Gunthorpe 302080b47deSLogan Gunthorpe u32 cmd; 303080b47deSLogan Gunthorpe u32 status; 304080b47deSLogan Gunthorpe u32 return_code; 305080b47deSLogan Gunthorpe size_t data_len; 306080b47deSLogan Gunthorpe size_t read_len; 307080b47deSLogan Gunthorpe unsigned char data[SWITCHTEC_MRPC_PAYLOAD_SIZE]; 308080b47deSLogan Gunthorpe int event_cnt; 309080b47deSLogan Gunthorpe }; 310080b47deSLogan Gunthorpe 311080b47deSLogan Gunthorpe static struct switchtec_user *stuser_create(struct switchtec_dev *stdev) 312080b47deSLogan Gunthorpe { 313080b47deSLogan Gunthorpe struct switchtec_user *stuser; 314080b47deSLogan Gunthorpe 315080b47deSLogan Gunthorpe stuser = kzalloc(sizeof(*stuser), GFP_KERNEL); 316080b47deSLogan Gunthorpe if (!stuser) 317080b47deSLogan Gunthorpe return ERR_PTR(-ENOMEM); 318080b47deSLogan Gunthorpe 319080b47deSLogan Gunthorpe get_device(&stdev->dev); 320080b47deSLogan Gunthorpe stuser->stdev = stdev; 321080b47deSLogan Gunthorpe kref_init(&stuser->kref); 322080b47deSLogan Gunthorpe INIT_LIST_HEAD(&stuser->list); 323080b47deSLogan Gunthorpe init_completion(&stuser->comp); 324080b47deSLogan Gunthorpe stuser->event_cnt = atomic_read(&stdev->event_cnt); 325080b47deSLogan Gunthorpe 326080b47deSLogan Gunthorpe dev_dbg(&stdev->dev, "%s: %p\n", __func__, stuser); 327080b47deSLogan Gunthorpe 328080b47deSLogan Gunthorpe return stuser; 329080b47deSLogan Gunthorpe } 330080b47deSLogan Gunthorpe 331080b47deSLogan Gunthorpe static void stuser_free(struct kref *kref) 332080b47deSLogan Gunthorpe { 333080b47deSLogan Gunthorpe struct switchtec_user *stuser; 334080b47deSLogan Gunthorpe 335080b47deSLogan Gunthorpe stuser = container_of(kref, struct switchtec_user, kref); 336080b47deSLogan Gunthorpe 337080b47deSLogan Gunthorpe dev_dbg(&stuser->stdev->dev, "%s: %p\n", __func__, stuser); 338080b47deSLogan Gunthorpe 339080b47deSLogan Gunthorpe put_device(&stuser->stdev->dev); 340080b47deSLogan Gunthorpe kfree(stuser); 341080b47deSLogan Gunthorpe } 342080b47deSLogan Gunthorpe 343080b47deSLogan Gunthorpe static void stuser_put(struct switchtec_user *stuser) 344080b47deSLogan Gunthorpe { 345080b47deSLogan Gunthorpe kref_put(&stuser->kref, stuser_free); 346080b47deSLogan Gunthorpe } 347080b47deSLogan Gunthorpe 348080b47deSLogan Gunthorpe static void stuser_set_state(struct switchtec_user *stuser, 349080b47deSLogan Gunthorpe enum mrpc_state state) 350080b47deSLogan Gunthorpe { 351080b47deSLogan Gunthorpe /* requires the mrpc_mutex to already be held when called */ 352080b47deSLogan Gunthorpe 353080b47deSLogan Gunthorpe const char * const state_names[] = { 354080b47deSLogan Gunthorpe [MRPC_IDLE] = "IDLE", 355080b47deSLogan Gunthorpe [MRPC_QUEUED] = "QUEUED", 356080b47deSLogan Gunthorpe [MRPC_RUNNING] = "RUNNING", 357080b47deSLogan Gunthorpe [MRPC_DONE] = "DONE", 358080b47deSLogan Gunthorpe }; 359080b47deSLogan Gunthorpe 360080b47deSLogan Gunthorpe stuser->state = state; 361080b47deSLogan Gunthorpe 362080b47deSLogan Gunthorpe dev_dbg(&stuser->stdev->dev, "stuser state %p -> %s", 363080b47deSLogan Gunthorpe stuser, state_names[state]); 364080b47deSLogan Gunthorpe } 365080b47deSLogan Gunthorpe 366080b47deSLogan Gunthorpe static void mrpc_complete_cmd(struct switchtec_dev *stdev); 367080b47deSLogan Gunthorpe 368080b47deSLogan Gunthorpe static void mrpc_cmd_submit(struct switchtec_dev *stdev) 369080b47deSLogan Gunthorpe { 370080b47deSLogan Gunthorpe /* requires the mrpc_mutex to already be held when called */ 371080b47deSLogan Gunthorpe 372080b47deSLogan Gunthorpe struct switchtec_user *stuser; 373080b47deSLogan Gunthorpe 374080b47deSLogan Gunthorpe if (stdev->mrpc_busy) 375080b47deSLogan Gunthorpe return; 376080b47deSLogan Gunthorpe 377080b47deSLogan Gunthorpe if (list_empty(&stdev->mrpc_queue)) 378080b47deSLogan Gunthorpe return; 379080b47deSLogan Gunthorpe 380080b47deSLogan Gunthorpe stuser = list_entry(stdev->mrpc_queue.next, struct switchtec_user, 381080b47deSLogan Gunthorpe list); 382080b47deSLogan Gunthorpe 383080b47deSLogan Gunthorpe stuser_set_state(stuser, MRPC_RUNNING); 384080b47deSLogan Gunthorpe stdev->mrpc_busy = 1; 385080b47deSLogan Gunthorpe memcpy_toio(&stdev->mmio_mrpc->input_data, 386080b47deSLogan Gunthorpe stuser->data, stuser->data_len); 387080b47deSLogan Gunthorpe iowrite32(stuser->cmd, &stdev->mmio_mrpc->cmd); 388080b47deSLogan Gunthorpe 389080b47deSLogan Gunthorpe stuser->status = ioread32(&stdev->mmio_mrpc->status); 390080b47deSLogan Gunthorpe if (stuser->status != SWITCHTEC_MRPC_STATUS_INPROGRESS) 391080b47deSLogan Gunthorpe mrpc_complete_cmd(stdev); 392080b47deSLogan Gunthorpe 393080b47deSLogan Gunthorpe schedule_delayed_work(&stdev->mrpc_timeout, 394080b47deSLogan Gunthorpe msecs_to_jiffies(500)); 395080b47deSLogan Gunthorpe } 396080b47deSLogan Gunthorpe 397080b47deSLogan Gunthorpe static int mrpc_queue_cmd(struct switchtec_user *stuser) 398080b47deSLogan Gunthorpe { 399080b47deSLogan Gunthorpe /* requires the mrpc_mutex to already be held when called */ 400080b47deSLogan Gunthorpe 401080b47deSLogan Gunthorpe struct switchtec_dev *stdev = stuser->stdev; 402080b47deSLogan Gunthorpe 403080b47deSLogan Gunthorpe kref_get(&stuser->kref); 404080b47deSLogan Gunthorpe stuser->read_len = sizeof(stuser->data); 405080b47deSLogan Gunthorpe stuser_set_state(stuser, MRPC_QUEUED); 406080b47deSLogan Gunthorpe init_completion(&stuser->comp); 407080b47deSLogan Gunthorpe list_add_tail(&stuser->list, &stdev->mrpc_queue); 408080b47deSLogan Gunthorpe 409080b47deSLogan Gunthorpe mrpc_cmd_submit(stdev); 410080b47deSLogan Gunthorpe 411080b47deSLogan Gunthorpe return 0; 412080b47deSLogan Gunthorpe } 413080b47deSLogan Gunthorpe 414080b47deSLogan Gunthorpe static void mrpc_complete_cmd(struct switchtec_dev *stdev) 415080b47deSLogan Gunthorpe { 416080b47deSLogan Gunthorpe /* requires the mrpc_mutex to already be held when called */ 417080b47deSLogan Gunthorpe struct switchtec_user *stuser; 418080b47deSLogan Gunthorpe 419080b47deSLogan Gunthorpe if (list_empty(&stdev->mrpc_queue)) 420080b47deSLogan Gunthorpe return; 421080b47deSLogan Gunthorpe 422080b47deSLogan Gunthorpe stuser = list_entry(stdev->mrpc_queue.next, struct switchtec_user, 423080b47deSLogan Gunthorpe list); 424080b47deSLogan Gunthorpe 425080b47deSLogan Gunthorpe stuser->status = ioread32(&stdev->mmio_mrpc->status); 426080b47deSLogan Gunthorpe if (stuser->status == SWITCHTEC_MRPC_STATUS_INPROGRESS) 427080b47deSLogan Gunthorpe return; 428080b47deSLogan Gunthorpe 429080b47deSLogan Gunthorpe stuser_set_state(stuser, MRPC_DONE); 430080b47deSLogan Gunthorpe stuser->return_code = 0; 431080b47deSLogan Gunthorpe 432080b47deSLogan Gunthorpe if (stuser->status != SWITCHTEC_MRPC_STATUS_DONE) 433080b47deSLogan Gunthorpe goto out; 434080b47deSLogan Gunthorpe 435080b47deSLogan Gunthorpe stuser->return_code = ioread32(&stdev->mmio_mrpc->ret_value); 436080b47deSLogan Gunthorpe if (stuser->return_code != 0) 437080b47deSLogan Gunthorpe goto out; 438080b47deSLogan Gunthorpe 439080b47deSLogan Gunthorpe memcpy_fromio(stuser->data, &stdev->mmio_mrpc->output_data, 440080b47deSLogan Gunthorpe stuser->read_len); 441080b47deSLogan Gunthorpe 442080b47deSLogan Gunthorpe out: 443080b47deSLogan Gunthorpe complete_all(&stuser->comp); 444080b47deSLogan Gunthorpe list_del_init(&stuser->list); 445080b47deSLogan Gunthorpe stuser_put(stuser); 446080b47deSLogan Gunthorpe stdev->mrpc_busy = 0; 447080b47deSLogan Gunthorpe 448080b47deSLogan Gunthorpe mrpc_cmd_submit(stdev); 449080b47deSLogan Gunthorpe } 450080b47deSLogan Gunthorpe 451080b47deSLogan Gunthorpe static void mrpc_event_work(struct work_struct *work) 452080b47deSLogan Gunthorpe { 453080b47deSLogan Gunthorpe struct switchtec_dev *stdev; 454080b47deSLogan Gunthorpe 455080b47deSLogan Gunthorpe stdev = container_of(work, struct switchtec_dev, mrpc_work); 456080b47deSLogan Gunthorpe 457080b47deSLogan Gunthorpe dev_dbg(&stdev->dev, "%s\n", __func__); 458080b47deSLogan Gunthorpe 459080b47deSLogan Gunthorpe mutex_lock(&stdev->mrpc_mutex); 460080b47deSLogan Gunthorpe cancel_delayed_work(&stdev->mrpc_timeout); 461080b47deSLogan Gunthorpe mrpc_complete_cmd(stdev); 462080b47deSLogan Gunthorpe mutex_unlock(&stdev->mrpc_mutex); 463080b47deSLogan Gunthorpe } 464080b47deSLogan Gunthorpe 465080b47deSLogan Gunthorpe static void mrpc_timeout_work(struct work_struct *work) 466080b47deSLogan Gunthorpe { 467080b47deSLogan Gunthorpe struct switchtec_dev *stdev; 468080b47deSLogan Gunthorpe u32 status; 469080b47deSLogan Gunthorpe 470080b47deSLogan Gunthorpe stdev = container_of(work, struct switchtec_dev, mrpc_timeout.work); 471080b47deSLogan Gunthorpe 472080b47deSLogan Gunthorpe dev_dbg(&stdev->dev, "%s\n", __func__); 473080b47deSLogan Gunthorpe 474080b47deSLogan Gunthorpe mutex_lock(&stdev->mrpc_mutex); 475080b47deSLogan Gunthorpe 476080b47deSLogan Gunthorpe status = ioread32(&stdev->mmio_mrpc->status); 477080b47deSLogan Gunthorpe if (status == SWITCHTEC_MRPC_STATUS_INPROGRESS) { 478080b47deSLogan Gunthorpe schedule_delayed_work(&stdev->mrpc_timeout, 479080b47deSLogan Gunthorpe msecs_to_jiffies(500)); 480080b47deSLogan Gunthorpe goto out; 481080b47deSLogan Gunthorpe } 482080b47deSLogan Gunthorpe 483080b47deSLogan Gunthorpe mrpc_complete_cmd(stdev); 484080b47deSLogan Gunthorpe 485080b47deSLogan Gunthorpe out: 486080b47deSLogan Gunthorpe mutex_unlock(&stdev->mrpc_mutex); 487080b47deSLogan Gunthorpe } 488080b47deSLogan Gunthorpe 489*5d8e1881SLogan Gunthorpe static ssize_t device_version_show(struct device *dev, 490*5d8e1881SLogan Gunthorpe struct device_attribute *attr, char *buf) 491*5d8e1881SLogan Gunthorpe { 492*5d8e1881SLogan Gunthorpe struct switchtec_dev *stdev = to_stdev(dev); 493*5d8e1881SLogan Gunthorpe u32 ver; 494*5d8e1881SLogan Gunthorpe 495*5d8e1881SLogan Gunthorpe ver = ioread32(&stdev->mmio_sys_info->device_version); 496*5d8e1881SLogan Gunthorpe 497*5d8e1881SLogan Gunthorpe return sprintf(buf, "%x\n", ver); 498*5d8e1881SLogan Gunthorpe } 499*5d8e1881SLogan Gunthorpe static DEVICE_ATTR_RO(device_version); 500*5d8e1881SLogan Gunthorpe 501*5d8e1881SLogan Gunthorpe static ssize_t fw_version_show(struct device *dev, 502*5d8e1881SLogan Gunthorpe struct device_attribute *attr, char *buf) 503*5d8e1881SLogan Gunthorpe { 504*5d8e1881SLogan Gunthorpe struct switchtec_dev *stdev = to_stdev(dev); 505*5d8e1881SLogan Gunthorpe u32 ver; 506*5d8e1881SLogan Gunthorpe 507*5d8e1881SLogan Gunthorpe ver = ioread32(&stdev->mmio_sys_info->firmware_version); 508*5d8e1881SLogan Gunthorpe 509*5d8e1881SLogan Gunthorpe return sprintf(buf, "%08x\n", ver); 510*5d8e1881SLogan Gunthorpe } 511*5d8e1881SLogan Gunthorpe static DEVICE_ATTR_RO(fw_version); 512*5d8e1881SLogan Gunthorpe 513*5d8e1881SLogan Gunthorpe static ssize_t io_string_show(char *buf, void __iomem *attr, size_t len) 514*5d8e1881SLogan Gunthorpe { 515*5d8e1881SLogan Gunthorpe int i; 516*5d8e1881SLogan Gunthorpe 517*5d8e1881SLogan Gunthorpe memcpy_fromio(buf, attr, len); 518*5d8e1881SLogan Gunthorpe buf[len] = '\n'; 519*5d8e1881SLogan Gunthorpe buf[len + 1] = 0; 520*5d8e1881SLogan Gunthorpe 521*5d8e1881SLogan Gunthorpe for (i = len - 1; i > 0; i--) { 522*5d8e1881SLogan Gunthorpe if (buf[i] != ' ') 523*5d8e1881SLogan Gunthorpe break; 524*5d8e1881SLogan Gunthorpe buf[i] = '\n'; 525*5d8e1881SLogan Gunthorpe buf[i + 1] = 0; 526*5d8e1881SLogan Gunthorpe } 527*5d8e1881SLogan Gunthorpe 528*5d8e1881SLogan Gunthorpe return strlen(buf); 529*5d8e1881SLogan Gunthorpe } 530*5d8e1881SLogan Gunthorpe 531*5d8e1881SLogan Gunthorpe #define DEVICE_ATTR_SYS_INFO_STR(field) \ 532*5d8e1881SLogan Gunthorpe static ssize_t field ## _show(struct device *dev, \ 533*5d8e1881SLogan Gunthorpe struct device_attribute *attr, char *buf) \ 534*5d8e1881SLogan Gunthorpe { \ 535*5d8e1881SLogan Gunthorpe struct switchtec_dev *stdev = to_stdev(dev); \ 536*5d8e1881SLogan Gunthorpe return io_string_show(buf, &stdev->mmio_sys_info->field, \ 537*5d8e1881SLogan Gunthorpe sizeof(stdev->mmio_sys_info->field)); \ 538*5d8e1881SLogan Gunthorpe } \ 539*5d8e1881SLogan Gunthorpe \ 540*5d8e1881SLogan Gunthorpe static DEVICE_ATTR_RO(field) 541*5d8e1881SLogan Gunthorpe 542*5d8e1881SLogan Gunthorpe DEVICE_ATTR_SYS_INFO_STR(vendor_id); 543*5d8e1881SLogan Gunthorpe DEVICE_ATTR_SYS_INFO_STR(product_id); 544*5d8e1881SLogan Gunthorpe DEVICE_ATTR_SYS_INFO_STR(product_revision); 545*5d8e1881SLogan Gunthorpe DEVICE_ATTR_SYS_INFO_STR(component_vendor); 546*5d8e1881SLogan Gunthorpe 547*5d8e1881SLogan Gunthorpe static ssize_t component_id_show(struct device *dev, 548*5d8e1881SLogan Gunthorpe struct device_attribute *attr, char *buf) 549*5d8e1881SLogan Gunthorpe { 550*5d8e1881SLogan Gunthorpe struct switchtec_dev *stdev = to_stdev(dev); 551*5d8e1881SLogan Gunthorpe int id = ioread16(&stdev->mmio_sys_info->component_id); 552*5d8e1881SLogan Gunthorpe 553*5d8e1881SLogan Gunthorpe return sprintf(buf, "PM%04X\n", id); 554*5d8e1881SLogan Gunthorpe } 555*5d8e1881SLogan Gunthorpe static DEVICE_ATTR_RO(component_id); 556*5d8e1881SLogan Gunthorpe 557*5d8e1881SLogan Gunthorpe static ssize_t component_revision_show(struct device *dev, 558*5d8e1881SLogan Gunthorpe struct device_attribute *attr, char *buf) 559*5d8e1881SLogan Gunthorpe { 560*5d8e1881SLogan Gunthorpe struct switchtec_dev *stdev = to_stdev(dev); 561*5d8e1881SLogan Gunthorpe int rev = ioread8(&stdev->mmio_sys_info->component_revision); 562*5d8e1881SLogan Gunthorpe 563*5d8e1881SLogan Gunthorpe return sprintf(buf, "%d\n", rev); 564*5d8e1881SLogan Gunthorpe } 565*5d8e1881SLogan Gunthorpe static DEVICE_ATTR_RO(component_revision); 566*5d8e1881SLogan Gunthorpe 567*5d8e1881SLogan Gunthorpe static ssize_t partition_show(struct device *dev, 568*5d8e1881SLogan Gunthorpe struct device_attribute *attr, char *buf) 569*5d8e1881SLogan Gunthorpe { 570*5d8e1881SLogan Gunthorpe struct switchtec_dev *stdev = to_stdev(dev); 571*5d8e1881SLogan Gunthorpe 572*5d8e1881SLogan Gunthorpe return sprintf(buf, "%d\n", stdev->partition); 573*5d8e1881SLogan Gunthorpe } 574*5d8e1881SLogan Gunthorpe static DEVICE_ATTR_RO(partition); 575*5d8e1881SLogan Gunthorpe 576*5d8e1881SLogan Gunthorpe static ssize_t partition_count_show(struct device *dev, 577*5d8e1881SLogan Gunthorpe struct device_attribute *attr, char *buf) 578*5d8e1881SLogan Gunthorpe { 579*5d8e1881SLogan Gunthorpe struct switchtec_dev *stdev = to_stdev(dev); 580*5d8e1881SLogan Gunthorpe 581*5d8e1881SLogan Gunthorpe return sprintf(buf, "%d\n", stdev->partition_count); 582*5d8e1881SLogan Gunthorpe } 583*5d8e1881SLogan Gunthorpe static DEVICE_ATTR_RO(partition_count); 584*5d8e1881SLogan Gunthorpe 585*5d8e1881SLogan Gunthorpe static struct attribute *switchtec_device_attrs[] = { 586*5d8e1881SLogan Gunthorpe &dev_attr_device_version.attr, 587*5d8e1881SLogan Gunthorpe &dev_attr_fw_version.attr, 588*5d8e1881SLogan Gunthorpe &dev_attr_vendor_id.attr, 589*5d8e1881SLogan Gunthorpe &dev_attr_product_id.attr, 590*5d8e1881SLogan Gunthorpe &dev_attr_product_revision.attr, 591*5d8e1881SLogan Gunthorpe &dev_attr_component_vendor.attr, 592*5d8e1881SLogan Gunthorpe &dev_attr_component_id.attr, 593*5d8e1881SLogan Gunthorpe &dev_attr_component_revision.attr, 594*5d8e1881SLogan Gunthorpe &dev_attr_partition.attr, 595*5d8e1881SLogan Gunthorpe &dev_attr_partition_count.attr, 596*5d8e1881SLogan Gunthorpe NULL, 597*5d8e1881SLogan Gunthorpe }; 598*5d8e1881SLogan Gunthorpe 599*5d8e1881SLogan Gunthorpe ATTRIBUTE_GROUPS(switchtec_device); 600*5d8e1881SLogan Gunthorpe 601080b47deSLogan Gunthorpe static int switchtec_dev_open(struct inode *inode, struct file *filp) 602080b47deSLogan Gunthorpe { 603080b47deSLogan Gunthorpe struct switchtec_dev *stdev; 604080b47deSLogan Gunthorpe struct switchtec_user *stuser; 605080b47deSLogan Gunthorpe 606080b47deSLogan Gunthorpe stdev = container_of(inode->i_cdev, struct switchtec_dev, cdev); 607080b47deSLogan Gunthorpe 608080b47deSLogan Gunthorpe stuser = stuser_create(stdev); 609080b47deSLogan Gunthorpe if (IS_ERR(stuser)) 610080b47deSLogan Gunthorpe return PTR_ERR(stuser); 611080b47deSLogan Gunthorpe 612080b47deSLogan Gunthorpe filp->private_data = stuser; 613080b47deSLogan Gunthorpe nonseekable_open(inode, filp); 614080b47deSLogan Gunthorpe 615080b47deSLogan Gunthorpe dev_dbg(&stdev->dev, "%s: %p\n", __func__, stuser); 616080b47deSLogan Gunthorpe 617080b47deSLogan Gunthorpe return 0; 618080b47deSLogan Gunthorpe } 619080b47deSLogan Gunthorpe 620080b47deSLogan Gunthorpe static int switchtec_dev_release(struct inode *inode, struct file *filp) 621080b47deSLogan Gunthorpe { 622080b47deSLogan Gunthorpe struct switchtec_user *stuser = filp->private_data; 623080b47deSLogan Gunthorpe 624080b47deSLogan Gunthorpe stuser_put(stuser); 625080b47deSLogan Gunthorpe 626080b47deSLogan Gunthorpe return 0; 627080b47deSLogan Gunthorpe } 628080b47deSLogan Gunthorpe 629080b47deSLogan Gunthorpe static int lock_mutex_and_test_alive(struct switchtec_dev *stdev) 630080b47deSLogan Gunthorpe { 631080b47deSLogan Gunthorpe if (mutex_lock_interruptible(&stdev->mrpc_mutex)) 632080b47deSLogan Gunthorpe return -EINTR; 633080b47deSLogan Gunthorpe 634080b47deSLogan Gunthorpe if (!stdev->alive) { 635080b47deSLogan Gunthorpe mutex_unlock(&stdev->mrpc_mutex); 636080b47deSLogan Gunthorpe return -ENODEV; 637080b47deSLogan Gunthorpe } 638080b47deSLogan Gunthorpe 639080b47deSLogan Gunthorpe return 0; 640080b47deSLogan Gunthorpe } 641080b47deSLogan Gunthorpe 642080b47deSLogan Gunthorpe static ssize_t switchtec_dev_write(struct file *filp, const char __user *data, 643080b47deSLogan Gunthorpe size_t size, loff_t *off) 644080b47deSLogan Gunthorpe { 645080b47deSLogan Gunthorpe struct switchtec_user *stuser = filp->private_data; 646080b47deSLogan Gunthorpe struct switchtec_dev *stdev = stuser->stdev; 647080b47deSLogan Gunthorpe int rc; 648080b47deSLogan Gunthorpe 649080b47deSLogan Gunthorpe if (size < sizeof(stuser->cmd) || 650080b47deSLogan Gunthorpe size > sizeof(stuser->cmd) + sizeof(stuser->data)) 651080b47deSLogan Gunthorpe return -EINVAL; 652080b47deSLogan Gunthorpe 653080b47deSLogan Gunthorpe stuser->data_len = size - sizeof(stuser->cmd); 654080b47deSLogan Gunthorpe 655080b47deSLogan Gunthorpe rc = lock_mutex_and_test_alive(stdev); 656080b47deSLogan Gunthorpe if (rc) 657080b47deSLogan Gunthorpe return rc; 658080b47deSLogan Gunthorpe 659080b47deSLogan Gunthorpe if (stuser->state != MRPC_IDLE) { 660080b47deSLogan Gunthorpe rc = -EBADE; 661080b47deSLogan Gunthorpe goto out; 662080b47deSLogan Gunthorpe } 663080b47deSLogan Gunthorpe 664080b47deSLogan Gunthorpe rc = copy_from_user(&stuser->cmd, data, sizeof(stuser->cmd)); 665080b47deSLogan Gunthorpe if (rc) { 666080b47deSLogan Gunthorpe rc = -EFAULT; 667080b47deSLogan Gunthorpe goto out; 668080b47deSLogan Gunthorpe } 669080b47deSLogan Gunthorpe 670080b47deSLogan Gunthorpe data += sizeof(stuser->cmd); 671080b47deSLogan Gunthorpe rc = copy_from_user(&stuser->data, data, size - sizeof(stuser->cmd)); 672080b47deSLogan Gunthorpe if (rc) { 673080b47deSLogan Gunthorpe rc = -EFAULT; 674080b47deSLogan Gunthorpe goto out; 675080b47deSLogan Gunthorpe } 676080b47deSLogan Gunthorpe 677080b47deSLogan Gunthorpe rc = mrpc_queue_cmd(stuser); 678080b47deSLogan Gunthorpe 679080b47deSLogan Gunthorpe out: 680080b47deSLogan Gunthorpe mutex_unlock(&stdev->mrpc_mutex); 681080b47deSLogan Gunthorpe 682080b47deSLogan Gunthorpe if (rc) 683080b47deSLogan Gunthorpe return rc; 684080b47deSLogan Gunthorpe 685080b47deSLogan Gunthorpe return size; 686080b47deSLogan Gunthorpe } 687080b47deSLogan Gunthorpe 688080b47deSLogan Gunthorpe static ssize_t switchtec_dev_read(struct file *filp, char __user *data, 689080b47deSLogan Gunthorpe size_t size, loff_t *off) 690080b47deSLogan Gunthorpe { 691080b47deSLogan Gunthorpe struct switchtec_user *stuser = filp->private_data; 692080b47deSLogan Gunthorpe struct switchtec_dev *stdev = stuser->stdev; 693080b47deSLogan Gunthorpe int rc; 694080b47deSLogan Gunthorpe 695080b47deSLogan Gunthorpe if (size < sizeof(stuser->cmd) || 696080b47deSLogan Gunthorpe size > sizeof(stuser->cmd) + sizeof(stuser->data)) 697080b47deSLogan Gunthorpe return -EINVAL; 698080b47deSLogan Gunthorpe 699080b47deSLogan Gunthorpe rc = lock_mutex_and_test_alive(stdev); 700080b47deSLogan Gunthorpe if (rc) 701080b47deSLogan Gunthorpe return rc; 702080b47deSLogan Gunthorpe 703080b47deSLogan Gunthorpe if (stuser->state == MRPC_IDLE) { 704080b47deSLogan Gunthorpe mutex_unlock(&stdev->mrpc_mutex); 705080b47deSLogan Gunthorpe return -EBADE; 706080b47deSLogan Gunthorpe } 707080b47deSLogan Gunthorpe 708080b47deSLogan Gunthorpe stuser->read_len = size - sizeof(stuser->return_code); 709080b47deSLogan Gunthorpe 710080b47deSLogan Gunthorpe mutex_unlock(&stdev->mrpc_mutex); 711080b47deSLogan Gunthorpe 712080b47deSLogan Gunthorpe if (filp->f_flags & O_NONBLOCK) { 713080b47deSLogan Gunthorpe if (!try_wait_for_completion(&stuser->comp)) 714080b47deSLogan Gunthorpe return -EAGAIN; 715080b47deSLogan Gunthorpe } else { 716080b47deSLogan Gunthorpe rc = wait_for_completion_interruptible(&stuser->comp); 717080b47deSLogan Gunthorpe if (rc < 0) 718080b47deSLogan Gunthorpe return rc; 719080b47deSLogan Gunthorpe } 720080b47deSLogan Gunthorpe 721080b47deSLogan Gunthorpe rc = lock_mutex_and_test_alive(stdev); 722080b47deSLogan Gunthorpe if (rc) 723080b47deSLogan Gunthorpe return rc; 724080b47deSLogan Gunthorpe 725080b47deSLogan Gunthorpe if (stuser->state != MRPC_DONE) { 726080b47deSLogan Gunthorpe mutex_unlock(&stdev->mrpc_mutex); 727080b47deSLogan Gunthorpe return -EBADE; 728080b47deSLogan Gunthorpe } 729080b47deSLogan Gunthorpe 730080b47deSLogan Gunthorpe rc = copy_to_user(data, &stuser->return_code, 731080b47deSLogan Gunthorpe sizeof(stuser->return_code)); 732080b47deSLogan Gunthorpe if (rc) { 733080b47deSLogan Gunthorpe rc = -EFAULT; 734080b47deSLogan Gunthorpe goto out; 735080b47deSLogan Gunthorpe } 736080b47deSLogan Gunthorpe 737080b47deSLogan Gunthorpe data += sizeof(stuser->return_code); 738080b47deSLogan Gunthorpe rc = copy_to_user(data, &stuser->data, 739080b47deSLogan Gunthorpe size - sizeof(stuser->return_code)); 740080b47deSLogan Gunthorpe if (rc) { 741080b47deSLogan Gunthorpe rc = -EFAULT; 742080b47deSLogan Gunthorpe goto out; 743080b47deSLogan Gunthorpe } 744080b47deSLogan Gunthorpe 745080b47deSLogan Gunthorpe stuser_set_state(stuser, MRPC_IDLE); 746080b47deSLogan Gunthorpe 747080b47deSLogan Gunthorpe out: 748080b47deSLogan Gunthorpe mutex_unlock(&stdev->mrpc_mutex); 749080b47deSLogan Gunthorpe 750080b47deSLogan Gunthorpe if (stuser->status == SWITCHTEC_MRPC_STATUS_DONE) 751080b47deSLogan Gunthorpe return size; 752080b47deSLogan Gunthorpe else if (stuser->status == SWITCHTEC_MRPC_STATUS_INTERRUPTED) 753080b47deSLogan Gunthorpe return -ENXIO; 754080b47deSLogan Gunthorpe else 755080b47deSLogan Gunthorpe return -EBADMSG; 756080b47deSLogan Gunthorpe } 757080b47deSLogan Gunthorpe 758080b47deSLogan Gunthorpe static unsigned int switchtec_dev_poll(struct file *filp, poll_table *wait) 759080b47deSLogan Gunthorpe { 760080b47deSLogan Gunthorpe struct switchtec_user *stuser = filp->private_data; 761080b47deSLogan Gunthorpe struct switchtec_dev *stdev = stuser->stdev; 762080b47deSLogan Gunthorpe int ret = 0; 763080b47deSLogan Gunthorpe 764080b47deSLogan Gunthorpe poll_wait(filp, &stuser->comp.wait, wait); 765080b47deSLogan Gunthorpe poll_wait(filp, &stdev->event_wq, wait); 766080b47deSLogan Gunthorpe 767080b47deSLogan Gunthorpe if (lock_mutex_and_test_alive(stdev)) 768080b47deSLogan Gunthorpe return POLLIN | POLLRDHUP | POLLOUT | POLLERR | POLLHUP; 769080b47deSLogan Gunthorpe 770080b47deSLogan Gunthorpe mutex_unlock(&stdev->mrpc_mutex); 771080b47deSLogan Gunthorpe 772080b47deSLogan Gunthorpe if (try_wait_for_completion(&stuser->comp)) 773080b47deSLogan Gunthorpe ret |= POLLIN | POLLRDNORM; 774080b47deSLogan Gunthorpe 775080b47deSLogan Gunthorpe if (stuser->event_cnt != atomic_read(&stdev->event_cnt)) 776080b47deSLogan Gunthorpe ret |= POLLPRI | POLLRDBAND; 777080b47deSLogan Gunthorpe 778080b47deSLogan Gunthorpe return ret; 779080b47deSLogan Gunthorpe } 780080b47deSLogan Gunthorpe 781080b47deSLogan Gunthorpe static const struct file_operations switchtec_fops = { 782080b47deSLogan Gunthorpe .owner = THIS_MODULE, 783080b47deSLogan Gunthorpe .open = switchtec_dev_open, 784080b47deSLogan Gunthorpe .release = switchtec_dev_release, 785080b47deSLogan Gunthorpe .write = switchtec_dev_write, 786080b47deSLogan Gunthorpe .read = switchtec_dev_read, 787080b47deSLogan Gunthorpe .poll = switchtec_dev_poll, 788080b47deSLogan Gunthorpe }; 789080b47deSLogan Gunthorpe 790080b47deSLogan Gunthorpe static void stdev_release(struct device *dev) 791080b47deSLogan Gunthorpe { 792080b47deSLogan Gunthorpe struct switchtec_dev *stdev = to_stdev(dev); 793080b47deSLogan Gunthorpe 794080b47deSLogan Gunthorpe kfree(stdev); 795080b47deSLogan Gunthorpe } 796080b47deSLogan Gunthorpe 797080b47deSLogan Gunthorpe static void stdev_kill(struct switchtec_dev *stdev) 798080b47deSLogan Gunthorpe { 799080b47deSLogan Gunthorpe struct switchtec_user *stuser, *tmpuser; 800080b47deSLogan Gunthorpe 801080b47deSLogan Gunthorpe pci_clear_master(stdev->pdev); 802080b47deSLogan Gunthorpe 803080b47deSLogan Gunthorpe cancel_delayed_work_sync(&stdev->mrpc_timeout); 804080b47deSLogan Gunthorpe 805080b47deSLogan Gunthorpe /* Mark the hardware as unavailable and complete all completions */ 806080b47deSLogan Gunthorpe mutex_lock(&stdev->mrpc_mutex); 807080b47deSLogan Gunthorpe stdev->alive = false; 808080b47deSLogan Gunthorpe 809080b47deSLogan Gunthorpe /* Wake up and kill any users waiting on an MRPC request */ 810080b47deSLogan Gunthorpe list_for_each_entry_safe(stuser, tmpuser, &stdev->mrpc_queue, list) { 811080b47deSLogan Gunthorpe complete_all(&stuser->comp); 812080b47deSLogan Gunthorpe list_del_init(&stuser->list); 813080b47deSLogan Gunthorpe stuser_put(stuser); 814080b47deSLogan Gunthorpe } 815080b47deSLogan Gunthorpe 816080b47deSLogan Gunthorpe mutex_unlock(&stdev->mrpc_mutex); 817080b47deSLogan Gunthorpe 818080b47deSLogan Gunthorpe /* Wake up any users waiting on event_wq */ 819080b47deSLogan Gunthorpe wake_up_interruptible(&stdev->event_wq); 820080b47deSLogan Gunthorpe } 821080b47deSLogan Gunthorpe 822080b47deSLogan Gunthorpe static struct switchtec_dev *stdev_create(struct pci_dev *pdev) 823080b47deSLogan Gunthorpe { 824080b47deSLogan Gunthorpe struct switchtec_dev *stdev; 825080b47deSLogan Gunthorpe int minor; 826080b47deSLogan Gunthorpe struct device *dev; 827080b47deSLogan Gunthorpe struct cdev *cdev; 828080b47deSLogan Gunthorpe int rc; 829080b47deSLogan Gunthorpe 830080b47deSLogan Gunthorpe stdev = kzalloc_node(sizeof(*stdev), GFP_KERNEL, 831080b47deSLogan Gunthorpe dev_to_node(&pdev->dev)); 832080b47deSLogan Gunthorpe if (!stdev) 833080b47deSLogan Gunthorpe return ERR_PTR(-ENOMEM); 834080b47deSLogan Gunthorpe 835080b47deSLogan Gunthorpe stdev->alive = true; 836080b47deSLogan Gunthorpe stdev->pdev = pdev; 837080b47deSLogan Gunthorpe INIT_LIST_HEAD(&stdev->mrpc_queue); 838080b47deSLogan Gunthorpe mutex_init(&stdev->mrpc_mutex); 839080b47deSLogan Gunthorpe stdev->mrpc_busy = 0; 840080b47deSLogan Gunthorpe INIT_WORK(&stdev->mrpc_work, mrpc_event_work); 841080b47deSLogan Gunthorpe INIT_DELAYED_WORK(&stdev->mrpc_timeout, mrpc_timeout_work); 842080b47deSLogan Gunthorpe init_waitqueue_head(&stdev->event_wq); 843080b47deSLogan Gunthorpe atomic_set(&stdev->event_cnt, 0); 844080b47deSLogan Gunthorpe 845080b47deSLogan Gunthorpe dev = &stdev->dev; 846080b47deSLogan Gunthorpe device_initialize(dev); 847080b47deSLogan Gunthorpe dev->class = switchtec_class; 848080b47deSLogan Gunthorpe dev->parent = &pdev->dev; 849*5d8e1881SLogan Gunthorpe dev->groups = switchtec_device_groups; 850080b47deSLogan Gunthorpe dev->release = stdev_release; 851080b47deSLogan Gunthorpe 852080b47deSLogan Gunthorpe minor = ida_simple_get(&switchtec_minor_ida, 0, 0, 853080b47deSLogan Gunthorpe GFP_KERNEL); 854080b47deSLogan Gunthorpe if (minor < 0) { 855080b47deSLogan Gunthorpe rc = minor; 856080b47deSLogan Gunthorpe goto err_put; 857080b47deSLogan Gunthorpe } 858080b47deSLogan Gunthorpe 859080b47deSLogan Gunthorpe dev->devt = MKDEV(MAJOR(switchtec_devt), minor); 860080b47deSLogan Gunthorpe dev_set_name(dev, "switchtec%d", minor); 861080b47deSLogan Gunthorpe 862080b47deSLogan Gunthorpe cdev = &stdev->cdev; 863080b47deSLogan Gunthorpe cdev_init(cdev, &switchtec_fops); 864080b47deSLogan Gunthorpe cdev->owner = THIS_MODULE; 865080b47deSLogan Gunthorpe cdev->kobj.parent = &dev->kobj; 866080b47deSLogan Gunthorpe 867080b47deSLogan Gunthorpe return stdev; 868080b47deSLogan Gunthorpe 869080b47deSLogan Gunthorpe err_put: 870080b47deSLogan Gunthorpe put_device(&stdev->dev); 871080b47deSLogan Gunthorpe return ERR_PTR(rc); 872080b47deSLogan Gunthorpe } 873080b47deSLogan Gunthorpe 874080b47deSLogan Gunthorpe static irqreturn_t switchtec_event_isr(int irq, void *dev) 875080b47deSLogan Gunthorpe { 876080b47deSLogan Gunthorpe struct switchtec_dev *stdev = dev; 877080b47deSLogan Gunthorpe u32 reg; 878080b47deSLogan Gunthorpe irqreturn_t ret = IRQ_NONE; 879080b47deSLogan Gunthorpe 880080b47deSLogan Gunthorpe reg = ioread32(&stdev->mmio_part_cfg->mrpc_comp_hdr); 881080b47deSLogan Gunthorpe if (reg & SWITCHTEC_EVENT_OCCURRED) { 882080b47deSLogan Gunthorpe dev_dbg(&stdev->dev, "%s: mrpc comp\n", __func__); 883080b47deSLogan Gunthorpe ret = IRQ_HANDLED; 884080b47deSLogan Gunthorpe schedule_work(&stdev->mrpc_work); 885080b47deSLogan Gunthorpe iowrite32(reg, &stdev->mmio_part_cfg->mrpc_comp_hdr); 886080b47deSLogan Gunthorpe } 887080b47deSLogan Gunthorpe 888080b47deSLogan Gunthorpe return ret; 889080b47deSLogan Gunthorpe } 890080b47deSLogan Gunthorpe 891080b47deSLogan Gunthorpe static int switchtec_init_isr(struct switchtec_dev *stdev) 892080b47deSLogan Gunthorpe { 893080b47deSLogan Gunthorpe int nvecs; 894080b47deSLogan Gunthorpe int event_irq; 895080b47deSLogan Gunthorpe 896080b47deSLogan Gunthorpe nvecs = pci_alloc_irq_vectors(stdev->pdev, 1, 4, 897080b47deSLogan Gunthorpe PCI_IRQ_MSIX | PCI_IRQ_MSI); 898080b47deSLogan Gunthorpe if (nvecs < 0) 899080b47deSLogan Gunthorpe return nvecs; 900080b47deSLogan Gunthorpe 901080b47deSLogan Gunthorpe event_irq = ioread32(&stdev->mmio_part_cfg->vep_vector_number); 902080b47deSLogan Gunthorpe if (event_irq < 0 || event_irq >= nvecs) 903080b47deSLogan Gunthorpe return -EFAULT; 904080b47deSLogan Gunthorpe 905080b47deSLogan Gunthorpe event_irq = pci_irq_vector(stdev->pdev, event_irq); 906080b47deSLogan Gunthorpe if (event_irq < 0) 907080b47deSLogan Gunthorpe return event_irq; 908080b47deSLogan Gunthorpe 909080b47deSLogan Gunthorpe return devm_request_irq(&stdev->pdev->dev, event_irq, 910080b47deSLogan Gunthorpe switchtec_event_isr, 0, 911080b47deSLogan Gunthorpe KBUILD_MODNAME, stdev); 912080b47deSLogan Gunthorpe } 913080b47deSLogan Gunthorpe 914080b47deSLogan Gunthorpe static void init_pff(struct switchtec_dev *stdev) 915080b47deSLogan Gunthorpe { 916080b47deSLogan Gunthorpe int i; 917080b47deSLogan Gunthorpe u32 reg; 918080b47deSLogan Gunthorpe struct part_cfg_regs *pcfg = stdev->mmio_part_cfg; 919080b47deSLogan Gunthorpe 920080b47deSLogan Gunthorpe for (i = 0; i < SWITCHTEC_MAX_PFF_CSR; i++) { 921080b47deSLogan Gunthorpe reg = ioread16(&stdev->mmio_pff_csr[i].vendor_id); 922080b47deSLogan Gunthorpe if (reg != MICROSEMI_VENDOR_ID) 923080b47deSLogan Gunthorpe break; 924080b47deSLogan Gunthorpe } 925080b47deSLogan Gunthorpe 926080b47deSLogan Gunthorpe stdev->pff_csr_count = i; 927080b47deSLogan Gunthorpe 928080b47deSLogan Gunthorpe reg = ioread32(&pcfg->usp_pff_inst_id); 929080b47deSLogan Gunthorpe if (reg < SWITCHTEC_MAX_PFF_CSR) 930080b47deSLogan Gunthorpe stdev->pff_local[reg] = 1; 931080b47deSLogan Gunthorpe 932080b47deSLogan Gunthorpe reg = ioread32(&pcfg->vep_pff_inst_id); 933080b47deSLogan Gunthorpe if (reg < SWITCHTEC_MAX_PFF_CSR) 934080b47deSLogan Gunthorpe stdev->pff_local[reg] = 1; 935080b47deSLogan Gunthorpe 936080b47deSLogan Gunthorpe for (i = 0; i < ARRAY_SIZE(pcfg->dsp_pff_inst_id); i++) { 937080b47deSLogan Gunthorpe reg = ioread32(&pcfg->dsp_pff_inst_id[i]); 938080b47deSLogan Gunthorpe if (reg < SWITCHTEC_MAX_PFF_CSR) 939080b47deSLogan Gunthorpe stdev->pff_local[reg] = 1; 940080b47deSLogan Gunthorpe } 941080b47deSLogan Gunthorpe } 942080b47deSLogan Gunthorpe 943080b47deSLogan Gunthorpe static int switchtec_init_pci(struct switchtec_dev *stdev, 944080b47deSLogan Gunthorpe struct pci_dev *pdev) 945080b47deSLogan Gunthorpe { 946080b47deSLogan Gunthorpe int rc; 947080b47deSLogan Gunthorpe 948080b47deSLogan Gunthorpe rc = pcim_enable_device(pdev); 949080b47deSLogan Gunthorpe if (rc) 950080b47deSLogan Gunthorpe return rc; 951080b47deSLogan Gunthorpe 952080b47deSLogan Gunthorpe rc = pcim_iomap_regions(pdev, 0x1, KBUILD_MODNAME); 953080b47deSLogan Gunthorpe if (rc) 954080b47deSLogan Gunthorpe return rc; 955080b47deSLogan Gunthorpe 956080b47deSLogan Gunthorpe pci_set_master(pdev); 957080b47deSLogan Gunthorpe 958080b47deSLogan Gunthorpe stdev->mmio = pcim_iomap_table(pdev)[0]; 959080b47deSLogan Gunthorpe stdev->mmio_mrpc = stdev->mmio + SWITCHTEC_GAS_MRPC_OFFSET; 960080b47deSLogan Gunthorpe stdev->mmio_sw_event = stdev->mmio + SWITCHTEC_GAS_SW_EVENT_OFFSET; 961080b47deSLogan Gunthorpe stdev->mmio_sys_info = stdev->mmio + SWITCHTEC_GAS_SYS_INFO_OFFSET; 962080b47deSLogan Gunthorpe stdev->mmio_flash_info = stdev->mmio + SWITCHTEC_GAS_FLASH_INFO_OFFSET; 963080b47deSLogan Gunthorpe stdev->mmio_ntb = stdev->mmio + SWITCHTEC_GAS_NTB_OFFSET; 964080b47deSLogan Gunthorpe stdev->partition = ioread8(&stdev->mmio_ntb->partition_id); 965080b47deSLogan Gunthorpe stdev->partition_count = ioread8(&stdev->mmio_ntb->partition_count); 966080b47deSLogan Gunthorpe stdev->mmio_part_cfg_all = stdev->mmio + SWITCHTEC_GAS_PART_CFG_OFFSET; 967080b47deSLogan Gunthorpe stdev->mmio_part_cfg = &stdev->mmio_part_cfg_all[stdev->partition]; 968080b47deSLogan Gunthorpe stdev->mmio_pff_csr = stdev->mmio + SWITCHTEC_GAS_PFF_CSR_OFFSET; 969080b47deSLogan Gunthorpe 970080b47deSLogan Gunthorpe init_pff(stdev); 971080b47deSLogan Gunthorpe 972080b47deSLogan Gunthorpe pci_set_drvdata(pdev, stdev); 973080b47deSLogan Gunthorpe 974080b47deSLogan Gunthorpe return 0; 975080b47deSLogan Gunthorpe } 976080b47deSLogan Gunthorpe 977080b47deSLogan Gunthorpe static int switchtec_pci_probe(struct pci_dev *pdev, 978080b47deSLogan Gunthorpe const struct pci_device_id *id) 979080b47deSLogan Gunthorpe { 980080b47deSLogan Gunthorpe struct switchtec_dev *stdev; 981080b47deSLogan Gunthorpe int rc; 982080b47deSLogan Gunthorpe 983080b47deSLogan Gunthorpe stdev = stdev_create(pdev); 984080b47deSLogan Gunthorpe if (IS_ERR(stdev)) 985080b47deSLogan Gunthorpe return PTR_ERR(stdev); 986080b47deSLogan Gunthorpe 987080b47deSLogan Gunthorpe rc = switchtec_init_pci(stdev, pdev); 988080b47deSLogan Gunthorpe if (rc) 989080b47deSLogan Gunthorpe goto err_put; 990080b47deSLogan Gunthorpe 991080b47deSLogan Gunthorpe rc = switchtec_init_isr(stdev); 992080b47deSLogan Gunthorpe if (rc) { 993080b47deSLogan Gunthorpe dev_err(&stdev->dev, "failed to init isr.\n"); 994080b47deSLogan Gunthorpe goto err_put; 995080b47deSLogan Gunthorpe } 996080b47deSLogan Gunthorpe 997080b47deSLogan Gunthorpe iowrite32(SWITCHTEC_EVENT_CLEAR | 998080b47deSLogan Gunthorpe SWITCHTEC_EVENT_EN_IRQ, 999080b47deSLogan Gunthorpe &stdev->mmio_part_cfg->mrpc_comp_hdr); 1000080b47deSLogan Gunthorpe 1001080b47deSLogan Gunthorpe rc = cdev_add(&stdev->cdev, stdev->dev.devt, 1); 1002080b47deSLogan Gunthorpe if (rc) 1003080b47deSLogan Gunthorpe goto err_put; 1004080b47deSLogan Gunthorpe 1005080b47deSLogan Gunthorpe rc = device_add(&stdev->dev); 1006080b47deSLogan Gunthorpe if (rc) 1007080b47deSLogan Gunthorpe goto err_devadd; 1008080b47deSLogan Gunthorpe 1009080b47deSLogan Gunthorpe dev_info(&stdev->dev, "Management device registered.\n"); 1010080b47deSLogan Gunthorpe 1011080b47deSLogan Gunthorpe return 0; 1012080b47deSLogan Gunthorpe 1013080b47deSLogan Gunthorpe err_devadd: 1014080b47deSLogan Gunthorpe cdev_del(&stdev->cdev); 1015080b47deSLogan Gunthorpe stdev_kill(stdev); 1016080b47deSLogan Gunthorpe err_put: 1017080b47deSLogan Gunthorpe ida_simple_remove(&switchtec_minor_ida, MINOR(stdev->dev.devt)); 1018080b47deSLogan Gunthorpe put_device(&stdev->dev); 1019080b47deSLogan Gunthorpe return rc; 1020080b47deSLogan Gunthorpe } 1021080b47deSLogan Gunthorpe 1022080b47deSLogan Gunthorpe static void switchtec_pci_remove(struct pci_dev *pdev) 1023080b47deSLogan Gunthorpe { 1024080b47deSLogan Gunthorpe struct switchtec_dev *stdev = pci_get_drvdata(pdev); 1025080b47deSLogan Gunthorpe 1026080b47deSLogan Gunthorpe pci_set_drvdata(pdev, NULL); 1027080b47deSLogan Gunthorpe 1028080b47deSLogan Gunthorpe device_del(&stdev->dev); 1029080b47deSLogan Gunthorpe cdev_del(&stdev->cdev); 1030080b47deSLogan Gunthorpe ida_simple_remove(&switchtec_minor_ida, MINOR(stdev->dev.devt)); 1031080b47deSLogan Gunthorpe dev_info(&stdev->dev, "unregistered.\n"); 1032080b47deSLogan Gunthorpe 1033080b47deSLogan Gunthorpe stdev_kill(stdev); 1034080b47deSLogan Gunthorpe put_device(&stdev->dev); 1035080b47deSLogan Gunthorpe } 1036080b47deSLogan Gunthorpe 1037080b47deSLogan Gunthorpe #define SWITCHTEC_PCI_DEVICE(device_id) \ 1038080b47deSLogan Gunthorpe { \ 1039080b47deSLogan Gunthorpe .vendor = MICROSEMI_VENDOR_ID, \ 1040080b47deSLogan Gunthorpe .device = device_id, \ 1041080b47deSLogan Gunthorpe .subvendor = PCI_ANY_ID, \ 1042080b47deSLogan Gunthorpe .subdevice = PCI_ANY_ID, \ 1043080b47deSLogan Gunthorpe .class = MICROSEMI_MGMT_CLASSCODE, \ 1044080b47deSLogan Gunthorpe .class_mask = 0xFFFFFFFF, \ 1045080b47deSLogan Gunthorpe }, \ 1046080b47deSLogan Gunthorpe { \ 1047080b47deSLogan Gunthorpe .vendor = MICROSEMI_VENDOR_ID, \ 1048080b47deSLogan Gunthorpe .device = device_id, \ 1049080b47deSLogan Gunthorpe .subvendor = PCI_ANY_ID, \ 1050080b47deSLogan Gunthorpe .subdevice = PCI_ANY_ID, \ 1051080b47deSLogan Gunthorpe .class = MICROSEMI_NTB_CLASSCODE, \ 1052080b47deSLogan Gunthorpe .class_mask = 0xFFFFFFFF, \ 1053080b47deSLogan Gunthorpe } 1054080b47deSLogan Gunthorpe 1055080b47deSLogan Gunthorpe static const struct pci_device_id switchtec_pci_tbl[] = { 1056080b47deSLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8531), //PFX 24xG3 1057080b47deSLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8532), //PFX 32xG3 1058080b47deSLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8533), //PFX 48xG3 1059080b47deSLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8534), //PFX 64xG3 1060080b47deSLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8535), //PFX 80xG3 1061080b47deSLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8536), //PFX 96xG3 1062080b47deSLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8543), //PSX 48xG3 1063080b47deSLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8544), //PSX 64xG3 1064080b47deSLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8545), //PSX 80xG3 1065080b47deSLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8546), //PSX 96xG3 1066080b47deSLogan Gunthorpe {0} 1067080b47deSLogan Gunthorpe }; 1068080b47deSLogan Gunthorpe MODULE_DEVICE_TABLE(pci, switchtec_pci_tbl); 1069080b47deSLogan Gunthorpe 1070080b47deSLogan Gunthorpe static struct pci_driver switchtec_pci_driver = { 1071080b47deSLogan Gunthorpe .name = KBUILD_MODNAME, 1072080b47deSLogan Gunthorpe .id_table = switchtec_pci_tbl, 1073080b47deSLogan Gunthorpe .probe = switchtec_pci_probe, 1074080b47deSLogan Gunthorpe .remove = switchtec_pci_remove, 1075080b47deSLogan Gunthorpe }; 1076080b47deSLogan Gunthorpe 1077080b47deSLogan Gunthorpe static int __init switchtec_init(void) 1078080b47deSLogan Gunthorpe { 1079080b47deSLogan Gunthorpe int rc; 1080080b47deSLogan Gunthorpe 1081080b47deSLogan Gunthorpe rc = alloc_chrdev_region(&switchtec_devt, 0, max_devices, 1082080b47deSLogan Gunthorpe "switchtec"); 1083080b47deSLogan Gunthorpe if (rc) 1084080b47deSLogan Gunthorpe return rc; 1085080b47deSLogan Gunthorpe 1086080b47deSLogan Gunthorpe switchtec_class = class_create(THIS_MODULE, "switchtec"); 1087080b47deSLogan Gunthorpe if (IS_ERR(switchtec_class)) { 1088080b47deSLogan Gunthorpe rc = PTR_ERR(switchtec_class); 1089080b47deSLogan Gunthorpe goto err_create_class; 1090080b47deSLogan Gunthorpe } 1091080b47deSLogan Gunthorpe 1092080b47deSLogan Gunthorpe rc = pci_register_driver(&switchtec_pci_driver); 1093080b47deSLogan Gunthorpe if (rc) 1094080b47deSLogan Gunthorpe goto err_pci_register; 1095080b47deSLogan Gunthorpe 1096080b47deSLogan Gunthorpe pr_info(KBUILD_MODNAME ": loaded.\n"); 1097080b47deSLogan Gunthorpe 1098080b47deSLogan Gunthorpe return 0; 1099080b47deSLogan Gunthorpe 1100080b47deSLogan Gunthorpe err_pci_register: 1101080b47deSLogan Gunthorpe class_destroy(switchtec_class); 1102080b47deSLogan Gunthorpe 1103080b47deSLogan Gunthorpe err_create_class: 1104080b47deSLogan Gunthorpe unregister_chrdev_region(switchtec_devt, max_devices); 1105080b47deSLogan Gunthorpe 1106080b47deSLogan Gunthorpe return rc; 1107080b47deSLogan Gunthorpe } 1108080b47deSLogan Gunthorpe module_init(switchtec_init); 1109080b47deSLogan Gunthorpe 1110080b47deSLogan Gunthorpe static void __exit switchtec_exit(void) 1111080b47deSLogan Gunthorpe { 1112080b47deSLogan Gunthorpe pci_unregister_driver(&switchtec_pci_driver); 1113080b47deSLogan Gunthorpe class_destroy(switchtec_class); 1114080b47deSLogan Gunthorpe unregister_chrdev_region(switchtec_devt, max_devices); 1115080b47deSLogan Gunthorpe ida_destroy(&switchtec_minor_ida); 1116080b47deSLogan Gunthorpe 1117080b47deSLogan Gunthorpe pr_info(KBUILD_MODNAME ": unloaded.\n"); 1118080b47deSLogan Gunthorpe } 1119080b47deSLogan Gunthorpe module_exit(switchtec_exit); 1120