Annotation of sys/dev/pci/if_tht.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: if_tht.c,v 1.108 2007/07/22 03:54:15 dlg Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 2007 David Gwynne <dlg@openbsd.org>
! 5: *
! 6: * Permission to use, copy, modify, and distribute this software for any
! 7: * purpose with or without fee is hereby granted, provided that the above
! 8: * copyright notice and this permission notice appear in all copies.
! 9: *
! 10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
! 11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
! 12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
! 13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
! 14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
! 15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
! 16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
! 17: */
! 18:
! 19: /*
! 20: * Driver for the Tehuti TN30xx multi port 10Gb Ethernet chipsets,
! 21: * see http://www.tehutinetworks.net/.
! 22: *
! 23: * This driver was made possible because Tehuti networks provided
! 24: * hardware and documentation. Thanks!
! 25: */
! 26:
! 27: #include "bpfilter.h"
! 28:
! 29: #include <sys/param.h>
! 30: #include <sys/systm.h>
! 31: #include <sys/sockio.h>
! 32: #include <sys/mbuf.h>
! 33: #include <sys/kernel.h>
! 34: #include <sys/socket.h>
! 35: #include <sys/malloc.h>
! 36: #include <sys/device.h>
! 37: #include <sys/proc.h>
! 38: #include <sys/queue.h>
! 39: #include <sys/rwlock.h>
! 40:
! 41: #include <machine/bus.h>
! 42:
! 43: #include <dev/pci/pcireg.h>
! 44: #include <dev/pci/pcivar.h>
! 45: #include <dev/pci/pcidevs.h>
! 46:
! 47: #include <net/if.h>
! 48: #include <net/if_dl.h>
! 49: #include <net/if_media.h>
! 50: #include <net/if_types.h>
! 51:
! 52: #if NBPFILTER > 0
! 53: #include <net/bpf.h>
! 54: #endif
! 55:
! 56: #ifdef INET
! 57: #include <netinet/in.h>
! 58: #include <netinet/if_ether.h>
! 59: #endif
! 60:
! 61: #ifdef THT_DEBUG
! 62: #define THT_D_FIFO (1<<0)
! 63: #define THT_D_TX (1<<1)
! 64: #define THT_D_RX (1<<2)
! 65: #define THT_D_INTR (1<<3)
! 66:
! 67: int thtdebug = THT_D_TX | THT_D_RX | THT_D_INTR;
! 68:
! 69: #define DPRINTF(l, f...) do { if (thtdebug & (l)) printf(f); } while (0)
! 70: #else
! 71: #define DPRINTF(l, f...)
! 72: #endif
! 73:
! 74: /* registers */
! 75:
! 76: #define THT_PCI_BAR 0x10
! 77:
! 78: #define _Q(_q) ((_q) * 4)
! 79:
! 80: /* General Configuration */
! 81: #define THT_REG_END_SEL 0x5448 /* PCI Endian Select */
! 82: #define THT_REG_CLKPLL 0x5000
! 83: #define THT_REG_CLKPLL_PLLLK (1<<9) /* PLL is locked */
! 84: #define THT_REG_CLKPLL_RSTEND (1<<8) /* Reset ended */
! 85: #define THT_REG_CLKPLL_TXF_DIS (1<<3) /* TX Free disabled */
! 86: #define THT_REG_CLKPLL_VNT_STOP (1<<2) /* VENETO Stop */
! 87: #define THT_REG_CLKPLL_PLLRST (1<<1) /* PLL Reset */
! 88: #define THT_REG_CLKPLL_SFTRST (1<<0) /* Software Reset */
! 89: /* Descriptors and FIFO Registers */
! 90: #define THT_REG_TXT_CFG0(_q) (0x4040 + _Q(_q)) /* CFG0 TX Task queues */
! 91: #define THT_REG_RXF_CFG0(_q) (0x4050 + _Q(_q)) /* CFG0 RX Free queues */
! 92: #define THT_REG_RXD_CFG0(_q) (0x4060 + _Q(_q)) /* CFG0 RX DSC queues */
! 93: #define THT_REG_TXF_CFG0(_q) (0x4070 + _Q(_q)) /* CFG0 TX Free queues */
! 94: #define THT_REG_TXT_CFG1(_q) (0x4000 + _Q(_q)) /* CFG1 TX Task queues */
! 95: #define THT_REG_RXF_CFG1(_q) (0x4010 + _Q(_q)) /* CFG1 RX Free queues */
! 96: #define THT_REG_RXD_CFG1(_q) (0x4020 + _Q(_q)) /* CFG1 RX DSC queues */
! 97: #define THT_REG_TXF_CFG1(_q) (0x4030 + _Q(_q)) /* CFG1 TX Free queues */
! 98: #define THT_REG_TXT_RPTR(_q) (0x40c0 + _Q(_q)) /* TX Task read ptr */
! 99: #define THT_REG_RXF_RPTR(_q) (0x40d0 + _Q(_q)) /* RX Free read ptr */
! 100: #define THT_REG_RXD_RPTR(_q) (0x40e0 + _Q(_q)) /* RX DSC read ptr */
! 101: #define THT_REG_TXF_RPTR(_q) (0x40f0 + _Q(_q)) /* TX Free read ptr */
! 102: #define THT_REG_TXT_WPTR(_q) (0x4080 + _Q(_q)) /* TX Task write ptr */
! 103: #define THT_REG_RXF_WPTR(_q) (0x4090 + _Q(_q)) /* RX Free write ptr */
! 104: #define THT_REG_RXD_WPTR(_q) (0x40a0 + _Q(_q)) /* RX DSC write ptr */
! 105: #define THT_REG_TXF_WPTR(_q) (0x40b0 + _Q(_q)) /* TX Free write ptr */
! 106: #define THT_REG_HTB_ADDR 0x4100 /* HTB Addressing Mechanism enable */
! 107: #define THT_REG_HTB_ADDR_HI 0x4110 /* High HTB Address */
! 108: #define THT_REG_HTB_ST_TMR 0x3290 /* HTB Timer */
! 109: #define THT_REG_RDINTCM(_q) (0x5120 + _Q(_q)) /* RX DSC Intr Coalescing */
! 110: #define THT_REG_RDINTCM_PKT_TH(_c) ((_c)<<20) /* pkt count threshold */
! 111: #define THT_REG_RDINTCM_RXF_TH(_c) ((_c)<<16) /* rxf intr req thresh */
! 112: #define THT_REG_RDINTCM_COAL_RC (1<<15) /* coalescing timer recharge */
! 113: #define THT_REG_RDINTCM_COAL(_c) (_c) /* coalescing timer */
! 114: #define THT_REG_TDINTCM(_q) (0x5130 + _Q(_q)) /* TX DSC Intr Coalescing */
! 115: #define THT_REG_TDINTCM_PKT_TH(_c) ((_c)<<20) /* pkt count threshold */
! 116: #define THT_REG_TDINTCM_COAL_RC (1<<15) /* coalescing timer recharge */
! 117: #define THT_REG_TDINTCM_COAL(_c) (_c) /* coalescing timer */
! 118: /* 10G Ethernet MAC */
! 119: #define THT_REG_10G_REV 0x6000 /* Revision */
! 120: #define THT_REG_10G_SCR 0x6004 /* Scratch */
! 121: #define THT_REG_10G_CTL 0x6008 /* Control/Status */
! 122: #define THT_REG_10G_CTL_CMD_FRAME_EN (1<<13) /* cmd frame enable */
! 123: #define THT_REG_10G_CTL_SW_RESET (1<<12) /* sw reset */
! 124: #define THT_REG_10G_CTL_STATS_AUTO_CLR (1<<11) /* auto clear statistics */
! 125: #define THT_REG_10G_CTL_LOOPBACK (1<<10) /* enable loopback */
! 126: #define THT_REG_10G_CTL_TX_ADDR_INS (1<<9) /* set mac on tx */
! 127: #define THT_REG_10G_CTL_PAUSE_IGNORE (1<<8) /* ignore pause */
! 128: #define THT_REG_10G_CTL_PAUSE_FWD (1<<7) /* forward pause */
! 129: #define THT_REG_10G_CTL_CRC_FWD (1<<6) /* crc forward */
! 130: #define THT_REG_10G_CTL_PAD (1<<5) /* frame padding */
! 131: #define THT_REG_10G_CTL_PROMISC (1<<4) /* promiscuous mode */
! 132: #define THT_REG_10G_CTL_WAN_MODE (1<<3) /* WAN mode */
! 133: #define THT_REG_10G_CTL_RX_EN (1<<1) /* RX enable */
! 134: #define THT_REG_10G_CTL_TX_EN (1<<0) /* TX enable */
! 135: #define THT_REG_10G_FRM_LEN 0x6014 /* Frame Length */
! 136: #define THT_REG_10G_PAUSE 0x6018 /* Pause Quanta */
! 137: #define THT_REG_10G_RX_SEC 0x601c /* RX Section */
! 138: #define THT_REG_10G_TX_SEC 0x6020 /* TX Section */
! 139: #define THT_REG_10G_SEC_AVAIL(_t) (_t) /* section available thresh*/
! 140: #define THT_REG_10G_SEC_EMPTY(_t) ((_t)<<16) /* section empty avail */
! 141: #define THT_REG_10G_RFIFO_AEF 0x6024 /* RX FIFO Almost Empty/Full */
! 142: #define THT_REG_10G_TFIFO_AEF 0x6028 /* TX FIFO Almost Empty/Full */
! 143: #define THT_REG_10G_FIFO_AE(_t) (_t) /* almost empty */
! 144: #define THT_REG_10G_FIFO_AF(_t) ((_t)<<16) /* almost full */
! 145: #define THT_REG_10G_SM_STAT 0x6030 /* MDIO Status */
! 146: #define THT_REG_10G_SM_CMD 0x6034 /* MDIO Command */
! 147: #define THT_REG_10G_SM_DAT 0x6038 /* MDIO Data */
! 148: #define THT_REG_10G_SM_ADD 0x603c /* MDIO Address */
! 149: #define THT_REG_10G_STAT 0x6040 /* Status */
! 150: /* Statistic Counters */
! 151: /* XXX todo */
! 152: /* Status Registers */
! 153: #define THT_REG_MAC_LNK_STAT 0x0200 /* Link Status */
! 154: #define THT_REG_MAC_LNK_STAT_DIS (1<<4) /* Mac Stats read disable */
! 155: #define THT_REG_MAC_LNK_STAT_LINK (1<<2) /* Link State */
! 156: #define THT_REG_MAC_LNK_STAT_REM_FAULT (1<<1) /* Remote Fault */
! 157: #define THT_REG_MAC_LNK_STAT_LOC_FAULT (1<<0) /* Local Fault */
! 158: /* Interrupt Registers */
! 159: #define THT_REG_ISR 0x5100 /* Interrupt Status */
! 160: #define THT_REG_ISR_LINKCHG(_p) (1<<(27+(_p))) /* link changed */
! 161: #define THT_REG_ISR_GPIO (1<<26) /* GPIO */
! 162: #define THT_REG_ISR_RFRSH (1<<25) /* DDR Refresh */
! 163: #define THT_REG_ISR_SWI (1<<23) /* software interrupt */
! 164: #define THT_REG_ISR_RXF(_q) (1<<(19+(_q))) /* rx free fifo */
! 165: #define THT_REG_ISR_TXF(_q) (1<<(15+(_q))) /* tx free fifo */
! 166: #define THT_REG_ISR_RXD(_q) (1<<(11+(_q))) /* rx desc fifo */
! 167: #define THT_REG_ISR_TMR(_t) (1<<(6+(_t))) /* timer */
! 168: #define THT_REG_ISR_VNT (1<<5) /* optistrata */
! 169: #define THT_REG_ISR_RxFL (1<<4) /* RX Full */
! 170: #define THT_REG_ISR_TR (1<<2) /* table read */
! 171: #define THT_REG_ISR_PCIE_LNK_INT (1<<1) /* pcie link fail */
! 172: #define THT_REG_ISR_GPLE_CLR (1<<0) /* pcie timeout */
! 173: #define THT_FMT_ISR "\020" "\035LINKCHG1" "\034LINKCHG0" \
! 174: "\033GPIO" "\032RFRSH" "\030SWI" \
! 175: "\027RXF3" "\026RXF2" "\025RXF1" \
! 176: "\024RXF0" "\023TXF3" "\022TXF2" \
! 177: "\021TXF1" "\020TXF0" "\017RXD3" \
! 178: "\016RXD2" "\015RXD1" "\014RXD0" \
! 179: "\012TMR3" "\011TMR2" "\010TMR1" \
! 180: "\007TMR0" "\006VNT" "\005RxFL" \
! 181: "\003TR" "\002PCI_LNK_INT" \
! 182: "\001GPLE_CLR"
! 183: #define THT_REG_ISR_GTI 0x5080 /* GTI Interrupt Status */
! 184: #define THT_REG_IMR 0x5110 /* Interrupt Mask */
! 185: #define THT_REG_IMR_LINKCHG(_p) (1<<(27+(_p))) /* link changed */
! 186: #define THT_REG_IMR_GPIO (1<<26) /* GPIO */
! 187: #define THT_REG_IMR_RFRSH (1<<25) /* DDR Refresh */
! 188: #define THT_REG_IMR_SWI (1<<23) /* software interrupt */
! 189: #define THT_REG_IMR_RXF(_q) (1<<(19+(_q))) /* rx free fifo */
! 190: #define THT_REG_IMR_TXF(_q) (1<<(15+(_q))) /* tx free fifo */
! 191: #define THT_REG_IMR_RXD(_q) (1<<(11+(_q))) /* rx desc fifo */
! 192: #define THT_REG_IMR_TMR(_t) (1<<(6+(_t))) /* timer */
! 193: #define THT_REG_IMR_VNT (1<<5) /* optistrata */
! 194: #define THT_REG_IMR_RxFL (1<<4) /* RX Full */
! 195: #define THT_REG_IMR_TR (1<<2) /* table read */
! 196: #define THT_REG_IMR_PCIE_LNK_INT (1<<1) /* pcie link fail */
! 197: #define THT_REG_IMR_GPLE_CLR (1<<0) /* pcie timeout */
! 198: #define THT_REG_IMR_GTI 0x5090 /* GTI Interrupt Mask */
! 199: #define THT_REG_ISR_MSK 0x5140 /* ISR Masked */
! 200: /* Global Counters */
! 201: /* XXX todo */
! 202: /* DDR2 SDRAM Controller Registers */
! 203: /* XXX TBD */
! 204: /* EEPROM Registers */
! 205: /* XXX todo */
! 206: /* Init arbitration and status registers */
! 207: #define THT_REG_INIT_SEMAPHORE 0x5170 /* Init Semaphore */
! 208: #define THT_REG_INIT_STATUS 0x5180 /* Init Status */
! 209: /* PCI Credits Registers */
! 210: /* XXX todo */
! 211: /* TX Arbitration Registers */
! 212: #define THT_REG_TXTSK_PR(_q) (0x41b0 + _Q(_q)) /* TX Queue Priority */
! 213: /* RX Part Registers */
! 214: #define THT_REG_RX_FLT 0x1240 /* RX Filter Configuration */
! 215: #define THT_REG_RX_FLT_ATXER (1<<15) /* accept with xfer err */
! 216: #define THT_REG_RX_FLT_ATRM (1<<14) /* accept with term err */
! 217: #define THT_REG_RX_FLT_AFTSQ (1<<13) /* accept with fault seq */
! 218: #define THT_REG_RX_FLT_OSEN (1<<12) /* enable pkts */
! 219: #define THT_REG_RX_FLT_APHER (1<<11) /* accept with phy err */
! 220: #define THT_REG_RX_FLT_TXFC (1<<10) /* TX flow control */
! 221: #define THT_REG_RX_FLT_FDA (1<<8) /* filter direct address */
! 222: #define THT_REG_RX_FLT_AOF (1<<7) /* accept overflow frame */
! 223: #define THT_REG_RX_FLT_ACF (1<<6) /* accept control frame */
! 224: #define THT_REG_RX_FLT_ARUNT (1<<5) /* accept runt */
! 225: #define THT_REG_RX_FLT_ACRC (1<<4) /* accept crc error */
! 226: #define THT_REG_RX_FLT_AM (1<<3) /* accept multicast */
! 227: #define THT_REG_RX_FLT_AB (1<<2) /* accept broadcast */
! 228: #define THT_REG_RX_FLT_PRM_MASK 0x3 /* promiscuous mode */
! 229: #define THT_REG_RX_FLT_PRM_NORMAL 0x0 /* normal mode */
! 230: #define THT_REG_RX_FLT_PRM_ALL 0x1 /* pass all incoming frames */
! 231: #define THT_REG_RX_MAX_FRAME 0x12c0 /* Max Frame Size */
! 232: #define THT_REG_RX_UNC_MAC0 0x1250 /* MAC Address low word */
! 233: #define THT_REG_RX_UNC_MAC1 0x1260 /* MAC Address mid word */
! 234: #define THT_REG_RX_UNC_MAC2 0x1270 /* MAC Address high word */
! 235: #define THT_REG_RX_MAC_MCST0(_m) (0x1a80 + (_m)*8)
! 236: #define THT_REG_RX_MAC_MCST1(_m) (0x1a84 + (_m)*8)
! 237: #define THT_REG_RX_MAC_MCST_CNT 15
! 238: #define THT_REG_RX_MCST_HASH 0x1a00 /* imperfect multicast filter hash */
! 239: #define THT_REG_RX_MCST_HASH_SIZE (256 / NBBY)
! 240: /* OptiStrata Debug Registers */
! 241: #define THT_REG_VPC 0x2300 /* Program Counter */
! 242: #define THT_REG_VLI 0x2310 /* Last Interrupt */
! 243: #define THT_REG_VIC 0x2320 /* Interrupts Count */
! 244: #define THT_REG_VTMR 0x2330 /* Timer */
! 245: #define THT_REG_VGLB 0x2340 /* Global */
! 246: /* SW Reset Registers */
! 247: #define THT_REG_RST_PRT 0x7000 /* Reset Port */
! 248: #define THT_REG_RST_PRT_ACTIVE 0x1 /* port reset is active */
! 249: #define THT_REG_DIS_PRT 0x7010 /* Disable Port */
! 250: #define THT_REG_RST_QU_0 0x7020 /* Reset Queue 0 */
! 251: #define THT_REG_RST_QU_1 0x7028 /* Reset Queue 1 */
! 252: #define THT_REG_DIS_QU_0 0x7030 /* Disable Queue 0 */
! 253: #define THT_REG_DIS_QU_1 0x7038 /* Disable Queue 1 */
! 254:
! 255: #define THT_PORT_SIZE 0x8000
! 256: #define THT_PORT_REGION(_p) ((_p) * THT_PORT_SIZE)
! 257: #define THT_NQUEUES 4
! 258:
! 259: #define THT_FIFO_ALIGN 4096
! 260: #define THT_FIFO_SIZE_4k 0x0
! 261: #define THT_FIFO_SIZE_8k 0x1
! 262: #define THT_FIFO_SIZE_16k 0x2
! 263: #define THT_FIFO_SIZE_32k 0x3
! 264: #define THT_FIFO_SIZE(_r) (4096 * (1<<(_r)))
! 265: #define THT_FIFO_GAP 8 /* keep 8 bytes between ptrs */
! 266: #define THT_FIFO_PTR_MASK 0x00007ff8 /* rptr/wptr mask */
! 267:
! 268: #define THT_FIFO_DESC_LEN 208 /* a descriptor cant be bigger than this */
! 269:
! 270: #define THT_IMR_DOWN(_p) (THT_REG_IMR_LINKCHG(_p))
! 271: #define THT_IMR_UP(_p) (THT_REG_IMR_LINKCHG(_p) | \
! 272: THT_REG_IMR_RXF(0) | THT_REG_IMR_TXF(0) | \
! 273: THT_REG_IMR_RXD(0))
! 274:
! 275: /* hardware structures (we're using the 64 bit variants) */
! 276:
! 277: /* physical buffer descriptor */
! 278: struct tht_pbd {
! 279: u_int32_t addr_lo;
! 280: u_int32_t addr_hi;
! 281: u_int32_t len;
! 282: } __packed;
! 283: #define THT_PBD_PKTLEN (64 * 1024)
! 284:
! 285: /* rx free fifo */
! 286: struct tht_rx_free {
! 287: u_int16_t bc; /* buffer count (0:4) */
! 288: u_int16_t type;
! 289:
! 290: u_int64_t uid;
! 291:
! 292: /* followed by a pdb list */
! 293: } __packed;
! 294: #define THT_RXF_TYPE 1
! 295: #define THT_RXF_1ST_PDB_LEN 128
! 296: #define THT_RXF_SGL_LEN ((THT_FIFO_DESC_LEN - \
! 297: sizeof(struct tht_rx_free)) / \
! 298: sizeof(struct tht_pbd))
! 299:
! 300: /* rx descriptor */
! 301: struct tht_rx_desc {
! 302: u_int32_t flags;
! 303: #define THT_RXD_FLAGS_BC(_f) ((_f) & 0x1f) /* buffer count */
! 304: #define THT_RXD_FLAGS_RXFQ(_f) (((_f)>>8) & 0x3) /* rxf queue id */
! 305: #define THT_RXD_FLAGS_TO (1<<15)
! 306: #define THT_RXD_FLAGS_TYPE(_f) (((_f)>>16) & 0xf) /* desc type */
! 307: #define THT_RXD_FLAGS_OVF (1<<21) /* overflow error */
! 308: #define THT_RXD_FLAGS_RUNT (1<<22) /* runt error */
! 309: #define THT_RXD_FLAGS_CRC (1<<23) /* crc error */
! 310: #define THT_RXD_FLAGS_UDPCS (1<<24) /* udp checksum error */
! 311: #define THT_RXD_FLAGS_TCPCS (1<<25) /* tcp checksum error */
! 312: #define THT_RXD_FLAGS_IPCS (1<<26) /* ip checksum error */
! 313: #define THT_RXD_FLAGS_PKT_ID 0x70000000
! 314: #define THT_RXD_FLAGS_PKT_ID_NONIP 0x00000000
! 315: #define THT_RXD_FLAGS_PKT_ID_TCP4 0x10000000
! 316: #define THT_RXD_FLAGS_PKT_ID_UDP4 0x20000000
! 317: #define THT_RXD_FLAGS_PKT_ID_IPV4 0x30000000
! 318: #define THT_RXD_FLAGS_PKT_ID_TCP6 0x50000000
! 319: #define THT_RXD_FLAGS_PKT_ID_UDP6 0x60000000
! 320: #define THT_RXD_FLAGS_PKT_ID_IPV6 0x70000000
! 321: #define THT_RXD_FLAGS_VTAG (1<<31)
! 322: u_int16_t len;
! 323: u_int16_t vlan;
! 324: #define THT_RXD_VLAN_ID(_v) ((_v) & 0xfff)
! 325: #define THT_RXD_VLAN_CFI (1<<12)
! 326: #define THT_RXD_VLAN_PRI(_v) ((_v) & 0x7) >> 13)
! 327:
! 328: u_int64_t uid;
! 329: } __packed;
! 330: #define THT_RXD_TYPE 2
! 331:
! 332: /* rx decriptor type 3: data chain instruction */
! 333: struct tht_rx_desc_dc {
! 334: /* preceded by tht_rx_desc */
! 335:
! 336: u_int16_t cd_offset;
! 337: u_int16_t flags;
! 338:
! 339: u_int8_t data[4];
! 340: } __packed;
! 341: #define THT_RXD_TYPE_DC 3
! 342:
! 343: /* rx descriptor type 4: rss (recv side scaling) information */
! 344: struct tht_rx_desc_rss {
! 345: /* preceded by tht_rx_desc */
! 346:
! 347: u_int8_t rss_hft;
! 348: u_int8_t rss_type;
! 349: u_int8_t rss_tcpu;
! 350: u_int8_t reserved;
! 351:
! 352: u_int32_t rss_hash;
! 353: } __packed;
! 354: #define THT_RXD_TYPE_RSS 4
! 355:
! 356: /* tx task fifo */
! 357: struct tht_tx_task {
! 358: u_int32_t flags;
! 359: #define THT_TXT_FLAGS_BC(_f) (_f) /* buffer count */
! 360: #define THT_TXT_FLAGS_UDPCS (1<<5) /* udp checksum */
! 361: #define THT_TXT_FLAGS_TCPCS (1<<6) /* tcp checksum */
! 362: #define THT_TXT_FLAGS_IPCS (1<<7) /* ip checksum */
! 363: #define THT_TXT_FLAGS_VTAG (1<<8) /* insert vlan tag */
! 364: #define THT_TXT_FLAGS_LGSND (1<<9) /* tcp large send enabled */
! 365: #define THT_TXT_FLAGS_FRAG (1<<10) /* ip fragmentation enabled */
! 366: #define THT_TXT_FLAGS_CFI (1<<12) /* canonical format indicator */
! 367: #define THT_TXT_FLAGS_PRIO(_f) ((_f)<<13) /* vlan priority */
! 368: #define THT_TXT_FLAGS_VLAN(_f) ((_f)<<20) /* vlan id */
! 369: u_int16_t mss_mtu;
! 370: u_int16_t len;
! 371:
! 372: u_int64_t uid;
! 373:
! 374: /* followed by a pbd list */
! 375: } __packed;
! 376: #define THT_TXT_TYPE (3<<16)
! 377: #define THT_TXT_SGL_LEN ((THT_FIFO_DESC_LEN - \
! 378: sizeof(struct tht_tx_task)) / \
! 379: sizeof(struct tht_pbd))
! 380:
! 381: /* tx free fifo */
! 382: struct tht_tx_free {
! 383: u_int32_t status;
! 384:
! 385: u_int64_t uid;
! 386:
! 387: u_int32_t pad;
! 388: } __packed;
! 389:
! 390: /* pci controller autoconf glue */
! 391:
! 392: struct thtc_softc {
! 393: struct device sc_dev;
! 394:
! 395: bus_dma_tag_t sc_dmat;
! 396:
! 397: bus_space_tag_t sc_memt;
! 398: bus_space_handle_t sc_memh;
! 399: bus_size_t sc_mems;
! 400: };
! 401:
! 402: int thtc_match(struct device *, void *, void *);
! 403: void thtc_attach(struct device *, struct device *, void *);
! 404: int thtc_print(void *, const char *);
! 405:
! 406: struct cfattach thtc_ca = {
! 407: sizeof(struct thtc_softc), thtc_match, thtc_attach
! 408: };
! 409:
! 410: struct cfdriver thtc_cd = {
! 411: NULL, "thtc", DV_DULL
! 412: };
! 413:
! 414: /* glue between the controller and the port */
! 415:
! 416: struct tht_attach_args {
! 417: int taa_port;
! 418:
! 419: struct pci_attach_args *taa_pa;
! 420: pci_intr_handle_t taa_ih;
! 421: };
! 422:
! 423: /* tht itself */
! 424:
! 425: struct tht_dmamem {
! 426: bus_dmamap_t tdm_map;
! 427: bus_dma_segment_t tdm_seg;
! 428: size_t tdm_size;
! 429: caddr_t tdm_kva;
! 430: };
! 431: #define THT_DMA_MAP(_tdm) ((_tdm)->tdm_map)
! 432: #define THT_DMA_DVA(_tdm) ((_tdm)->tdm_map->dm_segs[0].ds_addr)
! 433: #define THT_DMA_KVA(_tdm) ((void *)(_tdm)->tdm_kva)
! 434:
! 435: struct tht_fifo_desc {
! 436: bus_size_t tfd_cfg0;
! 437: bus_size_t tfd_cfg1;
! 438: bus_size_t tfd_rptr;
! 439: bus_size_t tfd_wptr;
! 440: u_int32_t tfd_size;
! 441: int tfd_write;
! 442: };
! 443: #define THT_FIFO_PRE_SYNC(_d) ((_d)->tfd_write ? \
! 444: BUS_DMASYNC_PREWRITE : \
! 445: BUS_DMASYNC_PREREAD)
! 446: #define THT_FIFO_POST_SYNC(_d) ((_d)->tfd_write ? \
! 447: BUS_DMASYNC_POSTWRITE : \
! 448: BUS_DMASYNC_POSTREAD)
! 449:
! 450: struct tht_fifo {
! 451: struct tht_fifo_desc *tf_desc;
! 452: struct tht_dmamem *tf_mem;
! 453: int tf_len;
! 454: int tf_rptr;
! 455: int tf_wptr;
! 456: int tf_ready;
! 457: };
! 458:
! 459: struct tht_pkt {
! 460: u_int64_t tp_id;
! 461:
! 462: bus_dmamap_t tp_dmap;
! 463: struct mbuf *tp_m;
! 464:
! 465: TAILQ_ENTRY(tht_pkt) tp_link;
! 466: };
! 467:
! 468: struct tht_pkt_list {
! 469: struct tht_pkt *tpl_pkts;
! 470: TAILQ_HEAD(, tht_pkt) tpl_free;
! 471: TAILQ_HEAD(, tht_pkt) tpl_used;
! 472: };
! 473:
! 474: struct tht_softc {
! 475: struct device sc_dev;
! 476: struct thtc_softc *sc_thtc;
! 477: int sc_port;
! 478:
! 479: void *sc_ih;
! 480:
! 481: bus_space_handle_t sc_memh;
! 482:
! 483: struct arpcom sc_ac;
! 484: struct ifmedia sc_media;
! 485:
! 486: u_int16_t sc_lladdr[3];
! 487:
! 488: struct tht_pkt_list sc_tx_list;
! 489: struct tht_pkt_list sc_rx_list;
! 490:
! 491: struct tht_fifo sc_txt;
! 492: struct tht_fifo sc_rxf;
! 493: struct tht_fifo sc_rxd;
! 494: struct tht_fifo sc_txf;
! 495:
! 496: u_int32_t sc_imr;
! 497:
! 498: struct rwlock sc_lock;
! 499: };
! 500:
! 501: int tht_match(struct device *, void *, void *);
! 502: void tht_attach(struct device *, struct device *, void *);
! 503: void tht_mountroot(void *);
! 504: int tht_intr(void *);
! 505:
! 506: struct cfattach tht_ca = {
! 507: sizeof(struct tht_softc), tht_match, tht_attach
! 508: };
! 509:
! 510: struct cfdriver tht_cd = {
! 511: NULL, "tht", DV_IFNET
! 512: };
! 513:
! 514: /* pkts */
! 515: int tht_pkt_alloc(struct tht_softc *,
! 516: struct tht_pkt_list *, int, int);
! 517: void tht_pkt_free(struct tht_softc *,
! 518: struct tht_pkt_list *);
! 519: void tht_pkt_put(struct tht_pkt_list *, struct tht_pkt *);
! 520: struct tht_pkt *tht_pkt_get(struct tht_pkt_list *);
! 521: struct tht_pkt *tht_pkt_used(struct tht_pkt_list *);
! 522:
! 523: /* fifos */
! 524:
! 525: struct tht_fifo_desc tht_txt_desc = {
! 526: THT_REG_TXT_CFG0(0),
! 527: THT_REG_TXT_CFG1(0),
! 528: THT_REG_TXT_RPTR(0),
! 529: THT_REG_TXT_WPTR(0),
! 530: THT_FIFO_SIZE_16k,
! 531: 1
! 532: };
! 533:
! 534: struct tht_fifo_desc tht_rxf_desc = {
! 535: THT_REG_RXF_CFG0(0),
! 536: THT_REG_RXF_CFG1(0),
! 537: THT_REG_RXF_RPTR(0),
! 538: THT_REG_RXF_WPTR(0),
! 539: THT_FIFO_SIZE_16k,
! 540: 1
! 541: };
! 542:
! 543: struct tht_fifo_desc tht_rxd_desc = {
! 544: THT_REG_RXD_CFG0(0),
! 545: THT_REG_RXD_CFG1(0),
! 546: THT_REG_RXD_RPTR(0),
! 547: THT_REG_RXD_WPTR(0),
! 548: THT_FIFO_SIZE_16k,
! 549: 0
! 550: };
! 551:
! 552: struct tht_fifo_desc tht_txf_desc = {
! 553: THT_REG_TXF_CFG0(0),
! 554: THT_REG_TXF_CFG1(0),
! 555: THT_REG_TXF_RPTR(0),
! 556: THT_REG_TXF_WPTR(0),
! 557: THT_FIFO_SIZE_4k,
! 558: 0
! 559: };
! 560:
! 561: int tht_fifo_alloc(struct tht_softc *, struct tht_fifo *,
! 562: struct tht_fifo_desc *);
! 563: void tht_fifo_free(struct tht_softc *, struct tht_fifo *);
! 564:
! 565: size_t tht_fifo_readable(struct tht_softc *,
! 566: struct tht_fifo *);
! 567: size_t tht_fifo_writable(struct tht_softc *,
! 568: struct tht_fifo *);
! 569: void tht_fifo_pre(struct tht_softc *,
! 570: struct tht_fifo *);
! 571: void tht_fifo_read(struct tht_softc *, struct tht_fifo *,
! 572: void *, size_t);
! 573: void tht_fifo_write(struct tht_softc *, struct tht_fifo *,
! 574: void *, size_t);
! 575: void tht_fifo_write_dmap(struct tht_softc *,
! 576: struct tht_fifo *, bus_dmamap_t);
! 577: void tht_fifo_write_pad(struct tht_softc *,
! 578: struct tht_fifo *, int);
! 579: void tht_fifo_post(struct tht_softc *,
! 580: struct tht_fifo *);
! 581:
! 582: /* port operations */
! 583: void tht_lladdr_read(struct tht_softc *);
! 584: void tht_lladdr_write(struct tht_softc *);
! 585: int tht_sw_reset(struct tht_softc *);
! 586: int tht_fw_load(struct tht_softc *);
! 587: void tht_fw_tick(void *arg);
! 588: void tht_link_state(struct tht_softc *);
! 589:
! 590: /* interface operations */
! 591: int tht_ioctl(struct ifnet *, u_long, caddr_t);
! 592: void tht_watchdog(struct ifnet *);
! 593: void tht_start(struct ifnet *);
! 594: int tht_load_pkt(struct tht_softc *, struct tht_pkt *,
! 595: struct mbuf *);
! 596: void tht_txf(struct tht_softc *sc);
! 597:
! 598: void tht_rxf_fill(struct tht_softc *, int);
! 599: void tht_rxf_drain(struct tht_softc *);
! 600: void tht_rxd(struct tht_softc *);
! 601:
! 602: void tht_up(struct tht_softc *);
! 603: void tht_iff(struct tht_softc *);
! 604: void tht_down(struct tht_softc *);
! 605:
! 606: /* ifmedia operations */
! 607: int tht_media_change(struct ifnet *);
! 608: void tht_media_status(struct ifnet *, struct ifmediareq *);
! 609:
! 610: /* wrapper around dma memory */
! 611: struct tht_dmamem *tht_dmamem_alloc(struct tht_softc *, bus_size_t,
! 612: bus_size_t);
! 613: void tht_dmamem_free(struct tht_softc *,
! 614: struct tht_dmamem *);
! 615:
! 616: /* bus space operations */
! 617: u_int32_t tht_read(struct tht_softc *, bus_size_t);
! 618: void tht_write(struct tht_softc *, bus_size_t, u_int32_t);
! 619: void tht_write_region(struct tht_softc *, bus_size_t,
! 620: void *, size_t);
! 621: int tht_wait_eq(struct tht_softc *, bus_size_t, u_int32_t,
! 622: u_int32_t, int);
! 623: int tht_wait_ne(struct tht_softc *, bus_size_t, u_int32_t,
! 624: u_int32_t, int);
! 625:
! 626: #define tht_set(_s, _r, _b) tht_write((_s), (_r), \
! 627: tht_read((_s), (_r)) | (_b))
! 628: #define tht_clr(_s, _r, _b) tht_write((_s), (_r), \
! 629: tht_read((_s), (_r)) & ~(_b))
! 630: #define tht_wait_set(_s, _r, _b, _t) tht_wait_eq((_s), (_r), \
! 631: (_b), (_b), (_t))
! 632:
! 633:
! 634: /* misc */
! 635: #define DEVNAME(_sc) ((_sc)->sc_dev.dv_xname)
! 636: #define sizeofa(_a) (sizeof(_a) / sizeof((_a)[0]))
! 637: #define LWORDS(_b) (((_b) + 7) >> 3)
! 638:
! 639:
! 640: struct thtc_device {
! 641: pci_vendor_id_t td_vendor;
! 642: pci_vendor_id_t td_product;
! 643: u_int td_nports;
! 644: };
! 645:
! 646: const struct thtc_device *thtc_lookup(struct pci_attach_args *);
! 647:
! 648: static const struct thtc_device thtc_devices[] = {
! 649: { PCI_VENDOR_TEHUTI, PCI_PRODUCT_TEHUTI_TN3009, 1 },
! 650: { PCI_VENDOR_TEHUTI, PCI_PRODUCT_TEHUTI_TN3010, 1 },
! 651: { PCI_VENDOR_TEHUTI, PCI_PRODUCT_TEHUTI_TN3014, 2 }
! 652: };
! 653:
! 654: const struct thtc_device *
! 655: thtc_lookup(struct pci_attach_args *pa)
! 656: {
! 657: int i;
! 658: const struct thtc_device *td;
! 659:
! 660: for (i = 0; i < sizeofa(thtc_devices); i++) {
! 661: td = &thtc_devices[i];
! 662: if (td->td_vendor == PCI_VENDOR(pa->pa_id) &&
! 663: td->td_product == PCI_PRODUCT(pa->pa_id))
! 664: return (td);
! 665: }
! 666:
! 667: return (NULL);
! 668: }
! 669:
! 670: int
! 671: thtc_match(struct device *parent, void *match, void *aux)
! 672: {
! 673: struct pci_attach_args *pa = aux;
! 674:
! 675: if (thtc_lookup(pa) != NULL)
! 676: return (1);
! 677:
! 678: return (0);
! 679: }
! 680:
! 681: void
! 682: thtc_attach(struct device *parent, struct device *self, void *aux)
! 683: {
! 684: struct thtc_softc *sc = (struct thtc_softc *)self;
! 685: struct pci_attach_args *pa = aux;
! 686: pcireg_t memtype;
! 687: const struct thtc_device *td;
! 688: struct tht_attach_args taa;
! 689: int i;
! 690:
! 691: bzero(&taa, sizeof(taa));
! 692: td = thtc_lookup(pa);
! 693:
! 694: sc->sc_dmat = pa->pa_dmat;
! 695:
! 696: memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, THT_PCI_BAR);
! 697: if (pci_mapreg_map(pa, THT_PCI_BAR, memtype, 0, &sc->sc_memt,
! 698: &sc->sc_memh, NULL, &sc->sc_mems, 0) != 0) {
! 699: printf(": unable to map host registers\n");
! 700: return;
! 701: }
! 702:
! 703: if (pci_intr_map(pa, &taa.taa_ih) != 0) {
! 704: printf(": unable to map interrupt\n");
! 705: goto unmap;
! 706: }
! 707: printf(": %s\n", pci_intr_string(pa->pa_pc, taa.taa_ih));
! 708:
! 709: taa.taa_pa = pa;
! 710: for (i = 0; i < td->td_nports; i++) {
! 711: taa.taa_port = i;
! 712:
! 713: config_found(self, &taa, thtc_print);
! 714: }
! 715:
! 716: return;
! 717:
! 718: unmap:
! 719: bus_space_unmap(sc->sc_memt, sc->sc_memh, sc->sc_mems);
! 720: sc->sc_mems = 0;
! 721: }
! 722:
! 723: int
! 724: thtc_print(void *aux, const char *pnp)
! 725: {
! 726: struct tht_attach_args *taa = aux;
! 727:
! 728: if (pnp != NULL)
! 729: printf("\"%s\" at %s", tht_cd.cd_name, pnp);
! 730:
! 731: printf(" port %d", taa->taa_port);
! 732:
! 733: return (UNCONF);
! 734: }
! 735:
! 736: int
! 737: tht_match(struct device *parent, void *match, void *aux)
! 738: {
! 739: return (1);
! 740: }
! 741:
! 742: void
! 743: tht_attach(struct device *parent, struct device *self, void *aux)
! 744: {
! 745: struct thtc_softc *csc = (struct thtc_softc *)parent;
! 746: struct tht_softc *sc = (struct tht_softc *)self;
! 747: struct tht_attach_args *taa = aux;
! 748: struct ifnet *ifp;
! 749:
! 750: sc->sc_thtc = csc;
! 751: sc->sc_port = taa->taa_port;
! 752: sc->sc_imr = THT_IMR_DOWN(sc->sc_port);
! 753: rw_init(&sc->sc_lock, "thtioc");
! 754:
! 755: if (bus_space_subregion(csc->sc_memt, csc->sc_memh,
! 756: THT_PORT_REGION(sc->sc_port), THT_PORT_SIZE,
! 757: &sc->sc_memh) != 0) {
! 758: printf(": unable to map port registers\n");
! 759: return;
! 760: }
! 761:
! 762: if (tht_sw_reset(sc) != 0) {
! 763: printf(": unable to reset port\n");
! 764: /* bus_space(9) says we dont have to free subregions */
! 765: return;
! 766: }
! 767:
! 768: sc->sc_ih = pci_intr_establish(taa->taa_pa->pa_pc, taa->taa_ih,
! 769: IPL_NET, tht_intr, sc, DEVNAME(sc));
! 770: if (sc->sc_ih == NULL) {
! 771: printf(": unable to establish interrupt\n");
! 772: /* bus_space(9) says we dont have to free subregions */
! 773: return;
! 774: }
! 775:
! 776: tht_lladdr_read(sc);
! 777: bcopy(sc->sc_lladdr, sc->sc_ac.ac_enaddr, ETHER_ADDR_LEN);
! 778:
! 779: ifp = &sc->sc_ac.ac_if;
! 780: ifp->if_softc = sc;
! 781: ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
! 782: ifp->if_capabilities = IFCAP_VLAN_MTU | IFCAP_CSUM_IPv4 |
! 783: IFCAP_CSUM_TCPv4 | IFCAP_CSUM_UDPv4;
! 784: ifp->if_ioctl = tht_ioctl;
! 785: ifp->if_start = tht_start;
! 786: ifp->if_watchdog = tht_watchdog;
! 787: ifp->if_hardmtu = MCLBYTES - ETHER_HDR_LEN - ETHER_CRC_LEN; /* XXX */
! 788: strlcpy(ifp->if_xname, DEVNAME(sc), IFNAMSIZ);
! 789: IFQ_SET_MAXLEN(&ifp->if_snd, 400);
! 790: IFQ_SET_READY(&ifp->if_snd);
! 791:
! 792: ifmedia_init(&sc->sc_media, 0, tht_media_change, tht_media_status);
! 793: ifmedia_add(&sc->sc_media, IFM_ETHER|IFM_AUTO, 0, NULL);
! 794: ifmedia_set(&sc->sc_media, IFM_ETHER|IFM_AUTO);
! 795:
! 796: if_attach(ifp);
! 797: ether_ifattach(ifp);
! 798:
! 799: printf(": address %s\n", ether_sprintf(sc->sc_ac.ac_enaddr));
! 800:
! 801: mountroothook_establish(tht_mountroot, sc);
! 802: }
! 803:
! 804: void
! 805: tht_mountroot(void *arg)
! 806: {
! 807: struct tht_softc *sc = arg;
! 808:
! 809: if (tht_fifo_alloc(sc, &sc->sc_txt, &tht_txt_desc) != 0)
! 810: return;
! 811:
! 812: if (tht_fw_load(sc) != 0)
! 813: printf("%s: firmware load failed\n", DEVNAME(sc));
! 814:
! 815: tht_sw_reset(sc);
! 816:
! 817: tht_fifo_free(sc, &sc->sc_txt);
! 818:
! 819: tht_link_state(sc);
! 820: tht_write(sc, THT_REG_IMR, sc->sc_imr);
! 821: }
! 822:
! 823: int
! 824: tht_intr(void *arg)
! 825: {
! 826: struct tht_softc *sc = arg;
! 827: struct ifnet *ifp;
! 828: u_int32_t isr;
! 829:
! 830: isr = tht_read(sc, THT_REG_ISR);
! 831: if (isr == 0x0) {
! 832: tht_write(sc, THT_REG_IMR, sc->sc_imr);
! 833: return (0);
! 834: }
! 835:
! 836: DPRINTF(THT_D_INTR, "%s: isr: 0x%b\n", DEVNAME(sc), isr, THT_FMT_ISR);
! 837:
! 838: if (ISSET(isr, THT_REG_ISR_LINKCHG(0) | THT_REG_ISR_LINKCHG(1)))
! 839: tht_link_state(sc);
! 840:
! 841: ifp = &sc->sc_ac.ac_if;
! 842: if (ifp->if_flags & IFF_RUNNING) {
! 843: if (ISSET(isr, THT_REG_ISR_RXD(0)))
! 844: tht_rxd(sc);
! 845:
! 846: if (ISSET(isr, THT_REG_ISR_RXF(0)))
! 847: tht_rxf_fill(sc, 0);
! 848:
! 849: if (ISSET(isr, THT_REG_ISR_TXF(0)))
! 850: tht_txf(sc);
! 851:
! 852: tht_start(ifp);
! 853: }
! 854:
! 855: tht_write(sc, THT_REG_IMR, sc->sc_imr);
! 856: return (1);
! 857: }
! 858:
! 859: int
! 860: tht_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr)
! 861: {
! 862: struct tht_softc *sc = ifp->if_softc;
! 863: struct ifreq *ifr = (struct ifreq *)addr;
! 864: struct ifaddr *ifa;
! 865: int error;
! 866: int s;
! 867:
! 868: rw_enter_write(&sc->sc_lock);
! 869: s = splnet();
! 870:
! 871: error = ether_ioctl(ifp, &sc->sc_ac, cmd, addr);
! 872: if (error > 0)
! 873: goto err;
! 874:
! 875: switch (cmd) {
! 876: case SIOCSIFADDR:
! 877: ifa = (struct ifaddr *)addr;
! 878:
! 879: #ifdef INET
! 880: if (ifa->ifa_addr->sa_family == AF_INET)
! 881: arp_ifinit(&sc->sc_ac, ifa);
! 882: #endif
! 883:
! 884: ifp->if_flags |= IFF_UP;
! 885: /* FALLTHROUGH */
! 886: case SIOCSIFFLAGS:
! 887: if (ifp->if_flags & IFF_UP) {
! 888: if (ifp->if_flags & IFF_RUNNING)
! 889: tht_iff(sc);
! 890: else
! 891: tht_up(sc);
! 892: } else {
! 893: if (ifp->if_flags & IFF_RUNNING)
! 894: tht_down(sc);
! 895: }
! 896: break;
! 897:
! 898: case SIOCSIFMTU:
! 899: if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > ifp->if_hardmtu)
! 900: error = EINVAL;
! 901: else
! 902: ifp->if_mtu = ifr->ifr_mtu;
! 903: break;
! 904:
! 905: case SIOCADDMULTI:
! 906: error = ether_addmulti(ifr, &sc->sc_ac);
! 907: break;
! 908: case SIOCDELMULTI:
! 909: error = ether_delmulti(ifr, &sc->sc_ac);
! 910: break;
! 911:
! 912: case SIOCGIFMEDIA:
! 913: case SIOCSIFMEDIA:
! 914: error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
! 915: break;
! 916:
! 917: default:
! 918: error = ENOTTY;
! 919: break;
! 920: }
! 921:
! 922: if (error == ENETRESET) {
! 923: if (ifp->if_flags & IFF_RUNNING)
! 924: tht_iff(sc);
! 925: error = 0;
! 926: }
! 927:
! 928: err:
! 929: splx(s);
! 930: rw_exit_write(&sc->sc_lock);
! 931:
! 932: return (error);
! 933: }
! 934:
! 935: void
! 936: tht_up(struct tht_softc *sc)
! 937: {
! 938: struct ifnet *ifp = &sc->sc_ac.ac_if;
! 939:
! 940: if (ISSET(ifp->if_flags, IFF_RUNNING)) {
! 941: printf("%s: interface is already up\n", DEVNAME(sc));
! 942: return;
! 943: }
! 944:
! 945: if (tht_pkt_alloc(sc, &sc->sc_tx_list, 128, THT_TXT_SGL_LEN) != 0)
! 946: return;
! 947: if (tht_pkt_alloc(sc, &sc->sc_rx_list, 128, THT_RXF_SGL_LEN) != 0)
! 948: goto free_tx_list;
! 949:
! 950: if (tht_fifo_alloc(sc, &sc->sc_txt, &tht_txt_desc) != 0)
! 951: goto free_rx_list;
! 952: if (tht_fifo_alloc(sc, &sc->sc_rxf, &tht_rxf_desc) != 0)
! 953: goto free_txt;
! 954: if (tht_fifo_alloc(sc, &sc->sc_rxd, &tht_rxd_desc) != 0)
! 955: goto free_rxf;
! 956: if (tht_fifo_alloc(sc, &sc->sc_txf, &tht_txf_desc) != 0)
! 957: goto free_rxd;
! 958:
! 959: tht_write(sc, THT_REG_10G_FRM_LEN, MCLBYTES - ETHER_ALIGN);
! 960: tht_write(sc, THT_REG_10G_PAUSE, 0x96);
! 961: tht_write(sc, THT_REG_10G_RX_SEC, THT_REG_10G_SEC_AVAIL(0x10) |
! 962: THT_REG_10G_SEC_EMPTY(0x80));
! 963: tht_write(sc, THT_REG_10G_TX_SEC, THT_REG_10G_SEC_AVAIL(0x10) |
! 964: THT_REG_10G_SEC_EMPTY(0xe0));
! 965: tht_write(sc, THT_REG_10G_RFIFO_AEF, THT_REG_10G_FIFO_AE(0x0) |
! 966: THT_REG_10G_FIFO_AF(0x0));
! 967: tht_write(sc, THT_REG_10G_TFIFO_AEF, THT_REG_10G_FIFO_AE(0x0) |
! 968: THT_REG_10G_FIFO_AF(0x0));
! 969: tht_write(sc, THT_REG_10G_CTL, THT_REG_10G_CTL_TX_EN |
! 970: THT_REG_10G_CTL_RX_EN | THT_REG_10G_CTL_PAD |
! 971: THT_REG_10G_CTL_PROMISC);
! 972:
! 973: tht_write(sc, THT_REG_VGLB, 0);
! 974:
! 975: tht_write(sc, THT_REG_RX_MAX_FRAME, MCLBYTES - ETHER_ALIGN);
! 976:
! 977: tht_write(sc, THT_REG_RDINTCM(0), THT_REG_RDINTCM_PKT_TH(12) |
! 978: THT_REG_RDINTCM_RXF_TH(4) | THT_REG_RDINTCM_COAL_RC |
! 979: THT_REG_RDINTCM_COAL(0x20));
! 980: tht_write(sc, THT_REG_TDINTCM(0), THT_REG_TDINTCM_PKT_TH(12) |
! 981: THT_REG_TDINTCM_COAL_RC | THT_REG_TDINTCM_COAL(0x20));
! 982:
! 983: bcopy(sc->sc_ac.ac_enaddr, sc->sc_lladdr, ETHER_ADDR_LEN);
! 984: tht_lladdr_write(sc);
! 985:
! 986: /* populate rxf fifo */
! 987: tht_rxf_fill(sc, 1);
! 988:
! 989: tht_iff(sc);
! 990:
! 991: ifp->if_flags |= IFF_RUNNING;
! 992: ifp->if_flags &= ~IFF_OACTIVE;
! 993:
! 994: /* enable interrupts */
! 995: sc->sc_imr = THT_IMR_UP(sc->sc_port);
! 996: tht_write(sc, THT_REG_IMR, sc->sc_imr);
! 997:
! 998: return;
! 999:
! 1000: free_rxd:
! 1001: tht_fifo_free(sc, &sc->sc_rxd);
! 1002: free_rxf:
! 1003: tht_fifo_free(sc, &sc->sc_rxf);
! 1004: free_txt:
! 1005: tht_fifo_free(sc, &sc->sc_txt);
! 1006:
! 1007: tht_sw_reset(sc);
! 1008:
! 1009: free_rx_list:
! 1010: tht_pkt_free(sc, &sc->sc_rx_list);
! 1011: free_tx_list:
! 1012: tht_pkt_free(sc, &sc->sc_tx_list);
! 1013: }
! 1014:
! 1015: void
! 1016: tht_iff(struct tht_softc *sc)
! 1017: {
! 1018: struct ifnet *ifp = &sc->sc_ac.ac_if;
! 1019: struct ether_multi *enm;
! 1020: struct ether_multistep step;
! 1021: u_int32_t rxf;
! 1022: u_int8_t imf[THT_REG_RX_MCST_HASH_SIZE];
! 1023: u_int8_t hash;
! 1024: int i;
! 1025:
! 1026: ifp->if_flags &= ~IFF_ALLMULTI;
! 1027:
! 1028: rxf = THT_REG_RX_FLT_OSEN | THT_REG_RX_FLT_AM | THT_REG_RX_FLT_AB;
! 1029: for (i = 0; i < THT_REG_RX_MAC_MCST_CNT; i++) {
! 1030: tht_write(sc, THT_REG_RX_MAC_MCST0(i), 0);
! 1031: tht_write(sc, THT_REG_RX_MAC_MCST1(i), 0);
! 1032: }
! 1033: memset(imf, 0x00, sizeof(imf));
! 1034:
! 1035: if (ifp->if_flags & IFF_PROMISC)
! 1036: rxf |= THT_REG_RX_FLT_PRM_ALL;
! 1037: else if (sc->sc_ac.ac_multirangecnt > 0) {
! 1038: ifp->if_flags |= IFF_ALLMULTI;
! 1039: memset(imf, 0xff, sizeof(imf));
! 1040: } else {
! 1041: ETHER_FIRST_MULTI(step, &sc->sc_ac, enm);
! 1042:
! 1043: #if 0
! 1044: /* fill the perfect multicast filters */
! 1045: for (i = 0; i < THT_REG_RX_MAC_MCST_CNT; i++) {
! 1046: if (enm == NULL)
! 1047: break;
! 1048:
! 1049: tht_write(sc, THT_REG_RX_MAC_MCST0(i),
! 1050: (enm->enm_addrlo[0] << 0) |
! 1051: (enm->enm_addrlo[1] << 8) |
! 1052: (enm->enm_addrlo[2] << 16) |
! 1053: (enm->enm_addrlo[3] << 24));
! 1054: tht_write(sc, THT_REG_RX_MAC_MCST1(i),
! 1055: (enm->enm_addrlo[4] << 0) |
! 1056: (enm->enm_addrlo[5] << 8));
! 1057:
! 1058: ETHER_NEXT_MULTI(step, enm);
! 1059: }
! 1060: #endif
! 1061:
! 1062: /* fill the imperfect multicast filter with whats left */
! 1063: while (enm != NULL) {
! 1064: hash = 0x00;
! 1065: for (i = 0; i < ETHER_ADDR_LEN; i++)
! 1066: hash ^= enm->enm_addrlo[i];
! 1067: setbit(imf, hash);
! 1068:
! 1069: ETHER_NEXT_MULTI(step, enm);
! 1070: }
! 1071: }
! 1072:
! 1073: tht_write_region(sc, THT_REG_RX_MCST_HASH, imf, sizeof(imf));
! 1074: tht_write(sc, THT_REG_RX_FLT, rxf);
! 1075: }
! 1076:
! 1077: void
! 1078: tht_down(struct tht_softc *sc)
! 1079: {
! 1080: struct ifnet *ifp = &sc->sc_ac.ac_if;
! 1081:
! 1082: if (!ISSET(ifp->if_flags, IFF_RUNNING)) {
! 1083: printf("%s: interface is already down\n", DEVNAME(sc));
! 1084: return;
! 1085: }
! 1086:
! 1087: ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE | IFF_ALLMULTI);
! 1088:
! 1089: while (tht_fifo_writable(sc, &sc->sc_txt) < sc->sc_txt.tf_len &&
! 1090: tht_fifo_readable(sc, &sc->sc_txf) > 0)
! 1091: tsleep(sc, 0, "thtdown", hz);
! 1092:
! 1093: sc->sc_imr = THT_IMR_DOWN(sc->sc_port);
! 1094: tht_write(sc, THT_REG_IMR, sc->sc_imr);
! 1095:
! 1096: tht_sw_reset(sc);
! 1097:
! 1098: tht_fifo_free(sc, &sc->sc_txf);
! 1099: tht_fifo_free(sc, &sc->sc_rxd);
! 1100: tht_fifo_free(sc, &sc->sc_rxf);
! 1101: tht_fifo_free(sc, &sc->sc_txt);
! 1102:
! 1103: /* free mbufs that were on the rxf fifo */
! 1104: tht_rxf_drain(sc);
! 1105:
! 1106: tht_pkt_free(sc, &sc->sc_rx_list);
! 1107: tht_pkt_free(sc, &sc->sc_tx_list);
! 1108: }
! 1109:
! 1110: void
! 1111: tht_start(struct ifnet *ifp)
! 1112: {
! 1113: struct tht_softc *sc = ifp->if_softc;
! 1114: struct tht_pkt *pkt;
! 1115: struct tht_tx_task txt;
! 1116: u_int32_t flags;
! 1117: struct mbuf *m;
! 1118: int bc;
! 1119:
! 1120: if (!(ifp->if_flags & IFF_RUNNING))
! 1121: return;
! 1122: if (ifp->if_flags & IFF_OACTIVE)
! 1123: return;
! 1124: if (IFQ_IS_EMPTY(&ifp->if_snd))
! 1125: return;
! 1126:
! 1127: if (tht_fifo_writable(sc, &sc->sc_txt) <= THT_FIFO_DESC_LEN)
! 1128: return;
! 1129:
! 1130: bzero(&txt, sizeof(txt));
! 1131:
! 1132: tht_fifo_pre(sc, &sc->sc_txt);
! 1133:
! 1134: do {
! 1135: IFQ_POLL(&ifp->if_snd, m);
! 1136: if (m == NULL)
! 1137: break;
! 1138:
! 1139: pkt = tht_pkt_get(&sc->sc_tx_list);
! 1140: if (pkt == NULL) {
! 1141: ifp->if_flags |= IFF_OACTIVE;
! 1142: break;
! 1143: }
! 1144:
! 1145: IFQ_DEQUEUE(&ifp->if_snd, m);
! 1146: if (tht_load_pkt(sc, pkt, m) != 0) {
! 1147: m_freem(m);
! 1148: tht_pkt_put(&sc->sc_tx_list, pkt);
! 1149: ifp->if_oerrors++;
! 1150: break;
! 1151: }
! 1152: /* thou shalt not use m after this point, only pkt->tp_m */
! 1153:
! 1154: #if NBPFILTER > 0
! 1155: if (ifp->if_bpf)
! 1156: bpf_mtap(ifp->if_bpf, pkt->tp_m, BPF_DIRECTION_OUT);
! 1157: #endif
! 1158:
! 1159: bc = sizeof(txt) +
! 1160: sizeof(struct tht_pbd) * pkt->tp_dmap->dm_nsegs;
! 1161:
! 1162: flags = THT_TXT_TYPE | THT_TXT_FLAGS_UDPCS |
! 1163: THT_TXT_FLAGS_TCPCS | THT_TXT_FLAGS_IPCS | LWORDS(bc);
! 1164: txt.flags = htole32(flags);
! 1165: txt.len = htole16(pkt->tp_m->m_pkthdr.len);
! 1166: txt.uid = pkt->tp_id;
! 1167:
! 1168: DPRINTF(THT_D_TX, "%s: txt uid 0x%llx flags 0x%08x len %d\n",
! 1169: DEVNAME(sc), pkt->tp_id, flags, pkt->tp_m->m_pkthdr.len);
! 1170:
! 1171: tht_fifo_write(sc, &sc->sc_txt, &txt, sizeof(txt));
! 1172: tht_fifo_write_dmap(sc, &sc->sc_txt, pkt->tp_dmap);
! 1173: tht_fifo_write_pad(sc, &sc->sc_txt, bc);
! 1174:
! 1175: bus_dmamap_sync(sc->sc_thtc->sc_dmat, pkt->tp_dmap, 0,
! 1176: pkt->tp_dmap->dm_mapsize, BUS_DMASYNC_PREWRITE);
! 1177:
! 1178: ifp->if_opackets++;
! 1179:
! 1180: } while (sc->sc_txt.tf_ready > THT_FIFO_DESC_LEN);
! 1181:
! 1182: tht_fifo_post(sc, &sc->sc_txt);
! 1183: }
! 1184:
! 1185: int
! 1186: tht_load_pkt(struct tht_softc *sc, struct tht_pkt *pkt, struct mbuf *m)
! 1187: {
! 1188: bus_dma_tag_t dmat = sc->sc_thtc->sc_dmat;
! 1189: bus_dmamap_t dmap = pkt->tp_dmap;
! 1190: struct mbuf *m0 = NULL;
! 1191:
! 1192: switch(bus_dmamap_load_mbuf(dmat, dmap, m, BUS_DMA_NOWAIT)) {
! 1193: case 0:
! 1194: pkt->tp_m = m;
! 1195: break;
! 1196:
! 1197: case EFBIG: /* mbuf chain is too fragmented */
! 1198: MGETHDR(m0, M_DONTWAIT, MT_DATA);
! 1199: if (m0 == NULL)
! 1200: return (ENOBUFS);
! 1201: if (m->m_pkthdr.len > MHLEN) {
! 1202: MCLGET(m0, M_DONTWAIT);
! 1203: if (!(m0->m_flags & M_EXT)) {
! 1204: m_freem(m0);
! 1205: return (ENOBUFS);
! 1206: }
! 1207: }
! 1208: m_copydata(m, 0, m->m_pkthdr.len, mtod(m0, caddr_t));
! 1209: m0->m_pkthdr.len = m0->m_len = m->m_pkthdr.len;
! 1210: if (bus_dmamap_load_mbuf(dmat, dmap, m0, BUS_DMA_NOWAIT)) {
! 1211: m_freem(m0);
! 1212: return (ENOBUFS);
! 1213: }
! 1214:
! 1215: m_freem(m);
! 1216: pkt->tp_m = m0;
! 1217: break;
! 1218:
! 1219: default:
! 1220: return (ENOBUFS);
! 1221: }
! 1222:
! 1223: return (0);
! 1224: }
! 1225:
! 1226: void
! 1227: tht_txf(struct tht_softc *sc)
! 1228: {
! 1229: struct ifnet *ifp = &sc->sc_ac.ac_if;
! 1230: bus_dma_tag_t dmat = sc->sc_thtc->sc_dmat;
! 1231: bus_dmamap_t dmap;
! 1232: struct tht_tx_free txf;
! 1233: struct tht_pkt *pkt;
! 1234:
! 1235: if (tht_fifo_readable(sc, &sc->sc_txf) < sizeof(txf))
! 1236: return;
! 1237:
! 1238: tht_fifo_pre(sc, &sc->sc_txf);
! 1239:
! 1240: do {
! 1241: tht_fifo_read(sc, &sc->sc_txf, &txf, sizeof(txf));
! 1242:
! 1243: DPRINTF(THT_D_TX, "%s: txf uid 0x%llx\n", DEVNAME(sc), txf.uid);
! 1244:
! 1245: pkt = &sc->sc_tx_list.tpl_pkts[txf.uid];
! 1246: dmap = pkt->tp_dmap;
! 1247:
! 1248: bus_dmamap_sync(dmat, dmap, 0, dmap->dm_mapsize,
! 1249: BUS_DMASYNC_POSTWRITE);
! 1250: bus_dmamap_unload(dmat, dmap);
! 1251:
! 1252: m_freem(pkt->tp_m);
! 1253:
! 1254: tht_pkt_put(&sc->sc_tx_list, pkt);
! 1255:
! 1256: } while (sc->sc_txf.tf_ready >= sizeof(txf));
! 1257:
! 1258: ifp->if_flags &= ~IFF_OACTIVE;
! 1259:
! 1260: tht_fifo_post(sc, &sc->sc_txf);
! 1261: }
! 1262:
! 1263: void
! 1264: tht_rxf_fill(struct tht_softc *sc, int wait)
! 1265: {
! 1266: bus_dma_tag_t dmat = sc->sc_thtc->sc_dmat;
! 1267: bus_dmamap_t dmap;
! 1268: struct tht_rx_free rxf;
! 1269: struct tht_pkt *pkt;
! 1270: struct mbuf *m;
! 1271: int bc;
! 1272:
! 1273: if (tht_fifo_writable(sc, &sc->sc_rxf) <= THT_FIFO_DESC_LEN)
! 1274: return;
! 1275:
! 1276: tht_fifo_pre(sc, &sc->sc_rxf);
! 1277:
! 1278: for (;;) {
! 1279: if ((pkt = tht_pkt_get(&sc->sc_rx_list)) == NULL)
! 1280: goto done;
! 1281:
! 1282: MGETHDR(m, wait ? M_WAIT : M_DONTWAIT, MT_DATA);
! 1283: if (m == NULL)
! 1284: goto put_pkt;
! 1285:
! 1286: MCLGET(m, wait ? M_WAIT : M_DONTWAIT);
! 1287: if (!ISSET(m->m_flags, M_EXT))
! 1288: goto free_m;
! 1289:
! 1290: m->m_data += ETHER_ALIGN;
! 1291: m->m_len = m->m_pkthdr.len = MCLBYTES - ETHER_ALIGN;
! 1292:
! 1293: dmap = pkt->tp_dmap;
! 1294: if (bus_dmamap_load_mbuf(dmat, dmap, m,
! 1295: wait ? BUS_DMA_WAITOK : BUS_DMA_NOWAIT) != 0)
! 1296: goto free_m;
! 1297:
! 1298: pkt->tp_m = m;
! 1299:
! 1300: bc = sizeof(rxf) + sizeof(struct tht_pbd) * dmap->dm_nsegs;
! 1301:
! 1302: rxf.bc = htole16(LWORDS(bc));
! 1303: rxf.type = htole16(THT_RXF_TYPE);
! 1304: rxf.uid = pkt->tp_id;
! 1305:
! 1306: tht_fifo_write(sc, &sc->sc_rxf, &rxf, sizeof(rxf));
! 1307: tht_fifo_write_dmap(sc, &sc->sc_rxf, dmap);
! 1308: tht_fifo_write_pad(sc, &sc->sc_rxf, bc);
! 1309:
! 1310: bus_dmamap_sync(dmat, dmap, 0, dmap->dm_mapsize,
! 1311: BUS_DMASYNC_PREREAD);
! 1312:
! 1313: if (sc->sc_rxf.tf_ready <= THT_FIFO_DESC_LEN)
! 1314: goto done;
! 1315: }
! 1316:
! 1317: free_m:
! 1318: m_freem(m);
! 1319: put_pkt:
! 1320: tht_pkt_put(&sc->sc_rx_list, pkt);
! 1321: done:
! 1322: tht_fifo_post(sc, &sc->sc_rxf);
! 1323: }
! 1324:
! 1325: void
! 1326: tht_rxf_drain(struct tht_softc *sc)
! 1327: {
! 1328: bus_dma_tag_t dmat = sc->sc_thtc->sc_dmat;
! 1329: bus_dmamap_t dmap;
! 1330: struct tht_pkt *pkt;
! 1331:
! 1332: while ((pkt = tht_pkt_used(&sc->sc_rx_list)) != NULL) {
! 1333: dmap = pkt->tp_dmap;
! 1334:
! 1335: bus_dmamap_sync(dmat, dmap, 0, dmap->dm_mapsize,
! 1336: BUS_DMASYNC_POSTREAD);
! 1337: bus_dmamap_unload(dmat, dmap);
! 1338:
! 1339: m_freem(pkt->tp_m);
! 1340:
! 1341: tht_pkt_put(&sc->sc_rx_list, pkt);
! 1342: }
! 1343: }
! 1344:
! 1345: void
! 1346: tht_rxd(struct tht_softc *sc)
! 1347: {
! 1348: struct ifnet *ifp = &sc->sc_ac.ac_if;
! 1349: bus_dma_tag_t dmat = sc->sc_thtc->sc_dmat;
! 1350: bus_dmamap_t dmap;
! 1351: struct tht_rx_desc rxd;
! 1352: struct tht_pkt *pkt;
! 1353: struct mbuf *m;
! 1354: int bc;
! 1355: u_int32_t flags;
! 1356:
! 1357: if (tht_fifo_readable(sc, &sc->sc_rxd) < sizeof(rxd))
! 1358: return;
! 1359:
! 1360: tht_fifo_pre(sc, &sc->sc_rxd);
! 1361:
! 1362: do {
! 1363: tht_fifo_read(sc, &sc->sc_rxd, &rxd, sizeof(rxd));
! 1364:
! 1365: flags = letoh32(rxd.flags);
! 1366: bc = THT_RXD_FLAGS_BC(flags) * 8;
! 1367: bc -= sizeof(rxd);
! 1368: pkt = &sc->sc_rx_list.tpl_pkts[rxd.uid];
! 1369:
! 1370: dmap = pkt->tp_dmap;
! 1371:
! 1372: bus_dmamap_sync(dmat, dmap, 0, dmap->dm_mapsize,
! 1373: BUS_DMASYNC_POSTREAD);
! 1374: bus_dmamap_unload(dmat, dmap);
! 1375:
! 1376: m = pkt->tp_m;
! 1377: m->m_pkthdr.rcvif = ifp;
! 1378: m->m_pkthdr.len = m->m_len = letoh16(rxd.len);
! 1379:
! 1380: if (!ISSET(flags, THT_RXD_FLAGS_IPCS))
! 1381: m->m_pkthdr.csum_flags |= M_IPV4_CSUM_IN_OK;
! 1382: if (!ISSET(flags, THT_RXD_FLAGS_TCPCS))
! 1383: m->m_pkthdr.csum_flags |= M_TCP_CSUM_IN_OK;
! 1384: if (!ISSET(flags, THT_RXD_FLAGS_UDPCS))
! 1385: m->m_pkthdr.csum_flags |= M_UDP_CSUM_IN_OK;
! 1386:
! 1387: /* XXX process type 3 rx descriptors */
! 1388:
! 1389: #if NBPFILTER > 0
! 1390: if (ifp->if_bpf)
! 1391: bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
! 1392: #endif
! 1393:
! 1394: ether_input_mbuf(ifp, m);
! 1395:
! 1396: tht_pkt_put(&sc->sc_rx_list, pkt);
! 1397:
! 1398: while (bc > 0) {
! 1399: static u_int32_t pad;
! 1400:
! 1401: tht_fifo_read(sc, &sc->sc_rxd, &pad, sizeof(pad));
! 1402: bc -= sizeof(pad);
! 1403: }
! 1404:
! 1405: ifp->if_ipackets++;
! 1406:
! 1407: } while (sc->sc_rxd.tf_ready >= sizeof(rxd));
! 1408:
! 1409: tht_fifo_post(sc, &sc->sc_rxd);
! 1410:
! 1411: /* put more pkts on the fifo */
! 1412: tht_rxf_fill(sc, 0);
! 1413: }
! 1414:
! 1415: void
! 1416: tht_watchdog(struct ifnet *ifp)
! 1417: {
! 1418: /* do nothing */
! 1419: }
! 1420:
! 1421: int
! 1422: tht_media_change(struct ifnet *ifp)
! 1423: {
! 1424: /* ignore */
! 1425: return (0);
! 1426: }
! 1427:
! 1428: void
! 1429: tht_media_status(struct ifnet *ifp, struct ifmediareq *imr)
! 1430: {
! 1431: struct tht_softc *sc = ifp->if_softc;
! 1432:
! 1433: imr->ifm_active = IFM_ETHER | IFM_AUTO;
! 1434: imr->ifm_status = IFM_AVALID;
! 1435:
! 1436: tht_link_state(sc);
! 1437:
! 1438: if (LINK_STATE_IS_UP(ifp->if_link_state))
! 1439: imr->ifm_status |= IFM_ACTIVE;
! 1440: }
! 1441:
! 1442: int
! 1443: tht_fifo_alloc(struct tht_softc *sc, struct tht_fifo *tf,
! 1444: struct tht_fifo_desc *tfd)
! 1445: {
! 1446: u_int64_t dva;
! 1447:
! 1448: tf->tf_len = THT_FIFO_SIZE(tfd->tfd_size);
! 1449: tf->tf_mem = tht_dmamem_alloc(sc, tf->tf_len, THT_FIFO_ALIGN);
! 1450: if (tf->tf_mem == NULL)
! 1451: return (1);
! 1452:
! 1453: tf->tf_desc = tfd;
! 1454: tf->tf_rptr = tf->tf_wptr = 0;
! 1455:
! 1456: bus_dmamap_sync(sc->sc_thtc->sc_dmat, THT_DMA_MAP(tf->tf_mem),
! 1457: 0, tf->tf_len, THT_FIFO_PRE_SYNC(tfd));
! 1458:
! 1459: dva = THT_DMA_DVA(tf->tf_mem);
! 1460: tht_write(sc, tfd->tfd_cfg0, (u_int32_t)dva | tfd->tfd_size);
! 1461: tht_write(sc, tfd->tfd_cfg1, (u_int32_t)(dva >> 32));
! 1462:
! 1463: return (0);
! 1464: }
! 1465:
! 1466: void
! 1467: tht_fifo_free(struct tht_softc *sc, struct tht_fifo *tf)
! 1468: {
! 1469: bus_dmamap_sync(sc->sc_thtc->sc_dmat, THT_DMA_MAP(tf->tf_mem),
! 1470: 0, tf->tf_len, THT_FIFO_POST_SYNC(tf->tf_desc));
! 1471: tht_dmamem_free(sc, tf->tf_mem);
! 1472: }
! 1473:
! 1474: size_t
! 1475: tht_fifo_readable(struct tht_softc *sc, struct tht_fifo *tf)
! 1476: {
! 1477: tf->tf_wptr = tht_read(sc, tf->tf_desc->tfd_wptr);
! 1478: tf->tf_wptr &= THT_FIFO_PTR_MASK;
! 1479: tf->tf_ready = tf->tf_wptr - tf->tf_rptr;
! 1480: if (tf->tf_ready < 0)
! 1481: tf->tf_ready += tf->tf_len;
! 1482:
! 1483: DPRINTF(THT_D_FIFO, "%s: fifo rdable wptr: %d rptr: %d ready: %d\n",
! 1484: DEVNAME(sc), tf->tf_wptr, tf->tf_rptr, tf->tf_ready);
! 1485:
! 1486: return (tf->tf_ready);
! 1487: }
! 1488:
! 1489: size_t
! 1490: tht_fifo_writable(struct tht_softc *sc, struct tht_fifo *tf)
! 1491: {
! 1492: tf->tf_rptr = tht_read(sc, tf->tf_desc->tfd_rptr);
! 1493: tf->tf_rptr &= THT_FIFO_PTR_MASK;
! 1494: tf->tf_ready = tf->tf_rptr - tf->tf_wptr;
! 1495: if (tf->tf_ready <= 0)
! 1496: tf->tf_ready += tf->tf_len;
! 1497:
! 1498: DPRINTF(THT_D_FIFO, "%s: fifo wrable wptr: %d rptr: %d ready: %d\n",
! 1499: DEVNAME(sc), tf->tf_wptr, tf->tf_rptr, tf->tf_ready);
! 1500:
! 1501: return (tf->tf_ready);
! 1502: }
! 1503:
! 1504: void
! 1505: tht_fifo_pre(struct tht_softc *sc, struct tht_fifo *tf)
! 1506: {
! 1507: bus_dmamap_sync(sc->sc_thtc->sc_dmat, THT_DMA_MAP(tf->tf_mem),
! 1508: 0, tf->tf_len, THT_FIFO_POST_SYNC(tf->tf_desc));
! 1509: }
! 1510:
! 1511: void
! 1512: tht_fifo_read(struct tht_softc *sc, struct tht_fifo *tf,
! 1513: void *buf, size_t buflen)
! 1514: {
! 1515: u_int8_t *fifo = THT_DMA_KVA(tf->tf_mem);
! 1516: u_int8_t *desc = buf;
! 1517: size_t len;
! 1518:
! 1519: tf->tf_ready -= buflen;
! 1520:
! 1521: len = tf->tf_len - tf->tf_rptr;
! 1522:
! 1523: if (len < buflen) {
! 1524: memcpy(desc, fifo + tf->tf_rptr, len);
! 1525:
! 1526: buflen -= len;
! 1527: desc += len;
! 1528:
! 1529: tf->tf_rptr = 0;
! 1530: }
! 1531:
! 1532: memcpy(desc, fifo + tf->tf_rptr, buflen);
! 1533: tf->tf_rptr += buflen;
! 1534:
! 1535: DPRINTF(THT_D_FIFO, "%s: fifo rd wptr: %d rptr: %d ready: %d\n",
! 1536: DEVNAME(sc), tf->tf_wptr, tf->tf_rptr, tf->tf_ready);
! 1537: }
! 1538:
! 1539: void
! 1540: tht_fifo_write(struct tht_softc *sc, struct tht_fifo *tf,
! 1541: void *buf, size_t buflen)
! 1542: {
! 1543: u_int8_t *fifo = THT_DMA_KVA(tf->tf_mem);
! 1544: u_int8_t *desc = buf;
! 1545: size_t len;
! 1546:
! 1547: tf->tf_ready -= buflen;
! 1548:
! 1549: len = tf->tf_len - tf->tf_wptr;
! 1550:
! 1551: if (len < buflen) {
! 1552: memcpy(fifo + tf->tf_wptr, desc, len);
! 1553:
! 1554: buflen -= len;
! 1555: desc += len;
! 1556:
! 1557: tf->tf_wptr = 0;
! 1558: }
! 1559:
! 1560: memcpy(fifo + tf->tf_wptr, desc, buflen);
! 1561: tf->tf_wptr += buflen;
! 1562: tf->tf_wptr %= tf->tf_len;
! 1563:
! 1564: DPRINTF(THT_D_FIFO, "%s: fifo wr wptr: %d rptr: %d ready: %d\n",
! 1565: DEVNAME(sc), tf->tf_wptr, tf->tf_rptr, tf->tf_ready);
! 1566: }
! 1567:
! 1568: void
! 1569: tht_fifo_write_dmap(struct tht_softc *sc, struct tht_fifo *tf,
! 1570: bus_dmamap_t dmap)
! 1571: {
! 1572: struct tht_pbd pbd;
! 1573: u_int64_t dva;
! 1574: int i;
! 1575:
! 1576: for (i = 0; i < dmap->dm_nsegs; i++) {
! 1577: dva = dmap->dm_segs[i].ds_addr;
! 1578:
! 1579: pbd.addr_lo = htole32(dva);
! 1580: pbd.addr_hi = htole32(dva >> 32);
! 1581: pbd.len = htole32(dmap->dm_segs[i].ds_len);
! 1582:
! 1583: tht_fifo_write(sc, tf, &pbd, sizeof(pbd));
! 1584: }
! 1585: }
! 1586:
! 1587: void
! 1588: tht_fifo_write_pad(struct tht_softc *sc, struct tht_fifo *tf, int bc)
! 1589: {
! 1590: const static u_int32_t pad = 0x0;
! 1591:
! 1592: /* this assumes you'll only ever be writing multiples of 4 bytes */
! 1593: if (bc % 8)
! 1594: tht_fifo_write(sc, tf, (void *)&pad, sizeof(pad));
! 1595: }
! 1596:
! 1597: void
! 1598: tht_fifo_post(struct tht_softc *sc, struct tht_fifo *tf)
! 1599: {
! 1600: bus_dmamap_sync(sc->sc_thtc->sc_dmat, THT_DMA_MAP(tf->tf_mem),
! 1601: 0, tf->tf_len, THT_FIFO_PRE_SYNC(tf->tf_desc));
! 1602: if (tf->tf_desc->tfd_write)
! 1603: tht_write(sc, tf->tf_desc->tfd_wptr, tf->tf_wptr);
! 1604: else
! 1605: tht_write(sc, tf->tf_desc->tfd_rptr, tf->tf_rptr);
! 1606:
! 1607: DPRINTF(THT_D_FIFO, "%s: fifo post wptr: %d rptr: %d\n", DEVNAME(sc),
! 1608: tf->tf_wptr, tf->tf_rptr);
! 1609: }
! 1610:
! 1611: const static bus_size_t tht_mac_regs[3] = {
! 1612: THT_REG_RX_UNC_MAC2, THT_REG_RX_UNC_MAC1, THT_REG_RX_UNC_MAC0
! 1613: };
! 1614:
! 1615: void
! 1616: tht_lladdr_read(struct tht_softc *sc)
! 1617: {
! 1618: int i;
! 1619:
! 1620: for (i = 0; i < sizeofa(tht_mac_regs); i++)
! 1621: sc->sc_lladdr[i] = betoh16(tht_read(sc, tht_mac_regs[i]));
! 1622: }
! 1623:
! 1624: void
! 1625: tht_lladdr_write(struct tht_softc *sc)
! 1626: {
! 1627: int i;
! 1628:
! 1629: for (i = 0; i < sizeofa(tht_mac_regs); i++)
! 1630: tht_write(sc, tht_mac_regs[i], htobe16(sc->sc_lladdr[i]));
! 1631: }
! 1632:
! 1633: #define tht_swrst_set(_s, _r) tht_write((_s), (_r), 0x1)
! 1634: #define tht_swrst_clr(_s, _r) tht_write((_s), (_r), 0x0)
! 1635: int
! 1636: tht_sw_reset(struct tht_softc *sc)
! 1637: {
! 1638: int i;
! 1639:
! 1640: /* this follows SW Reset process in 8.8 of the doco */
! 1641:
! 1642: /* 1. disable rx */
! 1643: tht_clr(sc, THT_REG_RX_FLT, THT_REG_RX_FLT_OSEN);
! 1644:
! 1645: /* 2. initiate port disable */
! 1646: tht_swrst_set(sc, THT_REG_DIS_PRT);
! 1647:
! 1648: /* 3. initiate queue disable */
! 1649: tht_swrst_set(sc, THT_REG_DIS_QU_0);
! 1650: tht_swrst_set(sc, THT_REG_DIS_QU_1);
! 1651:
! 1652: /* 4. wait for successful finish of previous tasks */
! 1653: if (!tht_wait_set(sc, THT_REG_RST_PRT, THT_REG_RST_PRT_ACTIVE, 1000))
! 1654: return (1);
! 1655:
! 1656: /* 5. Reset interrupt registers */
! 1657: tht_write(sc, THT_REG_IMR, 0x0); /* 5.a */
! 1658: tht_read(sc, THT_REG_ISR); /* 5.b */
! 1659: for (i = 0; i < THT_NQUEUES; i++) {
! 1660: tht_write(sc, THT_REG_RDINTCM(i), 0x0); /* 5.c/5.d */
! 1661: tht_write(sc, THT_REG_TDINTCM(i), 0x0); /* 5.e */
! 1662: }
! 1663:
! 1664: /* 6. initiate queue reset */
! 1665: tht_swrst_set(sc, THT_REG_RST_QU_0);
! 1666: tht_swrst_set(sc, THT_REG_RST_QU_1);
! 1667:
! 1668: /* 7. initiate port reset */
! 1669: tht_swrst_set(sc, THT_REG_RST_PRT);
! 1670:
! 1671: /* 8. clear txt/rxf/rxd/txf read and write ptrs */
! 1672: for (i = 0; i < THT_NQUEUES; i++) {
! 1673: tht_write(sc, THT_REG_TXT_RPTR(i), 0);
! 1674: tht_write(sc, THT_REG_RXF_RPTR(i), 0);
! 1675: tht_write(sc, THT_REG_RXD_RPTR(i), 0);
! 1676: tht_write(sc, THT_REG_TXF_RPTR(i), 0);
! 1677:
! 1678: tht_write(sc, THT_REG_TXT_WPTR(i), 0);
! 1679: tht_write(sc, THT_REG_RXF_WPTR(i), 0);
! 1680: tht_write(sc, THT_REG_RXD_WPTR(i), 0);
! 1681: tht_write(sc, THT_REG_TXF_WPTR(i), 0);
! 1682: }
! 1683:
! 1684: /* 9. unset port disable */
! 1685: tht_swrst_clr(sc, THT_REG_DIS_PRT);
! 1686:
! 1687: /* 10. unset queue disable */
! 1688: tht_swrst_clr(sc, THT_REG_DIS_QU_0);
! 1689: tht_swrst_clr(sc, THT_REG_DIS_QU_1);
! 1690:
! 1691: /* 11. unset queue reset */
! 1692: tht_swrst_clr(sc, THT_REG_RST_QU_0);
! 1693: tht_swrst_clr(sc, THT_REG_RST_QU_1);
! 1694:
! 1695: /* 12. unset port reset */
! 1696: tht_swrst_clr(sc, THT_REG_RST_PRT);
! 1697:
! 1698: /* 13. enable rx */
! 1699: tht_set(sc, THT_REG_RX_FLT, THT_REG_RX_FLT_OSEN);
! 1700:
! 1701: return (0);
! 1702: }
! 1703:
! 1704: int
! 1705: tht_fw_load(struct tht_softc *sc)
! 1706: {
! 1707: struct timeout ticker;
! 1708: volatile int ok = 1;
! 1709: u_int8_t *fw, *buf;
! 1710: size_t fwlen, wrlen;
! 1711: int error = 1;
! 1712:
! 1713: if (loadfirmware("tht", &fw, &fwlen) != 0)
! 1714: return (1);
! 1715:
! 1716: if ((fwlen % 8) != 0)
! 1717: goto err;
! 1718:
! 1719: buf = fw;
! 1720: while (fwlen > 0) {
! 1721: while (tht_fifo_writable(sc, &sc->sc_txt) <= THT_FIFO_GAP) {
! 1722: if (tsleep(sc, PCATCH, "thtfw", 1) == EINTR)
! 1723: goto err;
! 1724: }
! 1725:
! 1726: wrlen = MIN(sc->sc_txt.tf_ready - THT_FIFO_GAP, fwlen);
! 1727: tht_fifo_pre(sc, &sc->sc_txt);
! 1728: tht_fifo_write(sc, &sc->sc_txt, buf, wrlen);
! 1729: tht_fifo_post(sc, &sc->sc_txt);
! 1730:
! 1731: fwlen -= wrlen;
! 1732: buf += wrlen;
! 1733: }
! 1734:
! 1735: timeout_set(&ticker, tht_fw_tick, &ticker);
! 1736: timeout_add(&ticker, 2*hz);
! 1737: while (ok) {
! 1738: if (tht_read(sc, THT_REG_INIT_STATUS) != 0) {
! 1739: error = 0;
! 1740: break;
! 1741: }
! 1742:
! 1743: if (tsleep(sc, PCATCH, "thtinit", 1) == EINTR)
! 1744: goto err;
! 1745: }
! 1746: timeout_del(&ticker);
! 1747:
! 1748: tht_write(sc, THT_REG_INIT_SEMAPHORE, 0x1);
! 1749:
! 1750: err:
! 1751: free(fw, M_DEVBUF);
! 1752: return (error);
! 1753: }
! 1754:
! 1755: void
! 1756: tht_fw_tick(void *arg)
! 1757: {
! 1758: volatile int *ok = arg;
! 1759:
! 1760: *ok = 0;
! 1761: }
! 1762:
! 1763: void
! 1764: tht_link_state(struct tht_softc *sc)
! 1765: {
! 1766: struct ifnet *ifp = &sc->sc_ac.ac_if;
! 1767: int link_state = LINK_STATE_DOWN;
! 1768:
! 1769: if (tht_read(sc, THT_REG_MAC_LNK_STAT) & THT_REG_MAC_LNK_STAT_LINK)
! 1770: link_state = LINK_STATE_UP;
! 1771:
! 1772: if (ifp->if_link_state != link_state) {
! 1773: ifp->if_link_state = link_state;
! 1774: if_link_state_change(ifp);
! 1775: }
! 1776: }
! 1777:
! 1778: u_int32_t
! 1779: tht_read(struct tht_softc *sc, bus_size_t r)
! 1780: {
! 1781: bus_space_barrier(sc->sc_thtc->sc_memt, sc->sc_memh, r, 4,
! 1782: BUS_SPACE_BARRIER_READ);
! 1783: return (bus_space_read_4(sc->sc_thtc->sc_memt, sc->sc_memh, r));
! 1784: }
! 1785:
! 1786: void
! 1787: tht_write(struct tht_softc *sc, bus_size_t r, u_int32_t v)
! 1788: {
! 1789: bus_space_write_4(sc->sc_thtc->sc_memt, sc->sc_memh, r, v);
! 1790: bus_space_barrier(sc->sc_thtc->sc_memt, sc->sc_memh, r, 4,
! 1791: BUS_SPACE_BARRIER_WRITE);
! 1792: }
! 1793:
! 1794: void
! 1795: tht_write_region(struct tht_softc *sc, bus_size_t r, void *buf, size_t len)
! 1796: {
! 1797: bus_space_write_raw_region_4(sc->sc_thtc->sc_memt, sc->sc_memh, r,
! 1798: buf, len);
! 1799: bus_space_barrier(sc->sc_thtc->sc_memt, sc->sc_memh, r, len,
! 1800: BUS_SPACE_BARRIER_WRITE);
! 1801: }
! 1802:
! 1803: int
! 1804: tht_wait_eq(struct tht_softc *sc, bus_size_t r, u_int32_t m, u_int32_t v,
! 1805: int timeout)
! 1806: {
! 1807: while ((tht_read(sc, r) & m) != v) {
! 1808: if (timeout == 0)
! 1809: return (0);
! 1810:
! 1811: delay(1000);
! 1812: timeout--;
! 1813: }
! 1814:
! 1815: return (1);
! 1816: }
! 1817:
! 1818: int
! 1819: tht_wait_ne(struct tht_softc *sc, bus_size_t r, u_int32_t m, u_int32_t v,
! 1820: int timeout)
! 1821: {
! 1822: while ((tht_read(sc, r) & m) == v) {
! 1823: if (timeout == 0)
! 1824: return (0);
! 1825:
! 1826: delay(1000);
! 1827: timeout--;
! 1828: }
! 1829:
! 1830: return (1);
! 1831: }
! 1832:
! 1833: struct tht_dmamem *
! 1834: tht_dmamem_alloc(struct tht_softc *sc, bus_size_t size, bus_size_t align)
! 1835: {
! 1836: bus_dma_tag_t dmat = sc->sc_thtc->sc_dmat;
! 1837: struct tht_dmamem *tdm;
! 1838: int nsegs;
! 1839:
! 1840: tdm = malloc(sizeof(struct tht_dmamem), M_DEVBUF, M_WAITOK);
! 1841: bzero(tdm, sizeof(struct tht_dmamem));
! 1842: tdm->tdm_size = size;
! 1843:
! 1844: if (bus_dmamap_create(dmat, size, 1, size, 0,
! 1845: BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, &tdm->tdm_map) != 0)
! 1846: goto tdmfree;
! 1847:
! 1848: if (bus_dmamem_alloc(dmat, size, align, 0, &tdm->tdm_seg, 1, &nsegs,
! 1849: BUS_DMA_WAITOK) != 0)
! 1850: goto destroy;
! 1851:
! 1852: if (bus_dmamem_map(dmat, &tdm->tdm_seg, nsegs, size, &tdm->tdm_kva,
! 1853: BUS_DMA_WAITOK) != 0)
! 1854: goto free;
! 1855:
! 1856: if (bus_dmamap_load(dmat, tdm->tdm_map, tdm->tdm_kva, size,
! 1857: NULL, BUS_DMA_WAITOK) != 0)
! 1858: goto unmap;
! 1859:
! 1860: bzero(tdm->tdm_kva, size);
! 1861:
! 1862: return (tdm);
! 1863:
! 1864: unmap:
! 1865: bus_dmamem_unmap(dmat, tdm->tdm_kva, size);
! 1866: free:
! 1867: bus_dmamem_free(dmat, &tdm->tdm_seg, 1);
! 1868: destroy:
! 1869: bus_dmamap_destroy(dmat, tdm->tdm_map);
! 1870: tdmfree:
! 1871: free(tdm, M_DEVBUF);
! 1872:
! 1873: return (NULL);
! 1874: }
! 1875:
! 1876: void
! 1877: tht_dmamem_free(struct tht_softc *sc, struct tht_dmamem *tdm)
! 1878: {
! 1879: bus_dma_tag_t dmat = sc->sc_thtc->sc_dmat;
! 1880:
! 1881: bus_dmamap_unload(dmat, tdm->tdm_map);
! 1882: bus_dmamem_unmap(dmat, tdm->tdm_kva, tdm->tdm_size);
! 1883: bus_dmamem_free(dmat, &tdm->tdm_seg, 1);
! 1884: bus_dmamap_destroy(dmat, tdm->tdm_map);
! 1885: free(tdm, M_DEVBUF);
! 1886: }
! 1887:
! 1888: int
! 1889: tht_pkt_alloc(struct tht_softc *sc, struct tht_pkt_list *tpl, int npkts,
! 1890: int nsegs)
! 1891: {
! 1892: bus_dma_tag_t dmat = sc->sc_thtc->sc_dmat;
! 1893: struct tht_pkt *pkt;
! 1894: int i;
! 1895:
! 1896: tpl->tpl_pkts = malloc(sizeof(struct tht_pkt) * npkts, M_DEVBUF,
! 1897: M_WAITOK);
! 1898: bzero(tpl->tpl_pkts, sizeof(struct tht_pkt) * npkts);
! 1899:
! 1900: TAILQ_INIT(&tpl->tpl_free);
! 1901: TAILQ_INIT(&tpl->tpl_used);
! 1902: for (i = 0; i < npkts; i++) {
! 1903: pkt = &tpl->tpl_pkts[i];
! 1904:
! 1905: pkt->tp_id = i;
! 1906: if (bus_dmamap_create(dmat, THT_PBD_PKTLEN, nsegs,
! 1907: THT_PBD_PKTLEN, 0, BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW,
! 1908: &pkt->tp_dmap) != 0) {
! 1909: tht_pkt_free(sc, tpl);
! 1910: return (1);
! 1911: }
! 1912:
! 1913: TAILQ_INSERT_TAIL(&tpl->tpl_free, pkt, tp_link);
! 1914: }
! 1915:
! 1916: return (0);
! 1917: }
! 1918:
! 1919: void
! 1920: tht_pkt_free(struct tht_softc *sc, struct tht_pkt_list *tpl)
! 1921: {
! 1922: bus_dma_tag_t dmat = sc->sc_thtc->sc_dmat;
! 1923: struct tht_pkt *pkt;
! 1924:
! 1925: while ((pkt = tht_pkt_get(tpl)) != NULL)
! 1926: bus_dmamap_destroy(dmat, pkt->tp_dmap);
! 1927: free(tpl->tpl_pkts, M_DEVBUF);
! 1928: tpl->tpl_pkts = NULL;
! 1929: }
! 1930:
! 1931: void
! 1932: tht_pkt_put(struct tht_pkt_list *tpl, struct tht_pkt *pkt)
! 1933: {
! 1934: TAILQ_REMOVE(&tpl->tpl_used, pkt, tp_link);
! 1935: TAILQ_INSERT_TAIL(&tpl->tpl_free, pkt, tp_link);
! 1936: }
! 1937:
! 1938: struct tht_pkt *
! 1939: tht_pkt_get(struct tht_pkt_list *tpl)
! 1940: {
! 1941: struct tht_pkt *pkt;
! 1942:
! 1943: pkt = TAILQ_FIRST(&tpl->tpl_free);
! 1944: if (pkt != NULL) {
! 1945: TAILQ_REMOVE(&tpl->tpl_free, pkt, tp_link);
! 1946: TAILQ_INSERT_TAIL(&tpl->tpl_used, pkt, tp_link);
! 1947:
! 1948: }
! 1949:
! 1950: return (pkt);
! 1951: }
! 1952:
! 1953: struct tht_pkt *
! 1954: tht_pkt_used(struct tht_pkt_list *tpl)
! 1955: {
! 1956: return (TAILQ_FIRST(&tpl->tpl_used));
! 1957: }
CVSweb