at v4.16-rc3 830 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/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/slab.h> 29#include <linux/pagemap.h> 30#include <asm/io.h> 31#include <linux/uaccess.h> 32#include <asm/pgtable.h> 33#include <asm/sn/addrs.h> 34#include <asm/sn/intr.h> 35#include <asm/sn/tiocx.h> 36#include "mbcs.h" 37 38#define MBCS_DEBUG 0 39#if MBCS_DEBUG 40#define DBG(fmt...) printk(KERN_ALERT fmt) 41#else 42#define DBG(fmt...) 43#endif 44static DEFINE_MUTEX(mbcs_mutex); 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 mutex_lock(&mbcs_mutex); 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 mutex_unlock(&mbcs_mutex); 396 return 0; 397 } 398 } 399 400 mutex_unlock(&mbcs_mutex); 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 return generic_file_llseek_size(filp, off, whence, MAX_LFS_FILESIZE, 456 MBCS_SRAM_SIZE); 457} 458 459static uint64_t mbcs_pioaddr(struct mbcs_soft *soft, uint64_t offset) 460{ 461 uint64_t mmr_base; 462 463 mmr_base = (uint64_t) (soft->mmr_base + offset); 464 465 return mmr_base; 466} 467 468static void mbcs_debug_pioaddr_set(struct mbcs_soft *soft) 469{ 470 soft->debug_addr = mbcs_pioaddr(soft, MBCS_DEBUG_START); 471} 472 473static void mbcs_gscr_pioaddr_set(struct mbcs_soft *soft) 474{ 475 soft->gscr_addr = mbcs_pioaddr(soft, MBCS_GSCR_START); 476} 477 478static int mbcs_gscr_mmap(struct file *fp, struct vm_area_struct *vma) 479{ 480 struct cx_dev *cx_dev = fp->private_data; 481 struct mbcs_soft *soft = cx_dev->soft; 482 483 if (vma->vm_pgoff != 0) 484 return -EINVAL; 485 486 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); 487 488 /* Remap-pfn-range will mark the range VM_IO */ 489 if (remap_pfn_range(vma, 490 vma->vm_start, 491 __pa(soft->gscr_addr) >> PAGE_SHIFT, 492 PAGE_SIZE, 493 vma->vm_page_prot)) 494 return -EAGAIN; 495 496 return 0; 497} 498 499/** 500 * mbcs_completion_intr_handler - Primary completion handler. 501 * @irq: irq 502 * @arg: soft struct for device 503 * 504 */ 505static irqreturn_t 506mbcs_completion_intr_handler(int irq, void *arg) 507{ 508 struct mbcs_soft *soft = (struct mbcs_soft *)arg; 509 void *mmr_base; 510 union cm_status cm_status; 511 union cm_control cm_control; 512 513 mmr_base = soft->mmr_base; 514 cm_status.cm_status_reg = MBCS_MMR_GET(mmr_base, MBCS_CM_STATUS); 515 516 if (cm_status.rd_dma_done) { 517 /* stop dma-read engine, clear status */ 518 cm_control.cm_control_reg = 519 MBCS_MMR_GET(mmr_base, MBCS_CM_CONTROL); 520 cm_control.rd_dma_clr = 1; 521 MBCS_MMR_SET(mmr_base, MBCS_CM_CONTROL, 522 cm_control.cm_control_reg); 523 atomic_set(&soft->dmaread_done, 1); 524 wake_up(&soft->dmaread_queue); 525 } 526 if (cm_status.wr_dma_done) { 527 /* stop dma-write engine, clear status */ 528 cm_control.cm_control_reg = 529 MBCS_MMR_GET(mmr_base, MBCS_CM_CONTROL); 530 cm_control.wr_dma_clr = 1; 531 MBCS_MMR_SET(mmr_base, MBCS_CM_CONTROL, 532 cm_control.cm_control_reg); 533 atomic_set(&soft->dmawrite_done, 1); 534 wake_up(&soft->dmawrite_queue); 535 } 536 if (cm_status.alg_done) { 537 /* clear status */ 538 cm_control.cm_control_reg = 539 MBCS_MMR_GET(mmr_base, MBCS_CM_CONTROL); 540 cm_control.alg_done_clr = 1; 541 MBCS_MMR_SET(mmr_base, MBCS_CM_CONTROL, 542 cm_control.cm_control_reg); 543 atomic_set(&soft->algo_done, 1); 544 wake_up(&soft->algo_queue); 545 } 546 547 return IRQ_HANDLED; 548} 549 550/** 551 * mbcs_intr_alloc - Allocate interrupts. 552 * @dev: device pointer 553 * 554 */ 555static int mbcs_intr_alloc(struct cx_dev *dev) 556{ 557 struct sn_irq_info *sn_irq; 558 struct mbcs_soft *soft; 559 struct getdma *getdma; 560 struct putdma *putdma; 561 struct algoblock *algo; 562 563 soft = dev->soft; 564 getdma = &soft->getdma; 565 putdma = &soft->putdma; 566 algo = &soft->algo; 567 568 soft->get_sn_irq = NULL; 569 soft->put_sn_irq = NULL; 570 soft->algo_sn_irq = NULL; 571 572 sn_irq = tiocx_irq_alloc(dev->cx_id.nasid, TIOCX_CORELET, -1, -1, -1); 573 if (sn_irq == NULL) 574 return -EAGAIN; 575 soft->get_sn_irq = sn_irq; 576 getdma->intrHostDest = sn_irq->irq_xtalkaddr; 577 getdma->intrVector = sn_irq->irq_irq; 578 if (request_irq(sn_irq->irq_irq, 579 (void *)mbcs_completion_intr_handler, IRQF_SHARED, 580 "MBCS get intr", (void *)soft)) { 581 tiocx_irq_free(soft->get_sn_irq); 582 return -EAGAIN; 583 } 584 585 sn_irq = tiocx_irq_alloc(dev->cx_id.nasid, TIOCX_CORELET, -1, -1, -1); 586 if (sn_irq == NULL) { 587 free_irq(soft->get_sn_irq->irq_irq, soft); 588 tiocx_irq_free(soft->get_sn_irq); 589 return -EAGAIN; 590 } 591 soft->put_sn_irq = sn_irq; 592 putdma->intrHostDest = sn_irq->irq_xtalkaddr; 593 putdma->intrVector = sn_irq->irq_irq; 594 if (request_irq(sn_irq->irq_irq, 595 (void *)mbcs_completion_intr_handler, IRQF_SHARED, 596 "MBCS put intr", (void *)soft)) { 597 tiocx_irq_free(soft->put_sn_irq); 598 free_irq(soft->get_sn_irq->irq_irq, soft); 599 tiocx_irq_free(soft->get_sn_irq); 600 return -EAGAIN; 601 } 602 603 sn_irq = tiocx_irq_alloc(dev->cx_id.nasid, TIOCX_CORELET, -1, -1, -1); 604 if (sn_irq == NULL) { 605 free_irq(soft->put_sn_irq->irq_irq, soft); 606 tiocx_irq_free(soft->put_sn_irq); 607 free_irq(soft->get_sn_irq->irq_irq, soft); 608 tiocx_irq_free(soft->get_sn_irq); 609 return -EAGAIN; 610 } 611 soft->algo_sn_irq = sn_irq; 612 algo->intrHostDest = sn_irq->irq_xtalkaddr; 613 algo->intrVector = sn_irq->irq_irq; 614 if (request_irq(sn_irq->irq_irq, 615 (void *)mbcs_completion_intr_handler, IRQF_SHARED, 616 "MBCS algo intr", (void *)soft)) { 617 tiocx_irq_free(soft->algo_sn_irq); 618 free_irq(soft->put_sn_irq->irq_irq, soft); 619 tiocx_irq_free(soft->put_sn_irq); 620 free_irq(soft->get_sn_irq->irq_irq, soft); 621 tiocx_irq_free(soft->get_sn_irq); 622 return -EAGAIN; 623 } 624 625 return 0; 626} 627 628/** 629 * mbcs_intr_dealloc - Remove interrupts. 630 * @dev: device pointer 631 * 632 */ 633static void mbcs_intr_dealloc(struct cx_dev *dev) 634{ 635 struct mbcs_soft *soft; 636 637 soft = dev->soft; 638 639 free_irq(soft->get_sn_irq->irq_irq, soft); 640 tiocx_irq_free(soft->get_sn_irq); 641 free_irq(soft->put_sn_irq->irq_irq, soft); 642 tiocx_irq_free(soft->put_sn_irq); 643 free_irq(soft->algo_sn_irq->irq_irq, soft); 644 tiocx_irq_free(soft->algo_sn_irq); 645} 646 647static inline int mbcs_hw_init(struct mbcs_soft *soft) 648{ 649 void *mmr_base = soft->mmr_base; 650 union cm_control cm_control; 651 union cm_req_timeout cm_req_timeout; 652 uint64_t err_stat; 653 654 cm_req_timeout.cm_req_timeout_reg = 655 MBCS_MMR_GET(mmr_base, MBCS_CM_REQ_TOUT); 656 657 cm_req_timeout.time_out = MBCS_CM_CONTROL_REQ_TOUT_MASK; 658 MBCS_MMR_SET(mmr_base, MBCS_CM_REQ_TOUT, 659 cm_req_timeout.cm_req_timeout_reg); 660 661 mbcs_gscr_pioaddr_set(soft); 662 mbcs_debug_pioaddr_set(soft); 663 664 /* clear errors */ 665 err_stat = MBCS_MMR_GET(mmr_base, MBCS_CM_ERR_STAT); 666 MBCS_MMR_SET(mmr_base, MBCS_CM_CLR_ERR_STAT, err_stat); 667 MBCS_MMR_ZERO(mmr_base, MBCS_CM_ERROR_DETAIL1); 668 669 /* enable interrupts */ 670 /* turn off 2^23 (INT_EN_PIO_REQ_ADDR_INV) */ 671 MBCS_MMR_SET(mmr_base, MBCS_CM_ERR_INT_EN, 0x3ffffff7e00ffUL); 672 673 /* arm status regs and clear engines */ 674 cm_control.cm_control_reg = MBCS_MMR_GET(mmr_base, MBCS_CM_CONTROL); 675 cm_control.rearm_stat_regs = 1; 676 cm_control.alg_clr = 1; 677 cm_control.wr_dma_clr = 1; 678 cm_control.rd_dma_clr = 1; 679 680 MBCS_MMR_SET(mmr_base, MBCS_CM_CONTROL, cm_control.cm_control_reg); 681 682 return 0; 683} 684 685static ssize_t show_algo(struct device *dev, struct device_attribute *attr, char *buf) 686{ 687 struct cx_dev *cx_dev = to_cx_dev(dev); 688 struct mbcs_soft *soft = cx_dev->soft; 689 uint64_t debug0; 690 691 /* 692 * By convention, the first debug register contains the 693 * algorithm number and revision. 694 */ 695 debug0 = *(uint64_t *) soft->debug_addr; 696 697 return sprintf(buf, "0x%x 0x%x\n", 698 upper_32_bits(debug0), lower_32_bits(debug0)); 699} 700 701static ssize_t store_algo(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) 702{ 703 int n; 704 struct cx_dev *cx_dev = to_cx_dev(dev); 705 struct mbcs_soft *soft = cx_dev->soft; 706 707 if (count <= 0) 708 return 0; 709 710 n = simple_strtoul(buf, NULL, 0); 711 712 if (n == 1) { 713 mbcs_algo_start(soft); 714 if (wait_event_interruptible(soft->algo_queue, 715 atomic_read(&soft->algo_done))) 716 return -ERESTARTSYS; 717 } 718 719 return count; 720} 721 722DEVICE_ATTR(algo, 0644, show_algo, store_algo); 723 724/** 725 * mbcs_probe - Initialize for device 726 * @dev: device pointer 727 * @device_id: id table pointer 728 * 729 */ 730static int mbcs_probe(struct cx_dev *dev, const struct cx_device_id *id) 731{ 732 struct mbcs_soft *soft; 733 734 dev->soft = NULL; 735 736 soft = kzalloc(sizeof(struct mbcs_soft), GFP_KERNEL); 737 if (soft == NULL) 738 return -ENOMEM; 739 740 soft->nasid = dev->cx_id.nasid; 741 list_add(&soft->list, &soft_list); 742 soft->mmr_base = (void *)tiocx_swin_base(dev->cx_id.nasid); 743 dev->soft = soft; 744 soft->cxdev = dev; 745 746 init_waitqueue_head(&soft->dmawrite_queue); 747 init_waitqueue_head(&soft->dmaread_queue); 748 init_waitqueue_head(&soft->algo_queue); 749 750 mutex_init(&soft->dmawritelock); 751 mutex_init(&soft->dmareadlock); 752 mutex_init(&soft->algolock); 753 754 mbcs_getdma_init(&soft->getdma); 755 mbcs_putdma_init(&soft->putdma); 756 mbcs_algo_init(&soft->algo); 757 758 mbcs_hw_init(soft); 759 760 /* Allocate interrupts */ 761 mbcs_intr_alloc(dev); 762 763 device_create_file(&dev->dev, &dev_attr_algo); 764 765 return 0; 766} 767 768static int mbcs_remove(struct cx_dev *dev) 769{ 770 if (dev->soft) { 771 mbcs_intr_dealloc(dev); 772 kfree(dev->soft); 773 } 774 775 device_remove_file(&dev->dev, &dev_attr_algo); 776 777 return 0; 778} 779 780static const struct cx_device_id mbcs_id_table[] = { 781 { 782 .part_num = MBCS_PART_NUM, 783 .mfg_num = MBCS_MFG_NUM, 784 }, 785 { 786 .part_num = MBCS_PART_NUM_ALG0, 787 .mfg_num = MBCS_MFG_NUM, 788 }, 789 {0, 0} 790}; 791 792MODULE_DEVICE_TABLE(cx, mbcs_id_table); 793 794static struct cx_drv mbcs_driver = { 795 .name = DEVICE_NAME, 796 .id_table = mbcs_id_table, 797 .probe = mbcs_probe, 798 .remove = mbcs_remove, 799}; 800 801static void __exit mbcs_exit(void) 802{ 803 unregister_chrdev(mbcs_major, DEVICE_NAME); 804 cx_driver_unregister(&mbcs_driver); 805} 806 807static int __init mbcs_init(void) 808{ 809 int rv; 810 811 if (!ia64_platform_is("sn2")) 812 return -ENODEV; 813 814 // Put driver into chrdevs[]. Get major number. 815 rv = register_chrdev(mbcs_major, DEVICE_NAME, &mbcs_ops); 816 if (rv < 0) { 817 DBG(KERN_ALERT "mbcs_init: can't get major number. %d\n", rv); 818 return rv; 819 } 820 mbcs_major = rv; 821 822 return cx_driver_register(&mbcs_driver); 823} 824 825module_init(mbcs_init); 826module_exit(mbcs_exit); 827 828MODULE_AUTHOR("Bruce Losure <blosure@sgi.com>"); 829MODULE_DESCRIPTION("Driver for MOATB Core Services"); 830MODULE_LICENSE("GPL");