Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.27-rc7 851 lines 20 kB view raw
1/* 2 * This file is subject to the terms and conditions of the GNU General Public 3 * License. See the file "COPYING" in the main directory of this archive 4 * for more details. 5 * 6 * Copyright (c) 2005 Silicon Graphics, Inc. All rights reserved. 7 */ 8 9/* 10 * MOATB Core Services driver. 11 */ 12 13#include <linux/interrupt.h> 14#include <linux/module.h> 15#include <linux/moduleparam.h> 16#include <linux/types.h> 17#include <linux/ioport.h> 18#include <linux/notifier.h> 19#include <linux/reboot.h> 20#include <linux/init.h> 21#include <linux/fs.h> 22#include <linux/delay.h> 23#include <linux/device.h> 24#include <linux/mm.h> 25#include <linux/uio.h> 26#include <linux/mutex.h> 27#include <linux/smp_lock.h> 28#include <asm/io.h> 29#include <asm/uaccess.h> 30#include <asm/system.h> 31#include <asm/pgtable.h> 32#include <asm/sn/addrs.h> 33#include <asm/sn/intr.h> 34#include <asm/sn/tiocx.h> 35#include "mbcs.h" 36 37#define MBCS_DEBUG 0 38#if MBCS_DEBUG 39#define DBG(fmt...) printk(KERN_ALERT fmt) 40#else 41#define DBG(fmt...) 42#endif 43static int mbcs_major; 44 45static LIST_HEAD(soft_list); 46 47/* 48 * file operations 49 */ 50static const struct file_operations mbcs_ops = { 51 .open = mbcs_open, 52 .llseek = mbcs_sram_llseek, 53 .read = mbcs_sram_read, 54 .write = mbcs_sram_write, 55 .mmap = mbcs_gscr_mmap, 56}; 57 58struct mbcs_callback_arg { 59 int minor; 60 struct cx_dev *cx_dev; 61}; 62 63static inline void mbcs_getdma_init(struct getdma *gdma) 64{ 65 memset(gdma, 0, sizeof(struct getdma)); 66 gdma->DoneIntEnable = 1; 67} 68 69static inline void mbcs_putdma_init(struct putdma *pdma) 70{ 71 memset(pdma, 0, sizeof(struct putdma)); 72 pdma->DoneIntEnable = 1; 73} 74 75static inline void mbcs_algo_init(struct algoblock *algo_soft) 76{ 77 memset(algo_soft, 0, sizeof(struct algoblock)); 78} 79 80static inline void mbcs_getdma_set(void *mmr, 81 uint64_t hostAddr, 82 uint64_t localAddr, 83 uint64_t localRamSel, 84 uint64_t numPkts, 85 uint64_t amoEnable, 86 uint64_t intrEnable, 87 uint64_t peerIO, 88 uint64_t amoHostDest, 89 uint64_t amoModType, uint64_t intrHostDest, 90 uint64_t intrVector) 91{ 92 union dma_control rdma_control; 93 union dma_amo_dest amo_dest; 94 union intr_dest intr_dest; 95 union dma_localaddr local_addr; 96 union dma_hostaddr host_addr; 97 98 rdma_control.dma_control_reg = 0; 99 amo_dest.dma_amo_dest_reg = 0; 100 intr_dest.intr_dest_reg = 0; 101 local_addr.dma_localaddr_reg = 0; 102 host_addr.dma_hostaddr_reg = 0; 103 104 host_addr.dma_sys_addr = hostAddr; 105 MBCS_MMR_SET(mmr, MBCS_RD_DMA_SYS_ADDR, host_addr.dma_hostaddr_reg); 106 107 local_addr.dma_ram_addr = localAddr; 108 local_addr.dma_ram_sel = localRamSel; 109 MBCS_MMR_SET(mmr, MBCS_RD_DMA_LOC_ADDR, local_addr.dma_localaddr_reg); 110 111 rdma_control.dma_op_length = numPkts; 112 rdma_control.done_amo_en = amoEnable; 113 rdma_control.done_int_en = intrEnable; 114 rdma_control.pio_mem_n = peerIO; 115 MBCS_MMR_SET(mmr, MBCS_RD_DMA_CTRL, rdma_control.dma_control_reg); 116 117 amo_dest.dma_amo_sys_addr = amoHostDest; 118 amo_dest.dma_amo_mod_type = amoModType; 119 MBCS_MMR_SET(mmr, MBCS_RD_DMA_AMO_DEST, amo_dest.dma_amo_dest_reg); 120 121 intr_dest.address = intrHostDest; 122 intr_dest.int_vector = intrVector; 123 MBCS_MMR_SET(mmr, MBCS_RD_DMA_INT_DEST, intr_dest.intr_dest_reg); 124 125} 126 127static inline void mbcs_putdma_set(void *mmr, 128 uint64_t hostAddr, 129 uint64_t localAddr, 130 uint64_t localRamSel, 131 uint64_t numPkts, 132 uint64_t amoEnable, 133 uint64_t intrEnable, 134 uint64_t peerIO, 135 uint64_t amoHostDest, 136 uint64_t amoModType, 137 uint64_t intrHostDest, uint64_t intrVector) 138{ 139 union dma_control wdma_control; 140 union dma_amo_dest amo_dest; 141 union intr_dest intr_dest; 142 union dma_localaddr local_addr; 143 union dma_hostaddr host_addr; 144 145 wdma_control.dma_control_reg = 0; 146 amo_dest.dma_amo_dest_reg = 0; 147 intr_dest.intr_dest_reg = 0; 148 local_addr.dma_localaddr_reg = 0; 149 host_addr.dma_hostaddr_reg = 0; 150 151 host_addr.dma_sys_addr = hostAddr; 152 MBCS_MMR_SET(mmr, MBCS_WR_DMA_SYS_ADDR, host_addr.dma_hostaddr_reg); 153 154 local_addr.dma_ram_addr = localAddr; 155 local_addr.dma_ram_sel = localRamSel; 156 MBCS_MMR_SET(mmr, MBCS_WR_DMA_LOC_ADDR, local_addr.dma_localaddr_reg); 157 158 wdma_control.dma_op_length = numPkts; 159 wdma_control.done_amo_en = amoEnable; 160 wdma_control.done_int_en = intrEnable; 161 wdma_control.pio_mem_n = peerIO; 162 MBCS_MMR_SET(mmr, MBCS_WR_DMA_CTRL, wdma_control.dma_control_reg); 163 164 amo_dest.dma_amo_sys_addr = amoHostDest; 165 amo_dest.dma_amo_mod_type = amoModType; 166 MBCS_MMR_SET(mmr, MBCS_WR_DMA_AMO_DEST, amo_dest.dma_amo_dest_reg); 167 168 intr_dest.address = intrHostDest; 169 intr_dest.int_vector = intrVector; 170 MBCS_MMR_SET(mmr, MBCS_WR_DMA_INT_DEST, intr_dest.intr_dest_reg); 171 172} 173 174static inline void mbcs_algo_set(void *mmr, 175 uint64_t amoHostDest, 176 uint64_t amoModType, 177 uint64_t intrHostDest, 178 uint64_t intrVector, uint64_t algoStepCount) 179{ 180 union dma_amo_dest amo_dest; 181 union intr_dest intr_dest; 182 union algo_step step; 183 184 step.algo_step_reg = 0; 185 intr_dest.intr_dest_reg = 0; 186 amo_dest.dma_amo_dest_reg = 0; 187 188 amo_dest.dma_amo_sys_addr = amoHostDest; 189 amo_dest.dma_amo_mod_type = amoModType; 190 MBCS_MMR_SET(mmr, MBCS_ALG_AMO_DEST, amo_dest.dma_amo_dest_reg); 191 192 intr_dest.address = intrHostDest; 193 intr_dest.int_vector = intrVector; 194 MBCS_MMR_SET(mmr, MBCS_ALG_INT_DEST, intr_dest.intr_dest_reg); 195 196 step.alg_step_cnt = algoStepCount; 197 MBCS_MMR_SET(mmr, MBCS_ALG_STEP, step.algo_step_reg); 198} 199 200static inline int mbcs_getdma_start(struct mbcs_soft *soft) 201{ 202 void *mmr_base; 203 struct getdma *gdma; 204 uint64_t numPkts; 205 union cm_control cm_control; 206 207 mmr_base = soft->mmr_base; 208 gdma = &soft->getdma; 209 210 /* check that host address got setup */ 211 if (!gdma->hostAddr) 212 return -1; 213 214 numPkts = 215 (gdma->bytes + (MBCS_CACHELINE_SIZE - 1)) / MBCS_CACHELINE_SIZE; 216 217 /* program engine */ 218 mbcs_getdma_set(mmr_base, tiocx_dma_addr(gdma->hostAddr), 219 gdma->localAddr, 220 (gdma->localAddr < MB2) ? 0 : 221 (gdma->localAddr < MB4) ? 1 : 222 (gdma->localAddr < MB6) ? 2 : 3, 223 numPkts, 224 gdma->DoneAmoEnable, 225 gdma->DoneIntEnable, 226 gdma->peerIO, 227 gdma->amoHostDest, 228 gdma->amoModType, 229 gdma->intrHostDest, gdma->intrVector); 230 231 /* start engine */ 232 cm_control.cm_control_reg = MBCS_MMR_GET(mmr_base, MBCS_CM_CONTROL); 233 cm_control.rd_dma_go = 1; 234 MBCS_MMR_SET(mmr_base, MBCS_CM_CONTROL, cm_control.cm_control_reg); 235 236 return 0; 237 238} 239 240static inline int mbcs_putdma_start(struct mbcs_soft *soft) 241{ 242 void *mmr_base; 243 struct putdma *pdma; 244 uint64_t numPkts; 245 union cm_control cm_control; 246 247 mmr_base = soft->mmr_base; 248 pdma = &soft->putdma; 249 250 /* check that host address got setup */ 251 if (!pdma->hostAddr) 252 return -1; 253 254 numPkts = 255 (pdma->bytes + (MBCS_CACHELINE_SIZE - 1)) / MBCS_CACHELINE_SIZE; 256 257 /* program engine */ 258 mbcs_putdma_set(mmr_base, tiocx_dma_addr(pdma->hostAddr), 259 pdma->localAddr, 260 (pdma->localAddr < MB2) ? 0 : 261 (pdma->localAddr < MB4) ? 1 : 262 (pdma->localAddr < MB6) ? 2 : 3, 263 numPkts, 264 pdma->DoneAmoEnable, 265 pdma->DoneIntEnable, 266 pdma->peerIO, 267 pdma->amoHostDest, 268 pdma->amoModType, 269 pdma->intrHostDest, pdma->intrVector); 270 271 /* start engine */ 272 cm_control.cm_control_reg = MBCS_MMR_GET(mmr_base, MBCS_CM_CONTROL); 273 cm_control.wr_dma_go = 1; 274 MBCS_MMR_SET(mmr_base, MBCS_CM_CONTROL, cm_control.cm_control_reg); 275 276 return 0; 277 278} 279 280static inline int mbcs_algo_start(struct mbcs_soft *soft) 281{ 282 struct algoblock *algo_soft = &soft->algo; 283 void *mmr_base = soft->mmr_base; 284 union cm_control cm_control; 285 286 if (mutex_lock_interruptible(&soft->algolock)) 287 return -ERESTARTSYS; 288 289 atomic_set(&soft->algo_done, 0); 290 291 mbcs_algo_set(mmr_base, 292 algo_soft->amoHostDest, 293 algo_soft->amoModType, 294 algo_soft->intrHostDest, 295 algo_soft->intrVector, algo_soft->algoStepCount); 296 297 /* start algorithm */ 298 cm_control.cm_control_reg = MBCS_MMR_GET(mmr_base, MBCS_CM_CONTROL); 299 cm_control.alg_done_int_en = 1; 300 cm_control.alg_go = 1; 301 MBCS_MMR_SET(mmr_base, MBCS_CM_CONTROL, cm_control.cm_control_reg); 302 303 mutex_unlock(&soft->algolock); 304 305 return 0; 306} 307 308static inline ssize_t 309do_mbcs_sram_dmawrite(struct mbcs_soft *soft, uint64_t hostAddr, 310 size_t len, loff_t * off) 311{ 312 int rv = 0; 313 314 if (mutex_lock_interruptible(&soft->dmawritelock)) 315 return -ERESTARTSYS; 316 317 atomic_set(&soft->dmawrite_done, 0); 318 319 soft->putdma.hostAddr = hostAddr; 320 soft->putdma.localAddr = *off; 321 soft->putdma.bytes = len; 322 323 if (mbcs_putdma_start(soft) < 0) { 324 DBG(KERN_ALERT "do_mbcs_sram_dmawrite: " 325 "mbcs_putdma_start failed\n"); 326 rv = -EAGAIN; 327 goto dmawrite_exit; 328 } 329 330 if (wait_event_interruptible(soft->dmawrite_queue, 331 atomic_read(&soft->dmawrite_done))) { 332 rv = -ERESTARTSYS; 333 goto dmawrite_exit; 334 } 335 336 rv = len; 337 *off += len; 338 339dmawrite_exit: 340 mutex_unlock(&soft->dmawritelock); 341 342 return rv; 343} 344 345static inline ssize_t 346do_mbcs_sram_dmaread(struct mbcs_soft *soft, uint64_t hostAddr, 347 size_t len, loff_t * off) 348{ 349 int rv = 0; 350 351 if (mutex_lock_interruptible(&soft->dmareadlock)) 352 return -ERESTARTSYS; 353 354 atomic_set(&soft->dmawrite_done, 0); 355 356 soft->getdma.hostAddr = hostAddr; 357 soft->getdma.localAddr = *off; 358 soft->getdma.bytes = len; 359 360 if (mbcs_getdma_start(soft) < 0) { 361 DBG(KERN_ALERT "mbcs_strategy: mbcs_getdma_start failed\n"); 362 rv = -EAGAIN; 363 goto dmaread_exit; 364 } 365 366 if (wait_event_interruptible(soft->dmaread_queue, 367 atomic_read(&soft->dmaread_done))) { 368 rv = -ERESTARTSYS; 369 goto dmaread_exit; 370 } 371 372 rv = len; 373 *off += len; 374 375dmaread_exit: 376 mutex_unlock(&soft->dmareadlock); 377 378 return rv; 379} 380 381static int mbcs_open(struct inode *ip, struct file *fp) 382{ 383 struct mbcs_soft *soft; 384 int minor; 385 386 lock_kernel(); 387 minor = iminor(ip); 388 389 /* Nothing protects access to this list... */ 390 list_for_each_entry(soft, &soft_list, list) { 391 if (soft->nasid == minor) { 392 fp->private_data = soft->cxdev; 393 unlock_kernel(); 394 return 0; 395 } 396 } 397 398 unlock_kernel(); 399 return -ENODEV; 400} 401 402static ssize_t mbcs_sram_read(struct file * fp, char __user *buf, size_t len, loff_t * off) 403{ 404 struct cx_dev *cx_dev = fp->private_data; 405 struct mbcs_soft *soft = cx_dev->soft; 406 uint64_t hostAddr; 407 int rv = 0; 408 409 hostAddr = __get_dma_pages(GFP_KERNEL, get_order(len)); 410 if (hostAddr == 0) 411 return -ENOMEM; 412 413 rv = do_mbcs_sram_dmawrite(soft, hostAddr, len, off); 414 if (rv < 0) 415 goto exit; 416 417 if (copy_to_user(buf, (void *)hostAddr, len)) 418 rv = -EFAULT; 419 420 exit: 421 free_pages(hostAddr, get_order(len)); 422 423 return rv; 424} 425 426static ssize_t 427mbcs_sram_write(struct file * fp, const char __user *buf, size_t len, loff_t * off) 428{ 429 struct cx_dev *cx_dev = fp->private_data; 430 struct mbcs_soft *soft = cx_dev->soft; 431 uint64_t hostAddr; 432 int rv = 0; 433 434 hostAddr = __get_dma_pages(GFP_KERNEL, get_order(len)); 435 if (hostAddr == 0) 436 return -ENOMEM; 437 438 if (copy_from_user((void *)hostAddr, buf, len)) { 439 rv = -EFAULT; 440 goto exit; 441 } 442 443 rv = do_mbcs_sram_dmaread(soft, hostAddr, len, off); 444 445 exit: 446 free_pages(hostAddr, get_order(len)); 447 448 return rv; 449} 450 451static loff_t mbcs_sram_llseek(struct file * filp, loff_t off, int whence) 452{ 453 loff_t newpos; 454 455 switch (whence) { 456 case SEEK_SET: 457 newpos = off; 458 break; 459 460 case SEEK_CUR: 461 newpos = filp->f_pos + off; 462 break; 463 464 case SEEK_END: 465 newpos = MBCS_SRAM_SIZE + off; 466 break; 467 468 default: /* can't happen */ 469 return -EINVAL; 470 } 471 472 if (newpos < 0) 473 return -EINVAL; 474 475 filp->f_pos = newpos; 476 477 return newpos; 478} 479 480static uint64_t mbcs_pioaddr(struct mbcs_soft *soft, uint64_t offset) 481{ 482 uint64_t mmr_base; 483 484 mmr_base = (uint64_t) (soft->mmr_base + offset); 485 486 return mmr_base; 487} 488 489static void mbcs_debug_pioaddr_set(struct mbcs_soft *soft) 490{ 491 soft->debug_addr = mbcs_pioaddr(soft, MBCS_DEBUG_START); 492} 493 494static void mbcs_gscr_pioaddr_set(struct mbcs_soft *soft) 495{ 496 soft->gscr_addr = mbcs_pioaddr(soft, MBCS_GSCR_START); 497} 498 499static int mbcs_gscr_mmap(struct file *fp, struct vm_area_struct *vma) 500{ 501 struct cx_dev *cx_dev = fp->private_data; 502 struct mbcs_soft *soft = cx_dev->soft; 503 504 if (vma->vm_pgoff != 0) 505 return -EINVAL; 506 507 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); 508 509 /* Remap-pfn-range will mark the range VM_IO and VM_RESERVED */ 510 if (remap_pfn_range(vma, 511 vma->vm_start, 512 __pa(soft->gscr_addr) >> PAGE_SHIFT, 513 PAGE_SIZE, 514 vma->vm_page_prot)) 515 return -EAGAIN; 516 517 return 0; 518} 519 520/** 521 * mbcs_completion_intr_handler - Primary completion handler. 522 * @irq: irq 523 * @arg: soft struct for device 524 * 525 */ 526static irqreturn_t 527mbcs_completion_intr_handler(int irq, void *arg) 528{ 529 struct mbcs_soft *soft = (struct mbcs_soft *)arg; 530 void *mmr_base; 531 union cm_status cm_status; 532 union cm_control cm_control; 533 534 mmr_base = soft->mmr_base; 535 cm_status.cm_status_reg = MBCS_MMR_GET(mmr_base, MBCS_CM_STATUS); 536 537 if (cm_status.rd_dma_done) { 538 /* stop dma-read engine, clear status */ 539 cm_control.cm_control_reg = 540 MBCS_MMR_GET(mmr_base, MBCS_CM_CONTROL); 541 cm_control.rd_dma_clr = 1; 542 MBCS_MMR_SET(mmr_base, MBCS_CM_CONTROL, 543 cm_control.cm_control_reg); 544 atomic_set(&soft->dmaread_done, 1); 545 wake_up(&soft->dmaread_queue); 546 } 547 if (cm_status.wr_dma_done) { 548 /* stop dma-write engine, clear status */ 549 cm_control.cm_control_reg = 550 MBCS_MMR_GET(mmr_base, MBCS_CM_CONTROL); 551 cm_control.wr_dma_clr = 1; 552 MBCS_MMR_SET(mmr_base, MBCS_CM_CONTROL, 553 cm_control.cm_control_reg); 554 atomic_set(&soft->dmawrite_done, 1); 555 wake_up(&soft->dmawrite_queue); 556 } 557 if (cm_status.alg_done) { 558 /* clear status */ 559 cm_control.cm_control_reg = 560 MBCS_MMR_GET(mmr_base, MBCS_CM_CONTROL); 561 cm_control.alg_done_clr = 1; 562 MBCS_MMR_SET(mmr_base, MBCS_CM_CONTROL, 563 cm_control.cm_control_reg); 564 atomic_set(&soft->algo_done, 1); 565 wake_up(&soft->algo_queue); 566 } 567 568 return IRQ_HANDLED; 569} 570 571/** 572 * mbcs_intr_alloc - Allocate interrupts. 573 * @dev: device pointer 574 * 575 */ 576static int mbcs_intr_alloc(struct cx_dev *dev) 577{ 578 struct sn_irq_info *sn_irq; 579 struct mbcs_soft *soft; 580 struct getdma *getdma; 581 struct putdma *putdma; 582 struct algoblock *algo; 583 584 soft = dev->soft; 585 getdma = &soft->getdma; 586 putdma = &soft->putdma; 587 algo = &soft->algo; 588 589 soft->get_sn_irq = NULL; 590 soft->put_sn_irq = NULL; 591 soft->algo_sn_irq = NULL; 592 593 sn_irq = tiocx_irq_alloc(dev->cx_id.nasid, TIOCX_CORELET, -1, -1, -1); 594 if (sn_irq == NULL) 595 return -EAGAIN; 596 soft->get_sn_irq = sn_irq; 597 getdma->intrHostDest = sn_irq->irq_xtalkaddr; 598 getdma->intrVector = sn_irq->irq_irq; 599 if (request_irq(sn_irq->irq_irq, 600 (void *)mbcs_completion_intr_handler, IRQF_SHARED, 601 "MBCS get intr", (void *)soft)) { 602 tiocx_irq_free(soft->get_sn_irq); 603 return -EAGAIN; 604 } 605 606 sn_irq = tiocx_irq_alloc(dev->cx_id.nasid, TIOCX_CORELET, -1, -1, -1); 607 if (sn_irq == NULL) { 608 free_irq(soft->get_sn_irq->irq_irq, soft); 609 tiocx_irq_free(soft->get_sn_irq); 610 return -EAGAIN; 611 } 612 soft->put_sn_irq = sn_irq; 613 putdma->intrHostDest = sn_irq->irq_xtalkaddr; 614 putdma->intrVector = sn_irq->irq_irq; 615 if (request_irq(sn_irq->irq_irq, 616 (void *)mbcs_completion_intr_handler, IRQF_SHARED, 617 "MBCS put intr", (void *)soft)) { 618 tiocx_irq_free(soft->put_sn_irq); 619 free_irq(soft->get_sn_irq->irq_irq, soft); 620 tiocx_irq_free(soft->get_sn_irq); 621 return -EAGAIN; 622 } 623 624 sn_irq = tiocx_irq_alloc(dev->cx_id.nasid, TIOCX_CORELET, -1, -1, -1); 625 if (sn_irq == NULL) { 626 free_irq(soft->put_sn_irq->irq_irq, soft); 627 tiocx_irq_free(soft->put_sn_irq); 628 free_irq(soft->get_sn_irq->irq_irq, soft); 629 tiocx_irq_free(soft->get_sn_irq); 630 return -EAGAIN; 631 } 632 soft->algo_sn_irq = sn_irq; 633 algo->intrHostDest = sn_irq->irq_xtalkaddr; 634 algo->intrVector = sn_irq->irq_irq; 635 if (request_irq(sn_irq->irq_irq, 636 (void *)mbcs_completion_intr_handler, IRQF_SHARED, 637 "MBCS algo intr", (void *)soft)) { 638 tiocx_irq_free(soft->algo_sn_irq); 639 free_irq(soft->put_sn_irq->irq_irq, soft); 640 tiocx_irq_free(soft->put_sn_irq); 641 free_irq(soft->get_sn_irq->irq_irq, soft); 642 tiocx_irq_free(soft->get_sn_irq); 643 return -EAGAIN; 644 } 645 646 return 0; 647} 648 649/** 650 * mbcs_intr_dealloc - Remove interrupts. 651 * @dev: device pointer 652 * 653 */ 654static void mbcs_intr_dealloc(struct cx_dev *dev) 655{ 656 struct mbcs_soft *soft; 657 658 soft = dev->soft; 659 660 free_irq(soft->get_sn_irq->irq_irq, soft); 661 tiocx_irq_free(soft->get_sn_irq); 662 free_irq(soft->put_sn_irq->irq_irq, soft); 663 tiocx_irq_free(soft->put_sn_irq); 664 free_irq(soft->algo_sn_irq->irq_irq, soft); 665 tiocx_irq_free(soft->algo_sn_irq); 666} 667 668static inline int mbcs_hw_init(struct mbcs_soft *soft) 669{ 670 void *mmr_base = soft->mmr_base; 671 union cm_control cm_control; 672 union cm_req_timeout cm_req_timeout; 673 uint64_t err_stat; 674 675 cm_req_timeout.cm_req_timeout_reg = 676 MBCS_MMR_GET(mmr_base, MBCS_CM_REQ_TOUT); 677 678 cm_req_timeout.time_out = MBCS_CM_CONTROL_REQ_TOUT_MASK; 679 MBCS_MMR_SET(mmr_base, MBCS_CM_REQ_TOUT, 680 cm_req_timeout.cm_req_timeout_reg); 681 682 mbcs_gscr_pioaddr_set(soft); 683 mbcs_debug_pioaddr_set(soft); 684 685 /* clear errors */ 686 err_stat = MBCS_MMR_GET(mmr_base, MBCS_CM_ERR_STAT); 687 MBCS_MMR_SET(mmr_base, MBCS_CM_CLR_ERR_STAT, err_stat); 688 MBCS_MMR_ZERO(mmr_base, MBCS_CM_ERROR_DETAIL1); 689 690 /* enable interrupts */ 691 /* turn off 2^23 (INT_EN_PIO_REQ_ADDR_INV) */ 692 MBCS_MMR_SET(mmr_base, MBCS_CM_ERR_INT_EN, 0x3ffffff7e00ffUL); 693 694 /* arm status regs and clear engines */ 695 cm_control.cm_control_reg = MBCS_MMR_GET(mmr_base, MBCS_CM_CONTROL); 696 cm_control.rearm_stat_regs = 1; 697 cm_control.alg_clr = 1; 698 cm_control.wr_dma_clr = 1; 699 cm_control.rd_dma_clr = 1; 700 701 MBCS_MMR_SET(mmr_base, MBCS_CM_CONTROL, cm_control.cm_control_reg); 702 703 return 0; 704} 705 706static ssize_t show_algo(struct device *dev, struct device_attribute *attr, char *buf) 707{ 708 struct cx_dev *cx_dev = to_cx_dev(dev); 709 struct mbcs_soft *soft = cx_dev->soft; 710 uint64_t debug0; 711 712 /* 713 * By convention, the first debug register contains the 714 * algorithm number and revision. 715 */ 716 debug0 = *(uint64_t *) soft->debug_addr; 717 718 return sprintf(buf, "0x%lx 0x%lx\n", 719 (debug0 >> 32), (debug0 & 0xffffffff)); 720} 721 722static ssize_t store_algo(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) 723{ 724 int n; 725 struct cx_dev *cx_dev = to_cx_dev(dev); 726 struct mbcs_soft *soft = cx_dev->soft; 727 728 if (count <= 0) 729 return 0; 730 731 n = simple_strtoul(buf, NULL, 0); 732 733 if (n == 1) { 734 mbcs_algo_start(soft); 735 if (wait_event_interruptible(soft->algo_queue, 736 atomic_read(&soft->algo_done))) 737 return -ERESTARTSYS; 738 } 739 740 return count; 741} 742 743DEVICE_ATTR(algo, 0644, show_algo, store_algo); 744 745/** 746 * mbcs_probe - Initialize for device 747 * @dev: device pointer 748 * @device_id: id table pointer 749 * 750 */ 751static int mbcs_probe(struct cx_dev *dev, const struct cx_device_id *id) 752{ 753 struct mbcs_soft *soft; 754 755 dev->soft = NULL; 756 757 soft = kzalloc(sizeof(struct mbcs_soft), GFP_KERNEL); 758 if (soft == NULL) 759 return -ENOMEM; 760 761 soft->nasid = dev->cx_id.nasid; 762 list_add(&soft->list, &soft_list); 763 soft->mmr_base = (void *)tiocx_swin_base(dev->cx_id.nasid); 764 dev->soft = soft; 765 soft->cxdev = dev; 766 767 init_waitqueue_head(&soft->dmawrite_queue); 768 init_waitqueue_head(&soft->dmaread_queue); 769 init_waitqueue_head(&soft->algo_queue); 770 771 mutex_init(&soft->dmawritelock); 772 mutex_init(&soft->dmareadlock); 773 mutex_init(&soft->algolock); 774 775 mbcs_getdma_init(&soft->getdma); 776 mbcs_putdma_init(&soft->putdma); 777 mbcs_algo_init(&soft->algo); 778 779 mbcs_hw_init(soft); 780 781 /* Allocate interrupts */ 782 mbcs_intr_alloc(dev); 783 784 device_create_file(&dev->dev, &dev_attr_algo); 785 786 return 0; 787} 788 789static int mbcs_remove(struct cx_dev *dev) 790{ 791 if (dev->soft) { 792 mbcs_intr_dealloc(dev); 793 kfree(dev->soft); 794 } 795 796 device_remove_file(&dev->dev, &dev_attr_algo); 797 798 return 0; 799} 800 801static const struct cx_device_id __devinitdata mbcs_id_table[] = { 802 { 803 .part_num = MBCS_PART_NUM, 804 .mfg_num = MBCS_MFG_NUM, 805 }, 806 { 807 .part_num = MBCS_PART_NUM_ALG0, 808 .mfg_num = MBCS_MFG_NUM, 809 }, 810 {0, 0} 811}; 812 813MODULE_DEVICE_TABLE(cx, mbcs_id_table); 814 815static struct cx_drv mbcs_driver = { 816 .name = DEVICE_NAME, 817 .id_table = mbcs_id_table, 818 .probe = mbcs_probe, 819 .remove = mbcs_remove, 820}; 821 822static void __exit mbcs_exit(void) 823{ 824 unregister_chrdev(mbcs_major, DEVICE_NAME); 825 cx_driver_unregister(&mbcs_driver); 826} 827 828static int __init mbcs_init(void) 829{ 830 int rv; 831 832 if (!ia64_platform_is("sn2")) 833 return -ENODEV; 834 835 // Put driver into chrdevs[]. Get major number. 836 rv = register_chrdev(mbcs_major, DEVICE_NAME, &mbcs_ops); 837 if (rv < 0) { 838 DBG(KERN_ALERT "mbcs_init: can't get major number. %d\n", rv); 839 return rv; 840 } 841 mbcs_major = rv; 842 843 return cx_driver_register(&mbcs_driver); 844} 845 846module_init(mbcs_init); 847module_exit(mbcs_exit); 848 849MODULE_AUTHOR("Bruce Losure <blosure@sgi.com>"); 850MODULE_DESCRIPTION("Driver for MOATB Core Services"); 851MODULE_LICENSE("GPL");