summaryrefslogtreecommitdiffstats
path: root/sys/dev/pdq
diff options
context:
space:
mode:
authorjoerg <joerg@FreeBSD.org>1997-01-17 23:19:49 +0000
committerjoerg <joerg@FreeBSD.org>1997-01-17 23:19:49 +0000
commitdc55a901ea7d8f8b088f138e4e22f8af4542ec20 (patch)
tree3910fc06f6baae635c003bf32a482eab2638ddef /sys/dev/pdq
parentb01fce83c6d5a6d2cc7e32bf016cbb5fdd2a24e2 (diff)
parent2ac86283c8a524ff9bb540d04cc699cb60157750 (diff)
downloadFreeBSD-src-dc55a901ea7d8f8b088f138e4e22f8af4542ec20.zip
FreeBSD-src-dc55a901ea7d8f8b088f138e4e22f8af4542ec20.tar.gz
This commit was generated by cvs2svn to compensate for changes in r21826,
which included commits to RCS files with non-trunk default branches.
Diffstat (limited to 'sys/dev/pdq')
-rw-r--r--sys/dev/pdq/pdq.c1584
-rw-r--r--sys/dev/pdq/pdq_ifsubr.c404
-rw-r--r--sys/dev/pdq/pdqreg.h1065
-rw-r--r--sys/dev/pdq/pdqvar.h351
4 files changed, 3404 insertions, 0 deletions
diff --git a/sys/dev/pdq/pdq.c b/sys/dev/pdq/pdq.c
new file mode 100644
index 0000000..ad0b5a7
--- /dev/null
+++ b/sys/dev/pdq/pdq.c
@@ -0,0 +1,1584 @@
+/*-
+ * Copyright (c) 1995,1996 Matt Thomas <matt@3am-software.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: pdq.c,v 1.28 1996/07/31 21:38:44 thomas Exp $
+ *
+ */
+
+/*
+ * DEC PDQ FDDI Controller O/S independent code
+ *
+ * This module should work any PDQ based board. Note that changes for
+ * MIPS and Alpha architectures (or any other architecture which requires
+ * a flushing of memory or write buffers and/or has incoherent caches)
+ * have yet to be made.
+ *
+ * However, it is expected that the PDQ_CSR_WRITE macro will cause a
+ * flushing of the write buffers.
+ */
+
+#define PDQ_HWSUPPORT /* for pdq.h */
+
+#include "pdqvar.h"
+#include "pdqreg.h"
+
+#define PDQ_ROUNDUP(n, x) (((n) + ((x) - 1)) & ~((x) - 1))
+#define PDQ_CMD_RX_ALIGNMENT 16
+
+#if (defined(PDQTEST) && !defined(PDQ_NOPRINTF)) || defined(PDQVERBOSE)
+#define PDQ_PRINTF(x) printf x
+#else
+#define PDQ_PRINTF(x) do { } while (0)
+#endif
+
+static const char * const pdq_halt_codes[] = {
+ "Selftest Timeout", "Host Bus Parity Error", "Host Directed Fault",
+ "Software Fault", "Hardware Fault", "PC Trace Path Test",
+ "DMA Error", "Image CRC Error", "Adapter Processer Error"
+};
+
+static const char * const pdq_adapter_states[] = {
+ "Reset", "Upgrade", "DMA Unavailable", "DMA Available",
+ "Link Available", "Link Unavailable", "Halted", "Ring Member"
+};
+
+/*
+ * The following are used in conjunction with
+ * unsolicited events
+ */
+static const char * const pdq_entities[] = {
+ "Station", "Link", "Phy Port"
+};
+
+static const char * const pdq_station_events[] = {
+ "Trace Received"
+};
+
+static const char * const pdq_station_arguments[] = {
+ "Reason"
+};
+
+static const char * const pdq_link_events[] = {
+ "Transmit Underrun",
+ "Transmit Failed",
+ "Block Check Error (CRC)",
+ "Frame Status Error",
+ "PDU Length Error",
+ NULL,
+ NULL,
+ "Receive Data Overrun",
+ NULL,
+ "No User Buffer",
+ "Ring Initialization Initiated",
+ "Ring Initialization Received",
+ "Ring Beacon Initiated",
+ "Duplicate Address Failure",
+ "Duplicate Token Detected",
+ "Ring Purger Error",
+ "FCI Strip Error",
+ "Trace Initiated",
+ "Directed Beacon Received",
+};
+
+static const char * const pdq_link_arguments[] = {
+ "Reason",
+ "Data Link Header",
+ "Source",
+ "Upstream Neighbor"
+};
+
+static const char * const pdq_phy_events[] = {
+ "LEM Error Monitor Reject",
+ "Elasticy Buffer Error",
+ "Link Confidence Test Reject"
+};
+
+static const char * const pdq_phy_arguments[] = {
+ "Direction"
+};
+
+static const char * const * const pdq_event_arguments[] = {
+ pdq_station_arguments,
+ pdq_link_arguments,
+ pdq_phy_arguments
+};
+
+static const char * const * const pdq_event_codes[] = {
+ pdq_station_events,
+ pdq_link_events,
+ pdq_phy_events
+};
+
+static const char * const pdq_station_types[] = {
+ "SAS", "DAC", "SAC", "NAC", "DAS"
+};
+
+static const char * const pdq_smt_versions[] = { "", "V6.2", "V7.2", "V7.3" };
+
+static const char pdq_phy_types[] = "ABSM";
+
+static const char * const pdq_pmd_types0[] = {
+ "ANSI Multi-Mode", "ANSI Single-Mode Type 1", "ANSI Single-Mode Type 2",
+ "ANSI Sonet"
+};
+
+static const char * const pdq_pmd_types100[] = {
+ "Low Power", "Thin Wire", "Shielded Twisted Pair",
+ "Unshielded Twisted Pair"
+};
+
+static const char * const * const pdq_pmd_types[] = {
+ pdq_pmd_types0, pdq_pmd_types100
+};
+
+static const char * const pdq_descriptions[] = {
+ "DEFPA PCI",
+ "DEFEA EISA",
+ "DEFTA TC",
+ "DEFAA Futurebus",
+ "DEFQA Q-bus",
+};
+
+static void
+pdq_print_fddi_chars(
+ pdq_t *pdq,
+ const pdq_response_status_chars_get_t *rsp)
+{
+ const char hexchars[] = "0123456789abcdef";
+
+ printf(
+#if !defined(__bsdi__) && !defined(__NetBSD__)
+ PDQ_OS_PREFIX
+#else
+ ": "
+#endif
+ "DEC %s FDDI %s Controller\n",
+#if !defined(__bsdi__) && !defined(__NetBSD__)
+ PDQ_OS_PREFIX_ARGS,
+#endif
+ pdq_descriptions[pdq->pdq_type],
+ pdq_station_types[rsp->status_chars_get.station_type]);
+
+ 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",
+ PDQ_OS_PREFIX_ARGS,
+ hexchars[pdq->pdq_hwaddr.lanaddr_bytes[0] >> 4],
+ hexchars[pdq->pdq_hwaddr.lanaddr_bytes[0] & 0x0F],
+ hexchars[pdq->pdq_hwaddr.lanaddr_bytes[1] >> 4],
+ hexchars[pdq->pdq_hwaddr.lanaddr_bytes[1] & 0x0F],
+ hexchars[pdq->pdq_hwaddr.lanaddr_bytes[2] >> 4],
+ hexchars[pdq->pdq_hwaddr.lanaddr_bytes[2] & 0x0F],
+ hexchars[pdq->pdq_hwaddr.lanaddr_bytes[3] >> 4],
+ hexchars[pdq->pdq_hwaddr.lanaddr_bytes[3] & 0x0F],
+ hexchars[pdq->pdq_hwaddr.lanaddr_bytes[4] >> 4],
+ hexchars[pdq->pdq_hwaddr.lanaddr_bytes[4] & 0x0F],
+ hexchars[pdq->pdq_hwaddr.lanaddr_bytes[5] >> 4],
+ hexchars[pdq->pdq_hwaddr.lanaddr_bytes[5] & 0x0F],
+ pdq->pdq_fwrev.fwrev_bytes[0], pdq->pdq_fwrev.fwrev_bytes[1],
+ pdq->pdq_fwrev.fwrev_bytes[2], pdq->pdq_fwrev.fwrev_bytes[3],
+ rsp->status_chars_get.module_rev.fwrev_bytes[0]);
+
+ if (rsp->status_chars_get.smt_version_id < PDQ_ARRAY_SIZE(pdq_smt_versions)) {
+ printf(", SMT %s\n", pdq_smt_versions[rsp->status_chars_get.smt_version_id]);
+ }
+
+ printf(PDQ_OS_PREFIX "FDDI Port%s = %c (PMD = %s)",
+ PDQ_OS_PREFIX_ARGS,
+ rsp->status_chars_get.station_type == PDQ_STATION_TYPE_DAS ? "[A]" : "",
+ pdq_phy_types[rsp->status_chars_get.phy_type[0]],
+ pdq_pmd_types[rsp->status_chars_get.pmd_type[0] / 100][rsp->status_chars_get.pmd_type[0] % 100]);
+
+ if (rsp->status_chars_get.station_type == PDQ_STATION_TYPE_DAS)
+ printf(", FDDI Port[B] = %c (PMD = %s)",
+ pdq_phy_types[rsp->status_chars_get.phy_type[1]],
+ pdq_pmd_types[rsp->status_chars_get.pmd_type[1] / 100][rsp->status_chars_get.pmd_type[1] % 100]);
+
+ printf("\n");
+}
+
+static void
+pdq_init_csrs(
+ pdq_csrs_t *csrs,
+ pdq_bus_t bus,
+ pdq_bus_memaddr_t csr_base,
+ size_t csrsize)
+{
+ csrs->csr_bus = bus;
+ csrs->csr_base = csr_base;
+ csrs->csr_port_reset = PDQ_CSR_OFFSET(csr_base, 0 * csrsize);
+ csrs->csr_host_data = PDQ_CSR_OFFSET(csr_base, 1 * csrsize);
+ csrs->csr_port_control = PDQ_CSR_OFFSET(csr_base, 2 * csrsize);
+ csrs->csr_port_data_a = PDQ_CSR_OFFSET(csr_base, 3 * csrsize);
+ csrs->csr_port_data_b = PDQ_CSR_OFFSET(csr_base, 4 * csrsize);
+ csrs->csr_port_status = PDQ_CSR_OFFSET(csr_base, 5 * csrsize);
+ csrs->csr_host_int_type_0 = PDQ_CSR_OFFSET(csr_base, 6 * csrsize);
+ csrs->csr_host_int_enable = PDQ_CSR_OFFSET(csr_base, 7 * csrsize);
+ csrs->csr_type_2_producer = PDQ_CSR_OFFSET(csr_base, 8 * csrsize);
+ csrs->csr_cmd_response_producer = PDQ_CSR_OFFSET(csr_base, 10 * csrsize);
+ csrs->csr_cmd_request_producer = PDQ_CSR_OFFSET(csr_base, 11 * csrsize);
+ csrs->csr_host_smt_producer = PDQ_CSR_OFFSET(csr_base, 12 * csrsize);
+ csrs->csr_unsolicited_producer = PDQ_CSR_OFFSET(csr_base, 13 * csrsize);
+}
+
+static void
+pdq_init_pci_csrs(
+ pdq_pci_csrs_t *csrs,
+ pdq_bus_t bus,
+ pdq_bus_memaddr_t csr_base,
+ size_t csrsize)
+{
+ csrs->csr_bus = bus;
+ csrs->csr_base = csr_base;
+ csrs->csr_pfi_mode_control = PDQ_CSR_OFFSET(csr_base, 16 * csrsize);
+ csrs->csr_pfi_status = PDQ_CSR_OFFSET(csr_base, 17 * csrsize);
+ csrs->csr_fifo_write = PDQ_CSR_OFFSET(csr_base, 18 * csrsize);
+ csrs->csr_fifo_read = PDQ_CSR_OFFSET(csr_base, 19 * csrsize);
+}
+
+static void
+pdq_flush_databuf_queue(
+ pdq_databuf_queue_t *q)
+{
+ PDQ_OS_DATABUF_T *pdu;
+ for (;;) {
+ PDQ_OS_DATABUF_DEQUEUE(q, pdu);
+ if (pdu == NULL)
+ return;
+ PDQ_OS_DATABUF_FREE(pdu);
+ }
+}
+
+static pdq_boolean_t
+pdq_do_port_control(
+ const pdq_csrs_t * const csrs,
+ pdq_uint32_t cmd)
+{
+ int cnt = 0;
+ PDQ_CSR_WRITE(csrs, csr_host_int_type_0, PDQ_HOST_INT_CSR_CMD_DONE);
+ PDQ_CSR_WRITE(csrs, csr_port_control, PDQ_PCTL_CMD_ERROR | cmd);
+ while ((PDQ_CSR_READ(csrs, csr_host_int_type_0) & PDQ_HOST_INT_CSR_CMD_DONE) == 0 && cnt < 33000000)
+ cnt++;
+ PDQ_PRINTF(("CSR cmd spun %d times\n", cnt));
+ if (PDQ_CSR_READ(csrs, csr_host_int_type_0) & PDQ_HOST_INT_CSR_CMD_DONE) {
+ PDQ_CSR_WRITE(csrs, csr_host_int_type_0, PDQ_HOST_INT_CSR_CMD_DONE);
+ return (PDQ_CSR_READ(csrs, csr_port_control) & PDQ_PCTL_CMD_ERROR) ? PDQ_FALSE : PDQ_TRUE;
+ }
+ /* adapter failure */
+ PDQ_ASSERT(0);
+ return PDQ_FALSE;
+}
+
+static void
+pdq_read_mla(
+ const pdq_csrs_t * const csrs,
+ pdq_lanaddr_t *hwaddr)
+{
+ pdq_uint32_t data;
+
+ PDQ_CSR_WRITE(csrs, csr_port_data_a, 0);
+ pdq_do_port_control(csrs, PDQ_PCTL_MLA_READ);
+ data = PDQ_CSR_READ(csrs, csr_host_data);
+
+ hwaddr->lanaddr_bytes[0] = (data >> 0) & 0xFF;
+ hwaddr->lanaddr_bytes[1] = (data >> 8) & 0xFF;
+ hwaddr->lanaddr_bytes[2] = (data >> 16) & 0xFF;
+ hwaddr->lanaddr_bytes[3] = (data >> 24) & 0xFF;
+
+ PDQ_CSR_WRITE(csrs, csr_port_data_a, 1);
+ pdq_do_port_control(csrs, PDQ_PCTL_MLA_READ);
+ data = PDQ_CSR_READ(csrs, csr_host_data);
+
+ hwaddr->lanaddr_bytes[4] = (data >> 0) & 0xFF;
+ hwaddr->lanaddr_bytes[5] = (data >> 8) & 0xFF;
+}
+
+static void
+pdq_read_fwrev(
+ const pdq_csrs_t * const csrs,
+ pdq_fwrev_t *fwrev)
+{
+ pdq_uint32_t data;
+
+ pdq_do_port_control(csrs, PDQ_PCTL_FW_REV_READ);
+ data = PDQ_CSR_READ(csrs, csr_host_data);
+
+ fwrev->fwrev_bytes[3] = (data >> 0) & 0xFF;
+ fwrev->fwrev_bytes[2] = (data >> 8) & 0xFF;
+ fwrev->fwrev_bytes[1] = (data >> 16) & 0xFF;
+ fwrev->fwrev_bytes[0] = (data >> 24) & 0xFF;
+}
+
+static pdq_boolean_t
+pdq_read_error_log(
+ pdq_t *pdq,
+ pdq_response_error_log_get_t *log_entry)
+{
+ const pdq_csrs_t * const csrs = &pdq->pdq_csrs;
+ pdq_uint32_t *ptr = (pdq_uint32_t *) log_entry;
+
+ pdq_do_port_control(csrs, PDQ_PCTL_ERROR_LOG_START);
+
+ while (pdq_do_port_control(csrs, PDQ_PCTL_FW_REV_READ) == PDQ_TRUE) {
+ *ptr++ = PDQ_CSR_READ(csrs, csr_host_data);
+ if ((pdq_uint8_t *) ptr - (pdq_uint8_t *) log_entry == sizeof(*log_entry))
+ break;
+ }
+ return (ptr == (pdq_uint32_t *) log_entry) ? PDQ_FALSE : PDQ_TRUE;
+}
+
+static pdq_chip_rev_t
+pdq_read_chiprev(
+ const pdq_csrs_t * const csrs)
+{
+ pdq_uint32_t data;
+
+ PDQ_CSR_WRITE(csrs, csr_port_data_a, PDQ_SUB_CMD_PDQ_REV_GET);
+ pdq_do_port_control(csrs, PDQ_PCTL_SUB_CMD);
+ data = PDQ_CSR_READ(csrs, csr_host_data);
+
+ return (pdq_chip_rev_t) data;
+}
+
+static const struct {
+ size_t cmd_len;
+ size_t rsp_len;
+ const char *cmd_name;
+} pdq_cmd_info[] = {
+ { sizeof(pdq_cmd_generic_t), /* 0 - PDQC_START */
+ sizeof(pdq_response_generic_t),
+ "Start"
+ },
+ { sizeof(pdq_cmd_filter_set_t), /* 1 - PDQC_FILTER_SET */
+ sizeof(pdq_response_generic_t),
+ "Filter Set"
+ },
+ { sizeof(pdq_cmd_generic_t), /* 2 - PDQC_FILTER_GET */
+ sizeof(pdq_response_filter_get_t),
+ "Filter Get"
+ },
+ { sizeof(pdq_cmd_chars_set_t), /* 3 - PDQC_CHARS_SET */
+ sizeof(pdq_response_generic_t),
+ "Chars Set"
+ },
+ { sizeof(pdq_cmd_generic_t), /* 4 - PDQC_STATUS_CHARS_GET */
+ sizeof(pdq_response_status_chars_get_t),
+ "Status Chars Get"
+ },
+#if 0
+ { sizeof(pdq_cmd_generic_t), /* 5 - PDQC_COUNTERS_GET */
+ sizeof(pdq_response_counters_get_t),
+ "Counters Get"
+ },
+ { sizeof(pdq_cmd_counters_set_t), /* 6 - PDQC_COUNTERS_SET */
+ sizeof(pdq_response_generic_t),
+ "Counters Set"
+ },
+#else
+ { 0, 0, "Counters Get" },
+ { 0, 0, "Counters Set" },
+#endif
+ { sizeof(pdq_cmd_addr_filter_set_t), /* 7 - PDQC_ADDR_FILTER_SET */
+ sizeof(pdq_response_generic_t),
+ "Addr Filter Set"
+ },
+ { sizeof(pdq_cmd_generic_t), /* 8 - PDQC_ADDR_FILTER_GET */
+ sizeof(pdq_response_addr_filter_get_t),
+ "Addr Filter Get"
+ },
+#if 0
+ { sizeof(pdq_cmd_generic_t), /* 9 - PDQC_ERROR_LOG_CLEAR */
+ sizeof(pdq_response_generic_t),
+ "Error Log Clear"
+ },
+ { sizeof(pdq_cmd_generic_t), /* 10 - PDQC_ERROR_LOG_SET */
+ sizeof(pdq_response_generic_t),
+ "Error Log Set"
+ },
+ { sizeof(pdq_cmd_generic_t), /* 11 - PDQC_FDDI_MIB_GET */
+ sizeof(pdq_response_generic_t),
+ "FDDI MIB Get"
+ },
+ { sizeof(pdq_cmd_generic_t), /* 12 - PDQC_DEC_EXT_MIB_GET */
+ sizeof(pdq_response_generic_t),
+ "DEC Ext MIB Get"
+ },
+ { sizeof(pdq_cmd_generic_t), /* 13 - PDQC_DEC_SPECIFIC_GET */
+ sizeof(pdq_response_generic_t),
+ "DEC Specific Get"
+ },
+ { sizeof(pdq_cmd_generic_t), /* 14 - PDQC_SNMP_SET */
+ sizeof(pdq_response_generic_t),
+ "SNMP Set"
+ },
+ { 0, 0, "N/A" },
+ { sizeof(pdq_cmd_generic_t), /* 16 - PDQC_SMT_MIB_GET */
+ sizeof(pdq_response_generic_t),
+ "SMT MIB Get"
+ },
+ { sizeof(pdq_cmd_generic_t), /* 17 - PDQC_SMT_MIB_SET */
+ sizeof(pdq_response_generic_t),
+ "SMT MIB Set",
+ },
+#endif
+};
+
+static void
+pdq_queue_commands(
+ pdq_t *pdq)
+{
+ const pdq_csrs_t * const csrs = &pdq->pdq_csrs;
+ pdq_command_info_t * const ci = &pdq->pdq_command_info;
+ pdq_descriptor_block_t * const dbp = pdq->pdq_dbp;
+ pdq_cmd_code_t op;
+ pdq_uint32_t cmdlen, rsplen, mask;
+
+ /*
+ * If there are commands or responses active or there aren't
+ * any pending commands, then don't queue any more.
+ */
+ if (ci->ci_command_active || ci->ci_pending_commands == 0)
+ return;
+
+ /*
+ * Determine which command needs to be queued.
+ */
+ op = PDQC_SMT_MIB_SET;
+ for (mask = 1 << ((int) op); (mask & ci->ci_pending_commands) == 0; mask >>= 1)
+ op = (pdq_cmd_code_t) ((int) op - 1);
+ /*
+ * Obtain the sizes needed for the command and response.
+ * Round up to PDQ_CMD_RX_ALIGNMENT so the receive buffer is
+ * always properly aligned.
+ */
+ cmdlen = PDQ_ROUNDUP(pdq_cmd_info[op].cmd_len, PDQ_CMD_RX_ALIGNMENT);
+ rsplen = PDQ_ROUNDUP(pdq_cmd_info[op].rsp_len, PDQ_CMD_RX_ALIGNMENT);
+ if (cmdlen < rsplen)
+ cmdlen = rsplen;
+ /*
+ * Since only one command at a time will be queued, there will always
+ * be enough space.
+ */
+
+ /*
+ * Obtain and fill in the descriptor for the command (descriptor is
+ * pre-initialized)
+ */
+ dbp->pdqdb_command_requests[ci->ci_request_producer].txd_seg_len = cmdlen;
+ PDQ_ADVANCE(ci->ci_request_producer, 1, PDQ_RING_MASK(dbp->pdqdb_command_requests));
+
+ /*
+ * Obtain and fill in the descriptor for the response (descriptor is
+ * pre-initialized)
+ */
+ dbp->pdqdb_command_responses[ci->ci_response_producer].rxd_seg_len_hi = cmdlen / 16;
+ PDQ_ADVANCE(ci->ci_response_producer, 1, PDQ_RING_MASK(dbp->pdqdb_command_responses));
+
+ /*
+ * Clear the command area, set the opcode, and the command from the pending
+ * mask.
+ */
+
+ PDQ_OS_MEMZERO(ci->ci_bufstart, cmdlen);
+ *(pdq_cmd_code_t *) ci->ci_bufstart = op;
+ ci->ci_pending_commands &= ~mask;
+
+ /*
+ * Fill in the command area, if needed.
+ */
+ switch (op) {
+ case PDQC_FILTER_SET: {
+ pdq_cmd_filter_set_t *filter_set = (pdq_cmd_filter_set_t *) ci->ci_bufstart;
+ unsigned idx = 0;
+ filter_set->filter_set_items[idx].item_code = PDQI_IND_GROUP_PROM;
+ filter_set->filter_set_items[idx].filter_state = (pdq->pdq_flags & PDQ_PROMISC ? PDQ_FILTER_PASS : PDQ_FILTER_BLOCK);
+ idx++;
+ filter_set->filter_set_items[idx].item_code = PDQI_GROUP_PROM;
+ filter_set->filter_set_items[idx].filter_state = (pdq->pdq_flags & PDQ_ALLMULTI ? PDQ_FILTER_PASS : PDQ_FILTER_BLOCK);
+ idx++;
+ filter_set->filter_set_items[idx].item_code = PDQI_SMT_PROM;
+ 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);
+ idx++;
+ filter_set->filter_set_items[idx].item_code = PDQI_SMT_USER;
+ filter_set->filter_set_items[idx].filter_state = (pdq->pdq_flags & PDQ_PASS_SMT ? PDQ_FILTER_PASS : PDQ_FILTER_BLOCK);
+ idx++;
+ filter_set->filter_set_items[idx].item_code = PDQI_EOL;
+ break;
+ }
+ case PDQC_ADDR_FILTER_SET: {
+ pdq_cmd_addr_filter_set_t *addr_filter_set = (pdq_cmd_addr_filter_set_t *) ci->ci_bufstart;
+ pdq_lanaddr_t *addr = addr_filter_set->addr_filter_set_addresses;
+ addr->lanaddr_bytes[0] = 0xFF;
+ addr->lanaddr_bytes[1] = 0xFF;
+ addr->lanaddr_bytes[2] = 0xFF;
+ addr->lanaddr_bytes[3] = 0xFF;
+ addr->lanaddr_bytes[4] = 0xFF;
+ addr->lanaddr_bytes[5] = 0xFF;
+ addr++;
+ pdq_os_addr_fill(pdq, addr, 61);
+ break;
+ }
+ default: { /* to make gcc happy */
+ break;
+ }
+ }
+ /*
+ * At this point the command is done. All that needs to be done is to
+ * produce it to the PDQ.
+ */
+ PDQ_PRINTF(("PDQ Queue Command Request: %s queued\n",
+ pdq_cmd_info[op].cmd_name));
+
+ ci->ci_command_active++;
+ PDQ_CSR_WRITE(csrs, csr_cmd_response_producer, ci->ci_response_producer | (ci->ci_response_completion << 8));
+ PDQ_CSR_WRITE(csrs, csr_cmd_request_producer, ci->ci_request_producer | (ci->ci_request_completion << 8));
+}
+
+static void
+pdq_process_command_responses(
+ pdq_t * const pdq)
+{
+ const pdq_csrs_t * const csrs = &pdq->pdq_csrs;
+ pdq_command_info_t * const ci = &pdq->pdq_command_info;
+ volatile const pdq_consumer_block_t * const cbp = pdq->pdq_cbp;
+ pdq_descriptor_block_t * const dbp = pdq->pdq_dbp;
+ const pdq_response_generic_t *rspgen;
+
+ /*
+ * We have to process the command and response in tandem so
+ * just wait for the response to be consumed. If it has been
+ * consumed then the command must have been as well.
+ */
+
+ if (cbp->pdqcb_command_response == ci->ci_response_completion)
+ return;
+
+ PDQ_ASSERT(cbp->pdqcb_command_request != ci->ci_request_completion);
+
+ rspgen = (const pdq_response_generic_t *) ci->ci_bufstart;
+ PDQ_ASSERT(rspgen->generic_status == PDQR_SUCCESS);
+ PDQ_PRINTF(("PDQ Process Command Response: %s completed (status=%d)\n",
+ pdq_cmd_info[rspgen->generic_op].cmd_name,
+ rspgen->generic_status));
+
+ if (rspgen->generic_op == PDQC_STATUS_CHARS_GET && (pdq->pdq_flags & PDQ_PRINTCHARS)) {
+ pdq->pdq_flags &= ~PDQ_PRINTCHARS;
+ pdq_print_fddi_chars(pdq, (const pdq_response_status_chars_get_t *) rspgen);
+ }
+
+ PDQ_ADVANCE(ci->ci_request_completion, 1, PDQ_RING_MASK(dbp->pdqdb_command_requests));
+ PDQ_ADVANCE(ci->ci_response_completion, 1, PDQ_RING_MASK(dbp->pdqdb_command_responses));
+ ci->ci_command_active = 0;
+
+ if (ci->ci_pending_commands != 0) {
+ pdq_queue_commands(pdq);
+ } else {
+ PDQ_CSR_WRITE(csrs, csr_cmd_response_producer,
+ ci->ci_response_producer | (ci->ci_response_completion << 8));
+ PDQ_CSR_WRITE(csrs, csr_cmd_request_producer,
+ ci->ci_request_producer | (ci->ci_request_completion << 8));
+ }
+}
+
+/*
+ * This following routine processes unsolicited events.
+ * In addition, it also fills the unsolicited queue with
+ * event buffers so it can be used to initialize the queue
+ * as well.
+ */
+static void
+pdq_process_unsolicited_events(
+ pdq_t *pdq)
+{
+ const pdq_csrs_t * const csrs = &pdq->pdq_csrs;
+ pdq_unsolicited_info_t *ui = &pdq->pdq_unsolicited_info;
+ volatile const pdq_consumer_block_t *cbp = pdq->pdq_cbp;
+ pdq_descriptor_block_t *dbp = pdq->pdq_dbp;
+ const pdq_unsolicited_event_t *event;
+ pdq_rxdesc_t *rxd;
+
+ /*
+ * Process each unsolicited event (if any).
+ */
+
+ while (cbp->pdqcb_unsolicited_event != ui->ui_completion) {
+ rxd = &dbp->pdqdb_unsolicited_events[ui->ui_completion];
+ event = &ui->ui_events[ui->ui_completion & (PDQ_NUM_UNSOLICITED_EVENTS-1)];
+
+ switch (event->event_type) {
+ case PDQ_UNSOLICITED_EVENT: {
+ printf(PDQ_OS_PREFIX "Unsolicited Event: %s: %s",
+ PDQ_OS_PREFIX_ARGS,
+ pdq_entities[event->event_entity],
+ pdq_event_codes[event->event_entity][event->event_code.value]);
+ if (event->event_entity == PDQ_ENTITY_PHY_PORT)
+ printf("[%d]", event->event_index);
+ printf("\n");
+ break;
+ }
+ case PDQ_UNSOLICITED_COUNTERS: {
+ break;
+ }
+ }
+ PDQ_ADVANCE(ui->ui_completion, 1, PDQ_RING_MASK(dbp->pdqdb_unsolicited_events));
+ ui->ui_free++;
+ }
+
+ /*
+ * Now give back the event buffers back to the PDQ.
+ */
+ PDQ_ADVANCE(ui->ui_producer, ui->ui_free, PDQ_RING_MASK(dbp->pdqdb_unsolicited_events));
+ ui->ui_free = 0;
+
+ PDQ_CSR_WRITE(csrs, csr_unsolicited_producer,
+ ui->ui_producer | (ui->ui_completion << 8));
+}
+
+static void
+pdq_process_received_data(
+ pdq_t *pdq,
+ pdq_rx_info_t *rx,
+ pdq_rxdesc_t *receives,
+ pdq_uint32_t completion_goal,
+ pdq_uint32_t ring_mask)
+{
+ pdq_uint32_t completion = rx->rx_completion;
+ pdq_uint32_t producer = rx->rx_producer;
+ PDQ_OS_DATABUF_T **buffers = (PDQ_OS_DATABUF_T **) rx->rx_buffers;
+ pdq_rxdesc_t *rxd;
+ pdq_uint32_t idx;
+
+ while (completion != completion_goal) {
+ PDQ_OS_DATABUF_T *fpdu, *lpdu, *npdu;
+ pdq_uint8_t *dataptr;
+ pdq_uint32_t fc, datalen, pdulen, segcnt;
+ pdq_rxstatus_t status;
+
+ fpdu = lpdu = buffers[completion];
+ PDQ_ASSERT(fpdu != NULL);
+
+ dataptr = PDQ_OS_DATABUF_PTR(fpdu);
+ status = *(pdq_rxstatus_t *) dataptr;
+ if ((status.rxs_status & 0x200000) == 0) {
+ datalen = status.rxs_status & 0x1FFF;
+ fc = dataptr[PDQ_RX_FC_OFFSET];
+ switch (fc & (PDQ_FDDIFC_C|PDQ_FDDIFC_L|PDQ_FDDIFC_F)) {
+ case PDQ_FDDI_LLC_ASYNC:
+ case PDQ_FDDI_LLC_SYNC:
+ case PDQ_FDDI_IMP_ASYNC:
+ case PDQ_FDDI_IMP_SYNC: {
+ if (datalen > PDQ_FDDI_MAX || datalen < PDQ_FDDI_LLC_MIN) {
+ PDQ_PRINTF(("discard: bad length %d\n", datalen));
+ goto discard_frame;
+ }
+ break;
+ }
+ case PDQ_FDDI_SMT: {
+ if (datalen > PDQ_FDDI_MAX || datalen < PDQ_FDDI_SMT_MIN)
+ goto discard_frame;
+ break;
+ }
+ default: {
+ PDQ_PRINTF(("discard: bad fc 0x%x\n", fc));
+ goto discard_frame;
+ }
+ }
+ /*
+ * Update the lengths of the data buffers now that we know
+ * the real length.
+ */
+ pdulen = datalen - 4 /* CRC */;
+ segcnt = (pdulen + PDQ_RX_FC_OFFSET + PDQ_OS_DATABUF_SIZE - 1) / PDQ_OS_DATABUF_SIZE;
+ PDQ_OS_DATABUF_ALLOC(npdu);
+ if (npdu == NULL) {
+ PDQ_PRINTF(("discard: no databuf #0\n"));
+ goto discard_frame;
+ }
+ buffers[completion] = npdu;
+ for (idx = 1; idx < segcnt; idx++) {
+ PDQ_OS_DATABUF_ALLOC(npdu);
+ if (npdu == NULL) {
+ PDQ_OS_DATABUF_NEXT_SET(lpdu, NULL);
+ PDQ_OS_DATABUF_FREE(fpdu);
+ goto discard_frame;
+ }
+ PDQ_OS_DATABUF_NEXT_SET(lpdu, buffers[(completion + idx) & ring_mask]);
+ lpdu = PDQ_OS_DATABUF_NEXT(lpdu);
+ buffers[(completion + idx) & ring_mask] = npdu;
+ }
+ PDQ_OS_DATABUF_NEXT_SET(lpdu, NULL);
+ for (idx = 0; idx < PDQ_RX_SEGCNT; idx++) {
+ buffers[(producer + idx) & ring_mask] =
+ buffers[(completion + idx) & ring_mask];
+ buffers[(completion + idx) & ring_mask] = NULL;
+ }
+ PDQ_OS_DATABUF_ADJ(fpdu, PDQ_RX_FC_OFFSET);
+ if (segcnt == 1) {
+ PDQ_OS_DATABUF_LEN_SET(fpdu, pdulen);
+ } else {
+ PDQ_OS_DATABUF_LEN_SET(lpdu, pdulen + PDQ_RX_FC_OFFSET - (segcnt - 1) * PDQ_OS_DATABUF_SIZE);
+ }
+ pdq_os_receive_pdu(pdq, fpdu, pdulen);
+ rx->rx_free += PDQ_RX_SEGCNT;
+ PDQ_ADVANCE(producer, PDQ_RX_SEGCNT, ring_mask);
+ PDQ_ADVANCE(completion, PDQ_RX_SEGCNT, ring_mask);
+ continue;
+ } else {
+ PDQ_PRINTF(("discard: bad pdu 0x%x(%d.%d.%d.%d.%d)\n", status.rxs_status,
+ status.rxs_rcc_badpdu, status.rxs_rcc_badcrc,
+ status.rxs_rcc_reason, status.rxs_fsc, status.rxs_fsb_e));
+ if (status.rxs_rcc_reason == 7)
+ goto discard_frame;
+ if (status.rxs_rcc_reason != 0)
+ /* hardware fault */
+ if (status.rxs_rcc_badcrc) {
+ printf(PDQ_OS_PREFIX " MAC CRC error (source=%x-%x-%x-%x-%x-%x)\n",
+ PDQ_OS_PREFIX_ARGS,
+ dataptr[PDQ_RX_FC_OFFSET+1],
+ dataptr[PDQ_RX_FC_OFFSET+2],
+ dataptr[PDQ_RX_FC_OFFSET+3],
+ dataptr[PDQ_RX_FC_OFFSET+4],
+ dataptr[PDQ_RX_FC_OFFSET+5],
+ dataptr[PDQ_RX_FC_OFFSET+6]);
+ /* rx->rx_badcrc++; */
+ } else if (status.rxs_fsc == 0 | status.rxs_fsb_e == 1) {
+ /* rx->rx_frame_status_errors++; */
+ } else {
+ /* hardware fault */
+ }
+ }
+ discard_frame:
+ /*
+ * Discarded frames go right back on the queue; therefore
+ * ring entries were freed.
+ */
+ for (idx = 0; idx < PDQ_RX_SEGCNT; idx++) {
+ buffers[producer] = buffers[completion];
+ buffers[completion] = NULL;
+ rxd = &receives[rx->rx_producer];
+ if (idx == 0) {
+ rxd->rxd_sop = 1; rxd->rxd_seg_cnt = PDQ_RX_SEGCNT - 1;
+ } else {
+ rxd->rxd_sop = 0; rxd->rxd_seg_cnt = 0;
+ }
+ rxd->rxd_pa_hi = 0;
+ rxd->rxd_seg_len_hi = PDQ_OS_DATABUF_SIZE / 16;
+ rxd->rxd_pa_lo = PDQ_OS_VA_TO_PA(pdq, PDQ_OS_DATABUF_PTR(buffers[rx->rx_producer]));
+ PDQ_ADVANCE(rx->rx_producer, 1, ring_mask);
+ PDQ_ADVANCE(producer, 1, ring_mask);
+ PDQ_ADVANCE(completion, 1, ring_mask);
+ }
+ }
+ rx->rx_completion = completion;
+
+ while (rx->rx_free > PDQ_RX_SEGCNT && rx->rx_free > rx->rx_target) {
+ PDQ_OS_DATABUF_T *pdu;
+ /*
+ * Allocate the needed number of data buffers.
+ * Try to obtain them from our free queue before
+ * asking the system for more.
+ */
+ for (idx = 0; idx < PDQ_RX_SEGCNT; idx++) {
+ if ((pdu = buffers[(rx->rx_producer + idx) & ring_mask]) == NULL) {
+ PDQ_OS_DATABUF_ALLOC(pdu);
+ if (pdu == NULL)
+ break;
+ buffers[(rx->rx_producer + idx) & ring_mask] = pdu;
+ }
+ rxd = &receives[(rx->rx_producer + idx) & ring_mask];
+ if (idx == 0) {
+ rxd->rxd_sop = 1; rxd->rxd_seg_cnt = PDQ_RX_SEGCNT - 1;
+ } else {
+ rxd->rxd_sop = 0; rxd->rxd_seg_cnt = 0;
+ }
+ rxd->rxd_pa_hi = 0;
+ rxd->rxd_seg_len_hi = PDQ_OS_DATABUF_SIZE / 16;
+ rxd->rxd_pa_lo = PDQ_OS_VA_TO_PA(pdq, PDQ_OS_DATABUF_PTR(pdu));
+ }
+ if (idx < PDQ_RX_SEGCNT) {
+ /*
+ * We didn't get all databufs required to complete a new
+ * receive buffer. Keep the ones we got and retry a bit
+ * later for the rest.
+ */
+ break;
+ }
+ PDQ_ADVANCE(rx->rx_producer, PDQ_RX_SEGCNT, ring_mask);
+ rx->rx_free -= PDQ_RX_SEGCNT;
+ }
+}
+
+pdq_boolean_t
+pdq_queue_transmit_data(
+ pdq_t *pdq,
+ PDQ_OS_DATABUF_T *pdu)
+{
+ pdq_tx_info_t *tx = &pdq->pdq_tx_info;
+ pdq_descriptor_block_t *dbp = pdq->pdq_dbp;
+ pdq_uint32_t producer = tx->tx_producer;
+ pdq_txdesc_t *eop = NULL;
+ PDQ_OS_DATABUF_T *pdu0;
+ pdq_uint32_t freecnt;
+
+ if (tx->tx_free < 1)
+ return PDQ_FALSE;
+
+ dbp->pdqdb_transmits[producer] = tx->tx_hdrdesc;
+ PDQ_ADVANCE(producer, 1, PDQ_RING_MASK(dbp->pdqdb_transmits));
+
+ for (freecnt = tx->tx_free - 1, pdu0 = pdu; pdu0 != NULL && freecnt > 0;) {
+ pdq_uint32_t fraglen, datalen = PDQ_OS_DATABUF_LEN(pdu0);
+ const pdq_uint8_t *dataptr = PDQ_OS_DATABUF_PTR(pdu0);
+
+ /*
+ * The first segment is limited to the space remaining in
+ * page. All segments after that can be up to a full page
+ * in size.
+ */
+ fraglen = PDQ_OS_PAGESIZE - ((dataptr - (pdq_uint8_t *) NULL) & (PDQ_OS_PAGESIZE-1));
+ while (datalen > 0 && freecnt > 0) {
+ pdq_uint32_t seglen = (fraglen < datalen ? fraglen : datalen);
+
+ /*
+ * Initialize the transmit descriptor
+ */
+ eop = &dbp->pdqdb_transmits[producer];
+ eop->txd_seg_len = seglen;
+ eop->txd_pa_lo = PDQ_OS_VA_TO_PA(pdq, dataptr);
+ eop->txd_sop = eop->txd_eop = eop->txd_pa_hi = 0;
+
+ datalen -= seglen;
+ dataptr += seglen;
+ fraglen = PDQ_OS_PAGESIZE;
+ freecnt--;
+ PDQ_ADVANCE(producer, 1, PDQ_RING_MASK(dbp->pdqdb_transmits));
+ }
+ pdu0 = PDQ_OS_DATABUF_NEXT(pdu0);
+ }
+ if (pdu0 != NULL) {
+ PDQ_ASSERT(freecnt == 0);
+ /*
+ * If we still have data to process then the ring was too full
+ * to store the PDU. Return FALSE so the caller will requeue
+ * the PDU for later.
+ */
+ return PDQ_FALSE;
+ }
+ /*
+ * Everything went fine. Finish it up.
+ */
+ tx->tx_descriptor_count[tx->tx_producer] = tx->tx_free - freecnt;
+ eop->txd_eop = 1;
+ PDQ_OS_DATABUF_ENQUEUE(&tx->tx_txq, pdu);
+ tx->tx_producer = producer;
+ tx->tx_free = freecnt;
+ PDQ_DO_TYPE2_PRODUCER(pdq);
+ return PDQ_TRUE;
+}
+
+static void
+pdq_process_transmitted_data(
+ pdq_t *pdq)
+{
+ pdq_tx_info_t *tx = &pdq->pdq_tx_info;
+ volatile const pdq_consumer_block_t *cbp = pdq->pdq_cbp;
+ pdq_descriptor_block_t *dbp = pdq->pdq_dbp;
+ pdq_uint32_t completion = tx->tx_completion;
+
+ while (completion != cbp->pdqcb_transmits) {
+ PDQ_OS_DATABUF_T *pdu;
+ pdq_uint32_t descriptor_count = tx->tx_descriptor_count[completion];
+ PDQ_ASSERT(dbp->pdqdb_transmits[completion].txd_sop == 1);
+ PDQ_ASSERT(dbp->pdqdb_transmits[(completion + descriptor_count - 1) & PDQ_RING_MASK(dbp->pdqdb_transmits)].txd_eop == 1);
+ PDQ_OS_DATABUF_DEQUEUE(&tx->tx_txq, pdu);
+ pdq_os_transmit_done(pdq, pdu);
+ tx->tx_free += descriptor_count;
+
+ PDQ_ADVANCE(completion, descriptor_count, PDQ_RING_MASK(dbp->pdqdb_transmits));
+ }
+ if (tx->tx_completion != completion) {
+ tx->tx_completion = completion;
+ pdq_os_restart_transmitter(pdq);
+ }
+ PDQ_DO_TYPE2_PRODUCER(pdq);
+}
+
+void
+pdq_flush_transmitter(
+ pdq_t *pdq)
+{
+ volatile pdq_consumer_block_t *cbp = pdq->pdq_cbp;
+ pdq_tx_info_t *tx = &pdq->pdq_tx_info;
+
+ for (;;) {
+ PDQ_OS_DATABUF_T *pdu;
+ PDQ_OS_DATABUF_DEQUEUE(&tx->tx_txq, pdu);
+ if (pdu == NULL)
+ break;
+ /*
+ * Don't call transmit done since the packet never made it
+ * out on the wire.
+ */
+ PDQ_OS_DATABUF_FREE(pdu);
+ }
+
+ tx->tx_free = PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_transmits);
+ tx->tx_completion = cbp->pdqcb_transmits = tx->tx_producer;
+
+ PDQ_DO_TYPE2_PRODUCER(pdq);
+}
+
+void
+pdq_hwreset(
+ pdq_t *pdq)
+{
+ const pdq_csrs_t * const csrs = &pdq->pdq_csrs;
+ pdq_state_t state;
+ int cnt;
+
+ state = PDQ_PSTS_ADAPTER_STATE(PDQ_CSR_READ(csrs, csr_port_status));
+ if (state == PDQS_DMA_UNAVAILABLE)
+ return;
+ PDQ_CSR_WRITE(csrs, csr_port_data_a,
+ (state == PDQS_HALTED) ? 0 : PDQ_PRESET_SKIP_SELFTEST);
+ PDQ_CSR_WRITE(csrs, csr_port_reset, 1);
+ PDQ_OS_USEC_DELAY(100);
+ PDQ_CSR_WRITE(csrs, csr_port_reset, 0);
+ for (cnt = 45000;;cnt--) {
+ PDQ_OS_USEC_DELAY(1000);
+ state = PDQ_PSTS_ADAPTER_STATE(PDQ_CSR_READ(csrs, csr_port_status));
+ if (state == PDQS_DMA_UNAVAILABLE || cnt == 0)
+ break;
+ }
+ PDQ_PRINTF(("PDQ Reset spun %d cycles\n", 45000 - cnt));
+ PDQ_OS_USEC_DELAY(10000);
+ state = PDQ_PSTS_ADAPTER_STATE(PDQ_CSR_READ(csrs, csr_port_status));
+ PDQ_ASSERT(state == PDQS_DMA_UNAVAILABLE);
+ PDQ_ASSERT(cnt > 0);
+}
+
+/*
+ * The following routine brings the PDQ from whatever state it is
+ * in to DMA_UNAVAILABLE (ie. like a RESET but without doing a RESET).
+ */
+pdq_state_t
+pdq_stop(
+ pdq_t *pdq)
+{
+ pdq_state_t state;
+ const pdq_csrs_t * const csrs = &pdq->pdq_csrs;
+ int cnt, pass = 0, idx;
+ PDQ_OS_DATABUF_T **buffers;
+
+ restart:
+ state = PDQ_PSTS_ADAPTER_STATE(PDQ_CSR_READ(csrs, csr_port_status));
+ if (state != PDQS_DMA_UNAVAILABLE) {
+ pdq_hwreset(pdq);
+ state = PDQ_PSTS_ADAPTER_STATE(PDQ_CSR_READ(csrs, csr_port_status));
+ PDQ_ASSERT(state == PDQS_DMA_UNAVAILABLE);
+ }
+#if 0
+ switch (state) {
+ case PDQS_RING_MEMBER:
+ case PDQS_LINK_UNAVAILABLE:
+ case PDQS_LINK_AVAILABLE: {
+ PDQ_CSR_WRITE(csrs, csr_port_data_a, PDQ_SUB_CMD_LINK_UNINIT);
+ PDQ_CSR_WRITE(csrs, csr_port_data_b, 0);
+ pdq_do_port_control(csrs, PDQ_PCTL_SUB_CMD);
+ state = PDQ_PSTS_ADAPTER_STATE(PDQ_CSR_READ(csrs, csr_port_status));
+ PDQ_ASSERT(state == PDQS_DMA_AVAILABLE);
+ /* FALL THROUGH */
+ }
+ case PDQS_DMA_AVAILABLE: {
+ PDQ_CSR_WRITE(csrs, csr_port_data_a, 0);
+ PDQ_CSR_WRITE(csrs, csr_port_data_b, 0);
+ pdq_do_port_control(csrs, PDQ_PCTL_DMA_UNINIT);
+ state = PDQ_PSTS_ADAPTER_STATE(PDQ_CSR_READ(csrs, csr_port_status));
+ PDQ_ASSERT(state == PDQS_DMA_UNAVAILABLE);
+ /* FALL THROUGH */
+ }
+ case PDQS_DMA_UNAVAILABLE: {
+ break;
+ }
+ }
+#endif
+ /*
+ * Now we should be in DMA_UNAVAILABLE. So bring the PDQ into
+ * DMA_AVAILABLE.
+ */
+
+ /*
+ * Obtain the hardware address and firmware revisions
+ * (MLA = my long address which is FDDI speak for hardware address)
+ */
+ pdq_read_mla(&pdq->pdq_csrs, &pdq->pdq_hwaddr);
+ pdq_read_fwrev(&pdq->pdq_csrs, &pdq->pdq_fwrev);
+ pdq->pdq_chip_rev = pdq_read_chiprev(&pdq->pdq_csrs);
+
+ if (pdq->pdq_type == PDQ_DEFPA) {
+ /*
+ * Disable interrupts and DMA.
+ */
+ PDQ_CSR_WRITE(&pdq->pdq_pci_csrs, csr_pfi_mode_control, 0);
+ PDQ_CSR_WRITE(&pdq->pdq_pci_csrs, csr_pfi_status, 0x10);
+ }
+
+ /*
+ * Flush all the databuf queues.
+ */
+ pdq_flush_databuf_queue(&pdq->pdq_tx_info.tx_txq);
+ pdq->pdq_flags &= ~PDQ_TXOK;
+ buffers = (PDQ_OS_DATABUF_T **) pdq->pdq_rx_info.rx_buffers;
+ for (idx = 0; idx < PDQ_RING_SIZE(pdq->pdq_dbp->pdqdb_receives); idx++) {
+ if (buffers[idx] != NULL) {
+ PDQ_OS_DATABUF_FREE(buffers[idx]);
+ buffers[idx] = NULL;
+ }
+ }
+ pdq->pdq_rx_info.rx_free = PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_receives);
+ buffers = (PDQ_OS_DATABUF_T **) pdq->pdq_host_smt_info.rx_buffers;
+ for (idx = 0; idx < PDQ_RING_SIZE(pdq->pdq_dbp->pdqdb_host_smt); idx++) {
+ if (buffers[idx] != NULL) {
+ PDQ_OS_DATABUF_FREE(buffers[idx]);
+ buffers[idx] = NULL;
+ }
+ }
+ pdq->pdq_host_smt_info.rx_free = PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_host_smt);
+
+ /*
+ * Reset the consumer indexes to 0.
+ */
+ pdq->pdq_cbp->pdqcb_receives = 0;
+ pdq->pdq_cbp->pdqcb_transmits = 0;
+ pdq->pdq_cbp->pdqcb_host_smt = 0;
+ pdq->pdq_cbp->pdqcb_unsolicited_event = 0;
+ pdq->pdq_cbp->pdqcb_command_response = 0;
+ pdq->pdq_cbp->pdqcb_command_request = 0;
+
+ /*
+ * Reset the producer and completion indexes to 0.
+ */
+ pdq->pdq_command_info.ci_request_producer = 0;
+ pdq->pdq_command_info.ci_response_producer = 0;
+ pdq->pdq_command_info.ci_request_completion = 0;
+ pdq->pdq_command_info.ci_response_completion = 0;
+ pdq->pdq_unsolicited_info.ui_producer = 0;
+ pdq->pdq_unsolicited_info.ui_completion = 0;
+ pdq->pdq_rx_info.rx_producer = 0;
+ pdq->pdq_rx_info.rx_completion = 0;
+ pdq->pdq_tx_info.tx_producer = 0;
+ pdq->pdq_tx_info.tx_completion = 0;
+ pdq->pdq_host_smt_info.rx_producer = 0;
+ pdq->pdq_host_smt_info.rx_completion = 0;
+
+ pdq->pdq_command_info.ci_command_active = 0;
+ pdq->pdq_unsolicited_info.ui_free = PDQ_NUM_UNSOLICITED_EVENTS;
+ pdq->pdq_tx_info.tx_free = PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_transmits);
+
+ /*
+ * Allow the DEFPA to do DMA. Then program the physical
+ * addresses of the consumer and descriptor blocks.
+ */
+ if (pdq->pdq_type == PDQ_DEFPA) {
+#ifdef PDQTEST
+ PDQ_CSR_WRITE(&pdq->pdq_pci_csrs, csr_pfi_mode_control,
+ PDQ_PFI_MODE_DMA_ENABLE);
+#else
+ PDQ_CSR_WRITE(&pdq->pdq_pci_csrs, csr_pfi_mode_control,
+ PDQ_PFI_MODE_DMA_ENABLE
+ /*|PDQ_PFI_MODE_PFI_PCI_INTR*/|PDQ_PFI_MODE_PDQ_PCI_INTR);
+#endif
+ }
+
+ /*
+ * Make sure the unsolicited queue has events ...
+ */
+ pdq_process_unsolicited_events(pdq);
+
+ if (pdq->pdq_type == PDQ_DEFEA && pdq->pdq_chip_rev == PDQ_CHIP_REV_E)
+ PDQ_CSR_WRITE(csrs, csr_port_data_b, PDQ_DMA_BURST_16LW);
+ else
+ PDQ_CSR_WRITE(csrs, csr_port_data_b, PDQ_DMA_BURST_8LW);
+ PDQ_CSR_WRITE(csrs, csr_port_data_a, PDQ_SUB_CMD_DMA_BURST_SIZE_SET);
+ pdq_do_port_control(csrs, PDQ_PCTL_SUB_CMD);
+
+ PDQ_CSR_WRITE(csrs, csr_port_data_b, 0);
+ PDQ_CSR_WRITE(csrs, csr_port_data_a, PDQ_OS_VA_TO_PA(pdq, pdq->pdq_cbp));
+ pdq_do_port_control(csrs, PDQ_PCTL_CONSUMER_BLOCK);
+
+ PDQ_CSR_WRITE(csrs, csr_port_data_b, 0);
+ PDQ_CSR_WRITE(csrs, csr_port_data_a,
+ PDQ_OS_VA_TO_PA(pdq, pdq->pdq_dbp) | PDQ_DMA_INIT_LW_BSWAP_DATA);
+ pdq_do_port_control(csrs, PDQ_PCTL_DMA_INIT);
+
+ for (cnt = 0; cnt < 1000; cnt++) {
+ state = PDQ_PSTS_ADAPTER_STATE(PDQ_CSR_READ(csrs, csr_port_status));
+ if (state == PDQS_HALTED) {
+ if (pass > 0)
+ return PDQS_HALTED;
+ pass = 1;
+ goto restart;
+ }
+ if (state == PDQS_DMA_AVAILABLE) {
+ PDQ_PRINTF(("Transition to DMA Available took %d spins\n", cnt));
+ break;
+ }
+ PDQ_OS_USEC_DELAY(1000);
+ }
+ PDQ_ASSERT(state == PDQS_DMA_AVAILABLE);
+
+ PDQ_CSR_WRITE(csrs, csr_host_int_type_0, 0xFF);
+ PDQ_CSR_WRITE(csrs, csr_host_int_enable, 0) /* PDQ_HOST_INT_STATE_CHANGE
+ |PDQ_HOST_INT_FATAL_ERROR|PDQ_HOST_INT_CMD_RSP_ENABLE
+ |PDQ_HOST_INT_UNSOL_ENABLE */;
+
+ /*
+ * Any other command but START should be valid.
+ */
+ pdq->pdq_command_info.ci_pending_commands &= ~(PDQ_BITMASK(PDQC_START));
+ if (pdq->pdq_flags & PDQ_PRINTCHARS)
+ pdq->pdq_command_info.ci_pending_commands |= PDQ_BITMASK(PDQC_STATUS_CHARS_GET);
+ pdq_queue_commands(pdq);
+
+ if (pdq->pdq_flags & PDQ_PRINTCHARS) {
+ /*
+ * Now wait (up to 100ms) for the command(s) to finish.
+ */
+ for (cnt = 0; cnt < 1000; cnt++) {
+ pdq_process_command_responses(pdq);
+ if (pdq->pdq_command_info.ci_response_producer == pdq->pdq_command_info.ci_response_completion)
+ break;
+ PDQ_OS_USEC_DELAY(1000);
+ }
+ state = PDQ_PSTS_ADAPTER_STATE(PDQ_CSR_READ(csrs, csr_port_status));
+ }
+
+ return state;
+}
+
+void
+pdq_run(
+ pdq_t *pdq)
+{
+ const pdq_csrs_t * const csrs = &pdq->pdq_csrs;
+ pdq_state_t state;
+
+ state = PDQ_PSTS_ADAPTER_STATE(PDQ_CSR_READ(csrs, csr_port_status));
+ PDQ_ASSERT(state != PDQS_DMA_UNAVAILABLE);
+ PDQ_ASSERT(state != PDQS_RESET);
+ PDQ_ASSERT(state != PDQS_HALTED);
+ PDQ_ASSERT(state != PDQS_UPGRADE);
+ PDQ_ASSERT(state != PDQS_RING_MEMBER);
+ switch (state) {
+ case PDQS_DMA_AVAILABLE: {
+ /*
+ * The PDQ after being reset screws up some of its state.
+ * So we need to clear all the errors/interrupts so the real
+ * ones will get through.
+ */
+ PDQ_CSR_WRITE(csrs, csr_host_int_type_0, 0xFF);
+ PDQ_CSR_WRITE(csrs, csr_host_int_enable, PDQ_HOST_INT_STATE_CHANGE|PDQ_HOST_INT_XMT_DATA_FLUSH
+ |PDQ_HOST_INT_FATAL_ERROR|PDQ_HOST_INT_CMD_RSP_ENABLE|PDQ_HOST_INT_UNSOL_ENABLE
+ |PDQ_HOST_INT_RX_ENABLE|PDQ_HOST_INT_TX_ENABLE|PDQ_HOST_INT_HOST_SMT_ENABLE);
+ /*
+ * Set the MAC and address filters and start up the PDQ.
+ */
+ pdq_process_unsolicited_events(pdq);
+ pdq_process_received_data(pdq, &pdq->pdq_rx_info,
+ pdq->pdq_dbp->pdqdb_receives,
+ pdq->pdq_cbp->pdqcb_receives,
+ PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_receives));
+ PDQ_DO_TYPE2_PRODUCER(pdq);
+ if (pdq->pdq_flags & PDQ_PASS_SMT) {
+ pdq_process_received_data(pdq, &pdq->pdq_host_smt_info,
+ pdq->pdq_dbp->pdqdb_host_smt,
+ pdq->pdq_cbp->pdqcb_host_smt,
+ PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_host_smt));
+ PDQ_CSR_WRITE(csrs, csr_host_smt_producer,
+ pdq->pdq_host_smt_info.rx_producer
+ | (pdq->pdq_host_smt_info.rx_completion << 8));
+ }
+ pdq->pdq_command_info.ci_pending_commands = PDQ_BITMASK(PDQC_FILTER_SET)
+ | PDQ_BITMASK(PDQC_ADDR_FILTER_SET) | PDQ_BITMASK(PDQC_START);
+ if (pdq->pdq_flags & PDQ_PRINTCHARS)
+ pdq->pdq_command_info.ci_pending_commands |= PDQ_BITMASK(PDQC_STATUS_CHARS_GET);
+ pdq_queue_commands(pdq);
+ break;
+ }
+ case PDQS_LINK_UNAVAILABLE:
+ case PDQS_LINK_AVAILABLE: {
+ pdq->pdq_command_info.ci_pending_commands = PDQ_BITMASK(PDQC_FILTER_SET)
+ | PDQ_BITMASK(PDQC_ADDR_FILTER_SET);
+ if (pdq->pdq_flags & PDQ_PRINTCHARS)
+ pdq->pdq_command_info.ci_pending_commands |= PDQ_BITMASK(PDQC_STATUS_CHARS_GET);
+ if (pdq->pdq_flags & PDQ_PASS_SMT) {
+ pdq_process_received_data(pdq, &pdq->pdq_host_smt_info,
+ pdq->pdq_dbp->pdqdb_host_smt,
+ pdq->pdq_cbp->pdqcb_host_smt,
+ PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_host_smt));
+ PDQ_CSR_WRITE(csrs, csr_host_smt_producer,
+ pdq->pdq_host_smt_info.rx_producer
+ | (pdq->pdq_host_smt_info.rx_completion << 8));
+ }
+ pdq_process_unsolicited_events(pdq);
+ pdq_queue_commands(pdq);
+ break;
+ }
+ case PDQS_RING_MEMBER: {
+ }
+ default: { /* to make gcc happy */
+ break;
+ }
+ }
+}
+
+int
+pdq_interrupt(
+ pdq_t *pdq)
+{
+ const pdq_csrs_t * const csrs = &pdq->pdq_csrs;
+ pdq_uint32_t data;
+ int progress = 0;
+
+ if (pdq->pdq_type == PDQ_DEFPA)
+ PDQ_CSR_WRITE(&pdq->pdq_pci_csrs, csr_pfi_status, 0x18);
+
+ while ((data = PDQ_CSR_READ(csrs, csr_port_status)) & PDQ_PSTS_INTR_PENDING) {
+ progress = 1;
+ PDQ_PRINTF(("PDQ Interrupt: Status = 0x%08x\n", data));
+ if (data & PDQ_PSTS_RCV_DATA_PENDING) {
+ pdq_process_received_data(pdq, &pdq->pdq_rx_info,
+ pdq->pdq_dbp->pdqdb_receives,
+ pdq->pdq_cbp->pdqcb_receives,
+ PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_receives));
+ PDQ_DO_TYPE2_PRODUCER(pdq);
+ }
+ if (data & PDQ_PSTS_HOST_SMT_PENDING) {
+ pdq_process_received_data(pdq, &pdq->pdq_host_smt_info,
+ pdq->pdq_dbp->pdqdb_host_smt,
+ pdq->pdq_cbp->pdqcb_host_smt,
+ PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_host_smt));
+ PDQ_DO_HOST_SMT_PRODUCER(pdq);
+ }
+ if (data & PDQ_PSTS_XMT_DATA_PENDING)
+ pdq_process_transmitted_data(pdq);
+ if (data & PDQ_PSTS_UNSOL_PENDING)
+ pdq_process_unsolicited_events(pdq);
+ if (data & PDQ_PSTS_CMD_RSP_PENDING)
+ pdq_process_command_responses(pdq);
+ if (data & PDQ_PSTS_TYPE_0_PENDING) {
+ data = PDQ_CSR_READ(csrs, csr_host_int_type_0);
+ if (data & PDQ_HOST_INT_STATE_CHANGE) {
+ pdq_state_t state = PDQ_PSTS_ADAPTER_STATE(PDQ_CSR_READ(csrs, csr_port_status));
+ printf(PDQ_OS_PREFIX "%s", PDQ_OS_PREFIX_ARGS, pdq_adapter_states[state]);
+ if (state == PDQS_LINK_UNAVAILABLE) {
+ pdq->pdq_flags &= ~PDQ_TXOK;
+ } else if (state == PDQS_LINK_AVAILABLE) {
+ pdq->pdq_flags |= PDQ_TXOK;
+ pdq_os_restart_transmitter(pdq);
+ } else if (state == PDQS_HALTED) {
+ pdq_response_error_log_get_t log_entry;
+ pdq_halt_code_t halt_code = PDQ_PSTS_HALT_ID(PDQ_CSR_READ(csrs, csr_port_status));
+ printf(": halt code = %d (%s)\n",
+ halt_code, pdq_halt_codes[halt_code]);
+ if (halt_code == PDQH_DMA_ERROR && pdq->pdq_type == PDQ_DEFPA) {
+ PDQ_PRINTF(("\tPFI status = 0x%x, Host 0 Fatal Interrupt = 0x%x\n",
+ PDQ_CSR_READ(&pdq->pdq_pci_csrs, csr_pfi_status),
+ data & PDQ_HOST_INT_FATAL_ERROR));
+ }
+ pdq_read_error_log(pdq, &log_entry);
+ pdq_stop(pdq);
+ if (pdq->pdq_flags & PDQ_RUNNING)
+ pdq_run(pdq);
+ return 1;
+ }
+ printf("\n");
+ PDQ_CSR_WRITE(csrs, csr_host_int_type_0, PDQ_HOST_INT_STATE_CHANGE);
+ }
+ if (data & PDQ_HOST_INT_FATAL_ERROR) {
+ pdq_stop(pdq);
+ if (pdq->pdq_flags & PDQ_RUNNING)
+ pdq_run(pdq);
+ return 1;
+ }
+ if (data & PDQ_HOST_INT_XMT_DATA_FLUSH) {
+ printf(PDQ_OS_PREFIX "Flushing transmit queue\n", PDQ_OS_PREFIX_ARGS);
+ pdq->pdq_flags &= ~PDQ_TXOK;
+ pdq_flush_transmitter(pdq);
+ pdq_do_port_control(csrs, PDQ_PCTL_XMT_DATA_FLUSH_DONE);
+ PDQ_CSR_WRITE(csrs, csr_host_int_type_0, PDQ_HOST_INT_XMT_DATA_FLUSH);
+ }
+ }
+ if (pdq->pdq_type == PDQ_DEFPA)
+ PDQ_CSR_WRITE(&pdq->pdq_pci_csrs, csr_pfi_status, 0x18);
+ }
+ return progress;
+}
+
+pdq_t *
+pdq_initialize(
+ pdq_bus_t bus,
+ pdq_bus_memaddr_t csr_base,
+ const char *name,
+ int unit,
+ void *ctx,
+ pdq_type_t type)
+{
+ pdq_t *pdq;
+ pdq_state_t state;
+ const pdq_uint32_t contig_bytes = (sizeof(pdq_descriptor_block_t) * 2) - PDQ_OS_PAGESIZE;
+ pdq_uint8_t *p;
+ int idx;
+
+ PDQ_ASSERT(sizeof(pdq_descriptor_block_t) == 8192);
+ PDQ_ASSERT(sizeof(pdq_consumer_block_t) == 64);
+ PDQ_ASSERT(sizeof(pdq_response_filter_get_t) == PDQ_SIZE_RESPONSE_FILTER_GET);
+ PDQ_ASSERT(sizeof(pdq_cmd_addr_filter_set_t) == PDQ_SIZE_CMD_ADDR_FILTER_SET);
+ PDQ_ASSERT(sizeof(pdq_response_addr_filter_get_t) == PDQ_SIZE_RESPONSE_ADDR_FILTER_GET);
+ PDQ_ASSERT(sizeof(pdq_response_status_chars_get_t) == PDQ_SIZE_RESPONSE_STATUS_CHARS_GET);
+ PDQ_ASSERT(sizeof(pdq_response_fddi_mib_get_t) == PDQ_SIZE_RESPONSE_FDDI_MIB_GET);
+ PDQ_ASSERT(sizeof(pdq_response_dec_ext_mib_get_t) == PDQ_SIZE_RESPONSE_DEC_EXT_MIB_GET);
+ PDQ_ASSERT(sizeof(pdq_unsolicited_event_t) == 512);
+
+ pdq = (pdq_t *) PDQ_OS_MEMALLOC(sizeof(pdq_t));
+ if (pdq == NULL) {
+ PDQ_PRINTF(("malloc(%d) failed\n", sizeof(*pdq)));
+ return NULL;
+ }
+ PDQ_OS_MEMZERO(pdq, sizeof(pdq_t));
+ pdq->pdq_type = type;
+ pdq->pdq_unit = unit;
+ pdq->pdq_os_ctx = (void *) ctx;
+ pdq->pdq_os_name = name;
+ pdq->pdq_flags = PDQ_PRINTCHARS;
+ /*
+ * Allocate the additional data structures required by
+ * the PDQ driver. Allocate a contiguous region of memory
+ * for the descriptor block. We need to allocated enough
+ * to guarantee that we will a get 8KB block of memory aligned
+ * on a 8KB boundary. This turns to require that we allocate
+ * (N*2 - 1 page) pages of memory. On machine with less than
+ * a 8KB page size, it mean we will allocate more memory than
+ * we need. The extra will be used for the unsolicited event
+ * buffers (though on machines with 8KB pages we will to allocate
+ * them separately since there will be nothing left overs.)
+ */
+ p = (pdq_uint8_t *) PDQ_OS_MEMALLOC_CONTIG(contig_bytes);
+ if (p != NULL) {
+ pdq_physaddr_t physaddr = PDQ_OS_VA_TO_PA(pdq, p);
+ /*
+ * Assert that we really got contiguous memory. This isn't really
+ * needed on systems that actually have physical contiguous allocation
+ * routines, but on those systems that don't ...
+ */
+ for (idx = PDQ_OS_PAGESIZE; idx < 0x2000; idx += PDQ_OS_PAGESIZE) {
+ if (PDQ_OS_VA_TO_PA(pdq, p + idx) - physaddr != idx)
+ goto cleanup_and_return;
+ }
+ physaddr &= 0x1FFF;
+ if (physaddr) {
+ pdq->pdq_unsolicited_info.ui_events = (pdq_unsolicited_event_t *) p;
+ pdq->pdq_dbp = (pdq_descriptor_block_t *) &p[0x2000 - physaddr];
+ } else {
+ pdq->pdq_dbp = (pdq_descriptor_block_t *) p;
+ pdq->pdq_unsolicited_info.ui_events = (pdq_unsolicited_event_t *) &p[0x2000];
+ }
+ }
+ if (contig_bytes == sizeof(pdq_descriptor_block_t)) {
+ pdq->pdq_unsolicited_info.ui_events =
+ (pdq_unsolicited_event_t *) PDQ_OS_MEMALLOC(
+ PDQ_NUM_UNSOLICITED_EVENTS * sizeof(pdq_unsolicited_event_t));
+ }
+
+ /*
+ * Make sure everything got allocated. If not, free what did
+ * get allocated and return.
+ */
+ if (pdq->pdq_dbp == NULL || pdq->pdq_unsolicited_info.ui_events == NULL) {
+ cleanup_and_return:
+ if (p /* pdq->pdq_dbp */ != NULL)
+ PDQ_OS_MEMFREE_CONTIG(p /* pdq->pdq_dbp */, contig_bytes);
+ if (contig_bytes == sizeof(pdq_descriptor_block_t) && pdq->pdq_unsolicited_info.ui_events != NULL)
+ PDQ_OS_MEMFREE(pdq->pdq_unsolicited_info.ui_events,
+ PDQ_NUM_UNSOLICITED_EVENTS * sizeof(pdq_unsolicited_event_t));
+ PDQ_OS_MEMFREE(pdq, sizeof(pdq_t));
+ return NULL;
+ }
+
+ pdq->pdq_cbp = (volatile pdq_consumer_block_t *) &pdq->pdq_dbp->pdqdb_consumer;
+ pdq->pdq_command_info.ci_bufstart = (pdq_uint8_t *) pdq->pdq_dbp->pdqdb_command_pool;
+ pdq->pdq_rx_info.rx_buffers = (void *) pdq->pdq_dbp->pdqdb_receive_buffers;
+
+ pdq->pdq_host_smt_info.rx_buffers = (void *) pdq->pdq_dbp->pdqdb_host_smt_buffers;
+
+ PDQ_PRINTF(("\nPDQ Descriptor Block = " PDQ_OS_PTR_FMT "\n", pdq->pdq_dbp));
+ PDQ_PRINTF((" Recieve Queue = " PDQ_OS_PTR_FMT "\n", pdq->pdq_dbp->pdqdb_receives));
+ PDQ_PRINTF((" Transmit Queue = " PDQ_OS_PTR_FMT "\n", pdq->pdq_dbp->pdqdb_transmits));
+ PDQ_PRINTF((" Host SMT Queue = " PDQ_OS_PTR_FMT "\n", pdq->pdq_dbp->pdqdb_host_smt));
+ PDQ_PRINTF((" Command Response Queue = " PDQ_OS_PTR_FMT "\n", pdq->pdq_dbp->pdqdb_command_responses));
+ PDQ_PRINTF((" Command Request Queue = " PDQ_OS_PTR_FMT "\n", pdq->pdq_dbp->pdqdb_command_requests));
+ PDQ_PRINTF(("PDQ Consumer Block = " PDQ_OS_PTR_FMT "\n", pdq->pdq_cbp));
+
+ /*
+ * Zero out the descriptor block. Not really required but
+ * it pays to be neat. This will also zero out the consumer
+ * block, command pool, and buffer pointers for the receive
+ * host_smt rings.
+ */
+ PDQ_OS_MEMZERO(pdq->pdq_dbp, sizeof(*pdq->pdq_dbp));
+
+ /*
+ * Initialize the CSR references.
+ * the DEFAA (FutureBus+) skips a longword between registers
+ */
+ pdq_init_csrs(&pdq->pdq_csrs, bus, csr_base, pdq->pdq_type == PDQ_DEFAA ? 2 : 1);
+ if (pdq->pdq_type == PDQ_DEFPA)
+ pdq_init_pci_csrs(&pdq->pdq_pci_csrs, bus, csr_base, 1);
+
+ PDQ_PRINTF(("PDQ CSRs: BASE = " PDQ_OS_PTR_FMT "\n", pdq->pdq_csrs.csr_base));
+ PDQ_PRINTF((" Port Reset = " PDQ_OS_PTR_FMT " [0x%08x]\n",
+ pdq->pdq_csrs.csr_port_reset, PDQ_CSR_READ(&pdq->pdq_csrs, csr_port_reset)));
+ PDQ_PRINTF((" Host Data = " PDQ_OS_PTR_FMT " [0x%08x]\n",
+ pdq->pdq_csrs.csr_host_data, PDQ_CSR_READ(&pdq->pdq_csrs, csr_host_data)));
+ PDQ_PRINTF((" Port Control = " PDQ_OS_PTR_FMT " [0x%08x]\n",
+ pdq->pdq_csrs.csr_port_control, PDQ_CSR_READ(&pdq->pdq_csrs, csr_port_control)));
+ PDQ_PRINTF((" Port Data A = " PDQ_OS_PTR_FMT " [0x%08x]\n",
+ pdq->pdq_csrs.csr_port_data_a, PDQ_CSR_READ(&pdq->pdq_csrs, csr_port_data_a)));
+ PDQ_PRINTF((" Port Data B = " PDQ_OS_PTR_FMT " [0x%08x]\n",
+ pdq->pdq_csrs.csr_port_data_b, PDQ_CSR_READ(&pdq->pdq_csrs, csr_port_data_b)));
+ PDQ_PRINTF((" Port Status = " PDQ_OS_PTR_FMT " [0x%08x]\n",
+ pdq->pdq_csrs.csr_port_status, PDQ_CSR_READ(&pdq->pdq_csrs, csr_port_status)));
+ PDQ_PRINTF((" Host Int Type 0 = " PDQ_OS_PTR_FMT " [0x%08x]\n",
+ pdq->pdq_csrs.csr_host_int_type_0, PDQ_CSR_READ(&pdq->pdq_csrs, csr_host_int_type_0)));
+ PDQ_PRINTF((" Host Int Enable = " PDQ_OS_PTR_FMT " [0x%08x]\n",
+ pdq->pdq_csrs.csr_host_int_enable, PDQ_CSR_READ(&pdq->pdq_csrs, csr_host_int_enable)));
+ PDQ_PRINTF((" Type 2 Producer = " PDQ_OS_PTR_FMT " [0x%08x]\n",
+ pdq->pdq_csrs.csr_type_2_producer, PDQ_CSR_READ(&pdq->pdq_csrs, csr_type_2_producer)));
+ PDQ_PRINTF((" Command Response Producer = " PDQ_OS_PTR_FMT " [0x%08x]\n",
+ pdq->pdq_csrs.csr_cmd_response_producer, PDQ_CSR_READ(&pdq->pdq_csrs, csr_cmd_response_producer)));
+ PDQ_PRINTF((" Command Request Producer = " PDQ_OS_PTR_FMT " [0x%08x]\n",
+ pdq->pdq_csrs.csr_cmd_request_producer, PDQ_CSR_READ(&pdq->pdq_csrs, csr_cmd_request_producer)));
+ PDQ_PRINTF((" Host SMT Producer = " PDQ_OS_PTR_FMT " [0x%08x]\n",
+ pdq->pdq_csrs.csr_host_smt_producer, PDQ_CSR_READ(&pdq->pdq_csrs, csr_host_smt_producer)));
+ PDQ_PRINTF((" Unsolicited Producer = " PDQ_OS_PTR_FMT " [0x%08x]\n",
+ pdq->pdq_csrs.csr_unsolicited_producer, PDQ_CSR_READ(&pdq->pdq_csrs, csr_unsolicited_producer)));
+
+ /*
+ * Initialize the command information block
+ */
+ pdq->pdq_command_info.ci_pa_bufstart = PDQ_OS_VA_TO_PA(pdq, pdq->pdq_command_info.ci_bufstart);
+ for (idx = 0; idx < sizeof(pdq->pdq_dbp->pdqdb_command_requests)/sizeof(pdq->pdq_dbp->pdqdb_command_requests[0]); idx++) {
+ pdq_txdesc_t *txd = &pdq->pdq_dbp->pdqdb_command_requests[idx];
+
+ txd->txd_pa_lo = pdq->pdq_command_info.ci_pa_bufstart;
+ txd->txd_eop = txd->txd_sop = 1;
+ txd->txd_pa_hi = 0;
+ }
+ for (idx = 0; idx < sizeof(pdq->pdq_dbp->pdqdb_command_responses)/sizeof(pdq->pdq_dbp->pdqdb_command_responses[0]); idx++) {
+ pdq_rxdesc_t *rxd = &pdq->pdq_dbp->pdqdb_command_responses[idx];
+
+ rxd->rxd_pa_lo = pdq->pdq_command_info.ci_pa_bufstart;
+ rxd->rxd_sop = 1;
+ rxd->rxd_seg_cnt = 0;
+ rxd->rxd_seg_len_lo = 0;
+ }
+
+ /*
+ * Initialize the unsolicited event information block
+ */
+ pdq->pdq_unsolicited_info.ui_free = PDQ_NUM_UNSOLICITED_EVENTS;
+ pdq->pdq_unsolicited_info.ui_pa_bufstart = PDQ_OS_VA_TO_PA(pdq, pdq->pdq_unsolicited_info.ui_events);
+ for (idx = 0; idx < sizeof(pdq->pdq_dbp->pdqdb_unsolicited_events)/sizeof(pdq->pdq_dbp->pdqdb_unsolicited_events[0]); idx++) {
+ pdq_rxdesc_t *rxd = &pdq->pdq_dbp->pdqdb_unsolicited_events[idx];
+ pdq_unsolicited_event_t *event = &pdq->pdq_unsolicited_info.ui_events[idx & (PDQ_NUM_UNSOLICITED_EVENTS-1)];
+
+ rxd->rxd_sop = 1;
+ rxd->rxd_seg_cnt = 0;
+ rxd->rxd_seg_len_hi = sizeof(pdq_unsolicited_event_t) / 16;
+ rxd->rxd_pa_lo = pdq->pdq_unsolicited_info.ui_pa_bufstart + (const pdq_uint8_t *) event
+ - (const pdq_uint8_t *) pdq->pdq_unsolicited_info.ui_events;
+ rxd->rxd_pa_hi = 0;
+ }
+ /*
+ * Initialize the receive information blocks (normal and SMT).
+ */
+ pdq->pdq_rx_info.rx_free = PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_receives);
+ pdq->pdq_rx_info.rx_target = pdq->pdq_rx_info.rx_free - PDQ_RX_SEGCNT * 8;
+
+ pdq->pdq_host_smt_info.rx_free = PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_host_smt);
+ pdq->pdq_host_smt_info.rx_target = pdq->pdq_host_smt_info.rx_free - PDQ_RX_SEGCNT * 3;
+
+ /*
+ * Initialize the transmit information block.
+ */
+ pdq->pdq_tx_hdr[0] = PDQ_FDDI_PH0;
+ pdq->pdq_tx_hdr[1] = PDQ_FDDI_PH1;
+ pdq->pdq_tx_hdr[2] = PDQ_FDDI_PH2;
+ pdq->pdq_tx_info.tx_free = PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_transmits);
+ pdq->pdq_tx_info.tx_hdrdesc.txd_seg_len = sizeof(pdq->pdq_tx_hdr);
+ pdq->pdq_tx_info.tx_hdrdesc.txd_sop = 1;
+ pdq->pdq_tx_info.tx_hdrdesc.txd_pa_lo = PDQ_OS_VA_TO_PA(pdq, pdq->pdq_tx_hdr);
+
+ state = PDQ_PSTS_ADAPTER_STATE(PDQ_CSR_READ(&pdq->pdq_csrs, csr_port_status));
+ PDQ_PRINTF(("PDQ Adapter State = %s\n", pdq_adapter_states[state]));
+
+ /*
+ * Stop the PDQ if it is running and put it into a known state.
+ */
+ state = pdq_stop(pdq);
+
+ PDQ_PRINTF(("PDQ Adapter State = %s\n", pdq_adapter_states[state]));
+ PDQ_ASSERT(state == PDQS_DMA_AVAILABLE);
+ /*
+ * If the adapter is not the state we expect, then the initialization
+ * failed. Cleanup and exit.
+ */
+#if defined(PDQVERBOSE)
+ if (state == PDQS_HALTED) {
+ pdq_halt_code_t halt_code = PDQ_PSTS_HALT_ID(PDQ_CSR_READ(&pdq->pdq_csrs, csr_port_status));
+ printf("Halt code = %d (%s)\n", halt_code, pdq_halt_codes[halt_code]);
+ if (halt_code == PDQH_DMA_ERROR && pdq->pdq_type == PDQ_DEFPA)
+ PDQ_PRINTF(("PFI status = 0x%x, Host 0 Fatal Interrupt = 0x%x\n",
+ PDQ_CSR_READ(&pdq->pdq_pci_csrs, csr_pfi_status),
+ PDQ_CSR_READ(&pdq->pdq_csrs, csr_host_int_type_0) & PDQ_HOST_INT_FATAL_ERROR));
+ }
+#endif
+ if (state == PDQS_RESET || state == PDQS_HALTED || state == PDQS_UPGRADE)
+ goto cleanup_and_return;
+
+ PDQ_PRINTF(("PDQ Hardware Address = %02x-%02x-%02x-%02x-%02x-%02x\n",
+ pdq->pdq_hwaddr.lanaddr_bytes[0], pdq->pdq_hwaddr.lanaddr_bytes[1],
+ pdq->pdq_hwaddr.lanaddr_bytes[2], pdq->pdq_hwaddr.lanaddr_bytes[3],
+ pdq->pdq_hwaddr.lanaddr_bytes[4], pdq->pdq_hwaddr.lanaddr_bytes[5]));
+ PDQ_PRINTF(("PDQ Firmware Revision = %c%c%c%c\n",
+ pdq->pdq_fwrev.fwrev_bytes[0], pdq->pdq_fwrev.fwrev_bytes[1],
+ pdq->pdq_fwrev.fwrev_bytes[2], pdq->pdq_fwrev.fwrev_bytes[3]));
+ PDQ_PRINTF(("PDQ Chip Revision = "));
+ switch (pdq->pdq_chip_rev) {
+ case PDQ_CHIP_REV_A_B_OR_C: PDQ_PRINTF(("Rev C or below")); break;
+ case PDQ_CHIP_REV_D: PDQ_PRINTF(("Rev D")); break;
+ case PDQ_CHIP_REV_E: PDQ_PRINTF(("Rev E")); break;
+ default: PDQ_PRINTF(("Unknown Rev %d", (int) pdq->pdq_chip_rev));
+ }
+ PDQ_PRINTF(("\n"));
+
+ return pdq;
+}
diff --git a/sys/dev/pdq/pdq_ifsubr.c b/sys/dev/pdq/pdq_ifsubr.c
new file mode 100644
index 0000000..224e4e8
--- /dev/null
+++ b/sys/dev/pdq/pdq_ifsubr.c
@@ -0,0 +1,404 @@
+/*-
+ * Copyright (c) 1995, 1996 Matt Thomas <matt@3am-software.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: pdq_ifsubr.c,v 1.8 1996/07/31 21:38:44 thomas Exp $
+ *
+ */
+
+/*
+ * DEC PDQ FDDI Controller; code for BSD derived operating systems
+ *
+ * This module provide bus independent BSD specific O/S functions.
+ * (ie. it provides an ifnet interface to the rest of the system)
+ */
+
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/mbuf.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/errno.h>
+#include <sys/malloc.h>
+#if defined(__FreeBSD__)
+#include <sys/devconf.h>
+#elif defined(__bsdi__) || defined(__NetBSD__)
+#include <sys/device.h>
+#endif
+
+#include <net/if.h>
+#include <net/if_types.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+
+#include "bpfilter.h"
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#include <net/bpfdesc.h>
+#endif
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#include <netinet/if_ether.h>
+#endif
+#if defined(__FreeBSD__)
+#include <netinet/if_fddi.h>
+#else
+#include <net/if_fddi.h>
+#endif
+
+#if defined(__bsdi__)
+#include <i386/isa/isavar.h>
+#endif
+
+#ifdef NS
+#include <netns/ns.h>
+#include <netns/ns_if.h>
+#endif
+
+#include <vm/vm.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_param.h>
+
+#include "pdqvar.h"
+#include "pdqreg.h"
+
+#if defined(__bsdi__) && _BSDI_VERSION < 199506 /* XXX */
+static void
+arp_ifinit(
+ struct arpcom *ac,
+ struct ifaddr *ifa)
+{
+ sc->sc_ac.ac_ipaddr = IA_SIN(ifa)->sin_addr;
+ arpwhohas(&sc->sc_ac, &IA_SIN(ifa)->sin_addr);
+#if _BSDI_VERSION >= 199401
+ ifa->ifa_rtrequest = arp_rtrequest;
+ ifa->ifa_flags |= RTF_CLONING;
+#endif
+#endif
+
+
+void
+pdq_ifinit(
+ pdq_softc_t *sc)
+{
+ if (sc->sc_if.if_flags & IFF_UP) {
+ sc->sc_if.if_flags |= IFF_RUNNING;
+ if (sc->sc_if.if_flags & IFF_PROMISC) {
+ sc->sc_pdq->pdq_flags |= PDQ_PROMISC;
+ } else {
+ sc->sc_pdq->pdq_flags &= ~PDQ_PROMISC;
+ }
+ if (sc->sc_if.if_flags & IFF_ALLMULTI) {
+ sc->sc_pdq->pdq_flags |= PDQ_ALLMULTI;
+ } else {
+ sc->sc_pdq->pdq_flags &= ~PDQ_ALLMULTI;
+ }
+ if (sc->sc_if.if_flags & IFF_LINK1) {
+ sc->sc_pdq->pdq_flags |= PDQ_PASS_SMT;
+ } else {
+ sc->sc_pdq->pdq_flags &= ~PDQ_PASS_SMT;
+ }
+ sc->sc_pdq->pdq_flags |= PDQ_RUNNING;
+ pdq_run(sc->sc_pdq);
+ } else {
+ sc->sc_if.if_flags &= ~IFF_RUNNING;
+ sc->sc_pdq->pdq_flags &= ~PDQ_RUNNING;
+ pdq_stop(sc->sc_pdq);
+ }
+}
+
+void
+pdq_ifwatchdog(
+ struct ifnet *ifp)
+{
+ /*
+ * No progress was made on the transmit queue for PDQ_OS_TX_TRANSMIT
+ * seconds. Remove all queued packets.
+ */
+
+ ifp->if_flags &= ~IFF_OACTIVE;
+ ifp->if_timer = 0;
+ for (;;) {
+ struct mbuf *m;
+ IF_DEQUEUE(&ifp->if_snd, m);
+ if (m == NULL)
+ return;
+ m_freem(m);
+ }
+}
+
+ifnet_ret_t
+pdq_ifstart(
+ struct ifnet *ifp)
+{
+ pdq_softc_t *sc = (pdq_softc_t *) ((caddr_t) ifp - offsetof(pdq_softc_t, sc_ac.ac_if));
+ struct ifqueue *ifq = &ifp->if_snd;
+ struct mbuf *m;
+ int tx = 0;
+
+ if ((ifp->if_flags & IFF_RUNNING) == 0)
+ return;
+
+ if (sc->sc_if.if_timer == 0)
+ sc->sc_if.if_timer = PDQ_OS_TX_TIMEOUT;
+
+ if ((sc->sc_pdq->pdq_flags & PDQ_TXOK) == 0) {
+ sc->sc_if.if_flags |= IFF_OACTIVE;
+ return;
+ }
+ for (;; tx = 1) {
+ IF_DEQUEUE(ifq, m);
+ if (m == NULL)
+ break;
+
+ if (pdq_queue_transmit_data(sc->sc_pdq, m) == PDQ_FALSE) {
+ ifp->if_flags |= IFF_OACTIVE;
+ IF_PREPEND(ifq, m);
+ break;
+ }
+ }
+ if (tx)
+ PDQ_DO_TYPE2_PRODUCER(sc->sc_pdq);
+}
+
+void
+pdq_os_receive_pdu(
+ pdq_t *pdq,
+ struct mbuf *m,
+ size_t pktlen)
+{
+ pdq_softc_t *sc = (pdq_softc_t *) pdq->pdq_os_ctx;
+ struct fddi_header *fh = mtod(m, struct fddi_header *);
+
+ sc->sc_if.if_ipackets++;
+#if NBPFILTER > 0
+ if (sc->sc_bpf != NULL)
+ PDQ_BPF_MTAP(sc, m);
+ if ((fh->fddi_fc & (FDDIFC_L|FDDIFC_F)) != FDDIFC_LLC_ASYNC) {
+ m_freem(m);
+ return;
+ }
+#endif
+
+ m->m_data += sizeof(struct fddi_header);
+ m->m_len -= sizeof(struct fddi_header);
+ m->m_pkthdr.len = pktlen - sizeof(struct fddi_header);
+ m->m_pkthdr.rcvif = &sc->sc_if;
+ fddi_input(&sc->sc_if, fh, m);
+}
+
+void
+pdq_os_restart_transmitter(
+ pdq_t *pdq)
+{
+ pdq_softc_t *sc = (pdq_softc_t *) pdq->pdq_os_ctx;
+ sc->sc_if.if_flags &= ~IFF_OACTIVE;
+ if (sc->sc_if.if_snd.ifq_head != NULL) {
+ sc->sc_if.if_timer = PDQ_OS_TX_TIMEOUT;
+ pdq_ifstart(&sc->sc_if);
+ } else {
+ sc->sc_if.if_timer = 0;
+ }
+}
+
+void
+pdq_os_transmit_done(
+ pdq_t *pdq,
+ struct mbuf *m)
+{
+ pdq_softc_t *sc = (pdq_softc_t *) pdq->pdq_os_ctx;
+#if NBPFILTER > 0
+ if (sc->sc_bpf != NULL)
+ PDQ_BPF_MTAP(sc, m);
+#endif
+ m_freem(m);
+ sc->sc_if.if_opackets++;
+}
+
+void
+pdq_os_addr_fill(
+ pdq_t *pdq,
+ pdq_lanaddr_t *addr,
+ size_t num_addrs)
+{
+ pdq_softc_t *sc = (pdq_softc_t *) pdq->pdq_os_ctx;
+ struct ether_multistep step;
+ struct ether_multi *enm;
+
+ ETHER_FIRST_MULTI(step, &sc->sc_ac, enm);
+ while (enm != NULL && num_addrs > 0) {
+ ((u_short *) addr->lanaddr_bytes)[0] = ((u_short *) enm->enm_addrlo)[0];
+ ((u_short *) addr->lanaddr_bytes)[1] = ((u_short *) enm->enm_addrlo)[1];
+ ((u_short *) addr->lanaddr_bytes)[2] = ((u_short *) enm->enm_addrlo)[2];
+ ETHER_NEXT_MULTI(step, enm);
+ addr++;
+ num_addrs--;
+ }
+}
+
+int
+pdq_ifioctl(
+ struct ifnet *ifp,
+ ioctl_cmd_t cmd,
+ caddr_t data)
+{
+ pdq_softc_t *sc = (pdq_softc_t *) ((caddr_t) ifp - offsetof(pdq_softc_t, sc_ac.ac_if));
+ int s, error = 0;
+
+ s = splimp();
+
+ switch (cmd) {
+ case SIOCSIFADDR: {
+ struct ifaddr *ifa = (struct ifaddr *)data;
+
+ ifp->if_flags |= IFF_UP;
+ switch(ifa->ifa_addr->sa_family) {
+#if defined(INET)
+ case AF_INET: {
+ pdq_ifinit(sc);
+ arp_ifinit(&sc->sc_ac, ifa);
+ break;
+ }
+#endif /* INET */
+
+#if defined(NS)
+ /* This magic copied from if_is.c; I don't use XNS,
+ * so I have no way of telling if this actually
+ * works or not.
+ */
+ case AF_NS: {
+ struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
+ if (ns_nullhost(*ina)) {
+ ina->x_host = *(union ns_host *)(sc->sc_ac.ac_enaddr);
+ } else {
+ ifp->if_flags &= ~IFF_RUNNING;
+ bcopy((caddr_t)ina->x_host.c_host,
+ (caddr_t)sc->sc_ac.ac_enaddr,
+ sizeof sc->sc_ac.ac_enaddr);
+ }
+
+ pdq_ifinit(sc);
+ break;
+ }
+#endif /* NS */
+
+ default: {
+ pdq_ifinit(sc);
+ break;
+ }
+ }
+ break;
+ }
+ case SIOCGIFADDR: {
+ struct ifreq *ifr = (struct ifreq *)data;
+ bcopy((caddr_t) sc->sc_ac.ac_enaddr,
+ (caddr_t) ((struct sockaddr *)&ifr->ifr_data)->sa_data,
+ 6);
+ break;
+ }
+
+ case SIOCSIFFLAGS: {
+ pdq_ifinit(sc);
+ break;
+ }
+
+ case SIOCADDMULTI:
+ case SIOCDELMULTI: {
+ /*
+ * Update multicast listeners
+ */
+ if (cmd == SIOCADDMULTI)
+ error = ether_addmulti((struct ifreq *)data, &sc->sc_ac);
+ else
+ error = ether_delmulti((struct ifreq *)data, &sc->sc_ac);
+
+ if (error == ENETRESET) {
+ if (sc->sc_if.if_flags & IFF_RUNNING)
+ pdq_run(sc->sc_pdq);
+ error = 0;
+ }
+ break;
+ }
+
+#if defined(SIOCSIFMTU)
+#if !defined(ifr_mtu)
+#define ifr_mtu ifr_metric
+#endif
+ case SIOCSIFMTU: {
+ struct ifreq *ifr = (struct ifreq *)data;
+ /*
+ * Set the interface MTU.
+ */
+ if (ifr->ifr_mtu > FDDIMTU) {
+ error = EINVAL;
+ break;
+ }
+ ifp->if_mtu = ifr->ifr_mtu;
+ break;
+ }
+#endif /* SIOCSIFMTU */
+
+ default: {
+ error = EINVAL;
+ break;
+ }
+ }
+
+ splx(s);
+ return error;
+}
+
+#ifndef IFF_NOTRAILERS
+#define IFF_NOTRAILERS 0
+#endif
+
+void
+pdq_ifattach(
+ pdq_softc_t *sc,
+ ifnet_ret_t (*ifwatchdog)(int unit))
+{
+ struct ifnet *ifp = &sc->sc_if;
+
+ ifp->if_flags = IFF_BROADCAST|IFF_SIMPLEX|IFF_NOTRAILERS|IFF_MULTICAST;
+
+#if (defined(__FreeBSD__) && BSD >= 199506) || defined(__NetBSD__)
+ ifp->if_watchdog = pdq_ifwatchdog;
+#else
+ ifp->if_watchdog = ifwatchdog;
+#endif
+
+ ifp->if_ioctl = pdq_ifioctl;
+ ifp->if_output = fddi_output;
+ ifp->if_start = pdq_ifstart;
+
+ if_attach(ifp);
+ fddi_ifattach(ifp);
+#if NBPFILTER > 0
+ PDQ_BPFATTACH(sc, DLT_FDDI, sizeof(struct fddi_header));
+#endif
+}
diff --git a/sys/dev/pdq/pdqreg.h b/sys/dev/pdq/pdqreg.h
new file mode 100644
index 0000000..6c4d51a
--- /dev/null
+++ b/sys/dev/pdq/pdqreg.h
@@ -0,0 +1,1065 @@
+/*-
+ * Copyright (c) 1995, 1996 Matt Thomas <matt@3am-software.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: pdqreg.h,v 1.9 1996/05/16 14:25:26 thomas Exp $
+ *
+ */
+
+/*
+ * DEC PDQ FDDI Controller; PDQ port driver definitions
+ *
+ */
+
+#ifndef _PDQREG_H
+#define _PDQREG_H
+
+#include <stddef.h>
+#if defined(PDQTEST) && !defined(PDQ_NDEBUG)
+#include <assert.h>
+#define PDQ_ASSERT assert
+#else
+#define PDQ_ASSERT(x) do { } while(0)
+#endif
+
+#define PDQ_RING_SIZE(array) ((sizeof(array) / sizeof(array[0])))
+#define PDQ_ARRAY_SIZE(array) ((sizeof(array) / sizeof(array[0])))
+#define PDQ_RING_MASK(array) (PDQ_RING_SIZE(array) - 1)
+#define PDQ_BITMASK(n) (1L << (pdq_uint32_t) (n))
+
+#define PDQ_FDDI_MAX 4495
+#define PDQ_FDDI_LLC_MIN 20
+#define PDQ_FDDI_SMT_MIN 37
+
+#define PDQ_FDDI_SMT 0x40
+#define PDQ_FDDI_LLC_ASYNC 0x50
+#define PDQ_FDDI_LLC_SYNC 0xD0
+#define PDQ_FDDI_IMP_ASYNC 0x60
+#define PDQ_FDDI_IMP_SYNC 0xE0
+
+#define PDQ_FDDIFC_C 0x80
+#define PDQ_FDDIFC_L 0x40
+#define PDQ_FDDIFC_F 0x30
+#define PDQ_FDDIFC_Z 0x0F
+
+#define PDQ_FDDI_PH0 0x20
+#define PDQ_FDDI_PH1 0x38
+#define PDQ_FDDI_PH2 0x00
+
+typedef pdq_uint32_t pdq_physaddr_t;
+
+struct _pdq_lanaddr_t {
+ pdq_uint8_t lanaddr_bytes[8];
+};
+
+typedef struct {
+ pdq_uint8_t fwrev_bytes[4];
+} pdq_fwrev_t;
+
+enum _pdq_state_t {
+ PDQS_RESET=0,
+ PDQS_UPGRADE=1,
+ PDQS_DMA_UNAVAILABLE=2,
+ PDQS_DMA_AVAILABLE=3,
+ PDQS_LINK_AVAILABLE=4,
+ PDQS_LINK_UNAVAILABLE=5,
+ PDQS_HALTED=6,
+ PDQS_RING_MEMBER=7
+};
+
+struct _pdq_csrs_t {
+ pdq_bus_memoffset_t csr_port_reset; /* 0x00 [RW] */
+ pdq_bus_memoffset_t csr_host_data; /* 0x04 [R] */
+ pdq_bus_memoffset_t csr_port_control; /* 0x08 [RW] */
+ pdq_bus_memoffset_t csr_port_data_a; /* 0x0C [RW] */
+ pdq_bus_memoffset_t csr_port_data_b; /* 0x10 [RW] */
+ pdq_bus_memoffset_t csr_port_status; /* 0x14 [R] */
+ pdq_bus_memoffset_t csr_host_int_type_0; /* 0x18 [RW] */
+ pdq_bus_memoffset_t csr_host_int_enable; /* 0x1C [RW] */
+ pdq_bus_memoffset_t csr_type_2_producer; /* 0x20 [RW] */
+ pdq_bus_memoffset_t csr_cmd_response_producer; /* 0x28 [RW] */
+ pdq_bus_memoffset_t csr_cmd_request_producer; /* 0x2C [RW] */
+ pdq_bus_memoffset_t csr_host_smt_producer; /* 0x30 [RW] */
+ pdq_bus_memoffset_t csr_unsolicited_producer; /* 0x34 [RW] */
+ pdq_bus_t csr_bus;
+ pdq_bus_memaddr_t csr_base;
+};
+
+struct _pdq_pci_csrs_t {
+ pdq_bus_memoffset_t csr_pfi_mode_control; /* 0x40 [RW] */
+ pdq_bus_memoffset_t csr_pfi_status; /* 0x44 [RW] */
+ pdq_bus_memoffset_t csr_fifo_write; /* 0x48 [RW] */
+ pdq_bus_memoffset_t csr_fifo_read; /* 0x4C [RW] */
+ pdq_bus_t csr_bus;
+ pdq_bus_memaddr_t csr_base;
+};
+
+#define PDQ_PFI_MODE_DMA_ENABLE 0x01 /* DMA Enable */
+#define PDQ_PFI_MODE_PFI_PCI_INTR 0x02 /* PFI-to-PCI Int Enable */
+#define PDQ_PFI_MODE_PDQ_PCI_INTR 0x04 /* PDQ-to-PCI Int Enable */
+
+#define PDQ_PFI_STATUS_PDQ_INTR 0x10 /* PDQ Int received */
+#define PDQ_PFI_STATUS_DMA_ABORT 0x08 /* PDQ DMA Abort asserted */
+
+#define PDQ_EISA_BURST_HOLDOFF 0x0040
+#define PDQ_EISA_SLOT_ID 0x0C80
+#define PDQ_EISA_SLOT_CTRL 0x0C84
+#define PDQ_EISA_MEM_ADD_CMP_0 0x0C85
+#define PDQ_EISA_MEM_ADD_CMP_1 0x0C86
+#define PDQ_EISA_MEM_ADD_CMP_2 0x0C87
+#define PDQ_EISA_MEM_ADD_HI_CMP_0 0x0C88
+#define PDQ_EISA_MEM_ADD_HI_CMP_1 0x0C89
+#define PDQ_EISA_MEM_ADD_HI_CMP_2 0x0C8A
+#define PDQ_EISA_MEM_ADD_MASK_0 0x0C8B
+#define PDQ_EISA_MEM_ADD_MASK_1 0x0C8C
+#define PDQ_EISA_MEM_ADD_MASK_2 0x0C8D
+#define PDQ_EISA_MEM_ADD_LO_CMP_0 0x0C8E
+#define PDQ_EISA_MEM_ADD_LO_CMP_1 0x0C8F
+#define PDQ_EISA_MEM_ADD_LO_CMP_2 0x0C90
+#define PDQ_EISA_IO_CMP_0_0 0x0C91
+#define PDQ_EISA_IO_CMP_0_1 0x0C92
+#define PDQ_EISA_IO_CMP_1_0 0x0C93
+#define PDQ_EISA_IO_CMP_1_1 0x0C94
+#define PDQ_EISA_IO_CMP_2_0 0x0C95
+#define PDQ_EISA_IO_CMP_2_1 0x0C96
+#define PDQ_EISA_IO_CMP_3_0 0x0C97
+#define PDQ_EISA_IO_CMP_3_1 0x0C98
+#define PDQ_EISA_IO_ADD_MASK_0_0 0x0C99
+#define PDQ_EISA_IO_ADD_MASK_0_1 0x0C9A
+#define PDQ_EISA_IO_ADD_MASK_1_0 0x0C9B
+#define PDQ_EISA_IO_ADD_MASK_1_1 0x0C9C
+#define PDQ_EISA_IO_ADD_MASK_2_0 0x0C9D
+#define PDQ_EISA_IO_ADD_MASK_2_1 0x0C9E
+#define PDQ_EISA_IO_ADD_MASK_3_0 0x0C9F
+#define PDQ_EISA_IO_ADD_MASK_3_1 0x0CA0
+#define PDQ_EISA_MOD_CONFIG_1 0x0CA1
+#define PDQ_EISA_MOD_CONFIG_2 0x0CA2
+#define PDQ_EISA_MOD_CONFIG_3 0x0CA3
+#define PDQ_EISA_MOD_CONFIG_4 0x0CA4
+#define PDQ_EISA_MOD_CONFIG_5 0x0CA5
+#define PDQ_EISA_MOD_CONFIG_6 0x0CA6
+#define PDQ_EISA_MOD_CONFIG_7 0x0CA7
+#define PDQ_EISA_DIP_SWITCH 0x0CA8
+#define PDQ_EISA_IO_CONFIG_STAT_0 0x0CA9
+#define PDQ_EISA_IO_CONFIG_STAT_1 0x0CAA
+#define PDQ_EISA_DMA_CONFIG 0x0CAB
+#define PDQ_EISA_INPUT_PORT 0x0CAC
+#define PDQ_EISA_OUTPUT_PORT 0x0CAD
+#define PDQ_EISA_FUNCTION_CTRL 0x0CAE
+
+#define PDQ_TC_CSR_OFFSET 0x00100000
+#define PDQ_TC_CSR_SPACE 0x0040
+#define PDQ_FBUS_CSR_OFFSET 0x00200000
+#define PDQ_FBUS_CSR_SPACE 0x0080
+
+/*
+ * Port Reset Data A Definitions
+ */
+#define PDQ_PRESET_SKIP_SELFTEST 0x0004
+#define PDQ_PRESET_SOFT_RESET 0x0002
+#define PDQ_PRESET_UPGRADE 0x0001
+/*
+ * Port Control Register Definitions
+ */
+#define PDQ_PCTL_CMD_ERROR 0x8000
+#define PDQ_PCTL_FLASH_BLAST 0x4000
+#define PDQ_PCTL_HALT 0x2000
+#define PDQ_PCTL_COPY_DATA 0x1000
+#define PDQ_PCTL_ERROR_LOG_START 0x0800
+#define PDQ_PCTL_ERROR_LOG_READ 0x0400
+#define PDQ_PCTL_XMT_DATA_FLUSH_DONE 0x0200
+#define PDQ_PCTL_DMA_INIT 0x0100
+#define PDQ_DMA_INIT_LW_BSWAP_DATA 0x02
+#define PDQ_DMA_INIT_LW_BSWAP_LITERAL 0x01
+#define PDQ_PCTL_INIT_START 0x0080
+#define PDQ_PCTL_CONSUMER_BLOCK 0x0040
+#define PDQ_PCTL_DMA_UNINIT 0x0020
+#define PDQ_PCTL_RING_MEMBER 0x0010
+#define PDQ_PCTL_MLA_READ 0x0008
+#define PDQ_PCTL_FW_REV_READ 0x0004
+#define PDQ_PCTL_DEVICE_SPECIFIC 0x0002
+#define PDQ_PCTL_SUB_CMD 0x0001
+
+typedef enum {
+ PDQ_SUB_CMD_LINK_UNINIT=1,
+ PDQ_SUB_CMD_DMA_BURST_SIZE_SET=2,
+ PDQ_SUB_CMD_PDQ_REV_GET=4
+} pdq_sub_cmd_t;
+
+typedef enum {
+ PDQ_DMA_BURST_4LW=0,
+ PDQ_DMA_BURST_8LW=1,
+ PDQ_DMA_BURST_16LW=2,
+ PDQ_DMA_BURST_32LW=3
+} pdq_dma_burst_size_t;
+
+typedef enum {
+ PDQ_CHIP_REV_A_B_OR_C=0,
+ PDQ_CHIP_REV_D=2,
+ PDQ_CHIP_REV_E=4
+} pdq_chip_rev_t;
+/*
+ * Port Status Register Definitions
+ */
+#define PDQ_PSTS_RCV_DATA_PENDING 0x80000000ul
+#define PDQ_PSTS_XMT_DATA_PENDING 0x40000000ul
+#define PDQ_PSTS_HOST_SMT_PENDING 0x20000000ul
+#define PDQ_PSTS_UNSOL_PENDING 0x10000000ul
+#define PDQ_PSTS_CMD_RSP_PENDING 0x08000000ul
+#define PDQ_PSTS_CMD_REQ_PENDING 0x04000000ul
+#define PDQ_PSTS_TYPE_0_PENDING 0x02000000ul
+#define PDQ_PSTS_INTR_PENDING 0xFE000000ul
+#define PDQ_PSTS_ADAPTER_STATE(sts) ((pdq_state_t) (((sts) >> 8) & 0x07))
+#define PDQ_PSTS_HALT_ID(sts) ((pdq_halt_code_t) ((sts) & 0xFF))
+/*
+ * Host Interrupt Register Definitions
+ */
+#define PDQ_HOST_INT_TX_ENABLE 0x80000000ul
+#define PDQ_HOST_INT_RX_ENABLE 0x40000000ul
+#define PDQ_HOST_INT_UNSOL_ENABLE 0x20000000ul
+#define PDQ_HOST_INT_HOST_SMT_ENABLE 0x10000000ul
+#define PDQ_HOST_INT_CMD_RSP_ENABLE 0x08000000ul
+#define PDQ_HOST_INT_CMD_RQST_ENABLE 0x04000000ul
+
+#define PDQ_HOST_INT_1MS 0x80
+#define PDQ_HOST_INT_20MS 0x40
+#define PDQ_HOST_INT_CSR_CMD_DONE 0x20
+#define PDQ_HOST_INT_STATE_CHANGE 0x10
+#define PDQ_HOST_INT_XMT_DATA_FLUSH 0x08
+#define PDQ_HOST_INT_NXM 0x04
+#define PDQ_HOST_INT_PM_PARITY_ERROR 0x02
+#define PDQ_HOST_INT_HOST_BUS_PARITY_ERROR 0x01
+#define PDQ_HOST_INT_FATAL_ERROR 0x07
+
+typedef enum {
+ PDQH_SELFTEST_TIMEOUT=0,
+ PDQH_HOST_BUS_PARITY_ERROR=1,
+ PDQH_HOST_DIRECTED_HALT=2,
+ PDQH_SOFTWARE_FAULT=3,
+ PDQH_HARDWARE_FAULT=4,
+ PDQH_PC_TRACE_PATH_TEST=5,
+ PDQH_DMA_ERROR=6,
+ PDQH_IMAGE_CRC_ERROR=7,
+ PDQH_ADAPTER_PROCESSOR_ERROR=8,
+ PDQH_MAX=9
+} pdq_halt_code_t;
+
+typedef struct {
+ pdq_uint16_t pdqcb_receives;
+ pdq_uint16_t pdqcb_transmits;
+ pdq_uint32_t pdqcb__filler1;
+ pdq_uint32_t pdqcb_host_smt;
+ pdq_uint32_t pdqcb__filler2;
+ pdq_uint32_t pdqcb_unsolicited_event;
+ pdq_uint32_t pdqcb__filler3;
+ pdq_uint32_t pdqcb_command_response;
+ pdq_uint32_t pdqcb__filler4;
+ pdq_uint32_t pdqcb_command_request;
+ pdq_uint32_t pdqcb__filler5[7];
+} pdq_consumer_block_t;
+
+#if defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN
+#define PDQ_BITFIELD2(a, b) b, a
+#define PDQ_BITFIELD3(a, b, c) c, b, a
+#define PDQ_BITFIELD4(a, b, c, d) d, c, b, a
+#define PDQ_BITFIELD5(a, b, c, d, e) e, d, c, b, a
+#define PDQ_BITFIELD12(a, b, c, d, e, f, g, h, i, j, k, l) \
+ l, k, j, i, h, g, f, e, d, c, b, a
+#else
+#define PDQ_BITFIELD2(a, b) a, b
+#define PDQ_BITFIELD3(a, b, c) a, b, c
+#define PDQ_BITFIELD4(a, b, c, d) a, b, c, d
+#define PDQ_BITFIELD5(a, b, c, d, e) a, b, c, d, e
+#define PDQ_BITFIELD12(a, b, c, d, e, f, g, h, i, j, k, l) \
+ a, b, c, d, e, f, g, h, i, j, k, l
+#endif
+
+typedef struct {
+ pdq_uint32_t PDQ_BITFIELD5(rxd_pa_hi : 16,
+ rxd_seg_cnt : 4,
+ rxd_seg_len_hi : 9,
+ rxd_seg_len_lo : 2,
+ rxd_sop : 1);
+ pdq_uint32_t rxd_pa_lo;
+} pdq_rxdesc_t;
+
+typedef union {
+ pdq_uint32_t rxs_status;
+ pdq_uint32_t PDQ_BITFIELD12(rxs_len : 13,
+ rxs_rcc_ss : 2,
+ rxs_rcc_dd : 2,
+ rxs_rcc_reason : 3,
+ rxs_rcc_badcrc : 1,
+ rxs_rcc_badpdu : 1,
+ rxs_fsb__reserved : 2,
+ rxs_fsb_c : 1,
+ rxs_fsb_a : 1,
+ rxs_fsb_e : 1,
+ rxs_fsc : 3,
+ rxs__reserved : 2);
+} pdq_rxstatus_t;
+
+typedef struct {
+ pdq_uint32_t PDQ_BITFIELD5(txd_pa_hi : 16,
+ txd_seg_len : 13,
+ txd_mbz : 1,
+ txd_eop : 1,
+ txd_sop : 1);
+ pdq_uint32_t txd_pa_lo;
+} pdq_txdesc_t;
+
+typedef struct {
+ pdq_rxdesc_t pdqdb_receives[256]; /* 2048; 0x0000..0x07FF */
+ pdq_txdesc_t pdqdb_transmits[256]; /* 2048; 0x0800..0x0FFF */
+ pdq_rxdesc_t pdqdb_host_smt[64]; /* 512; 0x1000..0x11FF */
+ pdq_rxdesc_t pdqdb_unsolicited_events[16]; /* 128; 0x1200..0x127F */
+ pdq_rxdesc_t pdqdb_command_responses[16]; /* 128; 0x1280..0x12FF */
+ pdq_txdesc_t pdqdb_command_requests[16]; /* 128; 0x1300..0x137F */
+ /*
+ * The rest of the descriptor block is unused.
+ * As such we could use it for other things.
+ */
+ pdq_consumer_block_t pdqdb_consumer; /* 64; 0x1380..0x13BF */
+ void *pdqdb_receive_buffers[256]; /* 1024/2048; 0x13C0..0x17BF 0x13C0..0x1BBF */
+ void *pdqdb_host_smt_buffers[64]; /* 256/ 512; 0x17C0..0x18BF 0x1BC0..0x1DBF */
+ /*
+ * The maximum command size is 512 so as long as thes
+ * command is at least that long all will be fine.
+ */
+#if defined(__alpha) || defined(__alpha__)
+ pdq_uint32_t pdqdb_command_pool[144];
+#else
+ pdq_uint32_t pdqdb_command_pool[464];
+#endif
+} pdq_descriptor_block_t;
+
+typedef struct {
+ /*
+ * These value manage the available space in command/response
+ * buffer area.
+ */
+ pdq_physaddr_t ci_pa_bufstart;
+ pdq_uint8_t *ci_bufstart;
+ /*
+ * Bitmask of commands to sent to the PDQ
+ */
+ pdq_uint32_t ci_pending_commands;
+ /*
+ * Variables to maintain the PDQ queues.
+ */
+ pdq_uint32_t ci_command_active;
+ pdq_uint32_t ci_request_producer;
+ pdq_uint32_t ci_response_producer;
+ pdq_uint32_t ci_request_completion;
+ pdq_uint32_t ci_response_completion;
+} pdq_command_info_t;
+
+#define PDQ_SIZE_UNSOLICITED_EVENT 512
+#define PDQ_NUM_UNSOLICITED_EVENTS (PDQ_OS_PAGESIZE / PDQ_SIZE_UNSOLICITED_EVENT)
+
+typedef struct _pdq_unsolicited_event_t pdq_unsolicited_event_t;
+
+typedef struct {
+ pdq_physaddr_t ui_pa_bufstart;
+ pdq_unsolicited_event_t *ui_events;
+
+ pdq_uint32_t ui_free;
+ pdq_uint32_t ui_producer;
+ pdq_uint32_t ui_completion;
+} pdq_unsolicited_info_t;
+
+#define PDQ_RX_FC_OFFSET (sizeof(pdq_rxstatus_t) + 3)
+#define PDQ_RX_SEGCNT ((PDQ_FDDI_MAX + PDQ_OS_DATABUF_SIZE - 1) / PDQ_OS_DATABUF_SIZE)
+#define PDQ_DO_TYPE2_PRODUCER(pdq) \
+ PDQ_CSR_WRITE(&(pdq)->pdq_csrs, csr_type_2_producer, \
+ ((pdq)->pdq_rx_info.rx_producer << 0) \
+ | ((pdq)->pdq_tx_info.tx_producer << 8) \
+ | ((pdq)->pdq_rx_info.rx_completion << 16) \
+ | ((pdq)->pdq_tx_info.tx_completion << 24))
+
+#define PDQ_DO_HOST_SMT_PRODUCER(pdq) \
+ PDQ_CSR_WRITE(&(pdq)->pdq_csrs, csr_host_smt_producer, \
+ ((pdq)->pdq_host_smt_info.rx_producer << 0) \
+ | ((pdq)->pdq_host_smt_info.rx_completion << 8))\
+
+#define PDQ_ADVANCE(n, a, m) ((n) = ((n) + (a)) & (m))
+
+typedef struct {
+ void *q_head;
+ void *q_tail;
+} pdq_databuf_queue_t;
+
+typedef struct {
+ void *rx_buffers;
+
+ pdq_uint32_t rx_target;
+ pdq_uint32_t rx_free;
+ pdq_uint32_t rx_producer;
+ pdq_uint32_t rx_completion;
+} pdq_rx_info_t;
+
+typedef struct {
+ pdq_databuf_queue_t tx_txq;
+ pdq_txdesc_t tx_hdrdesc;
+ pdq_uint8_t tx_descriptor_count[256];
+
+ pdq_uint32_t tx_free;
+ pdq_uint32_t tx_producer;
+ pdq_uint32_t tx_completion;
+} pdq_tx_info_t;
+
+struct _pdq_t {
+ pdq_csrs_t pdq_csrs;
+ pdq_pci_csrs_t pdq_pci_csrs;
+ pdq_type_t pdq_type;
+ pdq_chip_rev_t pdq_chip_rev;
+ pdq_lanaddr_t pdq_hwaddr;
+ pdq_fwrev_t pdq_fwrev;
+ pdq_descriptor_block_t *pdq_dbp;
+ volatile pdq_consumer_block_t *pdq_cbp;
+ pdq_uint32_t pdq_flags;
+#define PDQ_PROMISC 0x0001
+#define PDQ_ALLMULTI 0x0002
+#define PDQ_PASS_SMT 0x0004
+#define PDQ_RUNNING 0x0008
+#define PDQ_PRINTCHARS 0x0010
+#define PDQ_TXOK 0x0020
+ const char *pdq_os_name;
+ void *pdq_os_ctx;
+ pdq_uint32_t pdq_unit;
+ pdq_command_info_t pdq_command_info;
+ pdq_unsolicited_info_t pdq_unsolicited_info;
+ pdq_tx_info_t pdq_tx_info;
+ pdq_rx_info_t pdq_rx_info;
+ pdq_rx_info_t pdq_host_smt_info;
+ pdq_uint8_t pdq_tx_hdr[3];
+};
+
+typedef enum {
+ PDQC_START=0,
+ PDQC_FILTER_SET=1,
+ PDQC_FILTER_GET=2,
+ PDQC_CHARS_SET=3,
+ PDQC_STATUS_CHARS_GET=4,
+ PDQC_COUNTERS_GET=5,
+ PDQC_COUNTERS_SET=6,
+ PDQC_ADDR_FILTER_SET=7,
+ PDQC_ADDR_FILTER_GET=8,
+ PDQC_ERROR_LOG_CLEAR=9,
+ PDQC_ERROR_LOG_GET=10,
+ PDQC_FDDI_MIB_GET=11,
+ PDQC_DEC_EXT_MIB_GET=12,
+ PDQC_DEV_SPECIFIC_GET=13,
+ PDQC_SNMP_SET=14,
+ PDQC_SMT_MIB_GET=16,
+ PDQC_SMT_MIB_SET=17
+} pdq_cmd_code_t;
+
+typedef enum {
+ PDQR_SUCCESS=0,
+ PDQR_FAILURE=1,
+ PDQR_WARNING=2,
+ PDQR_LOOP_MODE_BAD=3,
+ PDQR_ITEM_CODE_BAD=4,
+ PDQR_TVX_BAD=5,
+ PDQR_TREQ_BAD=6,
+ PDQR_RESTRICTED_TOKEN_BAD=7,
+ PDQR_NO_EOL=12,
+ PDQR_FILTER_STATE_BAD=13,
+ PDQR_CMD_TYPE_BAD=14,
+ PDQR_ADAPTER_STATE_BAD=15,
+ PDQR_RING_PURGER_BAD=16,
+ PDQR_LEM_THRESHOLD_BAD=17,
+ PDQR_LOOP_NOT_SUPPORTED=18,
+ PDQR_FLUSH_TIME_BAD=19,
+ PDQR_NOT_YET_IMPLEMENTED=20,
+ PDQR_CONFIG_POLICY_BAD=21,
+ PDQR_STATION_ACTION_BAD=22,
+ PDQR_MAC_ACTION_BAD=23,
+ PDQR_CON_POLICIES_BAD=24,
+ PDQR_MAC_LOOP_TIME_BAD=25,
+ PDQR_TB_MAX_BAD=26,
+ PDQR_LER_CUTOFF_BAD=27,
+ PDQR_LER_ALARM_BAD=28,
+ PDQR_MAC_PATHS_REQ_BAD=29,
+ PDQR_MAC_T_REQ_BAD=30,
+ PDQR_EMAC_RING_PURGER_BAD=31,
+ PDQR_EMAC_RTOKEN_TIMOUT_AD=32,
+ PDQR_NO_SUCH_ENTRY=33,
+ PDQR_T_NOTIFY_BAD=34,
+ PDQR_TR_MAX_EXP_BAD=35,
+ PDQR_FRAME_ERR_THRESHOLD_BAD=36,
+ PDQR_MAX_TREQ_BAD=37,
+ PDQR_FULL_DUPLEX_ENABLE_BAD=38,
+ PDQR_ITEM_INDEX_BAD=39
+} pdq_response_code_t;
+
+typedef enum {
+ PDQI_EOL=0,
+ PDQI_T_REQ=1,
+ PDQI_TVX=2,
+ PDQI_RESTRICTED_TOKEN=3,
+ PDQI_LEM_THRESHOLD=4,
+ PDQI_RING_PURGER=5,
+ PDQI_COUNTER_INTERVAL=6,
+ PDQI_IND_GROUP_PROM=7,
+ PDQI_GROUP_PROM=8,
+ PDQI_BROADCAST=9,
+ PDQI_SMT_PROM=10,
+ PDQI_SMT_USER=11,
+ PDQI_RESERVED=12,
+ PDQI_IMPLEMENTOR=13,
+ PDQI_LOOPBACK_MODE=14,
+ PDQI_SMT_CONFIG_POLICY=16,
+ PDQI_SMT_CONNECTION_POLICY=17,
+ PDQI_SMT_T_NOTIFY=18,
+ PDQI_SMT_STATION_ACTION=19,
+ PDQI_MAC_PATHS_REQUESTED=21,
+ PDQI_MAC_ACTION=23,
+ PDQI_PORT_CONNECTION_POLICIES=24,
+ PDQI_PORT_PATHS_REQUESTED=25,
+ PDQI_PORT_MAC_LOOP_TIME=26,
+ PDQI_PORT_TB_MAX=27,
+ PDQI_PORT_LER_CUTOFF=28,
+ PDQI_PORT_LER_ALARM=29,
+ PDQI_PORT_ACTION=30,
+ PDQI_FLUSH_TIME=32,
+ PDQI_SMT_USER_DATA=33,
+ PDQI_SMT_STATUS_REPORT_POLICY=34,
+ PDQI_SMT_TRACE_MAX_EXPIRATION=35,
+ PDQI_MAC_FRAME_ERR_THRESHOLD=36,
+ PDQI_MAC_UNIT_DATA_ENABLE=37,
+ PDQI_PATH_TVX_LOWER_BOUND=38,
+ PDQI_PATH_TMAX_LOWER_BOUND=39,
+ PDQI_PATH_MAX_TREQ=40,
+ PDQI_MAC_TREQ=41,
+ PDQI_EMAC_RING_PURGER=42,
+ PDQI_EMAC_RTOKEN_TIMEOUT=43,
+ PDQI_FULL_DUPLEX_ENABLE=44
+} pdq_item_code_t;
+
+enum _pdq_boolean_t {
+ PDQ_FALSE=0,
+ PDQ_TRUE=1
+};
+
+typedef enum {
+ PDQ_FILTER_BLOCK=0,
+ PDQ_FILTER_PASS=1
+} pdq_filter_state_t;
+
+typedef enum {
+ PDQ_STATION_TYPE_SAS=0,
+ PDQ_STATION_TYPE_DAC=1,
+ PDQ_STATION_TYPE_SAC=2,
+ PDQ_STATION_TYPE_NAC=3,
+ PDQ_STATION_TYPE_DAS=4
+} pdq_station_type_t;
+
+typedef enum {
+ PDQ_STATION_STATE_OFF=0,
+ PDQ_STATION_STATE_ON=1,
+ PDQ_STATION_STATE_LOOPBACK=2
+} pdq_station_state_t;
+
+typedef enum {
+ PDQ_LINK_STATE_OFF_READY=1,
+ PDQ_LINK_STATE_OFF_FAULT_RECOVERY=2,
+ PDQ_LINK_STATE_ON_RING_INIT=3,
+ PDQ_LINK_STATE_ON_RING_RUN=4,
+ PDQ_LINK_STATE_BROKEN=5
+} pdq_link_state_t;
+
+typedef enum {
+ PDQ_DA_TEST_STATE_UNKNOWN=0,
+ PDQ_DA_TEST_STATE_SUCCESS=1,
+ PDQ_DA_TEST_STATE_DUPLICATE=2
+} pdq_da_test_state_t;
+
+typedef enum {
+ PDQ_RING_PURGER_STATE_OFF=0,
+ PDQ_RING_PURGER_STATE_CANDIDATE=1,
+ PDQ_RING_PURGER_STATE_NON_PURGER=2,
+ PDQ_RING_PURGER_STATE_PURGER=3
+} pdq_ring_purger_state_t;
+
+typedef enum {
+ PDQ_FRAME_STRING_MODE_SA_MATCH=0,
+ PDQ_FRAME_STRING_MODE_FCI_STRIP=1
+} pdq_frame_strip_mode_t;
+
+typedef enum {
+ PDQ_RING_ERROR_REASON_NO_ERROR=0,
+ PDQ_RING_ERROR_REASON_RING_INIT_INITIATED=5,
+ PDQ_RING_ERROR_REASON_RING_INIT_RECEIVED=6,
+ PDQ_RING_ERROR_REASON_RING_BEACONING_INITIATED=7,
+ PDQ_RING_ERROR_REASON_DUPLICATE_ADDRESS_DETECTED=8,
+ PDQ_RING_ERROR_REASON_DUPLICATE_TOKEN_DETECTED=9,
+ PDQ_RING_ERROR_REASON_RING_PURGER_ERROR=10,
+ PDQ_RING_ERROR_REASON_FCI_STRIP_ERROR=11,
+ PDQ_RING_ERROR_REASON_RING_OP_OSCILLATION=12,
+ PDQ_RING_ERROR_REASON_DIRECTED_BEACON_RECEVIED=13,
+ PDQ_RING_ERROR_REASON_PC_TRACE_INITIATED=14,
+ PDQ_RING_ERROR_REASON_PC_TRACE_RECEVIED=15
+} pdq_ring_error_reason_t;
+
+typedef enum {
+ PDQ_STATION_MODE_NORMAL=0,
+ PDQ_STATION_MODE_INTERNAL_LOOPBACK=1
+} pdq_station_mode_t;
+
+typedef enum {
+ PDQ_PHY_TYPE_A=0,
+ PDQ_PHY_TYPE_B=1,
+ PDQ_PHY_TYPE_S=2,
+ PDQ_PHY_TYPE_M=3,
+ PDQ_PHY_TYPE_UNKNOWN=4
+} pdq_phy_type_t;
+
+typedef enum {
+ PDQ_PMD_TYPE_ANSI_MUTLI_MODE=0,
+ PDQ_PMD_TYPE_ANSI_SINGLE_MODE_TYPE_1=1,
+ PDQ_PMD_TYPE_ANSI_SIGNLE_MODE_TYPE_2=2,
+ PDQ_PMD_TYPE_ANSI_SONET=3,
+ PDQ_PMD_TYPE_LOW_POWER=100,
+ PDQ_PMD_TYPE_THINWIRE=101,
+ PDQ_PMD_TYPE_SHIELDED_TWISTED_PAIR=102,
+ PDQ_PMD_TYPE_UNSHIELDED_TWISTED_PAIR=103
+} pdq_pmd_type_t;
+
+typedef enum {
+ PDQ_PMD_CLASS_ANSI_MULTI_MODE=0,
+ PDQ_PMD_CLASS_SINGLE_MODE_TYPE_1=1,
+ PDQ_PMD_CLASS_SINGLE_MODE_TYPE_2=2,
+ PDQ_PMD_CLASS_SONET=3,
+ PDQ_PMD_CLASS_LOW_COST_POWER_FIBER=4,
+ PDQ_PMD_CLASS_TWISTED_PAIR=5,
+ PDQ_PMD_CLASS_UNKNOWN=6,
+ PDQ_PMD_CLASS_UNSPECIFIED=7
+} pdq_pmd_class_t;
+
+typedef enum {
+ PDQ_PHY_STATE_INTERNAL_LOOPBACK=0,
+ PDQ_PHY_STATE_BROKEN=1,
+ PDQ_PHY_STATE_OFF_READY=2,
+ PDQ_PHY_STATE_WAITING=3,
+ PDQ_PHY_STATE_STARTING=4,
+ PDQ_PHY_STATE_FAILED=5,
+ PDQ_PHY_STATE_WATCH=6,
+ PDQ_PHY_STATE_INUSE=7
+} pdq_phy_state_t;
+
+typedef enum {
+ PDQ_REJECT_REASON_NONE=0,
+ PDQ_REJECT_REASON_LOCAL_LCT=1,
+ PDQ_REJECT_REASON_REMOTE_LCT=2,
+ PDQ_REJECT_REASON_LCT_BOTH_SIDES=3,
+ PDQ_REJECT_REASON_LEM_REJECT=4,
+ PDQ_REJECT_REASON_TOPOLOGY_ERROR=5,
+ PDQ_REJECT_REASON_NOISE_REJECT=6,
+ PDQ_REJECT_REASON_REMOTE_REJECT=7,
+ PDQ_REJECT_REASON_TRACE_IN_PROGRESS=8,
+ PDQ_REJECT_REASON_TRACE_RECEIVED_DISABLED=9,
+ PDQ_REJECT_REASON_STANDBY=10,
+ PDQ_REJECT_REASON_LCT_PROTOCOL_ERROR=11
+} pdq_reject_reason_t;
+
+typedef enum {
+ PDQ_BROKEN_REASON_NONE=0
+} pdq_broken_reason_t;
+
+typedef enum {
+ PDQ_RI_REASON_TVX_EXPIRED=0,
+ PDQ_RI_REASON_TRT_EXPIRED=1,
+ PDQ_RI_REASON_RING_PURGER_ELECTION_ATTEMPT_LIMIT_EXCEEDED=2,
+ PDQ_RI_REASON_PURGE_ERROR_LIMIT_EXCEEDED=3,
+ PDQ_RI_REASON_RESTRICTED_TOKEN_TIMEOUT=4
+} pdq_ri_reason_t;
+
+typedef enum {
+ PDQ_LCT_DIRECTION_LOCAL_LCT=0,
+ PDQ_LCT_DIRECTION_REMOTE_LCT=1,
+ PDQ_LCT_DIRECTION_LCT_BOTH_SIDES=2
+} pdq_lct_direction_t;
+
+typedef enum {
+ PDQ_PORT_A=0,
+ PDQ_PORT_B=1
+} pdq_port_type_t;
+
+typedef struct {
+ pdq_uint8_t station_id_bytes[8];
+} pdq_station_id_t;
+
+typedef pdq_uint32_t pdq_fdditimer_t;
+/*
+ * Command format for Start, Filter_Get, ... commands
+ */
+typedef struct {
+ pdq_cmd_code_t generic_op;
+} pdq_cmd_generic_t;
+
+/*
+ * Response format for Start, Filter_Set, ... commands
+ */
+typedef struct {
+ pdq_uint32_t generic_reserved;
+ pdq_cmd_code_t generic_op;
+ pdq_response_code_t generic_status;
+} pdq_response_generic_t;
+
+/*
+ * Command format for Filter_Set command
+ */
+typedef struct {
+ pdq_cmd_code_t filter_set_op;
+ struct {
+ pdq_item_code_t item_code;
+ pdq_filter_state_t filter_state;
+ } filter_set_items[7];
+ pdq_item_code_t filter_set_eol_item_code;
+} pdq_cmd_filter_set_t;
+
+/*
+ * Response format for Filter_Get command.
+ */
+typedef struct {
+ pdq_uint32_t filter_get_reserved;
+ pdq_cmd_code_t filter_get_op;
+ pdq_response_code_t filter_get_status;
+ pdq_filter_state_t filter_get_ind_group_prom;
+ pdq_filter_state_t filter_get_group_prom;
+ pdq_filter_state_t filter_get_broadcast_all;
+ pdq_filter_state_t filter_get_smt_prom;
+ pdq_filter_state_t filter_get_smt_user;
+ pdq_filter_state_t filter_get_reserved_all;
+ pdq_filter_state_t filter_get_implementor_all;
+} pdq_response_filter_get_t;
+
+#define PDQ_SIZE_RESPONSE_FILTER_GET 0x28
+
+typedef struct {
+ pdq_cmd_code_t chars_set_op;
+ struct {
+ pdq_item_code_t item_code;
+ pdq_uint32_t item_value;
+ pdq_port_type_t item_port;
+ } chars_set_items[1];
+ pdq_item_code_t chars_set_eol_item_code;
+} pdq_cmd_chars_set_t;
+
+typedef struct {
+ pdq_cmd_code_t addr_filter_set_op;
+ pdq_lanaddr_t addr_filter_set_addresses[62];
+} pdq_cmd_addr_filter_set_t;
+
+#define PDQ_SIZE_CMD_ADDR_FILTER_SET 0x1F4
+
+typedef struct {
+ pdq_uint32_t addr_filter_get_reserved;
+ pdq_cmd_code_t addr_filter_get_op;
+ pdq_response_code_t addr_filter_get_status;
+ pdq_lanaddr_t addr_filter_get_addresses[62];
+} pdq_response_addr_filter_get_t;
+
+#define PDQ_SIZE_RESPONSE_ADDR_FILTER_GET 0x1FC
+
+typedef struct {
+ pdq_uint32_t status_chars_get_reserved;
+ pdq_cmd_code_t status_chars_get_op;
+ pdq_response_code_t status_chars_get_status;
+ struct {
+ /* Station Characteristic Attributes */
+ pdq_station_id_t station_id;
+ pdq_station_type_t station_type;
+ pdq_uint32_t smt_version_id;
+ pdq_uint32_t smt_max_version_id;
+ pdq_uint32_t smt_min_version_id;
+ /* Station Status Attributes */
+ pdq_station_state_t station_state;
+ /* Link Characteristic Attributes */
+ pdq_lanaddr_t link_address;
+ pdq_fdditimer_t t_req;
+ pdq_fdditimer_t tvx;
+ pdq_fdditimer_t restricted_token_timeout;
+ pdq_boolean_t ring_purger_enable;
+ pdq_link_state_t link_state;
+ pdq_fdditimer_t negotiated_trt;
+ pdq_da_test_state_t dup_addr_flag;
+ /* Link Status Attributes */
+ pdq_lanaddr_t upstream_neighbor;
+ pdq_lanaddr_t old_upstream_neighbor;
+ pdq_boolean_t upstream_neighbor_dup_addr_flag;
+ pdq_lanaddr_t downstream_neighbor;
+ pdq_lanaddr_t old_downstream_neighbor;
+ pdq_ring_purger_state_t ring_purger_state;
+ pdq_frame_strip_mode_t frame_strip_mode;
+ pdq_ring_error_reason_t ring_error_reason;
+ pdq_boolean_t loopback;
+ pdq_fdditimer_t ring_latency;
+ pdq_lanaddr_t last_dir_beacon_sa;
+ pdq_lanaddr_t last_dir_beacon_una;
+ /* Phy Characteristic Attributes */
+ pdq_phy_type_t phy_type[2];
+ pdq_pmd_type_t pmd_type[2];
+ pdq_uint32_t lem_threshold[2];
+ /* Phy Status Attributes */
+ pdq_phy_state_t phy_state[2];
+ pdq_phy_type_t neighbor_phy_type[2];
+ pdq_uint32_t link_error_estimate[2];
+ pdq_broken_reason_t broken_reason[2];
+ pdq_reject_reason_t reject_reason[2];
+ /* Miscellaneous */
+ pdq_uint32_t counter_interval;
+ pdq_fwrev_t module_rev;
+ pdq_fwrev_t firmware_rev;
+ pdq_uint32_t mop_device_type;
+ pdq_uint32_t fddi_led[2];
+ pdq_uint32_t flush;
+ } status_chars_get;
+} pdq_response_status_chars_get_t;
+
+#define PDQ_SIZE_RESPONSE_STATUS_CHARS_GET 0xF0
+
+typedef struct {
+ pdq_uint32_t fddi_mib_get_reserved;
+ pdq_cmd_code_t fddi_mib_get_op;
+ pdq_response_code_t fddi_mib_get_status;
+ struct {
+ /* SMT Objects */
+ pdq_station_id_t smt_station_id;
+ pdq_uint32_t smt_op_version_id;
+ pdq_uint32_t smt_hi_version_id;
+ pdq_uint32_t smt_lo_version_id;
+ pdq_uint32_t smt_mac_ct;
+ pdq_uint32_t smt_non_master_ct;
+ pdq_uint32_t smt_master_ct;
+ pdq_uint32_t smt_paths_available;
+ pdq_uint32_t smt_config_capabilities;
+ pdq_uint32_t smt_config_policy;
+ pdq_uint32_t smt_connection_policy;
+ pdq_uint32_t smt_t_notify;
+ pdq_uint32_t smt_status_reporting;
+ pdq_uint32_t smt_ecm_state;
+ pdq_uint32_t smt_cf_state;
+ pdq_uint32_t smt_hold_state;
+ pdq_uint32_t smt_remote_disconnect_flag;
+ pdq_uint32_t smt_station_action;
+ /* MAC Objects */
+ pdq_uint32_t mac_frame_status_capabilities;
+ pdq_uint32_t mac_t_max_greatest_lower_bound;
+ pdq_uint32_t mac_tvx_greatest_lower_bound;
+ pdq_uint32_t mac_paths_available;
+ pdq_uint32_t mac_current_path;
+ pdq_lanaddr_t mac_upstream_neighbor;
+ pdq_lanaddr_t mac_old_upstream_neighbor;
+ pdq_uint32_t mac_dup_addr_test;
+ pdq_uint32_t mac_paths_requested;
+ pdq_uint32_t mac_downstream_port_type;
+ pdq_lanaddr_t mac_smt_address;
+ pdq_uint32_t mac_t_req;
+ pdq_uint32_t mac_t_neg;
+ pdq_uint32_t mac_t_max;
+ pdq_uint32_t mac_tvx_value;
+ pdq_uint32_t mac_t_min;
+ pdq_uint32_t mac_current_frame_status;
+ pdq_uint32_t mac_frame_error_threshold;
+ pdq_uint32_t mac_frame_error_ratio;
+ pdq_uint32_t mac_rmt_state;
+ pdq_uint32_t mac_da_flag;
+ pdq_uint32_t mac_una_da_flag;
+ pdq_uint32_t mac_frame_condition;
+ pdq_uint32_t mac_chip_set;
+ pdq_uint32_t mac_action;
+ /* Port Objects */
+ pdq_uint32_t port_pc_type[2];
+ pdq_uint32_t port_pc_neighbor[2];
+ pdq_uint32_t port_connection_policies[2];
+ pdq_uint32_t port_remote_mac_indicated[2];
+ pdq_uint32_t port_ce_state[2];
+ pdq_uint32_t port_paths_requested[2];
+ pdq_uint32_t port_mac_placement[2];
+ pdq_uint32_t port_available_paths[2];
+ pdq_uint32_t port_mac_loop_time[2];
+ pdq_uint32_t port_tb_max[2];
+ pdq_uint32_t port_bs_flag[2];
+ pdq_uint32_t port_ler_estimate[2];
+ pdq_uint32_t port_ler_cutoff[2];
+ pdq_uint32_t port_ler_alarm[2];
+ pdq_uint32_t port_connect_state[2];
+ pdq_uint32_t port_pcm_state[2];
+ pdq_uint32_t port_pc_withhold[2];
+ pdq_uint32_t port_ler_condition[2];
+ pdq_uint32_t port_chip_set[2];
+ pdq_uint32_t port_action[2];
+ /* Attachment Objects */
+ pdq_uint32_t attachment_class;
+ pdq_uint32_t attachment_optical_bypass_present;
+ pdq_uint32_t attachment_imax_expiration;
+ pdq_uint32_t attachment_inserted_status;
+ pdq_uint32_t attachment_insert_policy;
+ } fddi_mib_get;
+} pdq_response_fddi_mib_get_t;
+
+#define PDQ_SIZE_RESPONSE_FDDI_MIB_GET 0x17C
+
+typedef enum {
+ PDQ_FDX_STATE_IDLE=0,
+ PDQ_FDX_STATE_REQUEST=1,
+ PDQ_FDX_STATE_CONFIRM=2,
+ PDQ_FDX_STATE_OPERATION=3
+} pdq_fdx_state_t;
+
+typedef struct {
+ pdq_uint32_t dec_ext_mib_get_reserved;
+ pdq_cmd_code_t dec_ext_mib_get_op;
+ pdq_response_code_t dec_ext_mib_get_response;
+ struct {
+ /* SMT Objects */
+ pdq_uint32_t esmt_station_type;
+ /* MAC Objects */
+ pdq_uint32_t emac_link_state;
+ pdq_uint32_t emac_ring_purger_state;
+ pdq_uint32_t emac_ring_purger_enable;
+ pdq_uint32_t emac_frame_strip_mode;
+ pdq_uint32_t emac_ring_error_reason;
+ pdq_uint32_t emac_upstream_nbr_dupl_address_flag;
+ pdq_uint32_t emac_restricted_token_timeout;
+ /* Port Objects */
+ pdq_uint32_t eport_pmd_type[2];
+ pdq_uint32_t eport_phy_state[2];
+ pdq_uint32_t eport_reject_reason[2];
+ /* Full Duplex Objects */
+ pdq_boolean_t fdx_enable;
+ pdq_boolean_t fdx_operational;
+ pdq_fdx_state_t fdx_state;
+ } dec_ext_mib_get;
+} pdq_response_dec_ext_mib_get_t;
+
+#define PDQ_SIZE_RESPONSE_DEC_EXT_MIB_GET 0x50
+
+typedef enum {
+ PDQ_CALLER_ID_NONE=0,
+ PDQ_CALLER_ID_SELFTEST=1,
+ PDQ_CALLER_ID_MFG=2,
+ PDQ_CALLER_ID_FIRMWARE=5,
+ PDQ_CALLER_ID_CONSOLE=8
+} pdq_caller_id_t;
+
+typedef struct {
+ pdq_uint32_t error_log_get__reserved;
+ pdq_cmd_code_t error_log_get_op;
+ pdq_response_code_t error_log_get_status;
+ /* Error Header */
+ pdq_uint32_t error_log_get_event_status;
+ /* Event Information Block */
+ pdq_caller_id_t error_log_get_caller_id;
+ pdq_uint32_t error_log_get_timestamp[2];
+ pdq_uint32_t error_log_get_write_count;
+ /* Diagnostic Information */
+ pdq_uint32_t error_log_get_fru_implication_mask;
+ pdq_uint32_t error_log_get_test_id;
+ pdq_uint32_t error_log_get_diag_reserved[6];
+ /* Firmware Information */
+ pdq_uint32_t error_log_get_fw_reserved[112];
+} pdq_response_error_log_get_t;
+
+
+/*
+ * Definitions for the Unsolicited Event Queue.
+ */
+typedef enum {
+ PDQ_UNSOLICITED_EVENT=0,
+ PDQ_UNSOLICITED_COUNTERS=1
+} pdq_event_t;
+
+typedef enum {
+ PDQ_ENTITY_STATION=0,
+ PDQ_ENTITY_LINK=1,
+ PDQ_ENTITY_PHY_PORT=2
+} pdq_entity_t;
+
+typedef enum {
+ PDQ_STATION_EVENT_TRACE_RECEIVED=1
+} pdq_station_event_t;
+
+typedef enum {
+ PDQ_STATION_EVENT_ARGUMENT_REASON=0, /* pdq_uint32_t */
+ PDQ_STATION_EVENT_ARGUMENT_EOL=0xFF
+} pdq_station_event_argument_t;
+
+typedef enum {
+ PDQ_LINK_EVENT_TRANSMIT_UNDERRUN=0,
+ PDQ_LINK_EVENT_TRANSMIT_FAILED=1,
+ PDQ_LINK_EVENT_BLOCK_CHECK_ERROR=2,
+ PDQ_LINK_EVENT_FRAME_STATUS_ERROR=3,
+ PDQ_LINK_EVENT_PDU_LENGTH_ERROR=4,
+ PDQ_LINK_EVENT_RECEIVE_DATA_OVERRUN=7,
+ PDQ_LINK_EVENT_NO_USER_BUFFER=9,
+ PDQ_LINK_EVENT_RING_INITIALIZATION_INITIATED=10,
+ PDQ_LINK_EVENT_RING_INITIALIZATION_RECEIVED=11,
+ PDQ_LINK_EVENT_RING_BEACON_INITIATED=12,
+ PDQ_LINK_EVENT_DUPLICATE_ADDRESS_FAILURE=13,
+ PDQ_LINK_EVENT_DUPLICATE_TOKEN_DETECTED=14,
+ PDQ_LINK_EVENT_RING_PURGE_ERROR=15,
+ PDQ_LINK_EVENT_FCI_STRIP_ERROR=16,
+ PDQ_LINK_EVENT_TRACE_INITIATED=17,
+ PDQ_LINK_EVENT_DIRECTED_BEACON_RECEIVED=18
+} pdq_link_event_t;
+
+typedef enum {
+ PDQ_LINK_EVENT_ARGUMENT_REASON=0, /* pdq_rireason_t */
+ PDQ_LINK_EVENT_ARGUMENT_DATA_LINK_HEADER=1, /* pdq_dlhdr_t */
+ PDQ_LINK_EVENT_ARGUMENT_SOURCE=2, /* pdq_lanaddr_t */
+ PDQ_LINK_EVENT_ARGUMENT_UPSTREAM_NEIGHBOR=3,/* pdq_lanaddr_t */
+ PDQ_LINK_EVENT_ARGUMENT_EOL=0xFF
+} pdq_link_event_argument_t;
+
+typedef enum {
+ PDQ_PHY_EVENT_LEM_ERROR_MONITOR_REJECT=0,
+ PDQ_PHY_EVENT_ELASTICITY_BUFFER_ERROR=1,
+ PDQ_PHY_EVENT_LINK_CONFIDENCE_TEST_REJECT=2
+} pdq_phy_event_t;
+
+typedef enum {
+ PDQ_PHY_EVENT_ARGUMENT_DIRECTION=0, /* pdq_lct_direction_t */
+ PDQ_PHY_EVENT_ARGUMENT_EOL=0xFF
+} pdq_phy_event_arguments;
+
+struct _pdq_unsolicited_event_t {
+ pdq_uint32_t rvent_reserved;
+ pdq_event_t event_type;
+ pdq_entity_t event_entity;
+ pdq_uint32_t event_index;
+ union {
+ pdq_station_event_t station_event;
+ pdq_link_event_t link_event;
+ pdq_phy_event_t phy_event;
+ pdq_uint32_t value;
+ } event_code;
+ /*
+ * The remainder of this event is an argument list.
+ */
+ pdq_uint32_t event__filler[123];
+};
+
+#endif /* _PDQREG_H */
diff --git a/sys/dev/pdq/pdqvar.h b/sys/dev/pdq/pdqvar.h
new file mode 100644
index 0000000..6bb3065
--- /dev/null
+++ b/sys/dev/pdq/pdqvar.h
@@ -0,0 +1,351 @@
+/*-
+ * Copyright (c) 1995, 1996 Matt Thomas <matt@3am-software.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: pdqvar.h,v 1.19 1996/07/31 21:38:44 thomas Exp $
+ *
+ */
+
+/*
+ * DEC PDQ FDDI Controller; PDQ O/S dependent definitions
+ *
+ * Written by Matt Thomas
+ *
+ */
+
+#ifndef _PDQ_OS_H
+#define _PDQ_OS_H
+
+#define PDQ_OS_TX_TIMEOUT 5 /* seconds */
+
+typedef struct _pdq_t pdq_t;
+typedef struct _pdq_csrs_t pdq_csrs_t;
+typedef struct _pdq_pci_csrs_t pdq_pci_csrs_t;
+typedef struct _pdq_lanaddr_t pdq_lanaddr_t;
+typedef unsigned int pdq_uint32_t;
+typedef unsigned short pdq_uint16_t;
+typedef unsigned char pdq_uint8_t;
+typedef enum _pdq_boolean_t pdq_boolean_t;
+typedef enum _pdq_type_t pdq_type_t;
+typedef enum _pdq_state_t pdq_state_t;
+
+enum _pdq_type_t {
+ PDQ_DEFPA, /* PCI-bus */
+ PDQ_DEFEA, /* EISA-bus */
+ PDQ_DEFTA, /* TurboChannel */
+ PDQ_DEFAA, /* FutureBus+ */
+ PDQ_DEFQA /* Q-bus */
+};
+
+#if defined(PDQTEST)
+#include <pdq_os_test.h>
+#elif defined(__FreeBSD__) || defined(__bsdi__) || defined(__NetBSD__)
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#ifndef M_MCAST
+#include <sys/mbuf.h>
+#endif /* M_CAST */
+#include <sys/malloc.h>
+#include <vm/vm.h>
+#include <vm/vm_kern.h>
+
+#define PDQ_USE_MBUFS
+#if defined(__NetBSD__)
+#define PDQ_OS_PREFIX "%s: "
+#define PDQ_OS_PREFIX_ARGS pdq->pdq_os_name
+#else
+#define PDQ_OS_PREFIX "%s%d: "
+#define PDQ_OS_PREFIX_ARGS pdq->pdq_os_name, pdq->pdq_unit
+#endif
+#if defined(__FreeBSD__) && BSD >= 199506
+#define PDQ_OS_PAGESIZE PAGE_SIZE
+#else
+#define PDQ_OS_PAGESIZE NBPG
+#endif
+#define PDQ_OS_USEC_DELAY(n) DELAY(n)
+#define PDQ_OS_MEMZERO(p, n) bzero((caddr_t)(p), (n))
+#if defined(__NetBSD__) && defined(__alpha__)
+#define PDQ_OS_VA_TO_PA(pdq, p) (vtophys((vm_offset_t)p) | (pdq->pdq_type == PDQ_DEFTA ? 0 : 0x40000000))
+#else
+#define PDQ_OS_VA_TO_PA(pdq, p) vtophys(p)
+#endif
+#define PDQ_OS_MEMALLOC(n) malloc(n, M_DEVBUF, M_NOWAIT)
+#define PDQ_OS_MEMFREE(p, n) free((void *) p, M_DEVBUF)
+#ifdef __FreeBSD__
+#define PDQ_OS_MEMALLOC_CONTIG(n) vm_page_alloc_contig(n, 0, 0xffffffff, PAGE_SIZE)
+#define PDQ_OS_MEMFREE_CONTIG(p, n) kmem_free(kernel_map, (vm_offset_t) p, n)
+#else
+#define PDQ_OS_MEMALLOC_CONTIG(n) kmem_alloc(kernel_map, round_page(n))
+#define PDQ_OS_MEMFREE_CONTIG(p, n) kmem_free(kernel_map, (vm_offset_t) p, n)
+#endif /* __FreeBSD__ */
+
+#if defined(__FreeBSD__)
+#include <vm/pmap.h>
+#include <vm/vm_extern.h>
+#include <machine/cpufunc.h>
+#include <machine/clock.h>
+typedef void ifnet_ret_t;
+typedef int ioctl_cmd_t;
+typedef enum { PDQ_BUS_EISA, PDQ_BUS_PCI } pdq_bus_t;
+typedef u_int16_t pdq_bus_ioport_t;
+typedef volatile pdq_uint32_t *pdq_bus_memaddr_t;
+typedef pdq_bus_memaddr_t pdq_bus_memoffset_t;
+#if BSD >= 199506 /* __FreeBSD__ */
+#define PDQ_BPF_MTAP(sc, m) bpf_mtap(&(sc)->sc_if, m)
+#define PDQ_BPFATTACH(sc, t, s) bpfattach(&(sc)->sc_if, t, s)
+#endif
+
+
+#elif defined(__bsdi__)
+#include <machine/inline.h>
+typedef int ifnet_ret_t;
+typedef int ioctl_cmd_t;
+typedef enum { PDQ_BUS_EISA, PDQ_BUS_PCI } pdq_bus_t;
+typedef u_int16_t pdq_bus_ioport_t;
+typedef volatile pdq_uint32_t *pdq_bus_memaddr_t;
+typedef pdq_bus_memaddr_t pdq_bus_memoffset_t;
+
+
+#elif defined(__NetBSD__)
+#include <machine/bus.h>
+#include <machine/intr.h>
+#define PDQ_OS_PTR_FMT "%p"
+typedef void ifnet_ret_t;
+typedef u_long ioctl_cmd_t;
+typedef bus_chipset_tag_t pdq_bus_t;
+typedef bus_io_handle_t pdq_bus_ioport_t;
+#if defined(PDQ_IOMAPPED)
+typedef bus_io_handle_t pdq_bus_memaddr_t;
+#else
+typedef bus_mem_handle_t pdq_bus_memaddr_t;
+#endif
+typedef pdq_uint32_t pdq_bus_memoffset_t;
+#define PDQ_OS_IOMEM
+#define PDQ_OS_IORD_32(t, base, offset) bus_io_read_4 (t, base, offset)
+#define PDQ_OS_IOWR_32(t, base, offset, data) bus_io_write_4 (t, base, offset, data)
+#define PDQ_OS_IORD_8(t, base, offset) bus_io_read_1 (t, base, offset)
+#define PDQ_OS_IOWR_8(t, base, offset, data) bus_io_write_1 (t, base, offset, data)
+#define PDQ_OS_MEMRD_32(t, base, offset) bus_mem_read_4(t, base, offset)
+#define PDQ_OS_MEMWR_32(t, base, offset, data) bus_mem_write_4(t, base, offset, data)
+#define PDQ_CSR_OFFSET(base, offset) (0 + (offset)*sizeof(pdq_uint32_t))
+
+#if defined(PDQ_IOMAPPED)
+#define PDQ_CSR_WRITE(csr, name, data) PDQ_OS_IOWR_32((csr)->csr_bus, (csr)->csr_base, (csr)->name, data)
+#define PDQ_CSR_READ(csr, name) PDQ_OS_IORD_32((csr)->csr_bus, (csr)->csr_base, (csr)->name)
+#else
+#define PDQ_CSR_WRITE(csr, name, data) PDQ_OS_MEMWR_32((csr)->csr_bus, (csr)->csr_base, (csr)->name, data)
+#define PDQ_CSR_READ(csr, name) PDQ_OS_MEMRD_32((csr)->csr_bus, (csr)->csr_base, (csr)->name)
+#endif
+
+#endif
+
+#if !defined(PDQ_BPF_MTAP)
+#define PDQ_BPF_MTAP(sc, m) bpf_mtap((sc)->sc_bpf, m)
+#endif
+
+#if !defined(PDQ_BPFATTACH)
+#define PDQ_BPFATTACH(sc, t, s) bpfattach(&(sc)->sc_bpf, &(sc)->sc_if, t, s)
+#endif
+
+#if !defined(PDQ_OS_PTR_FMT)
+#define PDQ_OS_PTR_FMT "0x%x"
+#endif
+
+#if !defined(PDQ_OS_IOMEM)
+#define PDQ_OS_IORD_32(t, base, offset) inl((base) + (offset))
+#define PDQ_OS_IOWR_32(t, base, offset, data) outl((base) + (offset), data)
+#define PDQ_OS_IORD_8(t, base, offset) inb((base) + (offset))
+#define PDQ_OS_IOWR_8(t, base, offset, data) outb((base) + (offset), data)
+#define PDQ_OS_MEMRD_32(t, base, offset) (0 + *((base) + (offset)))
+#define PDQ_OS_MEMWR_32(t, base, offset, data) do *((base) + (offset)) = (data); while (0)
+#endif
+#ifndef PDQ_CSR_OFFSET
+#define PDQ_CSR_OFFSET(base, offset) (0 + (base) + (offset))
+#endif
+
+#ifndef PDQ_CSR_WRITE
+#define PDQ_CSR_WRITE(csr, name, data) PDQ_OS_MEMWR_32((csr)->csr_bus, (csr)->name, 0, data)
+#define PDQ_CSR_READ(csr, name) PDQ_OS_MEMRD_32((csr)->csr_bus, (csr)->name, 0)
+#endif
+
+#if !defined(PDQ_HWSUPPORT)
+
+typedef struct {
+#if defined(__bsdi__)
+ struct device sc_dev; /* base device */
+ struct isadev sc_id; /* ISA device */
+ struct intrhand sc_ih; /* interrupt vectoring */
+ struct atshutdown sc_ats; /* shutdown routine */
+#elif defined(__NetBSD__)
+ struct device sc_dev; /* base device */
+ void *sc_ih; /* interrupt vectoring */
+ void *sc_ats; /* shutdown hook */
+#elif defined(__FreeBSD__)
+ struct kern_devconf *sc_kdc; /* freebsd cruft */
+#endif
+ struct arpcom sc_ac;
+#define sc_if sc_ac.ac_if
+ pdq_t *sc_pdq;
+#if defined(__alpha__) || defined(__i386__)
+ pdq_bus_ioport_t sc_iobase;
+#endif
+#ifdef PDQ_IOMAPPED
+#define sc_membase sc_iobase
+#else
+ pdq_bus_memaddr_t sc_membase;
+#endif
+ pdq_bus_t sc_bc;
+#if !defined(__bsdi__) || _BSDI_VERSION >= 199401
+#define sc_bpf sc_if.if_bpf
+#else
+ caddr_t sc_bpf;
+#endif
+} pdq_softc_t;
+
+
+extern void pdq_ifreset(pdq_softc_t *sc);
+extern void pdq_ifinit(pdq_softc_t *sc);
+extern void pdq_ifwatchdog(struct ifnet *ifp);
+extern ifnet_ret_t pdq_ifstart(struct ifnet *ifp);
+extern int pdq_ifioctl(struct ifnet *ifp, ioctl_cmd_t cmd, caddr_t data);
+extern void pdq_ifattach(pdq_softc_t *sc, ifnet_ret_t (*ifwatchdog)(int unit));
+#endif /* !PDQ_HWSUPPORT */
+
+
+#elif defined(DLPI_PDQ)
+#include <sys/param.h>
+#include <sys/kmem.h>
+#include <sys/ddi.h>
+#include <sys/stream.h>
+
+#define PDQ_USE_STREAMS
+#define PDQ_OS_PREFIX "%s board %d "
+#define PDQ_OS_PREFIX_ARGS pdq->pdq_os_name, pdq->pdq_unit
+
+#define PDQ_OS_PAGESIZE PAGESIZE
+#define PDQ_OS_USEC_DELAY(n) drv_usecwait(n)
+#define PDQ_OS_MEMZERO(p, n) bzero((caddr_t)(p), (n))
+#define PDQ_OS_VA_TO_PA(pdq, p) vtop((caddr_t)p, NULL)
+#define PDQ_OS_MEMALLOC(n) kmem_zalloc(n, KM_NOSLEEP)
+#define PDQ_OS_MEMFREE(p, n) kmem_free((caddr_t) p, n)
+#define PDQ_OS_MEMALLOC_CONTIG(n) kmem_zalloc_physreq(n, decfddiphysreq_db, KM_NOSLEEP)
+#define PDQ_OS_MEMFREE_CONTIG(p, n) PDQ_OS_MEMFREE(p, n)
+
+extern physreq_t *decfddiphysreq_db;
+extern physreq_t *decfddiphysreq_mblk;
+
+#define PDQ_OS_DATABUF_ALLOC(b) ((void) (((b) = allocb_physreq(PDQ_OS_DATABUF_SIZE, BPRI_MED, decfddiphysreq_mblk)) && ((b)->b_wptr = (b)->b_rptr + PDQ_OS_DATABUF_SIZE)))
+
+#define PDQ_OS_IORD_8(port) inb(port)
+#define PDQ_OS_IOWR_8(port, data) outb(port, data)
+#endif
+
+
+#ifdef PDQ_USE_MBUFS
+#define PDQ_OS_DATABUF_SIZE (MCLBYTES)
+#define PDQ_OS_DATABUF_FREE(b) (m_freem(b))
+#define PDQ_OS_DATABUF_NEXT(b) ((b)->m_next)
+#define PDQ_OS_DATABUF_NEXT_SET(b, b1) ((b)->m_next = (b1))
+#define PDQ_OS_DATABUF_NEXTPKT(b) ((b)->m_nextpkt)
+#define PDQ_OS_DATABUF_NEXTPKT_SET(b, b1) ((b)->m_nextpkt = (b1))
+#define PDQ_OS_DATABUF_LEN(b) ((b)->m_len)
+#define PDQ_OS_DATABUF_LEN_SET(b, n) ((b)->m_len = (n))
+/* #define PDQ_OS_DATABUF_LEN_ADJ(b, n) ((b)->m_len += (n)) */
+#define PDQ_OS_DATABUF_PTR(b) (mtod((b), pdq_uint8_t *))
+#define PDQ_OS_DATABUF_ADJ(b, n) ((b)->m_data += (n), (b)->m_len -= (n))
+typedef struct mbuf PDQ_OS_DATABUF_T;
+
+#define PDQ_OS_DATABUF_ALLOC(b) do { \
+ PDQ_OS_DATABUF_T *x_m0; \
+ MGETHDR(x_m0, M_DONTWAIT, MT_DATA); \
+ if (x_m0 != NULL) { \
+ MCLGET(x_m0, M_DONTWAIT); \
+ if ((x_m0->m_flags & M_EXT) == 0) { \
+ m_free(x_m0); \
+ (b) = NULL; \
+ } else { \
+ (b) = x_m0; \
+ x_m0->m_len = PDQ_OS_DATABUF_SIZE; \
+ } \
+ } else { \
+ (b) = NULL; \
+ } \
+} while (0)
+#define PDQ_OS_DATABUF_RESET(b) ((b)->m_data = (b)->m_ext.ext_buf, (b)->m_len = MCLBYTES)
+#endif /* PDQ_USE_MBUFS */
+
+#ifdef PDQ_USE_STREAMS
+#define PDQ_OS_DATABUF_SIZE (2048)
+#define PDQ_OS_DATABUF_FREE(b) (freemsg(b))
+#define PDQ_OS_DATABUF_NEXT(b) ((b)->b_cont)
+#define PDQ_OS_DATABUF_NEXT_SET(b, b1) ((b)->b_cont = (b1))
+#define PDQ_OS_DATABUF_NEXTPKT(b) ((b)->b_next)
+#define PDQ_OS_DATABUF_NEXTPKT_SET(b, b1) ((b)->b_next = (b1))
+#define PDQ_OS_DATABUF_LEN(b) ((b)->b_wptr - (b)->b_rptr)
+#define PDQ_OS_DATABUF_LEN_SET(b, n) ((b)->b_wptr = (b)->b_rptr + (n))
+/*#define PDQ_OS_DATABUF_LEN_ADJ(b, n) ((b)->b_wptr += (n))*/
+#define PDQ_OS_DATABUF_PTR(b) ((pdq_uint8_t *) (b)->b_rptr)
+#define PDQ_OS_DATABUF_ADJ(b, n) ((b)->b_rptr += (n))
+typedef mblk_t PDQ_OS_DATABUF_T;
+
+#ifndef PDQ_OS_DATABUF_ALLOC
+#define PDQ_OS_DATABUF_ALLOC(b) ((void) (((b) = allocb(PDQ_OS_DATABUF_SIZE, BPRI_MED)) && ((b)->b_wptr = (b)->b_rptr + PDQ_OS_DATABUF_SIZE)))
+#endif /* PDQ_OS_DATABUF_ALLOC */
+#endif /* PDQ_USE_STREAMS */
+
+#define PDQ_OS_TX_TRANSMIT 5
+
+#define PDQ_OS_DATABUF_ENQUEUE(q, b) do { \
+ PDQ_OS_DATABUF_NEXTPKT_SET(b, NULL); \
+ if ((q)->q_tail == NULL) \
+ (q)->q_head = (b); \
+ else \
+ PDQ_OS_DATABUF_NEXTPKT_SET(((PDQ_OS_DATABUF_T *)(q)->q_tail), b); \
+ (q)->q_tail = (b); \
+} while (0)
+
+#define PDQ_OS_DATABUF_DEQUEUE(q, b) do { \
+ if (((b) = (PDQ_OS_DATABUF_T *) (q)->q_head) != NULL) { \
+ if (((q)->q_head = PDQ_OS_DATABUF_NEXTPKT(b)) == NULL) \
+ (q)->q_tail = NULL; \
+ PDQ_OS_DATABUF_NEXTPKT_SET(b, NULL); \
+ } \
+} while (0)
+
+extern void pdq_os_addr_fill(pdq_t *pdq, pdq_lanaddr_t *addrs, size_t numaddrs);
+extern void pdq_os_receive_pdu(pdq_t *, PDQ_OS_DATABUF_T *pdu, size_t pdulen);
+extern void pdq_os_restart_transmitter(pdq_t *pdq);
+extern void pdq_os_transmit_done(pdq_t *pdq, PDQ_OS_DATABUF_T *pdu);
+
+extern pdq_boolean_t pdq_queue_transmit_data(pdq_t *pdq, PDQ_OS_DATABUF_T *pdu);
+extern void pdq_flush_transmitter(pdq_t *pdq);
+
+extern void pdq_run(pdq_t *pdq);
+extern pdq_state_t pdq_stop(pdq_t *pdq);
+extern void pdq_hwreset(pdq_t *pdq);
+
+extern int pdq_interrupt(pdq_t *pdq);
+extern pdq_t *pdq_initialize(pdq_bus_t bus, pdq_bus_memaddr_t csr_va,
+ const char *name, int unit,
+ void *ctx, pdq_type_t type);
+#endif /* _PDQ_OS_H */
OpenPOWER on IntegriCloud