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 | |
| 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>
| -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) |
