📄 keymile_hdlc_enet.c
字号:
et = NULL; arp = NULL; ip = NULL; j = 0; while ((rtx->txbd.cbd_sc & BD_SC_READY) && (j < TOUT_LOOP)) { /* will also trigger Wd if needed, but maybe too often */ udelay(1); j++; } if (j >= TOUT_LOOP) { dprintf("TX not ready sc %x\n", rtx->txbd.cbd_sc); return -1; } /* * First check for an ARP Request since this requires special handling. */ if (len >= (ARP_HDR_SIZE + ETHER_HDR_SIZE)) { et = (Ethernet_t *)packet; arp = (ARP_t *)(((char *)et) + ETHER_HDR_SIZE); /* ARP and REQUEST? */ if (et->et_protlen == PROT_ARP && arp->ar_op == htons(ARPOP_REQUEST)) { /* just short-circuit the request on the U-Boot side */ keymile_hdlc_enet_doarp(packet, len); return 0; } } /* * GJ - I suppose the assumption here that len will always be * > INET_HDR_SIZE is alright as long as the network stack * isn't changed. * Do not send INET header. */ data_len = len + sizeof(header) - INET_HDR_SIZE; frame = (struct icn_frame *) (((char *)packet) + INET_HDR_SIZE - sizeof(header));#ifdef TEST_TX printf("frame: %08x, ", frame); hexdump((unsigned char *)packet, data_len + INET_HDR_SIZE);#endif data_addr = (uint)frame; if (len >= (IP_HDR_SIZE + ETHER_HDR_SIZE)) ip = (IP_t *)(packet + ETHER_HDR_SIZE); /* Is it TFTP? TFTP always uses UDP and the cached dport */ if (ip != NULL && ip->ip_p == IPPROTO_UDP && ip->udp_dst == (ushort)cachedNumbers[TFTP_DST_PORT]) { /* just in case the port wasn't set in the environment */ if (cachedNumbers[TFTP_SRC_PORT] == (ulong)-1) cachedNumbers[TFTP_SRC_PORT] = ip->udp_src; frame->hdr.application = MGS_TFTP; } /* * Is it NETCONSOLE? NETCONSOLE always uses UDP. */ else if (ip != NULL && ip->ip_p == IPPROTO_UDP && ip->udp_dst == (ushort)cachedNumbers[NETCONS_PORT]) { frame->hdr.application = MGS_NETCONS; } else { /* reject unknown packets */ /* may do some check on frame->hdr.application */ dprintf("Unknown packet type in %s, rejected\n", __func__); return -1; } /* * Could extract the target's slot ID from its MAC here, * but u-boot only wants to talk to the active server. * * avoid setting new source address when moving to another slot */ frame->hdr.src_addr = keymile_slot; frame->hdr.dest_addr = HDLC_UACUA;#ifdef TEST_TX { dprintf("TX: "); hexdump((unsigned char *)data_addr, data_len); }#endif flush_cache(data_addr, data_len); rtx->txbd.cbd_bufaddr = data_addr; rtx->txbd.cbd_datlen = data_len; rtx->txbd.cbd_sc |= (BD_SC_READY | BD_SC_TC | BD_SC_LAST | BD_SC_WRAP); while ((rtx->txbd.cbd_sc & BD_SC_READY) && (j < TOUT_LOOP)) { /* will also trigger Wd if needed, but maybe too often */ udelay(1); j++; } if (j >= TOUT_LOOP) dprintf("TX timeout\n");#ifdef ET_DEBUG dprintf("cycles: %d status: %x\n", j, rtx->txbd.cbd_sc);#endif j = (rtx->txbd.cbd_sc & BD_SC_STATS); /* return only status bits */ return j;}/* * During a receive, the RxIdx points to the current incoming buffer. * When we update through the ring, if the next incoming buffer has * not been given to the system, we just set the empty indicator, * effectively tossing the packet. */static int keymile_hdlc_enet_recv(struct eth_device *dev){ int length; unsigned char app; struct icn_frame *fp; Ethernet_t *ep; IP_t *ip; for (;;) { if (rtx->rxbd[keymile_rxIdx].cbd_sc & BD_SC_EMPTY) { length = -1; break; /* nothing received - leave for() loop */ } length = rtx->rxbd[keymile_rxIdx].cbd_datlen;#ifdef TEST_RX dprintf("packet %d bytes long\n", length);#endif /* * BD_SC_BR -> LG bit * BD_SC_FR -> NO bit * BD_SC_PR -> AB bit * BD_SC_NAK -> CR bit * 0x80 -> DE bit */ if (rtx->rxbd[keymile_rxIdx].cbd_sc & BD_SC_STATS) {#ifdef ET_DEBUG dprintf("err: %x\n", rtx->rxbd[keymile_rxIdx].cbd_sc);#endif } else if (length > MAX_FRAME_LENGTH) { /* can't happen */#ifdef ET_DEBUG dprintf("err: packet too big\n");#endif } else { fp = (struct icn_frame *)(MyRxPackets[keymile_rxIdx] + INET_HDR_ALIGN - INET_HDR_SIZE);#ifdef TEST_RX dprintf("RX %d: ", keymile_rxIdx); hexdump((unsigned char *)MyRxPackets[keymile_rxIdx], INET_HDR_ALIGN + INET_HDR_SIZE + 4);#endif /* copy icn header to the beginning */ memcpy(fp, ((char *)fp + INET_HDR_SIZE), sizeof(struct icn_hdr)); app = fp->hdr.application; if (app == MGS_NETCONS || app == MGS_TFTP) { struct icn_hdr *ih = &fp->hdr; unsigned char icn_src_addr = ih->src_addr; unsigned char icn_dest_addr = ih->dest_addr; /* * expand header by INET_HDR_SIZE */ length += INET_HDR_SIZE; /* initalize header */ memset((char *)fp->data, 0x00, INET_HDR_SIZE); ep = (Ethernet_t *)fp->data; /* set MACs */ ep->et_dest[0] = icn_dest_addr; ep->et_src[0] = icn_src_addr; ep->et_protlen = htons(PROT_IP); /* set ip stuff */ ip = (IP_t *)(fp->data + ETHER_HDR_SIZE); /* set ip addresses */ ip->ip_src = cachedNumbers[IP_SERVER]; ip->ip_dst = cachedNumbers[IP_ADDR]; /* ip length */ ip->ip_len = htons(length - ETHER_HDR_SIZE - REMOVE); /* ip proto */ ip->ip_p = IPPROTO_UDP; switch (app) { case MGS_TFTP: /* swap src/dst port numbers */ ip->udp_src = (ushort) cachedNumbers[TFTP_DST_PORT]; ip->udp_dst = (ushort) cachedNumbers[TFTP_SRC_PORT]; ip->udp_len = ip->ip_len - IP_HDR_SIZE_NO_UDP; ip->udp_xsum = 0; break; case MGS_NETCONS: ip->udp_src = (ushort) cachedNumbers[NETCONS_PORT]; /* * in drivers/net/netconsole.c src port * equals dest port */ ip->udp_dst = ip->udp_src; ip->udp_len = ip->ip_len - IP_HDR_SIZE_NO_UDP; ip->udp_xsum = 0; break; } /* ip version */ ip->ip_hl_v = (0x40) | (0x0f & (IP_HDR_SIZE_NO_UDP / 4)); ip->ip_tos = 0; ip->ip_id = 0; /* flags, fragment offset */ ip->ip_off = htons(0x4000); ip->ip_ttl = 255; /* time to live */ /* have to fixup the checksum */ ip->ip_sum = ~NetCksum((uchar *)ip, IP_HDR_SIZE_NO_UDP / 2); /* * Pass the packet up to the protocol layers * but remove dest_addr, src_addr, application * and the CRC. */#ifdef TEST_RX hexdump((unsigned char *)fp->data, INET_HDR_SIZE + 4);#endif NetReceive(fp->data, length - REMOVE); } else { /* * the other application types are not yet * supported by u-boot. */ /* normally drop it */#ifdef TEST_NO /* send it anyway */ fp = (struct icn_frame *) (MyRxPackets[keymile_rxIdx] + INET_HDR_ALIGN); NetReceive(fp->data, length - REMOVE);#endif } } /* Give the buffer back to the SCC. */ rtx->rxbd[keymile_rxIdx].cbd_datlen = 0; /* wrap around buffer index when necessary */ if ((keymile_rxIdx + 1) >= HDLC_PKTBUFSRX) { rtx->rxbd[HDLC_PKTBUFSRX - 1].cbd_sc = (BD_SC_WRAP | BD_SC_EMPTY); keymile_rxIdx = 0; } else { rtx->rxbd[keymile_rxIdx].cbd_sc = BD_SC_EMPTY; keymile_rxIdx++; } } return length;}#ifdef TEST_IT/* simple send test routine */int hdlc_enet_stest(struct cmd_tbl_s *a, int b, int c, char **d){ unsigned char pkt[2]; int ret; dprintf("enter stest\n"); /* may have to initialize things */ if (seth->state != ETH_STATE_ACTIVE) { /* the bd_t* is not used */ if (seth->init(seth, NULL) >= 0) seth->state = ETH_STATE_ACTIVE; } pkt[0] = 0xea; pkt[1] = 0xae; ret = keymile_hdlc_enet_send(seth, pkt, 2); dprintf("return from send %x\n", ret); dprintf("exit stest\n"); return ret;}U_BOOT_CMD( stest, 1, 1, hdlc_enet_stest, "simple send test for hdlc_enet", "no arguments\n");/* simple receive test routine */int hdlc_enet_rtest(struct cmd_tbl_s *a, int b, int c, char **d){ int ret; dprintf("enter rtest\n"); /* may have to initialize things */ if (seth->state != ETH_STATE_ACTIVE) { /* the bd_t* is not used */ if (seth->init(seth, NULL) >= 0) seth->state = ETH_STATE_ACTIVE; } ret = keymile_hdlc_enet_recv(seth); dprintf("return from recv %x\n", ret); dprintf("exit rtest\n"); return ret;}U_BOOT_CMD( rtest, 1, 1, hdlc_enet_rtest, "simple receive test for hdlc_enet", "no arguments\n");#endif#endif /* CONFIG_KEYMILE_HDLC_ENET */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -