1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0+
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * IBM Hot Plug Controller Driver
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Written By: Jyoti Shah, IBM Corporation
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * Copyright (C) 2001-2003 IBM Corp.
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * All rights reserved.
10*4882a593Smuzhiyun *
11*4882a593Smuzhiyun * Send feedback to <gregkh@us.ibm.com>
12*4882a593Smuzhiyun * <jshah@us.ibm.com>
13*4882a593Smuzhiyun *
14*4882a593Smuzhiyun */
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun #include <linux/wait.h>
17*4882a593Smuzhiyun #include <linux/time.h>
18*4882a593Smuzhiyun #include <linux/completion.h>
19*4882a593Smuzhiyun #include <linux/delay.h>
20*4882a593Smuzhiyun #include <linux/module.h>
21*4882a593Smuzhiyun #include <linux/pci.h>
22*4882a593Smuzhiyun #include <linux/init.h>
23*4882a593Smuzhiyun #include <linux/mutex.h>
24*4882a593Smuzhiyun #include <linux/sched.h>
25*4882a593Smuzhiyun #include <linux/kthread.h>
26*4882a593Smuzhiyun #include "ibmphp.h"
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun static int to_debug = 0;
29*4882a593Smuzhiyun #define debug_polling(fmt, arg...) do { if (to_debug) debug(fmt, arg); } while (0)
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun //----------------------------------------------------------------------------
32*4882a593Smuzhiyun // timeout values
33*4882a593Smuzhiyun //----------------------------------------------------------------------------
34*4882a593Smuzhiyun #define CMD_COMPLETE_TOUT_SEC 60 // give HPC 60 sec to finish cmd
35*4882a593Smuzhiyun #define HPC_CTLR_WORKING_TOUT 60 // give HPC 60 sec to finish cmd
36*4882a593Smuzhiyun #define HPC_GETACCESS_TIMEOUT 60 // seconds
37*4882a593Smuzhiyun #define POLL_INTERVAL_SEC 2 // poll HPC every 2 seconds
38*4882a593Smuzhiyun #define POLL_LATCH_CNT 5 // poll latch 5 times, then poll slots
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun //----------------------------------------------------------------------------
41*4882a593Smuzhiyun // Winnipeg Architected Register Offsets
42*4882a593Smuzhiyun //----------------------------------------------------------------------------
43*4882a593Smuzhiyun #define WPG_I2CMBUFL_OFFSET 0x08 // I2C Message Buffer Low
44*4882a593Smuzhiyun #define WPG_I2CMOSUP_OFFSET 0x10 // I2C Master Operation Setup Reg
45*4882a593Smuzhiyun #define WPG_I2CMCNTL_OFFSET 0x20 // I2C Master Control Register
46*4882a593Smuzhiyun #define WPG_I2CPARM_OFFSET 0x40 // I2C Parameter Register
47*4882a593Smuzhiyun #define WPG_I2CSTAT_OFFSET 0x70 // I2C Status Register
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun //----------------------------------------------------------------------------
50*4882a593Smuzhiyun // Winnipeg Store Type commands (Add this commands to the register offset)
51*4882a593Smuzhiyun //----------------------------------------------------------------------------
52*4882a593Smuzhiyun #define WPG_I2C_AND 0x1000 // I2C AND operation
53*4882a593Smuzhiyun #define WPG_I2C_OR 0x2000 // I2C OR operation
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun //----------------------------------------------------------------------------
56*4882a593Smuzhiyun // Command set for I2C Master Operation Setup Register
57*4882a593Smuzhiyun //----------------------------------------------------------------------------
58*4882a593Smuzhiyun #define WPG_READATADDR_MASK 0x00010000 // read,bytes,I2C shifted,index
59*4882a593Smuzhiyun #define WPG_WRITEATADDR_MASK 0x40010000 // write,bytes,I2C shifted,index
60*4882a593Smuzhiyun #define WPG_READDIRECT_MASK 0x10010000
61*4882a593Smuzhiyun #define WPG_WRITEDIRECT_MASK 0x60010000
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun //----------------------------------------------------------------------------
65*4882a593Smuzhiyun // bit masks for I2C Master Control Register
66*4882a593Smuzhiyun //----------------------------------------------------------------------------
67*4882a593Smuzhiyun #define WPG_I2CMCNTL_STARTOP_MASK 0x00000002 // Start the Operation
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun //----------------------------------------------------------------------------
70*4882a593Smuzhiyun //
71*4882a593Smuzhiyun //----------------------------------------------------------------------------
72*4882a593Smuzhiyun #define WPG_I2C_IOREMAP_SIZE 0x2044 // size of linear address interval
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun //----------------------------------------------------------------------------
75*4882a593Smuzhiyun // command index
76*4882a593Smuzhiyun //----------------------------------------------------------------------------
77*4882a593Smuzhiyun #define WPG_1ST_SLOT_INDEX 0x01 // index - 1st slot for ctlr
78*4882a593Smuzhiyun #define WPG_CTLR_INDEX 0x0F // index - ctlr
79*4882a593Smuzhiyun #define WPG_1ST_EXTSLOT_INDEX 0x10 // index - 1st ext slot for ctlr
80*4882a593Smuzhiyun #define WPG_1ST_BUS_INDEX 0x1F // index - 1st bus for ctlr
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun //----------------------------------------------------------------------------
83*4882a593Smuzhiyun // macro utilities
84*4882a593Smuzhiyun //----------------------------------------------------------------------------
85*4882a593Smuzhiyun // if bits 20,22,25,26,27,29,30 are OFF return 1
86*4882a593Smuzhiyun #define HPC_I2CSTATUS_CHECK(s) ((u8)((s & 0x00000A76) ? 0 : 1))
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun //----------------------------------------------------------------------------
89*4882a593Smuzhiyun // global variables
90*4882a593Smuzhiyun //----------------------------------------------------------------------------
91*4882a593Smuzhiyun static DEFINE_MUTEX(sem_hpcaccess); // lock access to HPC
92*4882a593Smuzhiyun static DEFINE_MUTEX(operations_mutex); // lock all operations and
93*4882a593Smuzhiyun // access to data structures
94*4882a593Smuzhiyun static DECLARE_COMPLETION(exit_complete); // make sure polling thread goes away
95*4882a593Smuzhiyun static struct task_struct *ibmphp_poll_thread;
96*4882a593Smuzhiyun //----------------------------------------------------------------------------
97*4882a593Smuzhiyun // local function prototypes
98*4882a593Smuzhiyun //----------------------------------------------------------------------------
99*4882a593Smuzhiyun static u8 i2c_ctrl_read(struct controller *, void __iomem *, u8);
100*4882a593Smuzhiyun static u8 i2c_ctrl_write(struct controller *, void __iomem *, u8, u8);
101*4882a593Smuzhiyun static u8 hpc_writecmdtoindex(u8, u8);
102*4882a593Smuzhiyun static u8 hpc_readcmdtoindex(u8, u8);
103*4882a593Smuzhiyun static void get_hpc_access(void);
104*4882a593Smuzhiyun static void free_hpc_access(void);
105*4882a593Smuzhiyun static int poll_hpc(void *data);
106*4882a593Smuzhiyun static int process_changeinstatus(struct slot *, struct slot *);
107*4882a593Smuzhiyun static int process_changeinlatch(u8, u8, struct controller *);
108*4882a593Smuzhiyun static int hpc_wait_ctlr_notworking(int, struct controller *, void __iomem *, u8 *);
109*4882a593Smuzhiyun //----------------------------------------------------------------------------
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun /*----------------------------------------------------------------------
113*4882a593Smuzhiyun * Name: i2c_ctrl_read
114*4882a593Smuzhiyun *
115*4882a593Smuzhiyun * Action: read from HPC over I2C
116*4882a593Smuzhiyun *
117*4882a593Smuzhiyun *---------------------------------------------------------------------*/
i2c_ctrl_read(struct controller * ctlr_ptr,void __iomem * WPGBbar,u8 index)118*4882a593Smuzhiyun static u8 i2c_ctrl_read(struct controller *ctlr_ptr, void __iomem *WPGBbar, u8 index)
119*4882a593Smuzhiyun {
120*4882a593Smuzhiyun u8 status;
121*4882a593Smuzhiyun int i;
122*4882a593Smuzhiyun void __iomem *wpg_addr; // base addr + offset
123*4882a593Smuzhiyun unsigned long wpg_data; // data to/from WPG LOHI format
124*4882a593Smuzhiyun unsigned long ultemp;
125*4882a593Smuzhiyun unsigned long data; // actual data HILO format
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun debug_polling("%s - Entry WPGBbar[%p] index[%x] \n", __func__, WPGBbar, index);
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun //--------------------------------------------------------------------
130*4882a593Smuzhiyun // READ - step 1
131*4882a593Smuzhiyun // read at address, byte length, I2C address (shifted), index
132*4882a593Smuzhiyun // or read direct, byte length, index
133*4882a593Smuzhiyun if (ctlr_ptr->ctlr_type == 0x02) {
134*4882a593Smuzhiyun data = WPG_READATADDR_MASK;
135*4882a593Smuzhiyun // fill in I2C address
136*4882a593Smuzhiyun ultemp = (unsigned long)ctlr_ptr->u.wpeg_ctlr.i2c_addr;
137*4882a593Smuzhiyun ultemp = ultemp >> 1;
138*4882a593Smuzhiyun data |= (ultemp << 8);
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun // fill in index
141*4882a593Smuzhiyun data |= (unsigned long)index;
142*4882a593Smuzhiyun } else if (ctlr_ptr->ctlr_type == 0x04) {
143*4882a593Smuzhiyun data = WPG_READDIRECT_MASK;
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun // fill in index
146*4882a593Smuzhiyun ultemp = (unsigned long)index;
147*4882a593Smuzhiyun ultemp = ultemp << 8;
148*4882a593Smuzhiyun data |= ultemp;
149*4882a593Smuzhiyun } else {
150*4882a593Smuzhiyun err("this controller type is not supported \n");
151*4882a593Smuzhiyun return HPC_ERROR;
152*4882a593Smuzhiyun }
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun wpg_data = swab32(data); // swap data before writing
155*4882a593Smuzhiyun wpg_addr = WPGBbar + WPG_I2CMOSUP_OFFSET;
156*4882a593Smuzhiyun writel(wpg_data, wpg_addr);
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun //--------------------------------------------------------------------
159*4882a593Smuzhiyun // READ - step 2 : clear the message buffer
160*4882a593Smuzhiyun data = 0x00000000;
161*4882a593Smuzhiyun wpg_data = swab32(data);
162*4882a593Smuzhiyun wpg_addr = WPGBbar + WPG_I2CMBUFL_OFFSET;
163*4882a593Smuzhiyun writel(wpg_data, wpg_addr);
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun //--------------------------------------------------------------------
166*4882a593Smuzhiyun // READ - step 3 : issue start operation, I2C master control bit 30:ON
167*4882a593Smuzhiyun // 2020 : [20] OR operation at [20] offset 0x20
168*4882a593Smuzhiyun data = WPG_I2CMCNTL_STARTOP_MASK;
169*4882a593Smuzhiyun wpg_data = swab32(data);
170*4882a593Smuzhiyun wpg_addr = WPGBbar + WPG_I2CMCNTL_OFFSET + WPG_I2C_OR;
171*4882a593Smuzhiyun writel(wpg_data, wpg_addr);
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun //--------------------------------------------------------------------
174*4882a593Smuzhiyun // READ - step 4 : wait until start operation bit clears
175*4882a593Smuzhiyun i = CMD_COMPLETE_TOUT_SEC;
176*4882a593Smuzhiyun while (i) {
177*4882a593Smuzhiyun msleep(10);
178*4882a593Smuzhiyun wpg_addr = WPGBbar + WPG_I2CMCNTL_OFFSET;
179*4882a593Smuzhiyun wpg_data = readl(wpg_addr);
180*4882a593Smuzhiyun data = swab32(wpg_data);
181*4882a593Smuzhiyun if (!(data & WPG_I2CMCNTL_STARTOP_MASK))
182*4882a593Smuzhiyun break;
183*4882a593Smuzhiyun i--;
184*4882a593Smuzhiyun }
185*4882a593Smuzhiyun if (i == 0) {
186*4882a593Smuzhiyun debug("%s - Error : WPG timeout\n", __func__);
187*4882a593Smuzhiyun return HPC_ERROR;
188*4882a593Smuzhiyun }
189*4882a593Smuzhiyun //--------------------------------------------------------------------
190*4882a593Smuzhiyun // READ - step 5 : read I2C status register
191*4882a593Smuzhiyun i = CMD_COMPLETE_TOUT_SEC;
192*4882a593Smuzhiyun while (i) {
193*4882a593Smuzhiyun msleep(10);
194*4882a593Smuzhiyun wpg_addr = WPGBbar + WPG_I2CSTAT_OFFSET;
195*4882a593Smuzhiyun wpg_data = readl(wpg_addr);
196*4882a593Smuzhiyun data = swab32(wpg_data);
197*4882a593Smuzhiyun if (HPC_I2CSTATUS_CHECK(data))
198*4882a593Smuzhiyun break;
199*4882a593Smuzhiyun i--;
200*4882a593Smuzhiyun }
201*4882a593Smuzhiyun if (i == 0) {
202*4882a593Smuzhiyun debug("ctrl_read - Exit Error:I2C timeout\n");
203*4882a593Smuzhiyun return HPC_ERROR;
204*4882a593Smuzhiyun }
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun //--------------------------------------------------------------------
207*4882a593Smuzhiyun // READ - step 6 : get DATA
208*4882a593Smuzhiyun wpg_addr = WPGBbar + WPG_I2CMBUFL_OFFSET;
209*4882a593Smuzhiyun wpg_data = readl(wpg_addr);
210*4882a593Smuzhiyun data = swab32(wpg_data);
211*4882a593Smuzhiyun
212*4882a593Smuzhiyun status = (u8) data;
213*4882a593Smuzhiyun
214*4882a593Smuzhiyun debug_polling("%s - Exit index[%x] status[%x]\n", __func__, index, status);
215*4882a593Smuzhiyun
216*4882a593Smuzhiyun return (status);
217*4882a593Smuzhiyun }
218*4882a593Smuzhiyun
219*4882a593Smuzhiyun /*----------------------------------------------------------------------
220*4882a593Smuzhiyun * Name: i2c_ctrl_write
221*4882a593Smuzhiyun *
222*4882a593Smuzhiyun * Action: write to HPC over I2C
223*4882a593Smuzhiyun *
224*4882a593Smuzhiyun * Return 0 or error codes
225*4882a593Smuzhiyun *---------------------------------------------------------------------*/
i2c_ctrl_write(struct controller * ctlr_ptr,void __iomem * WPGBbar,u8 index,u8 cmd)226*4882a593Smuzhiyun static u8 i2c_ctrl_write(struct controller *ctlr_ptr, void __iomem *WPGBbar, u8 index, u8 cmd)
227*4882a593Smuzhiyun {
228*4882a593Smuzhiyun u8 rc;
229*4882a593Smuzhiyun void __iomem *wpg_addr; // base addr + offset
230*4882a593Smuzhiyun unsigned long wpg_data; // data to/from WPG LOHI format
231*4882a593Smuzhiyun unsigned long ultemp;
232*4882a593Smuzhiyun unsigned long data; // actual data HILO format
233*4882a593Smuzhiyun int i;
234*4882a593Smuzhiyun
235*4882a593Smuzhiyun debug_polling("%s - Entry WPGBbar[%p] index[%x] cmd[%x]\n", __func__, WPGBbar, index, cmd);
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun rc = 0;
238*4882a593Smuzhiyun //--------------------------------------------------------------------
239*4882a593Smuzhiyun // WRITE - step 1
240*4882a593Smuzhiyun // write at address, byte length, I2C address (shifted), index
241*4882a593Smuzhiyun // or write direct, byte length, index
242*4882a593Smuzhiyun data = 0x00000000;
243*4882a593Smuzhiyun
244*4882a593Smuzhiyun if (ctlr_ptr->ctlr_type == 0x02) {
245*4882a593Smuzhiyun data = WPG_WRITEATADDR_MASK;
246*4882a593Smuzhiyun // fill in I2C address
247*4882a593Smuzhiyun ultemp = (unsigned long)ctlr_ptr->u.wpeg_ctlr.i2c_addr;
248*4882a593Smuzhiyun ultemp = ultemp >> 1;
249*4882a593Smuzhiyun data |= (ultemp << 8);
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun // fill in index
252*4882a593Smuzhiyun data |= (unsigned long)index;
253*4882a593Smuzhiyun } else if (ctlr_ptr->ctlr_type == 0x04) {
254*4882a593Smuzhiyun data = WPG_WRITEDIRECT_MASK;
255*4882a593Smuzhiyun
256*4882a593Smuzhiyun // fill in index
257*4882a593Smuzhiyun ultemp = (unsigned long)index;
258*4882a593Smuzhiyun ultemp = ultemp << 8;
259*4882a593Smuzhiyun data |= ultemp;
260*4882a593Smuzhiyun } else {
261*4882a593Smuzhiyun err("this controller type is not supported \n");
262*4882a593Smuzhiyun return HPC_ERROR;
263*4882a593Smuzhiyun }
264*4882a593Smuzhiyun
265*4882a593Smuzhiyun wpg_data = swab32(data); // swap data before writing
266*4882a593Smuzhiyun wpg_addr = WPGBbar + WPG_I2CMOSUP_OFFSET;
267*4882a593Smuzhiyun writel(wpg_data, wpg_addr);
268*4882a593Smuzhiyun
269*4882a593Smuzhiyun //--------------------------------------------------------------------
270*4882a593Smuzhiyun // WRITE - step 2 : clear the message buffer
271*4882a593Smuzhiyun data = 0x00000000 | (unsigned long)cmd;
272*4882a593Smuzhiyun wpg_data = swab32(data);
273*4882a593Smuzhiyun wpg_addr = WPGBbar + WPG_I2CMBUFL_OFFSET;
274*4882a593Smuzhiyun writel(wpg_data, wpg_addr);
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun //--------------------------------------------------------------------
277*4882a593Smuzhiyun // WRITE - step 3 : issue start operation,I2C master control bit 30:ON
278*4882a593Smuzhiyun // 2020 : [20] OR operation at [20] offset 0x20
279*4882a593Smuzhiyun data = WPG_I2CMCNTL_STARTOP_MASK;
280*4882a593Smuzhiyun wpg_data = swab32(data);
281*4882a593Smuzhiyun wpg_addr = WPGBbar + WPG_I2CMCNTL_OFFSET + WPG_I2C_OR;
282*4882a593Smuzhiyun writel(wpg_data, wpg_addr);
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun //--------------------------------------------------------------------
285*4882a593Smuzhiyun // WRITE - step 4 : wait until start operation bit clears
286*4882a593Smuzhiyun i = CMD_COMPLETE_TOUT_SEC;
287*4882a593Smuzhiyun while (i) {
288*4882a593Smuzhiyun msleep(10);
289*4882a593Smuzhiyun wpg_addr = WPGBbar + WPG_I2CMCNTL_OFFSET;
290*4882a593Smuzhiyun wpg_data = readl(wpg_addr);
291*4882a593Smuzhiyun data = swab32(wpg_data);
292*4882a593Smuzhiyun if (!(data & WPG_I2CMCNTL_STARTOP_MASK))
293*4882a593Smuzhiyun break;
294*4882a593Smuzhiyun i--;
295*4882a593Smuzhiyun }
296*4882a593Smuzhiyun if (i == 0) {
297*4882a593Smuzhiyun debug("%s - Exit Error:WPG timeout\n", __func__);
298*4882a593Smuzhiyun rc = HPC_ERROR;
299*4882a593Smuzhiyun }
300*4882a593Smuzhiyun
301*4882a593Smuzhiyun //--------------------------------------------------------------------
302*4882a593Smuzhiyun // WRITE - step 5 : read I2C status register
303*4882a593Smuzhiyun i = CMD_COMPLETE_TOUT_SEC;
304*4882a593Smuzhiyun while (i) {
305*4882a593Smuzhiyun msleep(10);
306*4882a593Smuzhiyun wpg_addr = WPGBbar + WPG_I2CSTAT_OFFSET;
307*4882a593Smuzhiyun wpg_data = readl(wpg_addr);
308*4882a593Smuzhiyun data = swab32(wpg_data);
309*4882a593Smuzhiyun if (HPC_I2CSTATUS_CHECK(data))
310*4882a593Smuzhiyun break;
311*4882a593Smuzhiyun i--;
312*4882a593Smuzhiyun }
313*4882a593Smuzhiyun if (i == 0) {
314*4882a593Smuzhiyun debug("ctrl_read - Error : I2C timeout\n");
315*4882a593Smuzhiyun rc = HPC_ERROR;
316*4882a593Smuzhiyun }
317*4882a593Smuzhiyun
318*4882a593Smuzhiyun debug_polling("%s Exit rc[%x]\n", __func__, rc);
319*4882a593Smuzhiyun return (rc);
320*4882a593Smuzhiyun }
321*4882a593Smuzhiyun
322*4882a593Smuzhiyun //------------------------------------------------------------
323*4882a593Smuzhiyun // Read from ISA type HPC
324*4882a593Smuzhiyun //------------------------------------------------------------
isa_ctrl_read(struct controller * ctlr_ptr,u8 offset)325*4882a593Smuzhiyun static u8 isa_ctrl_read(struct controller *ctlr_ptr, u8 offset)
326*4882a593Smuzhiyun {
327*4882a593Smuzhiyun u16 start_address;
328*4882a593Smuzhiyun u16 end_address;
329*4882a593Smuzhiyun u8 data;
330*4882a593Smuzhiyun
331*4882a593Smuzhiyun start_address = ctlr_ptr->u.isa_ctlr.io_start;
332*4882a593Smuzhiyun end_address = ctlr_ptr->u.isa_ctlr.io_end;
333*4882a593Smuzhiyun data = inb(start_address + offset);
334*4882a593Smuzhiyun return data;
335*4882a593Smuzhiyun }
336*4882a593Smuzhiyun
337*4882a593Smuzhiyun //--------------------------------------------------------------
338*4882a593Smuzhiyun // Write to ISA type HPC
339*4882a593Smuzhiyun //--------------------------------------------------------------
isa_ctrl_write(struct controller * ctlr_ptr,u8 offset,u8 data)340*4882a593Smuzhiyun static void isa_ctrl_write(struct controller *ctlr_ptr, u8 offset, u8 data)
341*4882a593Smuzhiyun {
342*4882a593Smuzhiyun u16 start_address;
343*4882a593Smuzhiyun u16 port_address;
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun start_address = ctlr_ptr->u.isa_ctlr.io_start;
346*4882a593Smuzhiyun port_address = start_address + (u16) offset;
347*4882a593Smuzhiyun outb(data, port_address);
348*4882a593Smuzhiyun }
349*4882a593Smuzhiyun
pci_ctrl_read(struct controller * ctrl,u8 offset)350*4882a593Smuzhiyun static u8 pci_ctrl_read(struct controller *ctrl, u8 offset)
351*4882a593Smuzhiyun {
352*4882a593Smuzhiyun u8 data = 0x00;
353*4882a593Smuzhiyun debug("inside pci_ctrl_read\n");
354*4882a593Smuzhiyun if (ctrl->ctrl_dev)
355*4882a593Smuzhiyun pci_read_config_byte(ctrl->ctrl_dev, HPC_PCI_OFFSET + offset, &data);
356*4882a593Smuzhiyun return data;
357*4882a593Smuzhiyun }
358*4882a593Smuzhiyun
pci_ctrl_write(struct controller * ctrl,u8 offset,u8 data)359*4882a593Smuzhiyun static u8 pci_ctrl_write(struct controller *ctrl, u8 offset, u8 data)
360*4882a593Smuzhiyun {
361*4882a593Smuzhiyun u8 rc = -ENODEV;
362*4882a593Smuzhiyun debug("inside pci_ctrl_write\n");
363*4882a593Smuzhiyun if (ctrl->ctrl_dev) {
364*4882a593Smuzhiyun pci_write_config_byte(ctrl->ctrl_dev, HPC_PCI_OFFSET + offset, data);
365*4882a593Smuzhiyun rc = 0;
366*4882a593Smuzhiyun }
367*4882a593Smuzhiyun return rc;
368*4882a593Smuzhiyun }
369*4882a593Smuzhiyun
ctrl_read(struct controller * ctlr,void __iomem * base,u8 offset)370*4882a593Smuzhiyun static u8 ctrl_read(struct controller *ctlr, void __iomem *base, u8 offset)
371*4882a593Smuzhiyun {
372*4882a593Smuzhiyun u8 rc;
373*4882a593Smuzhiyun switch (ctlr->ctlr_type) {
374*4882a593Smuzhiyun case 0:
375*4882a593Smuzhiyun rc = isa_ctrl_read(ctlr, offset);
376*4882a593Smuzhiyun break;
377*4882a593Smuzhiyun case 1:
378*4882a593Smuzhiyun rc = pci_ctrl_read(ctlr, offset);
379*4882a593Smuzhiyun break;
380*4882a593Smuzhiyun case 2:
381*4882a593Smuzhiyun case 4:
382*4882a593Smuzhiyun rc = i2c_ctrl_read(ctlr, base, offset);
383*4882a593Smuzhiyun break;
384*4882a593Smuzhiyun default:
385*4882a593Smuzhiyun return -ENODEV;
386*4882a593Smuzhiyun }
387*4882a593Smuzhiyun return rc;
388*4882a593Smuzhiyun }
389*4882a593Smuzhiyun
ctrl_write(struct controller * ctlr,void __iomem * base,u8 offset,u8 data)390*4882a593Smuzhiyun static u8 ctrl_write(struct controller *ctlr, void __iomem *base, u8 offset, u8 data)
391*4882a593Smuzhiyun {
392*4882a593Smuzhiyun u8 rc = 0;
393*4882a593Smuzhiyun switch (ctlr->ctlr_type) {
394*4882a593Smuzhiyun case 0:
395*4882a593Smuzhiyun isa_ctrl_write(ctlr, offset, data);
396*4882a593Smuzhiyun break;
397*4882a593Smuzhiyun case 1:
398*4882a593Smuzhiyun rc = pci_ctrl_write(ctlr, offset, data);
399*4882a593Smuzhiyun break;
400*4882a593Smuzhiyun case 2:
401*4882a593Smuzhiyun case 4:
402*4882a593Smuzhiyun rc = i2c_ctrl_write(ctlr, base, offset, data);
403*4882a593Smuzhiyun break;
404*4882a593Smuzhiyun default:
405*4882a593Smuzhiyun return -ENODEV;
406*4882a593Smuzhiyun }
407*4882a593Smuzhiyun return rc;
408*4882a593Smuzhiyun }
409*4882a593Smuzhiyun /*----------------------------------------------------------------------
410*4882a593Smuzhiyun * Name: hpc_writecmdtoindex()
411*4882a593Smuzhiyun *
412*4882a593Smuzhiyun * Action: convert a write command to proper index within a controller
413*4882a593Smuzhiyun *
414*4882a593Smuzhiyun * Return index, HPC_ERROR
415*4882a593Smuzhiyun *---------------------------------------------------------------------*/
hpc_writecmdtoindex(u8 cmd,u8 index)416*4882a593Smuzhiyun static u8 hpc_writecmdtoindex(u8 cmd, u8 index)
417*4882a593Smuzhiyun {
418*4882a593Smuzhiyun u8 rc;
419*4882a593Smuzhiyun
420*4882a593Smuzhiyun switch (cmd) {
421*4882a593Smuzhiyun case HPC_CTLR_ENABLEIRQ: // 0x00.N.15
422*4882a593Smuzhiyun case HPC_CTLR_CLEARIRQ: // 0x06.N.15
423*4882a593Smuzhiyun case HPC_CTLR_RESET: // 0x07.N.15
424*4882a593Smuzhiyun case HPC_CTLR_IRQSTEER: // 0x08.N.15
425*4882a593Smuzhiyun case HPC_CTLR_DISABLEIRQ: // 0x01.N.15
426*4882a593Smuzhiyun case HPC_ALLSLOT_ON: // 0x11.N.15
427*4882a593Smuzhiyun case HPC_ALLSLOT_OFF: // 0x12.N.15
428*4882a593Smuzhiyun rc = 0x0F;
429*4882a593Smuzhiyun break;
430*4882a593Smuzhiyun
431*4882a593Smuzhiyun case HPC_SLOT_OFF: // 0x02.Y.0-14
432*4882a593Smuzhiyun case HPC_SLOT_ON: // 0x03.Y.0-14
433*4882a593Smuzhiyun case HPC_SLOT_ATTNOFF: // 0x04.N.0-14
434*4882a593Smuzhiyun case HPC_SLOT_ATTNON: // 0x05.N.0-14
435*4882a593Smuzhiyun case HPC_SLOT_BLINKLED: // 0x13.N.0-14
436*4882a593Smuzhiyun rc = index;
437*4882a593Smuzhiyun break;
438*4882a593Smuzhiyun
439*4882a593Smuzhiyun case HPC_BUS_33CONVMODE:
440*4882a593Smuzhiyun case HPC_BUS_66CONVMODE:
441*4882a593Smuzhiyun case HPC_BUS_66PCIXMODE:
442*4882a593Smuzhiyun case HPC_BUS_100PCIXMODE:
443*4882a593Smuzhiyun case HPC_BUS_133PCIXMODE:
444*4882a593Smuzhiyun rc = index + WPG_1ST_BUS_INDEX - 1;
445*4882a593Smuzhiyun break;
446*4882a593Smuzhiyun
447*4882a593Smuzhiyun default:
448*4882a593Smuzhiyun err("hpc_writecmdtoindex - Error invalid cmd[%x]\n", cmd);
449*4882a593Smuzhiyun rc = HPC_ERROR;
450*4882a593Smuzhiyun }
451*4882a593Smuzhiyun
452*4882a593Smuzhiyun return rc;
453*4882a593Smuzhiyun }
454*4882a593Smuzhiyun
455*4882a593Smuzhiyun /*----------------------------------------------------------------------
456*4882a593Smuzhiyun * Name: hpc_readcmdtoindex()
457*4882a593Smuzhiyun *
458*4882a593Smuzhiyun * Action: convert a read command to proper index within a controller
459*4882a593Smuzhiyun *
460*4882a593Smuzhiyun * Return index, HPC_ERROR
461*4882a593Smuzhiyun *---------------------------------------------------------------------*/
hpc_readcmdtoindex(u8 cmd,u8 index)462*4882a593Smuzhiyun static u8 hpc_readcmdtoindex(u8 cmd, u8 index)
463*4882a593Smuzhiyun {
464*4882a593Smuzhiyun u8 rc;
465*4882a593Smuzhiyun
466*4882a593Smuzhiyun switch (cmd) {
467*4882a593Smuzhiyun case READ_CTLRSTATUS:
468*4882a593Smuzhiyun rc = 0x0F;
469*4882a593Smuzhiyun break;
470*4882a593Smuzhiyun case READ_SLOTSTATUS:
471*4882a593Smuzhiyun case READ_ALLSTAT:
472*4882a593Smuzhiyun rc = index;
473*4882a593Smuzhiyun break;
474*4882a593Smuzhiyun case READ_EXTSLOTSTATUS:
475*4882a593Smuzhiyun rc = index + WPG_1ST_EXTSLOT_INDEX;
476*4882a593Smuzhiyun break;
477*4882a593Smuzhiyun case READ_BUSSTATUS:
478*4882a593Smuzhiyun rc = index + WPG_1ST_BUS_INDEX - 1;
479*4882a593Smuzhiyun break;
480*4882a593Smuzhiyun case READ_SLOTLATCHLOWREG:
481*4882a593Smuzhiyun rc = 0x28;
482*4882a593Smuzhiyun break;
483*4882a593Smuzhiyun case READ_REVLEVEL:
484*4882a593Smuzhiyun rc = 0x25;
485*4882a593Smuzhiyun break;
486*4882a593Smuzhiyun case READ_HPCOPTIONS:
487*4882a593Smuzhiyun rc = 0x27;
488*4882a593Smuzhiyun break;
489*4882a593Smuzhiyun default:
490*4882a593Smuzhiyun rc = HPC_ERROR;
491*4882a593Smuzhiyun }
492*4882a593Smuzhiyun return rc;
493*4882a593Smuzhiyun }
494*4882a593Smuzhiyun
495*4882a593Smuzhiyun /*----------------------------------------------------------------------
496*4882a593Smuzhiyun * Name: HPCreadslot()
497*4882a593Smuzhiyun *
498*4882a593Smuzhiyun * Action: issue a READ command to HPC
499*4882a593Smuzhiyun *
500*4882a593Smuzhiyun * Input: pslot - cannot be NULL for READ_ALLSTAT
501*4882a593Smuzhiyun * pstatus - can be NULL for READ_ALLSTAT
502*4882a593Smuzhiyun *
503*4882a593Smuzhiyun * Return 0 or error codes
504*4882a593Smuzhiyun *---------------------------------------------------------------------*/
ibmphp_hpc_readslot(struct slot * pslot,u8 cmd,u8 * pstatus)505*4882a593Smuzhiyun int ibmphp_hpc_readslot(struct slot *pslot, u8 cmd, u8 *pstatus)
506*4882a593Smuzhiyun {
507*4882a593Smuzhiyun void __iomem *wpg_bbar = NULL;
508*4882a593Smuzhiyun struct controller *ctlr_ptr;
509*4882a593Smuzhiyun u8 index, status;
510*4882a593Smuzhiyun int rc = 0;
511*4882a593Smuzhiyun int busindex;
512*4882a593Smuzhiyun
513*4882a593Smuzhiyun debug_polling("%s - Entry pslot[%p] cmd[%x] pstatus[%p]\n", __func__, pslot, cmd, pstatus);
514*4882a593Smuzhiyun
515*4882a593Smuzhiyun if ((pslot == NULL)
516*4882a593Smuzhiyun || ((pstatus == NULL) && (cmd != READ_ALLSTAT) && (cmd != READ_BUSSTATUS))) {
517*4882a593Smuzhiyun rc = -EINVAL;
518*4882a593Smuzhiyun err("%s - Error invalid pointer, rc[%d]\n", __func__, rc);
519*4882a593Smuzhiyun return rc;
520*4882a593Smuzhiyun }
521*4882a593Smuzhiyun
522*4882a593Smuzhiyun if (cmd == READ_BUSSTATUS) {
523*4882a593Smuzhiyun busindex = ibmphp_get_bus_index(pslot->bus);
524*4882a593Smuzhiyun if (busindex < 0) {
525*4882a593Smuzhiyun rc = -EINVAL;
526*4882a593Smuzhiyun err("%s - Exit Error:invalid bus, rc[%d]\n", __func__, rc);
527*4882a593Smuzhiyun return rc;
528*4882a593Smuzhiyun } else
529*4882a593Smuzhiyun index = (u8) busindex;
530*4882a593Smuzhiyun } else
531*4882a593Smuzhiyun index = pslot->ctlr_index;
532*4882a593Smuzhiyun
533*4882a593Smuzhiyun index = hpc_readcmdtoindex(cmd, index);
534*4882a593Smuzhiyun
535*4882a593Smuzhiyun if (index == HPC_ERROR) {
536*4882a593Smuzhiyun rc = -EINVAL;
537*4882a593Smuzhiyun err("%s - Exit Error:invalid index, rc[%d]\n", __func__, rc);
538*4882a593Smuzhiyun return rc;
539*4882a593Smuzhiyun }
540*4882a593Smuzhiyun
541*4882a593Smuzhiyun ctlr_ptr = pslot->ctrl;
542*4882a593Smuzhiyun
543*4882a593Smuzhiyun get_hpc_access();
544*4882a593Smuzhiyun
545*4882a593Smuzhiyun //--------------------------------------------------------------------
546*4882a593Smuzhiyun // map physical address to logical address
547*4882a593Smuzhiyun //--------------------------------------------------------------------
548*4882a593Smuzhiyun if ((ctlr_ptr->ctlr_type == 2) || (ctlr_ptr->ctlr_type == 4))
549*4882a593Smuzhiyun wpg_bbar = ioremap(ctlr_ptr->u.wpeg_ctlr.wpegbbar, WPG_I2C_IOREMAP_SIZE);
550*4882a593Smuzhiyun
551*4882a593Smuzhiyun //--------------------------------------------------------------------
552*4882a593Smuzhiyun // check controller status before reading
553*4882a593Smuzhiyun //--------------------------------------------------------------------
554*4882a593Smuzhiyun rc = hpc_wait_ctlr_notworking(HPC_CTLR_WORKING_TOUT, ctlr_ptr, wpg_bbar, &status);
555*4882a593Smuzhiyun if (!rc) {
556*4882a593Smuzhiyun switch (cmd) {
557*4882a593Smuzhiyun case READ_ALLSTAT:
558*4882a593Smuzhiyun // update the slot structure
559*4882a593Smuzhiyun pslot->ctrl->status = status;
560*4882a593Smuzhiyun pslot->status = ctrl_read(ctlr_ptr, wpg_bbar, index);
561*4882a593Smuzhiyun rc = hpc_wait_ctlr_notworking(HPC_CTLR_WORKING_TOUT, ctlr_ptr, wpg_bbar,
562*4882a593Smuzhiyun &status);
563*4882a593Smuzhiyun if (!rc)
564*4882a593Smuzhiyun pslot->ext_status = ctrl_read(ctlr_ptr, wpg_bbar, index + WPG_1ST_EXTSLOT_INDEX);
565*4882a593Smuzhiyun
566*4882a593Smuzhiyun break;
567*4882a593Smuzhiyun
568*4882a593Smuzhiyun case READ_SLOTSTATUS:
569*4882a593Smuzhiyun // DO NOT update the slot structure
570*4882a593Smuzhiyun *pstatus = ctrl_read(ctlr_ptr, wpg_bbar, index);
571*4882a593Smuzhiyun break;
572*4882a593Smuzhiyun
573*4882a593Smuzhiyun case READ_EXTSLOTSTATUS:
574*4882a593Smuzhiyun // DO NOT update the slot structure
575*4882a593Smuzhiyun *pstatus = ctrl_read(ctlr_ptr, wpg_bbar, index);
576*4882a593Smuzhiyun break;
577*4882a593Smuzhiyun
578*4882a593Smuzhiyun case READ_CTLRSTATUS:
579*4882a593Smuzhiyun // DO NOT update the slot structure
580*4882a593Smuzhiyun *pstatus = status;
581*4882a593Smuzhiyun break;
582*4882a593Smuzhiyun
583*4882a593Smuzhiyun case READ_BUSSTATUS:
584*4882a593Smuzhiyun pslot->busstatus = ctrl_read(ctlr_ptr, wpg_bbar, index);
585*4882a593Smuzhiyun break;
586*4882a593Smuzhiyun case READ_REVLEVEL:
587*4882a593Smuzhiyun *pstatus = ctrl_read(ctlr_ptr, wpg_bbar, index);
588*4882a593Smuzhiyun break;
589*4882a593Smuzhiyun case READ_HPCOPTIONS:
590*4882a593Smuzhiyun *pstatus = ctrl_read(ctlr_ptr, wpg_bbar, index);
591*4882a593Smuzhiyun break;
592*4882a593Smuzhiyun case READ_SLOTLATCHLOWREG:
593*4882a593Smuzhiyun // DO NOT update the slot structure
594*4882a593Smuzhiyun *pstatus = ctrl_read(ctlr_ptr, wpg_bbar, index);
595*4882a593Smuzhiyun break;
596*4882a593Smuzhiyun
597*4882a593Smuzhiyun // Not used
598*4882a593Smuzhiyun case READ_ALLSLOT:
599*4882a593Smuzhiyun list_for_each_entry(pslot, &ibmphp_slot_head,
600*4882a593Smuzhiyun ibm_slot_list) {
601*4882a593Smuzhiyun index = pslot->ctlr_index;
602*4882a593Smuzhiyun rc = hpc_wait_ctlr_notworking(HPC_CTLR_WORKING_TOUT, ctlr_ptr,
603*4882a593Smuzhiyun wpg_bbar, &status);
604*4882a593Smuzhiyun if (!rc) {
605*4882a593Smuzhiyun pslot->status = ctrl_read(ctlr_ptr, wpg_bbar, index);
606*4882a593Smuzhiyun rc = hpc_wait_ctlr_notworking(HPC_CTLR_WORKING_TOUT,
607*4882a593Smuzhiyun ctlr_ptr, wpg_bbar, &status);
608*4882a593Smuzhiyun if (!rc)
609*4882a593Smuzhiyun pslot->ext_status =
610*4882a593Smuzhiyun ctrl_read(ctlr_ptr, wpg_bbar,
611*4882a593Smuzhiyun index + WPG_1ST_EXTSLOT_INDEX);
612*4882a593Smuzhiyun } else {
613*4882a593Smuzhiyun err("%s - Error ctrl_read failed\n", __func__);
614*4882a593Smuzhiyun rc = -EINVAL;
615*4882a593Smuzhiyun break;
616*4882a593Smuzhiyun }
617*4882a593Smuzhiyun }
618*4882a593Smuzhiyun break;
619*4882a593Smuzhiyun default:
620*4882a593Smuzhiyun rc = -EINVAL;
621*4882a593Smuzhiyun break;
622*4882a593Smuzhiyun }
623*4882a593Smuzhiyun }
624*4882a593Smuzhiyun //--------------------------------------------------------------------
625*4882a593Smuzhiyun // cleanup
626*4882a593Smuzhiyun //--------------------------------------------------------------------
627*4882a593Smuzhiyun
628*4882a593Smuzhiyun // remove physical to logical address mapping
629*4882a593Smuzhiyun if ((ctlr_ptr->ctlr_type == 2) || (ctlr_ptr->ctlr_type == 4))
630*4882a593Smuzhiyun iounmap(wpg_bbar);
631*4882a593Smuzhiyun
632*4882a593Smuzhiyun free_hpc_access();
633*4882a593Smuzhiyun
634*4882a593Smuzhiyun debug_polling("%s - Exit rc[%d]\n", __func__, rc);
635*4882a593Smuzhiyun return rc;
636*4882a593Smuzhiyun }
637*4882a593Smuzhiyun
638*4882a593Smuzhiyun /*----------------------------------------------------------------------
639*4882a593Smuzhiyun * Name: ibmphp_hpc_writeslot()
640*4882a593Smuzhiyun *
641*4882a593Smuzhiyun * Action: issue a WRITE command to HPC
642*4882a593Smuzhiyun *---------------------------------------------------------------------*/
ibmphp_hpc_writeslot(struct slot * pslot,u8 cmd)643*4882a593Smuzhiyun int ibmphp_hpc_writeslot(struct slot *pslot, u8 cmd)
644*4882a593Smuzhiyun {
645*4882a593Smuzhiyun void __iomem *wpg_bbar = NULL;
646*4882a593Smuzhiyun struct controller *ctlr_ptr;
647*4882a593Smuzhiyun u8 index, status;
648*4882a593Smuzhiyun int busindex;
649*4882a593Smuzhiyun u8 done;
650*4882a593Smuzhiyun int rc = 0;
651*4882a593Smuzhiyun int timeout;
652*4882a593Smuzhiyun
653*4882a593Smuzhiyun debug_polling("%s - Entry pslot[%p] cmd[%x]\n", __func__, pslot, cmd);
654*4882a593Smuzhiyun if (pslot == NULL) {
655*4882a593Smuzhiyun rc = -EINVAL;
656*4882a593Smuzhiyun err("%s - Error Exit rc[%d]\n", __func__, rc);
657*4882a593Smuzhiyun return rc;
658*4882a593Smuzhiyun }
659*4882a593Smuzhiyun
660*4882a593Smuzhiyun if ((cmd == HPC_BUS_33CONVMODE) || (cmd == HPC_BUS_66CONVMODE) ||
661*4882a593Smuzhiyun (cmd == HPC_BUS_66PCIXMODE) || (cmd == HPC_BUS_100PCIXMODE) ||
662*4882a593Smuzhiyun (cmd == HPC_BUS_133PCIXMODE)) {
663*4882a593Smuzhiyun busindex = ibmphp_get_bus_index(pslot->bus);
664*4882a593Smuzhiyun if (busindex < 0) {
665*4882a593Smuzhiyun rc = -EINVAL;
666*4882a593Smuzhiyun err("%s - Exit Error:invalid bus, rc[%d]\n", __func__, rc);
667*4882a593Smuzhiyun return rc;
668*4882a593Smuzhiyun } else
669*4882a593Smuzhiyun index = (u8) busindex;
670*4882a593Smuzhiyun } else
671*4882a593Smuzhiyun index = pslot->ctlr_index;
672*4882a593Smuzhiyun
673*4882a593Smuzhiyun index = hpc_writecmdtoindex(cmd, index);
674*4882a593Smuzhiyun
675*4882a593Smuzhiyun if (index == HPC_ERROR) {
676*4882a593Smuzhiyun rc = -EINVAL;
677*4882a593Smuzhiyun err("%s - Error Exit rc[%d]\n", __func__, rc);
678*4882a593Smuzhiyun return rc;
679*4882a593Smuzhiyun }
680*4882a593Smuzhiyun
681*4882a593Smuzhiyun ctlr_ptr = pslot->ctrl;
682*4882a593Smuzhiyun
683*4882a593Smuzhiyun get_hpc_access();
684*4882a593Smuzhiyun
685*4882a593Smuzhiyun //--------------------------------------------------------------------
686*4882a593Smuzhiyun // map physical address to logical address
687*4882a593Smuzhiyun //--------------------------------------------------------------------
688*4882a593Smuzhiyun if ((ctlr_ptr->ctlr_type == 2) || (ctlr_ptr->ctlr_type == 4)) {
689*4882a593Smuzhiyun wpg_bbar = ioremap(ctlr_ptr->u.wpeg_ctlr.wpegbbar, WPG_I2C_IOREMAP_SIZE);
690*4882a593Smuzhiyun
691*4882a593Smuzhiyun debug("%s - ctlr id[%x] physical[%lx] logical[%lx] i2c[%x]\n", __func__,
692*4882a593Smuzhiyun ctlr_ptr->ctlr_id, (ulong) (ctlr_ptr->u.wpeg_ctlr.wpegbbar), (ulong) wpg_bbar,
693*4882a593Smuzhiyun ctlr_ptr->u.wpeg_ctlr.i2c_addr);
694*4882a593Smuzhiyun }
695*4882a593Smuzhiyun //--------------------------------------------------------------------
696*4882a593Smuzhiyun // check controller status before writing
697*4882a593Smuzhiyun //--------------------------------------------------------------------
698*4882a593Smuzhiyun rc = hpc_wait_ctlr_notworking(HPC_CTLR_WORKING_TOUT, ctlr_ptr, wpg_bbar, &status);
699*4882a593Smuzhiyun if (!rc) {
700*4882a593Smuzhiyun
701*4882a593Smuzhiyun ctrl_write(ctlr_ptr, wpg_bbar, index, cmd);
702*4882a593Smuzhiyun
703*4882a593Smuzhiyun //--------------------------------------------------------------------
704*4882a593Smuzhiyun // check controller is still not working on the command
705*4882a593Smuzhiyun //--------------------------------------------------------------------
706*4882a593Smuzhiyun timeout = CMD_COMPLETE_TOUT_SEC;
707*4882a593Smuzhiyun done = 0;
708*4882a593Smuzhiyun while (!done) {
709*4882a593Smuzhiyun rc = hpc_wait_ctlr_notworking(HPC_CTLR_WORKING_TOUT, ctlr_ptr, wpg_bbar,
710*4882a593Smuzhiyun &status);
711*4882a593Smuzhiyun if (!rc) {
712*4882a593Smuzhiyun if (NEEDTOCHECK_CMDSTATUS(cmd)) {
713*4882a593Smuzhiyun if (CTLR_FINISHED(status) == HPC_CTLR_FINISHED_YES)
714*4882a593Smuzhiyun done = 1;
715*4882a593Smuzhiyun } else
716*4882a593Smuzhiyun done = 1;
717*4882a593Smuzhiyun }
718*4882a593Smuzhiyun if (!done) {
719*4882a593Smuzhiyun msleep(1000);
720*4882a593Smuzhiyun if (timeout < 1) {
721*4882a593Smuzhiyun done = 1;
722*4882a593Smuzhiyun err("%s - Error command complete timeout\n", __func__);
723*4882a593Smuzhiyun rc = -EFAULT;
724*4882a593Smuzhiyun } else
725*4882a593Smuzhiyun timeout--;
726*4882a593Smuzhiyun }
727*4882a593Smuzhiyun }
728*4882a593Smuzhiyun ctlr_ptr->status = status;
729*4882a593Smuzhiyun }
730*4882a593Smuzhiyun // cleanup
731*4882a593Smuzhiyun
732*4882a593Smuzhiyun // remove physical to logical address mapping
733*4882a593Smuzhiyun if ((ctlr_ptr->ctlr_type == 2) || (ctlr_ptr->ctlr_type == 4))
734*4882a593Smuzhiyun iounmap(wpg_bbar);
735*4882a593Smuzhiyun free_hpc_access();
736*4882a593Smuzhiyun
737*4882a593Smuzhiyun debug_polling("%s - Exit rc[%d]\n", __func__, rc);
738*4882a593Smuzhiyun return rc;
739*4882a593Smuzhiyun }
740*4882a593Smuzhiyun
741*4882a593Smuzhiyun /*----------------------------------------------------------------------
742*4882a593Smuzhiyun * Name: get_hpc_access()
743*4882a593Smuzhiyun *
744*4882a593Smuzhiyun * Action: make sure only one process can access HPC at one time
745*4882a593Smuzhiyun *---------------------------------------------------------------------*/
get_hpc_access(void)746*4882a593Smuzhiyun static void get_hpc_access(void)
747*4882a593Smuzhiyun {
748*4882a593Smuzhiyun mutex_lock(&sem_hpcaccess);
749*4882a593Smuzhiyun }
750*4882a593Smuzhiyun
751*4882a593Smuzhiyun /*----------------------------------------------------------------------
752*4882a593Smuzhiyun * Name: free_hpc_access()
753*4882a593Smuzhiyun *---------------------------------------------------------------------*/
free_hpc_access(void)754*4882a593Smuzhiyun void free_hpc_access(void)
755*4882a593Smuzhiyun {
756*4882a593Smuzhiyun mutex_unlock(&sem_hpcaccess);
757*4882a593Smuzhiyun }
758*4882a593Smuzhiyun
759*4882a593Smuzhiyun /*----------------------------------------------------------------------
760*4882a593Smuzhiyun * Name: ibmphp_lock_operations()
761*4882a593Smuzhiyun *
762*4882a593Smuzhiyun * Action: make sure only one process can change the data structure
763*4882a593Smuzhiyun *---------------------------------------------------------------------*/
ibmphp_lock_operations(void)764*4882a593Smuzhiyun void ibmphp_lock_operations(void)
765*4882a593Smuzhiyun {
766*4882a593Smuzhiyun mutex_lock(&operations_mutex);
767*4882a593Smuzhiyun to_debug = 1;
768*4882a593Smuzhiyun }
769*4882a593Smuzhiyun
770*4882a593Smuzhiyun /*----------------------------------------------------------------------
771*4882a593Smuzhiyun * Name: ibmphp_unlock_operations()
772*4882a593Smuzhiyun *---------------------------------------------------------------------*/
ibmphp_unlock_operations(void)773*4882a593Smuzhiyun void ibmphp_unlock_operations(void)
774*4882a593Smuzhiyun {
775*4882a593Smuzhiyun debug("%s - Entry\n", __func__);
776*4882a593Smuzhiyun mutex_unlock(&operations_mutex);
777*4882a593Smuzhiyun to_debug = 0;
778*4882a593Smuzhiyun debug("%s - Exit\n", __func__);
779*4882a593Smuzhiyun }
780*4882a593Smuzhiyun
781*4882a593Smuzhiyun /*----------------------------------------------------------------------
782*4882a593Smuzhiyun * Name: poll_hpc()
783*4882a593Smuzhiyun *---------------------------------------------------------------------*/
784*4882a593Smuzhiyun #define POLL_LATCH_REGISTER 0
785*4882a593Smuzhiyun #define POLL_SLOTS 1
786*4882a593Smuzhiyun #define POLL_SLEEP 2
poll_hpc(void * data)787*4882a593Smuzhiyun static int poll_hpc(void *data)
788*4882a593Smuzhiyun {
789*4882a593Smuzhiyun struct slot myslot;
790*4882a593Smuzhiyun struct slot *pslot = NULL;
791*4882a593Smuzhiyun int rc;
792*4882a593Smuzhiyun int poll_state = POLL_LATCH_REGISTER;
793*4882a593Smuzhiyun u8 oldlatchlow = 0x00;
794*4882a593Smuzhiyun u8 curlatchlow = 0x00;
795*4882a593Smuzhiyun int poll_count = 0;
796*4882a593Smuzhiyun u8 ctrl_count = 0x00;
797*4882a593Smuzhiyun
798*4882a593Smuzhiyun debug("%s - Entry\n", __func__);
799*4882a593Smuzhiyun
800*4882a593Smuzhiyun while (!kthread_should_stop()) {
801*4882a593Smuzhiyun /* try to get the lock to do some kind of hardware access */
802*4882a593Smuzhiyun mutex_lock(&operations_mutex);
803*4882a593Smuzhiyun
804*4882a593Smuzhiyun switch (poll_state) {
805*4882a593Smuzhiyun case POLL_LATCH_REGISTER:
806*4882a593Smuzhiyun oldlatchlow = curlatchlow;
807*4882a593Smuzhiyun ctrl_count = 0x00;
808*4882a593Smuzhiyun list_for_each_entry(pslot, &ibmphp_slot_head,
809*4882a593Smuzhiyun ibm_slot_list) {
810*4882a593Smuzhiyun if (ctrl_count >= ibmphp_get_total_controllers())
811*4882a593Smuzhiyun break;
812*4882a593Smuzhiyun if (pslot->ctrl->ctlr_relative_id == ctrl_count) {
813*4882a593Smuzhiyun ctrl_count++;
814*4882a593Smuzhiyun if (READ_SLOT_LATCH(pslot->ctrl)) {
815*4882a593Smuzhiyun rc = ibmphp_hpc_readslot(pslot,
816*4882a593Smuzhiyun READ_SLOTLATCHLOWREG,
817*4882a593Smuzhiyun &curlatchlow);
818*4882a593Smuzhiyun if (oldlatchlow != curlatchlow)
819*4882a593Smuzhiyun process_changeinlatch(oldlatchlow,
820*4882a593Smuzhiyun curlatchlow,
821*4882a593Smuzhiyun pslot->ctrl);
822*4882a593Smuzhiyun }
823*4882a593Smuzhiyun }
824*4882a593Smuzhiyun }
825*4882a593Smuzhiyun ++poll_count;
826*4882a593Smuzhiyun poll_state = POLL_SLEEP;
827*4882a593Smuzhiyun break;
828*4882a593Smuzhiyun case POLL_SLOTS:
829*4882a593Smuzhiyun list_for_each_entry(pslot, &ibmphp_slot_head,
830*4882a593Smuzhiyun ibm_slot_list) {
831*4882a593Smuzhiyun // make a copy of the old status
832*4882a593Smuzhiyun memcpy((void *) &myslot, (void *) pslot,
833*4882a593Smuzhiyun sizeof(struct slot));
834*4882a593Smuzhiyun rc = ibmphp_hpc_readslot(pslot, READ_ALLSTAT, NULL);
835*4882a593Smuzhiyun if ((myslot.status != pslot->status)
836*4882a593Smuzhiyun || (myslot.ext_status != pslot->ext_status))
837*4882a593Smuzhiyun process_changeinstatus(pslot, &myslot);
838*4882a593Smuzhiyun }
839*4882a593Smuzhiyun ctrl_count = 0x00;
840*4882a593Smuzhiyun list_for_each_entry(pslot, &ibmphp_slot_head,
841*4882a593Smuzhiyun ibm_slot_list) {
842*4882a593Smuzhiyun if (ctrl_count >= ibmphp_get_total_controllers())
843*4882a593Smuzhiyun break;
844*4882a593Smuzhiyun if (pslot->ctrl->ctlr_relative_id == ctrl_count) {
845*4882a593Smuzhiyun ctrl_count++;
846*4882a593Smuzhiyun if (READ_SLOT_LATCH(pslot->ctrl))
847*4882a593Smuzhiyun rc = ibmphp_hpc_readslot(pslot,
848*4882a593Smuzhiyun READ_SLOTLATCHLOWREG,
849*4882a593Smuzhiyun &curlatchlow);
850*4882a593Smuzhiyun }
851*4882a593Smuzhiyun }
852*4882a593Smuzhiyun ++poll_count;
853*4882a593Smuzhiyun poll_state = POLL_SLEEP;
854*4882a593Smuzhiyun break;
855*4882a593Smuzhiyun case POLL_SLEEP:
856*4882a593Smuzhiyun /* don't sleep with a lock on the hardware */
857*4882a593Smuzhiyun mutex_unlock(&operations_mutex);
858*4882a593Smuzhiyun msleep(POLL_INTERVAL_SEC * 1000);
859*4882a593Smuzhiyun
860*4882a593Smuzhiyun if (kthread_should_stop())
861*4882a593Smuzhiyun goto out_sleep;
862*4882a593Smuzhiyun
863*4882a593Smuzhiyun mutex_lock(&operations_mutex);
864*4882a593Smuzhiyun
865*4882a593Smuzhiyun if (poll_count >= POLL_LATCH_CNT) {
866*4882a593Smuzhiyun poll_count = 0;
867*4882a593Smuzhiyun poll_state = POLL_SLOTS;
868*4882a593Smuzhiyun } else
869*4882a593Smuzhiyun poll_state = POLL_LATCH_REGISTER;
870*4882a593Smuzhiyun break;
871*4882a593Smuzhiyun }
872*4882a593Smuzhiyun /* give up the hardware semaphore */
873*4882a593Smuzhiyun mutex_unlock(&operations_mutex);
874*4882a593Smuzhiyun /* sleep for a short time just for good measure */
875*4882a593Smuzhiyun out_sleep:
876*4882a593Smuzhiyun msleep(100);
877*4882a593Smuzhiyun }
878*4882a593Smuzhiyun complete(&exit_complete);
879*4882a593Smuzhiyun debug("%s - Exit\n", __func__);
880*4882a593Smuzhiyun return 0;
881*4882a593Smuzhiyun }
882*4882a593Smuzhiyun
883*4882a593Smuzhiyun
884*4882a593Smuzhiyun /*----------------------------------------------------------------------
885*4882a593Smuzhiyun * Name: process_changeinstatus
886*4882a593Smuzhiyun *
887*4882a593Smuzhiyun * Action: compare old and new slot status, process the change in status
888*4882a593Smuzhiyun *
889*4882a593Smuzhiyun * Input: pointer to slot struct, old slot struct
890*4882a593Smuzhiyun *
891*4882a593Smuzhiyun * Return 0 or error codes
892*4882a593Smuzhiyun * Value:
893*4882a593Smuzhiyun *
894*4882a593Smuzhiyun * Side
895*4882a593Smuzhiyun * Effects: None.
896*4882a593Smuzhiyun *
897*4882a593Smuzhiyun * Notes:
898*4882a593Smuzhiyun *---------------------------------------------------------------------*/
process_changeinstatus(struct slot * pslot,struct slot * poldslot)899*4882a593Smuzhiyun static int process_changeinstatus(struct slot *pslot, struct slot *poldslot)
900*4882a593Smuzhiyun {
901*4882a593Smuzhiyun u8 status;
902*4882a593Smuzhiyun int rc = 0;
903*4882a593Smuzhiyun u8 disable = 0;
904*4882a593Smuzhiyun u8 update = 0;
905*4882a593Smuzhiyun
906*4882a593Smuzhiyun debug("process_changeinstatus - Entry pslot[%p], poldslot[%p]\n", pslot, poldslot);
907*4882a593Smuzhiyun
908*4882a593Smuzhiyun // bit 0 - HPC_SLOT_POWER
909*4882a593Smuzhiyun if ((pslot->status & 0x01) != (poldslot->status & 0x01))
910*4882a593Smuzhiyun update = 1;
911*4882a593Smuzhiyun
912*4882a593Smuzhiyun // bit 1 - HPC_SLOT_CONNECT
913*4882a593Smuzhiyun // ignore
914*4882a593Smuzhiyun
915*4882a593Smuzhiyun // bit 2 - HPC_SLOT_ATTN
916*4882a593Smuzhiyun if ((pslot->status & 0x04) != (poldslot->status & 0x04))
917*4882a593Smuzhiyun update = 1;
918*4882a593Smuzhiyun
919*4882a593Smuzhiyun // bit 3 - HPC_SLOT_PRSNT2
920*4882a593Smuzhiyun // bit 4 - HPC_SLOT_PRSNT1
921*4882a593Smuzhiyun if (((pslot->status & 0x08) != (poldslot->status & 0x08))
922*4882a593Smuzhiyun || ((pslot->status & 0x10) != (poldslot->status & 0x10)))
923*4882a593Smuzhiyun update = 1;
924*4882a593Smuzhiyun
925*4882a593Smuzhiyun // bit 5 - HPC_SLOT_PWRGD
926*4882a593Smuzhiyun if ((pslot->status & 0x20) != (poldslot->status & 0x20))
927*4882a593Smuzhiyun // OFF -> ON: ignore, ON -> OFF: disable slot
928*4882a593Smuzhiyun if ((poldslot->status & 0x20) && (SLOT_CONNECT(poldslot->status) == HPC_SLOT_CONNECTED) && (SLOT_PRESENT(poldslot->status)))
929*4882a593Smuzhiyun disable = 1;
930*4882a593Smuzhiyun
931*4882a593Smuzhiyun // bit 6 - HPC_SLOT_BUS_SPEED
932*4882a593Smuzhiyun // ignore
933*4882a593Smuzhiyun
934*4882a593Smuzhiyun // bit 7 - HPC_SLOT_LATCH
935*4882a593Smuzhiyun if ((pslot->status & 0x80) != (poldslot->status & 0x80)) {
936*4882a593Smuzhiyun update = 1;
937*4882a593Smuzhiyun // OPEN -> CLOSE
938*4882a593Smuzhiyun if (pslot->status & 0x80) {
939*4882a593Smuzhiyun if (SLOT_PWRGD(pslot->status)) {
940*4882a593Smuzhiyun // power goes on and off after closing latch
941*4882a593Smuzhiyun // check again to make sure power is still ON
942*4882a593Smuzhiyun msleep(1000);
943*4882a593Smuzhiyun rc = ibmphp_hpc_readslot(pslot, READ_SLOTSTATUS, &status);
944*4882a593Smuzhiyun if (SLOT_PWRGD(status))
945*4882a593Smuzhiyun update = 1;
946*4882a593Smuzhiyun else // overwrite power in pslot to OFF
947*4882a593Smuzhiyun pslot->status &= ~HPC_SLOT_POWER;
948*4882a593Smuzhiyun }
949*4882a593Smuzhiyun }
950*4882a593Smuzhiyun // CLOSE -> OPEN
951*4882a593Smuzhiyun else if ((SLOT_PWRGD(poldslot->status) == HPC_SLOT_PWRGD_GOOD)
952*4882a593Smuzhiyun && (SLOT_CONNECT(poldslot->status) == HPC_SLOT_CONNECTED) && (SLOT_PRESENT(poldslot->status))) {
953*4882a593Smuzhiyun disable = 1;
954*4882a593Smuzhiyun }
955*4882a593Smuzhiyun // else - ignore
956*4882a593Smuzhiyun }
957*4882a593Smuzhiyun // bit 4 - HPC_SLOT_BLINK_ATTN
958*4882a593Smuzhiyun if ((pslot->ext_status & 0x08) != (poldslot->ext_status & 0x08))
959*4882a593Smuzhiyun update = 1;
960*4882a593Smuzhiyun
961*4882a593Smuzhiyun if (disable) {
962*4882a593Smuzhiyun debug("process_changeinstatus - disable slot\n");
963*4882a593Smuzhiyun pslot->flag = 0;
964*4882a593Smuzhiyun rc = ibmphp_do_disable_slot(pslot);
965*4882a593Smuzhiyun }
966*4882a593Smuzhiyun
967*4882a593Smuzhiyun if (update || disable)
968*4882a593Smuzhiyun ibmphp_update_slot_info(pslot);
969*4882a593Smuzhiyun
970*4882a593Smuzhiyun debug("%s - Exit rc[%d] disable[%x] update[%x]\n", __func__, rc, disable, update);
971*4882a593Smuzhiyun
972*4882a593Smuzhiyun return rc;
973*4882a593Smuzhiyun }
974*4882a593Smuzhiyun
975*4882a593Smuzhiyun /*----------------------------------------------------------------------
976*4882a593Smuzhiyun * Name: process_changeinlatch
977*4882a593Smuzhiyun *
978*4882a593Smuzhiyun * Action: compare old and new latch reg status, process the change
979*4882a593Smuzhiyun *
980*4882a593Smuzhiyun * Input: old and current latch register status
981*4882a593Smuzhiyun *
982*4882a593Smuzhiyun * Return 0 or error codes
983*4882a593Smuzhiyun * Value:
984*4882a593Smuzhiyun *---------------------------------------------------------------------*/
process_changeinlatch(u8 old,u8 new,struct controller * ctrl)985*4882a593Smuzhiyun static int process_changeinlatch(u8 old, u8 new, struct controller *ctrl)
986*4882a593Smuzhiyun {
987*4882a593Smuzhiyun struct slot myslot, *pslot;
988*4882a593Smuzhiyun u8 i;
989*4882a593Smuzhiyun u8 mask;
990*4882a593Smuzhiyun int rc = 0;
991*4882a593Smuzhiyun
992*4882a593Smuzhiyun debug("%s - Entry old[%x], new[%x]\n", __func__, old, new);
993*4882a593Smuzhiyun // bit 0 reserved, 0 is LSB, check bit 1-6 for 6 slots
994*4882a593Smuzhiyun
995*4882a593Smuzhiyun for (i = ctrl->starting_slot_num; i <= ctrl->ending_slot_num; i++) {
996*4882a593Smuzhiyun mask = 0x01 << i;
997*4882a593Smuzhiyun if ((mask & old) != (mask & new)) {
998*4882a593Smuzhiyun pslot = ibmphp_get_slot_from_physical_num(i);
999*4882a593Smuzhiyun if (pslot) {
1000*4882a593Smuzhiyun memcpy((void *) &myslot, (void *) pslot, sizeof(struct slot));
1001*4882a593Smuzhiyun rc = ibmphp_hpc_readslot(pslot, READ_ALLSTAT, NULL);
1002*4882a593Smuzhiyun debug("%s - call process_changeinstatus for slot[%d]\n", __func__, i);
1003*4882a593Smuzhiyun process_changeinstatus(pslot, &myslot);
1004*4882a593Smuzhiyun } else {
1005*4882a593Smuzhiyun rc = -EINVAL;
1006*4882a593Smuzhiyun err("%s - Error bad pointer for slot[%d]\n", __func__, i);
1007*4882a593Smuzhiyun }
1008*4882a593Smuzhiyun }
1009*4882a593Smuzhiyun }
1010*4882a593Smuzhiyun debug("%s - Exit rc[%d]\n", __func__, rc);
1011*4882a593Smuzhiyun return rc;
1012*4882a593Smuzhiyun }
1013*4882a593Smuzhiyun
1014*4882a593Smuzhiyun /*----------------------------------------------------------------------
1015*4882a593Smuzhiyun * Name: ibmphp_hpc_start_poll_thread
1016*4882a593Smuzhiyun *
1017*4882a593Smuzhiyun * Action: start polling thread
1018*4882a593Smuzhiyun *---------------------------------------------------------------------*/
ibmphp_hpc_start_poll_thread(void)1019*4882a593Smuzhiyun int __init ibmphp_hpc_start_poll_thread(void)
1020*4882a593Smuzhiyun {
1021*4882a593Smuzhiyun debug("%s - Entry\n", __func__);
1022*4882a593Smuzhiyun
1023*4882a593Smuzhiyun ibmphp_poll_thread = kthread_run(poll_hpc, NULL, "hpc_poll");
1024*4882a593Smuzhiyun if (IS_ERR(ibmphp_poll_thread)) {
1025*4882a593Smuzhiyun err("%s - Error, thread not started\n", __func__);
1026*4882a593Smuzhiyun return PTR_ERR(ibmphp_poll_thread);
1027*4882a593Smuzhiyun }
1028*4882a593Smuzhiyun return 0;
1029*4882a593Smuzhiyun }
1030*4882a593Smuzhiyun
1031*4882a593Smuzhiyun /*----------------------------------------------------------------------
1032*4882a593Smuzhiyun * Name: ibmphp_hpc_stop_poll_thread
1033*4882a593Smuzhiyun *
1034*4882a593Smuzhiyun * Action: stop polling thread and cleanup
1035*4882a593Smuzhiyun *---------------------------------------------------------------------*/
ibmphp_hpc_stop_poll_thread(void)1036*4882a593Smuzhiyun void __exit ibmphp_hpc_stop_poll_thread(void)
1037*4882a593Smuzhiyun {
1038*4882a593Smuzhiyun debug("%s - Entry\n", __func__);
1039*4882a593Smuzhiyun
1040*4882a593Smuzhiyun kthread_stop(ibmphp_poll_thread);
1041*4882a593Smuzhiyun debug("before locking operations\n");
1042*4882a593Smuzhiyun ibmphp_lock_operations();
1043*4882a593Smuzhiyun debug("after locking operations\n");
1044*4882a593Smuzhiyun
1045*4882a593Smuzhiyun // wait for poll thread to exit
1046*4882a593Smuzhiyun debug("before exit_complete down\n");
1047*4882a593Smuzhiyun wait_for_completion(&exit_complete);
1048*4882a593Smuzhiyun debug("after exit_completion down\n");
1049*4882a593Smuzhiyun
1050*4882a593Smuzhiyun // cleanup
1051*4882a593Smuzhiyun debug("before free_hpc_access\n");
1052*4882a593Smuzhiyun free_hpc_access();
1053*4882a593Smuzhiyun debug("after free_hpc_access\n");
1054*4882a593Smuzhiyun ibmphp_unlock_operations();
1055*4882a593Smuzhiyun debug("after unlock operations\n");
1056*4882a593Smuzhiyun
1057*4882a593Smuzhiyun debug("%s - Exit\n", __func__);
1058*4882a593Smuzhiyun }
1059*4882a593Smuzhiyun
1060*4882a593Smuzhiyun /*----------------------------------------------------------------------
1061*4882a593Smuzhiyun * Name: hpc_wait_ctlr_notworking
1062*4882a593Smuzhiyun *
1063*4882a593Smuzhiyun * Action: wait until the controller is in a not working state
1064*4882a593Smuzhiyun *
1065*4882a593Smuzhiyun * Return 0, HPC_ERROR
1066*4882a593Smuzhiyun * Value:
1067*4882a593Smuzhiyun *---------------------------------------------------------------------*/
hpc_wait_ctlr_notworking(int timeout,struct controller * ctlr_ptr,void __iomem * wpg_bbar,u8 * pstatus)1068*4882a593Smuzhiyun static int hpc_wait_ctlr_notworking(int timeout, struct controller *ctlr_ptr, void __iomem *wpg_bbar,
1069*4882a593Smuzhiyun u8 *pstatus)
1070*4882a593Smuzhiyun {
1071*4882a593Smuzhiyun int rc = 0;
1072*4882a593Smuzhiyun u8 done = 0;
1073*4882a593Smuzhiyun
1074*4882a593Smuzhiyun debug_polling("hpc_wait_ctlr_notworking - Entry timeout[%d]\n", timeout);
1075*4882a593Smuzhiyun
1076*4882a593Smuzhiyun while (!done) {
1077*4882a593Smuzhiyun *pstatus = ctrl_read(ctlr_ptr, wpg_bbar, WPG_CTLR_INDEX);
1078*4882a593Smuzhiyun if (*pstatus == HPC_ERROR) {
1079*4882a593Smuzhiyun rc = HPC_ERROR;
1080*4882a593Smuzhiyun done = 1;
1081*4882a593Smuzhiyun }
1082*4882a593Smuzhiyun if (CTLR_WORKING(*pstatus) == HPC_CTLR_WORKING_NO)
1083*4882a593Smuzhiyun done = 1;
1084*4882a593Smuzhiyun if (!done) {
1085*4882a593Smuzhiyun msleep(1000);
1086*4882a593Smuzhiyun if (timeout < 1) {
1087*4882a593Smuzhiyun done = 1;
1088*4882a593Smuzhiyun err("HPCreadslot - Error ctlr timeout\n");
1089*4882a593Smuzhiyun rc = HPC_ERROR;
1090*4882a593Smuzhiyun } else
1091*4882a593Smuzhiyun timeout--;
1092*4882a593Smuzhiyun }
1093*4882a593Smuzhiyun }
1094*4882a593Smuzhiyun debug_polling("hpc_wait_ctlr_notworking - Exit rc[%x] status[%x]\n", rc, *pstatus);
1095*4882a593Smuzhiyun return rc;
1096*4882a593Smuzhiyun }
1097