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