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