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