1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917
|
/*
* Cisco router Simulation Platform.
* Copyright (C) 2005-2006 Christophe Fillot. All rights reserved.
*
* EEPROM types:
* - 0x3d: PA-4B
* - 0x3e: PA-8B
*
* Vernon Missouri offered a PA-4B.
*
* It is based on the Munich32 chip:
* http://www.infineon.com//upload/Document/cmc_upload/migrated_files/document_files/Datasheet/m32_34m.pdf
*
* There is also one TP3420A per BRI port.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
#include <assert.h>
#include "cpu.h"
#include "vm.h"
#include "dynamips.h"
#include "memory.h"
#include "device.h"
#include "net.h"
#include "net_io.h"
#include "ptask.h"
#include "dev_c7200.h"
/* Debugging flags */
#define DEBUG_ACCESS 1
#define DEBUG_TRANSMIT 0
#define DEBUG_RECEIVE 0
/* PCI vendor/product codes */
#define BRI_PCI_VENDOR_ID 0x10ee
#define BRI_PCI_PRODUCT_ID 0x4013
/* Memory used by the munich32 chip */
#define MUNICH32_MEM_SIZE 0x40000
/* Maximum packet size */
#define M32_MAX_PKT_SIZE 8192
/* 32 timeslots and 32 channels for a Munich32 chip */
#define M32_NR_TIMESLOTS 32
#define M32_NR_CHANNELS 32
/* Offsets */
#define M32_OFFSET_TS 0x0c /* Timeslots */
#define M32_OFFSET_CHAN 0x8c /* Channel specification */
#define M32_OFFSET_CRDA 0x28c /* Current RX descriptor address */
#define M32_OFFSET_CTDA 0x30c /* Current TX descriptor address */
/* Action Specification */
#define M32_AS_PCM_MASK 0xE0000000 /* PCM Highway Format */
#define M32_AS_PCM_SHIFT 29
#define M32_AS_MFL_MASK 0x1FFF0000 /* Maximum Frame Length */
#define M32_AS_MFL_SHIFT 16
#define M32_AS_IN 0x00008000 /* Initialization Procedure */
#define M32_AS_ICO 0x00004000 /* Initialize Channel Only */
#define M32_AS_CHAN_MASK 0x00001F00 /* Channel Number */
#define M32_AS_CHAN_SHIFT 8
#define M32_AS_IM 0x00000080 /* Interrupt Mask */
#define M32_AS_RES 0x00000040 /* Reset */
#define M32_AS_LOOPS_MASK 0x00000038 /* Loops (LOC,LOOP,LOOPI) */
#define M32_AS_LOOPS_SHIFT 3
#define M32_AS_IA 0x00000004 /* Interrupt Attention */
/* Interrupt Information */
#define M32_II_INT 0x80000000 /* Interrupt */
#define M32_II_VN3 0x20000000 /* Silicon version number */
#define M32_II_VN2 0x10000000
#define M32_II_VN1 0x08000000
#define M32_II_FRC 0x04000000 /* Framing bits changed */
#define M32_II_ARACK 0x00008000 /* Action Request Acknowledge */
#define M32_II_ARF 0x00004000 /* Action Request Failed */
#define M32_II_HI 0x00002000 /* Host Initiated Interrupt */
#define M32_II_FI 0x00001000 /* Frame Indication */
#define M32_II_IFC 0x00000800 /* Idle Flag Change */
#define M32_II_SF 0x00000400 /* Short Frame */
#define M32_II_ERR 0x00000200 /* Error condition */
#define M32_II_FO 0x00000100 /* Overflow/Underflow */
#define M32_II_RT 0x00000020 /* Direction (Transmit/Receive Int) */
/* Timeslot Assignment */
#define M32_TS_TTI 0x20000000 /* Transmit Timeslot Inhibit */
#define M32_TS_TCN_MASK 0x1F000000 /* Transmit Channel Number Mask */
#define M32_TS_TCN_SHIFT 24
#define M32_TS_TFM_MASK 0x00FF0000 /* Transmit Fill Mask */
#define M32_TS_TFM_SHIFT 16
#define M32_TS_RTI 0x00002000 /* Receive Timeslot Inhibit */
#define M32_TS_RCN_MASK 0x00001F00 /* Receive Channel Number Mask */
#define M32_TS_RCN_SHIFT 8
#define M32_TS_RFM_MASK 0x000000FF /* Receive Fill Mask */
#define M32_TS_RFM_SHIFT 0
/* Transmit Descriptor */
#define M32_TXDESC_FE 0x80000000 /* Frame End */
#define M32_TXDESC_HOLD 0x40000000 /* Hold=0: usable by Munich */
#define M32_TXDESC_HI 0x20000000 /* Host Initiated Interrupt */
#define M32_TXDESC_NO_MASK 0x1FFF0000 /* Number of bytes */
#define M32_TXDESC_NO_SHIFT 16
#define M32_TXDESC_V110 0x00008000 /* V.110/X.30 frame */
#define M32_TXDESC_CSM 0x00000800 /* CRC Select per Message */
#define M32_TXDESC_FNUM 0x000001FF /* Inter-Frame Time-Fill chars */
/* Munich32 TX descriptor */
struct m32_tx_desc {
m_uint32_t params; /* Size + Flags */
m_uint32_t tdp; /* Transmit Data Pointer */
m_uint32_t ntdp; /* Next Transmit Descriptor Pointer */
};
/* Receive Descriptor (parameters) */
#define M32_RXDESC_HOLD 0x40000000 /* Hold */
#define M32_RXDESC_HI 0x20000000 /* Host Initiated Interrupt */
#define M32_RXDESC_NO_MASK 0x1FFF0000 /* Size of receive data section */
#define M32_RXDESC_NO_SHIFT 16
/* Receive Descriptor (status) */
#define M32_RXDESC_FE 0x80000000 /* Frame End */
#define M32_RXDESC_C 0x40000000
#define M32_RXDESC_BNO_MASK 0x1FFF0000 /* Bytes stored in data section */
#define M32_RXDESC_BNO_SHIFT 16
#define M32_RXDESC_SF 0x00004000
#define M32_RXDESC_LOSS 0x00002000 /* Error in sync pattern */
#define M32_RXDESC_CRCO 0x00001000 /* CRC error */
#define M32_RXDESC_NOB 0x00000800 /* Bit content not divisible by 8 */
#define M32_RXDESC_LFD 0x00000400 /* Long Frame Detected */
#define M32_RXDESC_RA 0x00000200 /* Receive Abort */
#define M32_RXDESC_ROF 0x00000100 /* Overflow of internal buffer */
/* Munich32 RX descriptor */
struct m32_rx_desc {
m_uint32_t params; /* RX parameters (hold, hi, ...) */
m_uint32_t status; /* Status */
m_uint32_t rdp; /* Receive Data Pointer */
m_uint32_t nrdp; /* Next Receive Descriptor Pointer */
};
/* Munich32 channel */
struct m32_channel {
m_uint32_t status;
m_uint32_t frda;
m_uint32_t ftda;
m_uint32_t itbs;
/* Physical addresses of current RX and TX descriptors */
m_uint32_t rx_current,tx_current;
/* Poll mode */
u_int poll_mode;
};
/* Munich32 chip data */
struct m32_data {
/* Virtual machine */
vm_instance_t *vm;
/* TX ring scanner task id */
ptask_id_t tx_tid;
/* Interrupt Queue */
m_uint32_t iq_base_addr;
m_uint32_t iq_cur_addr;
u_int iq_size;
/* Timeslots */
m_uint32_t timeslots[M32_NR_TIMESLOTS];
/* Channels */
struct m32_channel channels[M32_NR_CHANNELS];
/* Embedded config memory */
m_uint32_t cfg_mem[MUNICH32_MEM_SIZE/4];
};
/* === TP3420 SID === */
/* Activation / Desactivation */
#define TP3420_SID_NOP 0xFF /* No Operation */
#define TP3420_SID_PDN 0x00 /* Power Down */
#define TP3420_SID_PUP 0x20 /* Power Up */
#define TP3420_SID_DR 0x01 /* Deactivation Request */
#define TP3420_SID_FI2 0x02 /* Force Info 2 (NT Only) */
#define TP3420_SID_MMA 0x1F /* Monitor Mode Activation */
/* Device Modes */
#define TP3420_SID_NTA 0x04 /* NT Mode, Adaptive Sampling */
#define TP3420_SID_NTF 0x05 /* NT Mode, Fixed Sampling */
#define TP3420_SID_TES 0x06 /* TE Mode, Digital System Interface Slave */
#define TP3420_SID_TEM 0x07 /* TE Mode, Digital System Interface Master */
/* Digital Interface Formats */
#define TP3420_SID_DIF1 0x08 /* Digital System Interface Format 1 */
#define TP3420_SID_DIF2 0x09 /* Digital System Interface Format 2 */
#define TP3420_SID_DIF3 0x0A /* Digital System Interface Format 3 */
#define TP3420_SID_DIF4 0x0B /* Digital System Interface Format 4 */
/* BCLK Frequency Settings */
#define TP3420_SID_BCLK1 0x98 /* Set BCLK to 2.048 Mhz */
#define TP3420_SID_BCLK2 0x99 /* Set BCLK to 256 Khz */
#define TP3420_SID_BCLK3 0x9A /* Set BCLK to 512 Khz */
#define TP3420_SID_BCLK4 0x9B /* Set BCLK to 2.56 Mhz */
/* B Channel Exchange */
#define TP3420_SID_BDIR 0x0C /* B Channels Mapped Direct (B1->B1,B2->B2) */
#define TP3420_SID_BEX 0x0D /* B Channels Exchanged (B1->B2,B2->B1) */
/* D Channel Access */
#define TP3420_SID_DREQ1 0x0E /* D Channel Request, Class 1 Message */
#define TP3420_SID_DREQ2 0x0F /* D Channel Request, Class 2 Message */
/* D Channel Access Control */
#define TP3420_SID_DACCE 0x90 /* Enable D-Channel Access Mechanism */
#define TP3420_SID_DACCD 0x91 /* Disable D-Channel Access Mechanism */
#define TP3420_SID_EBIT0 0x96 /* Force Echo Bit to 0 */
#define TP3420_SID_EBITI 0x97 /* Force Echo Bit to Inverted Received D bit */
#define TP3420_SID_EBITN 0x9C /* Reset EBITI and EBIT0 to Normal Condition */
#define TP3420_SID_DCKE 0xF1 /* D Channel Clock Enable */
/* End Of Message (EOM) Interrupt */
#define TP3420_SID_EIE 0x10 /* EOM Interrupt Enabled */
#define TP3420_SID_EID 0x11 /* EOM Interrupt Disabled */
/* B1 Channel Enable/Disable */
#define TP3420_SID_B1E 0x14 /* B1 Channel Enabled */
#define TP3420_SID_B1D 0x15 /* B1 Channel Disabled */
/* B2 Channel Enable/Disable */
#define TP3420_SID_B2E 0x16 /* B2 Channel Enabled */
#define TP3420_SID_B2D 0x17 /* B2 Channel Disabled */
/* Loopback Tests Modes */
#define TP3420_SID_CAL 0x1B /* Clear All Loopbacks */
/* Control Device State Reading */
#define TP3420_SID_ENST 0x92 /* Enable the Device State Output on NOCST */
#define TP3420_SID_DISST 0x93 /* Disable the Device State Output on NOCST */
/* PIN Signal Selection */
#define TP3420_SID_PINDEF 0xE0 /* Redefine PIN signals */
/* TP3420 Status Register */
#define TP3420_SR_LSD 0x02 /* Line Signal Detected Far-End */
#define TP3420_SR_AP 0x03 /* Activation Pending */
#define TP3420_SR_AI 0x0C /* Activation Indication */
#define TP3420_SR_EI 0x0E /* Error Indication */
#define TP3420_SR_DI 0x0F /* Deactivation Indication */
#define TP3420_SR_EOM 0x06 /* End of D-channel TX message */
#define TP3420_SR_CON 0x07 /* Lost Contention for D channel */
/* NO Change Return status */
#define TP3420_SR_NOC 0x00 /* NOC Status after DISST command */
#define TP3420_SR_NOCST 0x80 /* NOC Status after ENST command */
/* BRI Channel Index */
#define BRI_CHAN_INDEX_B1 0
#define BRI_CHAN_INDEX_B2 1
#define BRI_CHAN_INDEX_D 2
/* PA-4B Data */
struct pa_4b_data {
char *name;
/* Virtual machine */
vm_instance_t *vm;
/* Virtual device */
struct vdevice *dev;
/* PCI device information */
struct pci_device *pci_dev;
/* NetIO descriptor */
netio_desc_t *nio;
/* Munich32 data and base offset */
struct m32_data m32_data;
u_int m32_offset;
};
/* Log a PA-4B/PA-8B message */
#define BRI_LOG(d,msg...) vm_log((d)->vm,(d)->name,msg)
/* Read a configuration word */
static inline m_uint32_t m32_get_cfgw(struct m32_data *d,m_uint32_t offset)
{
return(d->cfg_mem[offset >> 2]);
}
/* Write a configuration word */
static inline void m32_set_cfgw(struct m32_data *d,m_uint32_t offset,
m_uint32_t val)
{
d->cfg_mem[offset >> 2] = val;
}
/* Post an interrupt into the interrupt queue */
static int m32_post_interrupt(struct m32_data *d,m_uint32_t iq_value)
{
if (!d->iq_base_addr)
return(-1);
/* The INT bit is mandatory */
iq_value |= M32_II_INT;
#if 0
printf("M32: Posting interrupt iq_val=0x%8.8x at 0x%8.8x\n",
iq_value,d->iq_cur_addr);
#endif
physmem_copy_u32_to_vm(d->vm,d->iq_cur_addr,iq_value);
d->iq_cur_addr += sizeof(m_uint32_t);
if (d->iq_cur_addr >= (d->iq_base_addr + d->iq_size))
d->iq_cur_addr = d->iq_base_addr;
return(0);
}
/* Fetch a timeslot assignment */
static int m32_fetch_ts_assign(struct m32_data *d,u_int ts_id)
{
m_uint32_t offset;
offset = M32_OFFSET_TS + (ts_id * sizeof(m_uint32_t));
d->timeslots[ts_id] = m32_get_cfgw(d,offset);
return(0);
}
/* Fetch all timeslot assignments */
static int m32_fetch_all_ts(struct m32_data *d)
{
m_uint32_t offset = M32_OFFSET_TS;
u_int i;
for(i=0;i<M32_NR_TIMESLOTS;i++,offset+=sizeof(m_uint32_t))
d->timeslots[i] = m32_get_cfgw(d,offset);
return(0);
}
/* Show timeslots assignments (debugging) */
static void m32_show_ts_assign(struct m32_data *d)
{
m_uint32_t ts;
u_int i;
printf("MUNICH32 timeslots:\n");
for(i=0;i<M32_NR_TIMESLOTS;i++) {
ts = d->timeslots[i];
if ((ts & (M32_TS_TTI|M32_TS_RTI)) != (M32_TS_TTI|M32_TS_RTI)) {
printf(" Timeslot %2u: ",i);
if (!(ts & M32_TS_TTI)) {
printf("TCN=%2u TFM=0x%2.2x ",
(ts & M32_TS_TCN_MASK) >> M32_TS_TCN_SHIFT,
(ts & M32_TS_TFM_MASK) >> M32_TS_TFM_SHIFT);
}
if (!(ts & M32_TS_RTI)) {
printf("RCN=%2u RFM=0x%2.2x",
(ts & M32_TS_RCN_MASK) >> M32_TS_RCN_SHIFT,
(ts & M32_TS_RFM_MASK) >> M32_TS_RFM_SHIFT);
}
printf("\n");
}
}
printf("\n");
}
/* Show info about a channels (debugging) */
static void m32_show_channel(struct m32_data *d,u_int chan_id)
{
struct m32_channel *chan;
chan = &d->channels[chan_id];
printf("M32 Channel %u:\n",chan_id);
printf(" Status : 0x%8.8x\n",chan->status);
printf(" FRDA : 0x%8.8x\n",chan->frda);
printf(" FTDA : 0x%8.8x\n",chan->ftda);
printf(" ITBS : 0x%8.8x\n",chan->itbs);
}
/* Fetch a channel specification */
static int m32_fetch_chan_spec(struct m32_data *d,u_int chan_id)
{
struct m32_channel *chan;
m_uint32_t offset;
offset = M32_OFFSET_CHAN + (chan_id * 4 * sizeof(m_uint32_t));
chan = &d->channels[chan_id];
chan->status = m32_get_cfgw(d,offset);
chan->frda = m32_get_cfgw(d,offset+4);
chan->ftda = m32_get_cfgw(d,offset+8);
chan->itbs = m32_get_cfgw(d,offset+12);
chan->poll_mode = 0;
chan->rx_current = chan->frda;
chan->tx_current = chan->ftda;
m32_set_cfgw(d,M32_OFFSET_CTDA+(chan_id*4),chan->tx_current);
#if 1
if (chan_id == 2) {
printf("M32: Fetched channel %u\n",chan_id);
//m32_show_ts_assign(d);
m32_show_channel(d,chan_id);
}
#endif
return(0);
}
/* Fetch all channel specifications */
static void m32_fetch_all_chan_spec(struct m32_data *d)
{
u_int i;
for(i=0;i<M32_NR_CHANNELS;i++)
m32_fetch_chan_spec(d,i);
}
/* Try to acquire the specified TX descriptor */
static int m32_tx_acquire(struct m32_data *d,m_uint32_t txd_addr,
struct m32_tx_desc *txd)
{
m_uint32_t params;
if (!(params = physmem_copy_u32_from_vm(d->vm,txd_addr)) & M32_TXDESC_HOLD)
return(FALSE);
txd->params = params;
txd->tdp = physmem_copy_u32_from_vm(d->vm,txd_addr+4);
txd->ntdp = physmem_copy_u32_from_vm(d->vm,txd_addr+8);
return(TRUE);
}
/* Try to acquire the next TX descriptor */
static int m32_tx_acquire_next(struct m32_data *d,m_uint32_t *txd_addr)
{
m_uint32_t params;
/* HOLD bit must be reset */
if ((params = physmem_copy_u32_from_vm(d->vm,*txd_addr)) & M32_TXDESC_HOLD)
return(FALSE);
*txd_addr = physmem_copy_u32_from_vm(d->vm,(*txd_addr)+8);
return(TRUE);
}
/* Scan a channel TX ring */
static inline int m32_tx_scan(struct m32_data *d,u_int chan_id)
{
struct m32_channel *chan = &d->channels[chan_id];
m_uint8_t pkt[M32_MAX_PKT_SIZE];
struct m32_tx_desc txd;
m_uint32_t pkt_len;
if (!chan->tx_current)
return(FALSE);
switch(chan->poll_mode) {
case 0:
m32_set_cfgw(d,M32_OFFSET_CTDA+(chan_id*4),chan->tx_current);
/* Try to transmit data */
if (!m32_tx_acquire(d,chan->tx_current,&txd))
return(FALSE);
printf("M32: TX scanner for channel %u (tx_current=0x%8.8x)\n",
chan_id,chan->tx_current);
printf("M32: params=0x%8.8x, next=0x%8.8x.\n",txd.params,txd.ntdp);
/* The descriptor has been acquired */
pkt_len = (txd.params & M32_TXDESC_NO_MASK) >> M32_TXDESC_NO_SHIFT;
physmem_copy_from_vm(d->vm,pkt,txd.tdp,pkt_len);
printf("M32: data_ptr=0x%x, len=%u\n",txd.tdp,pkt_len);
mem_dump(stdout,pkt,pkt_len);
/* Poll the next descriptor (wait for HOLD bit to be reset) */
chan->poll_mode = 1;
if (txd.params & M32_TXDESC_FE) {
m32_post_interrupt(d,M32_II_FI | chan_id);
vm_set_irq(d->vm,2);
}
break;
case 1:
if (!m32_tx_acquire_next(d,&chan->tx_current))
return(FALSE);
printf("M32: branching on next descriptor 0x%x\n",chan->tx_current);
chan->poll_mode = 0;
break;
}
return(TRUE);
}
/* Scan the all channel TX rings */
static void m32_tx_scan_all_channels(struct m32_data *d)
{
u_int i;
for(i=0;i<M32_NR_CHANNELS;i++)
m32_tx_scan(d,i);
}
/*
* Handle an action request.
*
* IN, ICO and RES bits are mutually exclusive.
*/
static int m32_action_req(struct m32_data *d,m_uint32_t action)
{
u_int chan_id;
/* Define a new Interrupt Queue */
if (action & M32_AS_IA) {
d->iq_base_addr = d->iq_cur_addr = m32_get_cfgw(d,4);
d->iq_size = ((m32_get_cfgw(d,8) & 0xFF) + 1) * 16 * sizeof(m_uint32_t);
}
/* Initialization Procedure */
if (action & M32_AS_IN) {
/* Fetch all timeslots assignments */
m32_fetch_all_ts(d);
/* Fetch specification of the specified channel */
chan_id = (action & M32_AS_CHAN_MASK) >> M32_AS_CHAN_SHIFT;
m32_fetch_chan_spec(d,chan_id);
/* Generate acknowledge */
if (!(action & M32_AS_IM))
m32_post_interrupt(d,M32_II_ARACK);
}
/* Initialize Channel Only */
if (action & M32_AS_ICO) {
/* Fetch specification of the specified channel */
chan_id = (action & M32_AS_CHAN_MASK) >> M32_AS_CHAN_SHIFT;
m32_fetch_chan_spec(d,chan_id);
/* Generate acknowledge */
if (!(action & M32_AS_IM))
m32_post_interrupt(d,M32_II_ARACK);
}
/* Reset */
if (action & M32_AS_RES) {
/* Fetch all timeslots assignments */
m32_fetch_all_ts(d);
/* Fetch all channel specifications */
m32_fetch_all_chan_spec(d);
/* Generate acknowledge */
if (!(action & M32_AS_IM))
m32_post_interrupt(d,M32_II_ARACK);
}
return(0);
}
/* Munich32 general access function */
static void *m32_gen_access(struct m32_data *d,cpu_gen_t *cpu,
m_uint32_t offset,u_int op_size,u_int op_type,
m_uint64_t *data)
{
u_int p;
switch(offset) {
/* Action Specification */
case 0x0:
if (op_type == MTS_WRITE)
m32_action_req(d,*data);
return NULL;
/* Configuration memory */
default:
switch(op_size) {
case 4:
if (op_type == MTS_READ)
*data = m32_get_cfgw(d,offset);
else
m32_set_cfgw(d,offset,*data);
break;
case 1:
if (op_type == MTS_READ) {
*data = m32_get_cfgw(d,offset & ~0x03);
*data >>= (24 - ((offset & 0x03) << 3));
*data &= 0xFF;
} else {
printf("UNSUPPORTED(1)!!!!\n");
}
break;
case 2:
if (op_type == MTS_READ) {
*data = m32_get_cfgw(d,offset & ~0x03);
*data >>= (16 - ((offset & 0x03) << 3));
*data &= 0xFFFF;
} else {
printf("UNSUPPORTED(2)!!!!\n");
}
break;
case 8:
if (op_type == MTS_READ) {
*data = (m_uint64_t)m32_get_cfgw(d,offset) << 32;
*data |= m32_get_cfgw(d,offset+4);
} else {
printf("UNSUPPORTED(8)!!!!\n");
}
break;
default:
printf("UNSUPPORTED (size=%u)!!!\n",op_size);
}
}
return NULL;
}
/*
* pa_4b_access()
*/
void *pa_4b_access(cpu_gen_t *cpu,struct vdevice *dev,m_uint32_t offset,
u_int op_size,u_int op_type,m_uint64_t *data)
{
struct pa_4b_data *d = dev->priv_data;
static m_uint32_t test1,test2,test3;
if (op_type == MTS_READ)
*data = 0xFFFFFFFF;
#if DEBUG_ACCESS
if (offset >= MUNICH32_MEM_SIZE) {
if (op_type == MTS_READ) {
cpu_log(cpu,d->name,"read access to offset = 0x%x, pc = 0x%llx "
"(op_size=%u)\n",offset,cpu_get_pc(cpu),op_size);
} else {
cpu_log(cpu,d->name,"write access to vaddr = 0x%x, pc = 0x%llx, "
"val = 0x%llx (op_size=%u)\n",
offset,cpu_get_pc(cpu),*data,op_size);
}
}
#endif
/* Specific cases */
switch(offset) {
case 0x40008:
if (op_type == MTS_READ)
*data = 0xFF;
break;
case 0x40030:
if (op_type == MTS_READ)
*data = 0xFF;
break;
case 0x40000:
if (op_type == MTS_READ)
*data = 0xFFFF;
break;
case 0x40020:
if (op_type == MTS_READ)
*data = 0xFFFFFFFF; //test2;
else
test2 = *data;
break;
case 0x40021:
if (op_type == MTS_READ)
*data = 0xFF; //test3;
else
test3 = *data;
break;
case 0x40023:
if (op_type == MTS_READ)
*data = 0xFF;
break;
case 0x40040:
if (op_type == MTS_READ)
*data = 0x04;
break;
/* Channels enabled ? */
case 0x40044:
if (op_type == MTS_READ)
*data = 0xFF; /* 0x02 */
break;
/* SID */
case 0x40050:
if (op_type == MTS_WRITE) {
test1 = *data;
} else {
switch(test1) {
case TP3420_SID_PUP:
*data = TP3420_SR_AI;
vm_set_irq(d->vm,C7200_PA_MGMT_IRQ);
break;
case TP3420_SID_ENST:
*data = 0xB0;
break;
default:
*data = 0x03;
break;
}
}
break;
default:
if (offset < MUNICH32_MEM_SIZE)
return(m32_gen_access(&d->m32_data,cpu,offset - d->m32_offset,
op_size,op_type,data));
}
return NULL;
}
/*
* pci_munich32_read()
*/
static m_uint32_t pci_munich32_read(cpu_gen_t *cpu,struct pci_device *dev,
int reg)
{
struct pa_4b_data *d = dev->priv_data;
#if DEBUG_ACCESS
BRI_LOG(d,"read PCI register 0x%x\n",reg);
#endif
switch(reg) {
case PCI_REG_BAR0:
return(d->dev->phys_addr);
default:
return(0);
}
}
/*
* pci_munich32_write()
*/
static void pci_munich32_write(cpu_gen_t *cpu,struct pci_device *dev,
int reg,m_uint32_t value)
{
struct pa_4b_data *d = dev->priv_data;
#if DEBUG_ACCESS
BRI_LOG(d,"write 0x%x to PCI register 0x%x\n",value,reg);
#endif
switch(reg) {
case PCI_REG_BAR0:
vm_map_device(cpu->vm,d->dev,(m_uint64_t)value);
BRI_LOG(d,"registers are mapped at 0x%x\n",value);
break;
}
}
/*
* dev_c7200_bri_init()
*
* Add a PA-4B/PA-8B port adapter into specified slot.
*/
int dev_c7200_pa_bri_init(vm_instance_t *vm,struct cisco_card *card)
{
u_int slot = card->slot_id;
struct pci_device *pci_dev;
struct pa_4b_data *d;
struct vdevice *dev;
/* Allocate the private data structure for PA-4B chip */
if (!(d = malloc(sizeof(*d)))) {
vm_error(vm,"%s: out of memory\n",card->dev_name);
return(-1);
}
memset(d,0,sizeof(*d));
d->m32_offset = 0x08;
d->m32_data.vm = vm;
/* Set the PCI bus */
card->pci_bus = vm->slots_pci_bus[slot];
/* Set the EEPROM */
cisco_card_set_eeprom(vm,card,cisco_eeprom_find_pa("PA-4B"));
c7200_set_slot_eeprom(VM_C7200(vm),slot,&card->eeprom);
/* Add as PCI device PA-4B */
pci_dev = pci_dev_add(card->pci_bus,card->dev_name,
BRI_PCI_VENDOR_ID,BRI_PCI_PRODUCT_ID,
0,0,C7200_NETIO_IRQ,d,
NULL,pci_munich32_read,pci_munich32_write);
if (!pci_dev) {
vm_error(vm,"%s: unable to create PCI device.\n",card->dev_name);
return(-1);
}
/* Create the PA-4B structure */
d->name = card->dev_name;
d->pci_dev = pci_dev;
d->vm = vm;
/* Create the device itself */
if (!(dev = dev_create(card->dev_name))) {
vm_error(vm,"%s: unable to create device.\n",card->dev_name);
return(-1);
}
dev->phys_len = 0x800000;
dev->handler = pa_4b_access;
/* Store device info */
dev->priv_data = d;
d->dev = dev;
/* Store device info into the router structure */
card->drv_info = d;
return(0);
}
/* Remove a PA-4B from the specified slot */
int dev_c7200_pa_bri_shutdown(vm_instance_t *vm,struct cisco_card *card)
{
struct pa_4b_data *d = card->drv_info;
/* Remove the PA EEPROM */
cisco_card_unset_eeprom(card);
c7200_set_slot_eeprom(VM_C7200(vm),card->slot_id,NULL);
/* Remove the PCI device */
pci_dev_remove(d->pci_dev);
/* Remove the device from the CPU address space */
vm_unbind_device(vm,d->dev);
cpu_group_rebuild_mts(vm->cpu_group);
/* Free the device structure itself */
free(d->dev);
free(d);
return(0);
}
/* Bind a Network IO descriptor to a specific port */
int dev_c7200_pa_bri_set_nio(vm_instance_t *vm,struct cisco_card *card,
u_int port_id,netio_desc_t *nio)
{
struct pa_4b_data *d = card->drv_info;
if (!d || (port_id > 0))
return(-1);
if (d->nio != NULL)
return(-1);
d->nio = nio;
/* TEST */
d->m32_data.tx_tid = ptask_add((ptask_callback)m32_tx_scan_all_channels,
&d->m32_data,NULL);
//netio_rxl_add(nio,(netio_rx_handler_t)dev_pa_4b_handle_rxring,d,NULL);
return(0);
}
/* Bind a Network IO descriptor to a specific port */
int dev_c7200_pa_bri_unset_nio(vm_instance_t *vm,struct cisco_card *card,
u_int port_id)
{
struct pa_4b_data *d = card->drv_info;
if (!d || (port_id > 0))
return(-1);
if (d->nio) {
/* TEST */
ptask_remove(d->m32_data.tx_tid);
//netio_rxl_remove(d->nio);
d->nio = NULL;
}
return(0);
}
/* PA-4B driver */
struct cisco_card_driver dev_c7200_pa_4b_driver = {
"PA-4B", 0, 0,
dev_c7200_pa_bri_init,
dev_c7200_pa_bri_shutdown,
NULL,
dev_c7200_pa_bri_set_nio,
dev_c7200_pa_bri_unset_nio,
NULL,
};
|