blob: 4ec8c7c593f28b6d14928038652e57bd01533dc2 [file] [log] [blame]
/*
* (C) Copyright 2015 Google, Inc.
* All rights reserved.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <linux/if_packet.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/ether.h>
#include <netinet/in.h>
#include <netdb.h>
#include <linux/types.h>
#include <unistd.h>
#include <stdbool.h>
#include <errno.h>
#include <signal.h>
#include "gpio.h"
#include "../common/util.h"
#include "../common/io.h"
#include "common.h"
#if USE_WAN0
#define MY_DEST_MAC0 0xc8
#define MY_DEST_MAC1 0xb3
#define MY_DEST_MAC2 0x73
#define MY_DEST_MAC3 0x36
#define MY_DEST_MAC4 0x00
#define MY_DEST_MAC5 0x9d
#else
#define MY_DEST_MAC0 0x33
#define MY_DEST_MAC1 0x33
#define MY_DEST_MAC2 0x00
#define MY_DEST_MAC3 0x00
#define MY_DEST_MAC4 0x00
#define MY_DEST_MAC5 0x01
#endif
#define DEFAULT_TST_IF "wlan0"
#define LAN_PORT_NAME "lan0"
#define WAN_PORT_NAME "wan0"
#define BUF_SIZ 1514
#define GE_TEST_MAX_CMD 4096
#define GE_TEST_MAX_RSP 4096
#define GE_TRAFFIC_PORT "lan0"
#define GE_TRAFFIC_DST_PORT "wan0"
#define GE_TRAFFIC_REPORT_PERIOD 10
#define GE_TRAFFIC_TEST_PERIOD_SYMBOL "-p"
#define SERVER_PORT 8888
#define MAX_CMD_SIZE 256
#define GE_SEND_DELAY_IN_USEC 1000
#define GE_MAX_LAN_PORTS 4
#define GE_WAIT_AFTER_LOOPBACK_SET 5
#define GE_PKTS_SENT_BEFORE_WAIT 0xFF
#define GE_PKTS_LEN_DEFAULT 32
#define GE_BUFFER_SIZE (GE_PKTS_SENT_BEFORE_WAIT * GE_PKTS_LEN_DEFAULT)
#define GE_LOOPBACK_PASS_FACTOR 0.8 // 80%
/* Max MII register/address (we support) */
#define MII_REGISTER_MAX 31
#define MII_ADDRESS_MAX 31
#define MDIO_TIMEOUT 5000
#define PHY_MAN_BASE 0x9c200000
#define EMAC_PHY_MANAGEMENT 0x34
#define EMAC_NETWORK_STATUS 0x8
#define PHY_MAN_READ_BASE 0x60020000
#define PHY_MAN_WRITE_BASE 0x50020000
#define PHY_ADDR_MASK 0x1f
#define PHY_ADDR_POS 23
#define PHY_REG_POS 18
#define PHY_DATA_MASK 0xffff
#define EMAC_PHY_IDLE (1 << 2)
#define SPACECAST_PHY_ADDR 1
#define M88E1512_PHY_PAGE_REG 22
#define M88E1512_PHY_DEFAULT_PAGE 0
#define M88E1512_PHY_PAGE_6 6
#define M88E1512_PHY_CHECKER_CTRL_REG 18
#define M88E1512_PHY_ENABLE_STUB_TEST_BIT 3
/********************************************************************
* gem_phy_man_rd :
* Performs phy management read operation.
*******************************************************************/
static void gem_phy_man_rd(unsigned int phy_addr, unsigned int phy_reg) {
unsigned int write_data;
write_data =
PHY_MAN_READ_BASE |
((phy_addr & (unsigned int)PHY_ADDR_MASK) << PHY_ADDR_POS) |
((phy_reg & (unsigned int)PHY_ADDR_MASK) << PHY_REG_POS); // read_op
write_physical_addr(PHY_MAN_BASE + EMAC_PHY_MANAGEMENT, write_data);
}
static void gem_phy_man_wr(unsigned int phy_addr, unsigned int phy_reg,
unsigned int val) {
unsigned int write_data;
write_data = PHY_MAN_WRITE_BASE |
((phy_addr & (unsigned int)PHY_ADDR_MASK) << PHY_ADDR_POS) |
((phy_reg & (unsigned int)PHY_ADDR_MASK) << PHY_REG_POS) |
(val & (unsigned int)PHY_DATA_MASK); // write_op
write_physical_addr(PHY_MAN_BASE + EMAC_PHY_MANAGEMENT, write_data);
}
/** gem_phy_man_data
* Read the data section of phy management register.
* After a successful read opeeration the data will be stored in
* in this register in lower 16bits.
*/
static unsigned int gem_phy_man_data() {
unsigned int value;
read_physical_addr(PHY_MAN_BASE + EMAC_PHY_MANAGEMENT, &value);
value &= PHY_DATA_MASK;
return value;
}
static int gem_phy_man_idle() {
unsigned int value;
read_physical_addr(PHY_MAN_BASE + EMAC_NETWORK_STATUS, &value);
return ((value & EMAC_PHY_IDLE) == EMAC_PHY_IDLE);
}
static int gem_phy_timeout(int timeout) {
while (!gem_phy_man_idle()) {
if (timeout-- <= 0) {
printf("Phy MDIO read/write timeout\n");
return -1;
}
}
return 0;
}
/** PHY read function
* Reads a 16bit value from a MII register
*
* @param[in] mdev Pointer to MII device structure
* @param[in] phy_addr
* @param[in] phy_reg
*
* @return 16bit value on success, a negative value (-1) on error
*/
static int c2000_phy_read(int phy_addr, int phy_reg) {
int value;
if ((phy_addr > MII_ADDRESS_MAX) || (phy_reg > MII_REGISTER_MAX)) return -1;
gem_phy_man_rd(phy_addr, phy_reg);
if (gem_phy_timeout(MDIO_TIMEOUT)) return -1;
value = gem_phy_man_data();
return value;
}
/** PHY write function
* Writes a 16bit value to a MII register
*
* @param[in] mdev Pointer to MII device structure
* @param[in] phy_addr
* @param[in] phy_reg
* @param[in] value Value to be written to Phy
*
* @return On success returns 0, a negative value (-1) on error
*/
static int c2000_phy_write(int phy_addr, int phy_reg, int value) {
if ((phy_addr > MII_ADDRESS_MAX) || (phy_reg > MII_REGISTER_MAX)) return -1;
gem_phy_man_wr(phy_addr, phy_reg, value);
if (gem_phy_timeout(MDIO_TIMEOUT)) return -1;
return 0;
}
void send_mac_pkt(char *if_name, char *out_name, unsigned int xfer_len,
unsigned int xfer_wait, int n,
const unsigned char *dst_mac1) {
int sockfd, i;
struct ifreq if_idx;
struct ifreq if_mac, out_mac;
int tx_len = 0;
char sendbuf[BUF_SIZ];
struct ether_header *eh = (struct ether_header *)sendbuf;
struct sockaddr_ll socket_address;
unsigned char dst_mac[6] = {0, 0, 0, 0, 0, 0};
/* Open RAW socket to send on */
if ((sockfd = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW)) == -1) {
perror("socket");
}
/* Get the index of the interface to send on */
memset(&if_idx, 0, sizeof(if_idx));
safe_strncpy(if_idx.ifr_name, if_name, IFNAMSIZ - 1);
if (ioctl(sockfd, SIOCGIFINDEX, &if_idx) < 0) {
perror("SIOCGIFINDEX");
}
/* Get the MAC address of the interface to send on */
memset(&out_mac, 0, sizeof(out_mac));
if (out_name != NULL) {
safe_strncpy(out_mac.ifr_name, out_name, IFNAMSIZ - 1);
if (ioctl(sockfd, SIOCGIFHWADDR, &out_mac) < 0) {
perror("out SIOCGIFHWADDR");
}
}
memset(&if_mac, 0, sizeof(if_mac));
safe_strncpy(if_mac.ifr_name, if_name, IFNAMSIZ - 1);
if (ioctl(sockfd, SIOCGIFHWADDR, &if_mac) < 0) {
perror("SIOCGIFHWADDR");
}
if (out_name != NULL) {
dst_mac[0] = ((uint8_t *)&out_mac.ifr_hwaddr.sa_data)[0];
dst_mac[1] = ((uint8_t *)&out_mac.ifr_hwaddr.sa_data)[1];
dst_mac[2] = ((uint8_t *)&out_mac.ifr_hwaddr.sa_data)[2];
dst_mac[3] = ((uint8_t *)&out_mac.ifr_hwaddr.sa_data)[3];
dst_mac[4] = ((uint8_t *)&out_mac.ifr_hwaddr.sa_data)[4];
dst_mac[5] = ((uint8_t *)&out_mac.ifr_hwaddr.sa_data)[5];
} else if (dst_mac1 != NULL) {
dst_mac[0] = dst_mac1[0];
dst_mac[1] = dst_mac1[1];
dst_mac[2] = dst_mac1[2];
dst_mac[3] = dst_mac1[3];
dst_mac[4] = dst_mac1[4];
dst_mac[5] = dst_mac1[5];
} else {
printf("Invalid out_name and dst_mac.\n");
return;
}
/* Construct the Ethernet header */
// memset(sendbuf, 0, BUF_SIZ);
for (i = 0; i < BUF_SIZ; ++i) {
sendbuf[i] = 0xA5;
}
/* Ethernet header */
eh->ether_shost[0] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[0];
eh->ether_shost[1] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[1];
eh->ether_shost[2] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[2];
eh->ether_shost[3] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[3];
eh->ether_shost[4] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[4];
eh->ether_shost[5] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[5];
eh->ether_dhost[0] = dst_mac[0];
eh->ether_dhost[1] = dst_mac[1];
eh->ether_dhost[2] = dst_mac[2];
eh->ether_dhost[3] = dst_mac[3];
eh->ether_dhost[4] = dst_mac[4];
eh->ether_dhost[5] = dst_mac[5];
/* Ethertype field */
eh->ether_type = htons(ETH_P_IP);
tx_len += sizeof(struct ether_header);
/* Packet data */
sendbuf[tx_len++] = 0xde;
sendbuf[tx_len++] = 0xad;
sendbuf[tx_len++] = 0xbe;
sendbuf[tx_len++] = 0xef;
/* Index of the network device */
socket_address.sll_ifindex = if_idx.ifr_ifindex;
/* Address length*/
socket_address.sll_halen = ETH_ALEN;
/* Destination MAC */
socket_address.sll_addr[0] = dst_mac[0];
socket_address.sll_addr[1] = dst_mac[1];
socket_address.sll_addr[2] = dst_mac[2];
socket_address.sll_addr[3] = dst_mac[3];
socket_address.sll_addr[4] = dst_mac[4];
socket_address.sll_addr[5] = dst_mac[5];
sleep(1);
/* Send packet */
if (n < 0) {
while (1) {
if (sendto(sockfd, sendbuf, xfer_len, 0,
(struct sockaddr *)&socket_address,
sizeof(struct sockaddr_ll)) < 0) {
printf("Send failed at msg %d\n", i);
break;
}
if (xfer_wait > 0) {
if ((i & GE_PKTS_SENT_BEFORE_WAIT) == 0) {
usleep(xfer_wait);
}
}
}
} else {
for (i = 0; i < n; ++i) {
if (sendto(sockfd, sendbuf, xfer_len, 0,
(struct sockaddr *)&socket_address,
sizeof(struct sockaddr_ll)) < 0) {
printf("Send failed at msg %d\n", i);
break;
}
if (xfer_wait > 0) {
if ((i & GE_PKTS_SENT_BEFORE_WAIT) == 0) {
usleep(xfer_wait);
}
}
}
}
close(sockfd);
}
static void phy_read_usage(void) {
printf("phy_read <register>\n");
printf("Example:\n");
printf("phy_read 22\n");
printf("read PHY register 22\n");
}
int phy_read(int argc, char *argv[]) {
int reg, data;
if (argc != 2) {
phy_read_usage();
return -1;
}
reg = strtol(argv[1], NULL, 10);
data = c2000_phy_read(SPACECAST_PHY_ADDR, reg);
printf("Reg %d: 0x%x\n", reg, data);
return 0;
}
static void phy_write_usage(void) {
printf("phy_write <register> <data>\n");
printf("Example:\n");
printf("phy_write 22 2\n");
printf("write 2 to PHY register 22\n");
}
int phy_write(int argc, char *argv[]) {
int reg, data;
if (argc != 3) {
phy_write_usage();
return -1;
}
reg = strtol(argv[1], NULL, 10);
data = strtoul(argv[2], NULL, 16);
c2000_phy_write(SPACECAST_PHY_ADDR, reg, data);
printf("Write PHY Reg %d: 0x%x\n", reg, data);
return 0;
}
static void send_ip_usage(void) {
printf("send_ip <address> <port> <num>\n");
printf("Example:\n");
printf("send_ip 192.168.1.1 10000 1\n");
printf("send 1 msg to ip address 192.168.1.1 port 10000\n");
}
int send_ip(int argc, char *argv[]) {
int sockfd, portno, i, n;
struct sockaddr_in serv_addr;
char *my_msg = "This is a test";
unsigned int ipaddr[4];
uint32_t ia;
if (argc != 4) {
send_ip_usage();
return -1;
}
sscanf(argv[1], "%u.%u.%u.%u", &(ipaddr[0]), &(ipaddr[1]), &(ipaddr[2]),
&(ipaddr[3]));
ia = (ipaddr[3] << 24) | (ipaddr[2] << 16) | (ipaddr[1] << 8) | ipaddr[0];
portno = strtoul(argv[2], NULL, 0);
n = strtoul(argv[3], NULL, 0);
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = portno;
serv_addr.sin_addr.s_addr = (__be32)(ia);
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) {
printf("Cannot create socket. sockfd = %d\n", sockfd);
return -1;
}
for (i = 0; i < n; ++i) {
if (sendto(sockfd, my_msg, strlen(my_msg), 0, (struct sockaddr *)&serv_addr,
sizeof(serv_addr)) < 0) {
printf("Cannot send msg to socket %s\n", my_msg);
return -1;
}
}
printf("send %d packets to %u.%u.%u.%u:0x%08x port %d\n", n, ipaddr[0],
ipaddr[1], ipaddr[2], ipaddr[3], serv_addr.sin_addr.s_addr, portno);
return 0;
}
int setup_loopback(int port) {
char command[GE_TEST_MAX_CMD];
FILE *fp;
// ssdk_sh hardcoded wan0 to be up in order to work
system_cmd("ifup wan0");
// printf("Set up loop back on PHY %d\n", port);
sprintf(command, "ssdk_sh >> %s\n", TMP_FILE);
fp = popen(command, "w");
fprintf(fp, "debug phy set %d 0x1d 0xb\n", port);
fprintf(fp, "debug phy set %d 0x1e 0x3c40\n", port);
fprintf(fp, "debug phy set %d 0x1d 0x11\n", port);
fprintf(fp, "debug phy set %d 0x1e 0x7553\n", port);
fprintf(fp, "debug phy set %d 0x10 0x0800\n", port);
fprintf(fp, "debug phy set %d 0x0 0x8140\n", port);
if (port == 4) {
fprintf(fp, "debug phy set %d 0x0 0x0140\n", port);
}
fprintf(fp, "quit\n");
pclose(fp);
system_cmd("ifdown wan0");
return 0;
}
int take_down_loopback(int port) {
char command[GE_TEST_MAX_CMD];
FILE *fp;
system_cmd("ifup wan0");
sprintf(command, "ssdk_sh >> %s\n", TMP_FILE);
fp = popen(command, "w");
fprintf(fp, "debug phy set %d 0x1d 0xb\n", port);
fprintf(fp, "debug phy set %d 0x1e 0xbc40\n", port);
fprintf(fp, "debug phy set %d 0x1d 0x11\n", port);
fprintf(fp, "debug phy set %d 0x1e 0x7552\n", port);
fprintf(fp, "debug phy set %d 0x10 0x0862\n", port);
fprintf(fp, "debug phy set %d 0x0 0x1000\n", port);
fprintf(fp, "quit\n");
pclose(fp);
system_cmd("ifdown wan0");
// printf("Take down loop back on PHY %d\n",port);
return 0;
}
int atheros_drv_init() {
char command[GE_TEST_MAX_CMD];
FILE *fp;
system_cmd("ifup wan0");
sprintf(command, "ssdk_sh >> %s\n", TMP_FILE);
fp = popen(command, "w");
fprintf(fp, "debug reg set 0x0624 0x3f3f3f 4\n");
fprintf(fp, "debug reg set 0x0004 0x6800000 4\n");
fprintf(fp, "debug reg set 0x0008 0x1000000 4\n");
fprintf(fp, "debug reg set 0x000c 0x20000 4\n");
fprintf(fp, "debug reg set 0x0090 0 4\n");
fprintf(fp, "debug reg set 0x0094 0 4\n");
fprintf(fp, "debug reg set 0x007c 0xfe 4\n");
fprintf(fp, "debug reg get 0x0 4\n");
fprintf(fp, "debug phy set 4 0x1d 0x0\n");
fprintf(fp, "debug phy get 4 0x1e\n");
fprintf(fp, "debug phy set 4 0x1d 0x0\n");
fprintf(fp, "debug phy set 4 0x1e 0x82ee\n");
fprintf(fp, "debug phy set 4 0x1d 0x5\n");
fprintf(fp, "debug phy get 4 0x1e\n");
fprintf(fp, "debug phy set 4 0x1d 0x5\n");
fprintf(fp, "debug phy set 4 0x1e 0x1d47\n");
fprintf(fp, "debug reg set 0x0970 0x2a666666 4\n");
fprintf(fp, "debug reg set 0x0974 0xc6 4\n");
fprintf(fp, "debug reg set 0x0978 0x2a008888 4\n");
fprintf(fp, "debug reg set 0x097c 0xc6 4\n");
fprintf(fp, "debug reg set 0x0980 0x2a008888 4\n");
fprintf(fp, "debug reg set 0x0984 0xc6 4\n");
fprintf(fp, "debug reg set 0x0988 0x2a008888 4\n");
fprintf(fp, "debug reg set 0x098C 0xc6 4\n");
fprintf(fp, "debug reg set 0x0990 0x2a008888 4\n");
fprintf(fp, "debug reg set 0x0994 0xc6 4\n");
fprintf(fp, "debug reg set 0x0998 0x2a666666 4\n");
fprintf(fp, "debug reg set 0x099C 0xc6 4\n");
fprintf(fp, "debug reg set 0x09a0 0x2a666666 4\n");
fprintf(fp, "debug reg set 0x09a4 0xc6 4\n");
fprintf(fp, "debug reg set 0x0050 0xffb7ffb7 4\n");
fprintf(fp, "debug reg set 0x0054 0xffb7ffb7 4\n");
fprintf(fp, "debug reg set 0x0058 0xffb7ffb7 4\n");
fprintf(fp, "quit\n");
pclose(fp);
system_cmd("ifdown wan0");
return 0;
}
int atheros_phy_init() {
char command[GE_TEST_MAX_CMD];
FILE *fp;
system_cmd("ifup wan0");
sprintf(command, "ssdk_sh >> %s\n", TMP_FILE);
fp = popen(command, "w");
// PHY 0
fprintf(fp, "debug phy set 0 4 0xDE0\n");
fprintf(fp, "debug phy set 0 9 0x0200\n");
fprintf(fp, "debug phy set 0 0 0x9000\n");
fprintf(fp, "debug phy get 0 0\n");
fprintf(fp, "debug phy set 0 13 3\n");
fprintf(fp, "debug phy set 0 14 0x8007\n");
fprintf(fp, "debug phy set 0 13 0x4003\n");
fprintf(fp, "debug phy set 0 14 0x8315\n");
fprintf(fp, "debug phy set 0 13 3\n");
fprintf(fp, "debug phy set 0 14 0x800d\n");
fprintf(fp, "debug phy set 0 13 0x4003\n");
fprintf(fp, "debug phy set 0 14 0x103f\n");
fprintf(fp, "debug phy set 0 0x1d 0x3d\n");
fprintf(fp, "debug phy set 0 0x1e 0x6860\n");
// PHY 1
fprintf(fp, "debug phy set 1 4 0xDE0\n");
fprintf(fp, "debug phy set 1 9 0x0200\n");
fprintf(fp, "debug phy set 1 0 0x9000\n");
fprintf(fp, "debug phy get 1 0\n");
fprintf(fp, "debug phy set 1 13 3\n");
fprintf(fp, "debug phy set 1 14 0x8007\n");
fprintf(fp, "debug phy set 1 13 0x4003\n");
fprintf(fp, "debug phy set 1 14 0x8315\n");
fprintf(fp, "debug phy set 1 13 3\n");
fprintf(fp, "debug phy set 1 14 0x800d\n");
fprintf(fp, "debug phy set 1 13 0x4003\n");
fprintf(fp, "debug phy set 1 14 0x103f\n");
fprintf(fp, "debug phy set 1 0x1d 0x3d\n");
fprintf(fp, "debug phy set 1 0x1e 0x6860\n");
// PHY 2
fprintf(fp, "debug phy set 2 4 0xDE0\n");
fprintf(fp, "debug phy set 2 9 0x0200\n");
fprintf(fp, "debug phy set 2 0 0x9000\n");
fprintf(fp, "debug phy get 2 0\n");
fprintf(fp, "debug phy set 2 13 3\n");
fprintf(fp, "debug phy set 2 14 0x800d\n");
fprintf(fp, "debug phy set 2 13 0x4003\n");
fprintf(fp, "debug phy set 2 14 0x103f\n");
fprintf(fp, "debug phy set 2 0x1d 0x3d\n");
fprintf(fp, "debug phy set 2 0x1e 0x6860\n");
// PHY 3
fprintf(fp, "debug phy set 3 4 0xDE0\n");
fprintf(fp, "debug phy set 3 9 0x0200\n");
fprintf(fp, "debug phy set 3 0 0x9000\n");
fprintf(fp, "debug phy get 3 0\n");
fprintf(fp, "debug phy set 3 13 3\n");
fprintf(fp, "debug phy set 3 14 0x800d\n");
fprintf(fp, "debug phy set 3 13 0x4003\n");
fprintf(fp, "debug phy set 3 14 0x103f\n");
fprintf(fp, "debug phy set 3 0x1d 0x3d\n");
fprintf(fp, "debug phy set 3 0x1e 0x6860\n");
// PHY 4
fprintf(fp, "debug phy set 4 4 0xDE0\n");
fprintf(fp, "debug phy set 4 9 0x0200\n");
fprintf(fp, "debug phy set 4 0 0x9000\n");
fprintf(fp, "debug phy get 4 0\n");
fprintf(fp, "debug phy set 4 13 3\n");
fprintf(fp, "debug phy set 4 14 0x800d\n");
fprintf(fp, "debug phy set 4 13 0x4003\n");
fprintf(fp, "debug phy set 4 14 0x103f\n");
fprintf(fp, "debug phy set 4 0x1d 0x3d\n");
fprintf(fp, "debug phy set 4 0x1e 0x6860\n");
fprintf(fp, "debug phy set 4 0x1d 0x12\n");
fprintf(fp, "debug phy set 4 0x1e 0x4c0c\n");
fprintf(fp, "debug phy set 4 0x1d 0x0\n");
fprintf(fp, "debug phy set 4 0x1e 0x82ee\n");
fprintf(fp, "debug phy set 4 0x1d 0x5\n");
fprintf(fp, "debug phy set 4 0x1e 0x3d46\n");
fprintf(fp, "debug phy set 4 0x1d 0xb\n");
fprintf(fp, "debug phy set 4 0x1e 0xbc20\n");
fprintf(fp, "quit\n");
pclose(fp);
system_cmd("ifdown wan0");
// printf("Take down loop back on PHY %d\n",port);
return 0;
}
static void atheros_init_usage(void) {
printf("atheros_init\n");
printf("Example:\n");
printf("atheros_init\n");
printf("initialize atheros chipset\n");
}
int atheros_init(int argc, char *argv[]) {
if ((argc != 1) || (argv[0] == NULL)) {
atheros_init_usage();
return -1;
}
return atheros_drv_init();
}
static void phy_init_usage(void) {
printf("phy_init\n");
printf("Example:\n");
printf("phy_init\n");
printf("initialize all PHY port (0 to 4)\n");
}
int phy_init(int argc, char *argv[]) {
if ((argc != 1) || (argv[0] == NULL)) {
phy_init_usage();
return -1;
}
return atheros_phy_init();
}
int get_ip_stat(int *rx_pkts, int *tx_pkts, int *rx_errs, int *tx_errs,
char *name) {
char command[4096], rsp[MAX_CMD_SIZE];
FILE *fp;
unsigned int j;
strcpy(command, "ifstat ");
strcat(command, name);
fp = popen(command, "r");
while (fscanf(fp, "%s", rsp) != EOF) {
if (!strncmp(rsp, name, strlen(name))) {
if (fscanf(fp, "%s", rsp) <= 0) return -1;
sscanf(rsp, "%d", rx_pkts);
for (j = 0; j < strlen(rsp); ++j) {
if (rsp[j] == 'K') {
*rx_pkts *= 1000;
break;
}
}
// RX Pkts rate
if (fscanf(fp, "%s", rsp) <= 0) return -1;
// TX
if (fscanf(fp, "%s", rsp) <= 0) return -1;
sscanf(rsp, "%d", tx_pkts);
for (j = 0; j < strlen(rsp); ++j) {
if (rsp[j] == 'K') {
*tx_pkts *= 1000;
break;
}
}
// TX Pkts rate
if (fscanf(fp, "%s", rsp) <= 0) return -1;
// RX Data
if (fscanf(fp, "%s", rsp) <= 0) return -1;
// RX Data Rate
if (fscanf(fp, "%s", rsp) <= 0) return -1;
// TX Data
if (fscanf(fp, "%s", rsp) <= 0) return -1;
// TX Data Rate
if (fscanf(fp, "%s", rsp) <= 0) return -1;
// RX Errs
if (fscanf(fp, "%s", rsp) <= 0) return -1;
sscanf(rsp, "%d", rx_errs);
// RX Drop
if (fscanf(fp, "%s", rsp) <= 0) return -1;
// TX Errs
if (fscanf(fp, "%s", rsp) <= 0) return -1;
sscanf(rsp, "%d", tx_errs);
break;
}
}
pclose(fp);
return 0;
}
int get_if_ip(char *name, unsigned int *ip) {
char command[GE_TEST_MAX_CMD], rsp[GE_TEST_MAX_RSP];
static const char *kIpName = "inet";
FILE *fp;
bool found = false;
sprintf(command, "ip addr show %s", name);
fp = popen(command, "r");
while (fscanf(fp, "%s", rsp) != EOF) {
if (!strcmp(rsp, kIpName)) {
if (fscanf(fp, "%s", rsp) <= 0) return -1;
if (sscanf(rsp, "%u.%u.%u.%u", ip, (ip + 1), (ip + 2), (ip + 3)) <= 0) {
return -1;
}
found = true;
break;
}
}
pclose(fp);
if (!found) {
return -1;
}
return 0;
}
static void send_eth_usage(void) {
printf(
"send_eth <source if> <dest if> <num>"
" [-t <delay between pkts send>]\n");
printf("Example:\n");
printf("send_eth lan0 wan0 100\n");
printf("send 100 msg from lan0 to wan0\n");
}
int send_eth(int argc, char *argv[]) {
int n;
char if_name[IFNAMSIZ];
char out_name[IFNAMSIZ];
unsigned char dst_mac[6] = {0, 0, 0, 0, 0, 0};
unsigned int xfer_wait = GE_SEND_DELAY_IN_USEC;
/* Get interface name */
if (argc == 6) {
if (strcmp(argv[4], "-t") == 0) {
xfer_wait = strtoul(argv[5], NULL, 10);
} else {
send_eth_usage();
return -1;
}
} else if (argc != 4) {
send_eth_usage();
return -1;
}
strcpy(if_name, argv[1]);
strcpy(out_name, argv[2]);
n = strtol(argv[3], NULL, 10);
send_mac_pkt(if_name, out_name, BUF_SIZ, xfer_wait, n, NULL);
printf("Sent %d pkt of size %d from %s to %02x:%02x:%02x:%02x:%02x:%02x\n", n,
BUF_SIZ, argv[1], dst_mac[0], dst_mac[1], dst_mac[2], dst_mac[3],
dst_mac[4], dst_mac[5]);
return 0;
}
static void geloopback_usage(void) {
printf(
"geloopback <PHY ports in bit mask (hex)> <num> "
"[-b <pkt byte size (max %d)>] "
"[-t <time delay in micro-second between pkt send>]\n",
BUF_SIZ);
printf("Example:\n");
printf("geloopback 0x1F 100\n");
printf("loopback PHY port 0, 1, 2, 3 ,4 with 100 msgs\n");
printf("geloopback 0xF 100 -b 256 -t 250\n");
printf(
"loopback PHY port 0, 1, 2, 3 with 100 msgs of size 256 bytes "
"and 250 us delay\n");
}
int geloopback(int argc, char *argv[]) {
int n, port, pass_num, j;
unsigned int xfer_len = GE_PKTS_LEN_DEFAULT, xfer_wait = 250, rx_wait = 2;
char if_name[IFNAMSIZ];
char out_name[IFNAMSIZ];
// char cmd[MAX_CMD_SIZE];
int rx_pkts, tx_pkts, rx_errs, tx_errs;
unsigned int portMask;
static const int kLoopbackRetries = 3;
/* Get interface name */
if ((argc != 3) && (argc != 5) && (argc != 7)) {
printf("%s invalid params\n", FAIL_TEXT);
geloopback_usage();
return -1;
}
#if 0
// Increase the buffer size
sprintf(cmd, "echo %d > /proc/sys/net/core/rmem_max", GE_BUFFER_SIZE);
system_cmd(cmd);
sprintf(cmd, "echo %d > /proc/sys/net/core/rmem_default", GE_BUFFER_SIZE);
system_cmd(cmd);
sprintf(cmd, "echo %d > /proc/sys/net/core/wmem_max", GE_BUFFER_SIZE);
system_cmd(cmd);
sprintf(cmd, "echo %d > /proc/sys/net/core/wmem_default", GE_BUFFER_SIZE);
system_cmd(cmd);
#endif
portMask = strtoul(argv[1], NULL, 16);
n = strtoul(argv[2], NULL, 10);
pass_num = (int)(n * GE_LOOPBACK_PASS_FACTOR);
if (argc >= 5) {
unsigned int tmp;
tmp = strtoul(argv[4], NULL, 10);
if (strcmp(argv[3], "-b") == 0) {
if (tmp > BUF_SIZ) {
printf("%s invalid params\n", FAIL_TEXT);
geloopback_usage();
return -1;
}
xfer_len = tmp;
if (argc == 7) {
if (strcmp(argv[5], "-t") == 0) {
xfer_wait = strtoul(argv[6], NULL, 10);
} else {
printf("%s invalid params\n", FAIL_TEXT);
geloopback_usage();
return -1;
}
}
} else if (strcmp(argv[3], "-t") == 0) {
xfer_wait = tmp;
if (argc == 7) {
if (strcmp(argv[5], "-b") == 0) {
xfer_len = strtoul(argv[6], NULL, 10);
if (xfer_len > BUF_SIZ) {
printf("%s invalid params\n", FAIL_TEXT);
geloopback_usage();
return -1;
}
} else {
printf("%s invalid params\n", FAIL_TEXT);
geloopback_usage();
return -1;
}
}
} else {
printf("%s invalid params\n", FAIL_TEXT);
geloopback_usage();
return -1;
}
}
strcpy(if_name, LAN_PORT_NAME);
strcpy(out_name, LAN_PORT_NAME);
printf("Sending %d packets of size %d delay %d\n", n, xfer_len, xfer_wait);
for (port = 0; port < GE_MAX_LAN_PORTS; ++port) {
if (portMask & (1 << port)) {
for (j = 0; j < kLoopbackRetries; ++j) {
setup_loopback(port);
sleep(GE_WAIT_AFTER_LOOPBACK_SET);
rx_pkts = 0;
get_ip_stat(&rx_pkts, &tx_pkts, &rx_errs, &tx_errs, LAN_PORT_NAME);
system_cmd("uptime");
send_mac_pkt(if_name, out_name, xfer_len, xfer_wait, n, NULL);
system_cmd("uptime");
rx_pkts = 0;
sleep(rx_wait);
get_ip_stat(&rx_pkts, &tx_pkts, &rx_errs, &tx_errs, LAN_PORT_NAME);
take_down_loopback(port);
if ((rx_pkts >= pass_num) && (tx_pkts >= pass_num) && (rx_errs == 0) &&
(tx_errs == 0)) {
printf("PHY %d passed loop back test. Sent %d:%d, Received %d\n",
port, n, tx_pkts, rx_pkts);
fflush(stdout);
break;
} else {
if (j == (kLoopbackRetries - 1)) {
printf(
"%s PHY %d failed loop back test. Sent %d:%d, Received %d, "
"Errs %d:%d\n",
FAIL_TEXT, port, n, tx_pkts, rx_pkts, tx_errs, rx_errs);
}
fflush(stdout);
}
}
}
}
return 0;
}
static void send_if_to_mac_usage(void) {
printf(
"send_if_to_mac <if> <dest MAC> <num> [-b <pkt byte size (max %d)>] "
"[-t <time delay in micro-second between pkt send>]\n",
BUF_SIZ);
printf("Example:\n");
printf("send_if_to_mac moca0 f8:8f:ca:00:16:04 100\n");
printf("send 100 msg from interface moca0 to f8:8f:ca:00:16:04\n");
printf("send_if_to_mac moca0 f8:8f:ca:00:16:04 100 -b 256 -t 250\n");
printf(
"send to interface moca0 with 100 msgs of size 256 bytes and 250 us "
"delay\n");
}
int send_if_to_mac(int argc, char *argv[]) {
int n;
unsigned int xfer_len = 16, xfer_wait = 0;
char if_name[IFNAMSIZ];
unsigned char dst_mac[6] = {0, 0, 0, 0, 0, 0};
/* Get interface name */
if ((argc != 4) && (argc != 6) && (argc != 8)) {
send_if_to_mac_usage();
return -1;
}
strcpy(if_name, argv[1]);
dst_mac[0] = strtoul(&argv[2][0], NULL, 16);
dst_mac[1] = strtoul(&argv[2][3], NULL, 16);
dst_mac[2] = strtoul(&argv[2][6], NULL, 16);
dst_mac[3] = strtoul(&argv[2][9], NULL, 16);
dst_mac[4] = strtoul(&argv[2][12], NULL, 16);
dst_mac[5] = strtoul(&argv[2][15], NULL, 16);
if (argc >= 6) {
unsigned int tmp;
tmp = strtoul(argv[5], NULL, 10);
if (strcmp(argv[4], "-b") == 0) {
if (tmp > BUF_SIZ) {
send_if_to_mac_usage();
return -1;
}
xfer_len = tmp;
if (argc == 8) {
if (strcmp(argv[6], "-t") == 0) {
xfer_wait = strtoul(argv[7], NULL, 10);
} else {
send_if_to_mac_usage();
return -1;
}
}
} else if (strcmp(argv[4], "-t") == 0) {
xfer_wait = tmp;
if (argc == 8) {
if (strcmp(argv[6], "-b") == 0) {
xfer_len = strtoul(argv[7], NULL, 10);
if (xfer_len > BUF_SIZ) {
send_if_to_mac_usage();
return -1;
}
} else {
send_if_to_mac_usage();
return -1;
}
}
} else {
send_if_to_mac_usage();
return -1;
}
}
n = strtoul(argv[3], NULL, 10);
send_mac_pkt(if_name, NULL, xfer_len, xfer_wait, n, dst_mac);
printf(
"Sent %d packets from IF %s to "
"%02x:%02x:%02x:%02x:%02x:%02x\n",
n, if_name, dst_mac[0], dst_mac[1], dst_mac[2], dst_mac[3], dst_mac[4],
dst_mac[5]);
return 0;
}
static void lan_lpbk_usage(void) {
printf("lan_lpbk <on/off>\n");
printf("Example:\n");
printf("lan_lpbk on\n");
printf("set all lan ports loop back to external\n");
}
/* This is for Marvell 88E1512 only */
int lan_lpbk(int argc, char *argv[]) {
int data;
bool loopback_on = false;
if (argc != 2) {
lan_lpbk_usage();
return -1;
}
if (strcmp(argv[1], "on") == 0) {
loopback_on = true;
} else if (strcmp(argv[1], "off") == 0) {
loopback_on = false;
} else {
lan_lpbk_usage();
return -1;
}
if (c2000_phy_write(SPACECAST_PHY_ADDR, M88E1512_PHY_PAGE_REG,
M88E1512_PHY_PAGE_6) < 0) {
printf("PHY write to reg %d of data 0x%x failed\n", M88E1512_PHY_PAGE_REG,
M88E1512_PHY_PAGE_6);
return -1;
}
data = c2000_phy_read(SPACECAST_PHY_ADDR, M88E1512_PHY_CHECKER_CTRL_REG);
if (loopback_on) {
data |= (1 << M88E1512_PHY_ENABLE_STUB_TEST_BIT);
printf("Ethernet port external loopback enabled\n");
} else {
data &= ~(1 << M88E1512_PHY_ENABLE_STUB_TEST_BIT);
printf("Ethernet port external loopback disabled\n");
}
if (c2000_phy_write(SPACECAST_PHY_ADDR, M88E1512_PHY_CHECKER_CTRL_REG, data) <
0) {
printf("PHY write to reg %d of data 0x%x failed\n",
M88E1512_PHY_CHECKER_CTRL_REG, data);
return -1;
}
if (c2000_phy_write(SPACECAST_PHY_ADDR, M88E1512_PHY_PAGE_REG,
M88E1512_PHY_DEFAULT_PAGE) < 0) {
printf("PHY write to reg %d of data 0x%x failed\n", M88E1512_PHY_PAGE_REG,
M88E1512_PHY_DEFAULT_PAGE);
return -1;
}
return 0;
}
/* This is for QCA switch */
int qca_lan_lpbk(int argc, char *argv[]) {
bool loopback_on = false;
if (argc != 2) {
lan_lpbk_usage();
return -1;
}
if (strcmp(argv[1], "on") == 0) {
loopback_on = true;
} else if (strcmp(argv[1], "off") == 0) {
loopback_on = false;
} else {
lan_lpbk_usage();
return -1;
}
system_cmd("ifup wan0");
if (loopback_on) {
system_cmd("ssdk_sh debug reg set 0x660 0x34007e 4");
system_cmd("ssdk_sh debug reg set 0x66C 0x34007e 4");
system_cmd("ssdk_sh debug reg set 0x678 0x34007e 4");
system_cmd("ssdk_sh debug reg set 0x684 0x34007e 4");
printf("All lan ports looped back to external\n");
} else {
system_cmd("ssdk_sh debug reg set 0x660 0x14007e 4");
system_cmd("ssdk_sh debug reg set 0x66C 0x14007e 4");
system_cmd("ssdk_sh debug reg set 0x678 0x14007e 4");
system_cmd("ssdk_sh debug reg set 0x684 0x14007e 4");
printf("All lan ports loopback turned off\n");
}
system_cmd("ifdown wan0");
return 0;
}
static void set_lan_snake_usage(void) {
printf("set_lan_snake\n");
printf("Example:\n");
printf("set_lan_snake\n");
printf("Traffic generator -> P1; and P1/2 are the same VLAN.\n");
printf("P2 is connected to P3 via cable\n");
printf("P3/4 are the same VLAN. P4 -> traffic receiver\n");
}
int set_lan_snake(int argc, char *argv[]) {
if ((argc != 1) || (argv[0] == NULL)) {
set_lan_snake_usage();
return -1;
}
system_cmd("ifup wan0");
// Take the LAN ports out of the default LAN VLAN 0
system_cmd("ssdk_sh portVlan member del 0 1 > /tmp/t");
system_cmd("ssdk_sh portVlan member del 0 2 > /tmp/t");
system_cmd("ssdk_sh portVlan member del 0 3 > /tmp/t");
system_cmd("ssdk_sh portVlan member del 0 4 > /tmp/t");
// Assign new VLAN ID
system_cmd("ssdk_sh portVlan member update 1 0x4 > /tmp/t");
system_cmd("ssdk_sh portVlan member update 2 0x2 > /tmp/t");
system_cmd("ssdk_sh portVlan member update 3 0x10 > /tmp/t");
system_cmd("ssdk_sh portVlan member update 4 0x8 > /tmp/t");
system_cmd("ssdk_sh portVlan defaultCVid set 1 1 > /tmp/t");
system_cmd("ssdk_sh portVlan defaultCVid set 2 1 > /tmp/t");
system_cmd("ssdk_sh portVlan defaultCVid set 3 2 > /tmp/t");
system_cmd("ssdk_sh portVlan defaultCVid set 4 2 > /tmp/t");
system_cmd("ifdown wan0");
return 0;
}
static void ge_traffic_usage(void) {
printf("ge_traffic <test duration> [<%s print period>]\n",
GE_TRAFFIC_TEST_PERIOD_SYMBOL);
printf("- duration >=1 or -1 (forever)\n");
printf("- traffic sent from lan0 to wan0\n");
printf("- print period > 0\n");
}
int ge_traffic(int argc, char *argv[]) {
char cmd[MAX_CMD_SIZE];
int duration, num = -1;
int pid, pid1, pid2;
int printPeriod = GE_TRAFFIC_REPORT_PERIOD;
static const unsigned char dst_mac[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
if ((argc != 2) && (argc != 4)) {
ge_traffic_usage();
return -1;
}
duration = strtol(argv[1], NULL, 0);
if ((duration < -1) || (duration == 0)) {
ge_traffic_usage();
return -1;
}
if (argc == 4) {
if (strcmp(argv[2], GE_TRAFFIC_TEST_PERIOD_SYMBOL) != 0) {
ge_traffic_usage();
return -1;
}
printPeriod = strtoul(argv[3], NULL, 0);
if (printPeriod == 0) {
ge_traffic_usage();
return -1;
}
}
pid = fork();
if (pid < 0) {
printf("Server fork error %d, errno %d\n", pid, errno);
return -1;
}
if (pid == 0) {
// Child process
send_mac_pkt(GE_TRAFFIC_PORT, NULL, BUF_SIZ, 0, num, dst_mac);
exit(0);
}
// Parent process
pid1 = pid;
pid = fork();
if (pid < 0) {
printf("Server fork error %d, errno %d\n", pid, errno);
return -1;
}
if (pid == 0) {
// Child process
send_mac_pkt(GE_TRAFFIC_PORT, NULL, BUF_SIZ, 0, num, dst_mac);
exit(0);
}
// Parent process
pid2 = pid;
while (duration != 0) {
if (duration >= 0) {
if (duration <= printPeriod) {
sleep(duration);
duration = 0;
kill(pid1, SIGKILL);
kill(pid2, SIGKILL);
// printf("Killed processes %d and %d\n", pid1, pid2);
} else {
duration -= printPeriod;
sleep(printPeriod);
}
} else {
sleep(printPeriod);
}
sprintf(cmd, "ifstat %s %s", GE_TRAFFIC_PORT, GE_TRAFFIC_DST_PORT);
system_cmd(cmd);
}
return 0;
}