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> |
939fdc67 | 38 | #include <linux/semaphore.h> |
2d100fe8 | 39 | #include <linux/kthread.h> |
1da177e4 LT |
40 | #include "ibmphp.h" |
41 | ||
dc6712d1 | 42 | static int to_debug = 0; |
ff3ce480 | 43 | #define debug_polling(fmt, arg...) do { if (to_debug) debug(fmt, arg); } while (0) |
1da177e4 LT |
44 | |
45 | //---------------------------------------------------------------------------- | |
46 | // timeout values | |
47 | //---------------------------------------------------------------------------- | |
48 | #define CMD_COMPLETE_TOUT_SEC 60 // give HPC 60 sec to finish cmd | |
49 | #define HPC_CTLR_WORKING_TOUT 60 // give HPC 60 sec to finish cmd | |
50 | #define HPC_GETACCESS_TIMEOUT 60 // seconds | |
51 | #define POLL_INTERVAL_SEC 2 // poll HPC every 2 seconds | |
52 | #define POLL_LATCH_CNT 5 // poll latch 5 times, then poll slots | |
53 | ||
54 | //---------------------------------------------------------------------------- | |
55 | // Winnipeg Architected Register Offsets | |
56 | //---------------------------------------------------------------------------- | |
57 | #define WPG_I2CMBUFL_OFFSET 0x08 // I2C Message Buffer Low | |
58 | #define WPG_I2CMOSUP_OFFSET 0x10 // I2C Master Operation Setup Reg | |
59 | #define WPG_I2CMCNTL_OFFSET 0x20 // I2C Master Control Register | |
60 | #define WPG_I2CPARM_OFFSET 0x40 // I2C Parameter Register | |
61 | #define WPG_I2CSTAT_OFFSET 0x70 // I2C Status Register | |
62 | ||
63 | //---------------------------------------------------------------------------- | |
64 | // Winnipeg Store Type commands (Add this commands to the register offset) | |
65 | //---------------------------------------------------------------------------- | |
66 | #define WPG_I2C_AND 0x1000 // I2C AND operation | |
67 | #define WPG_I2C_OR 0x2000 // I2C OR operation | |
68 | ||
69 | //---------------------------------------------------------------------------- | |
eaae4b3a | 70 | // Command set for I2C Master Operation Setup Register |
1da177e4 LT |
71 | //---------------------------------------------------------------------------- |
72 | #define WPG_READATADDR_MASK 0x00010000 // read,bytes,I2C shifted,index | |
73 | #define WPG_WRITEATADDR_MASK 0x40010000 // write,bytes,I2C shifted,index | |
74 | #define WPG_READDIRECT_MASK 0x10010000 | |
75 | #define WPG_WRITEDIRECT_MASK 0x60010000 | |
76 | ||
77 | ||
78 | //---------------------------------------------------------------------------- | |
79 | // bit masks for I2C Master Control Register | |
80 | //---------------------------------------------------------------------------- | |
81 | #define WPG_I2CMCNTL_STARTOP_MASK 0x00000002 // Start the Operation | |
82 | ||
83 | //---------------------------------------------------------------------------- | |
84 | // | |
85 | //---------------------------------------------------------------------------- | |
86 | #define WPG_I2C_IOREMAP_SIZE 0x2044 // size of linear address interval | |
87 | ||
88 | //---------------------------------------------------------------------------- | |
89 | // command index | |
90 | //---------------------------------------------------------------------------- | |
91 | #define WPG_1ST_SLOT_INDEX 0x01 // index - 1st slot for ctlr | |
92 | #define WPG_CTLR_INDEX 0x0F // index - ctlr | |
93 | #define WPG_1ST_EXTSLOT_INDEX 0x10 // index - 1st ext slot for ctlr | |
94 | #define WPG_1ST_BUS_INDEX 0x1F // index - 1st bus for ctlr | |
95 | ||
96 | //---------------------------------------------------------------------------- | |
97 | // macro utilities | |
98 | //---------------------------------------------------------------------------- | |
dc6712d1 KA |
99 | // if bits 20,22,25,26,27,29,30 are OFF return 1 |
100 | #define HPC_I2CSTATUS_CHECK(s) ((u8)((s & 0x00000A76) ? 0 : 1)) | |
1da177e4 LT |
101 | |
102 | //---------------------------------------------------------------------------- | |
103 | // global variables | |
104 | //---------------------------------------------------------------------------- | |
6aa4cdd0 | 105 | static struct mutex sem_hpcaccess; // lock access to HPC |
1da177e4 LT |
106 | static struct semaphore semOperations; // lock all operations and |
107 | // access to data structures | |
108 | static struct semaphore sem_exit; // make sure polling thread goes away | |
2d100fe8 | 109 | static struct task_struct *ibmphp_poll_thread; |
1da177e4 LT |
110 | //---------------------------------------------------------------------------- |
111 | // local function prototypes | |
112 | //---------------------------------------------------------------------------- | |
ff3ce480 BS |
113 | static u8 i2c_ctrl_read(struct controller *, void __iomem *, u8); |
114 | static u8 i2c_ctrl_write(struct controller *, void __iomem *, u8, u8); | |
115 | static u8 hpc_writecmdtoindex(u8, u8); | |
116 | static u8 hpc_readcmdtoindex(u8, u8); | |
117 | static void get_hpc_access(void); | |
118 | static void free_hpc_access(void); | |
2d100fe8 | 119 | static int poll_hpc(void *data); |
ff3ce480 BS |
120 | static int process_changeinstatus(struct slot *, struct slot *); |
121 | static int process_changeinlatch(u8, u8, struct controller *); | |
122 | static int hpc_wait_ctlr_notworking(int, struct controller *, void __iomem *, u8 *); | |
1da177e4 LT |
123 | //---------------------------------------------------------------------------- |
124 | ||
125 | ||
126 | /*---------------------------------------------------------------------- | |
127 | * Name: ibmphp_hpc_initvars | |
128 | * | |
129 | * Action: initialize semaphores and variables | |
130 | *---------------------------------------------------------------------*/ | |
ff3ce480 | 131 | void __init ibmphp_hpc_initvars(void) |
1da177e4 | 132 | { |
ff3ce480 | 133 | debug("%s - Entry\n", __func__); |
1da177e4 | 134 | |
6aa4cdd0 | 135 | mutex_init(&sem_hpcaccess); |
5a37f138 TG |
136 | sema_init(&semOperations, 1); |
137 | sema_init(&sem_exit, 0); | |
dc6712d1 | 138 | to_debug = 0; |
1da177e4 | 139 | |
ff3ce480 | 140 | debug("%s - Exit\n", __func__); |
1da177e4 LT |
141 | } |
142 | ||
143 | /*---------------------------------------------------------------------- | |
144 | * Name: i2c_ctrl_read | |
145 | * | |
146 | * Action: read from HPC over I2C | |
147 | * | |
148 | *---------------------------------------------------------------------*/ | |
ff3ce480 | 149 | static u8 i2c_ctrl_read(struct controller *ctlr_ptr, void __iomem *WPGBbar, u8 index) |
1da177e4 LT |
150 | { |
151 | u8 status; | |
152 | int i; | |
153 | void __iomem *wpg_addr; // base addr + offset | |
154 | unsigned long wpg_data; // data to/from WPG LOHI format | |
155 | unsigned long ultemp; | |
156 | unsigned long data; // actual data HILO format | |
157 | ||
ff3ce480 | 158 | debug_polling("%s - Entry WPGBbar[%p] index[%x] \n", __func__, WPGBbar, index); |
1da177e4 LT |
159 | |
160 | //-------------------------------------------------------------------- | |
161 | // READ - step 1 | |
162 | // read at address, byte length, I2C address (shifted), index | |
163 | // or read direct, byte length, index | |
164 | if (ctlr_ptr->ctlr_type == 0x02) { | |
165 | data = WPG_READATADDR_MASK; | |
166 | // fill in I2C address | |
167 | ultemp = (unsigned long)ctlr_ptr->u.wpeg_ctlr.i2c_addr; | |
168 | ultemp = ultemp >> 1; | |
169 | data |= (ultemp << 8); | |
170 | ||
171 | // fill in index | |
172 | data |= (unsigned long)index; | |
173 | } else if (ctlr_ptr->ctlr_type == 0x04) { | |
174 | data = WPG_READDIRECT_MASK; | |
175 | ||
176 | // fill in index | |
177 | ultemp = (unsigned long)index; | |
178 | ultemp = ultemp << 8; | |
179 | data |= ultemp; | |
180 | } else { | |
ff3ce480 | 181 | err("this controller type is not supported \n"); |
1da177e4 LT |
182 | return HPC_ERROR; |
183 | } | |
184 | ||
ff3ce480 | 185 | wpg_data = swab32(data); // swap data before writing |
1da177e4 | 186 | wpg_addr = WPGBbar + WPG_I2CMOSUP_OFFSET; |
ff3ce480 | 187 | writel(wpg_data, wpg_addr); |
1da177e4 LT |
188 | |
189 | //-------------------------------------------------------------------- | |
190 | // READ - step 2 : clear the message buffer | |
191 | data = 0x00000000; | |
ff3ce480 | 192 | wpg_data = swab32(data); |
1da177e4 | 193 | wpg_addr = WPGBbar + WPG_I2CMBUFL_OFFSET; |
ff3ce480 | 194 | writel(wpg_data, wpg_addr); |
1da177e4 LT |
195 | |
196 | //-------------------------------------------------------------------- | |
197 | // READ - step 3 : issue start operation, I2C master control bit 30:ON | |
198 | // 2020 : [20] OR operation at [20] offset 0x20 | |
199 | data = WPG_I2CMCNTL_STARTOP_MASK; | |
ff3ce480 | 200 | wpg_data = swab32(data); |
1da177e4 | 201 | wpg_addr = WPGBbar + WPG_I2CMCNTL_OFFSET + WPG_I2C_OR; |
ff3ce480 | 202 | writel(wpg_data, wpg_addr); |
1da177e4 LT |
203 | |
204 | //-------------------------------------------------------------------- | |
205 | // READ - step 4 : wait until start operation bit clears | |
206 | i = CMD_COMPLETE_TOUT_SEC; | |
207 | while (i) { | |
208 | msleep(10); | |
209 | wpg_addr = WPGBbar + WPG_I2CMCNTL_OFFSET; | |
ff3ce480 BS |
210 | wpg_data = readl(wpg_addr); |
211 | data = swab32(wpg_data); | |
1da177e4 LT |
212 | if (!(data & WPG_I2CMCNTL_STARTOP_MASK)) |
213 | break; | |
214 | i--; | |
215 | } | |
216 | if (i == 0) { | |
ff3ce480 | 217 | debug("%s - Error : WPG timeout\n", __func__); |
1da177e4 LT |
218 | return HPC_ERROR; |
219 | } | |
220 | //-------------------------------------------------------------------- | |
221 | // READ - step 5 : read I2C status register | |
222 | i = CMD_COMPLETE_TOUT_SEC; | |
223 | while (i) { | |
224 | msleep(10); | |
225 | wpg_addr = WPGBbar + WPG_I2CSTAT_OFFSET; | |
ff3ce480 BS |
226 | wpg_data = readl(wpg_addr); |
227 | data = swab32(wpg_data); | |
228 | if (HPC_I2CSTATUS_CHECK(data)) | |
1da177e4 LT |
229 | break; |
230 | i--; | |
231 | } | |
232 | if (i == 0) { | |
ff3ce480 | 233 | debug("ctrl_read - Exit Error:I2C timeout\n"); |
1da177e4 LT |
234 | return HPC_ERROR; |
235 | } | |
236 | ||
237 | //-------------------------------------------------------------------- | |
238 | // READ - step 6 : get DATA | |
239 | wpg_addr = WPGBbar + WPG_I2CMBUFL_OFFSET; | |
ff3ce480 BS |
240 | wpg_data = readl(wpg_addr); |
241 | data = swab32(wpg_data); | |
1da177e4 LT |
242 | |
243 | status = (u8) data; | |
244 | ||
ff3ce480 | 245 | debug_polling("%s - Exit index[%x] status[%x]\n", __func__, index, status); |
1da177e4 LT |
246 | |
247 | return (status); | |
248 | } | |
249 | ||
250 | /*---------------------------------------------------------------------- | |
251 | * Name: i2c_ctrl_write | |
252 | * | |
253 | * Action: write to HPC over I2C | |
254 | * | |
255 | * Return 0 or error codes | |
256 | *---------------------------------------------------------------------*/ | |
ff3ce480 | 257 | static u8 i2c_ctrl_write(struct controller *ctlr_ptr, void __iomem *WPGBbar, u8 index, u8 cmd) |
1da177e4 LT |
258 | { |
259 | u8 rc; | |
260 | void __iomem *wpg_addr; // base addr + offset | |
f7625980 | 261 | unsigned long wpg_data; // data to/from WPG LOHI format |
1da177e4 LT |
262 | unsigned long ultemp; |
263 | unsigned long data; // actual data HILO format | |
264 | int i; | |
265 | ||
ff3ce480 | 266 | debug_polling("%s - Entry WPGBbar[%p] index[%x] cmd[%x]\n", __func__, WPGBbar, index, cmd); |
1da177e4 LT |
267 | |
268 | rc = 0; | |
269 | //-------------------------------------------------------------------- | |
270 | // WRITE - step 1 | |
271 | // write at address, byte length, I2C address (shifted), index | |
272 | // or write direct, byte length, index | |
273 | data = 0x00000000; | |
274 | ||
275 | if (ctlr_ptr->ctlr_type == 0x02) { | |
276 | data = WPG_WRITEATADDR_MASK; | |
277 | // fill in I2C address | |
278 | ultemp = (unsigned long)ctlr_ptr->u.wpeg_ctlr.i2c_addr; | |
279 | ultemp = ultemp >> 1; | |
280 | data |= (ultemp << 8); | |
281 | ||
282 | // fill in index | |
283 | data |= (unsigned long)index; | |
284 | } else if (ctlr_ptr->ctlr_type == 0x04) { | |
285 | data = WPG_WRITEDIRECT_MASK; | |
286 | ||
287 | // fill in index | |
288 | ultemp = (unsigned long)index; | |
289 | ultemp = ultemp << 8; | |
290 | data |= ultemp; | |
291 | } else { | |
ff3ce480 | 292 | err("this controller type is not supported \n"); |
1da177e4 LT |
293 | return HPC_ERROR; |
294 | } | |
295 | ||
ff3ce480 | 296 | wpg_data = swab32(data); // swap data before writing |
1da177e4 | 297 | wpg_addr = WPGBbar + WPG_I2CMOSUP_OFFSET; |
ff3ce480 | 298 | writel(wpg_data, wpg_addr); |
1da177e4 LT |
299 | |
300 | //-------------------------------------------------------------------- | |
301 | // WRITE - step 2 : clear the message buffer | |
302 | data = 0x00000000 | (unsigned long)cmd; | |
ff3ce480 | 303 | wpg_data = swab32(data); |
1da177e4 | 304 | wpg_addr = WPGBbar + WPG_I2CMBUFL_OFFSET; |
ff3ce480 | 305 | writel(wpg_data, wpg_addr); |
1da177e4 LT |
306 | |
307 | //-------------------------------------------------------------------- | |
308 | // WRITE - step 3 : issue start operation,I2C master control bit 30:ON | |
309 | // 2020 : [20] OR operation at [20] offset 0x20 | |
310 | data = WPG_I2CMCNTL_STARTOP_MASK; | |
ff3ce480 | 311 | wpg_data = swab32(data); |
1da177e4 | 312 | wpg_addr = WPGBbar + WPG_I2CMCNTL_OFFSET + WPG_I2C_OR; |
ff3ce480 | 313 | writel(wpg_data, wpg_addr); |
1da177e4 LT |
314 | |
315 | //-------------------------------------------------------------------- | |
316 | // WRITE - step 4 : wait until start operation bit clears | |
317 | i = CMD_COMPLETE_TOUT_SEC; | |
318 | while (i) { | |
319 | msleep(10); | |
320 | wpg_addr = WPGBbar + WPG_I2CMCNTL_OFFSET; | |
ff3ce480 BS |
321 | wpg_data = readl(wpg_addr); |
322 | data = swab32(wpg_data); | |
1da177e4 LT |
323 | if (!(data & WPG_I2CMCNTL_STARTOP_MASK)) |
324 | break; | |
325 | i--; | |
326 | } | |
327 | if (i == 0) { | |
ff3ce480 | 328 | debug("%s - Exit Error:WPG timeout\n", __func__); |
1da177e4 LT |
329 | rc = HPC_ERROR; |
330 | } | |
331 | ||
332 | //-------------------------------------------------------------------- | |
333 | // WRITE - step 5 : read I2C status register | |
334 | i = CMD_COMPLETE_TOUT_SEC; | |
335 | while (i) { | |
336 | msleep(10); | |
337 | wpg_addr = WPGBbar + WPG_I2CSTAT_OFFSET; | |
ff3ce480 BS |
338 | wpg_data = readl(wpg_addr); |
339 | data = swab32(wpg_data); | |
340 | if (HPC_I2CSTATUS_CHECK(data)) | |
1da177e4 LT |
341 | break; |
342 | i--; | |
343 | } | |
344 | if (i == 0) { | |
ff3ce480 | 345 | debug("ctrl_read - Error : I2C timeout\n"); |
1da177e4 LT |
346 | rc = HPC_ERROR; |
347 | } | |
348 | ||
ff3ce480 | 349 | debug_polling("%s Exit rc[%x]\n", __func__, rc); |
1da177e4 LT |
350 | return (rc); |
351 | } | |
352 | ||
353 | //------------------------------------------------------------ | |
f7625980 | 354 | // Read from ISA type HPC |
1da177e4 | 355 | //------------------------------------------------------------ |
ff3ce480 | 356 | static u8 isa_ctrl_read(struct controller *ctlr_ptr, u8 offset) |
1da177e4 LT |
357 | { |
358 | u16 start_address; | |
359 | u16 end_address; | |
360 | u8 data; | |
361 | ||
362 | start_address = ctlr_ptr->u.isa_ctlr.io_start; | |
363 | end_address = ctlr_ptr->u.isa_ctlr.io_end; | |
ff3ce480 | 364 | data = inb(start_address + offset); |
1da177e4 LT |
365 | return data; |
366 | } | |
367 | ||
368 | //-------------------------------------------------------------- | |
369 | // Write to ISA type HPC | |
370 | //-------------------------------------------------------------- | |
ff3ce480 | 371 | static void isa_ctrl_write(struct controller *ctlr_ptr, u8 offset, u8 data) |
1da177e4 LT |
372 | { |
373 | u16 start_address; | |
374 | u16 port_address; | |
f7625980 | 375 | |
1da177e4 LT |
376 | start_address = ctlr_ptr->u.isa_ctlr.io_start; |
377 | port_address = start_address + (u16) offset; | |
ff3ce480 | 378 | outb(data, port_address); |
1da177e4 LT |
379 | } |
380 | ||
ff3ce480 | 381 | static u8 pci_ctrl_read(struct controller *ctrl, u8 offset) |
1da177e4 LT |
382 | { |
383 | u8 data = 0x00; | |
ff3ce480 | 384 | debug("inside pci_ctrl_read\n"); |
1da177e4 | 385 | if (ctrl->ctrl_dev) |
ff3ce480 | 386 | pci_read_config_byte(ctrl->ctrl_dev, HPC_PCI_OFFSET + offset, &data); |
1da177e4 LT |
387 | return data; |
388 | } | |
389 | ||
ff3ce480 | 390 | static u8 pci_ctrl_write(struct controller *ctrl, u8 offset, u8 data) |
1da177e4 LT |
391 | { |
392 | u8 rc = -ENODEV; | |
ff3ce480 | 393 | debug("inside pci_ctrl_write\n"); |
1da177e4 | 394 | if (ctrl->ctrl_dev) { |
ff3ce480 | 395 | pci_write_config_byte(ctrl->ctrl_dev, HPC_PCI_OFFSET + offset, data); |
1da177e4 LT |
396 | rc = 0; |
397 | } | |
398 | return rc; | |
399 | } | |
400 | ||
ff3ce480 | 401 | static u8 ctrl_read(struct controller *ctlr, void __iomem *base, u8 offset) |
1da177e4 LT |
402 | { |
403 | u8 rc; | |
404 | switch (ctlr->ctlr_type) { | |
405 | case 0: | |
ff3ce480 | 406 | rc = isa_ctrl_read(ctlr, offset); |
1da177e4 LT |
407 | break; |
408 | case 1: | |
ff3ce480 | 409 | rc = pci_ctrl_read(ctlr, offset); |
1da177e4 LT |
410 | break; |
411 | case 2: | |
412 | case 4: | |
ff3ce480 | 413 | rc = i2c_ctrl_read(ctlr, base, offset); |
1da177e4 LT |
414 | break; |
415 | default: | |
416 | return -ENODEV; | |
417 | } | |
418 | return rc; | |
419 | } | |
420 | ||
ff3ce480 | 421 | static u8 ctrl_write(struct controller *ctlr, void __iomem *base, u8 offset, u8 data) |
1da177e4 LT |
422 | { |
423 | u8 rc = 0; | |
424 | switch (ctlr->ctlr_type) { | |
425 | case 0: | |
426 | isa_ctrl_write(ctlr, offset, data); | |
427 | break; | |
428 | case 1: | |
ff3ce480 | 429 | rc = pci_ctrl_write(ctlr, offset, data); |
1da177e4 LT |
430 | break; |
431 | case 2: | |
432 | case 4: | |
433 | rc = i2c_ctrl_write(ctlr, base, offset, data); | |
434 | break; | |
435 | default: | |
436 | return -ENODEV; | |
437 | } | |
438 | return rc; | |
439 | } | |
440 | /*---------------------------------------------------------------------- | |
441 | * Name: hpc_writecmdtoindex() | |
442 | * | |
443 | * Action: convert a write command to proper index within a controller | |
444 | * | |
445 | * Return index, HPC_ERROR | |
446 | *---------------------------------------------------------------------*/ | |
ff3ce480 | 447 | static u8 hpc_writecmdtoindex(u8 cmd, u8 index) |
1da177e4 LT |
448 | { |
449 | u8 rc; | |
450 | ||
451 | switch (cmd) { | |
452 | case HPC_CTLR_ENABLEIRQ: // 0x00.N.15 | |
453 | case HPC_CTLR_CLEARIRQ: // 0x06.N.15 | |
454 | case HPC_CTLR_RESET: // 0x07.N.15 | |
455 | case HPC_CTLR_IRQSTEER: // 0x08.N.15 | |
456 | case HPC_CTLR_DISABLEIRQ: // 0x01.N.15 | |
457 | case HPC_ALLSLOT_ON: // 0x11.N.15 | |
458 | case HPC_ALLSLOT_OFF: // 0x12.N.15 | |
459 | rc = 0x0F; | |
460 | break; | |
461 | ||
462 | case HPC_SLOT_OFF: // 0x02.Y.0-14 | |
463 | case HPC_SLOT_ON: // 0x03.Y.0-14 | |
464 | case HPC_SLOT_ATTNOFF: // 0x04.N.0-14 | |
465 | case HPC_SLOT_ATTNON: // 0x05.N.0-14 | |
466 | case HPC_SLOT_BLINKLED: // 0x13.N.0-14 | |
467 | rc = index; | |
468 | break; | |
469 | ||
470 | case HPC_BUS_33CONVMODE: | |
471 | case HPC_BUS_66CONVMODE: | |
472 | case HPC_BUS_66PCIXMODE: | |
473 | case HPC_BUS_100PCIXMODE: | |
474 | case HPC_BUS_133PCIXMODE: | |
475 | rc = index + WPG_1ST_BUS_INDEX - 1; | |
476 | break; | |
477 | ||
478 | default: | |
ff3ce480 | 479 | err("hpc_writecmdtoindex - Error invalid cmd[%x]\n", cmd); |
1da177e4 LT |
480 | rc = HPC_ERROR; |
481 | } | |
482 | ||
483 | return rc; | |
484 | } | |
485 | ||
486 | /*---------------------------------------------------------------------- | |
487 | * Name: hpc_readcmdtoindex() | |
488 | * | |
489 | * Action: convert a read command to proper index within a controller | |
490 | * | |
491 | * Return index, HPC_ERROR | |
492 | *---------------------------------------------------------------------*/ | |
ff3ce480 | 493 | static u8 hpc_readcmdtoindex(u8 cmd, u8 index) |
1da177e4 LT |
494 | { |
495 | u8 rc; | |
496 | ||
497 | switch (cmd) { | |
498 | case READ_CTLRSTATUS: | |
499 | rc = 0x0F; | |
500 | break; | |
501 | case READ_SLOTSTATUS: | |
502 | case READ_ALLSTAT: | |
503 | rc = index; | |
504 | break; | |
505 | case READ_EXTSLOTSTATUS: | |
506 | rc = index + WPG_1ST_EXTSLOT_INDEX; | |
507 | break; | |
508 | case READ_BUSSTATUS: | |
509 | rc = index + WPG_1ST_BUS_INDEX - 1; | |
510 | break; | |
511 | case READ_SLOTLATCHLOWREG: | |
512 | rc = 0x28; | |
513 | break; | |
514 | case READ_REVLEVEL: | |
515 | rc = 0x25; | |
516 | break; | |
517 | case READ_HPCOPTIONS: | |
518 | rc = 0x27; | |
519 | break; | |
520 | default: | |
521 | rc = HPC_ERROR; | |
522 | } | |
523 | return rc; | |
524 | } | |
525 | ||
526 | /*---------------------------------------------------------------------- | |
527 | * Name: HPCreadslot() | |
528 | * | |
529 | * Action: issue a READ command to HPC | |
530 | * | |
0779bf2d | 531 | * Input: pslot - cannot be NULL for READ_ALLSTAT |
1da177e4 LT |
532 | * pstatus - can be NULL for READ_ALLSTAT |
533 | * | |
534 | * Return 0 or error codes | |
535 | *---------------------------------------------------------------------*/ | |
ff3ce480 | 536 | int ibmphp_hpc_readslot(struct slot *pslot, u8 cmd, u8 *pstatus) |
1da177e4 LT |
537 | { |
538 | void __iomem *wpg_bbar = NULL; | |
539 | struct controller *ctlr_ptr; | |
1da177e4 LT |
540 | u8 index, status; |
541 | int rc = 0; | |
542 | int busindex; | |
543 | ||
ff3ce480 | 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; | |
ff3ce480 | 549 | err("%s - Error invalid pointer, rc[%d]\n", __func__, rc); |
1da177e4 LT |
550 | return rc; |
551 | } | |
552 | ||
553 | if (cmd == READ_BUSSTATUS) { | |
ff3ce480 | 554 | busindex = ibmphp_get_bus_index(pslot->bus); |
1da177e4 LT |
555 | if (busindex < 0) { |
556 | rc = -EINVAL; | |
ff3ce480 | 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 | ||
ff3ce480 | 564 | index = hpc_readcmdtoindex(cmd, index); |
1da177e4 LT |
565 | |
566 | if (index == HPC_ERROR) { | |
567 | rc = -EINVAL; | |
ff3ce480 | 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 | ||
ff3ce480 | 574 | get_hpc_access(); |
1da177e4 LT |
575 | |
576 | //-------------------------------------------------------------------- | |
577 | // map physical address to logical address | |
578 | //-------------------------------------------------------------------- | |
579 | if ((ctlr_ptr->ctlr_type == 2) || (ctlr_ptr->ctlr_type == 4)) | |
ff3ce480 | 580 | wpg_bbar = ioremap(ctlr_ptr->u.wpeg_ctlr.wpegbbar, WPG_I2C_IOREMAP_SIZE); |
1da177e4 LT |
581 | |
582 | //-------------------------------------------------------------------- | |
583 | // check controller status before reading | |
584 | //-------------------------------------------------------------------- | |
ff3ce480 | 585 | rc = hpc_wait_ctlr_notworking(HPC_CTLR_WORKING_TOUT, ctlr_ptr, wpg_bbar, &status); |
1da177e4 LT |
586 | if (!rc) { |
587 | switch (cmd) { | |
588 | case READ_ALLSTAT: | |
589 | // update the slot structure | |
590 | pslot->ctrl->status = status; | |
ff3ce480 BS |
591 | pslot->status = ctrl_read(ctlr_ptr, wpg_bbar, index); |
592 | rc = hpc_wait_ctlr_notworking(HPC_CTLR_WORKING_TOUT, ctlr_ptr, wpg_bbar, | |
1da177e4 LT |
593 | &status); |
594 | if (!rc) | |
ff3ce480 | 595 | pslot->ext_status = ctrl_read(ctlr_ptr, wpg_bbar, index + WPG_1ST_EXTSLOT_INDEX); |
1da177e4 LT |
596 | |
597 | break; | |
598 | ||
599 | case READ_SLOTSTATUS: | |
600 | // DO NOT update the slot structure | |
ff3ce480 | 601 | *pstatus = ctrl_read(ctlr_ptr, wpg_bbar, index); |
1da177e4 LT |
602 | break; |
603 | ||
604 | case READ_EXTSLOTSTATUS: | |
605 | // DO NOT update the slot structure | |
ff3ce480 | 606 | *pstatus = ctrl_read(ctlr_ptr, wpg_bbar, index); |
1da177e4 LT |
607 | break; |
608 | ||
609 | case READ_CTLRSTATUS: | |
610 | // DO NOT update the slot structure | |
611 | *pstatus = status; | |
612 | break; | |
613 | ||
614 | case READ_BUSSTATUS: | |
ff3ce480 | 615 | pslot->busstatus = ctrl_read(ctlr_ptr, wpg_bbar, index); |
1da177e4 LT |
616 | break; |
617 | case READ_REVLEVEL: | |
ff3ce480 | 618 | *pstatus = ctrl_read(ctlr_ptr, wpg_bbar, index); |
1da177e4 LT |
619 | break; |
620 | case READ_HPCOPTIONS: | |
ff3ce480 | 621 | *pstatus = ctrl_read(ctlr_ptr, wpg_bbar, index); |
1da177e4 LT |
622 | break; |
623 | case READ_SLOTLATCHLOWREG: | |
624 | // DO NOT update the slot structure | |
ff3ce480 | 625 | *pstatus = ctrl_read(ctlr_ptr, wpg_bbar, index); |
1da177e4 LT |
626 | break; |
627 | ||
628 | // Not used | |
629 | case READ_ALLSLOT: | |
2ac83ccc GT |
630 | list_for_each_entry(pslot, &ibmphp_slot_head, |
631 | ibm_slot_list) { | |
1da177e4 | 632 | index = pslot->ctlr_index; |
ff3ce480 | 633 | rc = hpc_wait_ctlr_notworking(HPC_CTLR_WORKING_TOUT, ctlr_ptr, |
1da177e4 LT |
634 | wpg_bbar, &status); |
635 | if (!rc) { | |
ff3ce480 BS |
636 | pslot->status = ctrl_read(ctlr_ptr, wpg_bbar, index); |
637 | rc = hpc_wait_ctlr_notworking(HPC_CTLR_WORKING_TOUT, | |
1da177e4 LT |
638 | ctlr_ptr, wpg_bbar, &status); |
639 | if (!rc) | |
640 | pslot->ext_status = | |
ff3ce480 | 641 | ctrl_read(ctlr_ptr, wpg_bbar, |
1da177e4 LT |
642 | index + WPG_1ST_EXTSLOT_INDEX); |
643 | } else { | |
ff3ce480 | 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 | //-------------------------------------------------------------------- | |
f7625980 | 658 | |
1da177e4 LT |
659 | // remove physical to logical address mapping |
660 | if ((ctlr_ptr->ctlr_type == 2) || (ctlr_ptr->ctlr_type == 4)) | |
ff3ce480 | 661 | iounmap(wpg_bbar); |
f7625980 | 662 | |
ff3ce480 | 663 | free_hpc_access(); |
1da177e4 | 664 | |
ff3ce480 | 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 | *---------------------------------------------------------------------*/ | |
ff3ce480 | 674 | int ibmphp_hpc_writeslot(struct slot *pslot, u8 cmd) |
1da177e4 LT |
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 | ||
ff3ce480 | 684 | debug_polling("%s - Entry pslot[%p] cmd[%x]\n", __func__, pslot, cmd); |
1da177e4 LT |
685 | if (pslot == NULL) { |
686 | rc = -EINVAL; | |
ff3ce480 | 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)) { | |
ff3ce480 | 694 | busindex = ibmphp_get_bus_index(pslot->bus); |
1da177e4 LT |
695 | if (busindex < 0) { |
696 | rc = -EINVAL; | |
ff3ce480 | 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 | ||
ff3ce480 | 704 | index = hpc_writecmdtoindex(cmd, index); |
1da177e4 LT |
705 | |
706 | if (index == HPC_ERROR) { | |
707 | rc = -EINVAL; | |
ff3ce480 | 708 | err("%s - Error Exit rc[%d]\n", __func__, rc); |
1da177e4 LT |
709 | return rc; |
710 | } | |
711 | ||
712 | ctlr_ptr = pslot->ctrl; | |
713 | ||
ff3ce480 | 714 | get_hpc_access(); |
1da177e4 LT |
715 | |
716 | //-------------------------------------------------------------------- | |
717 | // map physical address to logical address | |
718 | //-------------------------------------------------------------------- | |
719 | if ((ctlr_ptr->ctlr_type == 2) || (ctlr_ptr->ctlr_type == 4)) { | |
ff3ce480 | 720 | wpg_bbar = ioremap(ctlr_ptr->u.wpeg_ctlr.wpegbbar, WPG_I2C_IOREMAP_SIZE); |
1da177e4 | 721 | |
ff3ce480 | 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 | //-------------------------------------------------------------------- | |
ff3ce480 | 729 | rc = hpc_wait_ctlr_notworking(HPC_CTLR_WORKING_TOUT, ctlr_ptr, wpg_bbar, &status); |
1da177e4 LT |
730 | if (!rc) { |
731 | ||
ff3ce480 | 732 | ctrl_write(ctlr_ptr, wpg_bbar, index, cmd); |
1da177e4 LT |
733 | |
734 | //-------------------------------------------------------------------- | |
735 | // check controller is still not working on the command | |
736 | //-------------------------------------------------------------------- | |
737 | timeout = CMD_COMPLETE_TOUT_SEC; | |
dc6712d1 | 738 | done = 0; |
1da177e4 | 739 | while (!done) { |
ff3ce480 | 740 | rc = hpc_wait_ctlr_notworking(HPC_CTLR_WORKING_TOUT, ctlr_ptr, wpg_bbar, |
1da177e4 LT |
741 | &status); |
742 | if (!rc) { | |
ff3ce480 BS |
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; |
ff3ce480 | 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)) | |
ff3ce480 BS |
765 | iounmap(wpg_bbar); |
766 | free_hpc_access(); | |
1da177e4 | 767 | |
ff3ce480 | 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 | *---------------------------------------------------------------------*/ | |
ff3ce480 | 777 | static void get_hpc_access(void) |
1da177e4 | 778 | { |
6aa4cdd0 | 779 | mutex_lock(&sem_hpcaccess); |
1da177e4 LT |
780 | } |
781 | ||
782 | /*---------------------------------------------------------------------- | |
783 | * Name: free_hpc_access() | |
784 | *---------------------------------------------------------------------*/ | |
ff3ce480 | 785 | void free_hpc_access(void) |
1da177e4 | 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 | *---------------------------------------------------------------------*/ | |
ff3ce480 | 795 | void ibmphp_lock_operations(void) |
1da177e4 | 796 | { |
ff3ce480 | 797 | down(&semOperations); |
dc6712d1 | 798 | to_debug = 1; |
1da177e4 LT |
799 | } |
800 | ||
801 | /*---------------------------------------------------------------------- | |
802 | * Name: ibmphp_unlock_operations() | |
803 | *---------------------------------------------------------------------*/ | |
ff3ce480 | 804 | void ibmphp_unlock_operations(void) |
1da177e4 | 805 | { |
ff3ce480 BS |
806 | debug("%s - Entry\n", __func__); |
807 | up(&semOperations); | |
dc6712d1 | 808 | to_debug = 0; |
ff3ce480 | 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; | |
1da177e4 LT |
822 | int rc; |
823 | int poll_state = POLL_LATCH_REGISTER; | |
824 | u8 oldlatchlow = 0x00; | |
825 | u8 curlatchlow = 0x00; | |
826 | int poll_count = 0; | |
827 | u8 ctrl_count = 0x00; | |
828 | ||
ff3ce480 | 829 | debug("%s - Entry\n", __func__); |
1da177e4 | 830 | |
2d100fe8 | 831 | while (!kthread_should_stop()) { |
eaae4b3a | 832 | /* try to get the lock to do some kind of hardware access */ |
ff3ce480 | 833 | down(&semOperations); |
1da177e4 LT |
834 | |
835 | switch (poll_state) { | |
f7625980 | 836 | case POLL_LATCH_REGISTER: |
1da177e4 LT |
837 | oldlatchlow = curlatchlow; |
838 | ctrl_count = 0x00; | |
2ac83ccc GT |
839 | list_for_each_entry(pslot, &ibmphp_slot_head, |
840 | ibm_slot_list) { | |
1da177e4 LT |
841 | if (ctrl_count >= ibmphp_get_total_controllers()) |
842 | break; | |
1da177e4 LT |
843 | if (pslot->ctrl->ctlr_relative_id == ctrl_count) { |
844 | ctrl_count++; | |
ff3ce480 BS |
845 | if (READ_SLOT_LATCH(pslot->ctrl)) { |
846 | rc = ibmphp_hpc_readslot(pslot, | |
1da177e4 LT |
847 | READ_SLOTLATCHLOWREG, |
848 | &curlatchlow); | |
849 | if (oldlatchlow != curlatchlow) | |
ff3ce480 | 850 | process_changeinlatch(oldlatchlow, |
1da177e4 LT |
851 | curlatchlow, |
852 | pslot->ctrl); | |
853 | } | |
854 | } | |
855 | } | |
856 | ++poll_count; | |
857 | poll_state = POLL_SLEEP; | |
858 | break; | |
859 | case POLL_SLOTS: | |
2ac83ccc GT |
860 | list_for_each_entry(pslot, &ibmphp_slot_head, |
861 | ibm_slot_list) { | |
1da177e4 | 862 | // make a copy of the old status |
ff3ce480 BS |
863 | memcpy((void *) &myslot, (void *) pslot, |
864 | sizeof(struct slot)); | |
865 | rc = ibmphp_hpc_readslot(pslot, READ_ALLSTAT, NULL); | |
1da177e4 LT |
866 | if ((myslot.status != pslot->status) |
867 | || (myslot.ext_status != pslot->ext_status)) | |
ff3ce480 | 868 | process_changeinstatus(pslot, &myslot); |
1da177e4 LT |
869 | } |
870 | ctrl_count = 0x00; | |
2ac83ccc GT |
871 | list_for_each_entry(pslot, &ibmphp_slot_head, |
872 | ibm_slot_list) { | |
1da177e4 LT |
873 | if (ctrl_count >= ibmphp_get_total_controllers()) |
874 | break; | |
1da177e4 LT |
875 | if (pslot->ctrl->ctlr_relative_id == ctrl_count) { |
876 | ctrl_count++; | |
ff3ce480 BS |
877 | if (READ_SLOT_LATCH(pslot->ctrl)) |
878 | rc = ibmphp_hpc_readslot(pslot, | |
1da177e4 LT |
879 | READ_SLOTLATCHLOWREG, |
880 | &curlatchlow); | |
881 | } | |
882 | } | |
883 | ++poll_count; | |
884 | poll_state = POLL_SLEEP; | |
885 | break; | |
886 | case POLL_SLEEP: | |
887 | /* don't sleep with a lock on the hardware */ | |
ff3ce480 | 888 | up(&semOperations); |
1da177e4 LT |
889 | msleep(POLL_INTERVAL_SEC * 1000); |
890 | ||
2d100fe8 | 891 | if (kthread_should_stop()) |
5c788a69 | 892 | goto out_sleep; |
f7625980 | 893 | |
ff3ce480 | 894 | down(&semOperations); |
f7625980 | 895 | |
1da177e4 LT |
896 | if (poll_count >= POLL_LATCH_CNT) { |
897 | poll_count = 0; | |
898 | poll_state = POLL_SLOTS; | |
899 | } else | |
900 | poll_state = POLL_LATCH_REGISTER; | |
901 | break; | |
f7625980 | 902 | } |
eaae4b3a | 903 | /* give up the hardware semaphore */ |
ff3ce480 | 904 | up(&semOperations); |
1da177e4 | 905 | /* sleep for a short time just for good measure */ |
5c788a69 | 906 | out_sleep: |
1da177e4 LT |
907 | msleep(100); |
908 | } | |
ff3ce480 BS |
909 | up(&sem_exit); |
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 | *---------------------------------------------------------------------*/ | |
ff3ce480 | 930 | static int process_changeinstatus(struct slot *pslot, struct slot *poldslot) |
1da177e4 LT |
931 | { |
932 | u8 status; | |
933 | int rc = 0; | |
dc6712d1 KA |
934 | u8 disable = 0; |
935 | u8 update = 0; | |
1da177e4 | 936 | |
ff3ce480 | 937 | debug("process_changeinstatus - Entry pslot[%p], poldslot[%p]\n", pslot, poldslot); |
1da177e4 LT |
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 | |
ff3ce480 | 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) { | |
ff3ce480 | 970 | if (SLOT_PWRGD(pslot->status)) { |
1da177e4 LT |
971 | // power goes on and off after closing latch |
972 | // check again to make sure power is still ON | |
973 | msleep(1000); | |
ff3ce480 BS |
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 | } | |
f7625980 | 981 | // CLOSE -> OPEN |
ff3ce480 BS |
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) { | |
ff3ce480 | 993 | debug("process_changeinstatus - disable slot\n"); |
dc6712d1 | 994 | pslot->flag = 0; |
ff3ce480 | 995 | rc = ibmphp_do_disable_slot(pslot); |
1da177e4 LT |
996 | } |
997 | ||
656f978f | 998 | if (update || disable) |
ff3ce480 | 999 | ibmphp_update_slot_info(pslot); |
1da177e4 | 1000 | |
ff3ce480 | 1001 | debug("%s - Exit rc[%d] disable[%x] update[%x]\n", __func__, rc, disable, update); |
1da177e4 LT |
1002 | |
1003 | return rc; | |
1004 | } | |
1005 | ||
1006 | /*---------------------------------------------------------------------- | |
1007 | * Name: process_changeinlatch | |
1008 | * | |
1009 | * Action: compare old and new latch reg status, process the change | |
1010 | * | |
1011 | * Input: old and current latch register status | |
1012 | * | |
1013 | * Return 0 or error codes | |
1014 | * Value: | |
1015 | *---------------------------------------------------------------------*/ | |
ff3ce480 | 1016 | static int process_changeinlatch(u8 old, u8 new, struct controller *ctrl) |
1da177e4 LT |
1017 | { |
1018 | struct slot myslot, *pslot; | |
1019 | u8 i; | |
1020 | u8 mask; | |
1021 | int rc = 0; | |
1022 | ||
ff3ce480 | 1023 | debug("%s - Entry old[%x], new[%x]\n", __func__, old, new); |
1da177e4 LT |
1024 | // bit 0 reserved, 0 is LSB, check bit 1-6 for 6 slots |
1025 | ||
1026 | for (i = ctrl->starting_slot_num; i <= ctrl->ending_slot_num; i++) { | |
1027 | mask = 0x01 << i; | |
1028 | if ((mask & old) != (mask & new)) { | |
ff3ce480 | 1029 | pslot = ibmphp_get_slot_from_physical_num(i); |
1da177e4 | 1030 | if (pslot) { |
ff3ce480 BS |
1031 | memcpy((void *) &myslot, (void *) pslot, sizeof(struct slot)); |
1032 | rc = ibmphp_hpc_readslot(pslot, READ_ALLSTAT, NULL); | |
1033 | debug("%s - call process_changeinstatus for slot[%d]\n", __func__, i); | |
1034 | process_changeinstatus(pslot, &myslot); | |
1da177e4 LT |
1035 | } else { |
1036 | rc = -EINVAL; | |
ff3ce480 | 1037 | err("%s - Error bad pointer for slot[%d]\n", __func__, i); |
1da177e4 LT |
1038 | } |
1039 | } | |
1040 | } | |
ff3ce480 | 1041 | debug("%s - Exit rc[%d]\n", __func__, rc); |
1da177e4 LT |
1042 | return rc; |
1043 | } | |
1044 | ||
1da177e4 LT |
1045 | /*---------------------------------------------------------------------- |
1046 | * Name: ibmphp_hpc_start_poll_thread | |
1047 | * | |
1048 | * Action: start polling thread | |
1049 | *---------------------------------------------------------------------*/ | |
ff3ce480 | 1050 | int __init ibmphp_hpc_start_poll_thread(void) |
1da177e4 | 1051 | { |
ff3ce480 | 1052 | debug("%s - Entry\n", __func__); |
1da177e4 | 1053 | |
2d100fe8 KCA |
1054 | ibmphp_poll_thread = kthread_run(poll_hpc, NULL, "hpc_poll"); |
1055 | if (IS_ERR(ibmphp_poll_thread)) { | |
ff3ce480 | 1056 | err("%s - Error, thread not started\n", __func__); |
2d100fe8 | 1057 | return PTR_ERR(ibmphp_poll_thread); |
1da177e4 | 1058 | } |
2d100fe8 | 1059 | return 0; |
1da177e4 LT |
1060 | } |
1061 | ||
1062 | /*---------------------------------------------------------------------- | |
1063 | * Name: ibmphp_hpc_stop_poll_thread | |
1064 | * | |
1065 | * Action: stop polling thread and cleanup | |
1066 | *---------------------------------------------------------------------*/ | |
ff3ce480 | 1067 | void __exit ibmphp_hpc_stop_poll_thread(void) |
1da177e4 | 1068 | { |
ff3ce480 | 1069 | debug("%s - Entry\n", __func__); |
1da177e4 | 1070 | |
2d100fe8 | 1071 | kthread_stop(ibmphp_poll_thread); |
ff3ce480 BS |
1072 | debug("before locking operations\n"); |
1073 | ibmphp_lock_operations(); | |
1074 | debug("after locking operations\n"); | |
f7625980 | 1075 | |
1da177e4 | 1076 | // wait for poll thread to exit |
ff3ce480 BS |
1077 | debug("before sem_exit down\n"); |
1078 | down(&sem_exit); | |
1079 | debug("after sem_exit down\n"); | |
1da177e4 LT |
1080 | |
1081 | // cleanup | |
ff3ce480 BS |
1082 | debug("before free_hpc_access\n"); |
1083 | free_hpc_access(); | |
1084 | debug("after free_hpc_access\n"); | |
1085 | ibmphp_unlock_operations(); | |
1086 | debug("after unlock operations\n"); | |
1087 | up(&sem_exit); | |
1088 | debug("after sem exit up\n"); | |
1089 | ||
1090 | debug("%s - Exit\n", __func__); | |
1da177e4 LT |
1091 | } |
1092 | ||
1093 | /*---------------------------------------------------------------------- | |
1094 | * Name: hpc_wait_ctlr_notworking | |
1095 | * | |
1096 | * Action: wait until the controller is in a not working state | |
1097 | * | |
1098 | * Return 0, HPC_ERROR | |
1099 | * Value: | |
1100 | *---------------------------------------------------------------------*/ | |
ff3ce480 | 1101 | static int hpc_wait_ctlr_notworking(int timeout, struct controller *ctlr_ptr, void __iomem *wpg_bbar, |
3c78bc61 | 1102 | u8 *pstatus) |
1da177e4 LT |
1103 | { |
1104 | int rc = 0; | |
dc6712d1 | 1105 | u8 done = 0; |
1da177e4 | 1106 | |
ff3ce480 | 1107 | debug_polling("hpc_wait_ctlr_notworking - Entry timeout[%d]\n", timeout); |
1da177e4 LT |
1108 | |
1109 | while (!done) { | |
ff3ce480 | 1110 | *pstatus = ctrl_read(ctlr_ptr, wpg_bbar, WPG_CTLR_INDEX); |
1da177e4 LT |
1111 | if (*pstatus == HPC_ERROR) { |
1112 | rc = HPC_ERROR; | |
dc6712d1 | 1113 | done = 1; |
1da177e4 | 1114 | } |
ff3ce480 | 1115 | if (CTLR_WORKING(*pstatus) == HPC_CTLR_WORKING_NO) |
dc6712d1 | 1116 | done = 1; |
1da177e4 LT |
1117 | if (!done) { |
1118 | msleep(1000); | |
1119 | if (timeout < 1) { | |
dc6712d1 | 1120 | done = 1; |
ff3ce480 | 1121 | err("HPCreadslot - Error ctlr timeout\n"); |
1da177e4 LT |
1122 | rc = HPC_ERROR; |
1123 | } else | |
1124 | timeout--; | |
1125 | } | |
1126 | } | |
ff3ce480 | 1127 | debug_polling("hpc_wait_ctlr_notworking - Exit rc[%x] status[%x]\n", rc, *pstatus); |
1da177e4 LT |
1128 | return rc; |
1129 | } |