xref: /linux/drivers/pci/switch/switchtec.c (revision 080b47def5e5e28b2509c5bb92160d1df730f27b)
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