diff options
author | David Altobelli <david.altobelli@hp.com> | 2009-08-17 19:07:03 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-09-15 12:50:48 -0400 |
commit | 66d5e5169c96f3e0175235e2bcbaedc8bc1c728f (patch) | |
tree | 8453acb01486b2e4adea3bc5284ca365fe78ae9c /drivers/misc/hpilo.c | |
parent | daa4122673f002911122cac2b996bd36b6c01b32 (diff) |
hpilo: staging for interrupt handling
Refactor some hpilo routines in order to allow for locking changes in
interrupt handling. Should not be functionally different.
Signed-off-by: David Altobelli <david.altobelli@hp.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/misc/hpilo.c')
-rw-r--r-- | drivers/misc/hpilo.c | 120 |
1 files changed, 73 insertions, 47 deletions
diff --git a/drivers/misc/hpilo.c b/drivers/misc/hpilo.c index 880ccf39e23b..35ed12379cd0 100644 --- a/drivers/misc/hpilo.c +++ b/drivers/misc/hpilo.c | |||
@@ -151,6 +151,7 @@ static inline void doorbell_clr(struct ccb *ccb) | |||
151 | { | 151 | { |
152 | iowrite8(2, ccb->ccb_u5.db_base); | 152 | iowrite8(2, ccb->ccb_u5.db_base); |
153 | } | 153 | } |
154 | |||
154 | static inline int ctrl_set(int l2sz, int idxmask, int desclim) | 155 | static inline int ctrl_set(int l2sz, int idxmask, int desclim) |
155 | { | 156 | { |
156 | int active = 0, go = 1; | 157 | int active = 0, go = 1; |
@@ -160,6 +161,7 @@ static inline int ctrl_set(int l2sz, int idxmask, int desclim) | |||
160 | active << CTRL_BITPOS_A | | 161 | active << CTRL_BITPOS_A | |
161 | go << CTRL_BITPOS_G; | 162 | go << CTRL_BITPOS_G; |
162 | } | 163 | } |
164 | |||
163 | static void ctrl_setup(struct ccb *ccb, int nr_desc, int l2desc_sz) | 165 | static void ctrl_setup(struct ccb *ccb, int nr_desc, int l2desc_sz) |
164 | { | 166 | { |
165 | /* for simplicity, use the same parameters for send and recv ctrls */ | 167 | /* for simplicity, use the same parameters for send and recv ctrls */ |
@@ -192,13 +194,10 @@ static void fifo_setup(void *base_addr, int nr_entry) | |||
192 | 194 | ||
193 | static void ilo_ccb_close(struct pci_dev *pdev, struct ccb_data *data) | 195 | static void ilo_ccb_close(struct pci_dev *pdev, struct ccb_data *data) |
194 | { | 196 | { |
195 | struct ccb *driver_ccb; | 197 | struct ccb *driver_ccb = &data->driver_ccb; |
196 | struct ccb __iomem *device_ccb; | 198 | struct ccb __iomem *device_ccb = data->mapped_ccb; |
197 | int retries; | 199 | int retries; |
198 | 200 | ||
199 | driver_ccb = &data->driver_ccb; | ||
200 | device_ccb = data->mapped_ccb; | ||
201 | |||
202 | /* complicated dance to tell the hw we are stopping */ | 201 | /* complicated dance to tell the hw we are stopping */ |
203 | doorbell_clr(driver_ccb); | 202 | doorbell_clr(driver_ccb); |
204 | iowrite32(ioread32(&device_ccb->send_ctrl) & ~(1 << CTRL_BITPOS_G), | 203 | iowrite32(ioread32(&device_ccb->send_ctrl) & ~(1 << CTRL_BITPOS_G), |
@@ -225,26 +224,22 @@ static void ilo_ccb_close(struct pci_dev *pdev, struct ccb_data *data) | |||
225 | pci_free_consistent(pdev, data->dma_size, data->dma_va, data->dma_pa); | 224 | pci_free_consistent(pdev, data->dma_size, data->dma_va, data->dma_pa); |
226 | } | 225 | } |
227 | 226 | ||
228 | static int ilo_ccb_open(struct ilo_hwinfo *hw, struct ccb_data *data, int slot) | 227 | static int ilo_ccb_setup(struct ilo_hwinfo *hw, struct ccb_data *data, int slot) |
229 | { | 228 | { |
230 | char *dma_va, *dma_pa; | 229 | char *dma_va, *dma_pa; |
231 | int pkt_id, pkt_sz, i, error; | ||
232 | struct ccb *driver_ccb, *ilo_ccb; | 230 | struct ccb *driver_ccb, *ilo_ccb; |
233 | struct pci_dev *pdev; | ||
234 | 231 | ||
235 | driver_ccb = &data->driver_ccb; | 232 | driver_ccb = &data->driver_ccb; |
236 | ilo_ccb = &data->ilo_ccb; | 233 | ilo_ccb = &data->ilo_ccb; |
237 | pdev = hw->ilo_dev; | ||
238 | 234 | ||
239 | data->dma_size = 2 * fifo_sz(NR_QENTRY) + | 235 | data->dma_size = 2 * fifo_sz(NR_QENTRY) + |
240 | 2 * desc_mem_sz(NR_QENTRY) + | 236 | 2 * desc_mem_sz(NR_QENTRY) + |
241 | ILO_START_ALIGN + ILO_CACHE_SZ; | 237 | ILO_START_ALIGN + ILO_CACHE_SZ; |
242 | 238 | ||
243 | error = -ENOMEM; | 239 | data->dma_va = pci_alloc_consistent(hw->ilo_dev, data->dma_size, |
244 | data->dma_va = pci_alloc_consistent(pdev, data->dma_size, | ||
245 | &data->dma_pa); | 240 | &data->dma_pa); |
246 | if (!data->dma_va) | 241 | if (!data->dma_va) |
247 | goto out; | 242 | return -ENOMEM; |
248 | 243 | ||
249 | dma_va = (char *)data->dma_va; | 244 | dma_va = (char *)data->dma_va; |
250 | dma_pa = (char *)data->dma_pa; | 245 | dma_pa = (char *)data->dma_pa; |
@@ -290,10 +285,18 @@ static int ilo_ccb_open(struct ilo_hwinfo *hw, struct ccb_data *data, int slot) | |||
290 | driver_ccb->ccb_u5.db_base = hw->db_vaddr + (slot << L2_DB_SIZE); | 285 | driver_ccb->ccb_u5.db_base = hw->db_vaddr + (slot << L2_DB_SIZE); |
291 | ilo_ccb->ccb_u5.db_base = NULL; /* hw ccb's doorbell is not used */ | 286 | ilo_ccb->ccb_u5.db_base = NULL; /* hw ccb's doorbell is not used */ |
292 | 287 | ||
288 | return 0; | ||
289 | } | ||
290 | |||
291 | static void ilo_ccb_open(struct ilo_hwinfo *hw, struct ccb_data *data, int slot) | ||
292 | { | ||
293 | int pkt_id, pkt_sz; | ||
294 | struct ccb *driver_ccb = &data->driver_ccb; | ||
295 | |||
293 | /* copy the ccb with physical addrs to device memory */ | 296 | /* copy the ccb with physical addrs to device memory */ |
294 | data->mapped_ccb = (struct ccb __iomem *) | 297 | data->mapped_ccb = (struct ccb __iomem *) |
295 | (hw->ram_vaddr + (slot * ILOHW_CCB_SZ)); | 298 | (hw->ram_vaddr + (slot * ILOHW_CCB_SZ)); |
296 | memcpy_toio(data->mapped_ccb, ilo_ccb, sizeof(struct ccb)); | 299 | memcpy_toio(data->mapped_ccb, &data->ilo_ccb, sizeof(struct ccb)); |
297 | 300 | ||
298 | /* put packets on the send and receive queues */ | 301 | /* put packets on the send and receive queues */ |
299 | pkt_sz = 0; | 302 | pkt_sz = 0; |
@@ -306,7 +309,14 @@ static int ilo_ccb_open(struct ilo_hwinfo *hw, struct ccb_data *data, int slot) | |||
306 | for (pkt_id = 0; pkt_id < NR_QENTRY; pkt_id++) | 309 | for (pkt_id = 0; pkt_id < NR_QENTRY; pkt_id++) |
307 | ilo_pkt_enqueue(hw, driver_ccb, RECVQ, pkt_id, pkt_sz); | 310 | ilo_pkt_enqueue(hw, driver_ccb, RECVQ, pkt_id, pkt_sz); |
308 | 311 | ||
312 | /* the ccb is ready to use */ | ||
309 | doorbell_clr(driver_ccb); | 313 | doorbell_clr(driver_ccb); |
314 | } | ||
315 | |||
316 | static int ilo_ccb_verify(struct ilo_hwinfo *hw, struct ccb_data *data) | ||
317 | { | ||
318 | int pkt_id, i; | ||
319 | struct ccb *driver_ccb = &data->driver_ccb; | ||
310 | 320 | ||
311 | /* make sure iLO is really handling requests */ | 321 | /* make sure iLO is really handling requests */ |
312 | for (i = MAX_WAIT; i > 0; i--) { | 322 | for (i = MAX_WAIT; i > 0; i--) { |
@@ -315,20 +325,14 @@ static int ilo_ccb_open(struct ilo_hwinfo *hw, struct ccb_data *data, int slot) | |||
315 | udelay(WAIT_TIME); | 325 | udelay(WAIT_TIME); |
316 | } | 326 | } |
317 | 327 | ||
318 | if (i) { | 328 | if (i == 0) { |
319 | ilo_pkt_enqueue(hw, driver_ccb, SENDQ, pkt_id, 0); | 329 | dev_err(&hw->ilo_dev->dev, "Open could not dequeue a packet\n"); |
320 | doorbell_set(driver_ccb); | 330 | return -EBUSY; |
321 | } else { | ||
322 | dev_err(&pdev->dev, "Open could not dequeue a packet\n"); | ||
323 | error = -EBUSY; | ||
324 | goto free; | ||
325 | } | 331 | } |
326 | 332 | ||
333 | ilo_pkt_enqueue(hw, driver_ccb, SENDQ, pkt_id, 0); | ||
334 | doorbell_set(driver_ccb); | ||
327 | return 0; | 335 | return 0; |
328 | free: | ||
329 | ilo_ccb_close(pdev, data); | ||
330 | out: | ||
331 | return error; | ||
332 | } | 336 | } |
333 | 337 | ||
334 | static inline int is_channel_reset(struct ccb *ccb) | 338 | static inline int is_channel_reset(struct ccb *ccb) |
@@ -343,16 +347,31 @@ static inline void set_channel_reset(struct ccb *ccb) | |||
343 | FIFOBARTOHANDLE(ccb->ccb_u1.send_fifobar)->reset = 1; | 347 | FIFOBARTOHANDLE(ccb->ccb_u1.send_fifobar)->reset = 1; |
344 | } | 348 | } |
345 | 349 | ||
350 | static inline int get_device_outbound(struct ilo_hwinfo *hw) | ||
351 | { | ||
352 | return ioread32(&hw->mmio_vaddr[DB_OUT]); | ||
353 | } | ||
354 | |||
355 | static inline int is_db_reset(int db_out) | ||
356 | { | ||
357 | return db_out & (1 << DB_RESET); | ||
358 | } | ||
359 | |||
346 | static inline int is_device_reset(struct ilo_hwinfo *hw) | 360 | static inline int is_device_reset(struct ilo_hwinfo *hw) |
347 | { | 361 | { |
348 | /* check for global reset condition */ | 362 | /* check for global reset condition */ |
349 | return ioread32(&hw->mmio_vaddr[DB_OUT]) & (1 << DB_RESET); | 363 | return is_db_reset(get_device_outbound(hw)); |
364 | } | ||
365 | |||
366 | static inline void clear_pending_db(struct ilo_hwinfo *hw, int clr) | ||
367 | { | ||
368 | iowrite32(clr, &hw->mmio_vaddr[DB_OUT]); | ||
350 | } | 369 | } |
351 | 370 | ||
352 | static inline void clear_device(struct ilo_hwinfo *hw) | 371 | static inline void clear_device(struct ilo_hwinfo *hw) |
353 | { | 372 | { |
354 | /* clear the device (reset bits, pending channel entries) */ | 373 | /* clear the device (reset bits, pending channel entries) */ |
355 | iowrite32(-1, &hw->mmio_vaddr[DB_OUT]); | 374 | clear_pending_db(hw, -1); |
356 | } | 375 | } |
357 | 376 | ||
358 | static void ilo_locked_reset(struct ilo_hwinfo *hw) | 377 | static void ilo_locked_reset(struct ilo_hwinfo *hw) |
@@ -387,15 +406,11 @@ static ssize_t ilo_read(struct file *fp, char __user *buf, | |||
387 | size_t len, loff_t *off) | 406 | size_t len, loff_t *off) |
388 | { | 407 | { |
389 | int err, found, cnt, pkt_id, pkt_len; | 408 | int err, found, cnt, pkt_id, pkt_len; |
390 | struct ccb_data *data; | 409 | struct ccb_data *data = fp->private_data; |
391 | struct ccb *driver_ccb; | 410 | struct ccb *driver_ccb = &data->driver_ccb; |
392 | struct ilo_hwinfo *hw; | 411 | struct ilo_hwinfo *hw = data->ilo_hw; |
393 | void *pkt; | 412 | void *pkt; |
394 | 413 | ||
395 | data = fp->private_data; | ||
396 | driver_ccb = &data->driver_ccb; | ||
397 | hw = data->ilo_hw; | ||
398 | |||
399 | if (is_device_reset(hw) || is_channel_reset(driver_ccb)) { | 414 | if (is_device_reset(hw) || is_channel_reset(driver_ccb)) { |
400 | /* | 415 | /* |
401 | * If the device has been reset, applications | 416 | * If the device has been reset, applications |
@@ -442,15 +457,11 @@ static ssize_t ilo_write(struct file *fp, const char __user *buf, | |||
442 | size_t len, loff_t *off) | 457 | size_t len, loff_t *off) |
443 | { | 458 | { |
444 | int err, pkt_id, pkt_len; | 459 | int err, pkt_id, pkt_len; |
445 | struct ccb_data *data; | 460 | struct ccb_data *data = fp->private_data; |
446 | struct ccb *driver_ccb; | 461 | struct ccb *driver_ccb = &data->driver_ccb; |
447 | struct ilo_hwinfo *hw; | 462 | struct ilo_hwinfo *hw = data->ilo_hw; |
448 | void *pkt; | 463 | void *pkt; |
449 | 464 | ||
450 | data = fp->private_data; | ||
451 | driver_ccb = &data->driver_ccb; | ||
452 | hw = data->ilo_hw; | ||
453 | |||
454 | if (is_device_reset(hw) || is_channel_reset(driver_ccb)) { | 465 | if (is_device_reset(hw) || is_channel_reset(driver_ccb)) { |
455 | /* | 466 | /* |
456 | * If the device has been reset, applications | 467 | * If the device has been reset, applications |
@@ -532,14 +543,28 @@ static int ilo_open(struct inode *ip, struct file *fp) | |||
532 | /* each fd private_data holds sw/hw view of ccb */ | 543 | /* each fd private_data holds sw/hw view of ccb */ |
533 | if (hw->ccb_alloc[slot] == NULL) { | 544 | if (hw->ccb_alloc[slot] == NULL) { |
534 | /* create a channel control block for this minor */ | 545 | /* create a channel control block for this minor */ |
535 | error = ilo_ccb_open(hw, data, slot); | 546 | error = ilo_ccb_setup(hw, data, slot); |
536 | if (!error) { | 547 | if (error) { |
537 | hw->ccb_alloc[slot] = data; | 548 | kfree(data); |
538 | hw->ccb_alloc[slot]->ccb_cnt = 1; | 549 | goto out; |
539 | hw->ccb_alloc[slot]->ccb_excl = fp->f_flags & O_EXCL; | 550 | } |
540 | hw->ccb_alloc[slot]->ilo_hw = hw; | 551 | |
541 | } else | 552 | /* write the ccb to hw */ |
553 | ilo_ccb_open(hw, data, slot); | ||
554 | |||
555 | /* make sure the channel is functional */ | ||
556 | error = ilo_ccb_verify(hw, data); | ||
557 | if (error) { | ||
558 | ilo_ccb_close(hw->ilo_dev, data); | ||
542 | kfree(data); | 559 | kfree(data); |
560 | goto out; | ||
561 | } | ||
562 | |||
563 | data->ccb_cnt = 1; | ||
564 | data->ccb_excl = fp->f_flags & O_EXCL; | ||
565 | data->ilo_hw = hw; | ||
566 | hw->ccb_alloc[slot] = data; | ||
567 | |||
543 | } else { | 568 | } else { |
544 | kfree(data); | 569 | kfree(data); |
545 | if (fp->f_flags & O_EXCL || hw->ccb_alloc[slot]->ccb_excl) { | 570 | if (fp->f_flags & O_EXCL || hw->ccb_alloc[slot]->ccb_excl) { |
@@ -554,6 +579,7 @@ static int ilo_open(struct inode *ip, struct file *fp) | |||
554 | error = 0; | 579 | error = 0; |
555 | } | 580 | } |
556 | } | 581 | } |
582 | out: | ||
557 | spin_unlock(&hw->alloc_lock); | 583 | spin_unlock(&hw->alloc_lock); |
558 | 584 | ||
559 | if (!error) | 585 | if (!error) |