Annotation of sys/dev/ic/pdq.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: pdq.c,v 1.13 2007/02/14 00:53:48 jsg Exp $ */
! 2: /* $NetBSD: pdq.c,v 1.9 1996/10/13 01:37:26 christos Exp $ */
! 3:
! 4: /*-
! 5: * Copyright (c) 1995,1996 Matt Thomas <matt@3am-software.com>
! 6: * All rights reserved.
! 7: *
! 8: * Redistribution and use in source and binary forms, with or without
! 9: * modification, are permitted provided that the following conditions
! 10: * are met:
! 11: * 1. Redistributions of source code must retain the above copyright
! 12: * notice, this list of conditions and the following disclaimer.
! 13: * 2. The name of the author may not be used to endorse or promote products
! 14: * derived from this software without specific prior written permission
! 15: *
! 16: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 17: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 18: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 19: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
! 20: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
! 21: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
! 22: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
! 23: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 24: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
! 25: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 26: *
! 27: * Id: pdq.c,v 1.27 1996/06/07 20:02:25 thomas Exp
! 28: *
! 29: */
! 30:
! 31: /*
! 32: * DEC PDQ FDDI Controller O/S independent code
! 33: *
! 34: * This module should work any PDQ based board. Note that changes for
! 35: * MIPS and Alpha architectures (or any other architecture which requires
! 36: * a flushing of memory or write buffers and/or has incoherent caches)
! 37: * have yet to be made.
! 38: *
! 39: * However, it is expected that the PDQ_CSR_WRITE macro will cause a
! 40: * flushing of the write buffers.
! 41: */
! 42:
! 43: #define PDQ_HWSUPPORT /* for pdq.h */
! 44:
! 45: #include "pdqvar.h"
! 46: #include "pdqreg.h"
! 47:
! 48: #define PDQ_ROUNDUP(n, x) (((n) + ((x) - 1)) & ~((x) - 1))
! 49: #define PDQ_CMD_RX_ALIGNMENT 16
! 50:
! 51: #if (defined(PDQTEST) && !defined(PDQ_NOPRINTF)) || defined(PDQVERBOSE)
! 52: #define PDQ_PRINTF(x) printf x
! 53: #else
! 54: #define PDQ_PRINTF(x) do { } while (0)
! 55: #endif
! 56:
! 57: static const char * const pdq_halt_codes[] = {
! 58: "Selftest Timeout", "Host Bus Parity Error", "Host Directed Fault",
! 59: "Software Fault", "Hardware Fault", "PC Trace Path Test",
! 60: "DMA Error", "Image CRC Error", "Adapter Processer Error"
! 61: };
! 62:
! 63: static const char * const pdq_adapter_states[] = {
! 64: "Reset", "Upgrade", "DMA Unavailable", "DMA Available",
! 65: "Link Available", "Link Unavailable", "Halted", "Ring Member"
! 66: };
! 67:
! 68: /*
! 69: * The following are used in conjunction with
! 70: * unsolicited events
! 71: */
! 72: static const char * const pdq_entities[] = {
! 73: "Station", "Link", "Phy Port"
! 74: };
! 75:
! 76: static const char * const pdq_station_events[] = {
! 77: "Trace Received"
! 78: };
! 79:
! 80: static const char * const pdq_station_arguments[] = {
! 81: "Reason"
! 82: };
! 83:
! 84: static const char * const pdq_link_events[] = {
! 85: "Transmit Underrun",
! 86: "Transmit Failed",
! 87: "Block Check Error (CRC)",
! 88: "Frame Status Error",
! 89: "PDU Length Error",
! 90: NULL,
! 91: NULL,
! 92: "Receive Data Overrun",
! 93: NULL,
! 94: "No User Buffer",
! 95: "Ring Initialization Initiated",
! 96: "Ring Initialization Received",
! 97: "Ring Beacon Initiated",
! 98: "Duplicate Address Failure",
! 99: "Duplicate Token Detected",
! 100: "Ring Purger Error",
! 101: "FCI Strip Error",
! 102: "Trace Initiated",
! 103: "Directed Beacon Received",
! 104: };
! 105:
! 106: static const char * const pdq_link_arguments[] = {
! 107: "Reason",
! 108: "Data Link Header",
! 109: "Source",
! 110: "Upstream Neighbor"
! 111: };
! 112:
! 113: static const char * const pdq_phy_events[] = {
! 114: "LEM Error Monitor Reject",
! 115: "Elasticy Buffer Error",
! 116: "Link Confidence Test Reject"
! 117: };
! 118:
! 119: static const char * const pdq_phy_arguments[] = {
! 120: "Direction"
! 121: };
! 122:
! 123: static const char * const * const pdq_event_arguments[] = {
! 124: pdq_station_arguments,
! 125: pdq_link_arguments,
! 126: pdq_phy_arguments
! 127: };
! 128:
! 129: static const char * const * const pdq_event_codes[] = {
! 130: pdq_station_events,
! 131: pdq_link_events,
! 132: pdq_phy_events
! 133: };
! 134:
! 135: static const char * const pdq_station_types[] = {
! 136: "SAS", "DAC", "SAC", "NAC", "DAS"
! 137: };
! 138:
! 139: static const char * const pdq_smt_versions[] = { "", "V6.2", "V7.2", "V7.3" };
! 140:
! 141: static const char pdq_phy_types[] = "ABSM";
! 142:
! 143: static const char * const pdq_pmd_types0[] = {
! 144: "ANSI Multi-Mode", "ANSI Single-Mode Type 1", "ANSI Single-Mode Type 2",
! 145: "ANSI Sonet"
! 146: };
! 147:
! 148: static const char * const pdq_pmd_types100[] = {
! 149: "Low Power", "Thin Wire", "Shielded Twisted Pair",
! 150: "Unshielded Twisted Pair"
! 151: };
! 152:
! 153: static const char * const * const pdq_pmd_types[] = {
! 154: pdq_pmd_types0, pdq_pmd_types100
! 155: };
! 156:
! 157: static const char * const pdq_descriptions[] = {
! 158: "DEFPA PCI",
! 159: "DEFEA EISA",
! 160: "DEFTA TC",
! 161: "DEFAA Futurebus",
! 162: "DEFQA Q-bus",
! 163: };
! 164:
! 165: static void
! 166: pdq_print_fddi_chars(
! 167: pdq_t *pdq,
! 168: const pdq_response_status_chars_get_t *rsp)
! 169: {
! 170: const char hexchars[] = "0123456789abcdef";
! 171:
! 172: printf(PDQ_OS_PREFIX "DEC %s FDDI %s Controller\n",
! 173: PDQ_OS_PREFIX_ARGS, pdq_descriptions[pdq->pdq_type],
! 174: pdq_station_types[rsp->status_chars_get.station_type]);
! 175:
! 176: printf(PDQ_OS_PREFIX "FDDI address %c%c:%c%c:%c%c:%c%c:%c%c:%c%c, FW=%c%c%c%c, HW=%c",
! 177: PDQ_OS_PREFIX_ARGS,
! 178: hexchars[pdq->pdq_hwaddr.lanaddr_bytes[0] >> 4],
! 179: hexchars[pdq->pdq_hwaddr.lanaddr_bytes[0] & 0x0F],
! 180: hexchars[pdq->pdq_hwaddr.lanaddr_bytes[1] >> 4],
! 181: hexchars[pdq->pdq_hwaddr.lanaddr_bytes[1] & 0x0F],
! 182: hexchars[pdq->pdq_hwaddr.lanaddr_bytes[2] >> 4],
! 183: hexchars[pdq->pdq_hwaddr.lanaddr_bytes[2] & 0x0F],
! 184: hexchars[pdq->pdq_hwaddr.lanaddr_bytes[3] >> 4],
! 185: hexchars[pdq->pdq_hwaddr.lanaddr_bytes[3] & 0x0F],
! 186: hexchars[pdq->pdq_hwaddr.lanaddr_bytes[4] >> 4],
! 187: hexchars[pdq->pdq_hwaddr.lanaddr_bytes[4] & 0x0F],
! 188: hexchars[pdq->pdq_hwaddr.lanaddr_bytes[5] >> 4],
! 189: hexchars[pdq->pdq_hwaddr.lanaddr_bytes[5] & 0x0F],
! 190: pdq->pdq_fwrev.fwrev_bytes[0], pdq->pdq_fwrev.fwrev_bytes[1],
! 191: pdq->pdq_fwrev.fwrev_bytes[2], pdq->pdq_fwrev.fwrev_bytes[3],
! 192: rsp->status_chars_get.module_rev.fwrev_bytes[0]);
! 193:
! 194: if (rsp->status_chars_get.smt_version_id < PDQ_ARRAY_SIZE(pdq_smt_versions)) {
! 195: printf(", SMT %s\n", pdq_smt_versions[rsp->status_chars_get.smt_version_id]);
! 196: }
! 197:
! 198: printf(PDQ_OS_PREFIX "FDDI Port%s = %c (PMD = %s)",
! 199: PDQ_OS_PREFIX_ARGS,
! 200: rsp->status_chars_get.station_type == PDQ_STATION_TYPE_DAS ? "[A]" : "",
! 201: pdq_phy_types[rsp->status_chars_get.phy_type[0]],
! 202: pdq_pmd_types[rsp->status_chars_get.pmd_type[0] / 100][rsp->status_chars_get.pmd_type[0] % 100]);
! 203:
! 204: if (rsp->status_chars_get.station_type == PDQ_STATION_TYPE_DAS)
! 205: printf(", FDDI Port[B] = %c (PMD = %s)",
! 206: pdq_phy_types[rsp->status_chars_get.phy_type[1]],
! 207: pdq_pmd_types[rsp->status_chars_get.pmd_type[1] / 100][rsp->status_chars_get.pmd_type[1] % 100]);
! 208:
! 209: printf("\n");
! 210: }
! 211:
! 212: static void
! 213: pdq_init_csrs(
! 214: pdq_csrs_t *csrs,
! 215: pdq_bus_t bus,
! 216: pdq_bus_memaddr_t csr_base,
! 217: size_t csrsize)
! 218: {
! 219: csrs->csr_bus = bus;
! 220: csrs->csr_base = csr_base;
! 221: csrs->csr_port_reset = PDQ_CSR_OFFSET(csr_base, 0 * csrsize);
! 222: csrs->csr_host_data = PDQ_CSR_OFFSET(csr_base, 1 * csrsize);
! 223: csrs->csr_port_control = PDQ_CSR_OFFSET(csr_base, 2 * csrsize);
! 224: csrs->csr_port_data_a = PDQ_CSR_OFFSET(csr_base, 3 * csrsize);
! 225: csrs->csr_port_data_b = PDQ_CSR_OFFSET(csr_base, 4 * csrsize);
! 226: csrs->csr_port_status = PDQ_CSR_OFFSET(csr_base, 5 * csrsize);
! 227: csrs->csr_host_int_type_0 = PDQ_CSR_OFFSET(csr_base, 6 * csrsize);
! 228: csrs->csr_host_int_enable = PDQ_CSR_OFFSET(csr_base, 7 * csrsize);
! 229: csrs->csr_type_2_producer = PDQ_CSR_OFFSET(csr_base, 8 * csrsize);
! 230: csrs->csr_cmd_response_producer = PDQ_CSR_OFFSET(csr_base, 10 * csrsize);
! 231: csrs->csr_cmd_request_producer = PDQ_CSR_OFFSET(csr_base, 11 * csrsize);
! 232: csrs->csr_host_smt_producer = PDQ_CSR_OFFSET(csr_base, 12 * csrsize);
! 233: csrs->csr_unsolicited_producer = PDQ_CSR_OFFSET(csr_base, 13 * csrsize);
! 234: }
! 235:
! 236: static void
! 237: pdq_init_pci_csrs(
! 238: pdq_pci_csrs_t *csrs,
! 239: pdq_bus_t bus,
! 240: pdq_bus_memaddr_t csr_base,
! 241: size_t csrsize)
! 242: {
! 243: csrs->csr_bus = bus;
! 244: csrs->csr_base = csr_base;
! 245: csrs->csr_pfi_mode_control = PDQ_CSR_OFFSET(csr_base, 16 * csrsize);
! 246: csrs->csr_pfi_status = PDQ_CSR_OFFSET(csr_base, 17 * csrsize);
! 247: csrs->csr_fifo_write = PDQ_CSR_OFFSET(csr_base, 18 * csrsize);
! 248: csrs->csr_fifo_read = PDQ_CSR_OFFSET(csr_base, 19 * csrsize);
! 249: }
! 250:
! 251: static void
! 252: pdq_flush_databuf_queue(
! 253: pdq_databuf_queue_t *q)
! 254: {
! 255: PDQ_OS_DATABUF_T *pdu;
! 256: for (;;) {
! 257: PDQ_OS_DATABUF_DEQUEUE(q, pdu);
! 258: if (pdu == NULL)
! 259: return;
! 260: PDQ_OS_DATABUF_FREE(pdu);
! 261: }
! 262: }
! 263:
! 264: static pdq_boolean_t
! 265: pdq_do_port_control(
! 266: const pdq_csrs_t * const csrs,
! 267: pdq_uint32_t cmd)
! 268: {
! 269: int cnt = 0;
! 270: PDQ_CSR_WRITE(csrs, csr_host_int_type_0, PDQ_HOST_INT_CSR_CMD_DONE);
! 271: PDQ_CSR_WRITE(csrs, csr_port_control, PDQ_PCTL_CMD_ERROR | cmd);
! 272: while ((PDQ_CSR_READ(csrs, csr_host_int_type_0) & PDQ_HOST_INT_CSR_CMD_DONE) == 0 && cnt < 33000000)
! 273: cnt++;
! 274: PDQ_PRINTF(("CSR cmd spun %d times\n", cnt));
! 275: if (PDQ_CSR_READ(csrs, csr_host_int_type_0) & PDQ_HOST_INT_CSR_CMD_DONE) {
! 276: PDQ_CSR_WRITE(csrs, csr_host_int_type_0, PDQ_HOST_INT_CSR_CMD_DONE);
! 277: return (PDQ_CSR_READ(csrs, csr_port_control) & PDQ_PCTL_CMD_ERROR) ? PDQ_FALSE : PDQ_TRUE;
! 278: }
! 279: /* adapter failure */
! 280: PDQ_ASSERT(0);
! 281: return PDQ_FALSE;
! 282: }
! 283:
! 284: static void
! 285: pdq_read_mla(
! 286: const pdq_csrs_t * const csrs,
! 287: pdq_lanaddr_t *hwaddr)
! 288: {
! 289: pdq_uint32_t data;
! 290:
! 291: PDQ_CSR_WRITE(csrs, csr_port_data_a, 0);
! 292: pdq_do_port_control(csrs, PDQ_PCTL_MLA_READ);
! 293: data = PDQ_CSR_READ(csrs, csr_host_data);
! 294:
! 295: hwaddr->lanaddr_bytes[0] = (data >> 0) & 0xFF;
! 296: hwaddr->lanaddr_bytes[1] = (data >> 8) & 0xFF;
! 297: hwaddr->lanaddr_bytes[2] = (data >> 16) & 0xFF;
! 298: hwaddr->lanaddr_bytes[3] = (data >> 24) & 0xFF;
! 299:
! 300: PDQ_CSR_WRITE(csrs, csr_port_data_a, 1);
! 301: pdq_do_port_control(csrs, PDQ_PCTL_MLA_READ);
! 302: data = PDQ_CSR_READ(csrs, csr_host_data);
! 303:
! 304: hwaddr->lanaddr_bytes[4] = (data >> 0) & 0xFF;
! 305: hwaddr->lanaddr_bytes[5] = (data >> 8) & 0xFF;
! 306: }
! 307:
! 308: static void
! 309: pdq_read_fwrev(
! 310: const pdq_csrs_t * const csrs,
! 311: pdq_fwrev_t *fwrev)
! 312: {
! 313: pdq_uint32_t data;
! 314:
! 315: pdq_do_port_control(csrs, PDQ_PCTL_FW_REV_READ);
! 316: data = PDQ_CSR_READ(csrs, csr_host_data);
! 317:
! 318: fwrev->fwrev_bytes[3] = (data >> 0) & 0xFF;
! 319: fwrev->fwrev_bytes[2] = (data >> 8) & 0xFF;
! 320: fwrev->fwrev_bytes[1] = (data >> 16) & 0xFF;
! 321: fwrev->fwrev_bytes[0] = (data >> 24) & 0xFF;
! 322: }
! 323:
! 324: static pdq_boolean_t
! 325: pdq_read_error_log(
! 326: pdq_t *pdq,
! 327: pdq_response_error_log_get_t *log_entry)
! 328: {
! 329: const pdq_csrs_t * const csrs = &pdq->pdq_csrs;
! 330: pdq_uint32_t *ptr = (pdq_uint32_t *) log_entry;
! 331:
! 332: pdq_do_port_control(csrs, PDQ_PCTL_ERROR_LOG_START);
! 333:
! 334: while (pdq_do_port_control(csrs, PDQ_PCTL_FW_REV_READ) == PDQ_TRUE) {
! 335: *ptr++ = PDQ_CSR_READ(csrs, csr_host_data);
! 336: if ((pdq_uint8_t *) ptr - (pdq_uint8_t *) log_entry == sizeof(*log_entry))
! 337: break;
! 338: }
! 339: return (ptr == (pdq_uint32_t *) log_entry) ? PDQ_FALSE : PDQ_TRUE;
! 340: }
! 341:
! 342: static pdq_chip_rev_t
! 343: pdq_read_chiprev(
! 344: const pdq_csrs_t * const csrs)
! 345: {
! 346: pdq_uint32_t data;
! 347:
! 348: PDQ_CSR_WRITE(csrs, csr_port_data_a, PDQ_SUB_CMD_PDQ_REV_GET);
! 349: pdq_do_port_control(csrs, PDQ_PCTL_SUB_CMD);
! 350: data = PDQ_CSR_READ(csrs, csr_host_data);
! 351:
! 352: return (pdq_chip_rev_t) data;
! 353: }
! 354:
! 355: static const struct {
! 356: size_t cmd_len;
! 357: size_t rsp_len;
! 358: const char *cmd_name;
! 359: } pdq_cmd_info[] = {
! 360: { sizeof(pdq_cmd_generic_t), /* 0 - PDQC_START */
! 361: sizeof(pdq_response_generic_t),
! 362: "Start"
! 363: },
! 364: { sizeof(pdq_cmd_filter_set_t), /* 1 - PDQC_FILTER_SET */
! 365: sizeof(pdq_response_generic_t),
! 366: "Filter Set"
! 367: },
! 368: { sizeof(pdq_cmd_generic_t), /* 2 - PDQC_FILTER_GET */
! 369: sizeof(pdq_response_filter_get_t),
! 370: "Filter Get"
! 371: },
! 372: { sizeof(pdq_cmd_chars_set_t), /* 3 - PDQC_CHARS_SET */
! 373: sizeof(pdq_response_generic_t),
! 374: "Chars Set"
! 375: },
! 376: { sizeof(pdq_cmd_generic_t), /* 4 - PDQC_STATUS_CHARS_GET */
! 377: sizeof(pdq_response_status_chars_get_t),
! 378: "Status Chars Get"
! 379: },
! 380: #if 0
! 381: { sizeof(pdq_cmd_generic_t), /* 5 - PDQC_COUNTERS_GET */
! 382: sizeof(pdq_response_counters_get_t),
! 383: "Counters Get"
! 384: },
! 385: { sizeof(pdq_cmd_counters_set_t), /* 6 - PDQC_COUNTERS_SET */
! 386: sizeof(pdq_response_generic_t),
! 387: "Counters Set"
! 388: },
! 389: #else
! 390: { 0, 0, "Counters Get" },
! 391: { 0, 0, "Counters Set" },
! 392: #endif
! 393: { sizeof(pdq_cmd_addr_filter_set_t), /* 7 - PDQC_ADDR_FILTER_SET */
! 394: sizeof(pdq_response_generic_t),
! 395: "Addr Filter Set"
! 396: },
! 397: { sizeof(pdq_cmd_generic_t), /* 8 - PDQC_ADDR_FILTER_GET */
! 398: sizeof(pdq_response_addr_filter_get_t),
! 399: "Addr Filter Get"
! 400: },
! 401: #if 0
! 402: { sizeof(pdq_cmd_generic_t), /* 9 - PDQC_ERROR_LOG_CLEAR */
! 403: sizeof(pdq_response_generic_t),
! 404: "Error Log Clear"
! 405: },
! 406: { sizeof(pdq_cmd_generic_t), /* 10 - PDQC_ERROR_LOG_SET */
! 407: sizeof(pdq_response_generic_t),
! 408: "Error Log Set"
! 409: },
! 410: { sizeof(pdq_cmd_generic_t), /* 11 - PDQC_FDDI_MIB_GET */
! 411: sizeof(pdq_response_generic_t),
! 412: "FDDI MIB Get"
! 413: },
! 414: { sizeof(pdq_cmd_generic_t), /* 12 - PDQC_DEC_EXT_MIB_GET */
! 415: sizeof(pdq_response_generic_t),
! 416: "DEC Ext MIB Get"
! 417: },
! 418: { sizeof(pdq_cmd_generic_t), /* 13 - PDQC_DEC_SPECIFIC_GET */
! 419: sizeof(pdq_response_generic_t),
! 420: "DEC Specific Get"
! 421: },
! 422: { sizeof(pdq_cmd_generic_t), /* 14 - PDQC_SNMP_SET */
! 423: sizeof(pdq_response_generic_t),
! 424: "SNMP Set"
! 425: },
! 426: { 0, 0, "N/A" },
! 427: { sizeof(pdq_cmd_generic_t), /* 16 - PDQC_SMT_MIB_GET */
! 428: sizeof(pdq_response_generic_t),
! 429: "SMT MIB Get"
! 430: },
! 431: { sizeof(pdq_cmd_generic_t), /* 17 - PDQC_SMT_MIB_SET */
! 432: sizeof(pdq_response_generic_t),
! 433: "SMT MIB Set",
! 434: },
! 435: #endif
! 436: };
! 437:
! 438: static void
! 439: pdq_queue_commands(
! 440: pdq_t *pdq)
! 441: {
! 442: const pdq_csrs_t * const csrs = &pdq->pdq_csrs;
! 443: pdq_command_info_t * const ci = &pdq->pdq_command_info;
! 444: pdq_descriptor_block_t * const dbp = pdq->pdq_dbp;
! 445: pdq_cmd_code_t op;
! 446: pdq_uint32_t cmdlen, rsplen, mask;
! 447:
! 448: /*
! 449: * If there are commands or responses active or there aren't
! 450: * any pending commands, then don't queue any more.
! 451: */
! 452: if (ci->ci_command_active || ci->ci_pending_commands == 0)
! 453: return;
! 454:
! 455: /*
! 456: * Determine which command needs to be queued.
! 457: */
! 458: op = PDQC_SMT_MIB_SET;
! 459: for (mask = 1 << ((int) op); (mask & ci->ci_pending_commands) == 0; mask >>= 1)
! 460: op = (pdq_cmd_code_t) ((int) op - 1);
! 461: /*
! 462: * Obtain the sizes needed for the command and response.
! 463: * Round up to PDQ_CMD_RX_ALIGNMENT so the receive buffer is
! 464: * always properly aligned.
! 465: */
! 466: cmdlen = PDQ_ROUNDUP(pdq_cmd_info[op].cmd_len, PDQ_CMD_RX_ALIGNMENT);
! 467: rsplen = PDQ_ROUNDUP(pdq_cmd_info[op].rsp_len, PDQ_CMD_RX_ALIGNMENT);
! 468: if (cmdlen < rsplen)
! 469: cmdlen = rsplen;
! 470: /*
! 471: * Since only one command at a time will be queued, there will always
! 472: * be enough space.
! 473: */
! 474:
! 475: /*
! 476: * Obtain and fill in the descriptor for the command (descriptor is
! 477: * pre-initialized)
! 478: */
! 479: dbp->pdqdb_command_requests[ci->ci_request_producer].txd_seg_len = cmdlen;
! 480: PDQ_ADVANCE(ci->ci_request_producer, 1, PDQ_RING_MASK(dbp->pdqdb_command_requests));
! 481:
! 482: /*
! 483: * Obtain and fill in the descriptor for the response (descriptor is
! 484: * pre-initialized)
! 485: */
! 486: dbp->pdqdb_command_responses[ci->ci_response_producer].rxd_seg_len_hi = cmdlen / 16;
! 487: PDQ_ADVANCE(ci->ci_response_producer, 1, PDQ_RING_MASK(dbp->pdqdb_command_responses));
! 488:
! 489: /*
! 490: * Clear the command area, set the opcode, and the command from the pending
! 491: * mask.
! 492: */
! 493:
! 494: PDQ_OS_MEMZERO(ci->ci_bufstart, cmdlen);
! 495: *(pdq_cmd_code_t *) ci->ci_bufstart = op;
! 496: ci->ci_pending_commands &= ~mask;
! 497:
! 498: /*
! 499: * Fill in the command area, if needed.
! 500: */
! 501: switch (op) {
! 502: case PDQC_FILTER_SET: {
! 503: pdq_cmd_filter_set_t *filter_set = (pdq_cmd_filter_set_t *) ci->ci_bufstart;
! 504: unsigned idx = 0;
! 505: filter_set->filter_set_items[idx].item_code = PDQI_IND_GROUP_PROM;
! 506: filter_set->filter_set_items[idx].filter_state = (pdq->pdq_flags & PDQ_PROMISC ? PDQ_FILTER_PASS : PDQ_FILTER_BLOCK);
! 507: idx++;
! 508: filter_set->filter_set_items[idx].item_code = PDQI_GROUP_PROM;
! 509: filter_set->filter_set_items[idx].filter_state = (pdq->pdq_flags & PDQ_ALLMULTI ? PDQ_FILTER_PASS : PDQ_FILTER_BLOCK);
! 510: idx++;
! 511: filter_set->filter_set_items[idx].item_code = PDQI_SMT_PROM;
! 512: filter_set->filter_set_items[idx].filter_state = ((pdq->pdq_flags & (PDQ_PROMISC|PDQ_PASS_SMT)) == (PDQ_PROMISC|PDQ_PASS_SMT) ? PDQ_FILTER_PASS : PDQ_FILTER_BLOCK);
! 513: idx++;
! 514: filter_set->filter_set_items[idx].item_code = PDQI_SMT_USER;
! 515: filter_set->filter_set_items[idx].filter_state = (pdq->pdq_flags & PDQ_PASS_SMT ? PDQ_FILTER_PASS : PDQ_FILTER_BLOCK);
! 516: idx++;
! 517: filter_set->filter_set_items[idx].item_code = PDQI_EOL;
! 518: break;
! 519: }
! 520: case PDQC_ADDR_FILTER_SET: {
! 521: pdq_cmd_addr_filter_set_t *addr_filter_set = (pdq_cmd_addr_filter_set_t *) ci->ci_bufstart;
! 522: pdq_lanaddr_t *addr = addr_filter_set->addr_filter_set_addresses;
! 523: addr->lanaddr_bytes[0] = 0xFF;
! 524: addr->lanaddr_bytes[1] = 0xFF;
! 525: addr->lanaddr_bytes[2] = 0xFF;
! 526: addr->lanaddr_bytes[3] = 0xFF;
! 527: addr->lanaddr_bytes[4] = 0xFF;
! 528: addr->lanaddr_bytes[5] = 0xFF;
! 529: addr++;
! 530: pdq_os_addr_fill(pdq, addr, 61);
! 531: break;
! 532: }
! 533: default:
! 534: break;
! 535: }
! 536: /*
! 537: * At this point the command is done. All that needs to be done is to
! 538: * produce it to the PDQ.
! 539: */
! 540: PDQ_PRINTF(("PDQ Queue Command Request: %s queued\n",
! 541: pdq_cmd_info[op].cmd_name));
! 542:
! 543: ci->ci_command_active++;
! 544: PDQ_CSR_WRITE(csrs, csr_cmd_response_producer, ci->ci_response_producer | (ci->ci_response_completion << 8));
! 545: PDQ_CSR_WRITE(csrs, csr_cmd_request_producer, ci->ci_request_producer | (ci->ci_request_completion << 8));
! 546: }
! 547:
! 548: static void
! 549: pdq_process_command_responses(
! 550: pdq_t * const pdq)
! 551: {
! 552: const pdq_csrs_t * const csrs = &pdq->pdq_csrs;
! 553: pdq_command_info_t * const ci = &pdq->pdq_command_info;
! 554: volatile const pdq_consumer_block_t * const cbp = pdq->pdq_cbp;
! 555: pdq_descriptor_block_t * const dbp = pdq->pdq_dbp;
! 556: const pdq_response_generic_t *rspgen;
! 557:
! 558: /*
! 559: * We have to process the command and response in tandem so
! 560: * just wait for the response to be consumed. If it has been
! 561: * consumed then the command must have been as well.
! 562: */
! 563:
! 564: if (cbp->pdqcb_command_response == ci->ci_response_completion)
! 565: return;
! 566:
! 567: PDQ_ASSERT(cbp->pdqcb_command_request != ci->ci_request_completion);
! 568:
! 569: rspgen = (const pdq_response_generic_t *) ci->ci_bufstart;
! 570: PDQ_ASSERT(rspgen->generic_status == PDQR_SUCCESS);
! 571: PDQ_PRINTF(("PDQ Process Command Response: %s completed (status=%d)\n",
! 572: pdq_cmd_info[rspgen->generic_op].cmd_name,
! 573: rspgen->generic_status));
! 574:
! 575: if (rspgen->generic_op == PDQC_STATUS_CHARS_GET && (pdq->pdq_flags & PDQ_PRINTCHARS)) {
! 576: pdq->pdq_flags &= ~PDQ_PRINTCHARS;
! 577: pdq_print_fddi_chars(pdq, (const pdq_response_status_chars_get_t *) rspgen);
! 578: }
! 579:
! 580: PDQ_ADVANCE(ci->ci_request_completion, 1, PDQ_RING_MASK(dbp->pdqdb_command_requests));
! 581: PDQ_ADVANCE(ci->ci_response_completion, 1, PDQ_RING_MASK(dbp->pdqdb_command_responses));
! 582: ci->ci_command_active = 0;
! 583:
! 584: if (ci->ci_pending_commands != 0) {
! 585: pdq_queue_commands(pdq);
! 586: } else {
! 587: PDQ_CSR_WRITE(csrs, csr_cmd_response_producer,
! 588: ci->ci_response_producer | (ci->ci_response_completion << 8));
! 589: PDQ_CSR_WRITE(csrs, csr_cmd_request_producer,
! 590: ci->ci_request_producer | (ci->ci_request_completion << 8));
! 591: }
! 592: }
! 593:
! 594: /*
! 595: * This following routine processes unsolicited events.
! 596: * In addition, it also fills the unsolicited queue with
! 597: * event buffers so it can be used to initialize the queue
! 598: * as well.
! 599: */
! 600: static void
! 601: pdq_process_unsolicited_events(
! 602: pdq_t *pdq)
! 603: {
! 604: const pdq_csrs_t * const csrs = &pdq->pdq_csrs;
! 605: pdq_unsolicited_info_t *ui = &pdq->pdq_unsolicited_info;
! 606: volatile const pdq_consumer_block_t *cbp = pdq->pdq_cbp;
! 607: pdq_descriptor_block_t *dbp = pdq->pdq_dbp;
! 608: const pdq_unsolicited_event_t *event;
! 609: pdq_rxdesc_t *rxd;
! 610:
! 611: /*
! 612: * Process each unsolicited event (if any).
! 613: */
! 614:
! 615: while (cbp->pdqcb_unsolicited_event != ui->ui_completion) {
! 616: rxd = &dbp->pdqdb_unsolicited_events[ui->ui_completion];
! 617: event = &ui->ui_events[ui->ui_completion & (PDQ_NUM_UNSOLICITED_EVENTS-1)];
! 618:
! 619: switch (event->event_type) {
! 620: case PDQ_UNSOLICITED_EVENT: {
! 621: printf(PDQ_OS_PREFIX "Unsolicited Event: %s: %s",
! 622: PDQ_OS_PREFIX_ARGS,
! 623: pdq_entities[event->event_entity],
! 624: pdq_event_codes[event->event_entity][event->event_code.value]);
! 625: if (event->event_entity == PDQ_ENTITY_PHY_PORT)
! 626: printf("[%d]", event->event_index);
! 627: printf("\n");
! 628: break;
! 629: }
! 630: case PDQ_UNSOLICITED_COUNTERS: {
! 631: break;
! 632: }
! 633: }
! 634: PDQ_ADVANCE(ui->ui_completion, 1, PDQ_RING_MASK(dbp->pdqdb_unsolicited_events));
! 635: ui->ui_free++;
! 636: }
! 637:
! 638: /*
! 639: * Now give back the event buffers back to the PDQ.
! 640: */
! 641: PDQ_ADVANCE(ui->ui_producer, ui->ui_free, PDQ_RING_MASK(dbp->pdqdb_unsolicited_events));
! 642: ui->ui_free = 0;
! 643:
! 644: PDQ_CSR_WRITE(csrs, csr_unsolicited_producer,
! 645: ui->ui_producer | (ui->ui_completion << 8));
! 646: }
! 647:
! 648: static void
! 649: pdq_process_received_data(
! 650: pdq_t *pdq,
! 651: pdq_rx_info_t *rx,
! 652: pdq_rxdesc_t *receives,
! 653: pdq_uint32_t completion_goal,
! 654: pdq_uint32_t ring_mask)
! 655: {
! 656: pdq_uint32_t completion = rx->rx_completion;
! 657: pdq_uint32_t producer = rx->rx_producer;
! 658: PDQ_OS_DATABUF_T **buffers = (PDQ_OS_DATABUF_T **) rx->rx_buffers;
! 659: pdq_rxdesc_t *rxd;
! 660: pdq_uint32_t idx;
! 661:
! 662: while (completion != completion_goal) {
! 663: PDQ_OS_DATABUF_T *fpdu, *lpdu, *npdu;
! 664: pdq_uint8_t *dataptr;
! 665: pdq_uint32_t fc, datalen, pdulen, segcnt;
! 666: pdq_rxstatus_t status;
! 667:
! 668: fpdu = lpdu = buffers[completion];
! 669: PDQ_ASSERT(fpdu != NULL);
! 670:
! 671: dataptr = PDQ_OS_DATABUF_PTR(fpdu);
! 672: status = *(pdq_rxstatus_t *) dataptr;
! 673: if ((status.rxs_status & 0x200000) == 0) {
! 674: datalen = status.rxs_status & 0x1FFF;
! 675: fc = dataptr[PDQ_RX_FC_OFFSET];
! 676: switch (fc & (PDQ_FDDIFC_C|PDQ_FDDIFC_L|PDQ_FDDIFC_F)) {
! 677: case PDQ_FDDI_LLC_ASYNC:
! 678: case PDQ_FDDI_LLC_SYNC:
! 679: case PDQ_FDDI_IMP_ASYNC:
! 680: case PDQ_FDDI_IMP_SYNC: {
! 681: if (datalen > PDQ_FDDI_MAX || datalen < PDQ_FDDI_LLC_MIN) {
! 682: PDQ_PRINTF(("discard: bad length %d\n", datalen));
! 683: goto discard_frame;
! 684: }
! 685: break;
! 686: }
! 687: case PDQ_FDDI_SMT: {
! 688: if (datalen > PDQ_FDDI_MAX || datalen < PDQ_FDDI_SMT_MIN)
! 689: goto discard_frame;
! 690: break;
! 691: }
! 692: default: {
! 693: PDQ_PRINTF(("discard: bad fc 0x%x\n", fc));
! 694: goto discard_frame;
! 695: }
! 696: }
! 697: /*
! 698: * Update the lengths of the data buffers now that we know
! 699: * the real length.
! 700: */
! 701: pdulen = datalen - 4 /* CRC */;
! 702: segcnt = (pdulen + PDQ_RX_FC_OFFSET + PDQ_OS_DATABUF_SIZE - 1) / PDQ_OS_DATABUF_SIZE;
! 703: PDQ_OS_DATABUF_ALLOC(npdu);
! 704: if (npdu == NULL) {
! 705: PDQ_PRINTF(("discard: no databuf #0\n"));
! 706: goto discard_frame;
! 707: }
! 708: buffers[completion] = npdu;
! 709: for (idx = 1; idx < segcnt; idx++) {
! 710: PDQ_OS_DATABUF_ALLOC(npdu);
! 711: if (npdu == NULL) {
! 712: PDQ_OS_DATABUF_NEXT_SET(lpdu, NULL);
! 713: PDQ_OS_DATABUF_FREE(fpdu);
! 714: goto discard_frame;
! 715: }
! 716: PDQ_OS_DATABUF_NEXT_SET(lpdu, buffers[(completion + idx) & ring_mask]);
! 717: lpdu = PDQ_OS_DATABUF_NEXT(lpdu);
! 718: buffers[(completion + idx) & ring_mask] = npdu;
! 719: }
! 720: PDQ_OS_DATABUF_NEXT_SET(lpdu, NULL);
! 721: for (idx = 0; idx < PDQ_RX_SEGCNT; idx++) {
! 722: buffers[(producer + idx) & ring_mask] =
! 723: buffers[(completion + idx) & ring_mask];
! 724: buffers[(completion + idx) & ring_mask] = NULL;
! 725: }
! 726: PDQ_OS_DATABUF_ADJ(fpdu, PDQ_RX_FC_OFFSET);
! 727: if (segcnt == 1) {
! 728: PDQ_OS_DATABUF_LEN_SET(fpdu, pdulen);
! 729: } else {
! 730: PDQ_OS_DATABUF_LEN_SET(lpdu, pdulen + PDQ_RX_FC_OFFSET - (segcnt - 1) * PDQ_OS_DATABUF_SIZE);
! 731: }
! 732: pdq_os_receive_pdu(pdq, fpdu, pdulen);
! 733: rx->rx_free += PDQ_RX_SEGCNT;
! 734: PDQ_ADVANCE(producer, PDQ_RX_SEGCNT, ring_mask);
! 735: PDQ_ADVANCE(completion, PDQ_RX_SEGCNT, ring_mask);
! 736: continue;
! 737: } else {
! 738: PDQ_PRINTF(("discard: bad pdu 0x%x(%d.%d.%d.%d.%d)\n", status.rxs_status,
! 739: status.rxs_rcc_badpdu, status.rxs_rcc_badcrc,
! 740: status.rxs_rcc_reason, status.rxs_fsc, status.rxs_fsb_e));
! 741: if (status.rxs_rcc_reason == 7)
! 742: goto discard_frame;
! 743: if (status.rxs_rcc_reason != 0) {
! 744: /* hardware fault */
! 745: }
! 746: if (status.rxs_rcc_badcrc) {
! 747: printf(PDQ_OS_PREFIX " MAC CRC error (source=%x-%x-%x-%x-%x-%x)\n",
! 748: PDQ_OS_PREFIX_ARGS,
! 749: dataptr[PDQ_RX_FC_OFFSET+1],
! 750: dataptr[PDQ_RX_FC_OFFSET+2],
! 751: dataptr[PDQ_RX_FC_OFFSET+3],
! 752: dataptr[PDQ_RX_FC_OFFSET+4],
! 753: dataptr[PDQ_RX_FC_OFFSET+5],
! 754: dataptr[PDQ_RX_FC_OFFSET+6]);
! 755: /* rx->rx_badcrc++; */
! 756: } else if (status.rxs_fsc == 0 || status.rxs_fsb_e == 1) {
! 757: /* rx->rx_frame_status_errors++; */
! 758: } else {
! 759: /* hardware fault */
! 760: }
! 761: }
! 762: discard_frame:
! 763: /*
! 764: * Discarded frames go right back on the queue; therefore
! 765: * ring entries were freed.
! 766: */
! 767: for (idx = 0; idx < PDQ_RX_SEGCNT; idx++) {
! 768: buffers[producer] = buffers[completion];
! 769: buffers[completion] = NULL;
! 770: rxd = &receives[rx->rx_producer];
! 771: if (idx == 0) {
! 772: rxd->rxd_sop = 1; rxd->rxd_seg_cnt = PDQ_RX_SEGCNT - 1;
! 773: } else {
! 774: rxd->rxd_sop = 0; rxd->rxd_seg_cnt = 0;
! 775: }
! 776: rxd->rxd_pa_hi = 0;
! 777: rxd->rxd_seg_len_hi = PDQ_OS_DATABUF_SIZE / 16;
! 778: rxd->rxd_pa_lo = PDQ_OS_VA_TO_PA(pdq, PDQ_OS_DATABUF_PTR(buffers[rx->rx_producer]));
! 779: PDQ_ADVANCE(rx->rx_producer, 1, ring_mask);
! 780: PDQ_ADVANCE(producer, 1, ring_mask);
! 781: PDQ_ADVANCE(completion, 1, ring_mask);
! 782: }
! 783: }
! 784: rx->rx_completion = completion;
! 785:
! 786: while (rx->rx_free > PDQ_RX_SEGCNT && rx->rx_free > rx->rx_target) {
! 787: PDQ_OS_DATABUF_T *pdu;
! 788: /*
! 789: * Allocate the needed number of data buffers.
! 790: * Try to obtain them from our free queue before
! 791: * asking the system for more.
! 792: */
! 793: for (idx = 0; idx < PDQ_RX_SEGCNT; idx++) {
! 794: if ((pdu = buffers[(rx->rx_producer + idx) & ring_mask]) == NULL) {
! 795: PDQ_OS_DATABUF_ALLOC(pdu);
! 796: if (pdu == NULL)
! 797: break;
! 798: buffers[(rx->rx_producer + idx) & ring_mask] = pdu;
! 799: }
! 800: rxd = &receives[(rx->rx_producer + idx) & ring_mask];
! 801: if (idx == 0) {
! 802: rxd->rxd_sop = 1; rxd->rxd_seg_cnt = PDQ_RX_SEGCNT - 1;
! 803: } else {
! 804: rxd->rxd_sop = 0; rxd->rxd_seg_cnt = 0;
! 805: }
! 806: rxd->rxd_pa_hi = 0;
! 807: rxd->rxd_seg_len_hi = PDQ_OS_DATABUF_SIZE / 16;
! 808: rxd->rxd_pa_lo = PDQ_OS_VA_TO_PA(pdq, PDQ_OS_DATABUF_PTR(pdu));
! 809: }
! 810: if (idx < PDQ_RX_SEGCNT) {
! 811: /*
! 812: * We didn't get all databufs required to complete a new
! 813: * receive buffer. Keep the ones we got and retry a bit
! 814: * later for the rest.
! 815: */
! 816: break;
! 817: }
! 818: PDQ_ADVANCE(rx->rx_producer, PDQ_RX_SEGCNT, ring_mask);
! 819: rx->rx_free -= PDQ_RX_SEGCNT;
! 820: }
! 821: }
! 822:
! 823: pdq_boolean_t
! 824: pdq_queue_transmit_data(
! 825: pdq_t *pdq,
! 826: PDQ_OS_DATABUF_T *pdu)
! 827: {
! 828: pdq_tx_info_t *tx = &pdq->pdq_tx_info;
! 829: pdq_descriptor_block_t *dbp = pdq->pdq_dbp;
! 830: pdq_uint32_t producer = tx->tx_producer;
! 831: pdq_txdesc_t *eop = NULL;
! 832: PDQ_OS_DATABUF_T *pdu0;
! 833: pdq_uint32_t freecnt;
! 834:
! 835: if (tx->tx_free < 1)
! 836: return PDQ_FALSE;
! 837:
! 838: dbp->pdqdb_transmits[producer] = tx->tx_hdrdesc;
! 839: PDQ_ADVANCE(producer, 1, PDQ_RING_MASK(dbp->pdqdb_transmits));
! 840:
! 841: for (freecnt = tx->tx_free - 1, pdu0 = pdu; pdu0 != NULL && freecnt > 0;) {
! 842: pdq_uint32_t fraglen, datalen = PDQ_OS_DATABUF_LEN(pdu0);
! 843: const pdq_uint8_t *dataptr = PDQ_OS_DATABUF_PTR(pdu0);
! 844:
! 845: /*
! 846: * The first segment is limited to the space remaining in
! 847: * page. All segments after that can be up to a full page
! 848: * in size.
! 849: */
! 850: fraglen = PDQ_OS_PAGESIZE - ((dataptr - (pdq_uint8_t *) NULL) & (PDQ_OS_PAGESIZE-1));
! 851: while (datalen > 0 && freecnt > 0) {
! 852: pdq_uint32_t seglen = (fraglen < datalen ? fraglen : datalen);
! 853:
! 854: /*
! 855: * Initialize the transmit descriptor
! 856: */
! 857: eop = &dbp->pdqdb_transmits[producer];
! 858: eop->txd_seg_len = seglen;
! 859: eop->txd_pa_lo = PDQ_OS_VA_TO_PA(pdq, dataptr);
! 860: eop->txd_sop = eop->txd_eop = eop->txd_pa_hi = 0;
! 861:
! 862: datalen -= seglen;
! 863: dataptr += seglen;
! 864: fraglen = PDQ_OS_PAGESIZE;
! 865: freecnt--;
! 866: PDQ_ADVANCE(producer, 1, PDQ_RING_MASK(dbp->pdqdb_transmits));
! 867: }
! 868: pdu0 = PDQ_OS_DATABUF_NEXT(pdu0);
! 869: }
! 870: if (pdu0 != NULL) {
! 871: PDQ_ASSERT(freecnt == 0);
! 872: /*
! 873: * If we still have data to process then the ring was too full
! 874: * to store the PDU. Return FALSE so the caller will requeue
! 875: * the PDU for later.
! 876: */
! 877: return PDQ_FALSE;
! 878: }
! 879: /*
! 880: * Everything went fine. Finish it up.
! 881: */
! 882: tx->tx_descriptor_count[tx->tx_producer] = tx->tx_free - freecnt;
! 883: eop->txd_eop = 1;
! 884: PDQ_OS_DATABUF_ENQUEUE(&tx->tx_txq, pdu);
! 885: tx->tx_producer = producer;
! 886: tx->tx_free = freecnt;
! 887: PDQ_DO_TYPE2_PRODUCER(pdq);
! 888: return PDQ_TRUE;
! 889: }
! 890:
! 891: static void
! 892: pdq_process_transmitted_data(
! 893: pdq_t *pdq)
! 894: {
! 895: pdq_tx_info_t *tx = &pdq->pdq_tx_info;
! 896: volatile const pdq_consumer_block_t *cbp = pdq->pdq_cbp;
! 897: pdq_descriptor_block_t *dbp = pdq->pdq_dbp;
! 898: pdq_uint32_t completion = tx->tx_completion;
! 899:
! 900: while (completion != cbp->pdqcb_transmits) {
! 901: PDQ_OS_DATABUF_T *pdu;
! 902: pdq_uint32_t descriptor_count = tx->tx_descriptor_count[completion];
! 903: PDQ_ASSERT(dbp->pdqdb_transmits[completion].txd_sop == 1);
! 904: PDQ_ASSERT(dbp->pdqdb_transmits[(completion + descriptor_count - 1) & PDQ_RING_MASK(dbp->pdqdb_transmits)].txd_eop == 1);
! 905: PDQ_OS_DATABUF_DEQUEUE(&tx->tx_txq, pdu);
! 906: pdq_os_transmit_done(pdq, pdu);
! 907: tx->tx_free += descriptor_count;
! 908:
! 909: PDQ_ADVANCE(completion, descriptor_count, PDQ_RING_MASK(dbp->pdqdb_transmits));
! 910: }
! 911: if (tx->tx_completion != completion) {
! 912: tx->tx_completion = completion;
! 913: pdq_os_restart_transmitter(pdq);
! 914: }
! 915: PDQ_DO_TYPE2_PRODUCER(pdq);
! 916: }
! 917:
! 918: void
! 919: pdq_flush_transmitter(
! 920: pdq_t *pdq)
! 921: {
! 922: volatile pdq_consumer_block_t *cbp = pdq->pdq_cbp;
! 923: pdq_tx_info_t *tx = &pdq->pdq_tx_info;
! 924:
! 925: for (;;) {
! 926: PDQ_OS_DATABUF_T *pdu;
! 927: PDQ_OS_DATABUF_DEQUEUE(&tx->tx_txq, pdu);
! 928: if (pdu == NULL)
! 929: break;
! 930: /*
! 931: * Don't call transmit done since the packet never made it
! 932: * out on the wire.
! 933: */
! 934: PDQ_OS_DATABUF_FREE(pdu);
! 935: }
! 936:
! 937: tx->tx_free = PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_transmits);
! 938: tx->tx_completion = cbp->pdqcb_transmits = tx->tx_producer;
! 939:
! 940: PDQ_DO_TYPE2_PRODUCER(pdq);
! 941: }
! 942:
! 943: void
! 944: pdq_hwreset(
! 945: pdq_t *pdq)
! 946: {
! 947: const pdq_csrs_t * const csrs = &pdq->pdq_csrs;
! 948: pdq_state_t state;
! 949: int cnt;
! 950:
! 951: state = PDQ_PSTS_ADAPTER_STATE(PDQ_CSR_READ(csrs, csr_port_status));
! 952: if (state == PDQS_DMA_UNAVAILABLE)
! 953: return;
! 954: PDQ_CSR_WRITE(csrs, csr_port_data_a,
! 955: (state == PDQS_HALTED) ? 0 : PDQ_PRESET_SKIP_SELFTEST);
! 956: PDQ_CSR_WRITE(csrs, csr_port_reset, 1);
! 957: PDQ_OS_USEC_DELAY(100);
! 958: PDQ_CSR_WRITE(csrs, csr_port_reset, 0);
! 959: for (cnt = 45000;;cnt--) {
! 960: PDQ_OS_USEC_DELAY(1000);
! 961: state = PDQ_PSTS_ADAPTER_STATE(PDQ_CSR_READ(csrs, csr_port_status));
! 962: if (state == PDQS_DMA_UNAVAILABLE || cnt == 0)
! 963: break;
! 964: }
! 965: PDQ_PRINTF(("PDQ Reset spun %d cycles\n", 45000 - cnt));
! 966: PDQ_OS_USEC_DELAY(10000);
! 967: state = PDQ_PSTS_ADAPTER_STATE(PDQ_CSR_READ(csrs, csr_port_status));
! 968: PDQ_ASSERT(state == PDQS_DMA_UNAVAILABLE);
! 969: PDQ_ASSERT(cnt > 0);
! 970: }
! 971:
! 972: /*
! 973: * The following routine brings the PDQ from whatever state it is
! 974: * in to DMA_UNAVAILABLE (ie. like a RESET but without doing a RESET).
! 975: */
! 976: pdq_state_t
! 977: pdq_stop(
! 978: pdq_t *pdq)
! 979: {
! 980: pdq_state_t state;
! 981: const pdq_csrs_t * const csrs = &pdq->pdq_csrs;
! 982: int cnt, pass = 0, idx;
! 983: PDQ_OS_DATABUF_T **buffers;
! 984:
! 985: restart:
! 986: state = PDQ_PSTS_ADAPTER_STATE(PDQ_CSR_READ(csrs, csr_port_status));
! 987: if (state != PDQS_DMA_UNAVAILABLE) {
! 988: pdq_hwreset(pdq);
! 989: state = PDQ_PSTS_ADAPTER_STATE(PDQ_CSR_READ(csrs, csr_port_status));
! 990: PDQ_ASSERT(state == PDQS_DMA_UNAVAILABLE);
! 991: }
! 992: #if 0
! 993: switch (state) {
! 994: case PDQS_RING_MEMBER:
! 995: case PDQS_LINK_UNAVAILABLE:
! 996: case PDQS_LINK_AVAILABLE: {
! 997: PDQ_CSR_WRITE(csrs, csr_port_data_a, PDQ_SUB_CMD_LINK_UNINIT);
! 998: PDQ_CSR_WRITE(csrs, csr_port_data_b, 0);
! 999: pdq_do_port_control(csrs, PDQ_PCTL_SUB_CMD);
! 1000: state = PDQ_PSTS_ADAPTER_STATE(PDQ_CSR_READ(csrs, csr_port_status));
! 1001: PDQ_ASSERT(state == PDQS_DMA_AVAILABLE);
! 1002: /* FALLTHROUGH */
! 1003: }
! 1004: case PDQS_DMA_AVAILABLE: {
! 1005: PDQ_CSR_WRITE(csrs, csr_port_data_a, 0);
! 1006: PDQ_CSR_WRITE(csrs, csr_port_data_b, 0);
! 1007: pdq_do_port_control(csrs, PDQ_PCTL_DMA_UNINIT);
! 1008: state = PDQ_PSTS_ADAPTER_STATE(PDQ_CSR_READ(csrs, csr_port_status));
! 1009: PDQ_ASSERT(state == PDQS_DMA_UNAVAILABLE);
! 1010: /* FALLTHROUGH */
! 1011: }
! 1012: case PDQS_DMA_UNAVAILABLE: {
! 1013: break;
! 1014: }
! 1015: }
! 1016: #endif
! 1017: /*
! 1018: * Now we should be in DMA_UNAVAILABLE. So bring the PDQ into
! 1019: * DMA_AVAILABLE.
! 1020: */
! 1021:
! 1022: /*
! 1023: * Obtain the hardware address and firmware revisions
! 1024: * (MLA = my long address which is FDDI speak for hardware address)
! 1025: */
! 1026: pdq_read_mla(&pdq->pdq_csrs, &pdq->pdq_hwaddr);
! 1027: pdq_read_fwrev(&pdq->pdq_csrs, &pdq->pdq_fwrev);
! 1028: pdq->pdq_chip_rev = pdq_read_chiprev(&pdq->pdq_csrs);
! 1029:
! 1030: if (pdq->pdq_type == PDQ_DEFPA) {
! 1031: /*
! 1032: * Disable interrupts and DMA.
! 1033: */
! 1034: PDQ_CSR_WRITE(&pdq->pdq_pci_csrs, csr_pfi_mode_control, 0);
! 1035: PDQ_CSR_WRITE(&pdq->pdq_pci_csrs, csr_pfi_status, 0x10);
! 1036: }
! 1037:
! 1038: /*
! 1039: * Flush all the databuf queues.
! 1040: */
! 1041: pdq_flush_databuf_queue(&pdq->pdq_tx_info.tx_txq);
! 1042: pdq->pdq_flags &= ~PDQ_TXOK;
! 1043: buffers = (PDQ_OS_DATABUF_T **) pdq->pdq_rx_info.rx_buffers;
! 1044: for (idx = 0; idx < PDQ_RING_SIZE(pdq->pdq_dbp->pdqdb_receives); idx++) {
! 1045: if (buffers[idx] != NULL) {
! 1046: PDQ_OS_DATABUF_FREE(buffers[idx]);
! 1047: buffers[idx] = NULL;
! 1048: }
! 1049: }
! 1050: pdq->pdq_rx_info.rx_free = PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_receives);
! 1051: buffers = (PDQ_OS_DATABUF_T **) pdq->pdq_host_smt_info.rx_buffers;
! 1052: for (idx = 0; idx < PDQ_RING_SIZE(pdq->pdq_dbp->pdqdb_host_smt); idx++) {
! 1053: if (buffers[idx] != NULL) {
! 1054: PDQ_OS_DATABUF_FREE(buffers[idx]);
! 1055: buffers[idx] = NULL;
! 1056: }
! 1057: }
! 1058: pdq->pdq_host_smt_info.rx_free = PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_host_smt);
! 1059:
! 1060: /*
! 1061: * Reset the consumer indexes to 0.
! 1062: */
! 1063: pdq->pdq_cbp->pdqcb_receives = 0;
! 1064: pdq->pdq_cbp->pdqcb_transmits = 0;
! 1065: pdq->pdq_cbp->pdqcb_host_smt = 0;
! 1066: pdq->pdq_cbp->pdqcb_unsolicited_event = 0;
! 1067: pdq->pdq_cbp->pdqcb_command_response = 0;
! 1068: pdq->pdq_cbp->pdqcb_command_request = 0;
! 1069:
! 1070: /*
! 1071: * Reset the producer and completion indexes to 0.
! 1072: */
! 1073: pdq->pdq_command_info.ci_request_producer = 0;
! 1074: pdq->pdq_command_info.ci_response_producer = 0;
! 1075: pdq->pdq_command_info.ci_request_completion = 0;
! 1076: pdq->pdq_command_info.ci_response_completion = 0;
! 1077: pdq->pdq_unsolicited_info.ui_producer = 0;
! 1078: pdq->pdq_unsolicited_info.ui_completion = 0;
! 1079: pdq->pdq_rx_info.rx_producer = 0;
! 1080: pdq->pdq_rx_info.rx_completion = 0;
! 1081: pdq->pdq_tx_info.tx_producer = 0;
! 1082: pdq->pdq_tx_info.tx_completion = 0;
! 1083: pdq->pdq_host_smt_info.rx_producer = 0;
! 1084: pdq->pdq_host_smt_info.rx_completion = 0;
! 1085:
! 1086: pdq->pdq_command_info.ci_command_active = 0;
! 1087: pdq->pdq_unsolicited_info.ui_free = PDQ_NUM_UNSOLICITED_EVENTS;
! 1088: pdq->pdq_tx_info.tx_free = PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_transmits);
! 1089:
! 1090: /*
! 1091: * Allow the DEFPA to do DMA. Then program the physical
! 1092: * addresses of the consumer and descriptor blocks.
! 1093: */
! 1094: if (pdq->pdq_type == PDQ_DEFPA) {
! 1095: #ifdef PDQTEST
! 1096: PDQ_CSR_WRITE(&pdq->pdq_pci_csrs, csr_pfi_mode_control,
! 1097: PDQ_PFI_MODE_DMA_ENABLE);
! 1098: #else
! 1099: PDQ_CSR_WRITE(&pdq->pdq_pci_csrs, csr_pfi_mode_control,
! 1100: PDQ_PFI_MODE_DMA_ENABLE
! 1101: /*|PDQ_PFI_MODE_PFI_PCI_INTR*/|PDQ_PFI_MODE_PDQ_PCI_INTR);
! 1102: #endif
! 1103: }
! 1104:
! 1105: /*
! 1106: * Make sure the unsolicited queue has events ...
! 1107: */
! 1108: pdq_process_unsolicited_events(pdq);
! 1109:
! 1110: if (pdq->pdq_type == PDQ_DEFEA && pdq->pdq_chip_rev == PDQ_CHIP_REV_E)
! 1111: PDQ_CSR_WRITE(csrs, csr_port_data_b, PDQ_DMA_BURST_16LW);
! 1112: else
! 1113: PDQ_CSR_WRITE(csrs, csr_port_data_b, PDQ_DMA_BURST_8LW);
! 1114: PDQ_CSR_WRITE(csrs, csr_port_data_a, PDQ_SUB_CMD_DMA_BURST_SIZE_SET);
! 1115: pdq_do_port_control(csrs, PDQ_PCTL_SUB_CMD);
! 1116:
! 1117: PDQ_CSR_WRITE(csrs, csr_port_data_b, 0);
! 1118: PDQ_CSR_WRITE(csrs, csr_port_data_a, PDQ_OS_VA_TO_PA(pdq, pdq->pdq_cbp));
! 1119: pdq_do_port_control(csrs, PDQ_PCTL_CONSUMER_BLOCK);
! 1120:
! 1121: PDQ_CSR_WRITE(csrs, csr_port_data_b, 0);
! 1122: PDQ_CSR_WRITE(csrs, csr_port_data_a,
! 1123: PDQ_OS_VA_TO_PA(pdq, pdq->pdq_dbp) | PDQ_DMA_INIT_LW_BSWAP_DATA);
! 1124: pdq_do_port_control(csrs, PDQ_PCTL_DMA_INIT);
! 1125:
! 1126: for (cnt = 0; cnt < 1000; cnt++) {
! 1127: state = PDQ_PSTS_ADAPTER_STATE(PDQ_CSR_READ(csrs, csr_port_status));
! 1128: if (state == PDQS_HALTED) {
! 1129: if (pass > 0)
! 1130: return PDQS_HALTED;
! 1131: pass = 1;
! 1132: goto restart;
! 1133: }
! 1134: if (state == PDQS_DMA_AVAILABLE) {
! 1135: PDQ_PRINTF(("Transition to DMA Available took %d spins\n", cnt));
! 1136: break;
! 1137: }
! 1138: PDQ_OS_USEC_DELAY(1000);
! 1139: }
! 1140: PDQ_ASSERT(state == PDQS_DMA_AVAILABLE);
! 1141:
! 1142: PDQ_CSR_WRITE(csrs, csr_host_int_type_0, 0xFF);
! 1143: PDQ_CSR_WRITE(csrs, csr_host_int_enable, 0) /* PDQ_HOST_INT_STATE_CHANGE
! 1144: |PDQ_HOST_INT_FATAL_ERROR|PDQ_HOST_INT_CMD_RSP_ENABLE
! 1145: |PDQ_HOST_INT_UNSOL_ENABLE */;
! 1146:
! 1147: /*
! 1148: * Any other command but START should be valid.
! 1149: */
! 1150: pdq->pdq_command_info.ci_pending_commands &= ~(PDQ_BITMASK(PDQC_START));
! 1151: if (pdq->pdq_flags & PDQ_PRINTCHARS)
! 1152: pdq->pdq_command_info.ci_pending_commands |= PDQ_BITMASK(PDQC_STATUS_CHARS_GET);
! 1153: pdq_queue_commands(pdq);
! 1154:
! 1155: if (pdq->pdq_flags & PDQ_PRINTCHARS) {
! 1156: /*
! 1157: * Now wait (up to 100ms) for the command(s) to finish.
! 1158: */
! 1159: for (cnt = 0; cnt < 1000; cnt++) {
! 1160: pdq_process_command_responses(pdq);
! 1161: if (pdq->pdq_command_info.ci_response_producer == pdq->pdq_command_info.ci_response_completion)
! 1162: break;
! 1163: PDQ_OS_USEC_DELAY(1000);
! 1164: }
! 1165: state = PDQ_PSTS_ADAPTER_STATE(PDQ_CSR_READ(csrs, csr_port_status));
! 1166: }
! 1167:
! 1168: return state;
! 1169: }
! 1170:
! 1171: void
! 1172: pdq_run(
! 1173: pdq_t *pdq)
! 1174: {
! 1175: const pdq_csrs_t * const csrs = &pdq->pdq_csrs;
! 1176: pdq_state_t state;
! 1177:
! 1178: state = PDQ_PSTS_ADAPTER_STATE(PDQ_CSR_READ(csrs, csr_port_status));
! 1179: PDQ_ASSERT(state != PDQS_DMA_UNAVAILABLE);
! 1180: PDQ_ASSERT(state != PDQS_RESET);
! 1181: PDQ_ASSERT(state != PDQS_HALTED);
! 1182: PDQ_ASSERT(state != PDQS_UPGRADE);
! 1183: PDQ_ASSERT(state != PDQS_RING_MEMBER);
! 1184: switch (state) {
! 1185: case PDQS_DMA_AVAILABLE: {
! 1186: /*
! 1187: * The PDQ after being reset screws up some of its state.
! 1188: * So we need to clear all the errors/interrupts so the real
! 1189: * ones will get through.
! 1190: */
! 1191: PDQ_CSR_WRITE(csrs, csr_host_int_type_0, 0xFF);
! 1192: PDQ_CSR_WRITE(csrs, csr_host_int_enable, PDQ_HOST_INT_STATE_CHANGE|PDQ_HOST_INT_XMT_DATA_FLUSH
! 1193: |PDQ_HOST_INT_FATAL_ERROR|PDQ_HOST_INT_CMD_RSP_ENABLE|PDQ_HOST_INT_UNSOL_ENABLE
! 1194: |PDQ_HOST_INT_RX_ENABLE|PDQ_HOST_INT_TX_ENABLE|PDQ_HOST_INT_HOST_SMT_ENABLE);
! 1195: /*
! 1196: * Set the MAC and address filters and start up the PDQ.
! 1197: */
! 1198: pdq_process_unsolicited_events(pdq);
! 1199: pdq_process_received_data(pdq, &pdq->pdq_rx_info,
! 1200: pdq->pdq_dbp->pdqdb_receives,
! 1201: pdq->pdq_cbp->pdqcb_receives,
! 1202: PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_receives));
! 1203: PDQ_DO_TYPE2_PRODUCER(pdq);
! 1204: if (pdq->pdq_flags & PDQ_PASS_SMT) {
! 1205: pdq_process_received_data(pdq, &pdq->pdq_host_smt_info,
! 1206: pdq->pdq_dbp->pdqdb_host_smt,
! 1207: pdq->pdq_cbp->pdqcb_host_smt,
! 1208: PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_host_smt));
! 1209: PDQ_CSR_WRITE(csrs, csr_host_smt_producer,
! 1210: pdq->pdq_host_smt_info.rx_producer
! 1211: | (pdq->pdq_host_smt_info.rx_completion << 8));
! 1212: }
! 1213: pdq->pdq_command_info.ci_pending_commands = PDQ_BITMASK(PDQC_FILTER_SET)
! 1214: | PDQ_BITMASK(PDQC_ADDR_FILTER_SET) | PDQ_BITMASK(PDQC_START);
! 1215: if (pdq->pdq_flags & PDQ_PRINTCHARS)
! 1216: pdq->pdq_command_info.ci_pending_commands |= PDQ_BITMASK(PDQC_STATUS_CHARS_GET);
! 1217: pdq_queue_commands(pdq);
! 1218: break;
! 1219: }
! 1220: case PDQS_LINK_UNAVAILABLE:
! 1221: case PDQS_LINK_AVAILABLE: {
! 1222: pdq->pdq_command_info.ci_pending_commands = PDQ_BITMASK(PDQC_FILTER_SET)
! 1223: | PDQ_BITMASK(PDQC_ADDR_FILTER_SET);
! 1224: if (pdq->pdq_flags & PDQ_PRINTCHARS)
! 1225: pdq->pdq_command_info.ci_pending_commands |= PDQ_BITMASK(PDQC_STATUS_CHARS_GET);
! 1226: if (pdq->pdq_flags & PDQ_PASS_SMT) {
! 1227: pdq_process_received_data(pdq, &pdq->pdq_host_smt_info,
! 1228: pdq->pdq_dbp->pdqdb_host_smt,
! 1229: pdq->pdq_cbp->pdqcb_host_smt,
! 1230: PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_host_smt));
! 1231: PDQ_CSR_WRITE(csrs, csr_host_smt_producer,
! 1232: pdq->pdq_host_smt_info.rx_producer
! 1233: | (pdq->pdq_host_smt_info.rx_completion << 8));
! 1234: }
! 1235: pdq_process_unsolicited_events(pdq);
! 1236: pdq_queue_commands(pdq);
! 1237: break;
! 1238: }
! 1239: case PDQS_RING_MEMBER: {
! 1240: }
! 1241: default:
! 1242: break;
! 1243: }
! 1244: }
! 1245:
! 1246: int
! 1247: pdq_interrupt(
! 1248: pdq_t *pdq)
! 1249: {
! 1250: const pdq_csrs_t * const csrs = &pdq->pdq_csrs;
! 1251: pdq_uint32_t data;
! 1252: int progress = 0;
! 1253:
! 1254: if (pdq->pdq_type == PDQ_DEFPA)
! 1255: PDQ_CSR_WRITE(&pdq->pdq_pci_csrs, csr_pfi_status, 0x18);
! 1256:
! 1257: while ((data = PDQ_CSR_READ(csrs, csr_port_status)) & PDQ_PSTS_INTR_PENDING) {
! 1258: progress = 1;
! 1259: PDQ_PRINTF(("PDQ Interrupt: Status = 0x%08x\n", data));
! 1260: if (data & PDQ_PSTS_RCV_DATA_PENDING) {
! 1261: pdq_process_received_data(pdq, &pdq->pdq_rx_info,
! 1262: pdq->pdq_dbp->pdqdb_receives,
! 1263: pdq->pdq_cbp->pdqcb_receives,
! 1264: PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_receives));
! 1265: PDQ_DO_TYPE2_PRODUCER(pdq);
! 1266: }
! 1267: if (data & PDQ_PSTS_HOST_SMT_PENDING) {
! 1268: pdq_process_received_data(pdq, &pdq->pdq_host_smt_info,
! 1269: pdq->pdq_dbp->pdqdb_host_smt,
! 1270: pdq->pdq_cbp->pdqcb_host_smt,
! 1271: PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_host_smt));
! 1272: PDQ_DO_HOST_SMT_PRODUCER(pdq);
! 1273: }
! 1274: if (data & PDQ_PSTS_XMT_DATA_PENDING)
! 1275: pdq_process_transmitted_data(pdq);
! 1276: if (data & PDQ_PSTS_UNSOL_PENDING)
! 1277: pdq_process_unsolicited_events(pdq);
! 1278: if (data & PDQ_PSTS_CMD_RSP_PENDING)
! 1279: pdq_process_command_responses(pdq);
! 1280: if (data & PDQ_PSTS_TYPE_0_PENDING) {
! 1281: data = PDQ_CSR_READ(csrs, csr_host_int_type_0);
! 1282: if (data & PDQ_HOST_INT_STATE_CHANGE) {
! 1283: pdq_state_t state = PDQ_PSTS_ADAPTER_STATE(PDQ_CSR_READ(csrs, csr_port_status));
! 1284: printf(PDQ_OS_PREFIX "%s", PDQ_OS_PREFIX_ARGS, pdq_adapter_states[state]);
! 1285: if (state == PDQS_LINK_UNAVAILABLE) {
! 1286: pdq->pdq_flags &= ~PDQ_TXOK;
! 1287: } else if (state == PDQS_LINK_AVAILABLE) {
! 1288: pdq->pdq_flags |= PDQ_TXOK;
! 1289: pdq_os_restart_transmitter(pdq);
! 1290: } else if (state == PDQS_HALTED) {
! 1291: pdq_response_error_log_get_t log_entry;
! 1292: pdq_halt_code_t halt_code = PDQ_PSTS_HALT_ID(PDQ_CSR_READ(csrs, csr_port_status));
! 1293: printf(": halt code = %d (%s)\n",
! 1294: halt_code, pdq_halt_codes[halt_code]);
! 1295: if (halt_code == PDQH_DMA_ERROR && pdq->pdq_type == PDQ_DEFPA) {
! 1296: PDQ_PRINTF(("\tPFI status = 0x%x, Host 0 Fatal Interrupt = 0x%x\n",
! 1297: PDQ_CSR_READ(&pdq->pdq_pci_csrs, csr_pfi_status),
! 1298: data & PDQ_HOST_INT_FATAL_ERROR));
! 1299: }
! 1300: pdq_read_error_log(pdq, &log_entry);
! 1301: pdq_stop(pdq);
! 1302: if (pdq->pdq_flags & PDQ_RUNNING)
! 1303: pdq_run(pdq);
! 1304: return 1;
! 1305: }
! 1306: printf("\n");
! 1307: PDQ_CSR_WRITE(csrs, csr_host_int_type_0, PDQ_HOST_INT_STATE_CHANGE);
! 1308: }
! 1309: if (data & PDQ_HOST_INT_FATAL_ERROR) {
! 1310: pdq_stop(pdq);
! 1311: if (pdq->pdq_flags & PDQ_RUNNING)
! 1312: pdq_run(pdq);
! 1313: return 1;
! 1314: }
! 1315: if (data & PDQ_HOST_INT_XMT_DATA_FLUSH) {
! 1316: printf(PDQ_OS_PREFIX "Flushing transmit queue\n", PDQ_OS_PREFIX_ARGS);
! 1317: pdq->pdq_flags &= ~PDQ_TXOK;
! 1318: pdq_flush_transmitter(pdq);
! 1319: pdq_do_port_control(csrs, PDQ_PCTL_XMT_DATA_FLUSH_DONE);
! 1320: PDQ_CSR_WRITE(csrs, csr_host_int_type_0, PDQ_HOST_INT_XMT_DATA_FLUSH);
! 1321: }
! 1322: }
! 1323: if (pdq->pdq_type == PDQ_DEFPA)
! 1324: PDQ_CSR_WRITE(&pdq->pdq_pci_csrs, csr_pfi_status, 0x18);
! 1325: }
! 1326: return progress;
! 1327: }
! 1328:
! 1329: pdq_t *
! 1330: pdq_initialize(
! 1331: pdq_bus_t bus,
! 1332: pdq_bus_memaddr_t csr_base,
! 1333: const char *name,
! 1334: int unit,
! 1335: void *ctx,
! 1336: pdq_type_t type)
! 1337: {
! 1338: pdq_t *pdq;
! 1339: pdq_state_t state;
! 1340: const pdq_uint32_t contig_bytes = (sizeof(pdq_descriptor_block_t) * 2) - PDQ_OS_PAGESIZE;
! 1341: pdq_uint8_t *p;
! 1342: int idx;
! 1343:
! 1344: PDQ_ASSERT(sizeof(pdq_descriptor_block_t) == 8192);
! 1345: PDQ_ASSERT(sizeof(pdq_consumer_block_t) == 64);
! 1346: PDQ_ASSERT(sizeof(pdq_response_filter_get_t) == PDQ_SIZE_RESPONSE_FILTER_GET);
! 1347: PDQ_ASSERT(sizeof(pdq_cmd_addr_filter_set_t) == PDQ_SIZE_CMD_ADDR_FILTER_SET);
! 1348: PDQ_ASSERT(sizeof(pdq_response_addr_filter_get_t) == PDQ_SIZE_RESPONSE_ADDR_FILTER_GET);
! 1349: PDQ_ASSERT(sizeof(pdq_response_status_chars_get_t) == PDQ_SIZE_RESPONSE_STATUS_CHARS_GET);
! 1350: PDQ_ASSERT(sizeof(pdq_response_fddi_mib_get_t) == PDQ_SIZE_RESPONSE_FDDI_MIB_GET);
! 1351: PDQ_ASSERT(sizeof(pdq_response_dec_ext_mib_get_t) == PDQ_SIZE_RESPONSE_DEC_EXT_MIB_GET);
! 1352: PDQ_ASSERT(sizeof(pdq_unsolicited_event_t) == 512);
! 1353:
! 1354: pdq = (pdq_t *) PDQ_OS_MEMALLOC(sizeof(pdq_t));
! 1355: if (pdq == NULL) {
! 1356: PDQ_PRINTF(("malloc(%d) failed\n", sizeof(*pdq)));
! 1357: return NULL;
! 1358: }
! 1359: PDQ_OS_MEMZERO(pdq, sizeof(pdq_t));
! 1360: pdq->pdq_type = type;
! 1361: pdq->pdq_unit = unit;
! 1362: pdq->pdq_os_ctx = (void *) ctx;
! 1363: pdq->pdq_os_name = name;
! 1364: pdq->pdq_flags = PDQ_PRINTCHARS;
! 1365: /*
! 1366: * Allocate the additional data structures required by
! 1367: * the PDQ driver. Allocate a contiguous region of memory
! 1368: * for the descriptor block. We need to allocated enough
! 1369: * to guarantee that we will a get 8KB block of memory aligned
! 1370: * on a 8KB boundary. This turns to require that we allocate
! 1371: * (N*2 - 1 page) pages of memory. On machine with less than
! 1372: * a 8KB page size, it mean we will allocate more memory than
! 1373: * we need. The extra will be used for the unsolicited event
! 1374: * buffers (though on machines with 8KB pages we will to allocate
! 1375: * them separately since there will be nothing left overs.)
! 1376: */
! 1377: p = (pdq_uint8_t *) PDQ_OS_MEMALLOC_CONTIG(contig_bytes);
! 1378: if (p != NULL) {
! 1379: pdq_physaddr_t physaddr = PDQ_OS_VA_TO_PA(pdq, p);
! 1380: /*
! 1381: * Assert that we really got contiguous memory. This isn't really
! 1382: * needed on systems that actually have physical contiguous allocation
! 1383: * routines, but on those systems that don't ...
! 1384: */
! 1385: for (idx = PDQ_OS_PAGESIZE; idx < 0x2000; idx += PDQ_OS_PAGESIZE) {
! 1386: if (PDQ_OS_VA_TO_PA(pdq, p + idx) - physaddr != idx)
! 1387: goto cleanup_and_return;
! 1388: }
! 1389: physaddr &= 0x1FFF;
! 1390: if (physaddr) {
! 1391: pdq->pdq_unsolicited_info.ui_events = (pdq_unsolicited_event_t *) p;
! 1392: pdq->pdq_dbp = (pdq_descriptor_block_t *) &p[0x2000 - physaddr];
! 1393: } else {
! 1394: pdq->pdq_dbp = (pdq_descriptor_block_t *) p;
! 1395: pdq->pdq_unsolicited_info.ui_events = (pdq_unsolicited_event_t *) &p[0x2000];
! 1396: }
! 1397: }
! 1398: if (contig_bytes == sizeof(pdq_descriptor_block_t)) {
! 1399: pdq->pdq_unsolicited_info.ui_events =
! 1400: (pdq_unsolicited_event_t *) PDQ_OS_MEMALLOC(
! 1401: PDQ_NUM_UNSOLICITED_EVENTS * sizeof(pdq_unsolicited_event_t));
! 1402: }
! 1403:
! 1404: /*
! 1405: * Make sure everything got allocated. If not, free what did
! 1406: * get allocated and return.
! 1407: */
! 1408: if (pdq->pdq_dbp == NULL || pdq->pdq_unsolicited_info.ui_events == NULL) {
! 1409: cleanup_and_return:
! 1410: if (p /* pdq->pdq_dbp */ != NULL)
! 1411: PDQ_OS_MEMFREE_CONTIG(p /* pdq->pdq_dbp */, contig_bytes);
! 1412: if (contig_bytes == sizeof(pdq_descriptor_block_t) && pdq->pdq_unsolicited_info.ui_events != NULL)
! 1413: PDQ_OS_MEMFREE(pdq->pdq_unsolicited_info.ui_events,
! 1414: PDQ_NUM_UNSOLICITED_EVENTS * sizeof(pdq_unsolicited_event_t));
! 1415: PDQ_OS_MEMFREE(pdq, sizeof(pdq_t));
! 1416: return NULL;
! 1417: }
! 1418:
! 1419: pdq->pdq_cbp = (volatile pdq_consumer_block_t *) &pdq->pdq_dbp->pdqdb_consumer;
! 1420: pdq->pdq_command_info.ci_bufstart = (pdq_uint8_t *) pdq->pdq_dbp->pdqdb_command_pool;
! 1421: pdq->pdq_rx_info.rx_buffers = (void *) pdq->pdq_dbp->pdqdb_receive_buffers;
! 1422:
! 1423: pdq->pdq_host_smt_info.rx_buffers = (void *) pdq->pdq_dbp->pdqdb_host_smt_buffers;
! 1424:
! 1425: PDQ_PRINTF(("\nPDQ Descriptor Block = " PDQ_OS_PTR_FMT "\n", pdq->pdq_dbp));
! 1426: PDQ_PRINTF((" Receive Queue = " PDQ_OS_PTR_FMT "\n", pdq->pdq_dbp->pdqdb_receives));
! 1427: PDQ_PRINTF((" Transmit Queue = " PDQ_OS_PTR_FMT "\n", pdq->pdq_dbp->pdqdb_transmits));
! 1428: PDQ_PRINTF((" Host SMT Queue = " PDQ_OS_PTR_FMT "\n", pdq->pdq_dbp->pdqdb_host_smt));
! 1429: PDQ_PRINTF((" Command Response Queue = " PDQ_OS_PTR_FMT "\n", pdq->pdq_dbp->pdqdb_command_responses));
! 1430: PDQ_PRINTF((" Command Request Queue = " PDQ_OS_PTR_FMT "\n", pdq->pdq_dbp->pdqdb_command_requests));
! 1431: PDQ_PRINTF(("PDQ Consumer Block = " PDQ_OS_PTR_FMT "\n", pdq->pdq_cbp));
! 1432:
! 1433: /*
! 1434: * Zero out the descriptor block. Not really required but
! 1435: * it pays to be neat. This will also zero out the consumer
! 1436: * block, command pool, and buffer pointers for the receive
! 1437: * host_smt rings.
! 1438: */
! 1439: PDQ_OS_MEMZERO(pdq->pdq_dbp, sizeof(*pdq->pdq_dbp));
! 1440:
! 1441: /*
! 1442: * Initialize the CSR references.
! 1443: * the DEFAA (FutureBus+) skips a longword between registers
! 1444: */
! 1445: pdq_init_csrs(&pdq->pdq_csrs, bus, csr_base, pdq->pdq_type == PDQ_DEFAA ? 2 : 1);
! 1446: if (pdq->pdq_type == PDQ_DEFPA)
! 1447: pdq_init_pci_csrs(&pdq->pdq_pci_csrs, bus, csr_base, 1);
! 1448:
! 1449: PDQ_PRINTF(("PDQ CSRs: BASE = " PDQ_OS_PTR_FMT "\n", pdq->pdq_csrs.csr_base));
! 1450: PDQ_PRINTF((" Port Reset = " PDQ_OS_PTR_FMT " [0x%08x]\n",
! 1451: pdq->pdq_csrs.csr_port_reset, PDQ_CSR_READ(&pdq->pdq_csrs, csr_port_reset)));
! 1452: PDQ_PRINTF((" Host Data = " PDQ_OS_PTR_FMT " [0x%08x]\n",
! 1453: pdq->pdq_csrs.csr_host_data, PDQ_CSR_READ(&pdq->pdq_csrs, csr_host_data)));
! 1454: PDQ_PRINTF((" Port Control = " PDQ_OS_PTR_FMT " [0x%08x]\n",
! 1455: pdq->pdq_csrs.csr_port_control, PDQ_CSR_READ(&pdq->pdq_csrs, csr_port_control)));
! 1456: PDQ_PRINTF((" Port Data A = " PDQ_OS_PTR_FMT " [0x%08x]\n",
! 1457: pdq->pdq_csrs.csr_port_data_a, PDQ_CSR_READ(&pdq->pdq_csrs, csr_port_data_a)));
! 1458: PDQ_PRINTF((" Port Data B = " PDQ_OS_PTR_FMT " [0x%08x]\n",
! 1459: pdq->pdq_csrs.csr_port_data_b, PDQ_CSR_READ(&pdq->pdq_csrs, csr_port_data_b)));
! 1460: PDQ_PRINTF((" Port Status = " PDQ_OS_PTR_FMT " [0x%08x]\n",
! 1461: pdq->pdq_csrs.csr_port_status, PDQ_CSR_READ(&pdq->pdq_csrs, csr_port_status)));
! 1462: PDQ_PRINTF((" Host Int Type 0 = " PDQ_OS_PTR_FMT " [0x%08x]\n",
! 1463: pdq->pdq_csrs.csr_host_int_type_0, PDQ_CSR_READ(&pdq->pdq_csrs, csr_host_int_type_0)));
! 1464: PDQ_PRINTF((" Host Int Enable = " PDQ_OS_PTR_FMT " [0x%08x]\n",
! 1465: pdq->pdq_csrs.csr_host_int_enable, PDQ_CSR_READ(&pdq->pdq_csrs, csr_host_int_enable)));
! 1466: PDQ_PRINTF((" Type 2 Producer = " PDQ_OS_PTR_FMT " [0x%08x]\n",
! 1467: pdq->pdq_csrs.csr_type_2_producer, PDQ_CSR_READ(&pdq->pdq_csrs, csr_type_2_producer)));
! 1468: PDQ_PRINTF((" Command Response Producer = " PDQ_OS_PTR_FMT " [0x%08x]\n",
! 1469: pdq->pdq_csrs.csr_cmd_response_producer, PDQ_CSR_READ(&pdq->pdq_csrs, csr_cmd_response_producer)));
! 1470: PDQ_PRINTF((" Command Request Producer = " PDQ_OS_PTR_FMT " [0x%08x]\n",
! 1471: pdq->pdq_csrs.csr_cmd_request_producer, PDQ_CSR_READ(&pdq->pdq_csrs, csr_cmd_request_producer)));
! 1472: PDQ_PRINTF((" Host SMT Producer = " PDQ_OS_PTR_FMT " [0x%08x]\n",
! 1473: pdq->pdq_csrs.csr_host_smt_producer, PDQ_CSR_READ(&pdq->pdq_csrs, csr_host_smt_producer)));
! 1474: PDQ_PRINTF((" Unsolicited Producer = " PDQ_OS_PTR_FMT " [0x%08x]\n",
! 1475: pdq->pdq_csrs.csr_unsolicited_producer, PDQ_CSR_READ(&pdq->pdq_csrs, csr_unsolicited_producer)));
! 1476:
! 1477: /*
! 1478: * Initialize the command information block
! 1479: */
! 1480: pdq->pdq_command_info.ci_pa_bufstart = PDQ_OS_VA_TO_PA(pdq, pdq->pdq_command_info.ci_bufstart);
! 1481: for (idx = 0; idx < sizeof(pdq->pdq_dbp->pdqdb_command_requests)/sizeof(pdq->pdq_dbp->pdqdb_command_requests[0]); idx++) {
! 1482: pdq_txdesc_t *txd = &pdq->pdq_dbp->pdqdb_command_requests[idx];
! 1483:
! 1484: txd->txd_pa_lo = pdq->pdq_command_info.ci_pa_bufstart;
! 1485: txd->txd_eop = txd->txd_sop = 1;
! 1486: txd->txd_pa_hi = 0;
! 1487: }
! 1488: for (idx = 0; idx < sizeof(pdq->pdq_dbp->pdqdb_command_responses)/sizeof(pdq->pdq_dbp->pdqdb_command_responses[0]); idx++) {
! 1489: pdq_rxdesc_t *rxd = &pdq->pdq_dbp->pdqdb_command_responses[idx];
! 1490:
! 1491: rxd->rxd_pa_lo = pdq->pdq_command_info.ci_pa_bufstart;
! 1492: rxd->rxd_sop = 1;
! 1493: rxd->rxd_seg_cnt = 0;
! 1494: rxd->rxd_seg_len_lo = 0;
! 1495: }
! 1496:
! 1497: /*
! 1498: * Initialize the unsolicited event information block
! 1499: */
! 1500: pdq->pdq_unsolicited_info.ui_free = PDQ_NUM_UNSOLICITED_EVENTS;
! 1501: pdq->pdq_unsolicited_info.ui_pa_bufstart = PDQ_OS_VA_TO_PA(pdq, pdq->pdq_unsolicited_info.ui_events);
! 1502: for (idx = 0; idx < sizeof(pdq->pdq_dbp->pdqdb_unsolicited_events)/sizeof(pdq->pdq_dbp->pdqdb_unsolicited_events[0]); idx++) {
! 1503: pdq_rxdesc_t *rxd = &pdq->pdq_dbp->pdqdb_unsolicited_events[idx];
! 1504: pdq_unsolicited_event_t *event = &pdq->pdq_unsolicited_info.ui_events[idx & (PDQ_NUM_UNSOLICITED_EVENTS-1)];
! 1505:
! 1506: rxd->rxd_sop = 1;
! 1507: rxd->rxd_seg_cnt = 0;
! 1508: rxd->rxd_seg_len_hi = sizeof(pdq_unsolicited_event_t) / 16;
! 1509: rxd->rxd_pa_lo = pdq->pdq_unsolicited_info.ui_pa_bufstart + (const pdq_uint8_t *) event
! 1510: - (const pdq_uint8_t *) pdq->pdq_unsolicited_info.ui_events;
! 1511: rxd->rxd_pa_hi = 0;
! 1512: }
! 1513: /*
! 1514: * Initialize the receive information blocks (normal and SMT).
! 1515: */
! 1516: pdq->pdq_rx_info.rx_free = PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_receives);
! 1517: pdq->pdq_rx_info.rx_target = pdq->pdq_rx_info.rx_free - PDQ_RX_SEGCNT * 8;
! 1518:
! 1519: pdq->pdq_host_smt_info.rx_free = PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_host_smt);
! 1520: pdq->pdq_host_smt_info.rx_target = pdq->pdq_host_smt_info.rx_free - PDQ_RX_SEGCNT * 3;
! 1521:
! 1522: /*
! 1523: * Initialize the transmit information block.
! 1524: */
! 1525: pdq->pdq_tx_hdr[0] = PDQ_FDDI_PH0;
! 1526: pdq->pdq_tx_hdr[1] = PDQ_FDDI_PH1;
! 1527: pdq->pdq_tx_hdr[2] = PDQ_FDDI_PH2;
! 1528: pdq->pdq_tx_info.tx_free = PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_transmits);
! 1529: pdq->pdq_tx_info.tx_hdrdesc.txd_seg_len = sizeof(pdq->pdq_tx_hdr);
! 1530: pdq->pdq_tx_info.tx_hdrdesc.txd_sop = 1;
! 1531: pdq->pdq_tx_info.tx_hdrdesc.txd_pa_lo = PDQ_OS_VA_TO_PA(pdq, pdq->pdq_tx_hdr);
! 1532:
! 1533: state = PDQ_PSTS_ADAPTER_STATE(PDQ_CSR_READ(&pdq->pdq_csrs, csr_port_status));
! 1534: PDQ_PRINTF(("PDQ Adapter State = %s\n", pdq_adapter_states[state]));
! 1535:
! 1536: /*
! 1537: * Stop the PDQ if it is running and put it into a known state.
! 1538: */
! 1539: state = pdq_stop(pdq);
! 1540:
! 1541: PDQ_PRINTF(("PDQ Adapter State = %s\n", pdq_adapter_states[state]));
! 1542: PDQ_ASSERT(state == PDQS_DMA_AVAILABLE);
! 1543: /*
! 1544: * If the adapter is not the state we expect, then the initialization
! 1545: * failed. Cleanup and exit.
! 1546: */
! 1547: #if defined(PDQVERBOSE)
! 1548: if (state == PDQS_HALTED) {
! 1549: pdq_halt_code_t halt_code = PDQ_PSTS_HALT_ID(PDQ_CSR_READ(&pdq->pdq_csrs, csr_port_status));
! 1550: printf("Halt code = %d (%s)\n", halt_code, pdq_halt_codes[halt_code]);
! 1551: if (halt_code == PDQH_DMA_ERROR && pdq->pdq_type == PDQ_DEFPA)
! 1552: PDQ_PRINTF(("PFI status = 0x%x, Host 0 Fatal Interrupt = 0x%x\n",
! 1553: PDQ_CSR_READ(&pdq->pdq_pci_csrs, csr_pfi_status),
! 1554: PDQ_CSR_READ(&pdq->pdq_csrs, csr_host_int_type_0) & PDQ_HOST_INT_FATAL_ERROR));
! 1555: }
! 1556: #endif
! 1557: if (state == PDQS_RESET || state == PDQS_HALTED || state == PDQS_UPGRADE)
! 1558: goto cleanup_and_return;
! 1559:
! 1560: PDQ_PRINTF(("PDQ Hardware Address = %02x-%02x-%02x-%02x-%02x-%02x\n",
! 1561: pdq->pdq_hwaddr.lanaddr_bytes[0], pdq->pdq_hwaddr.lanaddr_bytes[1],
! 1562: pdq->pdq_hwaddr.lanaddr_bytes[2], pdq->pdq_hwaddr.lanaddr_bytes[3],
! 1563: pdq->pdq_hwaddr.lanaddr_bytes[4], pdq->pdq_hwaddr.lanaddr_bytes[5]));
! 1564: PDQ_PRINTF(("PDQ Firmware Revision = %c%c%c%c\n",
! 1565: pdq->pdq_fwrev.fwrev_bytes[0], pdq->pdq_fwrev.fwrev_bytes[1],
! 1566: pdq->pdq_fwrev.fwrev_bytes[2], pdq->pdq_fwrev.fwrev_bytes[3]));
! 1567: PDQ_PRINTF(("PDQ Chip Revision = "));
! 1568: switch (pdq->pdq_chip_rev) {
! 1569: case PDQ_CHIP_REV_A_B_OR_C: PDQ_PRINTF(("Rev C or below")); break;
! 1570: case PDQ_CHIP_REV_D: PDQ_PRINTF(("Rev D")); break;
! 1571: case PDQ_CHIP_REV_E: PDQ_PRINTF(("Rev E")); break;
! 1572: default: PDQ_PRINTF(("Unknown Rev %d", (int) pdq->pdq_chip_rev));
! 1573: }
! 1574: PDQ_PRINTF(("\n"));
! 1575:
! 1576: return pdq;
! 1577: }
CVSweb