mirror of
https://github.com/Fishwaldo/u-boot.git
synced 2025-03-21 22:51:37 +00:00
Previously u-boot would initialize the network interface for every network operation and then shut it down again. This makes sense for most operations where the network in not known to be needed soon after the operation is complete. In the case of netconsole, it will use the network for every interaction with the shell or every printf. This means that the network is being reinitialized very often. On many devices, this intialization is very slow. This patch checks for consecutive netconsole actions and leaves the ethernet hardware initialized between them. It will still behave the same old way for all other network operations and any time another network operation happens between netconsole operations. Signed-off-by: Joe Hershberger <joe.hershberger@ni.com> Cc: Stefano Babic <sbabic@denx.de> Acked-by: Stefano Babic <sbabic@denx.de>
307 lines
6.8 KiB
C
307 lines
6.8 KiB
C
/*
|
|
* (C) Copyright 2004
|
|
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
|
*
|
|
* See file CREDITS for list of people who contributed to this
|
|
* project.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License as
|
|
* published by the Free Software Foundation; either version 2 of
|
|
* the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
|
* MA 02111-1307 USA
|
|
*/
|
|
|
|
#include <common.h>
|
|
#include <command.h>
|
|
#include <stdio_dev.h>
|
|
#include <net.h>
|
|
|
|
DECLARE_GLOBAL_DATA_PTR;
|
|
|
|
#ifndef CONFIG_NETCONSOLE_BUFFER_SIZE
|
|
#define CONFIG_NETCONSOLE_BUFFER_SIZE 512
|
|
#endif
|
|
|
|
static char input_buffer[CONFIG_NETCONSOLE_BUFFER_SIZE];
|
|
static int input_size; /* char count in input buffer */
|
|
static int input_offset; /* offset to valid chars in input buffer */
|
|
static int input_recursion;
|
|
static int output_recursion;
|
|
static int net_timeout;
|
|
static uchar nc_ether[6]; /* server enet address */
|
|
static IPaddr_t nc_ip; /* server ip */
|
|
static short nc_out_port; /* target output port */
|
|
static short nc_in_port; /* source input port */
|
|
static const char *output_packet; /* used by first send udp */
|
|
static int output_packet_len;
|
|
/*
|
|
* Start with a default last protocol.
|
|
* We are only interested in NETCONS or not.
|
|
*/
|
|
enum proto_t net_loop_last_protocol = BOOTP;
|
|
|
|
static void nc_wait_arp_handler(uchar *pkt, unsigned dest,
|
|
IPaddr_t sip, unsigned src,
|
|
unsigned len)
|
|
{
|
|
net_set_state(NETLOOP_SUCCESS); /* got arp reply - quit net loop */
|
|
}
|
|
|
|
static void nc_handler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,
|
|
unsigned len)
|
|
{
|
|
if (input_size)
|
|
net_set_state(NETLOOP_SUCCESS); /* got input - quit net loop */
|
|
}
|
|
|
|
static void nc_timeout(void)
|
|
{
|
|
net_set_state(NETLOOP_SUCCESS);
|
|
}
|
|
|
|
void NcStart(void)
|
|
{
|
|
if (!output_packet_len || memcmp(nc_ether, NetEtherNullAddr, 6)) {
|
|
/* going to check for input packet */
|
|
net_set_udp_handler(nc_handler);
|
|
NetSetTimeout(net_timeout, nc_timeout);
|
|
} else {
|
|
/* send arp request */
|
|
uchar *pkt;
|
|
net_set_arp_handler(nc_wait_arp_handler);
|
|
pkt = (uchar *)NetTxPacket + NetEthHdrSize() + IP_UDP_HDR_SIZE;
|
|
memcpy(pkt, output_packet, output_packet_len);
|
|
NetSendUDPPacket(nc_ether, nc_ip, nc_out_port, nc_in_port,
|
|
output_packet_len);
|
|
}
|
|
}
|
|
|
|
int nc_input_packet(uchar *pkt, unsigned dest, unsigned src, unsigned len)
|
|
{
|
|
int end, chunk;
|
|
|
|
if (dest != nc_in_port || !len)
|
|
return 0; /* not for us */
|
|
|
|
debug_cond(DEBUG_DEV_PKT, "input: \"%*.*s\"\n", len, len, pkt);
|
|
|
|
if (input_size == sizeof(input_buffer))
|
|
return 1; /* no space */
|
|
if (len > sizeof(input_buffer) - input_size)
|
|
len = sizeof(input_buffer) - input_size;
|
|
|
|
end = input_offset + input_size;
|
|
if (end > sizeof(input_buffer))
|
|
end -= sizeof(input_buffer);
|
|
|
|
chunk = len;
|
|
if (end + len > sizeof(input_buffer)) {
|
|
chunk = sizeof(input_buffer) - end;
|
|
memcpy(input_buffer, pkt + chunk, len - chunk);
|
|
}
|
|
memcpy(input_buffer + end, pkt, chunk);
|
|
|
|
input_size += len;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static void nc_send_packet(const char *buf, int len)
|
|
{
|
|
struct eth_device *eth;
|
|
int inited = 0;
|
|
uchar *pkt;
|
|
uchar *ether;
|
|
IPaddr_t ip;
|
|
|
|
debug_cond(DEBUG_DEV_PKT, "output: \"%*.*s\"\n", len, len, buf);
|
|
|
|
eth = eth_get_dev();
|
|
if (eth == NULL)
|
|
return;
|
|
|
|
if (!memcmp(nc_ether, NetEtherNullAddr, 6)) {
|
|
if (eth->state == ETH_STATE_ACTIVE)
|
|
return; /* inside net loop */
|
|
output_packet = buf;
|
|
output_packet_len = len;
|
|
NetLoop(NETCONS); /* wait for arp reply and send packet */
|
|
output_packet_len = 0;
|
|
return;
|
|
}
|
|
|
|
if (eth->state != ETH_STATE_ACTIVE) {
|
|
if (eth_is_on_demand_init()) {
|
|
if (eth_init(gd->bd) < 0)
|
|
return;
|
|
eth_set_last_protocol(NETCONS);
|
|
} else
|
|
eth_init_state_only(gd->bd);
|
|
|
|
inited = 1;
|
|
}
|
|
pkt = (uchar *)NetTxPacket + NetEthHdrSize() + IP_UDP_HDR_SIZE;
|
|
memcpy(pkt, buf, len);
|
|
ether = nc_ether;
|
|
ip = nc_ip;
|
|
NetSendUDPPacket(ether, ip, nc_out_port, nc_in_port, len);
|
|
|
|
if (inited) {
|
|
if (eth_is_on_demand_init())
|
|
eth_halt();
|
|
else
|
|
eth_halt_state_only();
|
|
}
|
|
}
|
|
|
|
static int nc_start(void)
|
|
{
|
|
int netmask, our_ip;
|
|
char *p;
|
|
|
|
nc_out_port = 6666; /* default port */
|
|
nc_in_port = nc_out_port;
|
|
|
|
if (getenv("ncip")) {
|
|
|
|
nc_ip = getenv_IPaddr("ncip");
|
|
if (!nc_ip)
|
|
return -1; /* ncip is 0.0.0.0 */
|
|
p = strchr(getenv("ncip"), ':');
|
|
if (p != NULL) {
|
|
nc_out_port = simple_strtoul(p + 1, NULL, 10);
|
|
nc_in_port = nc_out_port;
|
|
}
|
|
} else
|
|
nc_ip = ~0; /* ncip is not set, so broadcast */
|
|
|
|
p = getenv("ncoutport");
|
|
if (p != NULL)
|
|
nc_out_port = simple_strtoul(p, NULL, 10);
|
|
p = getenv("ncinport");
|
|
if (p != NULL)
|
|
nc_in_port = simple_strtoul(p, NULL, 10);
|
|
|
|
our_ip = getenv_IPaddr("ipaddr");
|
|
netmask = getenv_IPaddr("netmask");
|
|
|
|
if (nc_ip == ~0 || /* 255.255.255.255 */
|
|
((netmask & our_ip) == (netmask & nc_ip) && /* on the same net */
|
|
(netmask | nc_ip) == ~0)) /* broadcast to our net */
|
|
memset(nc_ether, 0xff, sizeof(nc_ether));
|
|
else
|
|
memset(nc_ether, 0, sizeof(nc_ether)); /* force arp request */
|
|
|
|
/*
|
|
* Initialize the static IP settings and buffer pointers
|
|
* incase we call NetSendUDPPacket before NetLoop
|
|
*/
|
|
net_init();
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void nc_putc(char c)
|
|
{
|
|
if (output_recursion)
|
|
return;
|
|
output_recursion = 1;
|
|
|
|
nc_send_packet(&c, 1);
|
|
|
|
output_recursion = 0;
|
|
}
|
|
|
|
static void nc_puts(const char *s)
|
|
{
|
|
int len;
|
|
|
|
if (output_recursion)
|
|
return;
|
|
output_recursion = 1;
|
|
|
|
len = strlen(s);
|
|
while (len) {
|
|
int send_len = min(len, sizeof(input_buffer));
|
|
nc_send_packet(s, send_len);
|
|
len -= send_len;
|
|
s += send_len;
|
|
}
|
|
|
|
output_recursion = 0;
|
|
}
|
|
|
|
static int nc_getc(void)
|
|
{
|
|
uchar c;
|
|
|
|
input_recursion = 1;
|
|
|
|
net_timeout = 0; /* no timeout */
|
|
while (!input_size)
|
|
NetLoop(NETCONS);
|
|
|
|
input_recursion = 0;
|
|
|
|
c = input_buffer[input_offset++];
|
|
|
|
if (input_offset >= sizeof(input_buffer))
|
|
input_offset -= sizeof(input_buffer);
|
|
input_size--;
|
|
|
|
return c;
|
|
}
|
|
|
|
static int nc_tstc(void)
|
|
{
|
|
struct eth_device *eth;
|
|
|
|
if (input_recursion)
|
|
return 0;
|
|
|
|
if (input_size)
|
|
return 1;
|
|
|
|
eth = eth_get_dev();
|
|
if (eth && eth->state == ETH_STATE_ACTIVE)
|
|
return 0; /* inside net loop */
|
|
|
|
input_recursion = 1;
|
|
|
|
net_timeout = 1;
|
|
NetLoop(NETCONS); /* kind of poll */
|
|
|
|
input_recursion = 0;
|
|
|
|
return input_size != 0;
|
|
}
|
|
|
|
int drv_nc_init(void)
|
|
{
|
|
struct stdio_dev dev;
|
|
int rc;
|
|
|
|
memset(&dev, 0, sizeof(dev));
|
|
|
|
strcpy(dev.name, "nc");
|
|
dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM;
|
|
dev.start = nc_start;
|
|
dev.putc = nc_putc;
|
|
dev.puts = nc_puts;
|
|
dev.getc = nc_getc;
|
|
dev.tstc = nc_tstc;
|
|
|
|
rc = stdio_register(&dev);
|
|
|
|
return (rc == 0) ? 1 : rc;
|
|
}
|