📄 if_gtx.c
字号:
txp->vbuff_ptr = (char *)(sc->tx_buff + (i * TX_BUF_SZ)); txp->buff_ptr = (u_int32_t)VA_TO_PA(txp->vbuff_ptr);#endif CACHESYNC(txp, sizeof(TX_DESC), SYNC_W); } /* Wrap the ring. */ sc->tx_ring[i-1].next = OCRAM_TO_PA(sc->tx_ring); CACHESYNC(&sc->tx_ring[i-1], sizeof(TX_DESC), SYNC_W); /* setup only the lowest priority TxCDP reg */ GT_WRITE(ETH_TX_CURRENT_QUEUE_DESC_PTR_0(sc->sc_port), OCRAM_TO_PA(sc->tx_ring)); GT_WRITE(ETH_TX_CURRENT_QUEUE_DESC_PTR_1(sc->sc_port), 0); /* Initialize Tx indeces and packet counter */ sc->tx_next_in = 0; sc->tx_next_out = 0; sc->tx_count = 0;}static voidreset_rx(struct gtx_softc *sc){ int i; for (i=0; i<RX_RING_SIZE; i++) { RX_DESC *rx_desc; struct mbuf *m; rx_desc = &sc->rx_ring[i]; if (rx_desc->rx_mbuf == NULL) { m = NULL; if(gtx_add_rfabuf(sc, &m) < 0) { printf("%s:malloc fail\n", sc->sc_dev.dv_xname); break; } rx_desc->rx_mbuf = m; }#if defined JAGUAR_ATX rx_desc->vbuff_ptr = (char *)sc->rx_buff + (i * RX_BUF_SZ); rx_desc->buff_ptr = OCRAM_TO_PA(rx_desc->vbuff_ptr);#else rx_desc->vbuff_ptr = NULL; rx_desc->buff_ptr = VA_TO_PA(m->m_data);#endif rx_desc->buf_size = RX_BUF_SZ; rx_desc->byte_cnt = 0; rx_desc->next = OCRAM_TO_PA((sc->rx_ring + (i+1))); /* * Give ownership to device, set first and last, * enable interrupt */ sc->rx_ring[i].cmdstat = (RX_F | RX_L | RX_O | RX_EI); CACHESYNC(&sc->rx_ring[i], sizeof(RX_DESC), SYNC_W); } /* Wrap the ring */ sc->rx_ring[i-1].next = OCRAM_TO_PA(sc->rx_ring); CACHESYNC(&sc->rx_ring[i-1], sizeof(RX_DESC), SYNC_W); /* Setup only the lowest priority regs */ for (i=0; i<4; i++) { if (i == 0) { GT_WRITE(ETH_RX_CURRENT_QUEUE_DESC_PTR_0(sc->sc_port), OCRAM_TO_PA(sc->rx_ring)); } else { GT_WRITE(ETH_RX_CURRENT_QUEUE_DESC_PTR_0(sc->sc_port) + i*4, 0); } } sc->rx_next_out = 0;}intgtx_ioctl(ifp, command, data) struct ifnet *ifp; u_long command; caddr_t data;{ struct gtx_softc *sc = ifp->if_softc; int s, error = 0; s = splimp(); switch (command) { case SIOCSIFADDR: error = ether_ioctl(ifp, command, data); break; case SIOCSIFFLAGS: printf("case SIOCSIFFLAGS, marking interface up/down...\n"); //sc->all_mcasts = (ifp->if_flags & IFF_ALLMULTI) ? 1 : 0; /* * If interface is marked up and not running, then start it. * If it is marked down and running, stop it. * XXX If it's up then re-initialize it. This is so flags * such as IFF_PROMISC are handled. */ if (ifp->if_flags & IFF_UP) { gtx_init(sc); } else { if (ifp->if_flags & IFF_RUNNING) gtx_reset(sc, 1); } break; case SIOCSIFMEDIA: case SIOCGIFMEDIA: /*error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii.mii_media, command);*/ break; default: error = EINVAL; } (void) splx(s); return (error);}voidgtx_init(xsc) void *xsc;{ struct gtx_softc *sc = xsc; struct ifnet *ifp = &sc->arpcom.ac_if; /*s = splimp();*/ /* * Cancel any pending I/O */ ifp->if_flags |= IFF_RUNNING; /* Stop and disable port, or reset to stable state */ /*gtx_reset(sc,0);*/}static intgtx_ether_ioctl(ifp, cmd, data) struct ifnet *ifp; u_int32_t cmd; caddr_t data;{ struct ifaddr *ifa = (struct ifaddr *) data; struct gtx_softc *sc = ifp->if_softc; switch (cmd) { case SIOCSIFADDR: ifp->if_flags |= IFF_UP; switch (ifa->ifa_addr->sa_family) {#ifdef INET case AF_INET: gtx_init(sc); arp_ifinit(&sc->arpcom, ifa); break;#endif#ifdef NS case AF_NS: { struct ns_addr *ina = &IA_SNS(ifa)->sns_addr; if (ns_nullhost(*ina)) ina->x_host = *(union ns_host *) LLADDR(ifp->if_sadl); else bcopy(ina->x_host.c_host, LLADDR(ifp->if_sadl), ifp->if_addrlen); /* Set new address. */ gtx_init(sc); break; }#endif default: gtx_init(sc); break; } break; default: return (EINVAL); } return (0);}static intgtx_intr(arg) void *arg;{ struct gtx_softc *sc = arg; struct ifnet *ifp = &sc->arpcom.ac_if; u_int32_t icr, xicr; /* Read Interrupt Cause Register and ACK interrupts */ icr = GT_READ(ETH_INTERRUPT_CAUSE_REG(sc->sc_port)); GT_WRITE(ETH_INTERRUPT_CAUSE_REG(sc->sc_port), 0); xicr = GT_READ(ETH_INTERRUPT_CAUSE_EXTEND_REG(sc->sc_port)); GT_WRITE(ETH_INTERRUPT_CAUSE_EXTEND_REG(sc->sc_port), 0); /* Process incoming packets if Rx descriptor returned to CPU */ gtx_rx(sc, icr, xicr); /* Transmit more packets if queue isn't empty */ if (ifp->if_snd.ifq_head != NULL) gtx_start(ifp); /* Check for Tx errors */ if (icr & ICR_TXEND(0)) { if (xicr & XICR_TXERROR(0)) printf("%s: Tx error\n", sc->sc_dev.dv_xname); } /* Check for Rx errors */ if (icr & ICR_RXERROR) { printf("%s: Rx. Resetting Rx\n", sc->sc_dev.dv_xname); reset_rx(sc); /* Restart receive engine */ GT_WRITE(ETH_RECEIVE_QUEUE_COMMAND_REG(sc->sc_port), 0x01); } if (xicr & XICR_RXOVR) printf("%s: Rx overrun\n", sc->sc_dev.dv_xname);#if 0 /* Check port status errors */ psr = GT_READ(ETH_PORT_STATUS_REG(sc->sc_port)); if (psr & psrPause) printf("%s: Pause!\n", sc->sc_dev.dv_xname);#endif return(0);}static intgtx_rx(struct gtx_softc *sc, u_int32_t status, u_int32_t xstatus){ struct ifnet *ifp = &sc->arpcom.ac_if; struct mbuf *m; int nextRx; RX_DESC *rd; u_int32_t cmdstat; u_int16_t total_len; /* * Process to current descriptor */ for (nextRx = sc->rx_next_out;; nextRx = (nextRx + 1) % RX_RING_SIZE) { /* This is the only place where we touch rx descriptors */ rd = &sc->rx_ring[nextRx]; cmdstat = (u_int32_t)rd->cmdstat; /* * Bail if gt owns descriptor. This is the workaround for * not relying on the icr register. */ if (cmdstat & RX_O) { CACHESYNC(rd, sizeof(RX_DESC), SYNC_R); /* Push back */ break; } /* * Must be first and last (ie only) buffer of packet */ if (!(cmdstat & RX_F) || !(cmdstat & RX_L)) { printf("%s: descriptor not first and last!\n", sc->sc_dev.dv_xname); goto next; } /* * Drop this packet if there were any errors */ if ((cmdstat & RX_ES) || (status & ICR_RXERROR)) { printf("%s: dropped packet %p:%p\n", sc->sc_dev.dv_xname, cmdstat, status); goto next; } if((total_len = rd->byte_cnt) > MCLBYTES) { printf("%s: bad packet length %d\n", sc->sc_dev.dv_xname, total_len); goto next; } /* * This is where the packets start to get processed to send * to upper layers of the protocol stack. */ m = rd->rx_mbuf; /* * Add a new buffer to the receive descriptor. The old * buffer is recycled if we fail to get a new buffer * and true is returned by gtx_add_rfabuf. */ if (!gtx_add_rfabuf(sc, &rd->rx_mbuf)) { struct ether_header *eh;#ifdef JAGUAR_ATX bcopy(rd->vbuff_ptr, m->m_data, rd->byte_cnt + 2); CACHESYNC(rd->vbuff_ptr, RX_BUF_SZ, SYNC_R);#else /* Attach the new buffer to this descriptor */ rd->buff_ptr = VA_TO_PA(rd->rx_mbuf->m_data);#endif /* extract, save, and reset the length of this packet */ total_len = rd->byte_cnt; rd->byte_cnt = 0; if (total_len < sizeof(struct ether_header)) { printf("%s: short packet received\n", sc->sc_dev.dv_xname); m_freem(m); goto next; } /* set up packet header interface and length */ m->m_pkthdr.rcvif = ifp; m->m_len = total_len - sizeof(struct ether_header); m->m_pkthdr.len = m->m_len; /* * Realign m_data to point actual input data. * The DiscoveryII puts data into the buffer * starting at a 2 byte offset (thanks gyus, * no more copy!). The receive buffer pointer * must be 64 bit aligned though so we adjust * the pointer here before sending up to input. */ m->m_data += RFA_ALIGNMENT_FUDGE; eh = mtod(m, struct ether_header *); m->m_data += sizeof(struct ether_header); ether_input(ifp, eh, m); } else { printf("%s: recycling rxbuf!\n", sc->sc_dev.dv_xname); }next: /* Release ownership to device */ rd->cmdstat = RX_F | RX_L | RX_O | RX_EI; CACHESYNC(rd, sizeof(RX_DESC), SYNC_W); } sc->rx_next_out = nextRx; return 0;}/* * Get a receive buffer and return it's data address. * Return 0 if recycled. */intgtx_add_rfabuf(sc, oldm) struct gtx_softc *sc; struct mbuf **oldm;{ struct mbuf *m, *pm; pm = *oldm; MGETHDR(m, M_DONTWAIT, MT_DATA); if (m != NULL) { MCLGET(m, M_DONTWAIT); if ((m->m_flags & M_EXT) == 0) { m_freem(m); if (pm == NULL) { printf("gtx_add_rfabuf: error 1\n"); return -1; } /* Recycle */ m = pm; m->m_data = m->m_ext.ext_buf; } } else { /* Recycle */ if (pm == NULL) { printf("gtx_add_rfabuf: error 2\n"); return 1; } m = pm; m->m_data = m->m_ext.ext_buf; } /* * Move the data pointer up so that the incoming data packet * will be 64-bit aligned as requiered by the Discovery. * The ether header is not a multiple of 4 bytes but the upper layer * assumes data to be aligned so we will have to adjust this later. */ m->m_data = (void *)ALIGN(m->m_data); CACHESYNC((void *)m->m_data, RX_BUF_SZ, SYNC_R); *oldm = m; return (m == pm);}void gtx_read_mib_counters (sc) struct gtx_softc *sc;{#if 0 u_int32_t *mib_reg = (u_int32_t *)&sc->mib; int i; for (i=0; i<sizeof(mib_counters_t)/sizeof(u_int32_t); i++) { mib_reg[i] = GTETH_READ(sc, ETH0_MIB_COUNTER_BASE + i*sizeof(u_int32_t)); }#endif}static voidmii_write (phyaddr, reg, value) int phyaddr; int reg; int value;{ int data; /* wait for device to become non-busy */ while (GT_READ(ETH_SMI_REG) & (0x1 << 28)) ; data = value & 0xffff; data |= (phyaddr & 0x1f) << 16; data |= (reg & 0x1f) << 21; GT_WRITE(ETH_SMI_REG, data);}static intmii_read (phyaddr, reg) int phyaddr; int reg;{ int data; /* wait for device to become non-busy */ while (GT_READ(ETH_SMI_REG) & (0x1 << 28)) ; data = 0x04000000; data |= (phyaddr & 0x1f) << 16; data |= (reg & 0x1f) << 21; GT_WRITE(ETH_SMI_REG, data); while (GT_READ(ETH_SMI_REG) & (0x1 << 28)) ; return data & 0xffff;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -