193383Smdodd/* $NetBSD: pdq.c,v 1.33 2001/11/13 13:14:43 lukem Exp $ */ 293383Smdodd 321826Sjoerg/*- 421826Sjoerg * Copyright (c) 1995,1996 Matt Thomas <matt@3am-software.com> 521826Sjoerg * All rights reserved. 621826Sjoerg * 721826Sjoerg * Redistribution and use in source and binary forms, with or without 821826Sjoerg * modification, are permitted provided that the following conditions 921826Sjoerg * are met: 1021826Sjoerg * 1. Redistributions of source code must retain the above copyright 1121826Sjoerg * notice, this list of conditions and the following disclaimer. 1221826Sjoerg * 2. The name of the author may not be used to endorse or promote products 1393383Smdodd * derived from this software without specific prior written permission 1421826Sjoerg * 1521826Sjoerg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1621826Sjoerg * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1721826Sjoerg * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1821826Sjoerg * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1921826Sjoerg * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2021826Sjoerg * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2121826Sjoerg * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2221826Sjoerg * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2321826Sjoerg * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2421826Sjoerg * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2521826Sjoerg * 2693383Smdodd * Id: pdq.c,v 1.32 1997/06/05 01:56:35 thomas Exp 2721826Sjoerg * 2821826Sjoerg */ 2921826Sjoerg 30119418Sobrien#include <sys/cdefs.h> 31119418Sobrien__FBSDID("$FreeBSD$"); 32119418Sobrien 3321826Sjoerg/* 3421826Sjoerg * DEC PDQ FDDI Controller O/S independent code 3521826Sjoerg * 3693383Smdodd * This module should work any on PDQ based board. Note that changes for 3721826Sjoerg * MIPS and Alpha architectures (or any other architecture which requires 3821826Sjoerg * a flushing of memory or write buffers and/or has incoherent caches) 3921826Sjoerg * have yet to be made. 4021826Sjoerg * 4121826Sjoerg * However, it is expected that the PDQ_CSR_WRITE macro will cause a 4221826Sjoerg * flushing of the write buffers. 4321826Sjoerg */ 4421826Sjoerg 4593383Smdodd 4621826Sjoerg#define PDQ_HWSUPPORT /* for pdq.h */ 4721826Sjoerg 4893383Smdodd/* 4993383Smdodd * What a botch having to specific includes for FreeBSD! 5093383Smdodd */ 5193383Smdodd#include <dev/pdq/pdq_freebsd.h> 5221830Sjoerg#include <dev/pdq/pdqreg.h> 5321826Sjoerg 5421826Sjoerg#define PDQ_ROUNDUP(n, x) (((n) + ((x) - 1)) & ~((x) - 1)) 5521826Sjoerg#define PDQ_CMD_RX_ALIGNMENT 16 5621826Sjoerg 5721826Sjoerg#if (defined(PDQTEST) && !defined(PDQ_NOPRINTF)) || defined(PDQVERBOSE) 5821826Sjoerg#define PDQ_PRINTF(x) printf x 5921826Sjoerg#else 6021826Sjoerg#define PDQ_PRINTF(x) do { } while (0) 6121826Sjoerg#endif 6221826Sjoerg 6321826Sjoergstatic const char * const pdq_halt_codes[] = { 6421826Sjoerg "Selftest Timeout", "Host Bus Parity Error", "Host Directed Fault", 6521826Sjoerg "Software Fault", "Hardware Fault", "PC Trace Path Test", 66298955Spfg "DMA Error", "Image CRC Error", "Adapter Processor Error" 6721826Sjoerg}; 6821826Sjoerg 6921826Sjoergstatic const char * const pdq_adapter_states[] = { 7021826Sjoerg "Reset", "Upgrade", "DMA Unavailable", "DMA Available", 7121826Sjoerg "Link Available", "Link Unavailable", "Halted", "Ring Member" 7221826Sjoerg}; 7321826Sjoerg 7421826Sjoerg/* 7521826Sjoerg * The following are used in conjunction with 7621826Sjoerg * unsolicited events 7721826Sjoerg */ 7821826Sjoergstatic const char * const pdq_entities[] = { 7921826Sjoerg "Station", "Link", "Phy Port" 8021826Sjoerg}; 8121826Sjoerg 8221826Sjoergstatic const char * const pdq_station_events[] = { 8393383Smdodd "Unknown Event #0", 8421826Sjoerg "Trace Received" 8521826Sjoerg}; 8621826Sjoerg 8721826Sjoergstatic const char * const pdq_station_arguments[] = { 8821826Sjoerg "Reason" 8921826Sjoerg}; 9021826Sjoerg 9121826Sjoergstatic const char * const pdq_link_events[] = { 9221826Sjoerg "Transmit Underrun", 9321826Sjoerg "Transmit Failed", 9421826Sjoerg "Block Check Error (CRC)", 9521826Sjoerg "Frame Status Error", 9621826Sjoerg "PDU Length Error", 9721826Sjoerg NULL, 9821826Sjoerg NULL, 9921826Sjoerg "Receive Data Overrun", 10021826Sjoerg NULL, 10121826Sjoerg "No User Buffer", 10221826Sjoerg "Ring Initialization Initiated", 10321826Sjoerg "Ring Initialization Received", 10421826Sjoerg "Ring Beacon Initiated", 10521826Sjoerg "Duplicate Address Failure", 10621826Sjoerg "Duplicate Token Detected", 10721826Sjoerg "Ring Purger Error", 10821826Sjoerg "FCI Strip Error", 10921826Sjoerg "Trace Initiated", 11021826Sjoerg "Directed Beacon Received", 11121826Sjoerg}; 11221826Sjoerg 11321826Sjoergstatic const char * const pdq_link_arguments[] = { 11421826Sjoerg "Reason", 11521826Sjoerg "Data Link Header", 11621826Sjoerg "Source", 11721826Sjoerg "Upstream Neighbor" 11821826Sjoerg}; 11921826Sjoerg 12021826Sjoergstatic const char * const pdq_phy_events[] = { 12121826Sjoerg "LEM Error Monitor Reject", 12221826Sjoerg "Elasticy Buffer Error", 12321826Sjoerg "Link Confidence Test Reject" 12421826Sjoerg}; 12521826Sjoerg 12621826Sjoergstatic const char * const pdq_phy_arguments[] = { 12721826Sjoerg "Direction" 12821826Sjoerg}; 12921826Sjoerg 13021826Sjoergstatic const char * const * const pdq_event_arguments[] = { 13121826Sjoerg pdq_station_arguments, 13221826Sjoerg pdq_link_arguments, 13321826Sjoerg pdq_phy_arguments 13421826Sjoerg}; 13521826Sjoerg 13621826Sjoergstatic const char * const * const pdq_event_codes[] = { 13721826Sjoerg pdq_station_events, 13821826Sjoerg pdq_link_events, 13921826Sjoerg pdq_phy_events 14021826Sjoerg}; 14121826Sjoerg 14221826Sjoergstatic const char * const pdq_station_types[] = { 14321826Sjoerg "SAS", "DAC", "SAC", "NAC", "DAS" 14421826Sjoerg}; 14521826Sjoerg 14621826Sjoergstatic const char * const pdq_smt_versions[] = { "", "V6.2", "V7.2", "V7.3" }; 14721826Sjoerg 14821826Sjoergstatic const char pdq_phy_types[] = "ABSM"; 14921826Sjoerg 15021826Sjoergstatic const char * const pdq_pmd_types0[] = { 15121826Sjoerg "ANSI Multi-Mode", "ANSI Single-Mode Type 1", "ANSI Single-Mode Type 2", 15221826Sjoerg "ANSI Sonet" 15321826Sjoerg}; 15421826Sjoerg 15521826Sjoergstatic const char * const pdq_pmd_types100[] = { 15621826Sjoerg "Low Power", "Thin Wire", "Shielded Twisted Pair", 15721826Sjoerg "Unshielded Twisted Pair" 15821826Sjoerg}; 15921826Sjoerg 16021826Sjoergstatic const char * const * const pdq_pmd_types[] = { 16121826Sjoerg pdq_pmd_types0, pdq_pmd_types100 16221826Sjoerg}; 16321826Sjoerg 16421826Sjoergstatic const char * const pdq_descriptions[] = { 16521826Sjoerg "DEFPA PCI", 16621826Sjoerg "DEFEA EISA", 16721826Sjoerg "DEFTA TC", 16821826Sjoerg "DEFAA Futurebus", 16921826Sjoerg "DEFQA Q-bus", 17021826Sjoerg}; 17121826Sjoerg 17221826Sjoergstatic void 17321826Sjoergpdq_print_fddi_chars( 17421826Sjoerg pdq_t *pdq, 17521826Sjoerg const pdq_response_status_chars_get_t *rsp) 17621826Sjoerg{ 17721826Sjoerg const char hexchars[] = "0123456789abcdef"; 17821826Sjoerg 17921826Sjoerg printf( 18021826Sjoerg PDQ_OS_PREFIX 18121826Sjoerg "DEC %s FDDI %s Controller\n", 18221826Sjoerg PDQ_OS_PREFIX_ARGS, 18321826Sjoerg pdq_descriptions[pdq->pdq_type], 18421826Sjoerg pdq_station_types[rsp->status_chars_get.station_type]); 18521826Sjoerg 18621826Sjoerg 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", 18721826Sjoerg PDQ_OS_PREFIX_ARGS, 18821826Sjoerg hexchars[pdq->pdq_hwaddr.lanaddr_bytes[0] >> 4], 18921826Sjoerg hexchars[pdq->pdq_hwaddr.lanaddr_bytes[0] & 0x0F], 19021826Sjoerg hexchars[pdq->pdq_hwaddr.lanaddr_bytes[1] >> 4], 19121826Sjoerg hexchars[pdq->pdq_hwaddr.lanaddr_bytes[1] & 0x0F], 19221826Sjoerg hexchars[pdq->pdq_hwaddr.lanaddr_bytes[2] >> 4], 19321826Sjoerg hexchars[pdq->pdq_hwaddr.lanaddr_bytes[2] & 0x0F], 19421826Sjoerg hexchars[pdq->pdq_hwaddr.lanaddr_bytes[3] >> 4], 19521826Sjoerg hexchars[pdq->pdq_hwaddr.lanaddr_bytes[3] & 0x0F], 19621826Sjoerg hexchars[pdq->pdq_hwaddr.lanaddr_bytes[4] >> 4], 19721826Sjoerg hexchars[pdq->pdq_hwaddr.lanaddr_bytes[4] & 0x0F], 19821826Sjoerg hexchars[pdq->pdq_hwaddr.lanaddr_bytes[5] >> 4], 19921826Sjoerg hexchars[pdq->pdq_hwaddr.lanaddr_bytes[5] & 0x0F], 20021826Sjoerg pdq->pdq_fwrev.fwrev_bytes[0], pdq->pdq_fwrev.fwrev_bytes[1], 20121826Sjoerg pdq->pdq_fwrev.fwrev_bytes[2], pdq->pdq_fwrev.fwrev_bytes[3], 20221826Sjoerg rsp->status_chars_get.module_rev.fwrev_bytes[0]); 20321826Sjoerg 20421826Sjoerg if (rsp->status_chars_get.smt_version_id < PDQ_ARRAY_SIZE(pdq_smt_versions)) { 20521826Sjoerg printf(", SMT %s\n", pdq_smt_versions[rsp->status_chars_get.smt_version_id]); 20621826Sjoerg } 20721826Sjoerg 20821826Sjoerg printf(PDQ_OS_PREFIX "FDDI Port%s = %c (PMD = %s)", 20921826Sjoerg PDQ_OS_PREFIX_ARGS, 21021826Sjoerg rsp->status_chars_get.station_type == PDQ_STATION_TYPE_DAS ? "[A]" : "", 21121826Sjoerg pdq_phy_types[rsp->status_chars_get.phy_type[0]], 21221826Sjoerg pdq_pmd_types[rsp->status_chars_get.pmd_type[0] / 100][rsp->status_chars_get.pmd_type[0] % 100]); 21321826Sjoerg 21421826Sjoerg if (rsp->status_chars_get.station_type == PDQ_STATION_TYPE_DAS) 21521826Sjoerg printf(", FDDI Port[B] = %c (PMD = %s)", 21621826Sjoerg pdq_phy_types[rsp->status_chars_get.phy_type[1]], 21721826Sjoerg pdq_pmd_types[rsp->status_chars_get.pmd_type[1] / 100][rsp->status_chars_get.pmd_type[1] % 100]); 21821826Sjoerg 21921826Sjoerg printf("\n"); 22093383Smdodd 22193383Smdodd pdq_os_update_status(pdq, rsp); 22221826Sjoerg} 22321826Sjoerg 22421826Sjoergstatic void 22521826Sjoergpdq_init_csrs( 22621826Sjoerg pdq_csrs_t *csrs, 22721826Sjoerg pdq_bus_t bus, 22821826Sjoerg pdq_bus_memaddr_t csr_base, 22921826Sjoerg size_t csrsize) 23021826Sjoerg{ 23121826Sjoerg csrs->csr_bus = bus; 23221826Sjoerg csrs->csr_base = csr_base; 23321826Sjoerg csrs->csr_port_reset = PDQ_CSR_OFFSET(csr_base, 0 * csrsize); 23421826Sjoerg csrs->csr_host_data = PDQ_CSR_OFFSET(csr_base, 1 * csrsize); 23521826Sjoerg csrs->csr_port_control = PDQ_CSR_OFFSET(csr_base, 2 * csrsize); 23621826Sjoerg csrs->csr_port_data_a = PDQ_CSR_OFFSET(csr_base, 3 * csrsize); 23721826Sjoerg csrs->csr_port_data_b = PDQ_CSR_OFFSET(csr_base, 4 * csrsize); 23821826Sjoerg csrs->csr_port_status = PDQ_CSR_OFFSET(csr_base, 5 * csrsize); 23921826Sjoerg csrs->csr_host_int_type_0 = PDQ_CSR_OFFSET(csr_base, 6 * csrsize); 24021826Sjoerg csrs->csr_host_int_enable = PDQ_CSR_OFFSET(csr_base, 7 * csrsize); 24121826Sjoerg csrs->csr_type_2_producer = PDQ_CSR_OFFSET(csr_base, 8 * csrsize); 24221826Sjoerg csrs->csr_cmd_response_producer = PDQ_CSR_OFFSET(csr_base, 10 * csrsize); 24321826Sjoerg csrs->csr_cmd_request_producer = PDQ_CSR_OFFSET(csr_base, 11 * csrsize); 24421826Sjoerg csrs->csr_host_smt_producer = PDQ_CSR_OFFSET(csr_base, 12 * csrsize); 24521826Sjoerg csrs->csr_unsolicited_producer = PDQ_CSR_OFFSET(csr_base, 13 * csrsize); 24621826Sjoerg} 24721826Sjoerg 24821826Sjoergstatic void 24921826Sjoergpdq_init_pci_csrs( 25021826Sjoerg pdq_pci_csrs_t *csrs, 25121826Sjoerg pdq_bus_t bus, 25221826Sjoerg pdq_bus_memaddr_t csr_base, 25321826Sjoerg size_t csrsize) 25421826Sjoerg{ 25521826Sjoerg csrs->csr_bus = bus; 25621826Sjoerg csrs->csr_base = csr_base; 25721826Sjoerg csrs->csr_pfi_mode_control = PDQ_CSR_OFFSET(csr_base, 16 * csrsize); 25821826Sjoerg csrs->csr_pfi_status = PDQ_CSR_OFFSET(csr_base, 17 * csrsize); 25921826Sjoerg csrs->csr_fifo_write = PDQ_CSR_OFFSET(csr_base, 18 * csrsize); 26021826Sjoerg csrs->csr_fifo_read = PDQ_CSR_OFFSET(csr_base, 19 * csrsize); 26121826Sjoerg} 26221826Sjoerg 26321826Sjoergstatic void 26421826Sjoergpdq_flush_databuf_queue( 26593383Smdodd pdq_t *pdq, 26621826Sjoerg pdq_databuf_queue_t *q) 26721826Sjoerg{ 26821826Sjoerg PDQ_OS_DATABUF_T *pdu; 26921826Sjoerg for (;;) { 27021826Sjoerg PDQ_OS_DATABUF_DEQUEUE(q, pdu); 27121826Sjoerg if (pdu == NULL) 27221826Sjoerg return; 27393383Smdodd PDQ_OS_DATABUF_FREE(pdq, pdu); 27421826Sjoerg } 27521826Sjoerg} 27621826Sjoerg 27721826Sjoergstatic pdq_boolean_t 27821826Sjoergpdq_do_port_control( 27921826Sjoerg const pdq_csrs_t * const csrs, 28021826Sjoerg pdq_uint32_t cmd) 28121826Sjoerg{ 28221826Sjoerg int cnt = 0; 28321826Sjoerg PDQ_CSR_WRITE(csrs, csr_host_int_type_0, PDQ_HOST_INT_CSR_CMD_DONE); 28421826Sjoerg PDQ_CSR_WRITE(csrs, csr_port_control, PDQ_PCTL_CMD_ERROR | cmd); 28521826Sjoerg while ((PDQ_CSR_READ(csrs, csr_host_int_type_0) & PDQ_HOST_INT_CSR_CMD_DONE) == 0 && cnt < 33000000) 28621826Sjoerg cnt++; 28721826Sjoerg PDQ_PRINTF(("CSR cmd spun %d times\n", cnt)); 28821826Sjoerg if (PDQ_CSR_READ(csrs, csr_host_int_type_0) & PDQ_HOST_INT_CSR_CMD_DONE) { 28921826Sjoerg PDQ_CSR_WRITE(csrs, csr_host_int_type_0, PDQ_HOST_INT_CSR_CMD_DONE); 29021826Sjoerg return (PDQ_CSR_READ(csrs, csr_port_control) & PDQ_PCTL_CMD_ERROR) ? PDQ_FALSE : PDQ_TRUE; 29121826Sjoerg } 29221826Sjoerg /* adapter failure */ 29321826Sjoerg PDQ_ASSERT(0); 29421826Sjoerg return PDQ_FALSE; 29521826Sjoerg} 29621826Sjoerg 29721826Sjoergstatic void 29821826Sjoergpdq_read_mla( 29921826Sjoerg const pdq_csrs_t * const csrs, 30021826Sjoerg pdq_lanaddr_t *hwaddr) 30121826Sjoerg{ 30221826Sjoerg pdq_uint32_t data; 30321826Sjoerg 30421826Sjoerg PDQ_CSR_WRITE(csrs, csr_port_data_a, 0); 30521826Sjoerg pdq_do_port_control(csrs, PDQ_PCTL_MLA_READ); 30621826Sjoerg data = PDQ_CSR_READ(csrs, csr_host_data); 30721826Sjoerg 30821826Sjoerg hwaddr->lanaddr_bytes[0] = (data >> 0) & 0xFF; 30921826Sjoerg hwaddr->lanaddr_bytes[1] = (data >> 8) & 0xFF; 31021826Sjoerg hwaddr->lanaddr_bytes[2] = (data >> 16) & 0xFF; 31121826Sjoerg hwaddr->lanaddr_bytes[3] = (data >> 24) & 0xFF; 31221826Sjoerg 31321826Sjoerg PDQ_CSR_WRITE(csrs, csr_port_data_a, 1); 31421826Sjoerg pdq_do_port_control(csrs, PDQ_PCTL_MLA_READ); 31521826Sjoerg data = PDQ_CSR_READ(csrs, csr_host_data); 31621826Sjoerg 31721826Sjoerg hwaddr->lanaddr_bytes[4] = (data >> 0) & 0xFF; 31821826Sjoerg hwaddr->lanaddr_bytes[5] = (data >> 8) & 0xFF; 31921826Sjoerg} 32021826Sjoerg 32121826Sjoergstatic void 32221826Sjoergpdq_read_fwrev( 32321826Sjoerg const pdq_csrs_t * const csrs, 32421826Sjoerg pdq_fwrev_t *fwrev) 32521826Sjoerg{ 32621826Sjoerg pdq_uint32_t data; 32721826Sjoerg 32821826Sjoerg pdq_do_port_control(csrs, PDQ_PCTL_FW_REV_READ); 32921826Sjoerg data = PDQ_CSR_READ(csrs, csr_host_data); 33021826Sjoerg 33121826Sjoerg fwrev->fwrev_bytes[3] = (data >> 0) & 0xFF; 33221826Sjoerg fwrev->fwrev_bytes[2] = (data >> 8) & 0xFF; 33321826Sjoerg fwrev->fwrev_bytes[1] = (data >> 16) & 0xFF; 33421826Sjoerg fwrev->fwrev_bytes[0] = (data >> 24) & 0xFF; 33521826Sjoerg} 33621826Sjoerg 33721826Sjoergstatic pdq_boolean_t 33821826Sjoergpdq_read_error_log( 33921826Sjoerg pdq_t *pdq, 34021826Sjoerg pdq_response_error_log_get_t *log_entry) 34121826Sjoerg{ 34221826Sjoerg const pdq_csrs_t * const csrs = &pdq->pdq_csrs; 34321826Sjoerg pdq_uint32_t *ptr = (pdq_uint32_t *) log_entry; 34421826Sjoerg 34521826Sjoerg pdq_do_port_control(csrs, PDQ_PCTL_ERROR_LOG_START); 34621826Sjoerg 34721826Sjoerg while (pdq_do_port_control(csrs, PDQ_PCTL_FW_REV_READ) == PDQ_TRUE) { 34821826Sjoerg *ptr++ = PDQ_CSR_READ(csrs, csr_host_data); 34921826Sjoerg if ((pdq_uint8_t *) ptr - (pdq_uint8_t *) log_entry == sizeof(*log_entry)) 35021826Sjoerg break; 35121826Sjoerg } 35221826Sjoerg return (ptr == (pdq_uint32_t *) log_entry) ? PDQ_FALSE : PDQ_TRUE; 35321826Sjoerg} 35421826Sjoerg 35521826Sjoergstatic pdq_chip_rev_t 35621826Sjoergpdq_read_chiprev( 35721826Sjoerg const pdq_csrs_t * const csrs) 35821826Sjoerg{ 35921826Sjoerg pdq_uint32_t data; 36021826Sjoerg 36121826Sjoerg PDQ_CSR_WRITE(csrs, csr_port_data_a, PDQ_SUB_CMD_PDQ_REV_GET); 36221826Sjoerg pdq_do_port_control(csrs, PDQ_PCTL_SUB_CMD); 36321826Sjoerg data = PDQ_CSR_READ(csrs, csr_host_data); 36421826Sjoerg 36521826Sjoerg return (pdq_chip_rev_t) data; 36621826Sjoerg} 36721826Sjoerg 36821826Sjoergstatic const struct { 36921826Sjoerg size_t cmd_len; 37021826Sjoerg size_t rsp_len; 37121826Sjoerg const char *cmd_name; 37221826Sjoerg} pdq_cmd_info[] = { 37321826Sjoerg { sizeof(pdq_cmd_generic_t), /* 0 - PDQC_START */ 37421826Sjoerg sizeof(pdq_response_generic_t), 37521826Sjoerg "Start" 37621826Sjoerg }, 37721826Sjoerg { sizeof(pdq_cmd_filter_set_t), /* 1 - PDQC_FILTER_SET */ 37821826Sjoerg sizeof(pdq_response_generic_t), 37921826Sjoerg "Filter Set" 38021826Sjoerg }, 38121826Sjoerg { sizeof(pdq_cmd_generic_t), /* 2 - PDQC_FILTER_GET */ 38221826Sjoerg sizeof(pdq_response_filter_get_t), 38321826Sjoerg "Filter Get" 38421826Sjoerg }, 38521826Sjoerg { sizeof(pdq_cmd_chars_set_t), /* 3 - PDQC_CHARS_SET */ 38621826Sjoerg sizeof(pdq_response_generic_t), 38721826Sjoerg "Chars Set" 38821826Sjoerg }, 38921826Sjoerg { sizeof(pdq_cmd_generic_t), /* 4 - PDQC_STATUS_CHARS_GET */ 39021826Sjoerg sizeof(pdq_response_status_chars_get_t), 39121826Sjoerg "Status Chars Get" 39221826Sjoerg }, 39321826Sjoerg#if 0 39421826Sjoerg { sizeof(pdq_cmd_generic_t), /* 5 - PDQC_COUNTERS_GET */ 39521826Sjoerg sizeof(pdq_response_counters_get_t), 39621826Sjoerg "Counters Get" 39721826Sjoerg }, 39821826Sjoerg { sizeof(pdq_cmd_counters_set_t), /* 6 - PDQC_COUNTERS_SET */ 39921826Sjoerg sizeof(pdq_response_generic_t), 40021826Sjoerg "Counters Set" 40121826Sjoerg }, 40221826Sjoerg#else 40321826Sjoerg { 0, 0, "Counters Get" }, 40421826Sjoerg { 0, 0, "Counters Set" }, 40521826Sjoerg#endif 40621826Sjoerg { sizeof(pdq_cmd_addr_filter_set_t), /* 7 - PDQC_ADDR_FILTER_SET */ 40721826Sjoerg sizeof(pdq_response_generic_t), 40821826Sjoerg "Addr Filter Set" 40921826Sjoerg }, 41021826Sjoerg { sizeof(pdq_cmd_generic_t), /* 8 - PDQC_ADDR_FILTER_GET */ 41121826Sjoerg sizeof(pdq_response_addr_filter_get_t), 41221826Sjoerg "Addr Filter Get" 41321826Sjoerg }, 41421826Sjoerg { sizeof(pdq_cmd_generic_t), /* 9 - PDQC_ERROR_LOG_CLEAR */ 41521826Sjoerg sizeof(pdq_response_generic_t), 41621826Sjoerg "Error Log Clear" 41721826Sjoerg }, 41821826Sjoerg { sizeof(pdq_cmd_generic_t), /* 10 - PDQC_ERROR_LOG_SET */ 41921826Sjoerg sizeof(pdq_response_generic_t), 42021826Sjoerg "Error Log Set" 42121826Sjoerg }, 42221826Sjoerg { sizeof(pdq_cmd_generic_t), /* 11 - PDQC_FDDI_MIB_GET */ 42321826Sjoerg sizeof(pdq_response_generic_t), 42421826Sjoerg "FDDI MIB Get" 42521826Sjoerg }, 42621826Sjoerg { sizeof(pdq_cmd_generic_t), /* 12 - PDQC_DEC_EXT_MIB_GET */ 42721826Sjoerg sizeof(pdq_response_generic_t), 42821826Sjoerg "DEC Ext MIB Get" 42921826Sjoerg }, 43021826Sjoerg { sizeof(pdq_cmd_generic_t), /* 13 - PDQC_DEC_SPECIFIC_GET */ 43121826Sjoerg sizeof(pdq_response_generic_t), 43221826Sjoerg "DEC Specific Get" 43321826Sjoerg }, 43421826Sjoerg { sizeof(pdq_cmd_generic_t), /* 14 - PDQC_SNMP_SET */ 43521826Sjoerg sizeof(pdq_response_generic_t), 43621826Sjoerg "SNMP Set" 43721826Sjoerg }, 43821826Sjoerg { 0, 0, "N/A" }, 43921826Sjoerg { sizeof(pdq_cmd_generic_t), /* 16 - PDQC_SMT_MIB_GET */ 44021826Sjoerg sizeof(pdq_response_generic_t), 44121826Sjoerg "SMT MIB Get" 44221826Sjoerg }, 44321826Sjoerg { sizeof(pdq_cmd_generic_t), /* 17 - PDQC_SMT_MIB_SET */ 44421826Sjoerg sizeof(pdq_response_generic_t), 44521826Sjoerg "SMT MIB Set", 44621826Sjoerg }, 44793383Smdodd { 0, 0, "Bogus CMD" }, 44821826Sjoerg}; 44921826Sjoerg 45021826Sjoergstatic void 45121826Sjoergpdq_queue_commands( 45221826Sjoerg pdq_t *pdq) 45321826Sjoerg{ 45421826Sjoerg const pdq_csrs_t * const csrs = &pdq->pdq_csrs; 45521826Sjoerg pdq_command_info_t * const ci = &pdq->pdq_command_info; 45621826Sjoerg pdq_descriptor_block_t * const dbp = pdq->pdq_dbp; 45793383Smdodd pdq_txdesc_t * const txd = &dbp->pdqdb_command_requests[ci->ci_request_producer]; 45821826Sjoerg pdq_cmd_code_t op; 45921826Sjoerg pdq_uint32_t cmdlen, rsplen, mask; 46021826Sjoerg 46121826Sjoerg /* 46221826Sjoerg * If there are commands or responses active or there aren't 46321826Sjoerg * any pending commands, then don't queue any more. 46421826Sjoerg */ 46521826Sjoerg if (ci->ci_command_active || ci->ci_pending_commands == 0) 46621826Sjoerg return; 46721826Sjoerg 46821826Sjoerg /* 46921826Sjoerg * Determine which command needs to be queued. 47021826Sjoerg */ 47121826Sjoerg op = PDQC_SMT_MIB_SET; 47221826Sjoerg for (mask = 1 << ((int) op); (mask & ci->ci_pending_commands) == 0; mask >>= 1) 47321826Sjoerg op = (pdq_cmd_code_t) ((int) op - 1); 47421826Sjoerg /* 47521826Sjoerg * Obtain the sizes needed for the command and response. 47621826Sjoerg * Round up to PDQ_CMD_RX_ALIGNMENT so the receive buffer is 47721826Sjoerg * always properly aligned. 47821826Sjoerg */ 47921826Sjoerg cmdlen = PDQ_ROUNDUP(pdq_cmd_info[op].cmd_len, PDQ_CMD_RX_ALIGNMENT); 48021826Sjoerg rsplen = PDQ_ROUNDUP(pdq_cmd_info[op].rsp_len, PDQ_CMD_RX_ALIGNMENT); 48121826Sjoerg if (cmdlen < rsplen) 48221826Sjoerg cmdlen = rsplen; 48321826Sjoerg /* 48421826Sjoerg * Since only one command at a time will be queued, there will always 48521826Sjoerg * be enough space. 48621826Sjoerg */ 48721826Sjoerg 48821826Sjoerg /* 48921826Sjoerg * Obtain and fill in the descriptor for the command (descriptor is 49021826Sjoerg * pre-initialized) 49121826Sjoerg */ 49293383Smdodd txd->txd_seg_len = cmdlen; 49321826Sjoerg 49421826Sjoerg /* 49521826Sjoerg * Clear the command area, set the opcode, and the command from the pending 49621826Sjoerg * mask. 49721826Sjoerg */ 49821826Sjoerg 49993383Smdodd ci->ci_queued_commands[ci->ci_request_producer] = op; 50093383Smdodd#if defined(PDQVERBOSE) 50193383Smdodd ((pdq_response_generic_t *) ci->ci_response_bufstart)->generic_op = PDQC_BOGUS_CMD; 50293383Smdodd#endif 50393383Smdodd PDQ_OS_MEMZERO(ci->ci_request_bufstart, cmdlen); 50493383Smdodd *(pdq_cmd_code_t *) ci->ci_request_bufstart = op; 50521826Sjoerg ci->ci_pending_commands &= ~mask; 50621826Sjoerg 50721826Sjoerg /* 50821826Sjoerg * Fill in the command area, if needed. 50921826Sjoerg */ 51021826Sjoerg switch (op) { 51121826Sjoerg case PDQC_FILTER_SET: { 51293383Smdodd pdq_cmd_filter_set_t *filter_set = (pdq_cmd_filter_set_t *) ci->ci_request_bufstart; 51321826Sjoerg unsigned idx = 0; 51421826Sjoerg filter_set->filter_set_items[idx].item_code = PDQI_IND_GROUP_PROM; 51521826Sjoerg filter_set->filter_set_items[idx].filter_state = (pdq->pdq_flags & PDQ_PROMISC ? PDQ_FILTER_PASS : PDQ_FILTER_BLOCK); 51621826Sjoerg idx++; 51721826Sjoerg filter_set->filter_set_items[idx].item_code = PDQI_GROUP_PROM; 51821826Sjoerg filter_set->filter_set_items[idx].filter_state = (pdq->pdq_flags & PDQ_ALLMULTI ? PDQ_FILTER_PASS : PDQ_FILTER_BLOCK); 51921826Sjoerg idx++; 52021826Sjoerg filter_set->filter_set_items[idx].item_code = PDQI_SMT_PROM; 52121826Sjoerg 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); 52221826Sjoerg idx++; 52321826Sjoerg filter_set->filter_set_items[idx].item_code = PDQI_SMT_USER; 52421826Sjoerg filter_set->filter_set_items[idx].filter_state = (pdq->pdq_flags & PDQ_PASS_SMT ? PDQ_FILTER_PASS : PDQ_FILTER_BLOCK); 52521826Sjoerg idx++; 52621826Sjoerg filter_set->filter_set_items[idx].item_code = PDQI_EOL; 52721826Sjoerg break; 52821826Sjoerg } 52921826Sjoerg case PDQC_ADDR_FILTER_SET: { 53093383Smdodd pdq_cmd_addr_filter_set_t *addr_filter_set = (pdq_cmd_addr_filter_set_t *) ci->ci_request_bufstart; 53121826Sjoerg pdq_lanaddr_t *addr = addr_filter_set->addr_filter_set_addresses; 53221826Sjoerg addr->lanaddr_bytes[0] = 0xFF; 53321826Sjoerg addr->lanaddr_bytes[1] = 0xFF; 53421826Sjoerg addr->lanaddr_bytes[2] = 0xFF; 53521826Sjoerg addr->lanaddr_bytes[3] = 0xFF; 53621826Sjoerg addr->lanaddr_bytes[4] = 0xFF; 53721826Sjoerg addr->lanaddr_bytes[5] = 0xFF; 53821826Sjoerg addr++; 53921826Sjoerg pdq_os_addr_fill(pdq, addr, 61); 54021826Sjoerg break; 54121826Sjoerg } 54293383Smdodd case PDQC_SNMP_SET: { 54393383Smdodd pdq_cmd_snmp_set_t *snmp_set = (pdq_cmd_snmp_set_t *) ci->ci_request_bufstart; 54493383Smdodd unsigned idx = 0; 54593383Smdodd snmp_set->snmp_set_items[idx].item_code = PDQSNMP_FULL_DUPLEX_ENABLE; 54693383Smdodd snmp_set->snmp_set_items[idx].item_value = (pdq->pdq_flags & PDQ_WANT_FDX ? 1 : 2); 54793383Smdodd snmp_set->snmp_set_items[idx].item_port = 0; 54893383Smdodd idx++; 54993383Smdodd snmp_set->snmp_set_items[idx].item_code = PDQSNMP_EOL; 55093383Smdodd break; 55193383Smdodd } 55221826Sjoerg default: { /* to make gcc happy */ 55321826Sjoerg break; 55421826Sjoerg } 55521826Sjoerg } 55693383Smdodd 55793383Smdodd 55821826Sjoerg /* 55993383Smdodd * Sync the command request buffer and descriptor, then advance 56093383Smdodd * the request producer index. 56193383Smdodd */ 56293383Smdodd PDQ_OS_CMDRQST_PRESYNC(pdq, txd->txd_seg_len); 56393383Smdodd PDQ_OS_DESC_PRESYNC(pdq, txd, sizeof(pdq_txdesc_t)); 56493383Smdodd PDQ_ADVANCE(ci->ci_request_producer, 1, PDQ_RING_MASK(dbp->pdqdb_command_requests)); 56593383Smdodd 56693383Smdodd /* 56793383Smdodd * Sync the command response buffer and advance the response 56893383Smdodd * producer index (descriptor is already pre-initialized) 56993383Smdodd */ 57093383Smdodd PDQ_OS_CMDRSP_PRESYNC(pdq, PDQ_SIZE_COMMAND_RESPONSE); 57193383Smdodd PDQ_ADVANCE(ci->ci_response_producer, 1, PDQ_RING_MASK(dbp->pdqdb_command_responses)); 57293383Smdodd /* 57321826Sjoerg * At this point the command is done. All that needs to be done is to 57421826Sjoerg * produce it to the PDQ. 57521826Sjoerg */ 57621826Sjoerg PDQ_PRINTF(("PDQ Queue Command Request: %s queued\n", 57721826Sjoerg pdq_cmd_info[op].cmd_name)); 57821826Sjoerg 57921826Sjoerg ci->ci_command_active++; 58021826Sjoerg PDQ_CSR_WRITE(csrs, csr_cmd_response_producer, ci->ci_response_producer | (ci->ci_response_completion << 8)); 58121826Sjoerg PDQ_CSR_WRITE(csrs, csr_cmd_request_producer, ci->ci_request_producer | (ci->ci_request_completion << 8)); 58221826Sjoerg} 58321826Sjoerg 58421826Sjoergstatic void 58521826Sjoergpdq_process_command_responses( 58621826Sjoerg pdq_t * const pdq) 58721826Sjoerg{ 58821826Sjoerg const pdq_csrs_t * const csrs = &pdq->pdq_csrs; 58921826Sjoerg pdq_command_info_t * const ci = &pdq->pdq_command_info; 59021826Sjoerg volatile const pdq_consumer_block_t * const cbp = pdq->pdq_cbp; 59121826Sjoerg pdq_descriptor_block_t * const dbp = pdq->pdq_dbp; 59221826Sjoerg const pdq_response_generic_t *rspgen; 59321826Sjoerg 59421826Sjoerg /* 59521826Sjoerg * We have to process the command and response in tandem so 59621826Sjoerg * just wait for the response to be consumed. If it has been 59721826Sjoerg * consumed then the command must have been as well. 59821826Sjoerg */ 59921826Sjoerg 60021826Sjoerg if (cbp->pdqcb_command_response == ci->ci_response_completion) 60121826Sjoerg return; 60221826Sjoerg 60321826Sjoerg PDQ_ASSERT(cbp->pdqcb_command_request != ci->ci_request_completion); 60421826Sjoerg 60593383Smdodd PDQ_OS_CMDRSP_POSTSYNC(pdq, PDQ_SIZE_COMMAND_RESPONSE); 60693383Smdodd rspgen = (const pdq_response_generic_t *) ci->ci_response_bufstart; 60793383Smdodd PDQ_ASSERT(rspgen->generic_op == ci->ci_queued_commands[ci->ci_request_completion]); 60821826Sjoerg PDQ_ASSERT(rspgen->generic_status == PDQR_SUCCESS); 60993383Smdodd PDQ_PRINTF(("PDQ Process Command Response: %s completed (status=%d [0x%x])\n", 61021826Sjoerg pdq_cmd_info[rspgen->generic_op].cmd_name, 61193383Smdodd rspgen->generic_status, rspgen->generic_status)); 61221826Sjoerg 61321826Sjoerg if (rspgen->generic_op == PDQC_STATUS_CHARS_GET && (pdq->pdq_flags & PDQ_PRINTCHARS)) { 61421826Sjoerg pdq->pdq_flags &= ~PDQ_PRINTCHARS; 61521826Sjoerg pdq_print_fddi_chars(pdq, (const pdq_response_status_chars_get_t *) rspgen); 61693383Smdodd } else if (rspgen->generic_op == PDQC_DEC_EXT_MIB_GET) { 61793383Smdodd pdq->pdq_flags &= ~PDQ_IS_FDX; 61893383Smdodd if (((const pdq_response_dec_ext_mib_get_t *)rspgen)->dec_ext_mib_get.fdx_operational) 61993383Smdodd pdq->pdq_flags |= PDQ_IS_FDX; 62021826Sjoerg } 62121826Sjoerg 62221826Sjoerg PDQ_ADVANCE(ci->ci_request_completion, 1, PDQ_RING_MASK(dbp->pdqdb_command_requests)); 62321826Sjoerg PDQ_ADVANCE(ci->ci_response_completion, 1, PDQ_RING_MASK(dbp->pdqdb_command_responses)); 62421826Sjoerg ci->ci_command_active = 0; 62521826Sjoerg 62621826Sjoerg if (ci->ci_pending_commands != 0) { 62721826Sjoerg pdq_queue_commands(pdq); 62821826Sjoerg } else { 62921826Sjoerg PDQ_CSR_WRITE(csrs, csr_cmd_response_producer, 63021826Sjoerg ci->ci_response_producer | (ci->ci_response_completion << 8)); 63121826Sjoerg PDQ_CSR_WRITE(csrs, csr_cmd_request_producer, 63221826Sjoerg ci->ci_request_producer | (ci->ci_request_completion << 8)); 63321826Sjoerg } 63421826Sjoerg} 63521826Sjoerg 63621826Sjoerg/* 63721826Sjoerg * This following routine processes unsolicited events. 63821826Sjoerg * In addition, it also fills the unsolicited queue with 63921826Sjoerg * event buffers so it can be used to initialize the queue 64021826Sjoerg * as well. 64121826Sjoerg */ 64221826Sjoergstatic void 64321826Sjoergpdq_process_unsolicited_events( 64421826Sjoerg pdq_t *pdq) 64521826Sjoerg{ 64621826Sjoerg const pdq_csrs_t * const csrs = &pdq->pdq_csrs; 64721826Sjoerg pdq_unsolicited_info_t *ui = &pdq->pdq_unsolicited_info; 64821826Sjoerg volatile const pdq_consumer_block_t *cbp = pdq->pdq_cbp; 64921826Sjoerg pdq_descriptor_block_t *dbp = pdq->pdq_dbp; 65021826Sjoerg 65121826Sjoerg /* 65221826Sjoerg * Process each unsolicited event (if any). 65321826Sjoerg */ 65421826Sjoerg 65521826Sjoerg while (cbp->pdqcb_unsolicited_event != ui->ui_completion) { 65693383Smdodd const pdq_unsolicited_event_t *event; 65721826Sjoerg event = &ui->ui_events[ui->ui_completion & (PDQ_NUM_UNSOLICITED_EVENTS-1)]; 65893383Smdodd PDQ_OS_UNSOL_EVENT_POSTSYNC(pdq, event); 65921826Sjoerg 66021826Sjoerg switch (event->event_type) { 66121826Sjoerg case PDQ_UNSOLICITED_EVENT: { 66293383Smdodd int bad_event = 0; 66393383Smdodd switch (event->event_entity) { 66493383Smdodd case PDQ_ENTITY_STATION: { 66593383Smdodd bad_event = event->event_code.value >= PDQ_STATION_EVENT_MAX; 66693383Smdodd break; 66793383Smdodd } 66893383Smdodd case PDQ_ENTITY_LINK: { 66993383Smdodd bad_event = event->event_code.value >= PDQ_LINK_EVENT_MAX; 67093383Smdodd break; 67193383Smdodd } 67293383Smdodd case PDQ_ENTITY_PHY_PORT: { 67393383Smdodd bad_event = event->event_code.value >= PDQ_PHY_EVENT_MAX; 67493383Smdodd break; 67593383Smdodd } 67693383Smdodd default: { 67793383Smdodd bad_event = 1; 67893383Smdodd break; 67993383Smdodd } 68093383Smdodd } 68193383Smdodd if (bad_event) { 68293383Smdodd break; 68393383Smdodd } 68421826Sjoerg printf(PDQ_OS_PREFIX "Unsolicited Event: %s: %s", 68521826Sjoerg PDQ_OS_PREFIX_ARGS, 68621826Sjoerg pdq_entities[event->event_entity], 68721826Sjoerg pdq_event_codes[event->event_entity][event->event_code.value]); 68821826Sjoerg if (event->event_entity == PDQ_ENTITY_PHY_PORT) 68921826Sjoerg printf("[%d]", event->event_index); 69021826Sjoerg printf("\n"); 69121826Sjoerg break; 69221826Sjoerg } 69321826Sjoerg case PDQ_UNSOLICITED_COUNTERS: { 69421826Sjoerg break; 69521826Sjoerg } 69621826Sjoerg } 69793383Smdodd PDQ_OS_UNSOL_EVENT_PRESYNC(pdq, event); 69821826Sjoerg PDQ_ADVANCE(ui->ui_completion, 1, PDQ_RING_MASK(dbp->pdqdb_unsolicited_events)); 69921826Sjoerg ui->ui_free++; 70021826Sjoerg } 70121826Sjoerg 70221826Sjoerg /* 70321826Sjoerg * Now give back the event buffers back to the PDQ. 70421826Sjoerg */ 70521826Sjoerg PDQ_ADVANCE(ui->ui_producer, ui->ui_free, PDQ_RING_MASK(dbp->pdqdb_unsolicited_events)); 70621826Sjoerg ui->ui_free = 0; 70721826Sjoerg 70821826Sjoerg PDQ_CSR_WRITE(csrs, csr_unsolicited_producer, 70921826Sjoerg ui->ui_producer | (ui->ui_completion << 8)); 71021826Sjoerg} 71121826Sjoerg 71221826Sjoergstatic void 71321826Sjoergpdq_process_received_data( 71421826Sjoerg pdq_t *pdq, 71521826Sjoerg pdq_rx_info_t *rx, 71621826Sjoerg pdq_rxdesc_t *receives, 71721826Sjoerg pdq_uint32_t completion_goal, 71821826Sjoerg pdq_uint32_t ring_mask) 71921826Sjoerg{ 72021826Sjoerg pdq_uint32_t completion = rx->rx_completion; 72121826Sjoerg pdq_uint32_t producer = rx->rx_producer; 72221826Sjoerg PDQ_OS_DATABUF_T **buffers = (PDQ_OS_DATABUF_T **) rx->rx_buffers; 72321826Sjoerg pdq_rxdesc_t *rxd; 72421826Sjoerg pdq_uint32_t idx; 72521826Sjoerg 72621826Sjoerg while (completion != completion_goal) { 72721826Sjoerg PDQ_OS_DATABUF_T *fpdu, *lpdu, *npdu; 72821826Sjoerg pdq_uint8_t *dataptr; 72921826Sjoerg pdq_uint32_t fc, datalen, pdulen, segcnt; 73021826Sjoerg pdq_rxstatus_t status; 73121826Sjoerg 73221826Sjoerg fpdu = lpdu = buffers[completion]; 73321826Sjoerg PDQ_ASSERT(fpdu != NULL); 73493383Smdodd PDQ_OS_RXPDU_POSTSYNC(pdq, fpdu, 0, sizeof(u_int32_t)); 73521826Sjoerg dataptr = PDQ_OS_DATABUF_PTR(fpdu); 73621826Sjoerg status = *(pdq_rxstatus_t *) dataptr; 73793383Smdodd if (status.rxs_rcc_badpdu == 0) { 73893383Smdodd datalen = status.rxs_len; 73993383Smdodd PDQ_OS_RXPDU_POSTSYNC(pdq, fpdu, sizeof(u_int32_t), 74093383Smdodd PDQ_RX_FC_OFFSET + 1 - sizeof(u_int32_t)); 74121826Sjoerg fc = dataptr[PDQ_RX_FC_OFFSET]; 74221826Sjoerg switch (fc & (PDQ_FDDIFC_C|PDQ_FDDIFC_L|PDQ_FDDIFC_F)) { 74321826Sjoerg case PDQ_FDDI_LLC_ASYNC: 74421826Sjoerg case PDQ_FDDI_LLC_SYNC: 74521826Sjoerg case PDQ_FDDI_IMP_ASYNC: 74621826Sjoerg case PDQ_FDDI_IMP_SYNC: { 74721826Sjoerg if (datalen > PDQ_FDDI_MAX || datalen < PDQ_FDDI_LLC_MIN) { 74821826Sjoerg PDQ_PRINTF(("discard: bad length %d\n", datalen)); 74921826Sjoerg goto discard_frame; 75021826Sjoerg } 75121826Sjoerg break; 75221826Sjoerg } 75321826Sjoerg case PDQ_FDDI_SMT: { 75421826Sjoerg if (datalen > PDQ_FDDI_MAX || datalen < PDQ_FDDI_SMT_MIN) 75521826Sjoerg goto discard_frame; 75621826Sjoerg break; 75721826Sjoerg } 75821826Sjoerg default: { 75921826Sjoerg PDQ_PRINTF(("discard: bad fc 0x%x\n", fc)); 76021826Sjoerg goto discard_frame; 76121826Sjoerg } 76221826Sjoerg } 76321826Sjoerg /* 76421826Sjoerg * Update the lengths of the data buffers now that we know 76521826Sjoerg * the real length. 76621826Sjoerg */ 76793383Smdodd pdulen = datalen + (PDQ_RX_FC_OFFSET - PDQ_OS_HDR_OFFSET) - 4 /* CRC */; 76893383Smdodd segcnt = (pdulen + PDQ_OS_HDR_OFFSET + PDQ_OS_DATABUF_SIZE - 1) / PDQ_OS_DATABUF_SIZE; 76993383Smdodd PDQ_OS_DATABUF_ALLOC(pdq, npdu); 77021826Sjoerg if (npdu == NULL) { 77121826Sjoerg PDQ_PRINTF(("discard: no databuf #0\n")); 77221826Sjoerg goto discard_frame; 77321826Sjoerg } 77421826Sjoerg buffers[completion] = npdu; 77521826Sjoerg for (idx = 1; idx < segcnt; idx++) { 77693383Smdodd PDQ_OS_DATABUF_ALLOC(pdq, npdu); 77721826Sjoerg if (npdu == NULL) { 77821826Sjoerg PDQ_OS_DATABUF_NEXT_SET(lpdu, NULL); 77993383Smdodd PDQ_OS_DATABUF_FREE(pdq, fpdu); 78021826Sjoerg goto discard_frame; 78121826Sjoerg } 78221826Sjoerg PDQ_OS_DATABUF_NEXT_SET(lpdu, buffers[(completion + idx) & ring_mask]); 78321826Sjoerg lpdu = PDQ_OS_DATABUF_NEXT(lpdu); 78421826Sjoerg buffers[(completion + idx) & ring_mask] = npdu; 78521826Sjoerg } 78621826Sjoerg PDQ_OS_DATABUF_NEXT_SET(lpdu, NULL); 78721826Sjoerg for (idx = 0; idx < PDQ_RX_SEGCNT; idx++) { 78821826Sjoerg buffers[(producer + idx) & ring_mask] = 78921826Sjoerg buffers[(completion + idx) & ring_mask]; 79021826Sjoerg buffers[(completion + idx) & ring_mask] = NULL; 79121826Sjoerg } 79293383Smdodd PDQ_OS_DATABUF_ADJ(fpdu, PDQ_OS_HDR_OFFSET); 79321826Sjoerg if (segcnt == 1) { 79421826Sjoerg PDQ_OS_DATABUF_LEN_SET(fpdu, pdulen); 79521826Sjoerg } else { 79693383Smdodd PDQ_OS_DATABUF_LEN_SET(lpdu, pdulen + PDQ_OS_HDR_OFFSET - (segcnt - 1) * PDQ_OS_DATABUF_SIZE); 79721826Sjoerg } 79893383Smdodd /* 79993383Smdodd * Do not pass to protocol if packet was received promiscuously 80093383Smdodd */ 80193383Smdodd pdq_os_receive_pdu(pdq, fpdu, pdulen, 80293383Smdodd status.rxs_rcc_dd < PDQ_RXS_RCC_DD_CAM_MATCH); 80321826Sjoerg rx->rx_free += PDQ_RX_SEGCNT; 80421826Sjoerg PDQ_ADVANCE(producer, PDQ_RX_SEGCNT, ring_mask); 80521826Sjoerg PDQ_ADVANCE(completion, PDQ_RX_SEGCNT, ring_mask); 80621826Sjoerg continue; 80721826Sjoerg } else { 80821826Sjoerg PDQ_PRINTF(("discard: bad pdu 0x%x(%d.%d.%d.%d.%d)\n", status.rxs_status, 80921826Sjoerg status.rxs_rcc_badpdu, status.rxs_rcc_badcrc, 81021826Sjoerg status.rxs_rcc_reason, status.rxs_fsc, status.rxs_fsb_e)); 81121826Sjoerg if (status.rxs_rcc_reason == 7) 81221826Sjoerg goto discard_frame; 81346568Speter if (status.rxs_rcc_reason != 0) { 81421826Sjoerg /* hardware fault */ 81593383Smdodd if (status.rxs_rcc_badcrc) { 81693383Smdodd printf(PDQ_OS_PREFIX " MAC CRC error (source=%x-%x-%x-%x-%x-%x)\n", 81793383Smdodd PDQ_OS_PREFIX_ARGS, 81893383Smdodd dataptr[PDQ_RX_FC_OFFSET+1], 81993383Smdodd dataptr[PDQ_RX_FC_OFFSET+2], 82093383Smdodd dataptr[PDQ_RX_FC_OFFSET+3], 82193383Smdodd dataptr[PDQ_RX_FC_OFFSET+4], 82293383Smdodd dataptr[PDQ_RX_FC_OFFSET+5], 82393383Smdodd dataptr[PDQ_RX_FC_OFFSET+6]); 82493383Smdodd /* rx->rx_badcrc++; */ 82593383Smdodd } else if (status.rxs_fsc == 0 || status.rxs_fsb_e == 1) { 82693383Smdodd /* rx->rx_frame_status_errors++; */ 82793383Smdodd } else { 82893383Smdodd /* hardware fault */ 82993383Smdodd } 83046568Speter } 83121826Sjoerg } 83221826Sjoerg discard_frame: 83321826Sjoerg /* 83421826Sjoerg * Discarded frames go right back on the queue; therefore 83521826Sjoerg * ring entries were freed. 83621826Sjoerg */ 83721826Sjoerg for (idx = 0; idx < PDQ_RX_SEGCNT; idx++) { 83821826Sjoerg buffers[producer] = buffers[completion]; 83921826Sjoerg buffers[completion] = NULL; 84021826Sjoerg rxd = &receives[rx->rx_producer]; 84121826Sjoerg if (idx == 0) { 84221826Sjoerg rxd->rxd_sop = 1; rxd->rxd_seg_cnt = PDQ_RX_SEGCNT - 1; 84321826Sjoerg } else { 84421826Sjoerg rxd->rxd_sop = 0; rxd->rxd_seg_cnt = 0; 84521826Sjoerg } 84621826Sjoerg rxd->rxd_pa_hi = 0; 84721826Sjoerg rxd->rxd_seg_len_hi = PDQ_OS_DATABUF_SIZE / 16; 84893383Smdodd rxd->rxd_pa_lo = PDQ_OS_DATABUF_BUSPA(pdq, buffers[rx->rx_producer]); 84993383Smdodd PDQ_OS_RXPDU_PRESYNC(pdq, buffers[rx->rx_producer], 0, PDQ_OS_DATABUF_SIZE); 85093383Smdodd PDQ_OS_DESC_PRESYNC(pdq, rxd, sizeof(*rxd)); 85121826Sjoerg PDQ_ADVANCE(rx->rx_producer, 1, ring_mask); 85221826Sjoerg PDQ_ADVANCE(producer, 1, ring_mask); 85321826Sjoerg PDQ_ADVANCE(completion, 1, ring_mask); 85421826Sjoerg } 85521826Sjoerg } 85621826Sjoerg rx->rx_completion = completion; 85721826Sjoerg 85821826Sjoerg while (rx->rx_free > PDQ_RX_SEGCNT && rx->rx_free > rx->rx_target) { 85921826Sjoerg PDQ_OS_DATABUF_T *pdu; 86021826Sjoerg /* 86121826Sjoerg * Allocate the needed number of data buffers. 86221826Sjoerg * Try to obtain them from our free queue before 86321826Sjoerg * asking the system for more. 86421826Sjoerg */ 86521826Sjoerg for (idx = 0; idx < PDQ_RX_SEGCNT; idx++) { 86621826Sjoerg if ((pdu = buffers[(rx->rx_producer + idx) & ring_mask]) == NULL) { 86793383Smdodd PDQ_OS_DATABUF_ALLOC(pdq, pdu); 86821826Sjoerg if (pdu == NULL) 86921826Sjoerg break; 87021826Sjoerg buffers[(rx->rx_producer + idx) & ring_mask] = pdu; 87121826Sjoerg } 87221826Sjoerg rxd = &receives[(rx->rx_producer + idx) & ring_mask]; 87321826Sjoerg if (idx == 0) { 87421826Sjoerg rxd->rxd_sop = 1; rxd->rxd_seg_cnt = PDQ_RX_SEGCNT - 1; 87521826Sjoerg } else { 87621826Sjoerg rxd->rxd_sop = 0; rxd->rxd_seg_cnt = 0; 87721826Sjoerg } 87821826Sjoerg rxd->rxd_pa_hi = 0; 87921826Sjoerg rxd->rxd_seg_len_hi = PDQ_OS_DATABUF_SIZE / 16; 88093383Smdodd rxd->rxd_pa_lo = PDQ_OS_DATABUF_BUSPA(pdq, pdu); 88193383Smdodd PDQ_OS_RXPDU_PRESYNC(pdq, pdu, 0, PDQ_OS_DATABUF_SIZE); 88293383Smdodd PDQ_OS_DESC_PRESYNC(pdq, rxd, sizeof(*rxd)); 88321826Sjoerg } 88421826Sjoerg if (idx < PDQ_RX_SEGCNT) { 88521826Sjoerg /* 88621826Sjoerg * We didn't get all databufs required to complete a new 88721826Sjoerg * receive buffer. Keep the ones we got and retry a bit 88821826Sjoerg * later for the rest. 88921826Sjoerg */ 89021826Sjoerg break; 89121826Sjoerg } 89221826Sjoerg PDQ_ADVANCE(rx->rx_producer, PDQ_RX_SEGCNT, ring_mask); 89321826Sjoerg rx->rx_free -= PDQ_RX_SEGCNT; 89421826Sjoerg } 89521826Sjoerg} 89621826Sjoerg 89793383Smdoddstatic void pdq_process_transmitted_data(pdq_t *pdq); 89893383Smdodd 89921826Sjoergpdq_boolean_t 90021826Sjoergpdq_queue_transmit_data( 90121826Sjoerg pdq_t *pdq, 90221826Sjoerg PDQ_OS_DATABUF_T *pdu) 90321826Sjoerg{ 90493383Smdodd pdq_tx_info_t * const tx = &pdq->pdq_tx_info; 90593383Smdodd pdq_descriptor_block_t * const dbp = pdq->pdq_dbp; 90621826Sjoerg pdq_uint32_t producer = tx->tx_producer; 90721826Sjoerg pdq_txdesc_t *eop = NULL; 90821826Sjoerg PDQ_OS_DATABUF_T *pdu0; 90921826Sjoerg pdq_uint32_t freecnt; 91093383Smdodd#if defined(PDQ_BUS_DMA) 91193383Smdodd bus_dmamap_t map; 91293383Smdodd#endif 91321826Sjoerg 91493383Smdodd again: 91593383Smdodd if (PDQ_RX_FC_OFFSET == PDQ_OS_HDR_OFFSET) { 91693383Smdodd freecnt = tx->tx_free - 1; 91793383Smdodd } else { 91893383Smdodd freecnt = tx->tx_free; 91993383Smdodd } 92093383Smdodd /* 92193383Smdodd * Need 2 or more descriptors to be able to send. 92293383Smdodd */ 92393383Smdodd if (freecnt == 0) { 92493383Smdodd pdq->pdq_intrmask |= PDQ_HOST_INT_TX_ENABLE; 92593383Smdodd PDQ_CSR_WRITE(&pdq->pdq_csrs, csr_host_int_enable, pdq->pdq_intrmask); 92621826Sjoerg return PDQ_FALSE; 92793383Smdodd } 92821826Sjoerg 92993383Smdodd if (PDQ_RX_FC_OFFSET == PDQ_OS_HDR_OFFSET) { 93093383Smdodd dbp->pdqdb_transmits[producer] = tx->tx_hdrdesc; 93193383Smdodd PDQ_OS_DESC_PRESYNC(pdq, &dbp->pdqdb_transmits[producer], sizeof(pdq_txdesc_t)); 93293383Smdodd PDQ_ADVANCE(producer, 1, PDQ_RING_MASK(dbp->pdqdb_transmits)); 93393383Smdodd } 93421826Sjoerg 93593383Smdodd#if defined(PDQ_BUS_DMA) 93693383Smdodd map = M_GETCTX(pdu, bus_dmamap_t); 93793383Smdodd if (freecnt >= map->dm_nsegs) { 93893383Smdodd int idx; 93993383Smdodd for (idx = 0; idx < map->dm_nsegs; idx++) { 94093383Smdodd /* 94193383Smdodd * Initialize the transmit descriptor 94293383Smdodd */ 94393383Smdodd eop = &dbp->pdqdb_transmits[producer]; 94493383Smdodd eop->txd_seg_len = map->dm_segs[idx].ds_len; 94593383Smdodd eop->txd_pa_lo = map->dm_segs[idx].ds_addr; 94693383Smdodd eop->txd_sop = eop->txd_eop = eop->txd_pa_hi = 0; 94793383Smdodd PDQ_OS_DESC_PRESYNC(pdq, eop, sizeof(pdq_txdesc_t)); 94893383Smdodd freecnt--; 94993383Smdodd PDQ_ADVANCE(producer, 1, PDQ_RING_MASK(dbp->pdqdb_transmits)); 95093383Smdodd } 95193383Smdodd pdu0 = NULL; 95293383Smdodd } else { 95393383Smdodd pdu0 = pdu; 95493383Smdodd } 95593383Smdodd#else 95621826Sjoerg for (freecnt = tx->tx_free - 1, pdu0 = pdu; pdu0 != NULL && freecnt > 0;) { 95721826Sjoerg pdq_uint32_t fraglen, datalen = PDQ_OS_DATABUF_LEN(pdu0); 95821826Sjoerg const pdq_uint8_t *dataptr = PDQ_OS_DATABUF_PTR(pdu0); 95921826Sjoerg 96021826Sjoerg /* 96121826Sjoerg * The first segment is limited to the space remaining in 96221826Sjoerg * page. All segments after that can be up to a full page 96321826Sjoerg * in size. 96421826Sjoerg */ 96521826Sjoerg fraglen = PDQ_OS_PAGESIZE - ((dataptr - (pdq_uint8_t *) NULL) & (PDQ_OS_PAGESIZE-1)); 96621826Sjoerg while (datalen > 0 && freecnt > 0) { 96721826Sjoerg pdq_uint32_t seglen = (fraglen < datalen ? fraglen : datalen); 96821826Sjoerg 96921826Sjoerg /* 97021826Sjoerg * Initialize the transmit descriptor 97121826Sjoerg */ 97221826Sjoerg eop = &dbp->pdqdb_transmits[producer]; 97321826Sjoerg eop->txd_seg_len = seglen; 97493383Smdodd eop->txd_pa_lo = PDQ_OS_VA_TO_BUSPA(pdq, dataptr); 97521826Sjoerg eop->txd_sop = eop->txd_eop = eop->txd_pa_hi = 0; 97693383Smdodd PDQ_OS_DESC_PRESYNC(pdq, eop, sizeof(pdq_txdesc_t)); 97721826Sjoerg datalen -= seglen; 97821826Sjoerg dataptr += seglen; 97921826Sjoerg fraglen = PDQ_OS_PAGESIZE; 98021826Sjoerg freecnt--; 98121826Sjoerg PDQ_ADVANCE(producer, 1, PDQ_RING_MASK(dbp->pdqdb_transmits)); 98221826Sjoerg } 98321826Sjoerg pdu0 = PDQ_OS_DATABUF_NEXT(pdu0); 98421826Sjoerg } 98593383Smdodd#endif /* defined(PDQ_BUS_DMA) */ 98621826Sjoerg if (pdu0 != NULL) { 98793383Smdodd unsigned completion = tx->tx_completion; 98821826Sjoerg PDQ_ASSERT(freecnt == 0); 98993383Smdodd PDQ_OS_CONSUMER_POSTSYNC(pdq); 99093383Smdodd pdq_process_transmitted_data(pdq); 99193383Smdodd if (completion != tx->tx_completion) { 99293383Smdodd producer = tx->tx_producer; 99393383Smdodd eop = NULL; 99493383Smdodd goto again; 99593383Smdodd } 99621826Sjoerg /* 99721826Sjoerg * If we still have data to process then the ring was too full 99821826Sjoerg * to store the PDU. Return FALSE so the caller will requeue 99921826Sjoerg * the PDU for later. 100021826Sjoerg */ 100193383Smdodd pdq->pdq_intrmask |= PDQ_HOST_INT_TX_ENABLE; 100293383Smdodd PDQ_CSR_WRITE(&pdq->pdq_csrs, csr_host_int_enable, pdq->pdq_intrmask); 100321826Sjoerg return PDQ_FALSE; 100421826Sjoerg } 100521826Sjoerg /* 100621826Sjoerg * Everything went fine. Finish it up. 100721826Sjoerg */ 100821826Sjoerg tx->tx_descriptor_count[tx->tx_producer] = tx->tx_free - freecnt; 100993383Smdodd if (PDQ_RX_FC_OFFSET != PDQ_OS_HDR_OFFSET) { 101093383Smdodd dbp->pdqdb_transmits[tx->tx_producer].txd_sop = 1; 101193383Smdodd PDQ_OS_DESC_PRESYNC(pdq, &dbp->pdqdb_transmits[tx->tx_producer], 101293383Smdodd sizeof(pdq_txdesc_t)); 101393383Smdodd } 101421826Sjoerg eop->txd_eop = 1; 101593383Smdodd PDQ_OS_DESC_PRESYNC(pdq, eop, sizeof(pdq_txdesc_t)); 101621826Sjoerg PDQ_OS_DATABUF_ENQUEUE(&tx->tx_txq, pdu); 101721826Sjoerg tx->tx_producer = producer; 101821826Sjoerg tx->tx_free = freecnt; 101921826Sjoerg PDQ_DO_TYPE2_PRODUCER(pdq); 102021826Sjoerg return PDQ_TRUE; 102121826Sjoerg} 102221826Sjoerg 102321826Sjoergstatic void 102421826Sjoergpdq_process_transmitted_data( 102521826Sjoerg pdq_t *pdq) 102621826Sjoerg{ 102721826Sjoerg pdq_tx_info_t *tx = &pdq->pdq_tx_info; 102821826Sjoerg volatile const pdq_consumer_block_t *cbp = pdq->pdq_cbp; 102921826Sjoerg pdq_descriptor_block_t *dbp = pdq->pdq_dbp; 103021826Sjoerg pdq_uint32_t completion = tx->tx_completion; 103193383Smdodd int reclaimed = 0; 103221826Sjoerg 103321826Sjoerg while (completion != cbp->pdqcb_transmits) { 103421826Sjoerg PDQ_OS_DATABUF_T *pdu; 103521826Sjoerg pdq_uint32_t descriptor_count = tx->tx_descriptor_count[completion]; 103621826Sjoerg PDQ_ASSERT(dbp->pdqdb_transmits[completion].txd_sop == 1); 103721826Sjoerg PDQ_ASSERT(dbp->pdqdb_transmits[(completion + descriptor_count - 1) & PDQ_RING_MASK(dbp->pdqdb_transmits)].txd_eop == 1); 103821826Sjoerg PDQ_OS_DATABUF_DEQUEUE(&tx->tx_txq, pdu); 103921826Sjoerg pdq_os_transmit_done(pdq, pdu); 104021826Sjoerg tx->tx_free += descriptor_count; 104193383Smdodd reclaimed = 1; 104221826Sjoerg PDQ_ADVANCE(completion, descriptor_count, PDQ_RING_MASK(dbp->pdqdb_transmits)); 104321826Sjoerg } 104421826Sjoerg if (tx->tx_completion != completion) { 104521826Sjoerg tx->tx_completion = completion; 104693383Smdodd pdq->pdq_intrmask &= ~PDQ_HOST_INT_TX_ENABLE; 104793383Smdodd PDQ_CSR_WRITE(&pdq->pdq_csrs, csr_host_int_enable, pdq->pdq_intrmask); 104821826Sjoerg pdq_os_restart_transmitter(pdq); 104921826Sjoerg } 105093383Smdodd if (reclaimed) 105193383Smdodd PDQ_DO_TYPE2_PRODUCER(pdq); 105221826Sjoerg} 105321826Sjoerg 105421826Sjoergvoid 105521826Sjoergpdq_flush_transmitter( 105621826Sjoerg pdq_t *pdq) 105721826Sjoerg{ 105821826Sjoerg volatile pdq_consumer_block_t *cbp = pdq->pdq_cbp; 105921826Sjoerg pdq_tx_info_t *tx = &pdq->pdq_tx_info; 106021826Sjoerg 106121826Sjoerg for (;;) { 106221826Sjoerg PDQ_OS_DATABUF_T *pdu; 106321826Sjoerg PDQ_OS_DATABUF_DEQUEUE(&tx->tx_txq, pdu); 106421826Sjoerg if (pdu == NULL) 106521826Sjoerg break; 106621826Sjoerg /* 106721826Sjoerg * Don't call transmit done since the packet never made it 106821826Sjoerg * out on the wire. 106921826Sjoerg */ 107093383Smdodd PDQ_OS_DATABUF_FREE(pdq, pdu); 107121826Sjoerg } 107221826Sjoerg 107321826Sjoerg tx->tx_free = PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_transmits); 107493383Smdodd cbp->pdqcb_transmits = tx->tx_completion = tx->tx_producer; 107593383Smdodd PDQ_OS_CONSUMER_PRESYNC(pdq); 107621826Sjoerg 107721826Sjoerg PDQ_DO_TYPE2_PRODUCER(pdq); 107821826Sjoerg} 107921826Sjoerg 108021826Sjoergvoid 108121826Sjoergpdq_hwreset( 108221826Sjoerg pdq_t *pdq) 108321826Sjoerg{ 108421826Sjoerg const pdq_csrs_t * const csrs = &pdq->pdq_csrs; 108521826Sjoerg pdq_state_t state; 108621826Sjoerg int cnt; 108721826Sjoerg 108821826Sjoerg state = PDQ_PSTS_ADAPTER_STATE(PDQ_CSR_READ(csrs, csr_port_status)); 108921826Sjoerg if (state == PDQS_DMA_UNAVAILABLE) 109021826Sjoerg return; 109121826Sjoerg PDQ_CSR_WRITE(csrs, csr_port_data_a, 109293383Smdodd (state == PDQS_HALTED && pdq->pdq_type != PDQ_DEFTA) ? 0 : PDQ_PRESET_SKIP_SELFTEST); 109321826Sjoerg PDQ_CSR_WRITE(csrs, csr_port_reset, 1); 109421826Sjoerg PDQ_OS_USEC_DELAY(100); 109521826Sjoerg PDQ_CSR_WRITE(csrs, csr_port_reset, 0); 109693383Smdodd for (cnt = 100000;;cnt--) { 109721826Sjoerg PDQ_OS_USEC_DELAY(1000); 109821826Sjoerg state = PDQ_PSTS_ADAPTER_STATE(PDQ_CSR_READ(csrs, csr_port_status)); 109921826Sjoerg if (state == PDQS_DMA_UNAVAILABLE || cnt == 0) 110021826Sjoerg break; 110121826Sjoerg } 110293383Smdodd PDQ_PRINTF(("PDQ Reset spun %d cycles\n", 100000 - cnt)); 110321826Sjoerg PDQ_OS_USEC_DELAY(10000); 110421826Sjoerg state = PDQ_PSTS_ADAPTER_STATE(PDQ_CSR_READ(csrs, csr_port_status)); 110521826Sjoerg PDQ_ASSERT(state == PDQS_DMA_UNAVAILABLE); 110621826Sjoerg PDQ_ASSERT(cnt > 0); 110721826Sjoerg} 110821826Sjoerg 110921826Sjoerg/* 111021826Sjoerg * The following routine brings the PDQ from whatever state it is 111121826Sjoerg * in to DMA_UNAVAILABLE (ie. like a RESET but without doing a RESET). 111221826Sjoerg */ 111321826Sjoergpdq_state_t 111421826Sjoergpdq_stop( 111521826Sjoerg pdq_t *pdq) 111621826Sjoerg{ 111721826Sjoerg pdq_state_t state; 111821826Sjoerg const pdq_csrs_t * const csrs = &pdq->pdq_csrs; 111921826Sjoerg int cnt, pass = 0, idx; 112021826Sjoerg PDQ_OS_DATABUF_T **buffers; 112121826Sjoerg 112221826Sjoerg restart: 112321826Sjoerg state = PDQ_PSTS_ADAPTER_STATE(PDQ_CSR_READ(csrs, csr_port_status)); 112421826Sjoerg if (state != PDQS_DMA_UNAVAILABLE) { 112521826Sjoerg pdq_hwreset(pdq); 112621826Sjoerg state = PDQ_PSTS_ADAPTER_STATE(PDQ_CSR_READ(csrs, csr_port_status)); 112721826Sjoerg PDQ_ASSERT(state == PDQS_DMA_UNAVAILABLE); 112821826Sjoerg } 112921826Sjoerg#if 0 113021826Sjoerg switch (state) { 113121826Sjoerg case PDQS_RING_MEMBER: 113221826Sjoerg case PDQS_LINK_UNAVAILABLE: 113321826Sjoerg case PDQS_LINK_AVAILABLE: { 113421826Sjoerg PDQ_CSR_WRITE(csrs, csr_port_data_a, PDQ_SUB_CMD_LINK_UNINIT); 113521826Sjoerg PDQ_CSR_WRITE(csrs, csr_port_data_b, 0); 113621826Sjoerg pdq_do_port_control(csrs, PDQ_PCTL_SUB_CMD); 113721826Sjoerg state = PDQ_PSTS_ADAPTER_STATE(PDQ_CSR_READ(csrs, csr_port_status)); 113821826Sjoerg PDQ_ASSERT(state == PDQS_DMA_AVAILABLE); 1139102412Scharnier /* FALLTHROUGH */ 114021826Sjoerg } 114121826Sjoerg case PDQS_DMA_AVAILABLE: { 114221826Sjoerg PDQ_CSR_WRITE(csrs, csr_port_data_a, 0); 114321826Sjoerg PDQ_CSR_WRITE(csrs, csr_port_data_b, 0); 114421826Sjoerg pdq_do_port_control(csrs, PDQ_PCTL_DMA_UNINIT); 114521826Sjoerg state = PDQ_PSTS_ADAPTER_STATE(PDQ_CSR_READ(csrs, csr_port_status)); 114621826Sjoerg PDQ_ASSERT(state == PDQS_DMA_UNAVAILABLE); 1147102412Scharnier /* FALLTHROUGH */ 114821826Sjoerg } 114921826Sjoerg case PDQS_DMA_UNAVAILABLE: { 115021826Sjoerg break; 115121826Sjoerg } 115221826Sjoerg } 115321826Sjoerg#endif 115421826Sjoerg /* 115521826Sjoerg * Now we should be in DMA_UNAVAILABLE. So bring the PDQ into 115621826Sjoerg * DMA_AVAILABLE. 115721826Sjoerg */ 115821826Sjoerg 115921826Sjoerg /* 116021826Sjoerg * Obtain the hardware address and firmware revisions 116121826Sjoerg * (MLA = my long address which is FDDI speak for hardware address) 116221826Sjoerg */ 116321826Sjoerg pdq_read_mla(&pdq->pdq_csrs, &pdq->pdq_hwaddr); 116421826Sjoerg pdq_read_fwrev(&pdq->pdq_csrs, &pdq->pdq_fwrev); 116521826Sjoerg pdq->pdq_chip_rev = pdq_read_chiprev(&pdq->pdq_csrs); 116621826Sjoerg 116721826Sjoerg if (pdq->pdq_type == PDQ_DEFPA) { 116821826Sjoerg /* 116921826Sjoerg * Disable interrupts and DMA. 117021826Sjoerg */ 117121826Sjoerg PDQ_CSR_WRITE(&pdq->pdq_pci_csrs, csr_pfi_mode_control, 0); 117221826Sjoerg PDQ_CSR_WRITE(&pdq->pdq_pci_csrs, csr_pfi_status, 0x10); 117321826Sjoerg } 117421826Sjoerg 117521826Sjoerg /* 117621826Sjoerg * Flush all the databuf queues. 117721826Sjoerg */ 117893383Smdodd pdq_flush_databuf_queue(pdq, &pdq->pdq_tx_info.tx_txq); 117993383Smdodd pdq->pdq_flags &= ~(PDQ_TXOK|PDQ_IS_ONRING|PDQ_IS_FDX); 118021826Sjoerg buffers = (PDQ_OS_DATABUF_T **) pdq->pdq_rx_info.rx_buffers; 118121826Sjoerg for (idx = 0; idx < PDQ_RING_SIZE(pdq->pdq_dbp->pdqdb_receives); idx++) { 118221826Sjoerg if (buffers[idx] != NULL) { 118393383Smdodd PDQ_OS_DATABUF_FREE(pdq, buffers[idx]); 118421826Sjoerg buffers[idx] = NULL; 118521826Sjoerg } 118621826Sjoerg } 118721826Sjoerg pdq->pdq_rx_info.rx_free = PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_receives); 118821826Sjoerg buffers = (PDQ_OS_DATABUF_T **) pdq->pdq_host_smt_info.rx_buffers; 118921826Sjoerg for (idx = 0; idx < PDQ_RING_SIZE(pdq->pdq_dbp->pdqdb_host_smt); idx++) { 119021826Sjoerg if (buffers[idx] != NULL) { 119193383Smdodd PDQ_OS_DATABUF_FREE(pdq, buffers[idx]); 119221826Sjoerg buffers[idx] = NULL; 119321826Sjoerg } 119421826Sjoerg } 119521826Sjoerg pdq->pdq_host_smt_info.rx_free = PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_host_smt); 119621826Sjoerg 119721826Sjoerg /* 119821826Sjoerg * Reset the consumer indexes to 0. 119921826Sjoerg */ 120021826Sjoerg pdq->pdq_cbp->pdqcb_receives = 0; 120121826Sjoerg pdq->pdq_cbp->pdqcb_transmits = 0; 120221826Sjoerg pdq->pdq_cbp->pdqcb_host_smt = 0; 120321826Sjoerg pdq->pdq_cbp->pdqcb_unsolicited_event = 0; 120421826Sjoerg pdq->pdq_cbp->pdqcb_command_response = 0; 120521826Sjoerg pdq->pdq_cbp->pdqcb_command_request = 0; 120693383Smdodd PDQ_OS_CONSUMER_PRESYNC(pdq); 120721826Sjoerg 120821826Sjoerg /* 120921826Sjoerg * Reset the producer and completion indexes to 0. 121021826Sjoerg */ 121121826Sjoerg pdq->pdq_command_info.ci_request_producer = 0; 121221826Sjoerg pdq->pdq_command_info.ci_response_producer = 0; 121321826Sjoerg pdq->pdq_command_info.ci_request_completion = 0; 121421826Sjoerg pdq->pdq_command_info.ci_response_completion = 0; 121521826Sjoerg pdq->pdq_unsolicited_info.ui_producer = 0; 121621826Sjoerg pdq->pdq_unsolicited_info.ui_completion = 0; 121721826Sjoerg pdq->pdq_rx_info.rx_producer = 0; 121821826Sjoerg pdq->pdq_rx_info.rx_completion = 0; 121921826Sjoerg pdq->pdq_tx_info.tx_producer = 0; 122021826Sjoerg pdq->pdq_tx_info.tx_completion = 0; 122121826Sjoerg pdq->pdq_host_smt_info.rx_producer = 0; 122221826Sjoerg pdq->pdq_host_smt_info.rx_completion = 0; 122321826Sjoerg 122421826Sjoerg pdq->pdq_command_info.ci_command_active = 0; 122521826Sjoerg pdq->pdq_unsolicited_info.ui_free = PDQ_NUM_UNSOLICITED_EVENTS; 122621826Sjoerg pdq->pdq_tx_info.tx_free = PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_transmits); 122721826Sjoerg 122821826Sjoerg /* 122921826Sjoerg * Allow the DEFPA to do DMA. Then program the physical 123021826Sjoerg * addresses of the consumer and descriptor blocks. 123121826Sjoerg */ 123221826Sjoerg if (pdq->pdq_type == PDQ_DEFPA) { 123321826Sjoerg#ifdef PDQTEST 123421826Sjoerg PDQ_CSR_WRITE(&pdq->pdq_pci_csrs, csr_pfi_mode_control, 123521826Sjoerg PDQ_PFI_MODE_DMA_ENABLE); 123621826Sjoerg#else 123721826Sjoerg PDQ_CSR_WRITE(&pdq->pdq_pci_csrs, csr_pfi_mode_control, 123821826Sjoerg PDQ_PFI_MODE_DMA_ENABLE 123921826Sjoerg /*|PDQ_PFI_MODE_PFI_PCI_INTR*/|PDQ_PFI_MODE_PDQ_PCI_INTR); 124021826Sjoerg#endif 124121826Sjoerg } 124221826Sjoerg 124321826Sjoerg /* 124421826Sjoerg * Make sure the unsolicited queue has events ... 124521826Sjoerg */ 124621826Sjoerg pdq_process_unsolicited_events(pdq); 124721826Sjoerg 124893383Smdodd if ((pdq->pdq_type == PDQ_DEFEA && pdq->pdq_chip_rev == PDQ_CHIP_REV_E) 124993383Smdodd || pdq->pdq_type == PDQ_DEFTA) 125021826Sjoerg PDQ_CSR_WRITE(csrs, csr_port_data_b, PDQ_DMA_BURST_16LW); 125121826Sjoerg else 125221826Sjoerg PDQ_CSR_WRITE(csrs, csr_port_data_b, PDQ_DMA_BURST_8LW); 125321826Sjoerg PDQ_CSR_WRITE(csrs, csr_port_data_a, PDQ_SUB_CMD_DMA_BURST_SIZE_SET); 125421826Sjoerg pdq_do_port_control(csrs, PDQ_PCTL_SUB_CMD); 125521826Sjoerg 125693383Smdodd /* 125793383Smdodd * Make sure there isn't stale information in the caches before 125893383Smdodd * tell the adapter about the blocks it's going to use. 125993383Smdodd */ 126093383Smdodd PDQ_OS_CONSUMER_PRESYNC(pdq); 126193383Smdodd 126221826Sjoerg PDQ_CSR_WRITE(csrs, csr_port_data_b, 0); 126393383Smdodd PDQ_CSR_WRITE(csrs, csr_port_data_a, pdq->pdq_pa_consumer_block); 126421826Sjoerg pdq_do_port_control(csrs, PDQ_PCTL_CONSUMER_BLOCK); 126521826Sjoerg 126621826Sjoerg PDQ_CSR_WRITE(csrs, csr_port_data_b, 0); 126793383Smdodd#if !defined(BYTE_ORDER) || BYTE_ORDER == LITTLE_ENDIAN 126893383Smdodd PDQ_CSR_WRITE(csrs, csr_port_data_a, pdq->pdq_pa_descriptor_block | PDQ_DMA_INIT_LW_BSWAP_DATA); 126993383Smdodd#else 127093383Smdodd PDQ_CSR_WRITE(csrs, csr_port_data_a, pdq->pdq_pa_descriptor_block | PDQ_DMA_INIT_LW_BSWAP_DATA | PDQ_DMA_INIT_LW_BSWAP_LITERAL); 127193383Smdodd#endif 127221826Sjoerg pdq_do_port_control(csrs, PDQ_PCTL_DMA_INIT); 127321826Sjoerg 127421826Sjoerg for (cnt = 0; cnt < 1000; cnt++) { 127521826Sjoerg state = PDQ_PSTS_ADAPTER_STATE(PDQ_CSR_READ(csrs, csr_port_status)); 127621826Sjoerg if (state == PDQS_HALTED) { 127721826Sjoerg if (pass > 0) 127821826Sjoerg return PDQS_HALTED; 127921826Sjoerg pass = 1; 128021826Sjoerg goto restart; 128121826Sjoerg } 128221826Sjoerg if (state == PDQS_DMA_AVAILABLE) { 128321826Sjoerg PDQ_PRINTF(("Transition to DMA Available took %d spins\n", cnt)); 128421826Sjoerg break; 128521826Sjoerg } 128621826Sjoerg PDQ_OS_USEC_DELAY(1000); 128721826Sjoerg } 128821826Sjoerg PDQ_ASSERT(state == PDQS_DMA_AVAILABLE); 128921826Sjoerg 129021826Sjoerg PDQ_CSR_WRITE(csrs, csr_host_int_type_0, 0xFF); 129193383Smdodd pdq->pdq_intrmask = 0; 129293383Smdodd /* PDQ_HOST_INT_STATE_CHANGE 129321826Sjoerg |PDQ_HOST_INT_FATAL_ERROR|PDQ_HOST_INT_CMD_RSP_ENABLE 1294297793Spfg |PDQ_HOST_INT_UNSOL_ENABLE */ 129593383Smdodd PDQ_CSR_WRITE(csrs, csr_host_int_enable, pdq->pdq_intrmask); 129621826Sjoerg 129721826Sjoerg /* 129821826Sjoerg * Any other command but START should be valid. 129921826Sjoerg */ 130021826Sjoerg pdq->pdq_command_info.ci_pending_commands &= ~(PDQ_BITMASK(PDQC_START)); 130121826Sjoerg if (pdq->pdq_flags & PDQ_PRINTCHARS) 130221826Sjoerg pdq->pdq_command_info.ci_pending_commands |= PDQ_BITMASK(PDQC_STATUS_CHARS_GET); 130321826Sjoerg pdq_queue_commands(pdq); 130421826Sjoerg 130521826Sjoerg if (pdq->pdq_flags & PDQ_PRINTCHARS) { 130621826Sjoerg /* 130721826Sjoerg * Now wait (up to 100ms) for the command(s) to finish. 130821826Sjoerg */ 130921826Sjoerg for (cnt = 0; cnt < 1000; cnt++) { 131093383Smdodd PDQ_OS_CONSUMER_POSTSYNC(pdq); 131121826Sjoerg pdq_process_command_responses(pdq); 131221826Sjoerg if (pdq->pdq_command_info.ci_response_producer == pdq->pdq_command_info.ci_response_completion) 131321826Sjoerg break; 131421826Sjoerg PDQ_OS_USEC_DELAY(1000); 131521826Sjoerg } 131621826Sjoerg state = PDQ_PSTS_ADAPTER_STATE(PDQ_CSR_READ(csrs, csr_port_status)); 131721826Sjoerg } 131821826Sjoerg 131921826Sjoerg return state; 132021826Sjoerg} 132121826Sjoerg 132221826Sjoergvoid 132321826Sjoergpdq_run( 132421826Sjoerg pdq_t *pdq) 132521826Sjoerg{ 132621826Sjoerg const pdq_csrs_t * const csrs = &pdq->pdq_csrs; 132721826Sjoerg pdq_state_t state; 132821826Sjoerg 132921826Sjoerg state = PDQ_PSTS_ADAPTER_STATE(PDQ_CSR_READ(csrs, csr_port_status)); 133021826Sjoerg PDQ_ASSERT(state != PDQS_DMA_UNAVAILABLE); 133121826Sjoerg PDQ_ASSERT(state != PDQS_RESET); 133221826Sjoerg PDQ_ASSERT(state != PDQS_HALTED); 133321826Sjoerg PDQ_ASSERT(state != PDQS_UPGRADE); 133421826Sjoerg PDQ_ASSERT(state != PDQS_RING_MEMBER); 133521826Sjoerg switch (state) { 133621826Sjoerg case PDQS_DMA_AVAILABLE: { 133721826Sjoerg /* 133821826Sjoerg * The PDQ after being reset screws up some of its state. 133921826Sjoerg * So we need to clear all the errors/interrupts so the real 134021826Sjoerg * ones will get through. 134121826Sjoerg */ 134221826Sjoerg PDQ_CSR_WRITE(csrs, csr_host_int_type_0, 0xFF); 134393383Smdodd pdq->pdq_intrmask = PDQ_HOST_INT_STATE_CHANGE 134493383Smdodd |PDQ_HOST_INT_XMT_DATA_FLUSH|PDQ_HOST_INT_FATAL_ERROR 134593383Smdodd |PDQ_HOST_INT_CMD_RSP_ENABLE|PDQ_HOST_INT_UNSOL_ENABLE 134693383Smdodd |PDQ_HOST_INT_RX_ENABLE|PDQ_HOST_INT_HOST_SMT_ENABLE; 134793383Smdodd PDQ_CSR_WRITE(csrs, csr_host_int_enable, pdq->pdq_intrmask); 134821826Sjoerg /* 134921826Sjoerg * Set the MAC and address filters and start up the PDQ. 135021826Sjoerg */ 135121826Sjoerg pdq_process_unsolicited_events(pdq); 135221826Sjoerg pdq_process_received_data(pdq, &pdq->pdq_rx_info, 135321826Sjoerg pdq->pdq_dbp->pdqdb_receives, 135421826Sjoerg pdq->pdq_cbp->pdqcb_receives, 135521826Sjoerg PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_receives)); 135621826Sjoerg PDQ_DO_TYPE2_PRODUCER(pdq); 135721826Sjoerg if (pdq->pdq_flags & PDQ_PASS_SMT) { 135821826Sjoerg pdq_process_received_data(pdq, &pdq->pdq_host_smt_info, 135921826Sjoerg pdq->pdq_dbp->pdqdb_host_smt, 136021826Sjoerg pdq->pdq_cbp->pdqcb_host_smt, 136121826Sjoerg PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_host_smt)); 136221826Sjoerg PDQ_CSR_WRITE(csrs, csr_host_smt_producer, 136321826Sjoerg pdq->pdq_host_smt_info.rx_producer 136421826Sjoerg | (pdq->pdq_host_smt_info.rx_completion << 8)); 136521826Sjoerg } 136621826Sjoerg pdq->pdq_command_info.ci_pending_commands = PDQ_BITMASK(PDQC_FILTER_SET) 136793383Smdodd | PDQ_BITMASK(PDQC_ADDR_FILTER_SET) 136893383Smdodd | PDQ_BITMASK(PDQC_SNMP_SET) 136993383Smdodd | PDQ_BITMASK(PDQC_START); 137021826Sjoerg if (pdq->pdq_flags & PDQ_PRINTCHARS) 137121826Sjoerg pdq->pdq_command_info.ci_pending_commands |= PDQ_BITMASK(PDQC_STATUS_CHARS_GET); 137221826Sjoerg pdq_queue_commands(pdq); 137321826Sjoerg break; 137421826Sjoerg } 137521826Sjoerg case PDQS_LINK_UNAVAILABLE: 137621826Sjoerg case PDQS_LINK_AVAILABLE: { 137721826Sjoerg pdq->pdq_command_info.ci_pending_commands = PDQ_BITMASK(PDQC_FILTER_SET) 137893383Smdodd | PDQ_BITMASK(PDQC_ADDR_FILTER_SET) 137993383Smdodd | PDQ_BITMASK(PDQC_SNMP_SET); 138021826Sjoerg if (pdq->pdq_flags & PDQ_PRINTCHARS) 138121826Sjoerg pdq->pdq_command_info.ci_pending_commands |= PDQ_BITMASK(PDQC_STATUS_CHARS_GET); 138221826Sjoerg if (pdq->pdq_flags & PDQ_PASS_SMT) { 138321826Sjoerg pdq_process_received_data(pdq, &pdq->pdq_host_smt_info, 138421826Sjoerg pdq->pdq_dbp->pdqdb_host_smt, 138521826Sjoerg pdq->pdq_cbp->pdqcb_host_smt, 138621826Sjoerg PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_host_smt)); 138721826Sjoerg PDQ_CSR_WRITE(csrs, csr_host_smt_producer, 138821826Sjoerg pdq->pdq_host_smt_info.rx_producer 138921826Sjoerg | (pdq->pdq_host_smt_info.rx_completion << 8)); 139021826Sjoerg } 139121826Sjoerg pdq_process_unsolicited_events(pdq); 139221826Sjoerg pdq_queue_commands(pdq); 139321826Sjoerg break; 139421826Sjoerg } 139521826Sjoerg case PDQS_RING_MEMBER: { 139621826Sjoerg } 139721826Sjoerg default: { /* to make gcc happy */ 139821826Sjoerg break; 139921826Sjoerg } 140021826Sjoerg } 140121826Sjoerg} 140221826Sjoerg 140321826Sjoergint 140421826Sjoergpdq_interrupt( 140521826Sjoerg pdq_t *pdq) 140621826Sjoerg{ 140721826Sjoerg const pdq_csrs_t * const csrs = &pdq->pdq_csrs; 140821826Sjoerg pdq_uint32_t data; 140921826Sjoerg int progress = 0; 141021826Sjoerg 141121826Sjoerg if (pdq->pdq_type == PDQ_DEFPA) 141221826Sjoerg PDQ_CSR_WRITE(&pdq->pdq_pci_csrs, csr_pfi_status, 0x18); 141321826Sjoerg 141421826Sjoerg while ((data = PDQ_CSR_READ(csrs, csr_port_status)) & PDQ_PSTS_INTR_PENDING) { 141521826Sjoerg progress = 1; 141621826Sjoerg PDQ_PRINTF(("PDQ Interrupt: Status = 0x%08x\n", data)); 141793383Smdodd PDQ_OS_CONSUMER_POSTSYNC(pdq); 141821826Sjoerg if (data & PDQ_PSTS_RCV_DATA_PENDING) { 141921826Sjoerg pdq_process_received_data(pdq, &pdq->pdq_rx_info, 142021826Sjoerg pdq->pdq_dbp->pdqdb_receives, 142121826Sjoerg pdq->pdq_cbp->pdqcb_receives, 142221826Sjoerg PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_receives)); 142321826Sjoerg PDQ_DO_TYPE2_PRODUCER(pdq); 142421826Sjoerg } 142521826Sjoerg if (data & PDQ_PSTS_HOST_SMT_PENDING) { 142621826Sjoerg pdq_process_received_data(pdq, &pdq->pdq_host_smt_info, 142721826Sjoerg pdq->pdq_dbp->pdqdb_host_smt, 142821826Sjoerg pdq->pdq_cbp->pdqcb_host_smt, 142921826Sjoerg PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_host_smt)); 143021826Sjoerg PDQ_DO_HOST_SMT_PRODUCER(pdq); 143121826Sjoerg } 143293383Smdodd /* if (data & PDQ_PSTS_XMT_DATA_PENDING) */ 143321826Sjoerg pdq_process_transmitted_data(pdq); 143421826Sjoerg if (data & PDQ_PSTS_UNSOL_PENDING) 143521826Sjoerg pdq_process_unsolicited_events(pdq); 143621826Sjoerg if (data & PDQ_PSTS_CMD_RSP_PENDING) 143721826Sjoerg pdq_process_command_responses(pdq); 143821826Sjoerg if (data & PDQ_PSTS_TYPE_0_PENDING) { 143921826Sjoerg data = PDQ_CSR_READ(csrs, csr_host_int_type_0); 144021826Sjoerg if (data & PDQ_HOST_INT_STATE_CHANGE) { 144121826Sjoerg pdq_state_t state = PDQ_PSTS_ADAPTER_STATE(PDQ_CSR_READ(csrs, csr_port_status)); 144221826Sjoerg printf(PDQ_OS_PREFIX "%s", PDQ_OS_PREFIX_ARGS, pdq_adapter_states[state]); 144321826Sjoerg if (state == PDQS_LINK_UNAVAILABLE) { 144493383Smdodd pdq->pdq_flags &= ~(PDQ_TXOK|PDQ_IS_ONRING|PDQ_IS_FDX); 144521826Sjoerg } else if (state == PDQS_LINK_AVAILABLE) { 144693383Smdodd if (pdq->pdq_flags & PDQ_WANT_FDX) { 144793383Smdodd pdq->pdq_command_info.ci_pending_commands |= PDQ_BITMASK(PDQC_DEC_EXT_MIB_GET); 144893383Smdodd pdq_queue_commands(pdq); 144993383Smdodd } 145093383Smdodd pdq->pdq_flags |= PDQ_TXOK|PDQ_IS_ONRING; 145121826Sjoerg pdq_os_restart_transmitter(pdq); 145221826Sjoerg } else if (state == PDQS_HALTED) { 145321826Sjoerg pdq_response_error_log_get_t log_entry; 145421826Sjoerg pdq_halt_code_t halt_code = PDQ_PSTS_HALT_ID(PDQ_CSR_READ(csrs, csr_port_status)); 145521826Sjoerg printf(": halt code = %d (%s)\n", 145621826Sjoerg halt_code, pdq_halt_codes[halt_code]); 145721826Sjoerg if (halt_code == PDQH_DMA_ERROR && pdq->pdq_type == PDQ_DEFPA) { 145821826Sjoerg PDQ_PRINTF(("\tPFI status = 0x%x, Host 0 Fatal Interrupt = 0x%x\n", 145921826Sjoerg PDQ_CSR_READ(&pdq->pdq_pci_csrs, csr_pfi_status), 146021826Sjoerg data & PDQ_HOST_INT_FATAL_ERROR)); 146121826Sjoerg } 146293383Smdodd PDQ_OS_MEMZERO(&log_entry, sizeof(log_entry)); 146393383Smdodd if (pdq_read_error_log(pdq, &log_entry)) { 146493383Smdodd PDQ_PRINTF((" Error log Entry:\n")); 146593383Smdodd PDQ_PRINTF((" CMD Status = %d (0x%x)\n", 146693383Smdodd log_entry.error_log_get_status, 146793383Smdodd log_entry.error_log_get_status)); 146893383Smdodd PDQ_PRINTF((" Event Status = %d (0x%x)\n", 146993383Smdodd log_entry.error_log_get_event_status, 147093383Smdodd log_entry.error_log_get_event_status)); 147193383Smdodd PDQ_PRINTF((" Caller Id = %d (0x%x)\n", 147293383Smdodd log_entry.error_log_get_caller_id, 147393383Smdodd log_entry.error_log_get_caller_id)); 147493383Smdodd PDQ_PRINTF((" Write Count = %d (0x%x)\n", 147593383Smdodd log_entry.error_log_get_write_count, 147693383Smdodd log_entry.error_log_get_write_count)); 147793383Smdodd PDQ_PRINTF((" FRU Implication Mask = %d (0x%x)\n", 147893383Smdodd log_entry.error_log_get_fru_implication_mask, 147993383Smdodd log_entry.error_log_get_fru_implication_mask)); 148093383Smdodd PDQ_PRINTF((" Test ID = %d (0x%x)\n", 148193383Smdodd log_entry.error_log_get_test_id, 148293383Smdodd log_entry.error_log_get_test_id)); 148393383Smdodd } 148421826Sjoerg pdq_stop(pdq); 148521826Sjoerg if (pdq->pdq_flags & PDQ_RUNNING) 148621826Sjoerg pdq_run(pdq); 148721826Sjoerg return 1; 148821826Sjoerg } 148921826Sjoerg printf("\n"); 149021826Sjoerg PDQ_CSR_WRITE(csrs, csr_host_int_type_0, PDQ_HOST_INT_STATE_CHANGE); 149121826Sjoerg } 149221826Sjoerg if (data & PDQ_HOST_INT_FATAL_ERROR) { 149321826Sjoerg pdq_stop(pdq); 149421826Sjoerg if (pdq->pdq_flags & PDQ_RUNNING) 149521826Sjoerg pdq_run(pdq); 149621826Sjoerg return 1; 149721826Sjoerg } 149821826Sjoerg if (data & PDQ_HOST_INT_XMT_DATA_FLUSH) { 149921826Sjoerg printf(PDQ_OS_PREFIX "Flushing transmit queue\n", PDQ_OS_PREFIX_ARGS); 150021826Sjoerg pdq->pdq_flags &= ~PDQ_TXOK; 150121826Sjoerg pdq_flush_transmitter(pdq); 150221826Sjoerg pdq_do_port_control(csrs, PDQ_PCTL_XMT_DATA_FLUSH_DONE); 150321826Sjoerg PDQ_CSR_WRITE(csrs, csr_host_int_type_0, PDQ_HOST_INT_XMT_DATA_FLUSH); 150421826Sjoerg } 150521826Sjoerg } 150621826Sjoerg if (pdq->pdq_type == PDQ_DEFPA) 150721826Sjoerg PDQ_CSR_WRITE(&pdq->pdq_pci_csrs, csr_pfi_status, 0x18); 150821826Sjoerg } 150921826Sjoerg return progress; 151021826Sjoerg} 151121826Sjoerg 151221826Sjoergpdq_t * 151321826Sjoergpdq_initialize( 151421826Sjoerg pdq_bus_t bus, 151521826Sjoerg pdq_bus_memaddr_t csr_base, 151621826Sjoerg const char *name, 151721826Sjoerg int unit, 151821826Sjoerg void *ctx, 151921826Sjoerg pdq_type_t type) 152021826Sjoerg{ 152121826Sjoerg pdq_t *pdq; 152221826Sjoerg pdq_state_t state; 152393383Smdodd pdq_descriptor_block_t *dbp; 152493383Smdodd#if !defined(PDQ_BUS_DMA) 152521826Sjoerg const pdq_uint32_t contig_bytes = (sizeof(pdq_descriptor_block_t) * 2) - PDQ_OS_PAGESIZE; 152621826Sjoerg pdq_uint8_t *p; 152793383Smdodd#endif 152821826Sjoerg int idx; 152921826Sjoerg 153021826Sjoerg PDQ_ASSERT(sizeof(pdq_descriptor_block_t) == 8192); 153121826Sjoerg PDQ_ASSERT(sizeof(pdq_consumer_block_t) == 64); 153221826Sjoerg PDQ_ASSERT(sizeof(pdq_response_filter_get_t) == PDQ_SIZE_RESPONSE_FILTER_GET); 153321826Sjoerg PDQ_ASSERT(sizeof(pdq_cmd_addr_filter_set_t) == PDQ_SIZE_CMD_ADDR_FILTER_SET); 153421826Sjoerg PDQ_ASSERT(sizeof(pdq_response_addr_filter_get_t) == PDQ_SIZE_RESPONSE_ADDR_FILTER_GET); 153521826Sjoerg PDQ_ASSERT(sizeof(pdq_response_status_chars_get_t) == PDQ_SIZE_RESPONSE_STATUS_CHARS_GET); 153621826Sjoerg PDQ_ASSERT(sizeof(pdq_response_fddi_mib_get_t) == PDQ_SIZE_RESPONSE_FDDI_MIB_GET); 153721826Sjoerg PDQ_ASSERT(sizeof(pdq_response_dec_ext_mib_get_t) == PDQ_SIZE_RESPONSE_DEC_EXT_MIB_GET); 153821826Sjoerg PDQ_ASSERT(sizeof(pdq_unsolicited_event_t) == 512); 153921826Sjoerg 154021826Sjoerg pdq = (pdq_t *) PDQ_OS_MEMALLOC(sizeof(pdq_t)); 154121826Sjoerg if (pdq == NULL) { 154221826Sjoerg PDQ_PRINTF(("malloc(%d) failed\n", sizeof(*pdq))); 154321826Sjoerg return NULL; 154421826Sjoerg } 154521826Sjoerg PDQ_OS_MEMZERO(pdq, sizeof(pdq_t)); 154621826Sjoerg pdq->pdq_type = type; 154721826Sjoerg pdq->pdq_unit = unit; 154821826Sjoerg pdq->pdq_os_ctx = (void *) ctx; 154921826Sjoerg pdq->pdq_os_name = name; 155021826Sjoerg pdq->pdq_flags = PDQ_PRINTCHARS; 155121826Sjoerg /* 155221826Sjoerg * Allocate the additional data structures required by 155321826Sjoerg * the PDQ driver. Allocate a contiguous region of memory 155421826Sjoerg * for the descriptor block. We need to allocated enough 155521826Sjoerg * to guarantee that we will a get 8KB block of memory aligned 155621826Sjoerg * on a 8KB boundary. This turns to require that we allocate 155721826Sjoerg * (N*2 - 1 page) pages of memory. On machine with less than 155821826Sjoerg * a 8KB page size, it mean we will allocate more memory than 155921826Sjoerg * we need. The extra will be used for the unsolicited event 156021826Sjoerg * buffers (though on machines with 8KB pages we will to allocate 156121826Sjoerg * them separately since there will be nothing left overs.) 156221826Sjoerg */ 156393383Smdodd#if defined(PDQ_OS_MEMALLOC_CONTIG) 156421826Sjoerg p = (pdq_uint8_t *) PDQ_OS_MEMALLOC_CONTIG(contig_bytes); 156593383Smdodd 1566105507Sphk if (p == NULL) 1567135577Sstefanf printf("%s() - PDQ_OS_MEMALLOC_CONTIG() failed!\n", __func__); 156893383Smdodd 156921826Sjoerg if (p != NULL) { 157093383Smdodd pdq_physaddr_t physaddr = PDQ_OS_VA_TO_BUSPA(pdq, p); 157121826Sjoerg /* 157221826Sjoerg * Assert that we really got contiguous memory. This isn't really 157321826Sjoerg * needed on systems that actually have physical contiguous allocation 157421826Sjoerg * routines, but on those systems that don't ... 157521826Sjoerg */ 157621826Sjoerg for (idx = PDQ_OS_PAGESIZE; idx < 0x2000; idx += PDQ_OS_PAGESIZE) { 157793383Smdodd if (PDQ_OS_VA_TO_BUSPA(pdq, p + idx) - physaddr != idx) 157821826Sjoerg goto cleanup_and_return; 157921826Sjoerg } 158093383Smdodd if (physaddr & 0x1FFF) { 158121826Sjoerg pdq->pdq_unsolicited_info.ui_events = (pdq_unsolicited_event_t *) p; 158293383Smdodd pdq->pdq_unsolicited_info.ui_pa_bufstart = physaddr; 158393383Smdodd pdq->pdq_dbp = (pdq_descriptor_block_t *) &p[0x2000 - (physaddr & 0x1FFF)]; 158493383Smdodd pdq->pdq_pa_descriptor_block = physaddr & ~0x1FFFUL; 158521826Sjoerg } else { 158621826Sjoerg pdq->pdq_dbp = (pdq_descriptor_block_t *) p; 158793383Smdodd pdq->pdq_pa_descriptor_block = physaddr; 158821826Sjoerg pdq->pdq_unsolicited_info.ui_events = (pdq_unsolicited_event_t *) &p[0x2000]; 158993383Smdodd pdq->pdq_unsolicited_info.ui_pa_bufstart = physaddr + 0x2000; 159021826Sjoerg } 159121826Sjoerg } 159293383Smdodd pdq->pdq_cbp = (volatile pdq_consumer_block_t *) &pdq->pdq_dbp->pdqdb_consumer; 159393383Smdodd pdq->pdq_pa_consumer_block = PDQ_DB_BUSPA(pdq, pdq->pdq_cbp); 159421826Sjoerg if (contig_bytes == sizeof(pdq_descriptor_block_t)) { 159521826Sjoerg pdq->pdq_unsolicited_info.ui_events = 159621826Sjoerg (pdq_unsolicited_event_t *) PDQ_OS_MEMALLOC( 159721826Sjoerg PDQ_NUM_UNSOLICITED_EVENTS * sizeof(pdq_unsolicited_event_t)); 159821826Sjoerg } 159993383Smdodd#else 160093383Smdodd if (pdq_os_memalloc_contig(pdq)) 160193383Smdodd goto cleanup_and_return; 160293383Smdodd#endif 160321826Sjoerg 160421826Sjoerg /* 160521826Sjoerg * Make sure everything got allocated. If not, free what did 160621826Sjoerg * get allocated and return. 160721826Sjoerg */ 160821826Sjoerg if (pdq->pdq_dbp == NULL || pdq->pdq_unsolicited_info.ui_events == NULL) { 160921826Sjoerg cleanup_and_return: 161093383Smdodd#ifdef PDQ_OS_MEMFREE_CONTIG 161121826Sjoerg if (p /* pdq->pdq_dbp */ != NULL) 161221826Sjoerg PDQ_OS_MEMFREE_CONTIG(p /* pdq->pdq_dbp */, contig_bytes); 161321826Sjoerg if (contig_bytes == sizeof(pdq_descriptor_block_t) && pdq->pdq_unsolicited_info.ui_events != NULL) 161421826Sjoerg PDQ_OS_MEMFREE(pdq->pdq_unsolicited_info.ui_events, 161521826Sjoerg PDQ_NUM_UNSOLICITED_EVENTS * sizeof(pdq_unsolicited_event_t)); 161693383Smdodd#endif 161721826Sjoerg PDQ_OS_MEMFREE(pdq, sizeof(pdq_t)); 161821826Sjoerg return NULL; 161921826Sjoerg } 162093383Smdodd dbp = pdq->pdq_dbp; 162121826Sjoerg 162293383Smdodd PDQ_PRINTF(("\nPDQ Descriptor Block = " PDQ_OS_PTR_FMT " (PA = 0x%x)\n", dbp, pdq->pdq_pa_descriptor_block)); 162393383Smdodd PDQ_PRINTF((" Receive Queue = " PDQ_OS_PTR_FMT "\n", dbp->pdqdb_receives)); 162493383Smdodd PDQ_PRINTF((" Transmit Queue = " PDQ_OS_PTR_FMT "\n", dbp->pdqdb_transmits)); 162593383Smdodd PDQ_PRINTF((" Host SMT Queue = " PDQ_OS_PTR_FMT "\n", dbp->pdqdb_host_smt)); 162693383Smdodd PDQ_PRINTF((" Command Response Queue = " PDQ_OS_PTR_FMT "\n", dbp->pdqdb_command_responses)); 162793383Smdodd PDQ_PRINTF((" Command Request Queue = " PDQ_OS_PTR_FMT "\n", dbp->pdqdb_command_requests)); 162821826Sjoerg PDQ_PRINTF(("PDQ Consumer Block = " PDQ_OS_PTR_FMT "\n", pdq->pdq_cbp)); 162921826Sjoerg 163021826Sjoerg /* 163121826Sjoerg * Zero out the descriptor block. Not really required but 163221826Sjoerg * it pays to be neat. This will also zero out the consumer 163321826Sjoerg * block, command pool, and buffer pointers for the receive 163421826Sjoerg * host_smt rings. 163521826Sjoerg */ 163693383Smdodd PDQ_OS_MEMZERO(dbp, sizeof(*dbp)); 163721826Sjoerg 163821826Sjoerg /* 163921826Sjoerg * Initialize the CSR references. 164021826Sjoerg * the DEFAA (FutureBus+) skips a longword between registers 164121826Sjoerg */ 164221826Sjoerg pdq_init_csrs(&pdq->pdq_csrs, bus, csr_base, pdq->pdq_type == PDQ_DEFAA ? 2 : 1); 164321826Sjoerg if (pdq->pdq_type == PDQ_DEFPA) 164421826Sjoerg pdq_init_pci_csrs(&pdq->pdq_pci_csrs, bus, csr_base, 1); 164521826Sjoerg 164693383Smdodd PDQ_PRINTF(("PDQ CSRs: BASE = " PDQ_OS_CSR_FMT "\n", pdq->pdq_csrs.csr_base)); 164793383Smdodd PDQ_PRINTF((" Port Reset = " PDQ_OS_CSR_FMT " [0x%08x]\n", 164821826Sjoerg pdq->pdq_csrs.csr_port_reset, PDQ_CSR_READ(&pdq->pdq_csrs, csr_port_reset))); 164993383Smdodd PDQ_PRINTF((" Host Data = " PDQ_OS_CSR_FMT " [0x%08x]\n", 165021826Sjoerg pdq->pdq_csrs.csr_host_data, PDQ_CSR_READ(&pdq->pdq_csrs, csr_host_data))); 165193383Smdodd PDQ_PRINTF((" Port Control = " PDQ_OS_CSR_FMT " [0x%08x]\n", 165221826Sjoerg pdq->pdq_csrs.csr_port_control, PDQ_CSR_READ(&pdq->pdq_csrs, csr_port_control))); 165393383Smdodd PDQ_PRINTF((" Port Data A = " PDQ_OS_CSR_FMT " [0x%08x]\n", 165421826Sjoerg pdq->pdq_csrs.csr_port_data_a, PDQ_CSR_READ(&pdq->pdq_csrs, csr_port_data_a))); 165593383Smdodd PDQ_PRINTF((" Port Data B = " PDQ_OS_CSR_FMT " [0x%08x]\n", 165621826Sjoerg pdq->pdq_csrs.csr_port_data_b, PDQ_CSR_READ(&pdq->pdq_csrs, csr_port_data_b))); 165793383Smdodd PDQ_PRINTF((" Port Status = " PDQ_OS_CSR_FMT " [0x%08x]\n", 165821826Sjoerg pdq->pdq_csrs.csr_port_status, PDQ_CSR_READ(&pdq->pdq_csrs, csr_port_status))); 165993383Smdodd PDQ_PRINTF((" Host Int Type 0 = " PDQ_OS_CSR_FMT " [0x%08x]\n", 166021826Sjoerg pdq->pdq_csrs.csr_host_int_type_0, PDQ_CSR_READ(&pdq->pdq_csrs, csr_host_int_type_0))); 166193383Smdodd PDQ_PRINTF((" Host Int Enable = " PDQ_OS_CSR_FMT " [0x%08x]\n", 166221826Sjoerg pdq->pdq_csrs.csr_host_int_enable, PDQ_CSR_READ(&pdq->pdq_csrs, csr_host_int_enable))); 166393383Smdodd PDQ_PRINTF((" Type 2 Producer = " PDQ_OS_CSR_FMT " [0x%08x]\n", 166421826Sjoerg pdq->pdq_csrs.csr_type_2_producer, PDQ_CSR_READ(&pdq->pdq_csrs, csr_type_2_producer))); 166593383Smdodd PDQ_PRINTF((" Command Response Producer = " PDQ_OS_CSR_FMT " [0x%08x]\n", 166621826Sjoerg pdq->pdq_csrs.csr_cmd_response_producer, PDQ_CSR_READ(&pdq->pdq_csrs, csr_cmd_response_producer))); 166793383Smdodd PDQ_PRINTF((" Command Request Producer = " PDQ_OS_CSR_FMT " [0x%08x]\n", 166821826Sjoerg pdq->pdq_csrs.csr_cmd_request_producer, PDQ_CSR_READ(&pdq->pdq_csrs, csr_cmd_request_producer))); 166993383Smdodd PDQ_PRINTF((" Host SMT Producer = " PDQ_OS_CSR_FMT " [0x%08x]\n", 167021826Sjoerg pdq->pdq_csrs.csr_host_smt_producer, PDQ_CSR_READ(&pdq->pdq_csrs, csr_host_smt_producer))); 167193383Smdodd PDQ_PRINTF((" Unsolicited Producer = " PDQ_OS_CSR_FMT " [0x%08x]\n", 167221826Sjoerg pdq->pdq_csrs.csr_unsolicited_producer, PDQ_CSR_READ(&pdq->pdq_csrs, csr_unsolicited_producer))); 167321826Sjoerg 167421826Sjoerg /* 167521826Sjoerg * Initialize the command information block 167621826Sjoerg */ 167793383Smdodd pdq->pdq_command_info.ci_request_bufstart = dbp->pdqdb_cmd_request_buf; 167893383Smdodd pdq->pdq_command_info.ci_pa_request_bufstart = PDQ_DB_BUSPA(pdq, pdq->pdq_command_info.ci_request_bufstart); 167993383Smdodd pdq->pdq_command_info.ci_pa_request_descriptors = PDQ_DB_BUSPA(pdq, dbp->pdqdb_command_requests); 168093383Smdodd PDQ_PRINTF(("PDQ Command Request Buffer = " PDQ_OS_PTR_FMT " (PA=0x%x)\n", 168193383Smdodd pdq->pdq_command_info.ci_request_bufstart, 168293383Smdodd pdq->pdq_command_info.ci_pa_request_bufstart)); 168393383Smdodd for (idx = 0; idx < sizeof(dbp->pdqdb_command_requests)/sizeof(dbp->pdqdb_command_requests[0]); idx++) { 168493383Smdodd pdq_txdesc_t *txd = &dbp->pdqdb_command_requests[idx]; 168521826Sjoerg 168693383Smdodd txd->txd_pa_lo = pdq->pdq_command_info.ci_pa_request_bufstart; 168721826Sjoerg txd->txd_eop = txd->txd_sop = 1; 168821826Sjoerg txd->txd_pa_hi = 0; 168921826Sjoerg } 169093383Smdodd PDQ_OS_DESC_PRESYNC(pdq, dbp->pdqdb_command_requests, 169193383Smdodd sizeof(dbp->pdqdb_command_requests)); 169221826Sjoerg 169393383Smdodd pdq->pdq_command_info.ci_response_bufstart = dbp->pdqdb_cmd_response_buf; 169493383Smdodd pdq->pdq_command_info.ci_pa_response_bufstart = PDQ_DB_BUSPA(pdq, pdq->pdq_command_info.ci_response_bufstart); 169593383Smdodd pdq->pdq_command_info.ci_pa_response_descriptors = PDQ_DB_BUSPA(pdq, dbp->pdqdb_command_responses); 169693383Smdodd PDQ_PRINTF(("PDQ Command Response Buffer = " PDQ_OS_PTR_FMT " (PA=0x%x)\n", 169793383Smdodd pdq->pdq_command_info.ci_response_bufstart, 169893383Smdodd pdq->pdq_command_info.ci_pa_response_bufstart)); 169993383Smdodd for (idx = 0; idx < sizeof(dbp->pdqdb_command_responses)/sizeof(dbp->pdqdb_command_responses[0]); idx++) { 170093383Smdodd pdq_rxdesc_t *rxd = &dbp->pdqdb_command_responses[idx]; 170193383Smdodd 170293383Smdodd rxd->rxd_pa_lo = pdq->pdq_command_info.ci_pa_response_bufstart; 170321826Sjoerg rxd->rxd_sop = 1; 170421826Sjoerg rxd->rxd_seg_cnt = 0; 170521826Sjoerg rxd->rxd_seg_len_lo = 0; 170693383Smdodd rxd->rxd_seg_len_hi = PDQ_SIZE_COMMAND_RESPONSE / 16; 170721826Sjoerg } 170893383Smdodd PDQ_OS_DESC_PRESYNC(pdq, dbp->pdqdb_command_responses, 170993383Smdodd sizeof(dbp->pdqdb_command_responses)); 171021826Sjoerg 171121826Sjoerg /* 171221826Sjoerg * Initialize the unsolicited event information block 171321826Sjoerg */ 171421826Sjoerg pdq->pdq_unsolicited_info.ui_free = PDQ_NUM_UNSOLICITED_EVENTS; 171593383Smdodd pdq->pdq_unsolicited_info.ui_pa_descriptors = PDQ_DB_BUSPA(pdq, dbp->pdqdb_unsolicited_events); 171693383Smdodd PDQ_PRINTF(("PDQ Unsolicit Event Buffer = " PDQ_OS_PTR_FMT " (PA=0x%x)\n", 171793383Smdodd pdq->pdq_unsolicited_info.ui_events, 171893383Smdodd pdq->pdq_unsolicited_info.ui_pa_bufstart)); 171993383Smdodd for (idx = 0; idx < sizeof(dbp->pdqdb_unsolicited_events)/sizeof(dbp->pdqdb_unsolicited_events[0]); idx++) { 172093383Smdodd pdq_rxdesc_t *rxd = &dbp->pdqdb_unsolicited_events[idx]; 172121826Sjoerg pdq_unsolicited_event_t *event = &pdq->pdq_unsolicited_info.ui_events[idx & (PDQ_NUM_UNSOLICITED_EVENTS-1)]; 172221826Sjoerg 172321826Sjoerg rxd->rxd_sop = 1; 172421826Sjoerg rxd->rxd_seg_cnt = 0; 172521826Sjoerg rxd->rxd_seg_len_hi = sizeof(pdq_unsolicited_event_t) / 16; 172621826Sjoerg rxd->rxd_pa_lo = pdq->pdq_unsolicited_info.ui_pa_bufstart + (const pdq_uint8_t *) event 172721826Sjoerg - (const pdq_uint8_t *) pdq->pdq_unsolicited_info.ui_events; 172821826Sjoerg rxd->rxd_pa_hi = 0; 172993383Smdodd PDQ_OS_UNSOL_EVENT_PRESYNC(pdq, event); 173021826Sjoerg } 173193383Smdodd PDQ_OS_DESC_PRESYNC(pdq, dbp->pdqdb_unsolicited_events, 173293383Smdodd sizeof(dbp->pdqdb_unsolicited_events)); 173393383Smdodd 173421826Sjoerg /* 173521826Sjoerg * Initialize the receive information blocks (normal and SMT). 173621826Sjoerg */ 173793383Smdodd pdq->pdq_rx_info.rx_buffers = pdq->pdq_receive_buffers; 173893383Smdodd pdq->pdq_rx_info.rx_free = PDQ_RING_MASK(dbp->pdqdb_receives); 173921826Sjoerg pdq->pdq_rx_info.rx_target = pdq->pdq_rx_info.rx_free - PDQ_RX_SEGCNT * 8; 174093383Smdodd pdq->pdq_rx_info.rx_pa_descriptors = PDQ_DB_BUSPA(pdq, dbp->pdqdb_receives); 174121826Sjoerg 174293383Smdodd pdq->pdq_host_smt_info.rx_buffers = pdq->pdq_host_smt_buffers; 174393383Smdodd pdq->pdq_host_smt_info.rx_free = PDQ_RING_MASK(dbp->pdqdb_host_smt); 174421826Sjoerg pdq->pdq_host_smt_info.rx_target = pdq->pdq_host_smt_info.rx_free - PDQ_RX_SEGCNT * 3; 174593383Smdodd pdq->pdq_host_smt_info.rx_pa_descriptors = PDQ_DB_BUSPA(pdq, dbp->pdqdb_host_smt); 174621826Sjoerg 174721826Sjoerg /* 174821826Sjoerg * Initialize the transmit information block. 174921826Sjoerg */ 175093383Smdodd dbp->pdqdb_tx_hdr[0] = PDQ_FDDI_PH0; 175193383Smdodd dbp->pdqdb_tx_hdr[1] = PDQ_FDDI_PH1; 175293383Smdodd dbp->pdqdb_tx_hdr[2] = PDQ_FDDI_PH2; 175393383Smdodd pdq->pdq_tx_info.tx_free = PDQ_RING_MASK(dbp->pdqdb_transmits); 175493383Smdodd pdq->pdq_tx_info.tx_hdrdesc.txd_seg_len = 3; 175521826Sjoerg pdq->pdq_tx_info.tx_hdrdesc.txd_sop = 1; 175693383Smdodd pdq->pdq_tx_info.tx_hdrdesc.txd_pa_lo = PDQ_DB_BUSPA(pdq, dbp->pdqdb_tx_hdr); 175793383Smdodd pdq->pdq_tx_info.tx_pa_descriptors = PDQ_DB_BUSPA(pdq, dbp->pdqdb_transmits); 175821826Sjoerg 175921826Sjoerg state = PDQ_PSTS_ADAPTER_STATE(PDQ_CSR_READ(&pdq->pdq_csrs, csr_port_status)); 176021826Sjoerg PDQ_PRINTF(("PDQ Adapter State = %s\n", pdq_adapter_states[state])); 176121826Sjoerg 176221826Sjoerg /* 176321826Sjoerg * Stop the PDQ if it is running and put it into a known state. 176421826Sjoerg */ 176521826Sjoerg state = pdq_stop(pdq); 176621826Sjoerg 176721826Sjoerg PDQ_PRINTF(("PDQ Adapter State = %s\n", pdq_adapter_states[state])); 176821826Sjoerg PDQ_ASSERT(state == PDQS_DMA_AVAILABLE); 176921826Sjoerg /* 177021826Sjoerg * If the adapter is not the state we expect, then the initialization 177121826Sjoerg * failed. Cleanup and exit. 177221826Sjoerg */ 177321826Sjoerg#if defined(PDQVERBOSE) 177421826Sjoerg if (state == PDQS_HALTED) { 177521826Sjoerg pdq_halt_code_t halt_code = PDQ_PSTS_HALT_ID(PDQ_CSR_READ(&pdq->pdq_csrs, csr_port_status)); 177621826Sjoerg printf("Halt code = %d (%s)\n", halt_code, pdq_halt_codes[halt_code]); 177721826Sjoerg if (halt_code == PDQH_DMA_ERROR && pdq->pdq_type == PDQ_DEFPA) 177821826Sjoerg PDQ_PRINTF(("PFI status = 0x%x, Host 0 Fatal Interrupt = 0x%x\n", 177921826Sjoerg PDQ_CSR_READ(&pdq->pdq_pci_csrs, csr_pfi_status), 178021826Sjoerg PDQ_CSR_READ(&pdq->pdq_csrs, csr_host_int_type_0) & PDQ_HOST_INT_FATAL_ERROR)); 178121826Sjoerg } 178221826Sjoerg#endif 178321826Sjoerg if (state == PDQS_RESET || state == PDQS_HALTED || state == PDQS_UPGRADE) 178421826Sjoerg goto cleanup_and_return; 178521826Sjoerg 178621826Sjoerg PDQ_PRINTF(("PDQ Hardware Address = %02x-%02x-%02x-%02x-%02x-%02x\n", 178721826Sjoerg pdq->pdq_hwaddr.lanaddr_bytes[0], pdq->pdq_hwaddr.lanaddr_bytes[1], 178821826Sjoerg pdq->pdq_hwaddr.lanaddr_bytes[2], pdq->pdq_hwaddr.lanaddr_bytes[3], 178921826Sjoerg pdq->pdq_hwaddr.lanaddr_bytes[4], pdq->pdq_hwaddr.lanaddr_bytes[5])); 179021826Sjoerg PDQ_PRINTF(("PDQ Firmware Revision = %c%c%c%c\n", 179121826Sjoerg pdq->pdq_fwrev.fwrev_bytes[0], pdq->pdq_fwrev.fwrev_bytes[1], 179221826Sjoerg pdq->pdq_fwrev.fwrev_bytes[2], pdq->pdq_fwrev.fwrev_bytes[3])); 179321826Sjoerg PDQ_PRINTF(("PDQ Chip Revision = ")); 179421826Sjoerg switch (pdq->pdq_chip_rev) { 179521826Sjoerg case PDQ_CHIP_REV_A_B_OR_C: PDQ_PRINTF(("Rev C or below")); break; 179621826Sjoerg case PDQ_CHIP_REV_D: PDQ_PRINTF(("Rev D")); break; 179721826Sjoerg case PDQ_CHIP_REV_E: PDQ_PRINTF(("Rev E")); break; 179821826Sjoerg default: PDQ_PRINTF(("Unknown Rev %d", (int) pdq->pdq_chip_rev)); 179921826Sjoerg } 180021826Sjoerg PDQ_PRINTF(("\n")); 180121826Sjoerg 180221826Sjoerg return pdq; 180321826Sjoerg} 1804